/* Brain Grain — TNPSC Arena: the play surface
 * ===========================================================================
 * WHY THIS FILE REPLACES AN OVERRIDE LAYER
 * ----------------------------------------
 * The previous arena was a dark skin bolted onto light pages: tnpsc-group*.html
 * each carried a full light stylesheet (`--bg:#f8faff`, `.q-card{background:#fff}`,
 * `nav{background:#fff}`) and tnpsc-arena.css fought it with ~30 `!important`
 * rules scoped to `.ar-play`. That is an override war, and it loses by default:
 * every rule the override list did not name stayed light, every rule it half-named
 * produced white-on-white, and any new markup arrived unstyled. The collapsed UI
 * was not a handful of bad pixels — it was the architecture.
 *
 * So this file does not override anything. It is the ONLY stylesheet the play
 * surface needs, everything is scoped under `.bga`, and no rule outside `.bga`
 * is assumed or fought. Drop it on a light page or a dark one and the arena
 * looks the same.
 *
 * THE READING SURFACE
 * -------------------
 * A TNPSC aspirant sits with this for two hours. The old skin put gold-on-near-
 * black text over a 44px purple grid and three radial colour glows — high drama,
 * and genuinely painful past about twenty minutes. The split here is deliberate:
 *
 *   CHROME (HUD, bars, chips, results) keeps the arena — gold, depth, contrast.
 *   THE WORKING AREA (question, options, explanation) is calm and flat. No grid
 *   behind text, no glow behind text, no saturated hue on a reading surface,
 *   and body text at WCAG AA or better against its own card.
 *
 * Both themes are real, not a filter: `data-bga-theme="day"` is a warm paper
 * surface (#f7f3ec, not white — white at 1am is its own headache), `"night"` is
 * a desaturated slate. Text size is a third axis (`data-bga-size`) because the
 * commonest fix for eye strain is simply bigger type, and asking someone to
 * pinch-zoom a fixed layout every question is not a fix.
 *
 * ES5/old-WebView note: no `:is()`, no `aspect-ratio`, no custom-property
 * fallbacks that assume `@property`. These pages run on cheap Android WebViews.
 */

/* ── tokens ────────────────────────────────────────────────────────────────
   Night is the default: unset or unknown values must land somewhere legible,
   so the base `.bga` block IS night and `[data-bga-theme="day"]` overrides it.
   A theme that only exists in an attribute selector leaves the pre-hydration
   paint unstyled, which is the flash everyone notices. */
.bga {
  --bga-chrome: #0d101a;
  --bga-chrome2: #151a28;
  /* The HUD and the action bar are the only surfaces that do not sit on
     --bga-card, so they need their own ink tokens. Hardcoding #e9ecf6 / #ffd97a
     here is what left Day mode as a warm card sandwiched between two permanently
     dark bars — a light middle bolted between dark ends, which is the exact
     pattern this rebuild exists to remove. */
  --bga-chrome-ink: #e9ecf6;
  --bga-chrome-ink2: #a9b0c6;
  --bga-chrome-accent: #ffd97a;
  --bga-chrome-line: rgba(255, 255, 255, .16);
  --bga-chrome-fill: rgba(255, 255, 255, .07);
  --bga-chrome-track: rgba(255, 255, 255, .10);
  --bga-field: #12141d;
  --bga-card: #1a1e2a;
  --bga-card2: #222736;
  --bga-card3: #2a3040;
  --bga-line: #2f3546;
  --bga-line2: #3b4356;
  --bga-ink: #edeff7;      /* 14.2:1 on --bga-card */
  --bga-ink2: #c2c8da;     /*  9.1:1 on --bga-card */
  --bga-mut: #949bb2;      /*  5.4:1 on --bga-card — AA for body, not for 12px */
  --bga-gold: #ffc233;
  --bga-gold2: #ff8f1f;
  --bga-cyan: #56d9f0;
  --bga-green: #3ddc84;
  --bga-green-b: rgba(61, 220, 132, .14);
  --bga-red: #ff7a7a;
  --bga-red-b: rgba(255, 122, 122, .13);
  --bga-shadow: 0 8px 26px rgba(0, 0, 0, .45);
  --bga-head: Nunito, "Segoe UI", system-ui, sans-serif;
  --bga-text: Inter, "Noto Sans Tamil", "Segoe UI", system-ui, -apple-system, Roboto, sans-serif;
  --bga-tamil: "Noto Sans Tamil", Inter, system-ui, sans-serif;
  --bga-q: 1rem;           /* driven by data-bga-size */
  --bga-o: .94rem;
  --bga-lh: 1.55;          /* question/option leading, tightened at larger sizes */
  --bga-lh-ta: 1.8;
  /* How far down the sticky HUD parks. A host page that already has its own
     sticky bar sets this to that bar's height; two elements both claiming
     top:0 is the overlap that made the old surface look collapsed. */
  --bga-top: 0px;
}

/* The second selector covers the pre-hydration window only: a head script stamps
   `data-bga-boot` on <html> from saved prefs, so a Day learner never gets a dark
   flash before the engine mounts. Once the engine runs it sets data-bga-theme on
   the pane itself and the `:not()` stops matching. */
.bga[data-bga-theme="day"],
html[data-bga-boot="day"] .bga:not([data-bga-theme]) {
  /* Day means day all the way through, bars included. */
  --bga-chrome: #e5ddce;
  --bga-chrome2: #d8cfbc;
  --bga-chrome-ink: #242a38;      /* 11.6:1 on --bga-chrome */
  --bga-chrome-ink2: #575e70;     /*  5.2:1 on --bga-chrome */
  --bga-chrome-accent: #8a4a00;   /*  5.6:1 on --bga-chrome */
  --bga-chrome-line: rgba(60, 45, 20, .22);
  --bga-chrome-fill: rgba(255, 255, 255, .5);
  --bga-chrome-track: rgba(60, 45, 20, .14);
  --bga-field: #ece7dd;
  --bga-card: #fbf8f2;
  --bga-card2: #fffdf9;
  --bga-card3: #f1ece2;
  --bga-line: #ddd4c4;
  --bga-line2: #c9bda8;
  --bga-ink: #1d2230;      /* 15.1:1 on --bga-card */
  --bga-ink2: #3a4152;     /*  9.4:1 on --bga-card */
  --bga-mut: #6a7183;      /*  4.8:1 on --bga-card */
  --bga-gold: #a35d00;
  --bga-gold2: #c2410c;
  --bga-cyan: #0e6f88;
  --bga-green: #157347;
  --bga-green-b: #e3f5ea;
  --bga-red: #b3261e;
  --bga-red-b: #fbeae9;
  --bga-shadow: 0 6px 18px rgba(60, 45, 20, .12);
}

/* Bigger type needs proportionally LESS leading, not the same ratio applied to a
   larger number. Without tightening these, A++ grew the block so much that the
   answer options — the thing the learner needs to reach — went off the bottom of
   the screen, so the comfort control made comfort worse. */
.bga[data-bga-size="l"]  { --bga-q: 1.1rem;  --bga-o: 1.02rem; --bga-lh: 1.45; --bga-lh-ta: 1.7; }
.bga[data-bga-size="xl"] { --bga-q: 1.22rem; --bga-o: 1.12rem; --bga-lh: 1.36; --bga-lh-ta: 1.6; }

/* ── shell ─────────────────────────────────────────────────────────────────
   `overflow-x:clip` and a box-sizing reset are load-bearing, not tidiness: a
   shared widget that sets its own width used to blow 18px past the viewport and
   trip the layout gate. Scoped, so it cannot surprise a host page. */
.bga, .bga *, .bga *::before, .bga *::after { box-sizing: border-box; }

.bga {
  font-family: var(--bga-text);
  color: var(--bga-ink);
  background: var(--bga-field);
  line-height: 1.6;
  overflow-x: clip;
  -webkit-text-size-adjust: 100%;
  /* The pane must NOT create a stacking context. /tnpsc is an `.ar-body` page,
     and tnpsc-arena.css sets `.ar-body > * { position:relative; z-index:1 }` to
     lift content above its background grid. That trapped everything in here at
     z-index 1, so the action bar's z-index 100 lost to #xp-hud's 89 no matter
     what number it claimed, and the Next button sat under the XP bar. Keeping
     this `auto` lets the bar's own z-index reach the root context, where it
     actually means something. This file loads after tnpsc-arena.css, so it wins
     on order at equal specificity. */
  position: relative;
  z-index: auto;
  /* Deliberately NOT `contain: paint` — it makes this a containing block for
     fixed descendants, which would trap the settings sheet inside the pane
     instead of the viewport, and it clips the sticky HUD. */
}
.bga button { font-family: inherit; cursor: pointer; color: inherit; }
.bga a { color: var(--bga-gold); text-decoration: none; }
.bga h1, .bga h2, .bga h3 { margin: 0; font-family: var(--bga-head); }

.bga-wrap { max-width: 720px; margin: 0 auto; padding: 0 12px; }

/* ── the HUD ───────────────────────────────────────────────────────────────
   Sticky, because "how long have I got / how am I doing" must be answerable
   without scrolling — that is what makes a run feel like a run. It stays arena:
   this is the chrome, not the reading surface. */
.bga-hud {
  position: -webkit-sticky;
  position: sticky;
  top: var(--bga-top, 0px);
  z-index: 40;
  background: var(--bga-chrome);
  border-bottom: 1px solid var(--bga-chrome-line);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .22);
}
.bga-hud-in {
  max-width: 720px;
  margin: 0 auto;
  padding: 6px 12px;
  display: flex;
  align-items: center;
  gap: 9px;
}
.bga-timer {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  font-family: var(--bga-head);
  font-weight: 900;
  font-size: 1.02rem;
  color: var(--bga-chrome-accent);
  font-variant-numeric: tabular-nums;
  min-width: 56px;
}
.bga-timer.low { color: #e0443c; }
.bga[data-bga-theme="day"] .bga-timer.low { color: #a3160f; }
.bga-ring { width: 24px; height: 24px; flex-shrink: 0; }
.bga-ring circle { fill: none; stroke-width: 3.5; }
.bga-ring .bg { stroke: var(--bga-chrome-track); }
.bga-ring .fg {
  stroke: currentColor;
  stroke-linecap: round;
  transform: rotate(-90deg);
  transform-origin: 50% 50%;
  transition: stroke-dashoffset .25s linear;
}
.bga-hud-mid { flex: 1; min-width: 0; }
.bga-prog-txt {
  font-size: .68rem;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--bga-chrome-ink2);
  display: flex;
  justify-content: space-between;
  gap: 8px;
}
.bga-prog-txt b { color: var(--bga-chrome-accent); letter-spacing: 0; }
.bga-prog {
  height: 5px;
  margin-top: 3px;
  border-radius: 100px;
  background: var(--bga-chrome-track);
  overflow: hidden;
}
.bga-prog i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 100px;
  background: linear-gradient(90deg, var(--bga-gold2), var(--bga-gold));
  transition: width .3s ease;
}
.bga-hud-btn {
  flex-shrink: 0;
  border: 1px solid var(--bga-chrome-line);
  background: var(--bga-chrome-fill);
  color: var(--bga-chrome-ink);
  border-radius: 9px;
  padding: 5px 8px;
  font-size: .92rem;
  line-height: 1;
}
.bga-hud-btn:hover { border-color: var(--bga-chrome-accent); }

/* Score: correct / wrong / streak, INSIDE the HUD row rather than in a band of
   its own beneath it. The separate strip cost ~42px of vertical chrome, and the
   render sweep showed that on a long bilingual question — the kind this site
   exists to serve — those 42px were the difference between seeing four options
   and seeing one. Three numbers do not need their own storey. */
.bga-score {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
  font-size: .62rem;
  font-weight: 900;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--bga-chrome-ink2);
  text-align: center;
  line-height: 1.15;
}
.bga-score span { display: block; }
.bga-score b {
  display: block;
  font-family: var(--bga-head);
  font-size: .92rem;
  letter-spacing: 0;
  color: var(--bga-chrome-ink);
  font-variant-numeric: tabular-nums;
}
.bga-score .c b { color: var(--bga-green); }
.bga-score .w b { color: var(--bga-red); }
.bga-score .hot b { color: var(--bga-chrome-accent); }
.bga[data-bga-theme="day"] .bga-score .c b { color: #0f6b3f; }
.bga[data-bga-theme="day"] .bga-score .w b { color: #a3160f; }

/* ── the working area ──────────────────────────────────────────────────────
   Flat. No gradient, no glow, no pattern. Everything below is judged on being
   readable for two hours, not on looking exciting for two seconds. */
.bga-card {
  background: var(--bga-card);
  border: 1px solid var(--bga-line);
  border-radius: 14px;
  padding: 12px 13px 11px;
  margin: 8px 0;
  box-shadow: var(--bga-shadow);
}
.bga-meta {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-wrap: wrap;
  margin-bottom: 7px;
}
/* The syllabus-topic pill is the longest of the three and the least load-bearing
   — on a phone it wraps to a second row and costs ~24px that the options need
   more than it does. Group and topic stay; the sub-topic is on the explanation. */
@media (max-width: 460px) { .bga-meta .bga-pill.sub { display: none; } }
.bga-pill {
  font-size: .66rem;
  font-weight: 900;
  letter-spacing: .06em;
  text-transform: uppercase;
  border-radius: 6px;
  padding: 3px 7px;
  background: var(--bga-card3);
  color: var(--bga-ink2);
  border: 1px solid var(--bga-line);
}
.bga-pill.g1 { color: var(--bga-gold); }
.bga-pill.g2 { color: var(--bga-cyan); }
.bga-pill.g4 { color: var(--bga-green); }
/* CTET: Paper I, Paper II, and the questions that belong to BOTH (Child
   Development, Language and Maths). The shared pill is deliberately the neutral
   colour — it is not a third paper, it is the absence of a distinction. */
.bga-pill.p1 { color: var(--bga-gold); }
.bga-pill.p2 { color: var(--bga-cyan); }
.bga-pill.pb { color: var(--bga-green); }

.bga-q {
  font-size: var(--bga-q);
  font-weight: 700;
  line-height: var(--bga-lh, 1.55);
  color: var(--bga-ink);
  margin-bottom: 4px;
}
/* Tamil is a first-class line, not a caption. Rendering it at --bga-mut (the old
   skin did) reads as disabled text to a Tamil-medium learner — for whom it is
   the primary line. Same weight class as the English, slightly looser leading
   because the script needs it. */
.bga-q-ta {
  font-family: var(--bga-tamil);
  font-size: calc(var(--bga-q) * .97);
  line-height: var(--bga-lh-ta, 1.85);
  color: var(--bga-ink2);
  margin-bottom: 2px;
}

.bga-opts { display: grid; gap: 7px; margin-top: 10px; }
.bga-opt {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  width: 100%;
  text-align: left;
  background: var(--bga-card2);
  border: 1.5px solid var(--bga-line);
  border-radius: 11px;
  padding: 9px 11px;
  font-size: var(--bga-o);
  line-height: var(--bga-lh, 1.5);
  color: var(--bga-ink);
  transition: border-color .12s, background .12s;
  /* 44px min touch target — an option you mis-tap under a clock is a wrong
     answer the learner did not give. */
  min-height: 44px;
}
.bga-opt:hover:not([disabled]) { border-color: var(--bga-line2); background: var(--bga-card3); }
.bga-opt-key {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: var(--bga-card3);
  border: 1px solid var(--bga-line);
  color: var(--bga-ink2);
  font-weight: 900;
  font-size: .76rem;
  line-height: 20px;
  text-align: center;
}
.bga-opt-lines { min-width: 0; }
.bga-opt-ta {
  display: block;
  font-family: var(--bga-tamil);
  font-size: calc(var(--bga-o) * .96);
  line-height: var(--bga-lh-ta, 1.75);
  color: var(--bga-ink2);
  margin-top: 1px;
}
.bga-opt[disabled] { cursor: default; }
.bga-opt.right {
  border-color: var(--bga-green);
  background: var(--bga-green-b);
}
.bga-opt.right .bga-opt-key { background: var(--bga-green); color: #05210f; border-color: transparent; }
.bga-opt.wrong {
  border-color: var(--bga-red);
  background: var(--bga-red-b);
}
.bga-opt.wrong .bga-opt-key { background: var(--bga-red); color: #2c0606; border-color: transparent; }
.bga-opt.chosen { border-color: var(--bga-gold); background: var(--bga-card3); }
.bga-opt.chosen .bga-opt-key { background: var(--bga-gold); color: #241700; border-color: transparent; }

/* Explanation — the payoff of the whole loop. It only appears AFTER an option is
   clicked, which is exactly why the old skin shipped it white-on-white for a
   while: a static scan of the stylesheet never sees this state. */
.bga-exp {
  margin-top: 11px;
  background: var(--bga-card3);
  border: 1px solid var(--bga-line);
  border-left: 3px solid var(--bga-gold);
  border-radius: 9px;
  padding: 10px 12px;
  font-size: calc(var(--bga-o) * .96);
  line-height: 1.65;
  color: var(--bga-ink);
}
.bga-exp h4 {
  margin: 0 0 4px;
  font-family: var(--bga-head);
  font-size: .74rem;
  font-weight: 900;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--bga-gold);
}
.bga-exp .ta {
  display: block;
  font-family: var(--bga-tamil);
  line-height: 1.8;
  color: var(--bga-ink2);
  margin-top: 5px;
}

/* ── action bar ────────────────────────────────────────────────────────────
   Fixed to the bottom so the primary action never moves and never needs a
   scroll after a long question. Safe-area inset for notched phones. */
.bga-act {
  position: -webkit-sticky;
  position: sticky;
  /* Not `bottom: 0` — bottom-anchored site chrome publishes its height here and
     this bar steps above it. Today the only publisher is the cookie notice,
     which is 130px tall at 390px and fixed at z-index 10000: with `bottom: 0`
     it covered End run and Skip completely on a first visit, and a timed
     question whose controls are under a consent bar is a broken first
     impression. Defaults to 0px, so every page without a notice is unchanged. */
  bottom: var(--bg-bottom-inset, 0px);
  /* Above the site's floating widgets, not below them. #xp-hud is fixed at
     z-index 89 and was covering this bar completely at 390px — the primary
     control of the primary loop, invisible on the phone, which is where nearly
     all of this traffic is. When a floating badge and the run's own Next button
     want the same 60px, the Next button wins. */
  z-index: 100;
  background: var(--bga-chrome);
  border-top: 1px solid var(--bga-chrome-line);
  padding: 7px 12px calc(7px + env(safe-area-inset-bottom, 0px));
  margin-top: 10px;
}
.bga-act-in {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  gap: 8px;
  align-items: center;
}
.bga-btn {
  border: none;
  border-radius: 11px;
  padding: 10px 16px;
  font-family: var(--bga-head);
  font-weight: 900;
  font-size: .95rem;
  background: var(--bga-card3);
  color: var(--bga-ink);
  border: 1px solid var(--bga-line);
  white-space: nowrap;
}
.bga-btn.primary {
  flex: 1;
  background: linear-gradient(135deg, var(--bga-gold), var(--bga-gold2));
  color: #24180a;
  border-color: transparent;
}
.bga-btn.primary:hover { filter: brightness(1.06); }
.bga-btn.ghost {
  background: transparent;
  color: var(--bga-chrome-ink2);
  border-color: var(--bga-chrome-line);
}
a.bga-btn { display: inline-block; text-align: center; }
a.bga-btn.primary { color: #24180a; }

/* ── "there are more options below" ────────────────────────────────────────
   The honest fix for a question that is genuinely too long to fit: say so.
   Reducing chrome bought back ~90px, which covers most questions, but a long
   English stem plus a two-line Tamil translation plus four bilingual options
   will not fit on a 390x844 phone no matter how tight the padding is — and the
   failure mode without this is silent, which is the worst kind. The engine
   measures after every render and shows this only when it is actually true. */
.bga-more {
  position: -webkit-sticky;
  position: sticky;
  bottom: 62px;
  z-index: 90;
  display: none;
  width: -webkit-fit-content;
  width: fit-content;
  margin: -30px auto 0;
  border: 1px solid var(--bga-gold);
  background: var(--bga-card3);
  color: var(--bga-ink);
  border-radius: 100px;
  padding: 6px 14px;
  font-size: .75rem;
  font-weight: 900;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .35);
}
.bga-more.on { display: block; }
@media (prefers-reduced-motion: no-preference) {
  .bga-more.on { animation: bgaNudge 1.6s ease-in-out infinite; }
}
@keyframes bgaNudge {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(3px); }
}

/* ── the sheet: mode, group, topic, language, comfort ──────────────────────
   Everything configurable lives HERE, behind the gear, and never in front of a
   learner who just wants to play. The one-click promise dies the moment a
   chooser stands between the tap and the first question. */
.bga-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 120;
  background: var(--bga-card);
  border-top: 1px solid var(--bga-line2);
  border-radius: 18px 18px 0 0;
  box-shadow: 0 -14px 40px rgba(0, 0, 0, .5);
  /* The bottom padding clears #xp-hud, which parks a "Beginner · 0 XP · 1d" bar
     over the last row of chips. The sheet also hides that bar while it is open
     (see body.bga-sheet-open below) — the padding is the belt to that braces,
     because a chip sliced in half by an opaque bar reads as broken even when it
     is only one scroll away. */
  padding: 6px 14px calc(76px + env(safe-area-inset-bottom, 0px));
  max-height: 82vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  transform: translateY(103%);
  transition: transform .22s ease;
}
.bga-sheet.open { transform: translateY(0); }
.bga-sheet-grip {
  width: 40px;
  height: 4px;
  border-radius: 100px;
  background: var(--bga-line2);
  margin: 8px auto 12px;
}
.bga-scrim {
  position: fixed;
  inset: 0;
  z-index: 119;
  background: rgba(0, 0, 0, .55);
  opacity: 0;
  visibility: hidden;
  transition: opacity .22s;
}
.bga-scrim.open { opacity: 1; visibility: visible; }
.bga-sec { margin-bottom: 15px; }
.bga-sec > h4 {
  font-size: .67rem;
  font-weight: 900;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--bga-mut);
  margin: 0 0 7px;
}
.bga-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.bga-chip {
  border: 1.5px solid var(--bga-line);
  background: var(--bga-card2);
  color: var(--bga-ink2);
  border-radius: 100px;
  padding: 7px 13px;
  font-size: .8rem;
  font-weight: 800;
  min-height: 36px;
}
.bga-chip.on {
  background: var(--bga-gold);
  border-color: var(--bga-gold);
  color: #24180a;
}
.bga-chip small { display: block; font-size: .66rem; font-weight: 700; opacity: .75; }

/* Mode cards get more room than a chip — a learner picking "Mock Test" over
   "Blitz" is choosing between 3 minutes and 2 hours, and the difference has to
   be legible before the tap, not after it. */
.bga-modes { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.bga-mode {
  text-align: left;
  border: 1.5px solid var(--bga-line);
  background: var(--bga-card2);
  border-radius: 12px;
  padding: 10px 11px;
}
.bga-mode.on { border-color: var(--bga-gold); background: var(--bga-card3); }
.bga-mode b {
  display: block;
  font-family: var(--bga-head);
  font-size: .88rem;
  font-weight: 900;
  color: var(--bga-ink);
}
.bga-mode small {
  display: block;
  font-size: .71rem;
  line-height: 1.4;
  color: var(--bga-mut);
  margin-top: 2px;
}

/* ── result screen ─────────────────────────────────────────────────────────
   This is chrome, so the arena comes back: this is the moment worth dressing. */
.bga-result { text-align: center; padding: 6px 0 2px; }
.bga-result .big {
  font-family: var(--bga-head);
  font-size: 2.9rem;
  font-weight: 900;
  line-height: 1;
  color: var(--bga-gold);
}
.bga-result h2 { font-size: 1.25rem; font-weight: 900; margin: 8px 0 3px; }
.bga-result p { color: var(--bga-mut); font-size: .85rem; margin: 0 0 12px; }
.bga-rgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; margin: 12px 0; }
.bga-rgrid div {
  background: var(--bga-card2);
  border: 1px solid var(--bga-line);
  border-radius: 10px;
  padding: 9px 5px;
}
.bga-rgrid strong {
  display: block;
  font-family: var(--bga-head);
  font-size: 1.3rem;
  font-weight: 900;
}
.bga-rgrid span {
  font-size: .66rem;
  font-weight: 800;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--bga-mut);
}
.bga-rgrid .c strong { color: var(--bga-green); }
.bga-rgrid .w strong { color: var(--bga-red); }
.bga-rgrid .p strong { color: var(--bga-gold); }

/* The wrong-answer review. The single highest-value screen in the product and
   the reason a run ends in a list rather than a number. */
.bga-review { text-align: left; margin-top: 14px; }
.bga-review > h3 {
  font-size: .8rem;
  font-weight: 900;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--bga-mut);
  margin-bottom: 8px;
}
.bga-rv {
  background: var(--bga-card2);
  border: 1px solid var(--bga-line);
  border-left: 3px solid var(--bga-red);
  border-radius: 10px;
  padding: 10px 12px;
  margin-bottom: 8px;
  font-size: .85rem;
  line-height: 1.55;
}
.bga-rv .qq { font-weight: 700; color: var(--bga-ink); margin-bottom: 5px; }
.bga-rv .yy { color: var(--bga-red); font-weight: 700; font-size: .8rem; }
.bga-rv .aa { color: var(--bga-green); font-weight: 700; font-size: .8rem; }
.bga-rv .ee { color: var(--bga-ink2); font-size: .8rem; margin-top: 5px; }

/* ── loading / empty ───────────────────────────────────────────────────────
   A skeleton, not a spinner: the shape of the question is on screen before the
   question is, so the first paint already looks like the thing being waited for. */
.bga-skel { padding: 4px 0; }
.bga-skel i {
  display: block;
  height: 13px;
  border-radius: 6px;
  background: var(--bga-card3);
  margin-bottom: 9px;
  animation: bgaPulse 1.2s ease-in-out infinite;
}
.bga-skel i.s2 { width: 72%; }
.bga-skel i.tall { height: 42px; }
@keyframes bgaPulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }
@media (prefers-reduced-motion: reduce) {
  .bga-skel i { animation: none; }
  .bga-sheet, .bga-scrim, .bga-prog i, .bga-ring .fg { transition: none; }
}

/* ── keeping the floating widgets off the run ──────────────────────────────
   At 390px the render sweep found FOUR floating widgets stacked into the last
   96px of an 844px screen, on top of the arena's action bar. Two of them —
   .gl-pill ("N learners today") and .dc-fab ("Daily done · N-day streak") — are
   gone for good now, removed at source in group-learning.js and
   daily-challenge.js because they covered page content on every phone.

   The two that remain are legitimate, so they get moved rather than removed.
   Raising .bga-act above them stops the run's own button being buried; lifting
   them here stops it being buried the other way round.

   This is positioning only. It is deliberately NOT a colour or theme override:
   that is the pattern that broke these pages in the first place. */
/* #xp-hud is deliberately NOT lifted. Raising it to clear the action bar only
   moved the collision: while the arena fills the screen the bar is stuck to the
   viewport bottom and z-index 100 covers #xp-hud harmlessly, but the moment you
   scroll to where the pane ENDS, the action bar comes to rest mid-screen and a
   lifted #xp-hud lands straight on the Next button. Left where it belongs, the
   two never occupy the same place: bar at the bottom during play, #xp-hud at the
   bottom afterwards. Being hidden under the action bar mid-run is fine — the
   HUD is already showing the score. */
body.bga-host #bg-lb-fab { bottom: 118px !important; }
body.bga-host #bg-lb-pop { bottom: 174px !important; }

/* The cookie bar used to be handled here, with an offset that lifted it clear of
   .bga-act. It is not handled here any more, and the reason is worth keeping:
   .bga-act is STICKY, so it comes to rest at the bottom of its own pane rather
   than at the bottom of the viewport. On /ctet-practice the pane ends mid-screen
   and the "clear" offset put the notice straight back on the action bar. There
   is no constant that is right on every page. cookie-consent.js now reserves its
   own height in the document instead, which every bottom-anchored element on
   every page benefits from without knowing about it. */

/* Nothing floats over a question while the clock is running. #bg-lb-fab is a
   44px circle parked at the right edge; lifted clear of the action bar it lands
   instead on the last OPTION, which on a bilingual question is 190px tall — so
   a tap meant for D opened the leaderboard. The engine already publishes
   data-bga-running for exactly this kind of decision (daily-challenge.js reads
   it to hold its overlay back), so the FAB simply steps aside for the duration
   of a run and comes back when it ends. */
html[data-bga-running="1"] #bg-lb-fab,
html[data-bga-running="1"] #bg-lb-pop { display: none !important; }

/* While the settings sheet is up it owns the screen. Nothing floating belongs
   on top of a modal surface the learner is reading. */
body.bga-sheet-open #xp-hud,
body.bga-sheet-open #bg-lb-fab,
body.bga-sheet-open #bg-lb-pop { display: none !important; }

.bga-toast {
  position: fixed;
  left: 50%;
  bottom: 84px;
  transform: translate(-50%, 12px);
  z-index: 130;
  background: var(--bga-chrome2);
  border: 1px solid var(--bga-gold);
  color: #ffe6ab;
  border-radius: 100px;
  padding: 8px 16px;
  font-size: .82rem;
  font-weight: 900;
  opacity: 0;
  visibility: hidden;
  transition: opacity .2s, transform .2s;
  pointer-events: none;
  max-width: 88vw;
  text-align: center;
}
.bga-toast.on { opacity: 1; visibility: visible; transform: translate(-50%, 0); }

/* ── wide screens ──────────────────────────────────────────────────────────
   The column stays 720px. A 1600px monitor does not make a 1600px line of text
   readable — it makes it worse. Desktop gets breathing room, not more width. */
@media (min-width: 900px) {
  .bga-card { padding: 18px 20px 16px; }
  .bga-modes { grid-template-columns: repeat(4, 1fr); }
}

/* On a wide screen the 720px column was floating in a third of a page of empty
   dark canvas, which read as a phone layout with spare room around it rather
   than a desktop layout. Framing it turns that emptiness into deliberate
   matting: the arena becomes a bounded board on the page instead of a column
   that ran out of content. The column itself does NOT get wider — a 1600px line
   of text is harder to read, not easier. */
@media (min-width: 1000px) {
  .bga {
    max-width: 860px;
    margin: 14px auto 22px;
    border: 1px solid var(--bga-line);
    border-radius: 18px;
    box-shadow: var(--bga-shadow);
  }
  /* Deliberately NOT `overflow:hidden` on the frame: it would make .bga the
     scroll container and the sticky HUD would stop tracking the viewport, so
     the timer would scroll away mid-run. The bars are rounded individually
     instead. */
  .bga-hud {
    box-shadow: none;
    border-radius: 17px 17px 0 0;
  }
  .bga-act { border-radius: 0 0 17px 17px; }
  /* A framed board is short enough to hold its options; the nudge is a phone
     affordance and would just be noise here. */
  .bga-more { display: none !important; }
}
@media (max-width: 380px) {
  .bga-score { font-size: .66rem; }
  .bga-btn { padding: 11px 13px; font-size: .88rem; }
}

/* ── banked-to-the-table confirmation ──────────────────────────────────────
   Written only after the server confirms the row, so this block is the one
   place on the result card that is allowed to say the points are safe. Muted
   on purpose: the score is the headline, this is the receipt. */
.bga-bank { margin: 10px 0 2px; }
.bga-bank:empty { display: none; }
.bga-bank-line {
  margin: 0;
  font-size: .84rem;
  color: var(--bga-mut);
  text-align: center;
}
.bga-bank-line strong { color: var(--bga-ink, inherit); }
.bga-bank-name {
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px solid var(--bga-line, rgba(128, 128, 128, .28));
  border-radius: 12px;
  text-align: left;
}
.bga-bank-name label {
  display: block;
  font-size: .78rem;
  font-weight: 600;
  margin-bottom: 6px;
}
.bga-bank-name > div { display: flex; gap: 8px; }
.bga-bank-name input {
  flex: 1 1 auto;
  min-width: 0;              /* a flex child will not shrink below its content without this */
  padding: 9px 11px;
  font: inherit;
  font-size: .88rem;
  border: 1px solid var(--bga-line, rgba(128, 128, 128, .35));
  border-radius: 9px;
  background: transparent;
  color: inherit;
}
.bga-bank-name .bga-btn { flex: 0 0 auto; }
.bga-bank-name small {
  display: block;
  margin-top: 6px;
  font-size: .72rem;
  color: var(--bga-mut);
}

/* ── auto-advance ──────────────────────────────────────────────────────────
   Only ever on a correct answer (see answer() for why). The bar is not
   decoration: an auto-advance with no visible clock is a page that moves on
   its own, which reads as a bug. This says what is about to happen and leaves
   time to stop it. */
.bga-btn.bga-auto { position: relative; overflow: hidden; }
.bga-btn.bga-auto::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  height: 3px;
  width: 100%;
  background: currentColor;
  opacity: .45;
  transform-origin: left center;
  animation: bga-auto-fill var(--bga-auto-ms, 1100ms) linear forwards;
}
@keyframes bga-auto-fill {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
/* Someone who has asked the system to stop animating has asked for this too —
   the timer still runs, it just stops advertising itself with movement. */
@media (prefers-reduced-motion: reduce) {
  .bga-btn.bga-auto::after { animation: none; opacity: .25; }
}

/* ── phones: the question and its options, together, without scrolling ─────
   The whole premise of a timed run is that you can see what you are answering
   and what you may answer with, at the same time. On a 390px screen the card
   was built from desktop spacing and the fourth option sat below the fold, so
   every question cost a scroll before it could be read — and a run of ten cost
   ten. Nothing here shrinks the TYPE, which is the one thing that must not get
   harder to read; it takes the space back from padding, gaps and margins, which
   nobody is reading. */
@media (max-width: 430px) {
  .bga-wrap { padding: 0 9px; }
  .bga-card { padding: 10px 11px 9px; margin: 6px 0; border-radius: 12px; }
  .bga-meta { gap: 4px; margin-bottom: 5px; }
  .bga-q { margin-bottom: 3px; line-height: 1.42; }
  /* Tamil keeps more of its leading than the English does — the script sits on
     a taller body and tightening it the same amount is what makes it blur. */
  .bga-q-ta { line-height: 1.62; margin-bottom: 1px; }
  .bga-opts { gap: 5px; margin-top: 7px; }
  .bga-opt { padding: 8px 10px; gap: 8px; }
  /* The explanation appears after an answer, when the options above it are
     already read — it can afford to be the compact one. */
  .bga-exp { padding: 8px 10px; }
}

/* ── the campaign points table ─────────────────────────────────────────────
   Open on load. A leaderboard nobody opens cannot make anyone want a place on
   it, and seeing yourself on it is the entire reason to bank a run. Collapsed
   state is remembered per device, so it makes its case once rather than every
   visit. */
.bga-board {
  max-width: 720px;
  margin: 10px auto 18px;
  padding: 0 12px;
}
.bga-board-tog {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  font: inherit;
  font-weight: 700;
  font-size: .88rem;
  color: var(--bga-ink);
  background: var(--bga-card);
  border: 1px solid var(--bga-line);
  border-radius: 12px;
  cursor: pointer;
}
.bga-board-tog .c {
  font-size: .76rem;
  font-weight: 600;
  color: var(--bga-mut);
  flex: 0 0 auto;
}
/* Collapsed is a tab, not a disappearance — the way back is always on screen. */
.bga-board.shut .bga-board-list,
.bga-board.shut .bga-board-empty { display: none; }
.bga-board.shut .bga-board-tog { border-radius: 999px; }

.bga-board-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  border: 1px solid var(--bga-line);
  border-radius: 12px;
  overflow: hidden;
}
.bga-board-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  font-size: .86rem;
  background: var(--bga-card);
  border-top: 1px solid var(--bga-line);
}
.bga-board-list li:first-child { border-top: 0; }
/* Your own row, findable without reading every name. */
.bga-board-list li.me {
  background: var(--bga-card2);
  font-weight: 700;
}
.bga-board-list .r {
  flex: 0 0 1.6em;
  color: var(--bga-mut);
  font-variant-numeric: tabular-nums;
}
.bga-board-list .n {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bga-board-list .p {
  flex: 0 0 auto;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.bga-board-empty {
  margin: 8px 0 0;
  padding: 12px;
  font-size: .84rem;
  color: var(--bga-mut);
  border: 1px dashed var(--bga-line);
  border-radius: 12px;
}
@media (max-width: 430px) {
  .bga-board { padding: 0 9px; margin: 8px auto 14px; }
  .bga-board-list li { padding: 8px 10px; font-size: .84rem; }
}
