/* ============================================================
   Ulearn Child Game Dashboard — Brawl Stars-style theme
   Ported from claude.ai/design bundle on 2026-05-16.
   Source files (combined here):
     - tokens.css (design system variables)
     - game-styles.css (component & screen layout)
   Scoped to ody.child-dashboard-active for the html/body/* /
   button universal rules so this file doesn't bleed into the rest
   of Ulearn. Class selectors are left unscoped because their
   names (.dock-btn, .brawler-card, etc.) are specific enough not
   to collide with app.css. The single shared class name (.label)
   cascades cleanly — dock-btn / quiz-nav selectors win on
   specificity.
   ============================================================ */
/* ============================================================
   Ulearn Design System â€” Colors & Type
   ============================================================
   Cream canvas, sunny yellow lead, warm orange accent,
   deep navy ink, mid-blue support. Modern neutral sans.
   ============================================================ */

/* Webfonts â€” substituted from Google Fonts.
   FLAGGED: substitution, awaiting brand-owned font files.
   - Plus Jakarta Sans: friendly geometric sans â€” body & UI
   - Fraunces (display, soft optical): used SPARINGLY for marketing hero only
   - JetBrains Mono: code/numerals
*/
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Lilita+One&display=swap');

:root {
  /* ---------- Brand core (sampled directly from owl logo) ---------- */
  --brand-yellow:        #F0C040;  /* primary â€” graduation cap */
  --brand-yellow-deep:   #E5AE2A;
  --brand-yellow-soft:   #FFE38A;
  --brand-orange:        #F09020;  /* book pages */
  --brand-orange-deep:   #D9761A;
  --brand-orange-soft:   #FFC082;
  --brand-navy:          #0B1E3F;  /* owl body â€” sampled #001030 lifted for legibility */
  --brand-navy-deep:     #050F22;
  --brand-blue:          #106090;  /* mid-blue accent */
  --brand-blue-soft:     #B9D9EE;

  /* ---------- Neutrals (cream-tinted, not gray-cold) ---------- */
  --cream:               #FBF3DC;  /* canvas â€” the brief's "cream that matches the logo" */
  --cream-deep:          #F5E9C4;  /* secondary surface */
  --cream-rim:           #ECDDB0;  /* hairline borders on cream */
  --paper:               #FFFCF3;  /* lightest surface, cards on cream */
  --ink:                 #0B1E3F;  /* === --brand-navy, primary text */
  --ink-2:               #2A3B5C;  /* secondary text */
  --ink-3:               #5A6B85;  /* tertiary text, captions */
  --ink-4:               #8A98AE;  /* disabled, placeholder */
  --rule:                #E3D8B6;  /* divider lines on cream */
  --rule-strong:         #C9BC93;

  /* ---------- Semantic ---------- */
  --success:             #2E8B5E;
  --success-soft:        #D7EFE0;
  --warning:             #D9761A;  /* aligns with brand-orange-deep */
  --warning-soft:        #FFE0BE;
  --danger:              #C0392B;
  --danger-soft:         #F8D7D2;
  --info:                #106090;
  --info-soft:           #D6E9F4;

  /* ---------- Foreground / Background tokens ---------- */
  --bg:                  var(--cream);
  --bg-elevated:         var(--paper);
  --bg-sunk:             var(--cream-deep);
  --fg:                  var(--ink);
  --fg-muted:            var(--ink-3);
  --fg-subtle:           var(--ink-4);
  --border:              var(--rule);
  --border-strong:       var(--rule-strong);
  --accent:              var(--brand-yellow);
  --accent-fg:           var(--brand-navy);

  /* ---------- Type scale ---------- */
  --font-sans:    'Plus Jakarta Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-display: 'Plus Jakarta Sans', ui-sans-serif, system-ui, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  /* fluid display sizes */
  --fs-display:   clamp(48px, 6vw, 88px);
  --fs-h1:        clamp(36px, 4.4vw, 60px);
  --fs-h2:        clamp(28px, 3vw, 40px);
  --fs-h3:        24px;
  --fs-h4:        20px;
  --fs-body-lg:   18px;
  --fs-body:      16px;
  --fs-body-sm:   14px;
  --fs-caption:   13px;
  --fs-micro:     12px;

  /* line height */
  --lh-tight:     1.05;
  --lh-snug:      1.2;
  --lh-normal:    1.5;
  --lh-relaxed:   1.65;

  /* tracking */
  --tr-tight:     -0.02em;
  --tr-normal:    0;
  --tr-wide:      0.04em;
  --tr-eyebrow:   0.12em;

  /* weights */
  --w-regular: 400;
  --w-medium:  500;
  --w-semi:    600;
  --w-bold:    700;
  --w-black:   800;

  /* ---------- Spacing (4px base) ---------- */
  --s-0:   0;
  --s-1:   4px;
  --s-2:   8px;
  --s-3:   12px;
  --s-4:   16px;
  --s-5:   20px;
  --s-6:   24px;
  --s-8:   32px;
  --s-10:  40px;
  --s-12:  48px;
  --s-16:  64px;
  --s-20:  80px;
  --s-24:  96px;

  /* ---------- Radii (soft & rounded shape language) ---------- */
  --r-xs:  6px;
  --r-sm:  10px;
  --r-md:  14px;
  --r-lg:  20px;
  --r-xl:  28px;
  --r-2xl: 36px;
  --r-pill: 999px;

  /* ---------- Shadows (warm-tinted, not gray) ---------- */
  --shadow-xs:  0 1px 2px rgba(11, 30, 63, 0.06);
  --shadow-sm:  0 2px 6px rgba(11, 30, 63, 0.06), 0 1px 2px rgba(11, 30, 63, 0.04);
  --shadow-md:  0 6px 18px -4px rgba(11, 30, 63, 0.10), 0 2px 6px rgba(11, 30, 63, 0.05);
  --shadow-lg:  0 18px 40px -8px rgba(11, 30, 63, 0.14), 0 6px 14px rgba(11, 30, 63, 0.06);
  --shadow-xl:  0 30px 60px -12px rgba(11, 30, 63, 0.18), 0 10px 22px rgba(11, 30, 63, 0.08);
  /* Sticker shadow â€” used on student/homeschool dashboards for playful affordance */
  --shadow-sticker: 0 4px 0 0 var(--brand-navy);

  /* focus */
  --ring: 0 0 0 3px rgba(240, 192, 64, 0.55);
  --ring-blue: 0 0 0 3px rgba(16, 96, 144, 0.45);

  /* motion */
  --ease-out:    cubic-bezier(.2,.7,.2,1);
  --ease-spring: cubic-bezier(.34,1.56,.64,1);
  --dur-fast:    120ms;
  --dur-base:    200ms;
  --dur-slow:    320ms;
}

/* ============================================================
   Element-level semantic styles
   Apply by adding classes (.h1, .body, .eyebrow) OR via the
   element selectors below where appropriate.
   ============================================================ */

html, body {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-normal);
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.display, h1.display {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: var(--w-black);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-tight);
  color: var(--ink);
  text-wrap: balance;
}

.h1, h1 {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: var(--w-bold);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-tight);
  color: var(--ink);
  text-wrap: balance;
}

.h2, h2 {
  font-size: var(--fs-h2);
  font-weight: var(--w-bold);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-tight);
  color: var(--ink);
}

.h3, h3 {
  font-size: var(--fs-h3);
  font-weight: var(--w-semi);
  line-height: var(--lh-snug);
  color: var(--ink);
}

.h4, h4 {
  font-size: var(--fs-h4);
  font-weight: var(--w-semi);
  line-height: var(--lh-snug);
  color: var(--ink);
}

.body-lg {
  font-size: var(--fs-body-lg);
  line-height: var(--lh-relaxed);
  color: var(--ink-2);
}

.body, p {
  font-size: var(--fs-body);
  line-height: var(--lh-normal);
  color: var(--ink-2);
  text-wrap: pretty;
}

.body-sm {
  font-size: var(--fs-body-sm);
  line-height: var(--lh-normal);
  color: var(--ink-3);
}

.caption {
  font-size: var(--fs-caption);
  line-height: var(--lh-normal);
  color: var(--ink-3);
}

.eyebrow {
  font-size: var(--fs-micro);
  font-weight: var(--w-bold);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--brand-blue);
}

.code, code, kbd, samp, pre {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

/* Numeric tabular figures for stats / dashboards */
.numeric {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}


/* ============================================================
   Game-style child dashboard â€” Brawl Stars vocabulary
   Cream/yellow/navy/blue from Ulearn, dialed to "playful 10".
   (Lilita One @import moved to the top of this combined file so it
    precedes all other rules — browsers ignore @imports that come
    after non-@import rules.)
   ============================================================ */

:root {
  --game-sky-top:    #2A8FE0;
  --game-sky-mid:    #1F6FB8;
  --game-sky-bot:    #0E3F75;
  --game-deep:       #07254B;
  --game-gold:       #F0C040;
  --game-gold-deep:  #C18C12;
  --game-orange:     #F09020;
  --game-orange-deep:#A85A0C;
  --game-blue:       #1E9CE8;
  --game-blue-deep:  #0D5C9E;
  --game-mint:       #4ED6B8;
  --game-pink:       #E96AA8;
  --game-purple:     #8B5DC7;
  --game-red:        #E04848;
  --game-red-deep:   #8C1F1F;
  --navy:            #0B1E3F;
  --navy-2:          #122A55;
  --paper:           #FFFCF3;
  --cream:           #FBF3DC;
  --hud-bg:          rgba(7, 32, 65, 0.78);
  --hud-rim:         rgba(255, 255, 255, 0.08);
  --shadow-3d:       0 4px 0 0 rgba(0,0,0,0.35);
  --shadow-3d-lg:    0 6px 0 0 rgba(0,0,0,0.40);
  --font-game:       'Lilita One', 'Plus Jakarta Sans', system-ui, sans-serif;
  --font-ui:         'Plus Jakarta Sans', system-ui, sans-serif;
}

body.child-dashboard-active *, body.child-dashboard-active *::before, body.child-dashboard-active *::after { box-sizing: border-box; }
body.child-dashboard-active { margin: 0; padding: 0; min-height: 100%; font-family: var(--font-ui); color: var(--paper); }
body.child-dashboard-active { overflow: hidden; }

/* Hide the main app navbar while the kid dashboard is active — it
   overlaps the game-play back button + the HUD stats and isn't part
   of the kid UX. A "MENU" button in the kid screens (data-cgd-action
   = "toggle-nav") flips body.child-nav-open which un-hides it. */
body.child-dashboard-active #navbar { display: none !important; }
body.child-dashboard-active.child-nav-open #navbar {
  display: flex !important;
  position: fixed; top: 0; left: 0; right: 0;
  z-index: 200; /* above overlays (.overlay = z 50, .game-fullscreen
                   doesn't set its own z) so the menu can be popped
                   over anything on screen. */
}
/* Floating "MENU" pill that lives on the kid dashboard's home and
   game-play screens. Tap → toggles the navbar in/out. */
.kid-nav-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(11,30,63,0.7);
  border: 2px solid rgba(255,227,138,0.4);
  border-radius: 999px;
  padding: 6px 12px 6px 10px;
  color: #FFE38A;
  font-family: var(--font-game);
  font-size: 12px;
  letter-spacing: 0.06em;
  cursor: pointer;
  line-height: 1;
}
.kid-nav-toggle:hover { background: rgba(11,30,63,0.9); }
.kid-nav-toggle .bars {
  display: inline-flex; flex-direction: column; gap: 3px;
}
.kid-nav-toggle .bars i {
  display: block; width: 14px; height: 2px;
  background: #FFE38A; border-radius: 1px;
}
/* Button reset — wrapped in :where() so its specificity is (0,0,0).
   Past attempts to put this rule at (0,1,2) created a specificity
   trap that overrode per-button styles at (0,1,0). Dropping
   properties one by one (background, border, padding) was a treadmill
   — the real fix is :where(), which lets per-button rules always win
   while still applying the reset to bare/unstyled buttons. */
:where(body.child-dashboard-active button) {
  font-family: inherit;
  cursor: pointer;
  color: inherit;
}

/* ----- Screen ----- */
.screen {
  position: fixed; inset: 0;
  background:
    radial-gradient(120% 80% at 50% 0%,  #4AB0F0 0%, transparent 55%),
    radial-gradient(140% 100% at 50% 100%, #061C3A 0%, transparent 60%),
    linear-gradient(180deg, var(--game-sky-top) 0%, var(--game-sky-mid) 45%, var(--game-sky-bot) 100%);
  overflow: hidden;
  display: grid;
  /* Bottom row sizes to its content (auto) so the owl pass, daily-
   * goal banner, and play block can render at full height instead of
   * being clipped — middle (1fr) shrinks to fit, character scales
   * down via the responsive breakpoints below. */
  grid-template-rows: 76px 1fr auto;
  grid-template-columns: 124px 1fr 124px;
  gap: 0;
  /* Padding respects safe-area insets on phones with notches / home
   * bars. max() keeps the 16-px baseline on devices without insets. */
  padding:
    max(16px, env(safe-area-inset-top))
    max(16px, env(safe-area-inset-right))
    max(16px, env(safe-area-inset-bottom))
    max(16px, env(safe-area-inset-left));
}

/* Touch behaviour for the whole kid dashboard. manipulation drops
 * the 300-ms tap delay and disables double-tap zoom on iOS; the
 * tap-highlight rule removes the grey rectangle iOS Safari draws
 * on touch. */
.screen, .screen * { -webkit-tap-highlight-color: transparent; }
.dock-btn, .play-btn, .chip, button { touch-action: manipulation; }

/* sky pattern + spotlight */
.screen::before {
  content: "";
  position: absolute; inset: 0;
  background-image:
    radial-gradient(2px 2px at 8% 18%, rgba(255,255,255,0.5), transparent 50%),
    radial-gradient(2px 2px at 22% 65%, rgba(255,255,255,0.35), transparent 50%),
    radial-gradient(3px 3px at 78% 22%, rgba(255,255,255,0.45), transparent 50%),
    radial-gradient(2px 2px at 88% 70%, rgba(255,255,255,0.30), transparent 50%),
    radial-gradient(2px 2px at 44% 12%, rgba(255,255,255,0.40), transparent 50%),
    radial-gradient(2px 2px at 62% 85%, rgba(255,255,255,0.30), transparent 50%),
    radial-gradient(2px 2px at 12% 88%, rgba(255,255,255,0.35), transparent 50%);
  pointer-events: none;
  animation: twinkle 5s ease-in-out infinite alternate;
}
.screen::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(60% 50% at 50% 55%, rgba(255,220,140,0.30) 0%, transparent 60%);
}

@keyframes twinkle {
  0%, 100% { opacity: 0.6; } 50% { opacity: 1; }
}

/* owl silhouette pattern overlay */
.bg-owls {
  position: absolute; inset: 0; pointer-events: none; opacity: 0.07;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='90' height='90' viewBox='0 0 24 24' fill='%23ffffff'><path d='M12 2a4 4 0 0 0-3 7c-1 1-2 3-2 5a5 5 0 0 0 10 0c0-2-1-4-2-5a4 4 0 0 0-3-7zm-2 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z'/></svg>");
  background-size: 120px 120px;
  transform: rotate(-8deg) scale(1.2);
}

/* ----- HUD ----- */
.hud { grid-column: 1 / -1; grid-row: 1;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  position: relative; z-index: 5;
}
.hud-left, .hud-right { display: flex; align-items: center; gap: 10px; }

.profile-tab {
  display: grid; grid-template-columns: 56px 1fr; gap: 0;
  background: var(--hud-bg);
  border: 2px solid rgba(255,255,255,0.12);
  border-radius: 14px;
  padding: 4px 12px 4px 4px;
  align-items: center;
  box-shadow: var(--shadow-3d);
  min-width: 220px;
}
.profile-tab .avatar {
  width: 52px; height: 52px; border-radius: 10px;
  background: linear-gradient(180deg, #2C7AC9, #1A4E8C);
  border: 2px solid #0A2C57;
  display: grid; place-items: center;
  box-shadow: inset 0 -3px 0 rgba(0,0,0,0.25), inset 0 3px 0 rgba(255,255,255,0.15);
}
.profile-tab .avatar img { width: 44px; height: 44px; object-fit: contain; }
.profile-tab .name { font-family: var(--font-game); font-size: 18px; letter-spacing: 0.5px; line-height: 1; color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4); padding-left: 10px; }
.profile-tab .tag { font-family: var(--font-ui); font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: #FFD478; padding-left: 10px; margin-top: 2px; opacity: 0.95; }

/* currency chip â€” pill with icon overlapping left */
.chip {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--hud-bg);
  border: 2px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  padding: 4px 14px 4px 4px;
  font-family: var(--font-game); font-size: 18px; color: #fff;
  letter-spacing: 0.5px; line-height: 1;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  box-shadow: var(--shadow-3d);
  min-width: 90px;
}
.chip .ico {
  width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center;
  border: 2px solid #0A1A30;
  box-shadow: inset 0 -3px 0 rgba(0,0,0,0.30), inset 0 3px 0 rgba(255,255,255,0.25);
  flex-shrink: 0;
  overflow: hidden;
}
/* Cap any chip icon's SVG to fit inside the rounded chip wrapper.
 * Star points reach the bounding box edge; corner regions of the
 * bounding box are empty and land in the clipped portion of the
 * circle (overflow:hidden above). 88 % gives a full visual fit.
 * The star SVG itself is geometrically centered (see ICONS.star),
 * so no per-chip transform is needed — every chip's icon scales
 * as one self-contained image at every breakpoint. */
.chip .ico > svg { max-width: 88%; max-height: 88%; display: block; }
.chip.coin .ico { background: radial-gradient(circle at 35% 30%, #FFE48A, #E5A91A 70%, #A86E0A); }
.chip.gem .ico  { background: radial-gradient(circle at 35% 30%, #B3F5C5, #34C46F 70%, #115E2C); }
.chip.streak .ico { background: radial-gradient(circle at 35% 30%, #FFD27A, #E04848 70%, #6B1414); }
/* XP chip is a single compound SVG (disk + highlight + shadow +
 * star). Strip the wrapper background / border / inset so it doesn't
 * draw a second disk underneath the SVG, and let the SVG fill the
 * whole wrapper at any size. */
.chip.xp .ico {
  background: none;
  border: none;
  box-shadow: none;
}
.chip.xp .ico > svg { max-width: 100%; max-height: 100%; width: 100%; height: 100%; }
.chip.xp.pop, .quiz-xp-counter.pop, .game-xp-pill.pop {
  animation: quizCoinPop 380ms ease-out;
}
.chip .num { font-variant-numeric: tabular-nums; }
.chip .plus {
  width: 22px; height: 22px; border-radius: 50%;
  background: #34C46F; border: 1.5px solid #0A1A30;
  display: grid; place-items: center; color: #fff;
  font-family: var(--font-game); font-size: 18px; line-height: 0.9;
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.25), inset 0 2px 0 rgba(255,255,255,0.20);
  margin-left: 2px;
}

.menu-btn {
  width: 56px; height: 56px; border-radius: 14px;
  background: var(--hud-bg); border: 2px solid rgba(255,255,255,0.12);
  display: grid; place-items: center; color: #fff;
  box-shadow: var(--shadow-3d);
}
/* Admin star — visible only for the dev uid via _isAdmin() in JS.
   Gold-tinted so it reads as "secret" next to the regular hamburger. */
.menu-btn.admin-btn {
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  border-color: rgba(11, 30, 63, 0.25);
  color: #0B1E3F;
  font-family: var(--font-game);
  font-size: 28px;
  line-height: 1;
}

/* ----- Admin catalog overlay (rewards + badges audit) ----- */
.admin-summary {
  display: flex; flex-wrap: wrap; gap: 14px;
  font-family: var(--font-ui); font-weight: 700;
  font-size: 12px;
  color: rgba(255,255,255,0.85);
  background: rgba(11,30,63,0.4);
  border: 2px solid rgba(255,255,255,0.15);
  border-radius: 12px;
  padding: 10px 14px;
  margin-bottom: 14px;
}
.admin-summary span { letter-spacing: 0.04em; }
.admin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 10px;
}
.admin-card {
  background: rgba(255,252,243,0.06);
  border: 2.5px solid rgba(255,255,255,0.2);
  border-radius: 14px;
  padding: 10px;
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 10px;
  align-items: center;
  color: #fff;
}
.admin-card-img {
  width: 56px; height: 56px;
  background: rgba(255,255,255,0.08);
  border-radius: 10px;
  display: grid; place-items: center;
  overflow: hidden;
}
.admin-card-img img {
  width: 80%; height: 80%; object-fit: contain;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
}
.admin-card-body { min-width: 0; }
.admin-card-name {
  font-family: var(--font-game); font-size: 13px;
  letter-spacing: 0.4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  margin-bottom: 4px;
}
.admin-card-meta {
  display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
  margin-bottom: 6px;
}
.admin-tier {
  display: inline-block;
  font-family: var(--font-ui); font-size: 9px; font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #0B1E3F;
  border-radius: 6px;
  padding: 2px 6px;
}
.admin-type {
  font-family: var(--font-ui); font-size: 10px; font-weight: 700;
  opacity: 0.75;
}
.admin-card-stats {
  display: flex; gap: 8px; align-items: center;
  font-family: var(--font-game); font-size: 11px;
  letter-spacing: 0.3px;
}
.admin-card-stats svg { width: 14px; height: 14px; vertical-align: -2px; }
.admin-card-criterion {
  font-family: var(--font-ui); font-size: 11px;
  opacity: 0.75;
  line-height: 1.3;
}

/* ----- Side docks ----- */
.dock { grid-row: 2; display: flex; flex-direction: column; gap: 14px; padding-top: 30px;
  position: relative; z-index: 4; }
.dock.left { grid-column: 1; align-items: flex-start; }
.dock.right { grid-column: 3; align-items: flex-end; }

.dock-btn {
  width: 96px; height: 96px;
  display: grid; grid-template-rows: 1fr auto; place-items: center;
  border-radius: 18px;
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  box-shadow: 0 5px 0 0 var(--navy), 0 8px 18px -4px rgba(0,0,0,0.4);
  position: relative;
  transition: transform 100ms ease, box-shadow 100ms ease;
  cursor: pointer;
}
.dock-btn:hover { transform: translateY(-2px); box-shadow: 0 7px 0 0 var(--navy), 0 10px 22px -4px rgba(0,0,0,0.5); }
.dock-btn:active { transform: translateY(3px); box-shadow: 0 2px 0 0 var(--navy); }
.dock-btn .glyph { font-size: 36px; line-height: 1; filter: drop-shadow(0 2px 0 rgba(0,0,0,0.15)); }
.dock-btn .label {
  font-family: var(--font-game); font-size: 13px; letter-spacing: 0.5px;
  color: var(--navy); line-height: 1; margin-bottom: 8px;
  text-shadow: 0 1px 0 rgba(255,255,255,0.6);
}
.dock-btn.color-shop  { background: linear-gradient(180deg,#FFE38A,#F0B520); }
.dock-btn.color-brawl { background: linear-gradient(180deg,#FFC182,#F0742A); }
.dock-btn.color-news  { background: linear-gradient(180deg,#B0E5FF,#3FA6E5); }
.dock-btn.color-fam   { background: linear-gradient(180deg,#FFB8C7,#E9527A); }
.dock-btn.color-club  { background: linear-gradient(180deg,#C9F2D6,#3DBE6B); }

/* Daily-goal banner — takes over the DAILY REVIEW slot when the
   kid has at least one parent-assigned course. Same navy gradient
   shell as .event so the layout doesn't shift; an extra column
   of horizontal goal boxes on the right. */
.event.event-goals {
  /* badge / title block / goal-boxes row */
  grid-template-columns: 80px 1fr auto;
}
.event.event-goals .badge-icon {
  background: linear-gradient(180deg, #7B5BD8, #4A2BB8);
}
.event.event-goals .goal-event-text { min-width: 0; }
.goal-event-boxes {
  display: inline-flex; align-items: stretch; gap: 8px;
  flex-wrap: wrap;
  max-width: min(60vw, 540px);
  justify-content: flex-end;
}
.goal-box {
  display: inline-grid; grid-template-columns: 22px 1fr;
  gap: 6px; align-items: center;
  min-width: 130px;
  padding: 7px 10px 7px 7px;
  border-radius: 12px;
  border: 2.5px solid var(--navy);
  background: linear-gradient(180deg, #FFFCF3, #F2E4B6);
  box-shadow: 0 3px 0 0 var(--navy);
  cursor: pointer;
  transition: transform 100ms ease, box-shadow 100ms ease, background 120ms ease;
  font-family: var(--font-ui);
  text-align: left;
}
.goal-box:hover  { transform: translateY(-1px); box-shadow: 0 4px 0 0 var(--navy); }
.goal-box:active { transform: translateY(2px);  box-shadow: 0 1px 0 0 var(--navy); }
.goal-box.is-checked {
  background: linear-gradient(180deg, #C9F2D6, #5ED4A8);
}
.goal-box-tick {
  width: 20px; height: 20px;
  border-radius: 4px;
  background: #fff;
  border: 2px solid var(--navy);
  display: grid; place-items: center;
  font-family: var(--font-game); font-size: 14px; color: var(--navy);
  line-height: 1;
}
.goal-box.is-checked .goal-box-tick {
  background: #34C46F;
  color: #fff;
}
.goal-box-meta {
  display: flex; flex-direction: column; gap: 2px;
  min-width: 0;
}
.goal-box-name {
  font-family: var(--font-game); font-size: 12px;
  color: var(--navy); line-height: 1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 140px;
}
.goal-box-progress {
  font-family: var(--font-game); font-size: 11px;
  color: rgba(11, 30, 63, 0.7); line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* Celebratory toast that pops bottom-center when the kid completes
   today's goal for a deck. Auto-dismisses after ~2.4s. */
.goal-done-toast {
  position: fixed; bottom: 24px; left: 50%;
  transform: translate(-50%, 30px);
  z-index: 9998;
  min-width: 260px; max-width: 380px;
  background: linear-gradient(180deg, #FFFCF3 0%, #FFE38A 100%);
  border: 4px solid var(--navy);
  border-radius: 22px;
  box-shadow: 0 8px 0 0 var(--navy), 0 20px 40px rgba(0, 0, 0, 0.35);
  padding: 14px 20px;
  text-align: center;
  color: var(--navy);
  opacity: 0;
  animation: goal-done-in 320ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
.goal-done-toast.is-dismissing { animation: goal-done-out 360ms ease-in forwards; }
@keyframes goal-done-in {
  from { opacity: 0; transform: translate(-50%, 30px) scale(0.85); }
  to   { opacity: 1; transform: translate(-50%, 0)    scale(1); }
}
@keyframes goal-done-out {
  from { opacity: 1; transform: translate(-50%, 0)    scale(1); }
  to   { opacity: 0; transform: translate(-50%, -20px) scale(0.95); }
}
.goal-done-head {
  font-family: var(--font-game); font-size: 22px;
  letter-spacing: 0.8px; line-height: 1;
  text-shadow: 0 2px 0 rgba(255,255,255,0.7);
  margin-bottom: 4px;
}
.goal-done-sub {
  font-family: var(--font-ui); font-weight: 700;
  font-size: 13px; opacity: 0.7;
  margin-bottom: 10px;
}
.goal-done-rewards {
  display: inline-flex; gap: 8px; flex-wrap: wrap; justify-content: center;
}
.goal-done-rewards span {
  display: inline-block;
  font-family: var(--font-game); font-size: 14px;
  background: #fff; border: 2px solid var(--navy);
  border-radius: 999px; padding: 4px 12px;
  box-shadow: 0 2px 0 0 var(--navy);
}

/* Badge detail modal — backdrop dim + centered card. Open via
   data-cgd-action="badge-detail" on a tile; backdrop or ✕ closes. */
.badge-detail-backdrop {
  position: fixed; inset: 0; z-index: 70;
  background: rgba(7, 20, 45, 0.65);
  display: grid; place-items: center;
  padding: 24px;
  animation: badge-detail-fade 180ms ease-out both;
}
@keyframes badge-detail-fade { from { opacity: 0; } to { opacity: 1; } }
.badge-detail-card {
  position: relative;
  width: min(360px, 100%);
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 4px solid var(--navy);
  border-radius: 22px;
  padding: 22px 22px 18px;
  text-align: center;
  color: var(--navy);
  box-shadow: 0 8px 0 0 var(--navy), 0 20px 40px rgba(0, 0, 0, 0.5);
  animation: badge-detail-pop 240ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes badge-detail-pop {
  from { transform: scale(0.85); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}
.badge-detail-card .bd-close {
  position: absolute; top: 12px; right: 12px;
  width: 32px; height: 32px;
  border-radius: 50%;
  border: 2px solid var(--navy);
  background: linear-gradient(180deg, #FFB8C7, #E04848);
  color: #fff;
  font-family: var(--font-game); font-size: 14px;
  line-height: 1; padding: 0;
  box-shadow: 0 2px 0 0 var(--navy);
  cursor: pointer;
}
.badge-detail-card .bd-close:active {
  transform: translateY(1px);
  box-shadow: 0 1px 0 0 var(--navy);
}
.badge-detail-card .bd-medal {
  width: 110px; height: 110px;
  margin: 4px auto 12px;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  filter: drop-shadow(0 4px 4px rgba(0,0,0,0.3));
}
.badge-detail-card .bd-medal.is-locked {
  filter: grayscale(1) opacity(0.5) drop-shadow(0 4px 4px rgba(0,0,0,0.3));
}
.badge-detail-card .bd-name {
  font-family: var(--font-game); font-size: 24px;
  letter-spacing: 0.5px;
  text-shadow: 0 2px 0 rgba(255,255,255,0.5);
  margin-bottom: 8px;
}
.badge-detail-card .bd-tier {
  display: inline-block;
  font-family: var(--font-ui); font-size: 10px; font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #fff;
  border-radius: 8px;
  padding: 3px 10px;
  margin-bottom: 12px;
}
.badge-detail-card .bd-criterion {
  font-family: var(--font-ui); font-weight: 700;
  font-size: 14px;
  line-height: 1.35;
  opacity: 0.85;
  margin-bottom: 14px;
}
.badge-detail-card .bd-status {
  font-family: var(--font-game); font-size: 14px;
  letter-spacing: 0.4px;
  color: var(--navy);
  opacity: 0.7;
  padding: 6px 12px;
  background: rgba(11, 30, 63, 0.08);
  border-radius: 999px;
  display: inline-block;
}
.badge-detail-card .bd-status.is-earned {
  background: linear-gradient(180deg, #B3F5C5, #34C46F);
  color: var(--navy);
  opacity: 1;
  border: 2px solid var(--navy);
  text-shadow: 0 1px 0 rgba(255,255,255,0.4);
}
/* Make badge tiles read as buttons. */
.badge-tile[role="button"] {
  cursor: pointer;
  transition: transform 120ms ease;
}
.badge-tile[role="button"]:hover {
  transform: translateY(-2px);
}
.badge-tile[role="button"]:active {
  transform: translateY(0);
}

/* Badge-unlocked toast — gold gradient, badge artwork on the left,
   slides up from the bottom. Queued in JS so multi-unlocks stack
   sequentially rather than overlapping. */
.badge-earned-toast {
  position: fixed; bottom: 24px; left: 50%;
  transform: translate(-50%, 30px);
  z-index: 9999;
  min-width: 280px; max-width: 420px;
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 100%);
  border: 4px solid var(--navy);
  border-radius: 22px;
  box-shadow: 0 8px 0 0 var(--navy), 0 20px 40px rgba(0, 0, 0, 0.4);
  padding: 12px 16px;
  display: grid;
  grid-template-columns: 56px 1fr;
  align-items: center;
  gap: 12px;
  color: var(--navy);
  opacity: 0;
  animation: goal-done-in 320ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
.badge-earned-toast.is-dismissing { animation: goal-done-out 360ms ease-in forwards; }
.badge-earned-toast .bet-icon {
  width: 56px; height: 56px;
  background: rgba(255,252,243,0.6);
  border: 2.5px solid var(--navy);
  border-radius: 14px;
  display: grid; place-items: center;
  box-shadow: 0 3px 0 0 var(--navy);
}
.badge-earned-toast .bet-icon img {
  width: 80%; height: 80%; object-fit: contain;
  image-rendering: pixelated;
}
.badge-earned-toast .bet-head {
  font-family: var(--font-game); font-size: 12px; letter-spacing: 1px;
  line-height: 1; opacity: 0.7; margin-bottom: 3px;
}
.badge-earned-toast .bet-name {
  font-family: var(--font-game); font-size: 20px;
  letter-spacing: 0.6px; line-height: 1;
  text-shadow: 0 2px 0 rgba(255,255,255,0.5);
  margin-bottom: 3px;
}
.badge-earned-toast .bet-sub {
  font-family: var(--font-ui); font-weight: 700;
  font-size: 12px; opacity: 0.75;
  line-height: 1.2;
}

/* Work-ahead lock warning — pops when the kid taps a course whose
   daily quota is already done and they haven't finished SRS reviews
   yet. Red gradient to read as "blocked", same shape language as
   the goal-done toast so the kid recognises it as a one-shot popup. */
.lock-warn-toast {
  position: fixed; bottom: 24px; left: 50%;
  transform: translate(-50%, 30px);
  z-index: 9998;
  min-width: 260px; max-width: 380px;
  background: linear-gradient(180deg, #FFEAEA 0%, #FF8E8E 100%);
  border: 4px solid var(--navy);
  border-radius: 22px;
  box-shadow: 0 8px 0 0 var(--navy), 0 20px 40px rgba(0, 0, 0, 0.35);
  padding: 14px 20px;
  text-align: center;
  color: var(--navy);
  opacity: 0;
  animation: goal-done-in 320ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
.lock-warn-toast.is-dismissing { animation: goal-done-out 360ms ease-in forwards; }
.lock-warn-head {
  font-family: var(--font-game); font-size: 20px;
  letter-spacing: 0.8px; line-height: 1;
  text-shadow: 0 2px 0 rgba(255,255,255,0.6);
  margin-bottom: 4px;
}
.lock-warn-sub {
  font-family: var(--font-ui); font-weight: 700;
  font-size: 13px; opacity: 0.85;
}

/* "ALL REVIEWS DONE!" — fires once per day when the kid clears
   every due review across every deck. Bigger and brighter than
   the per-deck goal toast, and shows a character unlock card
   inline when the 1/7 random unlock hits. */
.all-review-toast {
  position: fixed; bottom: 32px; left: 50%;
  transform: translate(-50%, 30px);
  z-index: 9999;
  min-width: 320px; max-width: 420px;
  background: linear-gradient(180deg, #FFFCF3 0%, #FFE38A 70%, #F0C040 100%);
  border: 5px solid var(--navy);
  border-radius: 28px;
  box-shadow: 0 10px 0 0 var(--navy), 0 24px 50px rgba(0, 0, 0, 0.4);
  padding: 18px 22px;
  text-align: center;
  color: var(--navy);
  opacity: 0;
  animation: all-review-in 380ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
.all-review-toast.is-dismissing {
  animation: all-review-out 460ms ease-in forwards;
}
@keyframes all-review-in {
  from { opacity: 0; transform: translate(-50%, 30px) scale(0.75); }
  to   { opacity: 1; transform: translate(-50%, 0)    scale(1); }
}
@keyframes all-review-out {
  from { opacity: 1; transform: translate(-50%, 0)     scale(1); }
  to   { opacity: 0; transform: translate(-50%, -30px) scale(0.95); }
}
.all-review-head {
  font-family: var(--font-game); font-size: 26px;
  letter-spacing: 1px; line-height: 1;
  text-shadow: 0 3px 0 rgba(255,255,255,0.7);
  margin-bottom: 12px;
}
.all-review-rewards {
  display: inline-flex; gap: 8px; flex-wrap: wrap; justify-content: center;
  margin-bottom: 6px;
}
.all-review-rewards span {
  display: inline-block;
  font-family: var(--font-game); font-size: 16px;
  background: #fff; border: 2.5px solid var(--navy);
  border-radius: 999px; padding: 5px 14px;
  box-shadow: 0 3px 0 0 var(--navy);
}
.all-review-char {
  margin-top: 12px;
  padding: 10px 12px;
  background: linear-gradient(180deg, #D5BFFF, #7B5BD8);
  border: 3px solid var(--navy);
  border-radius: 18px;
  box-shadow: 0 4px 0 0 var(--navy);
  display: grid; grid-template-columns: 56px 1fr;
  align-items: center; gap: 12px;
  text-align: left;
  animation: all-review-char-pop 500ms cubic-bezier(0.34, 1.56, 0.64, 1) 220ms both;
}
@keyframes all-review-char-pop {
  from { transform: scale(0.6) rotate(-3deg); opacity: 0; }
  to   { transform: scale(1)   rotate(0deg);  opacity: 1; }
}
.all-review-char-portrait {
  width: 56px; height: 56px;
  border-radius: 14px;
  background: rgba(255,255,255,0.7);
  border: 3px solid var(--navy);
  display: grid; place-items: center;
  box-shadow: inset 0 -3px 0 rgba(0,0,0,0.2);
}
.all-review-char-portrait img {
  width: 90%; height: auto;
  image-rendering: pixelated;
  filter: drop-shadow(0 3px 3px rgba(0, 0, 0, 0.35));
}
.all-review-char-tag {
  font-family: var(--font-game); font-size: 10px;
  letter-spacing: 1px; color: #fff;
  text-shadow: 0 1px 0 rgba(0,0,0,0.4);
}
.all-review-char-name {
  font-family: var(--font-game); font-size: 18px;
  letter-spacing: 0.6px;
  color: var(--navy);
  text-shadow: 0 1px 0 rgba(255,255,255,0.55);
  line-height: 1;
}
.dock-btn.color-chat  { background: linear-gradient(180deg,#D7C2F0,#8B5DC7); }
.dock-btn.color-games { background: linear-gradient(180deg,#D7C2F0,#7B3F99); }

.dock-btn .badge {
  position: absolute; top: -10px; right: -10px;
  min-width: 28px; height: 28px; padding: 0 8px;
  border-radius: 999px;
  background: var(--game-red);
  border: 2.5px solid var(--paper);
  color: #fff; font-family: var(--font-game); font-size: 16px;
  display: grid; place-items: center;
  box-shadow: 0 3px 0 rgba(0,0,0,0.3);
  line-height: 1;
}
.dock-btn .new-tag {
  position: absolute; top: -8px; left: -8px;
  background: var(--game-red); color: #fff;
  font-family: var(--font-game); font-size: 11px;
  padding: 3px 8px; border-radius: 6px;
  border: 2px solid var(--paper);
  transform: rotate(-8deg);
  box-shadow: 0 2px 0 rgba(0,0,0,0.3);
}

/* ----- Center stage ----- */
.stage { grid-column: 2; grid-row: 2; position: relative;
  display: grid; place-items: center; z-index: 3; }

.rank-plate {
  display: flex; align-items: center; gap: 10px;
  position: absolute; top: 14px; left: 50%; transform: translateX(-50%);
  z-index: 4;
}
.rank-plate .pill {
  display: flex; align-items: center; gap: 8px;
  background: var(--hud-bg);
  border: 2px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  padding: 5px 16px 5px 5px;
  font-family: var(--font-game); font-size: 18px; color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  box-shadow: var(--shadow-3d);
  white-space: nowrap;
  line-height: 1;
}
.rank-plate .pill span { white-space: nowrap; }
.rank-plate .pill .ico {
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  border: 2px solid #0A1A30;
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.30), inset 0 2px 0 rgba(255,255,255,0.20);
  font-size: 16px;
}
.rank-plate .pill.rank .ico { background: radial-gradient(circle at 35% 30%, #FFD27A, #C0392B 70%, #6B1414); color:#fff; }
.rank-plate .pill.troph .ico { background: radial-gradient(circle at 35% 30%, #FFE48A, #E5A91A 70%, #A86E0A); }
.rank-plate .pill.level .ico { background: radial-gradient(circle at 35% 30%, #FFEAA0, #F0C040 70%, #A8770A); color:var(--navy); }

.character-floor {
  position: absolute; bottom: 6%; left: 50%; transform: translateX(-50%);
  width: 560px; height: 110px;
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(255,210,120,0.45) 0%, rgba(255,210,120,0.0) 70%);
  z-index: 2;
}
.character-platform {
  position: absolute; bottom: 8%; left: 50%; transform: translateX(-50%);
  width: 420px; height: 42px;
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(0,0,0,0.35) 0%, transparent 70%);
  z-index: 2;
}
.character {
  position: relative; z-index: 3;
  display: grid; place-items: end center;
  width: 620px; max-width: 100%; height: 100%;
  animation: bob 3.6s ease-in-out infinite;
  filter: drop-shadow(0 18px 14px rgba(0,0,0,0.45));
}
/* 612px = 9× the 68 px chemist-wizard source sprite — clean
   integer scale so the pixel art stays sharp under nearest-neighbor
   interpolation. max-height keeps the sprite inside the stage row
   on landscape phones / short viewports; width caps via max-width
   so portrait phones (where width is the constraint) still scale. */
.character img { width: 612px; max-width: 100%; height: auto; max-height: 100%; object-fit: contain; }

/* Make the stage character clickable so tapping it opens the
   character picker. Hover scales the inner pixel sprite up slightly
   (transition on the img only — the parent .character keeps its
   bob animation untouched). :hover is the only state that changes
   size, so the moment the cursor leaves the avatar (or the picker
   opens, or a touch ends) the scale auto-reverts to 1. No JS state,
   no sticky transforms. */
.character[data-cgd-action="pick-character"] { cursor: pointer; }
.character[data-cgd-action="pick-character"] img {
  transition: transform 180ms ease;
  transform-origin: bottom center;
}
.character[data-cgd-action="pick-character"]:hover img {
  transform: scale(1.08);
}
/* Pet sidekick — tucked in front of the character's right leg
   (viewer's left), smaller than the kid avatar and bobbing out of
   phase so the two read as separate creatures. z-index sits ABOVE
   the character so the pet visually overlaps the leg, like it's
   hugging the kid's foot. Tap to open the pet picker.
   Positioned via `right` so the pet's RIGHT edge sits at center
   and the image extends LEFTWARD — keeps it on the viewer's
   left side of the character. */
.pet {
  position: absolute;
  z-index: 5;
  bottom: 22px;
  right: calc(50% + 0px);
  /* JS sets `width` inline from the character img's actual rendered
     width (via ResizeObserver in child-dashboard.js _sizePetToCharacter).
     This fallback keeps pet/character roughly in proportion before
     the observer fires or in browsers without ResizeObserver — but
     it can drift on height-constrained stages because 34% of stage
     doesn't equal 34% of a height-shrunk character img. The
     inline-style override is the source of truth. */
  width: min(210px, 34%);
  cursor: pointer;
  animation: bob 3s ease-in-out infinite -0.7s;
  filter: drop-shadow(0 8px 6px rgba(0,0,0,0.45));
}
/* Hover scale is on the inner <img> (not the .pet wrapper) so the
   bob animation on the wrapper keeps running uninterrupted —
   matches the .character[data-cgd-action="pick-character"]:hover
   pattern. */
.pet img {
  width: 100%; height: auto;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  transition: transform 180ms ease;
  transform-origin: bottom center;
}
.pet:hover img { transform: scale(1.08); }
/* Pet picker's "No pet" tile shows a muted dash so the slot still
   reads as a clickable card. */
.pet-none-mark {
  font-family: var(--font-game);
  font-size: 48px;
  color: rgba(11, 30, 63, 0.35);
  line-height: 1;
}

.character-pick-hint {
  position: absolute;
  bottom: -4px; left: 50%; transform: translateX(-50%);
  background: rgba(11, 30, 63, 0.7);
  color: #FFE38A;
  font-family: var(--font-ui); font-size: 11px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  padding: 4px 12px;
  border-radius: 999px;
  border: 1.5px solid rgba(255, 227, 138, 0.4);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none;
}
.character[data-cgd-action="pick-character"]:hover .character-pick-hint { opacity: 1; }

/* Character picker grid (opened from tapping the stage avatar). */
.char-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 14px;
}
.char-card {
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  border-radius: 18px;
  padding: 14px 14px 12px;
  box-shadow: 0 5px 0 0 var(--navy);
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  cursor: pointer;
  position: relative;
  transition: transform 100ms ease, box-shadow 100ms ease;
}
.char-card:hover  { transform: translateY(-2px); box-shadow: 0 7px 0 0 var(--navy); }
.char-card:active { transform: translateY(2px);  box-shadow: 0 2px 0 0 var(--navy); }
.char-card.is-active {
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 100%);
}
.char-portrait {
  width: 100%; aspect-ratio: 1 / 1;
  background: radial-gradient(ellipse at center, rgba(255,210,120,0.5) 0%, rgba(255,210,120,0) 70%);
  display: grid; place-items: center;
}
.char-portrait img {
  width: 90%; height: auto;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  filter: drop-shadow(0 6px 6px rgba(0,0,0,0.35));
}
/* Per-pet visual scale tweaks. Some PixelLab sprites land with a
   lot of internal whitespace around the creature — when rendered
   at the same display width as the 92×92 pets, the actual animal
   reads small. Bump them via transform so the source PNG isn't
   touched and the picker grid spacing stays even.
   Applied to BOTH the picker tile (.char-card[data-pet-id])
   AND the equipped-pet sprite on the dashboard (.pet[data-pet-id])
   so the size is consistent everywhere the kid sees it. */
.char-card[data-pet-id="unicorn_puffy"] .char-portrait img { transform: scale(1.5); }
.char-card[data-pet-id="wolf_chef"]     .char-portrait img { transform: scale(1.35); }
.pet[data-pet-id="unicorn_puffy"] img       { transform: scale(1.5); }
.pet[data-pet-id="unicorn_puffy"]:hover img { transform: scale(1.62); }
.pet[data-pet-id="wolf_chef"]     img       { transform: scale(1.35); }
.pet[data-pet-id="wolf_chef"]:hover img     { transform: scale(1.46); }
/* Placeholder for level-locked characters — silhouette behind a
   big ? so the kid sees something's coming without spoiling who. */
.char-portrait-placeholder {
  width: 70%; aspect-ratio: 1 / 1;
  border-radius: 18px;
  background: linear-gradient(180deg, rgba(11,30,63,0.25), rgba(11,30,63,0.45));
  border: 3px dashed rgba(11,30,63,0.5);
  display: grid; place-items: center;
  font-family: var(--font-game); font-size: 72px;
  color: rgba(11,30,63,0.45);
  text-shadow: 0 3px 0 rgba(255,255,255,0.5);
}
.char-name {
  font-family: var(--font-game); font-size: 14px;
  color: var(--navy); letter-spacing: 0.5px;
}
/* Picker-local gem balance chip — top-right of the picker body
   so kids see exactly which counter the gems leave from when
   they buy a character. */
/* Tab toggle at the top of the unified character/pet picker.
   Two big chunky buttons; the active one gets the gold gradient
   and a slight punch-down so it reads as the "current view". */
.picker-tabs {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-bottom: 6px;
  align-self: center;
}
.picker-tab {
  font-family: var(--font-game);
  font-size: 15px;
  letter-spacing: 0.6px;
  background: linear-gradient(180deg, #FFFCF3, #F2E4B6);
  border: 3px solid var(--navy);
  border-radius: 14px;
  padding: 10px 24px;
  color: var(--navy);
  box-shadow: 0 4px 0 0 var(--navy);
  cursor: pointer;
  transition: transform 100ms ease, box-shadow 100ms ease;
}
.picker-tab:hover  { transform: translateY(-1px); box-shadow: 0 5px 0 0 var(--navy); }
.picker-tab:active { transform: translateY(2px);  box-shadow: 0 2px 0 0 var(--navy); }
.picker-tab.is-active {
  background: linear-gradient(180deg, #FFE38A, #F0C040);
}

/* Picker-local gem balance chip — top-right of the picker body
   so kids see exactly which counter the gems leave from when
   they buy a character. align-self pulls it right in the
   .ov-body column flex; the grid sits below. */
.char-picker-balance {
  align-self: flex-end;
  display: inline-flex; align-items: center; gap: 6px;
  background: linear-gradient(180deg, #B8EDD5, #5ED4A8);
  border: 3px solid var(--navy);
  border-radius: 999px;
  padding: 6px 14px 6px 10px;
  box-shadow: 0 4px 0 0 var(--navy);
  font-family: var(--font-game); font-size: 16px;
  color: var(--navy);
}
.char-picker-balance svg { width: 20px; height: 20px; }

.char-active-pill,
.char-owned-pill,
.char-price-pill {
  position: absolute; top: 10px; right: 10px;
  border: 2px solid var(--navy);
  color: var(--navy);
  font-family: var(--font-game); font-size: 10px;
  letter-spacing: 0.6px;
  padding: 3px 8px;
  border-radius: 999px;
  box-shadow: 0 2px 0 0 var(--navy);
}
.char-active-pill { background: linear-gradient(180deg, #C9F2D6, #34C46F); }
.char-owned-pill  { background: linear-gradient(180deg, #FFFCF3, #F2E4B6); opacity: 0.75; }
.char-price-pill {
  background: linear-gradient(180deg, #B8EDD5, #5ED4A8);
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px 3px 6px;
}
.char-price-pill svg { width: 14px; height: 14px; }
/* Level-lock pill — pops on cards gated behind an Owl Pass tier.
   Gold gradient matches the Owl Pass tier visuals so the kid
   reads "earn me by levelling up" instead of "I cost something." */
.char-level-pill {
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  color: var(--navy);
  text-shadow: 0 1px 0 rgba(255,255,255,0.5);
}
/* Locked characters: muted card + a small lock badge on the
   portrait so the price tag alone doesn't fully read as "locked". */
.char-card.is-locked .char-portrait img { filter: grayscale(0.55) drop-shadow(0 6px 6px rgba(0,0,0,0.35)); }
.char-card.cannot-afford { opacity: 0.6; }
/* Level-locked cards: deeper grayscale + a subtle navy tint so it
   reads as "earn this — don't just try to buy it". */
.char-card.is-level-locked { opacity: 0.85; cursor: not-allowed; }
.char-card.is-level-locked .char-portrait img {
  filter: grayscale(0.85) drop-shadow(0 6px 6px rgba(0,0,0,0.35));
}
/* Brief horizontal shake when the kid taps a card they can't
   afford — purely cosmetic feedback, no other UI change. */
.char-card.shake-no { animation: char-shake 0.4s ease both; }
@keyframes char-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(4px); }
}

/* ============ BUY CONFIRMATION MODAL ============
   Kid-video-game-style buy confirmation: chunky borders, drop
   shadow under each layer, oversized BUY!/NOPE buttons. Sits
   inside the picker overlay so the picker stays mounted behind. */
.char-buy-backdrop {
  position: fixed; inset: 0;
  background: rgba(11, 30, 63, 0.55);
  display: grid; place-items: center;
  z-index: 1000;
  animation: char-buy-fadein 180ms ease-out both;
}
@keyframes char-buy-fadein { from { opacity: 0; } to { opacity: 1; } }
.char-buy-modal {
  width: min(420px, 88vw);
  background: linear-gradient(180deg, #FFFCF3 0%, #FFE38A 100%);
  border: 4px solid var(--navy);
  border-radius: 28px;
  box-shadow: 0 8px 0 0 var(--navy), 0 20px 40px rgba(0, 0, 0, 0.35);
  padding: 22px 22px 18px;
  text-align: center;
  cursor: default;
  animation: char-buy-pop 280ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes char-buy-pop {
  0%   { transform: scale(0.7) translateY(20px); opacity: 0; }
  100% { transform: scale(1)   translateY(0);    opacity: 1; }
}
.char-buy-title {
  font-family: var(--font-game);
  font-size: 22px;
  color: var(--navy);
  letter-spacing: 0.5px;
  margin-bottom: 12px;
  text-shadow: 0 2px 0 rgba(255, 255, 255, 0.7);
}
.char-buy-portrait {
  width: 140px; height: 140px;
  margin: 0 auto 14px;
  background: radial-gradient(ellipse at center, rgba(255,210,120,0.7) 0%, rgba(255,210,120,0) 70%);
  border: 4px solid var(--navy);
  border-radius: 24px;
  box-shadow: 0 5px 0 0 var(--navy);
  display: grid; place-items: center;
}
.char-buy-portrait img {
  width: 80%; height: auto;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  filter: drop-shadow(0 4px 4px rgba(0, 0, 0, 0.35));
}
.char-buy-price {
  display: inline-flex; align-items: center; gap: 8px;
  background: linear-gradient(180deg, #B8EDD5, #5ED4A8);
  border: 3px solid var(--navy);
  border-radius: 999px;
  padding: 8px 18px;
  box-shadow: 0 4px 0 0 var(--navy);
  font-family: var(--font-game);
  font-size: 22px;
  color: var(--navy);
  margin-bottom: 18px;
}
.char-buy-price svg { width: 26px; height: 26px; }
.char-buy-actions {
  display: grid; grid-template-columns: 1fr 1.4fr; gap: 12px;
}
.char-buy-yes,
.char-buy-no {
  font-family: var(--font-game);
  font-size: 20px;
  letter-spacing: 0.8px;
  border: 4px solid var(--navy);
  border-radius: 16px;
  padding: 12px 8px;
  cursor: pointer;
  color: var(--navy);
  transition: transform 100ms ease, box-shadow 100ms ease;
}
.char-buy-yes {
  background: linear-gradient(180deg, #C9F2D6 0%, #34C46F 100%);
  box-shadow: 0 6px 0 0 var(--navy);
}
.char-buy-yes:hover  { transform: translateY(-2px); box-shadow: 0 8px 0 0 var(--navy); }
.char-buy-yes:active { transform: translateY(3px);  box-shadow: 0 3px 0 0 var(--navy); }
.char-buy-yes.is-disabled,
.char-buy-yes:disabled {
  background: linear-gradient(180deg, #E0E0E0 0%, #B0B0B0 100%);
  box-shadow: 0 4px 0 0 #888;
  color: #555;
  cursor: not-allowed;
  border-color: #555;
}
.char-buy-no {
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  box-shadow: 0 6px 0 0 var(--navy);
}
.char-buy-no:hover  { transform: translateY(-2px); box-shadow: 0 8px 0 0 var(--navy); }
.char-buy-no:active { transform: translateY(3px);  box-shadow: 0 3px 0 0 var(--navy); }

/* Gem-buy bubble: same flight pattern as the hint-coin float,
   different sprite (gem SVG instead of coin) and tuned timing
   so the deduction lands at the end (~880 ms). */
.quiz-coin-bubble.gem-buy-bubble {
  animation: gemBuyFly 900ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
@keyframes gemBuyFly {
  0%   {
    transform: translate(-50%, -50%) scale(0.5) rotate(0deg);
    opacity: 0;
  }
  18%  {
    transform: translate(-50%, -50%) scale(1.2) rotate(-8deg);
    opacity: 1;
  }
  55%  {
    transform:
      translate(calc(-50% + var(--end-x, 0px) * 0.55 + var(--sway, 0px)),
                calc(-50% + var(--end-y, 0px) * 0.55 - 18px))
      scale(1.0) rotate(180deg);
    opacity: 1;
  }
  92%  {
    transform:
      translate(calc(-50% + var(--end-x, 0px)),
                calc(-50% + var(--end-y, 0px)))
      scale(0.55) rotate(360deg);
    opacity: 1;
  }
  100% {
    transform:
      translate(calc(-50% + var(--end-x, 0px)),
                calc(-50% + var(--end-y, 0px)))
      scale(0.2) rotate(360deg);
    opacity: 0;
  }
}

/* Stage / avatar / family-card images now use 68×68 pixel-art
   sprites. Force nearest-neighbor scaling so the upscale stays
   crisp blocky pixel art rather than bilinear-smoothed mush.
   Covers both the legacy owl-* paths and the new
   assets/characters/<slug>/ paths the picker swaps between. */
img[src*="owl-"],
img[src*="characters/"],
img[src*="pets/"] {
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges; /* Firefox fallback */
}

@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}

.beams {
  position: absolute; top: 8%; left: 50%; transform: translateX(-50%);
  width: 600px; height: 600px; pointer-events: none;
  z-index: 1; opacity: 0.55;
}
.beams svg { width: 100%; height: 100%; animation: spin 80s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ----- Bottom bar ----- */
.bottom { grid-column: 1 / -1; grid-row: 3;
  display: grid; grid-template-columns: 280px 1fr 360px;
  gap: 14px; align-items: stretch; position: relative; z-index: 5;
}

/* Owl pass */
.pass {
  background: linear-gradient(180deg, #6F3DC6 0%, #4A1E9E 100%);
  border: 3px solid var(--navy);
  border-radius: 18px;
  padding: 10px 14px;
  position: relative;
  display: flex; flex-direction: column; justify-content: space-between;
  box-shadow: 0 5px 0 0 var(--navy);
}
.pass .pass-head {
  display: flex; align-items: center; gap: 10px;
}
.pass .pass-chest {
  width: 48px; height: 48px; border-radius: 12px;
  background: linear-gradient(180deg, #F0C040, #C18C12);
  border: 2.5px solid var(--navy);
  display: grid; place-items: center;
  font-size: 28px; line-height: 1;
  box-shadow: inset 0 -3px 0 rgba(0,0,0,0.25), inset 0 3px 0 rgba(255,255,255,0.20);
}
.pass .pass-title {
  font-family: var(--font-game); font-size: 22px; color: #fff;
  letter-spacing: 0.5px; line-height: 1;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
}
.pass .pass-sub {
  font-family: var(--font-ui); font-size: 11px; font-weight: 700;
  color: #E1D0FF; letter-spacing: 0.05em; text-transform: uppercase;
  margin-top: 3px;
}
.pass .pass-bar {
  height: 14px; border-radius: 999px;
  background: rgba(0,0,0,0.35);
  border: 2px solid var(--navy);
  overflow: hidden; position: relative;
}
.pass .pass-fill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 60%, #C18C12 100%);
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.25), inset 0 2px 0 rgba(255,255,255,0.30);
}
.pass .pass-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-family: var(--font-game); font-size: 14px; color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4); }
.pass .pass-gems {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(0,0,0,0.35);
  border: 2px solid var(--navy);
  border-radius: 999px;
  padding: 2px 10px 2px 3px;
  font-family: var(--font-game); font-size: 14px; color: #fff;
}
/* Compact LV pill that lives in .pass-meta (Owl Pass footer).
   Mirrors the .rank-plate .pill.level styling so the same gold
   star + navy gradient + "LV N" reads in both places. */
.pass .pass-level-pill {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--hud-bg, rgba(0,0,0,0.35));
  border: 2px solid var(--navy);
  border-radius: 999px;
  padding: 3px 12px 3px 4px;
  font-family: var(--font-game); font-size: 14px; color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  box-shadow: var(--shadow-3d, 0 2px 0 0 rgba(0,0,0,0.35));
  line-height: 1;
}
.pass .pass-level-pill .ico {
  width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  border: 2px solid #0A1A30;
  background: radial-gradient(circle at 35% 30%, #FFEAA0, #F0C040 70%, #A8770A);
  color: var(--navy);
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.30), inset 0 2px 0 rgba(255,255,255,0.20);
}
.pass .pass-level-pill .ico svg { width: 14px; height: 14px; }
.pass[data-cgd-action="open-owl-pass"] {
  cursor: pointer;
  transition: transform 100ms ease, box-shadow 100ms ease;
}
.pass[data-cgd-action="open-owl-pass"]:hover  { transform: translateY(-1px); box-shadow: 0 6px 18px -4px rgba(0,0,0,0.45); }
.pass[data-cgd-action="open-owl-pass"]:active { transform: translateY(2px); }

/* ====== Owl Pass popover ======
   Tiny floating panel that pops up just above the .pass card on
   home. 5x5 grid of small level squares, ‹ › step through 8
   pages of 25 levels each. Each square has a level number and
   (when an unlock lives on that tier) a small portrait — locked
   unlocks show "?" silhouettes until the kid reaches them.
   --------------------------------------------------------------- */
.pass-wrap {
  position: relative;
}
.op-popover {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
  width: 320px;
  max-width: calc(100vw - 32px);
  background: linear-gradient(180deg, #0E3F75 0%, #061C3A 100%);
  border: 3px solid var(--navy);
  border-radius: 16px;
  box-shadow: 0 8px 0 0 var(--navy), 0 14px 32px rgba(0,0,0,0.5);
  padding: 10px 10px 12px;
  z-index: 30;
  animation: opPop 180ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes opPop {
  from { opacity: 0; transform: translateX(-50%) translateY(6px) scale(0.92); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
}
.op-popover::after {
  /* Speech-bubble tail pointing down at the .pass card. */
  content: "";
  position: absolute;
  left: 50%; top: 100%;
  transform: translateX(-50%);
  border: 9px solid transparent;
  border-top-color: var(--navy);
}
.op-popover-head {
  display: grid;
  grid-template-columns: 28px 1fr 28px 28px;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
}
.op-popover-title {
  text-align: center;
  font-family: var(--font-game); font-size: 12px;
  letter-spacing: 0.6px;
  color: #FFE38A;
  text-shadow: 0 1px 0 rgba(0,0,0,0.4);
}
.op-pager-btn {
  width: 28px; height: 28px;
  border-radius: 8px;
  border: 2px solid var(--navy);
  background: linear-gradient(180deg, #FFFCF3, #F2E4B6);
  color: var(--navy);
  font-family: var(--font-game); font-size: 16px;
  line-height: 1; padding: 0;
  box-shadow: 0 2px 0 0 var(--navy);
  cursor: pointer;
  transition: transform 100ms ease, box-shadow 100ms ease;
}
.op-pager-btn:hover:not(:disabled)  { transform: translateY(-1px); box-shadow: 0 3px 0 0 var(--navy); }
.op-pager-btn:active:not(:disabled) { transform: translateY(1px);  box-shadow: 0 1px 0 0 var(--navy); }
.op-pager-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.op-close-btn {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 2px solid var(--navy);
  background: linear-gradient(180deg, #FFB8C7, #E04848);
  color: #fff;
  font-family: var(--font-game); font-size: 14px;
  line-height: 1; padding: 0;
  box-shadow: 0 2px 0 0 var(--navy);
  cursor: pointer;
}
.op-close-btn:active { transform: translateY(1px); box-shadow: 0 1px 0 0 var(--navy); }
.op-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
}
.op-cell {
  position: relative;
  aspect-ratio: 1 / 1;
  min-height: 48px;
  background: rgba(255,255,255,0.06);
  border: 1.5px solid rgba(255,255,255,0.14);
  border-radius: 8px;
  color: #fff;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 2px;
}
.op-cell .op-level {
  font-family: var(--font-game); font-size: 11px;
  letter-spacing: 0.3px;
  color: rgba(255,255,255,0.65);
}
.op-cell.is-passed {
  background: linear-gradient(180deg, rgba(94, 212, 168, 0.22), rgba(52, 196, 111, 0.10));
  border-color: rgba(94, 212, 168, 0.55);
}
.op-cell.is-passed .op-level { color: #C9F2D6; }
.op-cell.is-current {
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  border-color: var(--navy);
  box-shadow: 0 2px 0 0 var(--navy);
  color: var(--navy);
}
.op-cell.is-current .op-level { color: var(--navy); }
.op-cell.has-unlock {
  border-color: rgba(255, 227, 138, 0.55);
}
.op-unlock {
  display: grid; place-items: center;
}
/* Multiple unlocks in one cell — lay them out left-to-right so a
   level with 5 starter items doesn't stack into a tall stripe. The
   data-count attribute lets us shrink portraits when crowded so
   they still fit inside the square. */
.op-unlock-row {
  display: flex; flex-direction: row;
  align-items: center; justify-content: center;
  flex-wrap: wrap;
  gap: 2px;
  max-width: 100%;
}
.op-unlock-row .op-unlock-portrait {
  width: 22px; height: 22px;
}
.op-unlock-row[data-count="3"] .op-unlock-portrait,
.op-unlock-row[data-count="4"] .op-unlock-portrait {
  width: 18px; height: 18px;
}
.op-unlock-row[data-count="5"] .op-unlock-portrait,
.op-unlock-row[data-count="6"] .op-unlock-portrait,
.op-unlock-row[data-count="7"] .op-unlock-portrait,
.op-unlock-row[data-count="8"] .op-unlock-portrait {
  width: 14px; height: 14px;
}
.op-unlock-portrait {
  width: 28px; height: 28px;
  border-radius: 6px;
  background: radial-gradient(ellipse at center, rgba(255,210,120,0.55) 0%, rgba(255,210,120,0) 70%);
  display: grid; place-items: center;
}
.op-unlock-portrait img {
  width: 90%; height: auto;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,0.35));
}
/* Locked unlock — silhouette + dashed border + ? glyph so it
   reads as "something's coming, but not yet". */
.op-unlock.is-locked .op-unlock-portrait {
  background: rgba(11,30,63,0.45);
  border: 1.5px dashed rgba(255,255,255,0.4);
}
.op-unlock-placeholder {
  font-family: var(--font-game); font-size: 16px;
  color: rgba(255,255,255,0.6);
  text-shadow: 0 1px 0 rgba(0,0,0,0.4);
  line-height: 1;
}

.pass .pass-gems .ico {
  width: 22px; height: 22px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #B3F5C5, #34C46F 70%, #115E2C);
  border: 2px solid var(--navy);
}

/* Event card */
.event {
  background: linear-gradient(180deg, #0E3F75 0%, #061C3A 100%);
  border: 3px solid var(--navy);
  border-radius: 18px;
  display: grid; grid-template-columns: 80px 1fr auto;
  gap: 14px; align-items: center;
  padding: 12px 16px;
  box-shadow: 0 5px 0 0 var(--navy);
}
.event .badge-icon {
  width: 64px; height: 64px; border-radius: 14px;
  background: linear-gradient(180deg, #2C7AC9, #1A4E8C);
  border: 2.5px solid var(--navy);
  display: grid; place-items: center;
  font-size: 38px; line-height: 1;
  box-shadow: inset 0 -3px 0 rgba(0,0,0,0.25), inset 0 3px 0 rgba(255,255,255,0.20);
}
.event .event-name { font-family: var(--font-game); font-size: 24px; color: #fff;
  letter-spacing: 1px; line-height: 1; text-shadow: 0 2px 0 rgba(0,0,0,0.5); }
.event .event-sub { font-family: var(--font-ui); font-size: 13px; font-weight: 700;
  color: #FFE38A; margin-top: 4px; }
.event .event-timer {
  font-family: var(--font-ui); font-size: 11px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: rgba(255,255,255,0.65);
  margin-top: 4px;
}
.event .event-info-btn {
  width: 36px; height: 36px; border-radius: 50%;
  background: rgba(255,255,255,0.10);
  border: 2px solid rgba(255,255,255,0.18);
  color: #fff; display: grid; place-items: center;
  font-family: var(--font-game); font-size: 18px;
}

/* Play */
.play-wrap { display: flex; flex-direction: column; gap: 6px; }
.token-bar {
  display: grid; grid-template-columns: 1fr auto; gap: 10px;
  align-items: center;
  background: var(--hud-bg);
  border: 2px solid rgba(255,255,255,0.14);
  border-radius: 12px;
  padding: 4px 12px 4px 4px;
  box-shadow: var(--shadow-3d);
  cursor: pointer;
  transition: transform 100ms ease, border-color 100ms ease;
}
.token-bar:hover  { border-color: rgba(255,227,138,0.55); transform: translateY(-1px); }
.token-bar:active { transform: translateY(1px); }
.token-bar .ico {
  width: 32px; height: 32px; border-radius: 8px;
  background: linear-gradient(180deg, #F0C040, #C18C12);
  border: 2px solid var(--navy);
  display: grid; place-items: center; font-size: 18px;
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.25);
}
.token-bar .meter {
  display: flex; flex-direction: column; gap: 3px; min-width: 0;
}
.token-bar .meter-num {
  font-family: var(--font-game); font-size: 14px; color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  white-space: nowrap; line-height: 1;
}
.token-bar .meter-num .reward { color: #7CE2A8; font-size: 12px; }
.token-bar .meter-bar { height: 6px; background: rgba(0,0,0,0.35); border-radius: 999px; overflow: hidden; }
.token-bar .meter-fill { height: 100%; background: linear-gradient(180deg, #FFE38A, #F0C040); border-radius: 999px; }

/* Upcoming-reviews schedule overlay — opened by tapping the
   review-progress bar on home. List of bars showing when the
   next reviews come back. */
.sched-summary {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  margin-bottom: 6px;
}
.sched-summary-row {
  background: linear-gradient(180deg, #FFFCF3, #F2E4B6);
  border: 3px solid var(--navy);
  border-radius: 14px;
  box-shadow: 0 4px 0 0 var(--navy);
  padding: 10px 14px;
  display: flex; align-items: baseline; justify-content: space-between;
  color: var(--navy);
}
.sched-summary-label {
  font-family: var(--font-game); font-size: 11px;
  letter-spacing: 0.6px;
  opacity: 0.7;
}
.sched-summary-num {
  font-family: var(--font-game); font-size: 24px;
  letter-spacing: 0.4px;
}
.sched-section { margin-top: 4px; }
.sched-section-head {
  font-family: var(--font-game); font-size: 13px;
  letter-spacing: 0.8px;
  color: rgba(255,255,255,0.7);
  padding: 8px 4px 6px;
  border-bottom: 1.5px solid rgba(255,255,255,0.15);
  margin-bottom: 6px;
}
.sched-list {
  display: flex; flex-direction: column; gap: 4px;
}
.sched-row {
  display: grid; grid-template-columns: 130px 1fr 36px; gap: 12px;
  align-items: center;
  padding: 6px 10px;
  border-radius: 10px;
  background: rgba(255,255,255,0.04);
}
.sched-row.is-empty {
  opacity: 0.4;
}
.sched-label {
  font-family: var(--font-ui); font-size: 13px; font-weight: 700;
  color: #fff;
  letter-spacing: 0.3px;
}
.sched-bar {
  height: 10px; border-radius: 999px;
  background: rgba(0,0,0,0.4);
  border: 1.5px solid rgba(255,255,255,0.15);
  overflow: hidden;
}
.sched-fill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.2), inset 0 2px 0 rgba(255,255,255,0.25);
}
.sched-count {
  font-family: var(--font-game); font-size: 14px;
  color: #FFE38A;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.sched-row.is-empty .sched-count { color: rgba(255,255,255,0.4); }
.sched-empty {
  text-align: center; padding: 16px 8px;
  font-family: var(--font-ui); font-size: 14px;
  color: rgba(255,255,255,0.55);
}
.sched-summary-row.is-hot {
  background: linear-gradient(180deg, #FFB8C7, #E04848);
  color: #fff;
  text-shadow: 0 1px 0 rgba(0,0,0,0.35);
}
.sched-summary-row.is-hot .sched-summary-label,
.sched-summary-row.is-hot .sched-summary-num { color: #fff; }
.sched-summary-num.sched-summary-small {
  font-size: 18px;
  letter-spacing: 0.3px;
}

/* Calendar month-nav — < and > buttons flanking the month label.
   < disables on the current month so the kid can't browse to past
   months (no SRS data there). */
.cal-month-nav {
  display: grid;
  grid-template-columns: 44px 1fr 44px;
  align-items: center;
  margin-bottom: 10px;
}
.cal-nav-btn {
  width: 40px; height: 40px;
  border-radius: 10px;
  border: 2.5px solid var(--navy);
  background: linear-gradient(180deg, #FFFCF3, #F2E4B6);
  color: var(--navy);
  font-family: var(--font-game); font-size: 22px;
  line-height: 1;
  box-shadow: 0 3px 0 0 var(--navy);
  cursor: pointer;
  transition: transform 100ms ease, box-shadow 100ms ease;
}
.cal-nav-btn:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 4px 0 0 var(--navy); }
.cal-nav-btn:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 1px 0 0 var(--navy); }
.cal-nav-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.cal-month-label {
  text-align: center;
  font-family: var(--font-game); font-size: 18px;
  letter-spacing: 0.8px;
  color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
}

/* Calendar grid — full month with leading/trailing days from
   adjacent months. Each cell is a button so the kid can tap a day
   to load its hour-by-hour breakdown. Today is highlighted in
   gold; the currently-selected day gets a navy ring; past + other-
   month days are dimmed. */
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
}
.cal-head {
  text-align: center;
  font-family: var(--font-game); font-size: 11px;
  letter-spacing: 0.8px;
  color: rgba(255,255,255,0.55);
  padding: 4px 0 2px;
}
.cal-cell {
  position: relative;
  aspect-ratio: 1 / 1;
  min-height: 52px;
  background: rgba(255,255,255,0.06);
  border: 2px solid rgba(255,255,255,0.12);
  border-radius: 10px;
  color: #fff;
  cursor: pointer;
  padding: 6px 4px 4px;
  display: flex; flex-direction: column;
  align-items: center; justify-content: flex-start;
  gap: 2px;
  transition: transform 100ms ease, border-color 100ms ease, background 120ms ease;
}
.cal-cell:hover:not(:disabled) {
  background: rgba(255,255,255,0.12);
  transform: translateY(-1px);
}
.cal-cell:disabled, .cal-cell.is-past {
  opacity: 0.35;
  cursor: not-allowed;
}
/* Leading/trailing days from adjacent months — dim but still
   tappable (the click handler jumps the calendar to that month). */
.cal-cell.is-other-month {
  opacity: 0.45;
  background: rgba(255,255,255,0.03);
  border-color: rgba(255,255,255,0.08);
}
.cal-cell.is-other-month:disabled {
  opacity: 0.25;
}
.cal-cell .cal-day {
  font-family: var(--font-game); font-size: 16px;
  line-height: 1;
}
.cal-cell .cal-count {
  font-family: var(--font-game); font-size: 11px;
  letter-spacing: 0.4px;
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  color: var(--navy);
  border: 1.5px solid var(--navy);
  border-radius: 999px;
  padding: 1px 7px;
  line-height: 1;
  margin-top: auto;
}
.cal-cell.is-today {
  background: linear-gradient(180deg, rgba(255,227,138,0.25), rgba(240,192,64,0.10));
  border-color: rgba(255,227,138,0.7);
}
.cal-cell.is-today .cal-day { color: #FFE38A; }
.cal-cell.is-selected {
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  border-color: var(--navy);
  box-shadow: 0 3px 0 0 var(--navy);
  color: var(--navy);
}
.cal-cell.is-selected .cal-day { color: var(--navy); }
.cal-cell.is-selected .cal-count {
  background: var(--navy);
  color: #FFE38A;
  border-color: var(--navy);
}
.token-bar .meter-hint { font-family: var(--font-ui); font-size: 10px; font-weight: 700;
  color: rgba(255,255,255,0.75); letter-spacing: 0.04em; }

.play-btn {
  flex: 1;
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 45%, #C18C12 100%);
  border: 3px solid var(--navy);
  border-radius: 18px;
  font-family: var(--font-game); font-size: 42px;
  color: var(--navy); letter-spacing: 2px;
  text-shadow: 0 2px 0 rgba(255,255,255,0.5);
  box-shadow: 0 6px 0 0 var(--navy), 0 10px 22px -4px rgba(0,0,0,0.5);
  display: grid; place-items: center;
  transition: transform 80ms ease, box-shadow 80ms ease;
  animation: pulse 2.2s ease-in-out infinite;
}
.play-btn:hover { filter: brightness(1.05); }
.play-btn:active { transform: translateY(4px); box-shadow: 0 2px 0 0 var(--navy); animation: none; }

@keyframes pulse {
  0%, 100% { box-shadow: 0 6px 0 0 var(--navy), 0 10px 22px -4px rgba(0,0,0,0.5), 0 0 0 0 rgba(240,192,64,0); }
  50%      { box-shadow: 0 6px 0 0 var(--navy), 0 10px 22px -4px rgba(0,0,0,0.5), 0 0 0 14px rgba(240,192,64,0); }
}

@media (prefers-reduced-motion: reduce) {
  .character, .play-btn, .beams svg, .screen::before { animation: none !important; }
}

/* ============================================================
   Overlay screens (Brawl Stars-style sub-screens)
   ============================================================ */
.overlay {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(7, 32, 65, 0.62);
  display: grid; place-items: center;
  padding: 24px;
  opacity: 1;
}
@keyframes ovFade { from { opacity: 0; } to { opacity: 1; } }

.ov-card {
  width: min(1180px, 100%);
  max-height: calc(100vh - 48px);
  background: linear-gradient(180deg, #1F6FB8 0%, #0E3F75 100%);
  border: 4px solid var(--navy);
  border-radius: 22px;
  box-shadow: 0 8px 0 0 var(--navy), 0 24px 50px -10px rgba(0,0,0,0.6);
  display: grid; grid-template-rows: 72px 1fr;
  overflow: hidden;
  opacity: 1;
}
@keyframes ovPop { from { transform: scale(0.92); opacity: 0; } to { transform: scale(1); opacity: 1; } }

.ov-head {
  display: grid; grid-template-columns: 56px 1fr 56px; gap: 12px;
  align-items: center;
  padding: 10px 14px;
  background: linear-gradient(180deg, rgba(0,0,0,0.18), rgba(0,0,0,0) 80%);
  border-bottom: 3px solid var(--navy);
}
.ov-head .back, .ov-head .home {
  width: 52px; height: 52px; border-radius: 14px;
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  box-shadow: 0 4px 0 0 var(--navy);
  display: grid; place-items: center;
  color: var(--navy);
  transition: transform 80ms ease, box-shadow 80ms ease;
}
.ov-head .back:active, .ov-head .home:active {
  transform: translateY(3px); box-shadow: 0 1px 0 0 var(--navy);
}
.ov-head .home { background: linear-gradient(180deg, #FFB8C7, #E04848); color: #fff; }
.ov-head h2 {
  font-family: var(--font-game); font-size: 30px; color: #fff;
  letter-spacing: 2px; line-height: 1; text-align: center;
  margin: 0; text-shadow: 0 3px 0 rgba(0,0,0,0.45);
}
.ov-head .subtitle {
  font-family: var(--font-ui); font-size: 12px; font-weight: 700;
  color: #FFE38A; letter-spacing: 0.06em; text-transform: uppercase;
  text-align: center; margin-top: 4px;
}

.ov-body {
  padding: 20px 24px 24px;
  overflow: auto;
  display: flex; flex-direction: column; gap: 16px;
}

/* Fullscreen variant — opt-in via renderOverlay({ fullscreen: true }).
   Used for the course-detail screen so the kid can focus on the
   lesson list / video without the sky gradient + dock chrome
   peeking around the card. Card fills the viewport edge-to-edge,
   no rounded outer border, no scrim padding. */
.overlay.is-fullscreen {
  padding: 0;
  background: linear-gradient(180deg, #1F6FB8 0%, #0E3F75 100%);
}
.overlay.is-fullscreen .ov-card {
  width: 100%;
  max-height: 100vh;
  min-height: 100vh;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* ----- Reviews screen ----- */
.daily-hero {
  display: grid; grid-template-columns: 110px 1fr auto;
  gap: 16px; align-items: center;
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 60%, #C18C12 100%);
  border: 3px solid var(--navy);
  border-radius: 18px;
  padding: 14px 16px 14px 14px;
  box-shadow: 0 5px 0 0 var(--navy);
}
.daily-hero .hero-icon {
  width: 96px; height: 96px; border-radius: 18px;
  background: linear-gradient(180deg, #FFFCF3, #F2E4B6);
  border: 3px solid var(--navy);
  display: grid; place-items: center;
  box-shadow: inset 0 -4px 0 rgba(0,0,0,0.15), inset 0 4px 0 rgba(255,255,255,0.4);
  position: relative;
}
.daily-hero .hero-icon img { width: 78px; height: 78px; object-fit: contain; }
.daily-hero .hero-icon .due-pill {
  position: absolute; top: -8px; right: -10px;
  background: var(--game-red); color: #fff;
  font-family: var(--font-game); font-size: 14px;
  padding: 2px 8px; border-radius: 999px;
  border: 2.5px solid var(--paper);
  box-shadow: 0 2px 0 rgba(0,0,0,0.3);
}
.daily-hero .hero-title {
  font-family: var(--font-game); font-size: 32px; color: var(--navy);
  letter-spacing: 1.5px; line-height: 1;
  text-shadow: 0 2px 0 rgba(255,255,255,0.5);
}
.daily-hero .hero-sub {
  font-family: var(--font-ui); font-weight: 800; font-size: 14px;
  color: var(--navy); margin-top: 6px; opacity: 0.85;
}
.daily-hero .hero-cta {
  background: linear-gradient(180deg, #4ED6B8 0%, #2E8B5E 100%);
  border: 3px solid var(--navy);
  border-radius: 16px;
  font-family: var(--font-game); font-size: 22px; color: #fff;
  letter-spacing: 1px; padding: 14px 28px;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  box-shadow: 0 5px 0 0 var(--navy);
  transition: transform 80ms ease, box-shadow 80ms ease;
}
.daily-hero .hero-cta:active { transform: translateY(3px); box-shadow: 0 2px 0 0 var(--navy); }

.deck-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px;
}
.deck-card {
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  border-radius: 16px;
  padding: 12px;
  box-shadow: 0 4px 0 0 var(--navy);
  display: grid; grid-template-columns: 56px 1fr auto; gap: 12px; align-items: center;
}
.deck-card .deck-ico {
  width: 56px; height: 56px; border-radius: 12px;
  display: grid; place-items: center; font-size: 28px;
  border: 2.5px solid var(--navy);
  box-shadow: inset 0 -3px 0 rgba(0,0,0,0.2), inset 0 3px 0 rgba(255,255,255,0.4);
}
.deck-card .deck-name {
  font-family: var(--font-game); font-size: 17px; color: var(--navy);
  letter-spacing: 0.4px; line-height: 1.05;
}
.deck-card .deck-sub {
  font-family: var(--font-ui); font-size: 12px; font-weight: 700;
  color: var(--navy); opacity: 0.65; margin-top: 4px;
}
.deck-card .deck-go {
  width: 44px; height: 44px; border-radius: 12px;
  background: linear-gradient(180deg, #2C7AC9, #0D5C9E);
  border: 2.5px solid var(--navy);
  display: grid; place-items: center;
  box-shadow: 0 3px 0 0 var(--navy);
  color: #fff;
}
.deck-card.locked { opacity: 0.55; }
.deck-card.locked .deck-go { background: #6A7A95; }

.streak-banner {
  display: grid; grid-template-columns: 80px 1fr auto; gap: 14px; align-items: center;
  background: linear-gradient(180deg, #F09020 0%, #A85A0C 100%);
  border: 3px solid var(--navy);
  border-radius: 16px;
  padding: 12px 16px;
  box-shadow: 0 5px 0 0 var(--navy);
}
.streak-banner .flame-ico {
  width: 72px; height: 72px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #FFE38A, #F09020 60%, #6B1414);
  border: 3px solid var(--navy);
  display: grid; place-items: center; font-size: 42px;
  box-shadow: inset 0 -4px 0 rgba(0,0,0,0.25);
}
.streak-banner h3 {
  margin: 0; font-family: var(--font-game); font-size: 26px; color: #fff;
  letter-spacing: 1px; line-height: 1; text-shadow: 0 2px 0 rgba(0,0,0,0.4);
}
.streak-banner p {
  margin: 4px 0 0; font-family: var(--font-ui); font-size: 13px; font-weight: 700;
  color: #FFE38A;
}
.streak-banner .streak-num {
  font-family: var(--font-game); font-size: 48px; color: #fff;
  text-shadow: 0 3px 0 rgba(0,0,0,0.45); line-height: 1;
}

.section-label {
  font-family: var(--font-game); font-size: 18px; color: #fff;
  letter-spacing: 1.2px;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  margin: 8px 0 -4px;
}

/* ----- Courses screen (Brawlers-style grid) ----- */
.brawler-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px;
}
/* Empty-state banner shown above the grid when the kid has zero
   assigned courses. The ADD COURSE tile still renders below so
   they have an obvious entry point. */
.courses-empty {
  text-align: center;
  padding: 22px 18px;
  margin-bottom: 14px;
  background: rgba(11, 30, 63, 0.4);
  border: 2px dashed rgba(255, 255, 255, 0.35);
  border-radius: 18px;
  color: #fff;
}
.courses-empty-emoji {
  font-size: 40px;
  line-height: 1;
  margin-bottom: 8px;
}
.courses-empty-head {
  font-family: var(--font-game); font-size: 22px;
  letter-spacing: 0.6px;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
  margin-bottom: 4px;
}
.courses-empty-sub {
  font-family: var(--font-ui); font-weight: 600;
  font-size: 13px;
  opacity: 0.85;
}
.brawler-card {
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  border-radius: 18px;
  padding: 12px;
  box-shadow: 0 5px 0 0 var(--navy);
  position: relative;
  display: flex; flex-direction: column; gap: 8px;
  transition: transform 100ms ease, box-shadow 100ms ease;
}
.brawler-card:hover { transform: translateY(-2px); box-shadow: 0 7px 0 0 var(--navy); }
.brawler-card .b-hero {
  height: 110px; border-radius: 12px;
  display: grid; place-items: center;
  border: 2px solid var(--navy);
  box-shadow: inset 0 -3px 0 rgba(0,0,0,0.18), inset 0 3px 0 rgba(255,255,255,0.3);
  font-size: 56px;
  position: relative;
  overflow: hidden;
}
.brawler-card .b-name {
  font-family: var(--font-game); font-size: 18px; color: var(--navy);
  letter-spacing: 0.4px; line-height: 1;
}
.brawler-card .b-sub {
  font-family: var(--font-ui); font-size: 11px; font-weight: 700;
  color: var(--navy); opacity: 0.65; letter-spacing: 0.04em; text-transform: uppercase;
  margin-top: -2px;
}
.brawler-card .b-bar {
  height: 10px; border-radius: 999px;
  background: rgba(11,30,63,0.25);
  border: 2px solid var(--navy);
  overflow: hidden;
}
.brawler-card .b-fill {
  height: 100%;
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.2);
}
.brawler-card .b-foot {
  display: flex; align-items: center; justify-content: space-between;
  font-family: var(--font-game); font-size: 13px; color: var(--navy);
}
.brawler-card .b-rank-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--navy); color: #fff;
  font-family: var(--font-game); font-size: 11px;
  padding: 3px 9px; border-radius: 999px;
  border: 2px solid #fff;
  position: absolute; top: 8px; right: 8px;
  white-space: nowrap; z-index: 2;
  box-shadow: 0 2px 0 rgba(0,0,0,0.3);
}
.brawler-card .b-new {
  position: absolute; top: -6px; left: -6px;
  background: var(--game-red); color: #fff;
  font-family: var(--font-game); font-size: 11px;
  padding: 3px 8px; border-radius: 6px;
  border: 2px solid var(--paper);
  transform: rotate(-8deg);
  box-shadow: 0 2px 0 rgba(0,0,0,0.3);
}

/* ----- Badges screen ----- */
.badge-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 12px;
}
.badge-tile {
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  border-radius: 16px;
  padding: 12px 8px 14px;
  box-shadow: 0 4px 0 0 var(--navy);
  display: grid; grid-template-rows: auto 1fr auto;
  align-items: center; justify-items: center;
  gap: 8px;
  text-align: center;
  min-height: 170px;
}
.badge-tile.locked {
  background: linear-gradient(180deg, #6A8AB0 0%, #354B6E 100%);
  border-color: #1A2D4F;
  box-shadow: 0 4px 0 0 #1A2D4F;
  color: rgba(255,255,255,0.7);
}
.badge-tile .badge-medal {
  width: 88px; height: 88px;
  display: grid; place-items: center;
  flex-shrink: 0;
}
/* Each badge has its own PNG (sliced from the source sheets via
   connected-component analysis to remove neighbor bleed). The
   renderer sets background-image inline; CSS just centers and
   contains it. */
.badge-img {
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}
.badge-sprite.is-locked {
  filter: grayscale(0.85) brightness(0.7);
}
/* Unified padlock for every locked badge. One artwork, no sprite math. */
.badge-locked {
  background-image: url('../assets/badges/locked.png');
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}
.badge-tile .badge-name {
  font-family: var(--font-game); font-size: 12px;
  color: var(--navy); letter-spacing: 0.3px; line-height: 1.15;
  align-self: end;
  white-space: nowrap;
}
.badge-tile.locked .badge-name { color: rgba(255,255,255,0.9); }
.badge-tile .badge-meta {
  font-family: var(--font-ui); font-size: 10px; font-weight: 700;
  color: var(--navy); opacity: 0.55; letter-spacing: 0.04em; text-transform: uppercase;
  line-height: 1.1;
}
.badge-tile.locked .badge-meta { color: rgba(255,255,255,0.65); opacity: 1; }

/* ----- Games screen (placeholders) ----- */
.games-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}

/* Heading for each subject section on the games page. Slim row with
   the subject emoji, label, and a "N GAMES" right-aligned count. */
.games-subject-head {
  display: flex; align-items: center; gap: 12px;
  margin: 24px 0 12px;
  padding-bottom: 8px;
  border-bottom: 2px dashed rgba(255,255,255,0.18);
  font-family: var(--font-game);
  font-size: 18px;
  color: #FFE38A;
  letter-spacing: 0.5px;
}
.games-subject-head:first-child { margin-top: 0; }
.games-subject-emoji {
  font-size: 26px;
  filter: drop-shadow(0 2px 0 rgba(0,0,0,0.4));
  line-height: 1;
}
.games-subject-label {
  color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  letter-spacing: 1px;
}
.games-subject-count {
  margin-left: auto;
  font-family: var(--font-ui); font-size: 11px; font-weight: 800;
  color: rgba(255,255,255,0.55);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.games-card {
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  border-radius: 18px;
  box-shadow: 0 5px 0 0 var(--navy);
  overflow: hidden;
  cursor: pointer;
  display: flex; flex-direction: column;
  transition: transform 100ms ease, box-shadow 100ms ease;
}
.games-card:hover  { transform: translateY(-2px); box-shadow: 0 7px 0 0 var(--navy); }
.games-card:active { transform: translateY(2px);  box-shadow: 0 2px 0 0 var(--navy); }
.games-hero {
  position: relative;
  aspect-ratio: 16/9;
  display: grid; place-items: center;
  border-bottom: 3px solid var(--navy);
}
.games-hero::after {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(circle at 30% 25%, rgba(255,255,255,0.30), transparent 45%),
    radial-gradient(circle at 75% 80%, rgba(0,0,0,0.25), transparent 55%);
  pointer-events: none;
}
.games-emoji {
  font-size: 56px;
  filter: drop-shadow(0 3px 0 rgba(0,0,0,0.25));
  position: relative; z-index: 1;
}
.games-soon {
  position: absolute;
  top: 10px; right: 10px;
  background: rgba(11,30,63,0.85);
  color: #FFE38A;
  font-family: var(--font-game);
  font-size: 10px;
  letter-spacing: 0.6px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 2px solid rgba(255,227,138,0.5);
  z-index: 2;
}
.games-soon.games-play {
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  color: var(--navy);
  border-color: var(--navy);
}

/* True-fullscreen game overlay. Skips the standard .ov-card/.ov-head
   chrome (which eats ~140 px vertical) so the iframe fills the
   viewport below a slim 50 px top bar. Minesweeper, Sudoku, etc.
   need the height. */
.overlay.game-fullscreen {
  padding: 0;
  background: #0a1a2e;
  display: grid;
  /* topbar / 16px breathing room / iframe / 16px breathing room.
     Without the buffer rows the iframe's content kisses the
     topbar's bottom border and the viewport's bottom edge. */
  grid-template-rows: 50px 16px 1fr 16px;
  /* Override the default overlay's centered-card layout. */
  place-items: stretch;
}
.overlay.game-fullscreen .game-topbar  { grid-row: 1; }
.overlay.game-fullscreen .game-iframe  { grid-row: 3; }
.overlay.game-fullscreen .game-topbar {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 8px 14px;
  background: rgba(11, 30, 63, 0.9);
  border-bottom: 2px solid rgba(255, 227, 138, 0.18);
  z-index: 10;
}
.overlay.game-fullscreen .game-topbar-right {
  display: inline-flex; align-items: center; gap: 10px;
}
.overlay.game-fullscreen .game-back {
  display: inline-flex; align-items: center; gap: 6px;
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 2.5px solid var(--navy);
  border-radius: 12px;
  padding: 7px 14px;
  font-family: var(--font-game); font-size: 13px;
  color: var(--navy); letter-spacing: 0.5px;
  box-shadow: 0 3px 0 0 var(--navy);
  cursor: pointer;
  line-height: 1;
}
.overlay.game-fullscreen .game-back:active {
  transform: translateY(2px);
  box-shadow: 0 1px 0 0 var(--navy);
}
.overlay.game-fullscreen .game-topbar-title {
  font-family: var(--font-game);
  font-size: 16px;
  color: #fff;
  letter-spacing: 1.5px;
  text-align: center;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.overlay.game-fullscreen .game-iframe {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: #fff;
  display: block;
  /* Suppress iframe-level scrollbars — if the game's content still
     overflows we'd rather the fit logic catch it than fall back to
     a browser scrollbar that hides part of the board. */
  overflow: hidden;
}
/* When _fitGameIframe inflates the iframe's logical size + scales
   it down, the overflow needs to be clipped to the grid row. */
.overlay.game-fullscreen { overflow: hidden; }
.overlay.game-fullscreen > :nth-child(2),
.overlay.game-fullscreen .game-iframe { overflow: hidden; }

/* Hint-buy bar above the iframe: live coin balance pill on the left,
   spend-10-coins "HINT" button on the right. Posts a 'ulearn-hint'
   message into the iframe; games listen and reveal a hint per their
   own rules. */
.game-hint-bar {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 12px;
  gap: 12px;
}
.game-coin-pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  color: var(--navy);
  font-family: var(--font-game);
  font-size: 20px;
  border: 2.5px solid var(--navy);
  border-radius: 999px;
  padding: 6px 16px 6px 8px;
  box-shadow: 0 3px 0 0 var(--navy);
  line-height: 1;
}
.game-coin-pill svg { width: 26px; height: 26px; }
.game-gem-pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: linear-gradient(180deg, #C9F2D6, #34C46F);
  color: var(--navy);
  font-family: var(--font-game);
  font-size: 20px;
  border: 2.5px solid var(--navy);
  border-radius: 999px;
  padding: 6px 16px 6px 8px;
  box-shadow: 0 3px 0 0 var(--navy);
  line-height: 1;
}
.game-gem-pill svg { width: 26px; height: 26px; }
/* Reveal-gem float — single emerald sprite, slightly larger and
   greener than the coin variant. */
.quiz-coin-bubble.reveal-gem {
  filter: drop-shadow(0 2px 0 rgba(43, 166, 122, 0.55));
}
/* Game-overlay XP pill — sibling of .game-coin-pill / .game-gem-pill
   in the top bar of the fullscreen game. Purple gradient so XP reads
   distinctly from coins (gold) and gems (green). */
.game-xp-pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: linear-gradient(180deg, #D5BFFF, #7B5BD8);
  color: var(--navy);
  font-family: var(--font-game);
  font-size: 20px;
  border: 2.5px solid var(--navy);
  border-radius: 999px;
  padding: 6px 16px 6px 8px;
  box-shadow: 0 3px 0 0 var(--navy);
  line-height: 1;
}
.game-xp-pill svg { width: 26px; height: 26px; }
.game-hint-note {
  font-family: var(--font-ui);
  font-size: 12px; font-weight: 700;
  color: rgba(255,255,255,0.7);
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.games-body { padding: 12px 14px 14px; }
.games-name {
  font-family: var(--font-game); font-size: 16px;
  color: var(--navy); letter-spacing: 0.5px;
  margin-bottom: 4px;
}
.games-desc {
  font-family: var(--font-ui); font-size: 12px; font-weight: 600;
  color: var(--navy); opacity: 0.65; line-height: 1.35;
}

/* ----- Family screen ----- */
.fam-list {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 12px;
}
.fam-card {
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  border-radius: 18px;
  padding: 14px;
  box-shadow: 0 5px 0 0 var(--navy);
  display: grid; grid-template-columns: 64px 1fr; gap: 12px; align-items: center;
  position: relative;
}
.fam-card .fam-avatar {
  width: 64px; height: 64px; border-radius: 14px;
  border: 3px solid var(--navy);
  display: grid; place-items: center;
  box-shadow: inset 0 -3px 0 rgba(0,0,0,0.2);
}
.fam-card .fam-avatar img {
  width: 52px; height: 52px;
  object-fit: contain;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
}
.fam-empty {
  grid-column: 1 / -1;
  text-align: center;
  padding: 28px 16px;
  font-family: var(--font-ui); font-weight: 700;
  color: #fff; opacity: 0.85;
  font-size: 13px;
  background: rgba(11, 30, 63, 0.4);
  border: 2px dashed rgba(255,255,255,0.35);
  border-radius: 16px;
}
.fam-card .fam-info { min-width: 0; }
.fam-card .fam-row {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.fam-card .fam-name {
  font-family: var(--font-game); font-size: 18px; color: var(--navy);
  letter-spacing: 0.4px; line-height: 1;
}
.fam-card .fam-streak-chip {
  font-family: var(--font-game); font-size: 16px; color: var(--navy);
  line-height: 1; white-space: nowrap;
}
.fam-card .fam-role {
  font-family: var(--font-ui); font-size: 11px; font-weight: 700;
  color: var(--navy); opacity: 0.55; letter-spacing: 0.04em; text-transform: uppercase;
  margin-top: 4px;
}
.fam-card .fam-today {
  font-family: var(--font-ui); font-size: 12px; font-weight: 700;
  color: var(--navy); opacity: 0.8;
  margin-top: 6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fam-card.parent {
  background: linear-gradient(180deg, #D7C2F0 0%, #8B5DC7 100%);
}
.fam-card.parent .fam-name,
.fam-card.parent .fam-role,
.fam-card.parent .fam-today,
.fam-card.parent .fam-streak-chip { color: #fff; }
.fam-card.parent .fam-role { opacity: 0.85; }
.fam-card.me {
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 100%);
}
.fam-card .me-tag {
  position: absolute; top: -8px; left: 14px;
  background: var(--navy); color: #fff;
  font-family: var(--font-game); font-size: 10px;
  padding: 3px 10px; border-radius: 6px;
  letter-spacing: 0.06em;
  box-shadow: 0 2px 0 rgba(0,0,0,0.3);
}

/* ============================================================
   Today's schedule (top of Reviews screen)
   ============================================================ */
.schedule {
  background: linear-gradient(180deg, rgba(255,255,255,0.10) 0%, rgba(0,0,0,0.15) 100%);
  border: 2.5px solid rgba(255,255,255,0.18);
  border-radius: 16px;
  padding: 12px 16px;
  display: grid; grid-template-columns: auto 1fr; gap: 16px; align-items: center;
}
.schedule .sched-head { display: flex; flex-direction: column; gap: 4px; min-width: 140px; }
.schedule .sched-head .lbl {
  font-family: var(--font-ui); font-size: 10px; font-weight: 800;
  color: #FFE38A; letter-spacing: 0.08em; text-transform: uppercase;
}
.schedule .sched-head .total {
  font-family: var(--font-game); font-size: 28px; color: #fff;
  line-height: 1; text-shadow: 0 2px 0 rgba(0,0,0,0.4);
}
.schedule .sched-head .sub {
  font-family: var(--font-ui); font-size: 12px; font-weight: 700;
  color: rgba(255,255,255,0.7);
}
.schedule .timeline {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
}
.timeline .slot {
  background: rgba(255,255,255,0.08);
  border: 2px solid rgba(255,255,255,0.14);
  border-radius: 12px;
  padding: 8px 10px;
  display: flex; flex-direction: column; gap: 2px;
}
.timeline .slot .time {
  font-family: var(--font-game); font-size: 14px; color: #FFE38A;
  letter-spacing: 0.5px; line-height: 1;
}
.timeline .slot .subj {
  font-family: var(--font-ui); font-size: 12px; font-weight: 700; color: #fff;
}
.timeline .slot .count {
  font-family: var(--font-ui); font-size: 10px; font-weight: 700;
  color: rgba(255,255,255,0.65); letter-spacing: 0.04em; text-transform: uppercase;
}

/* ============================================================
   Course detail screen
   ============================================================ */
.course-shell {
  display: grid; grid-template-columns: 320px 1fr; gap: 16px;
  align-items: start;
  flex-shrink: 0;
}
.lesson-list {
  background: rgba(0,0,0,0.18);
  border: 2.5px solid rgba(255,255,255,0.14);
  border-radius: 16px;
  padding: 16px;
  display: flex; flex-direction: column; gap: 10px;
  max-height: 640px; overflow: auto;
}
.lesson-list .lh {
  display: flex; justify-content: space-between; align-items: center;
  font-family: var(--font-game); font-size: 15px; color: #FFE38A;
  letter-spacing: 0.5px; padding: 4px 8px 10px;
  border-bottom: 1.5px dashed rgba(255,255,255,0.18);
  margin-bottom: 6px;
}
/* SCOPED. The teacher's create page also renders elements with class
   `lesson-row` (the per-lesson edit card). Without :where() scoping
   here the kid's grid layout below was bleeding into that page and
   squashing the lesson-row-header into a 40px-wide chip — visible
   as a stray "1" badge floating to the left of the cards. The
   :where() keeps specificity at (0,1,0) per the memory note about
   the button reset, so the kid styles win in the kid context by
   cascade order without overpowering other per-class rules. */
:where(body.child-dashboard-active) .lesson-row {
  display: grid; grid-template-columns: 40px 1fr auto; gap: 14px; align-items: center;
  padding: 16px 18px;
  border-radius: 14px;
  background: rgba(255,255,255,0.04);
  border: 2px solid transparent;
  cursor: pointer;
  transition: background 100ms ease, border-color 100ms ease;
  min-height: 56px;
}
:where(body.child-dashboard-active) .lesson-row:hover { background: rgba(255,255,255,0.10); }
:where(body.child-dashboard-active) .lesson-row.active {
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 100%);
  border-color: var(--navy);
  box-shadow: 0 3px 0 0 var(--navy);
}
:where(body.child-dashboard-active) .lesson-row .dot {
  width: 32px; height: 32px; border-radius: 50%;
  background: rgba(255,255,255,0.20);
  border: 2px solid rgba(255,255,255,0.30);
  display: grid; place-items: center;
  font-family: var(--font-game); font-size: 14px; color: #fff;
  line-height: 1;
}
:where(body.child-dashboard-active) .lesson-row.active .dot {
  background: var(--navy); border-color: var(--navy); color: #fff;
}
:where(body.child-dashboard-active) .lesson-row .name {
  font-family: var(--font-ui); font-size: 16px; font-weight: 800;
  color: #fff; line-height: 1.25;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
:where(body.child-dashboard-active) .lesson-row.active .name { color: var(--navy); }
:where(body.child-dashboard-active) .lesson-row .cards-chip {
  font-family: var(--font-game); font-size: 13px; color: rgba(255,255,255,0.65);
  white-space: nowrap; line-height: 1;
  letter-spacing: 0.3px;
}
:where(body.child-dashboard-active) .lesson-row.active .cards-chip { color: var(--navy); }

/* Daily-goal tinting for lessons.
   - goal-green: assigned today, kid still needs to do it
   - goal-blue:  assigned and completed today (or marked done)
   - goal-grey:  not part of today's plan
   `active` keeps its gold gradient on top — colored left border
   so the kid still sees the goal status when the lesson is selected. */
:where(body.child-dashboard-active) .lesson-row.goal-green {
  background: linear-gradient(180deg, rgba(94, 212, 168, 0.20), rgba(94, 212, 168, 0.08));
  border-left: 4px solid #34C46F;
}
:where(body.child-dashboard-active) .lesson-row.goal-green:hover { background: linear-gradient(180deg, rgba(94, 212, 168, 0.30), rgba(94, 212, 168, 0.14)); }
:where(body.child-dashboard-active) .lesson-row.goal-blue {
  background: linear-gradient(180deg, rgba(77, 183, 232, 0.20), rgba(77, 183, 232, 0.08));
  border-left: 4px solid #2E8FBF;
}
:where(body.child-dashboard-active) .lesson-row.goal-blue:hover { background: linear-gradient(180deg, rgba(77, 183, 232, 0.30), rgba(77, 183, 232, 0.14)); }
:where(body.child-dashboard-active) .lesson-row.goal-grey {
  background: rgba(255,255,255,0.03);
  border-left: 4px solid rgba(255,255,255,0.18);
  opacity: 0.65;
}
:where(body.child-dashboard-active) .lesson-row.goal-grey:hover { opacity: 0.85; background: rgba(255,255,255,0.07); }
:where(body.child-dashboard-active) .lesson-row.active.goal-green,
:where(body.child-dashboard-active) .lesson-row.active.goal-blue,
:where(body.child-dashboard-active) .lesson-row.active.goal-grey {
  /* Active gold gradient stays; left border encodes goal status. */
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 100%);
  opacity: 1;
}

.course-main {
  display: flex; flex-direction: column; gap: 14px;
}
.video-hero {
  position: relative;
  /* Fixed 40vh height, full column width — YouTube's own iframe
     letterboxes the 16/9 video inside the box on any viewport.
     Dropped aspect-ratio entirely because its interaction with
     max-height + flex stretch was collapsing the box to ~0px on
     some viewports. Explicit height = box always viewable. */
  height: 40vh;
  width: 100%;
  border-radius: 16px; overflow: hidden;
  border: 3px solid var(--navy);
  box-shadow: 0 5px 0 0 var(--navy);
  background: linear-gradient(160deg, #FFB8C7 0%, #E04848 50%, #8B5DC7 100%);
  display: grid; place-items: center;
}
/* Post-video popup — shown by _wireVideoEndDetect when the YouTube
   iframe reports playerState=0 (ended). Sits on top of the iframe
   with z-index 5 so the kid can tap it without scrolling. */
.video-quiz-overlay {
  position: absolute; inset: 0; z-index: 5;
  display: none;
  align-items: center; justify-content: center;
  background: radial-gradient(circle at 50% 45%, rgba(11, 30, 63, 0.78) 0%, rgba(11, 30, 63, 0.94) 70%);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  animation: cgdVideoEndFadeIn 220ms ease-out;
}
.video-quiz-overlay.is-visible { display: flex; }
.video-quiz-overlay .vqo-card {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 20px 28px;
}
.video-quiz-overlay .vqo-eyebrow {
  font-family: var(--font-game); font-size: 14px; color: #FFE38A;
  letter-spacing: 0.18em; text-transform: uppercase;
}
.video-quiz-overlay .vqo-btn {
  border: 3px solid var(--navy); border-radius: 14px;
  font-family: var(--font-game); font-size: 22px;
  color: var(--navy); letter-spacing: 0.8px;
  padding: 16px 32px;
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 60%, #C18C12 100%);
  box-shadow: 0 5px 0 0 var(--navy);
  text-shadow: 0 2px 0 rgba(255,255,255,0.4);
  cursor: pointer;
  transition: transform 80ms ease, box-shadow 80ms ease;
}
.video-quiz-overlay .vqo-btn:active {
  transform: translateY(3px); box-shadow: 0 2px 0 0 var(--navy);
}
@keyframes cgdVideoEndFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.video-hero::after {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(circle at 30% 30%, rgba(255,255,255,0.25), transparent 40%),
    radial-gradient(circle at 70% 80%, rgba(0,0,0,0.30), transparent 50%);
  pointer-events: none;
}
/* When the YouTube iframe is mounted, hide the decorative gradient
   so it doesn't haze the video poster. */
.video-hero[data-cgd-video-host]::after { display: none; }
.video-hero iframe[data-cgd-video-iframe] { z-index: 1; }
.video-hero .play-circle {
  position: relative; z-index: 2;
  width: 92px; height: 92px; border-radius: 50%;
  background: linear-gradient(180deg, #FF6464, #C0392B);
  border: 4px solid #fff;
  display: grid; place-items: center;
  box-shadow: 0 6px 0 0 rgba(0,0,0,0.35);
}
.video-hero .play-circle svg { width: 36px; height: 36px; fill: #fff; margin-left: 6px; }
.video-hero .vh-badge {
  position: absolute; top: 14px; left: 14px; z-index: 3;
  display: flex; align-items: center; gap: 8px;
  background: rgba(7, 32, 65, 0.85);
  border: 2px solid rgba(255,255,255,0.16);
  border-radius: 999px; padding: 5px 12px 5px 5px;
}
.video-hero .vh-badge .av {
  width: 26px; height: 26px; border-radius: 50%;
  background: #FFE38A; display: grid; place-items: center;
  font-size: 14px;
}
.video-hero .vh-badge .who {
  font-family: var(--font-ui); font-size: 11px; font-weight: 800; color: #fff;
  text-transform: uppercase; letter-spacing: 0.06em;
}

/* ─── Non-video lesson material ─────────────────────────────────
   The course-detail hero box also hosts uploaded MP3 / PDF / DOCX
   and plain-text lesson notes. Same chunky navy border + sticker
   shadow as .video-hero so the layout reads consistent regardless
   of material type. .video-hero[data-cgd-file-host] keeps the 16/9
   box for uploaded MP4s; the other variants use their own sizing. */
.video-hero[data-cgd-file-host] .lesson-hero-video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: block; background: #000;
}
.video-hero[data-cgd-file-host]::after { display: none; }
.lesson-hero {
  position: relative;
  border-radius: 16px;
  border: 3px solid var(--navy);
  box-shadow: 0 5px 0 0 var(--navy);
  overflow: hidden;
  background: linear-gradient(160deg, #FFE48A 0%, #F0B520 50%, #C0700A 100%);
}
.lesson-hero-loading {
  position: absolute; inset: 0; display: grid; place-items: center;
  color: #fff; font-family: var(--font-game); font-size: 16px;
  letter-spacing: 0.6px; text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  background: rgba(7,32,65,0.55);
}
.lesson-hero-missing {
  padding: 28px 22px; min-height: 120px;
  display: grid; place-items: center; text-align: center;
  font-family: var(--font-ui); font-size: 14px; font-weight: 700;
  color: rgba(255,255,255,0.92);
  background: rgba(7,32,65,0.45);
  text-shadow: 0 2px 0 rgba(0,0,0,0.3);
}
.lesson-hero-dl {
  display: inline-block; margin-top: 6px;
  padding: 10px 18px;
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  border: 3px solid var(--navy); border-radius: 12px;
  font-family: var(--font-game); font-size: 14px;
  color: var(--navy); letter-spacing: 0.6px;
  box-shadow: 0 4px 0 0 var(--navy);
  text-decoration: none;
}
.lesson-hero-dl:active { transform: translateY(2px); box-shadow: 0 2px 0 0 var(--navy); }

/* Audio: chunky owl-yellow card with a big headphone glyph above
   the native audio controls. Comfortable tap targets for kids. */
.lesson-hero--audio {
  background: linear-gradient(160deg, #B0E5FF 0%, #3FA6E5 50%, #1E5B92 100%);
  padding: 22px 22px 18px;
}
.lesson-hero--audio .audio-hero-inner {
  display: grid; gap: 12px; place-items: center;
}
.lesson-hero--audio .audio-hero-art {
  font-size: 52px; line-height: 1;
  filter: drop-shadow(0 3px 0 rgba(0,0,0,0.4));
}
.lesson-hero--audio .audio-hero-name {
  font-family: var(--font-game); font-size: 16px;
  color: #fff; letter-spacing: 0.4px; text-align: center;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  max-width: 100%; word-break: break-word;
}
.lesson-hero--audio audio {
  width: 100%; max-width: 480px;
  /* Native controls keep their own look; the surrounding box is
     branded so the audio reads as part of the lesson, not a stray
     player chrome. */
}

/* PDF: fixed-height scrollable canvas area. The internal pdf.js
   render writes a column of .pdf-page elements; we clip them to
   the hero box so tall lecture decks don't blow the layout. */
.lesson-hero--pdf {
  background: #1d2a3d;
  height: clamp(360px, 56vh, 620px);
}
.lesson-hero--pdf .pdf-hero-canvas {
  position: absolute; inset: 0;
  overflow-y: auto; overflow-x: hidden;
  padding: 14px;
  display: flex; flex-direction: column; align-items: stretch; gap: 14px;
  -webkit-overflow-scrolling: touch;
}
/* pdf.js writes an inline `width:857px;height:1109px` on each
   .pdf-page (and an 857-wide bitmap on the canvas). On narrow
   screens that overflows the hero box; max-width:100% alone
   doesn't help because the outer .pdf-pages flex container with
   align-items:center lets the page keep its intrinsic size and
   just clips on both sides. Force a full-width override and let
   the canvas's intrinsic aspect ratio drive the height. */
.lesson-hero--pdf .pdf-pages {
  width: 100%;
  max-width: 100%;
  align-self: stretch;
  align-items: stretch;
}
.lesson-hero--pdf .pdf-page {
  background: #fff;
  border-radius: 6px;
  box-shadow: 0 3px 10px rgba(0,0,0,0.35);
  /* --pdf-zoom drives a uniform up/down scale on every page; the kid
     can press the ± buttons to step between 50% and 300%. The canvas
     bitmap stays at pdf.js's full-resolution render so zoomed-in text
     doesn't pixelate. Without an explicit zoom value the CSS variable
     falls back to 1, i.e. the previous fit-to-width behaviour. */
  width: calc(100% * var(--pdf-zoom, 1)) !important;
  max-width: none !important;
  height: auto !important;
}
.lesson-hero--pdf .pdf-page canvas {
  width: 100%;
  height: auto;
  display: block;
}
.lesson-hero--pdf .pdf-hero-canvas {
  /* On zoom-in the rendered page is wider than the hero; let the
     kid scroll sideways to reach the right edge instead of clipping. */
  overflow-x: auto;
}
/* The text layer is positioned by pdf.js using the original
   render scale; once the canvas is CSS-scaled down to fit, those
   spans land in the wrong places and create selection halos
   over the wrong words. Kids don't need find-in-text, so we
   hide it in this view. */
.lesson-hero--pdf .pdf-page .pdf-text-layer {
  display: none;
}
.lesson-hero-pdf-iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%; border: 0;
  background: #fff;
}

/* DOCX: rendered as HTML by mammoth, lives inside the same hero
   box. Paper-like surface, scrollable, kid-friendly type. */
.lesson-hero--docx {
  background: #FFFCF3;
  height: clamp(360px, 56vh, 620px);
}
.lesson-hero--docx .docx-hero-body {
  position: absolute; inset: 0;
  overflow-y: auto;
  padding: 22px 26px;
  font-family: var(--font-ui);
  font-size: 15px; line-height: 1.6;
  color: #0B1E3F;
  -webkit-overflow-scrolling: touch;
}
.lesson-hero--docx .docx-hero-body h1,
.lesson-hero--docx .docx-hero-body h2,
.lesson-hero--docx .docx-hero-body h3 {
  font-family: var(--font-game); color: #0B1E3F; margin: 14px 0 6px;
}
.lesson-hero--docx .docx-hero-body p { margin: 0 0 10px; }

/* Plain-text lesson notes (no file uploaded). Same paper surface
   as DOCX but no async render — text is dropped in inline by
   _renderKidVideoHero. */
.lesson-hero--text {
  background: #FFFCF3;
  height: clamp(280px, 48vh, 520px);
  text-align: left;
}
.lesson-hero--text .lesson-hero-text-head {
  position: absolute; top: 0; left: 0; right: 0;
  padding: 10px 16px;
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  border-bottom: 3px solid var(--navy);
  font-family: var(--font-game); font-size: 14px;
  color: #0B1E3F; letter-spacing: 0.5px;
}
.lesson-hero--text .lesson-hero-text-body {
  position: absolute; top: 42px; left: 0; right: 0; bottom: 0;
  overflow-y: auto;
  padding: 16px 22px 22px;
  font-family: var(--font-ui);
  font-size: 15px; line-height: 1.6;
  color: #0B1E3F;
  white-space: pre-wrap;
  -webkit-overflow-scrolling: touch;
}

.lesson-meta {
  background: rgba(0,0,0,0.18);
  border: 2.5px solid rgba(255,255,255,0.14);
  border-radius: 16px;
  padding: 14px 16px;
}
.lesson-meta .lm-title {
  font-family: var(--font-game); font-size: 22px; color: #fff;
  letter-spacing: 0.6px; line-height: 1.1;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
}
.lesson-meta .lm-stats {
  display: flex; gap: 14px; margin-top: 6px;
  font-family: var(--font-ui); font-size: 12px; font-weight: 700;
  color: rgba(255,255,255,0.75); letter-spacing: 0.04em; text-transform: uppercase;
}
.lesson-meta .lm-stats span strong {
  color: #FFE38A; margin-right: 4px;
  font-family: var(--font-game); font-size: 14px; letter-spacing: 0.4px;
}

.lesson-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.lesson-btn {
  border: 3px solid var(--navy); border-radius: 14px;
  font-family: var(--font-game); font-size: 18px;
  color: var(--navy); letter-spacing: 0.8px;
  padding: 14px 18px;
  box-shadow: 0 5px 0 0 var(--navy);
  text-shadow: 0 2px 0 rgba(255,255,255,0.4);
  transition: transform 80ms ease, box-shadow 80ms ease;
}
.lesson-btn:active { transform: translateY(3px); box-shadow: 0 2px 0 0 var(--navy); }
.lesson-btn.start { background: linear-gradient(180deg, #FFE38A 0%, #F0C040 60%, #C18C12 100%); }
.lesson-btn.practice { background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%); }

/* ----- Progress map ----- */
.stage-map {
  background: rgba(0,0,0,0.18);
  border: 2.5px solid rgba(255,255,255,0.14);
  border-radius: 16px;
  padding: 14px 16px 16px;
  display: flex; flex-direction: column; gap: 10px;
  flex-shrink: 0;
}
.stage-map .map-title {
  font-family: var(--font-game); font-size: 16px; color: #FFE38A;
  letter-spacing: 0.6px;
}
.stage-bar {
  display: flex; height: 22px; border-radius: 999px;
  background: rgba(0,0,0,0.30);
  border: 2.5px solid var(--navy);
  overflow: hidden;
}
.stage-bar .seg {
  height: 100%;
  box-shadow: inset 0 -3px 0 rgba(0,0,0,0.20), inset 0 3px 0 rgba(255,255,255,0.25);
  transition: width 300ms var(--ease-spring, ease-out);
}
.stage-stats { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
.stage-stat {
  background: rgba(255,255,255,0.06);
  border: 2px solid rgba(255,255,255,0.14);
  border-radius: 10px; padding: 6px 4px;
  text-align: center;
  display: flex; flex-direction: column; gap: 1px;
  align-items: center;
  min-width: 0;
  overflow: hidden;
}
.stage-stat .dot {
  width: 10px; height: 10px; border-radius: 50%;
  border: 1.5px solid var(--navy);
  flex-shrink: 0;
}
.stage-stat .lbl {
  font-family: var(--font-ui); font-size: 9px; font-weight: 800;
  color: rgba(255,255,255,0.75); letter-spacing: 0.04em; text-transform: uppercase;
  line-height: 1;
  max-width: 100%;
}
.stage-stat .num {
  font-family: var(--font-game); font-size: 18px; color: #fff;
  line-height: 1; text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  max-width: 100%;
}

/* ============================================================
   Review session (quiz) screen
   ============================================================ */
/* ----- Quiz theme tokens. data-quiz-theme on .quiz-overlay flips
   the whole quiz between the bright Brawl Stars "sky" palette
   (current default) and an Acellus Gold "navy" palette (deep teal +
   cyan glow). Toggle button lives in the top nav. Every quiz-side
   class below references --q-* tokens so the same markup themes
   both ways. */
.quiz-overlay[data-quiz-theme="sky"] {
  --q-bg-top: var(--game-sky-top);
  --q-bg-bot: var(--game-sky-bot);
  --q-accent:        #F0C040;
  --q-accent-glow:   rgba(255,227,138,0.55);
  --q-yellow:        #FFE38A;
  --q-yellow-deep:   #C18C12;
  --q-card-bg:       linear-gradient(180deg, #FFFCF3 0%, #FBF3DC 100%);
  --q-card-border:   var(--navy);
  --q-card-text:     var(--navy);
  --q-text:          #fff;
  --q-text-dim:      rgba(255,255,255,0.75);
  --q-pill-bg:       linear-gradient(180deg, #FFFCF3 0%, #FBF3DC 100%);
  --q-pill-border:   var(--navy);
  --q-pill-text:     var(--navy);
  --q-pill-shadow:   0 4px 0 0 var(--navy);
  --q-kicker:        var(--navy);
  --q-stripe-1:      #F09020;
  --q-stripe-2:      #F0C040;
  --q-stripe-3:      #106090;
}
.quiz-overlay[data-quiz-theme="navy"] {
  --q-bg-top:        #103043;
  --q-bg-bot:        #051421;
  --q-accent:        #3DD2D6;
  --q-accent-glow:   rgba(61,210,214,0.55);
  --q-yellow:        #F5C73E;
  --q-yellow-deep:   #C99A14;
  --q-card-bg:       linear-gradient(180deg, rgba(20,45,60,0.78), rgba(8,24,38,0.78));
  --q-card-border:   rgba(61,210,214,0.55);
  --q-card-text:     #E8F6F8;
  --q-text:          #E8F6F8;
  --q-text-dim:      rgba(232,246,248,0.6);
  --q-pill-bg:       linear-gradient(180deg, rgba(15,42,58,0.85), rgba(8,28,42,0.85));
  --q-pill-border:   rgba(61,210,214,0.6);
  --q-pill-text:     #E8F6F8;
  --q-pill-shadow:   0 0 18px rgba(61,210,214,0.18), inset 0 0 24px rgba(61,210,214,0.06);
  --q-kicker:        #3DD2D6;
  --q-stripe-1:      #3DD2D6;
  --q-stripe-2:      #5FE3E8;
  --q-stripe-3:      #88F0F2;
}

.quiz-overlay {
  position: fixed; inset: 0; z-index: 60;
  background:
    radial-gradient(120% 80% at 50% 0%, var(--q-bg-top, var(--game-sky-top)) 0%, transparent 55%),
    linear-gradient(180deg, var(--q-bg-top, var(--game-sky-top)) 0%, var(--q-bg-bot, var(--game-sky-bot)) 100%);
  /* 4 rows: top nav (BACK / progress / counter / home), the streak
     pass mini owl-pass, the question card (always visible), then
     the scrolling body (toggle, choices, feedback, dunno, nav
     arrows). The streak-pass added a fourth child to this grid, so
     the explicit template is 4 rows — without the second `auto`
     the card would land in the 1fr row and inherit its full
     height, clipping multi-line questions. */
  display: grid; grid-template-rows: 80px auto auto 1fr;
  gap: 14px;
  padding: 16px 32px 24px;
}
.quiz-top {
  display: grid; grid-template-columns: auto 1fr auto auto auto; gap: 14px; align-items: center;
}

/* Coin counter chip in the quiz top bar — grows as the kid answers
   correctly. The .pop class triggers a one-shot scale punch when the
   value changes (applied by JS right after a coin floater arrives). */
.quiz-coin-counter {
  display: inline-flex; align-items: center; gap: 6px;
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  color: var(--navy);
  font-family: var(--font-game);
  font-size: 18px;
  border: 2.5px solid var(--navy);
  border-radius: 999px;
  padding: 6px 14px 6px 8px;
  box-shadow: 0 3px 0 0 var(--navy);
  line-height: 1;
  min-width: 64px;
  justify-content: center;
}
.quiz-coin-counter svg { width: 22px; height: 22px; flex-shrink: 0; }
.quiz-coin-counter.pop { animation: quizCoinPop 380ms ease-out; }
@keyframes quizCoinPop {
  0%   { transform: scale(1);    }
  40%  { transform: scale(1.18); }
  100% { transform: scale(1);    }
}

/* Sister chip to .quiz-coin-counter. Same shape so the two read
   as a HUD pair; green gradient distinguishes it as emeralds. */
.quiz-gem-counter {
  display: inline-flex; align-items: center; gap: 6px;
  background: linear-gradient(180deg, #C9F2D6, #34C46F);
  color: var(--navy);
  font-family: var(--font-game);
  font-size: 18px;
  border: 2.5px solid var(--navy);
  border-radius: 999px;
  padding: 6px 14px 6px 8px;
  box-shadow: 0 3px 0 0 var(--navy);
  line-height: 1;
  min-width: 64px;
  justify-content: center;
  margin-left: 8px;
}
.quiz-gem-counter svg { width: 22px; height: 22px; flex-shrink: 0; }
.quiz-gem-counter.pop { animation: quizCoinPop 380ms ease-out; }

/* Quiz top-bar XP chip — sibling of .quiz-coin-counter and
   .quiz-gem-counter. Purple gradient matches the HUD .chip.xp. */
.quiz-xp-counter {
  display: inline-flex; align-items: center; gap: 6px;
  background: linear-gradient(180deg, #D5BFFF, #7B5BD8);
  color: var(--navy);
  font-family: var(--font-game);
  font-size: 18px;
  border: 2.5px solid var(--navy);
  border-radius: 999px;
  padding: 6px 14px 6px 8px;
  box-shadow: 0 3px 0 0 var(--navy);
  line-height: 1;
  min-width: 64px;
  justify-content: center;
  margin-left: 8px;
}
.quiz-xp-counter svg { width: 22px; height: 22px; flex-shrink: 0; }

/* Streak pass — compact mini owl-pass in the upper-right of the
   quiz screen. Fills 0→5 with consecutive correct answers; each
   completed level grants the milestone gem reward shown on the
   right. Lives in the grid's row-2 (the question-card row) but
   positioned absolutely so it doesn't push the card down. Top
   offset matches the 80 px quiz-top + 14 px gap from the overlay
   grid; right offset matches the overlay's 32 px padding. */
.quiz-streak-pass {
  /* Sit in row 2 of the .quiz-overlay grid, right-aligned and
     narrow so the chips/HOME button above stay uncovered and the
     question card below isn't pushed far. */
  width: 100%;
  max-width: 280px;
  margin: 4px 0 0 auto;
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 8px;
  align-items: center;
  background: linear-gradient(180deg, #0E3F75 0%, #061C3A 100%);
  border: 2.5px solid var(--navy);
  border-radius: 14px;
  padding: 7px 10px;
  box-shadow: 0 3px 0 0 var(--navy);
}
.quiz-streak-pass .qsp-icon {
  width: 26px; height: 26px; border-radius: 8px;
  background: linear-gradient(180deg, #B3F5C5, #34C46F 70%, #115E2C);
  border: 2px solid var(--navy);
  display: grid; place-items: center;
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.2), inset 0 2px 0 rgba(255,255,255,0.25);
}
.quiz-streak-pass .qsp-icon svg { width: 18px; height: 18px; }
.quiz-streak-pass .qsp-meta {
  display: flex; flex-direction: column; gap: 3px; min-width: 0;
}
.quiz-streak-pass .qsp-head {
  display: flex; align-items: center; gap: 6px;
  font-family: var(--font-game); font-size: 10px;
  color: #fff; line-height: 1; letter-spacing: 0.5px;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
}
.quiz-streak-pass .qsp-label { color: rgba(255,255,255,0.7); }
.quiz-streak-pass .qsp-level {
  background: rgba(255,255,255,0.12);
  border: 1.5px solid rgba(255,255,255,0.25);
  padding: 1px 6px; border-radius: 999px;
  color: #FFE38A;
  font-size: 9px;
}
.quiz-streak-pass .qsp-count {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  color: rgba(255,255,255,0.85);
  font-size: 10px;
}
.quiz-streak-pass .qsp-bar {
  height: 8px; border-radius: 999px;
  background: rgba(0,0,0,0.45);
  border: 1.5px solid var(--navy);
  overflow: hidden; position: relative;
}
.quiz-streak-pass .qsp-fill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(180deg, #B3F5C5 0%, #34C46F 60%, #1F8C4D 100%);
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.25), inset 0 2px 0 rgba(255,255,255,0.30);
  transition: width 320ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.quiz-streak-pass .qsp-reward {
  display: none; /* tucked into the meta header to save space */
}
.quiz-streak-pass .qsp-reward-inline {
  display: inline-flex; align-items: center; gap: 3px;
  font-family: var(--font-game); font-size: 10px;
  background: linear-gradient(180deg, #C9F2D6, #5ED4A8);
  color: var(--navy);
  border: 1.5px solid var(--navy);
  border-radius: 999px;
  padding: 1px 6px 1px 4px;
  line-height: 1;
}
.quiz-streak-pass .qsp-reward-inline svg { width: 11px; height: 11px; }

/* "+N XP" floating label — pops at the source, drifts up and
   inward toward the XP counter, fades on landing. */
.xp-float-label {
  position: fixed;
  z-index: 202;
  pointer-events: none;
  transform: translate(-50%, -50%);
  font-family: var(--font-game);
  font-size: 22px;
  letter-spacing: 0.5px;
  color: #7B5BD8;
  text-shadow:
     2px 2px 0 var(--navy),
    -2px 2px 0 var(--navy),
     2px -2px 0 var(--navy),
    -2px -2px 0 var(--navy);
  line-height: 1;
  animation: xpFloatFly 950ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
  opacity: 0;
}
@keyframes xpFloatFly {
  0%   { transform: translate(-50%, -50%) scale(0.6); opacity: 0; }
  20%  { transform: translate(-50%, -90%) scale(1.15); opacity: 1; }
  85%  {
    transform:
      translate(calc(-50% + var(--end-x, 0px) * 0.95),
                calc(-50% + var(--end-y, 0px) * 0.95))
      scale(0.85);
    opacity: 1;
  }
  100% {
    transform:
      translate(calc(-50% + var(--end-x, 0px)),
                calc(-50% + var(--end-y, 0px)))
      scale(0.6);
    opacity: 0;
  }
}

/* ============ LEVEL-UP OVERLAY ============
   Ported from the design's game-levelup.jsx. Multi-step sequence:
   "LEVEL UP!" banner with giant level ball → one reward card per
   reward, tap anywhere to advance. Rotating ray-burst, falling
   confetti, twinkling sparkles render behind everything. */
.lvl-overlay {
  position: fixed; inset: 0; z-index: 9999;
  background: radial-gradient(ellipse at center, rgba(7,32,65,0.85) 0%, rgba(7,32,65,0.96) 70%);
  display: grid; place-items: center;
  cursor: pointer;
  overflow: hidden;
  animation: lvlup-overlay-in 220ms ease-out both;
}
@keyframes lvlup-overlay-in { from { opacity: 0; } to { opacity: 1; } }
.lvl-overlay.is-dismissing {
  animation: lvlup-overlay-out 200ms ease-in both;
  pointer-events: none;
}
@keyframes lvlup-overlay-out { from { opacity: 1; } to { opacity: 0; } }
.lvl-overlay .lvl-content {
  position: relative; z-index: 2;
  display: grid; place-items: center;
}
.lvl-overlay .tap-hint {
  position: absolute; bottom: 32px; left: 50%; transform: translateX(-50%);
  font-family: var(--font-game); font-size: 14px; letter-spacing: 1.5px;
  color: rgba(255,255,255,0.65);
  text-shadow: 0 2px 0 rgba(0,0,0,0.5);
  animation: tapPulse 1.4s ease-in-out infinite;
  z-index: 3;
}
@keyframes tapPulse {
  0%, 100% { opacity: 0.5; transform: translate(-50%, 0)    scale(1); }
  50%      { opacity: 1;   transform: translate(-50%, -2px) scale(1.05); }
}

/* FocusBurst — rays radiate from the wrapped focal element (level
   ball or reward icon) so the burst feels tied to what you're
   getting, not the whole screen. */
.lvl-overlay .focus-burst {
  position: relative;
  display: grid; place-items: center;
  isolation: isolate;
}
.lvl-overlay .focus-burst > .focus-rays {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 1200px; height: 1200px;
  pointer-events: none;
  z-index: 0;
}
.lvl-overlay .focus-burst > .focus-rays svg {
  width: 100%; height: 100%;
  animation: rayspin 14s linear infinite;
  filter: drop-shadow(0 0 40px rgba(255, 220, 140, 0.55));
}
.lvl-overlay .focus-burst > .focus-content {
  position: relative;
  z-index: 1;
}
@keyframes rayspin { to { transform: rotate(360deg); } }

/* Falling confetti */
.lvl-overlay .confetti {
  position: absolute; inset: 0;
  pointer-events: none; overflow: hidden;
}
.lvl-overlay .confetti i {
  position: absolute; top: -20px;
  width: 12px; height: 16px; border-radius: 2px;
  animation: fall linear infinite;
}
@keyframes fall {
  0%   { transform: translateY(-40px) rotate(0deg); opacity: 1; }
  100% { transform: translateY(120vh) rotate(720deg); opacity: 0.6; }
}

/* Twinkling sparkles */
.lvl-overlay .sparkles { position: absolute; inset: 0; pointer-events: none; }
.lvl-overlay .sparkles span {
  position: absolute; font-size: 22px;
  animation: sparkle 1.6s ease-in-out infinite;
  filter: drop-shadow(0 0 6px rgba(255, 220, 140, 0.8));
}
@keyframes sparkle {
  0%, 100% { opacity: 0; transform: scale(0.4); }
  50%      { opacity: 1; transform: scale(1.2); }
}

/* LEVEL UP! banner — step -1 */
.lvl-up-banner {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 18px;
  animation: lvlEnter 600ms cubic-bezier(.34,1.56,.64,1) both;
}
@keyframes lvlEnter {
  0%   { transform: scale(0.3) rotate(-8deg); opacity: 0; }
  60%  { transform: scale(1.15) rotate(2deg);  opacity: 1; }
  100% { transform: scale(1) rotate(0); }
}
.lvl-up-banner h1 {
  font-family: var(--font-game);
  font-size: clamp(72px, 11vw, 140px);
  line-height: 0.9; letter-spacing: 4px;
  color: #FFE38A;
  text-shadow:
    0 0 30px rgba(255, 220, 140, 0.8),
    0 6px 0 #C18C12,
    0 10px 0 var(--navy),
    0 14px 30px rgba(0,0,0,0.6);
  -webkit-text-stroke: 4px var(--navy);
  paint-order: stroke fill;
  text-align: center;
  margin: 0;
  animation: lvlPulse 1.6s ease-in-out infinite;
}
@keyframes lvlPulse {
  0%, 100% { transform: scale(1);    }
  50%      { transform: scale(1.04); }
}
.lvl-up-banner .lvl-num {
  display: grid; place-items: center;
  width: 240px; height: 240px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #FFE48A 0%, #F0C040 50%, #A86E0A 100%);
  border: 7px solid var(--navy);
  box-shadow:
    inset 0 -10px 0 rgba(0,0,0,0.20),
    inset 0 10px 0 rgba(255,255,255,0.35),
    0 14px 0 var(--navy),
    0 0 80px rgba(255, 220, 140, 0.5);
  font-family: var(--font-game);
  font-size: 140px; line-height: 1;
  color: #fff;
  -webkit-text-stroke: 4px var(--navy);
  paint-order: stroke fill;
  text-shadow: 0 6px 0 var(--navy);
  animation: numBounce 600ms cubic-bezier(.34,1.56,.64,1) 200ms both;
}
@keyframes numBounce {
  0%   { transform: translateY(-200px) scale(0.4); opacity: 0; }
  70%  { transform: translateY(15px)   scale(1.05); opacity: 1; }
  100% { transform: translateY(0)      scale(1); }
}
.lvl-up-banner .sub {
  font-family: var(--font-game); font-size: 22px; color: #fff;
  letter-spacing: 1.5px;
  text-shadow: 0 3px 0 rgba(0,0,0,0.5);
}

/* Reward reveal — one card per step */
.lvl-overlay .reward-card {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  animation: revealEnter 500ms cubic-bezier(.34,1.56,.64,1) both;
}
@keyframes revealEnter {
  0%   { transform: scale(0.5) translateY(60px); opacity: 0; }
  60%  { transform: scale(1.08) translateY(-10px); opacity: 1; }
  100% { transform: scale(1) translateY(0); }
}
.lvl-overlay .reward-card .reward-icon {
  width: 220px; height: 220px;
  border-radius: 32px;
  border: 6px solid var(--navy);
  display: grid; place-items: center;
  box-shadow:
    inset 0 -10px 0 rgba(0,0,0,0.20),
    inset 0 10px 0 rgba(255,255,255,0.35),
    0 14px 0 var(--navy),
    0 0 80px rgba(255, 220, 140, 0.45);
  font-size: 130px;
  position: relative;
  animation: rewardBob 2.4s ease-in-out infinite;
}
@keyframes rewardBob {
  0%, 100% { transform: translateY(0)   rotate(-2deg); }
  50%      { transform: translateY(-6px) rotate(2deg); }
}
.lvl-overlay .reward-card .reward-icon.coin   { background: radial-gradient(circle at 35% 30%, #FFE48A, #F0C040 50%, #A86E0A); }
.lvl-overlay .reward-card .reward-icon.gem    { background: radial-gradient(circle at 35% 30%, #B3F5C5, #34C46F 50%, #115E2C); }
.lvl-overlay .reward-card .reward-icon.badge  { background: radial-gradient(circle at 35% 30%, #FFD27A, #E04848 60%, #6B1414); }
.lvl-overlay .reward-card .reward-icon.course { background: radial-gradient(circle at 35% 30%, #B0E5FF, #2C7AC9 50%, #0D2A55); }
.lvl-overlay .reward-card .reward-icon.pass   { background: radial-gradient(circle at 35% 30%, #D7C2F0, #8B5DC7 50%, #3B1E68); }
.lvl-overlay .reward-card .reward-amount {
  position: absolute; bottom: -12px; right: -16px;
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  border: 4px solid var(--navy);
  border-radius: 999px;
  padding: 6px 18px;
  font-family: var(--font-game); font-size: 28px; line-height: 1;
  color: var(--navy);
  text-shadow: 0 2px 0 rgba(255,255,255,0.4);
  box-shadow: 0 4px 0 var(--navy);
  transform: rotate(-6deg);
}
.lvl-overlay .reward-card .reward-title {
  font-family: var(--font-game);
  font-size: clamp(36px, 5vw, 60px);
  letter-spacing: 1.5px; line-height: 1;
  color: #fff;
  -webkit-text-stroke: 3px var(--navy);
  paint-order: stroke fill;
  text-shadow: 0 4px 0 rgba(0,0,0,0.5);
  text-align: center;
  margin: 0;
}
.lvl-overlay .reward-card .reward-sub {
  font-family: var(--font-ui); font-size: 16px; font-weight: 800;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: #FFE38A;
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
}
.lvl-overlay .reward-card .reward-step {
  font-family: var(--font-game); font-size: 14px; letter-spacing: 0.6px;
  color: rgba(255,255,255,0.7);
  text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  margin-top: 4px;
}

/* ====== Present (gift box) — phase 1 of the level-up flow ======
   Red-and-gold wrapped present that lives on a shake loop, then
   pops open on tap: lid launches off rotating 32deg, bow somersaults,
   box jiggles with squash-and-stretch, gold burst flashes from inside.
   Phase advances to .lvl-up-banner 850ms after the .opening class is
   applied (see _showLevelUpModal in js/child-dashboard.js).
   --------------------------------------------------------------- */
.lvl-overlay .present-stage {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 28px;
}
.lvl-overlay .present-stage .pretitle {
  font-family: var(--font-game); font-size: 22px; color: #fff;
  letter-spacing: 1.5px;
  text-shadow: 0 3px 0 rgba(0,0,0,0.5);
  animation: cgdNameRise 600ms cubic-bezier(.34,1.56,.64,1) both;
}
@keyframes cgdNameRise {
  0%   { transform: translateY(40px) scale(0.6); opacity: 0; }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}
.lvl-overlay .present-wrap {
  position: relative; z-index: 2;
  width: 280px; height: 280px;
  animation: cgdPresentShake 1.7s ease-in-out infinite;
  cursor: pointer;
}
.lvl-overlay .present-wrap.opening { animation: none; }
@keyframes cgdPresentShake {
  0%, 64%, 100% { transform: translateY(0) rotate(0); }
  68%   { transform: translateY(-6px) rotate(-5deg); }
  72%   { transform: translateY(-4px) rotate(5deg); }
  76%   { transform: translateY(-6px) rotate(-5deg); }
  80%   { transform: translateY(-4px) rotate(4deg); }
  84%   { transform: translateY(-2px) rotate(-2deg); }
  88%   { transform: translateY(0) rotate(0); }
}
.lvl-overlay .present-glow {
  position: absolute; inset: -60px;
  background: radial-gradient(circle, rgba(255,220,140,0.55) 0%, rgba(255,220,140,0) 60%);
  pointer-events: none;
  animation: cgdPresentGlow 2s ease-in-out infinite alternate;
}
@keyframes cgdPresentGlow {
  from { opacity: 0.55; transform: scale(1); }
  to   { opacity: 1;    transform: scale(1.1); }
}
.lvl-overlay .present-box {
  position: absolute; bottom: 20px; left: 50%;
  transform: translateX(-50%);
  width: 240px; height: 180px;
  background: linear-gradient(180deg, #FF6464 0%, #C0392B 100%);
  border: 4px solid var(--navy);
  border-radius: 12px;
  box-shadow: 0 8px 0 var(--navy),
              inset 0 -8px 0 rgba(0,0,0,0.25),
              inset 0 8px 0 rgba(255,255,255,0.18);
  overflow: hidden;
}
.lvl-overlay .present-box::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 50%;
  transform: translateX(-50%);
  width: 38px;
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 100%);
  border-left: 3px solid var(--navy);
  border-right: 3px solid var(--navy);
}
.lvl-overlay .present-box::after {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 28%;
  background: linear-gradient(180deg, rgba(255,255,255,0.22), transparent);
  pointer-events: none;
}
.lvl-overlay .present-lid {
  position: absolute; top: 50px; left: 50%;
  transform: translateX(-50%);
  width: 260px; height: 54px;
  background: linear-gradient(180deg, #FF7C7C 0%, #D9442F 100%);
  border: 4px solid var(--navy);
  border-radius: 10px;
  box-shadow: 0 5px 0 var(--navy),
              inset 0 -4px 0 rgba(0,0,0,0.25),
              inset 0 4px 0 rgba(255,255,255,0.22);
  z-index: 2;
}
.lvl-overlay .present-lid::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 50%;
  transform: translateX(-50%);
  width: 38px;
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 100%);
  border-left: 3px solid var(--navy);
  border-right: 3px solid var(--navy);
}
.lvl-overlay .present-bow {
  position: absolute; top: 50px; left: 50%;
  transform: translate(-50%, -88%);
  width: 130px; height: 90px;
  z-index: 3;
  filter: drop-shadow(0 4px 0 rgba(0,0,0,0.2));
}
.lvl-overlay .present-wrap.opening .present-lid {
  animation: cgdLidFly 900ms cubic-bezier(.34,1.56,.64,1) forwards;
}
@keyframes cgdLidFly {
  0%   { transform: translateX(-50%) translateY(0)    rotate(0deg);   opacity: 1; }
  18%  { transform: translateX(-50%) translateY(10px) rotate(0deg);   opacity: 1; }
  100% { transform: translateX(-50%) translateY(-460px) rotate(-32deg); opacity: 0.25; }
}
.lvl-overlay .present-wrap.opening .present-bow {
  animation: cgdBowFly 900ms cubic-bezier(.34,1.56,.64,1) forwards;
}
@keyframes cgdBowFly {
  0%   { transform: translate(-50%, -88%) rotate(0deg); opacity: 1; }
  18%  { transform: translate(-50%, -75%) rotate(0deg); opacity: 1; }
  100% { transform: translate(-22%, -540px) rotate(140deg); opacity: 0.2; }
}
.lvl-overlay .present-wrap.opening .present-box {
  animation: cgdBoxJiggle 900ms cubic-bezier(.34,1.56,.64,1) forwards;
  transform-origin: bottom center;
}
@keyframes cgdBoxJiggle {
  0%   { transform: translateX(-50%) scale(1, 1); }
  10%  { transform: translateX(-50%) scale(1.06, 0.85); }
  30%  { transform: translateX(-50%) scale(0.96, 1.10); }
  55%  { transform: translateX(-50%) scale(1.02, 0.96); }
  80%  { transform: translateX(-50%) scale(0.99, 1.02); }
  100% { transform: translateX(-50%) scale(1, 1); }
}
.lvl-overlay .present-burst {
  position: absolute; inset: -120px;
  display: grid; place-items: center;
  pointer-events: none;
  z-index: 1;
}
.lvl-overlay .present-burst::before {
  content: ""; width: 480px; height: 480px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255,228,138,0.95) 0%, rgba(255,228,138,0) 60%);
  animation: cgdBurstPulse 700ms ease-out forwards;
}
@keyframes cgdBurstPulse {
  0%   { opacity: 0; transform: scale(0.2); }
  40%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.7); }
}

/* Streak-milestone callout: green-tinted text that pops above the
   answered card. Uses the same vertical drift as quiz-coin-label. */
.quiz-gem-streak-label {
  position: fixed;
  z-index: 201;
  pointer-events: none;
  transform: translate(-50%, -50%);
  font-family: var(--font-game);
  font-size: 36px;
  letter-spacing: 1px;
  color: #2BA67A;
  text-shadow:
     2px 2px 0 var(--navy),
    -2px 2px 0 var(--navy),
     2px -2px 0 var(--navy),
    -2px -2px 0 var(--navy);
  text-align: center;
  line-height: 1;
  animation: quizStreakFloat 1500ms cubic-bezier(0.2, 0, 0, 1) forwards;
}
.quiz-gem-streak-label .streak-tag {
  font-size: 16px;
  letter-spacing: 2px;
  color: #FFFCF3;
  text-shadow:
     2px 2px 0 var(--navy),
    -2px 2px 0 var(--navy),
     2px -2px 0 var(--navy),
    -2px -2px 0 var(--navy);
}
@keyframes quizStreakFloat {
  0%   { transform: translate(-50%, -50%) scale(0.4) rotate(-10deg); opacity: 0; }
  18%  { transform: translate(-50%, -90%) scale(1.2)  rotate(2deg);  opacity: 1; }
  35%  { transform: translate(-50%, -110%) scale(1.0) rotate(-2deg); opacity: 1; }
  90%  { transform: translate(-50%, -150%) scale(1.0) rotate(0deg);  opacity: 1; }
  100% { transform: translate(-50%, -170%) scale(0.9) rotate(0deg);  opacity: 0; }
}

/* Green shockwave ring for the gem burst — same shape as the coin
   ring but emerald-tinted. */
.quiz-gem-ring {
  position: fixed;
  z-index: 199;
  pointer-events: none;
  width: 16px; height: 16px;
  margin-left: -8px; margin-top: -8px;
  border-radius: 50%;
  border: 4px solid rgba(52, 196, 111, 0.85);
  box-shadow: 0 0 24px rgba(52, 196, 111, 0.55);
  animation: quizGemRing 700ms ease-out forwards;
  opacity: 0;
}
@keyframes quizGemRing {
  0%   { transform: scale(0.3); opacity: 0;   }
  20%  { transform: scale(1);   opacity: 0.9; }
  100% { transform: scale(6);   opacity: 0;   }
}

/* Gem-burst sprite — same flight pattern as quiz-coin-bubble, just
   a different drop shadow tint so the gems read green. */
.quiz-coin-bubble.quiz-gem-bubble {
  filter: drop-shadow(0 2px 0 rgba(43, 166, 122, 0.55));
}

/* "+N" text label that pops above the card the moment a correct
   answer lands. Separate from the bubbling coin tokens so each does
   its own thing on its own timing. */
.quiz-coin-label {
  position: fixed;
  z-index: 201;
  pointer-events: none;
  font-family: var(--font-game);
  font-size: 32px;
  letter-spacing: 0.5px;
  color: #FFE38A;
  text-shadow:
    0 3px 0 var(--navy),
    0 0 16px rgba(255, 227, 138, 0.95);
  transform: translate(-50%, -50%);
  animation: quizCoinLabel 760ms cubic-bezier(0.18, 0.74, 0.4, 1.18) forwards;
}
@keyframes quizCoinLabel {
  0%   { transform: translate(-50%, -50%)        scale(0.3); opacity: 0; }
  18%  { transform: translate(-50%, -60%)        scale(1.5); opacity: 1; }
  60%  { transform: translate(-50%, -160%)       scale(1.0); opacity: 1; }
  100% { transform: translate(-50%, -260%)       scale(0.85); opacity: 0; }
}

/* Coin burst — N coins all start stacked at the card center, pop
   outward to a circle of radius BURST_RADIUS (set per-coin via
   --burst-x / --burst-y), hover for a beat, then fly to the counter
   (delta --end-x / --end-y). Pure game-style "one becomes five". */
.quiz-coin-bubble {
  position: fixed;
  z-index: 200;
  pointer-events: none;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 2px 0 rgba(11, 30, 63, 0.35));
  animation: quizCoinBurst 1500ms cubic-bezier(0.4, 0, 0.25, 1) forwards;
  opacity: 0;
}
@keyframes quizCoinBurst {
  /* Phase 1 — single coin appears at card center. */
  0%   {
    transform: translate(-50%, -50%) scale(0.2) rotate(-20deg);
    opacity: 0;
  }
  8%   {
    transform: translate(-50%, -50%) scale(1.35) rotate(0deg);
    opacity: 1;
  }
  /* Phase 2 — duplicate / burst out to the ring of N positions. */
  26%  {
    transform: translate(calc(-50% + var(--burst-x, 0px)),
                         calc(-50% + var(--burst-y, 0px)))
               scale(1.0) rotate(0deg);
    opacity: 1;
  }
  /* Phase 3 — hover at the ring with a tiny bob. */
  40%  {
    transform: translate(calc(-50% + var(--burst-x, 0px)),
                         calc(-50% + var(--burst-y, 0px) - 6px))
               scale(1.05) rotate(0deg);
    opacity: 1;
  }
  /* Phase 4 — converge on the counter together. */
  92%  {
    transform: translate(calc(-50% + var(--end-x, 0px)),
                         calc(-50% + var(--end-y, 0px)))
               scale(0.7) rotate(360deg);
    opacity: 1;
  }
  100% {
    transform: translate(calc(-50% + var(--end-x, 0px)),
                         calc(-50% + var(--end-y, 0px)))
               scale(0.35) rotate(360deg);
    opacity: 0;
  }
}

/* Hint-cost variant — same .quiz-coin-bubble sprite, but different
   keyframes: spawn at counter, arc across with a per-coin sway, land
   on the iframe's hint button. No burst-out phase (we already know
   where each coin is going). */
.quiz-coin-bubble.hint-coin {
  animation: quizCoinHintFly 880ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
@keyframes quizCoinHintFly {
  0%   {
    transform: translate(-50%, -50%) scale(0.5) rotate(0deg);
    opacity: 0;
  }
  18%  {
    transform: translate(-50%, -50%) scale(1.15) rotate(8deg);
    opacity: 1;
  }
  55%  {
    transform:
      translate(calc(-50% + var(--end-x, 0px) * 0.55 + var(--sway, 0px)),
                calc(-50% + var(--end-y, 0px) * 0.55 - 14px))
      scale(1.0) rotate(180deg);
    opacity: 1;
  }
  90%  {
    transform:
      translate(calc(-50% + var(--end-x, 0px)),
                calc(-50% + var(--end-y, 0px)))
      scale(0.85) rotate(340deg);
    opacity: 1;
  }
  100% {
    transform:
      translate(calc(-50% + var(--end-x, 0px)),
                calc(-50% + var(--end-y, 0px)))
      scale(0.35) rotate(360deg);
    opacity: 0;
  }
}

/* Shockwave ring drawn at the burst origin — pops + expands as the
   coins split apart, then fades. Purely decorative. */
.quiz-coin-ring {
  position: fixed;
  z-index: 199;
  pointer-events: none;
  width: 24px; height: 24px;
  margin-left: -12px; margin-top: -12px;
  border: 3px solid rgba(255, 227, 138, 0.9);
  border-radius: 50%;
  box-shadow: 0 0 20px rgba(255, 227, 138, 0.7);
  animation: quizCoinRing 520ms cubic-bezier(0.25, 0.46, 0.45, 1) forwards;
  opacity: 0;
}
@keyframes quizCoinRing {
  0%   { transform: scale(0.2); opacity: 0; }
  20%  { transform: scale(1);   opacity: 1; }
  100% { transform: scale(8);   opacity: 0; }
}
.quiz-back-btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  border-radius: 14px;
  padding: 10px 16px;
  font-family: var(--font-game); font-size: 14px;
  color: var(--navy); letter-spacing: 0.6px;
  box-shadow: 0 4px 0 0 var(--navy);
}
.quiz-back-btn:active { transform: translateY(2px); box-shadow: 0 2px 0 0 var(--navy); }
/* Scoped under .quiz-overlay so the kid quiz bar styling doesn't leak
   into the main #view-quiz progress block, which renders a meta row
   above a thin yellow→orange track per the Quiz Review design. */
.quiz-overlay .quiz-progress {
  height: 16px; border-radius: 999px;
  background: rgba(0,0,0,0.30);
  border: 2.5px solid var(--q-card-border);
  overflow: hidden;
  margin: 0 8px;
}
.quiz-overlay .quiz-progress-fill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--q-yellow), var(--q-accent) 60%, var(--q-yellow-deep));
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.2), inset 0 2px 0 rgba(255,255,255,0.25);
  transition: width 280ms var(--ease-spring, ease-out);
}
.quiz-counter .lbl {
  font-family: var(--font-ui); font-size: 10px; font-weight: 800;
  color: var(--q-yellow); letter-spacing: 0.06em; white-space: nowrap;
}
.quiz-counter {
  display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
  font-family: var(--font-game); color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,0.45);
  min-width: 100px;
  line-height: 1;
}
.quiz-counter .num { font-size: 22px; line-height: 1; white-space: nowrap; }
.quiz-counter .lbl { font-family: var(--font-ui); font-size: 10px; font-weight: 800;
  color: #FFE38A; letter-spacing: 0.06em; white-space: nowrap; }
.quiz-home {
  width: 56px; height: 56px; border-radius: 14px;
  background: linear-gradient(180deg, #FFB8C7, #E04848);
  border: 3px solid var(--navy);
  display: grid; place-items: center; color: #fff;
  box-shadow: 0 4px 0 0 var(--navy);
}
.quiz-home:active { transform: translateY(2px); box-shadow: 0 2px 0 0 var(--navy); }

.quiz-body {
  display: flex; flex-direction: column; gap: 14px;
  align-items: stretch;
  max-width: 880px; margin: 0 auto;
  width: 100%;
  padding-top: 8px;
  overflow: auto;
}

/* Replay popup — fires when the kid taps "▶ Replay m:ss" after
   answering. Fixed-position backdrop dims the quiz; a centered
   modal holds the source video + a chunky ✕ close button. Click
   either the ✕ or the backdrop to dismiss. */
.quiz-video-popup {
  position: fixed; inset: 0;
  background: rgba(7, 32, 65, 0.72);
  display: grid; place-items: center;
  z-index: 9000;
  padding: 24px;
  animation: quizVideoFade 180ms ease-out both;
}
@keyframes quizVideoFade { from { opacity: 0; } to { opacity: 1; } }
.quiz-video-modal {
  position: relative;
  width: min(960px, 100%);
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 4px solid var(--navy);
  border-radius: 22px;
  box-shadow: 0 10px 0 0 var(--navy), 0 24px 50px rgba(0, 0, 0, 0.4);
  padding: 16px;
  animation: quizVideoPop 260ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
  cursor: default;
}
@keyframes quizVideoPop {
  from { transform: scale(0.85); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}
.quiz-video-x {
  position: absolute;
  top: -16px; right: -16px;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: linear-gradient(180deg, #FFB8C7, #E04848);
  color: #fff;
  border: 3px solid var(--navy);
  box-shadow: 0 4px 0 0 var(--navy);
  font-family: var(--font-game); font-size: 22px;
  line-height: 1; cursor: pointer;
  display: grid; place-items: center;
  z-index: 2;
  transition: transform 80ms ease, box-shadow 80ms ease;
}
.quiz-video-x:hover  { transform: translateY(-2px); box-shadow: 0 6px 0 0 var(--navy); }
.quiz-video-x:active { transform: translateY(2px);  box-shadow: 0 2px 0 0 var(--navy); }
.quiz-video-host {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000;
  border: 3px solid var(--navy);
  border-radius: 14px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
  overflow: hidden;
}
/* Audio replay: the lesson is just a clip, so the 16/9 black box
   would feel empty. Collapse to a comfortable strip with the kid's
   chunky border treatment + room for native controls. */
.quiz-source-host--audio {
  aspect-ratio: auto;
  background: linear-gradient(160deg, #B0E5FF 0%, #3FA6E5 50%, #1E5B92 100%);
  padding: 20px 18px;
  display: grid; place-items: center;
}
.quiz-source-host--audio .quiz-source-media {
  width: 100%; max-width: 540px;
}
/* Uploaded MP4 lives in the same 16/9 black box as YouTube — keep
   the iframe rules above untouched, just style the inline <video>. */
.quiz-source-host--video .quiz-source-media {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block; background: #000;
}
/* Document viewers — PDF, DOCX, plain text. Drop the 16/9 ratio
   for a comfortable reading column and a paper-coloured backdrop. */
.quiz-source-host.is-textual {
  aspect-ratio: auto;
  height: clamp(360px, 70vh, 720px);
  background: #FFFCF3;
}
.quiz-source-host--pdf .quiz-source-pdf-canvas {
  position: absolute; inset: 0;
  overflow-y: auto; overflow-x: hidden;
  padding: 14px;
  display: flex; flex-direction: column; align-items: stretch; gap: 14px;
  background: #1d2a3d;
  -webkit-overflow-scrolling: touch;
}
/* Same overflow guard as .lesson-hero--pdf — see that block above
   for the full reasoning. pdf.js writes intrinsic-pixel width/height
   inline; we force the page + canvas down to the container width and
   let the aspect ratio drive height. */
.quiz-source-host--pdf .pdf-pages {
  width: 100%;
  max-width: 100%;
  align-self: stretch;
  align-items: stretch;
}
.quiz-source-host--pdf .pdf-page {
  background: #fff;
  border-radius: 6px;
  box-shadow: 0 3px 10px rgba(0,0,0,0.35);
  /* See .lesson-hero--pdf .pdf-page for the --pdf-zoom rationale. */
  width: calc(100% * var(--pdf-zoom, 1)) !important;
  max-width: none !important;
  height: auto !important;
}
.quiz-source-host--pdf .pdf-page canvas {
  width: 100%;
  height: auto;
  display: block;
}
.quiz-source-host--pdf .pdf-page .pdf-text-layer {
  display: none;
}
.quiz-source-host--pdf .quiz-source-pdf-canvas {
  overflow-x: auto;
}

/* ─── PDF zoom controls (kid hero + quiz-replay modal) ─────────
   Floating ± buttons over the top-right of the PDF viewer with a
   live percentage in between. They sit above the canvas (z-index
   above scrollbar shadow) and use the kid's chunky-button visual
   language so they don't read as system chrome. */
.pdf-zoom-controls {
  position: absolute;
  top: 12px; right: 12px;
  z-index: 5;
  display: flex; align-items: center; gap: 4px;
  padding: 4px 6px;
  background: rgba(7, 32, 65, 0.88);
  border: 2px solid var(--navy);
  border-radius: 999px;
  box-shadow: 0 3px 0 0 var(--navy);
}
.pdf-zoom-btn {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  border: 2px solid var(--navy);
  color: var(--navy);
  font-family: var(--font-game); font-weight: 800;
  font-size: 22px; line-height: 1;
  display: grid; place-items: center;
  cursor: pointer; padding: 0;
  box-shadow: 0 2px 0 0 var(--navy);
  transition: transform 70ms ease, box-shadow 70ms ease;
}
.pdf-zoom-btn:hover  { transform: translateY(-1px); box-shadow: 0 3px 0 0 var(--navy); }
.pdf-zoom-btn:active { transform: translateY(1px);  box-shadow: 0 1px 0 0 var(--navy); }
.pdf-zoom-level {
  font-family: var(--font-game);
  font-size: 12px; font-weight: 700;
  color: #FFE38A;
  min-width: 38px; text-align: center;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}
.quiz-source-host--pdf .quiz-source-pdf-iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%; border: 0;
  background: #fff;
}
.quiz-source-host--docx .quiz-source-docx,
.quiz-source-host--text .quiz-source-text {
  position: absolute; inset: 0;
  overflow-y: auto;
  padding: 22px 26px;
  font-family: var(--font-ui);
  font-size: 15px; line-height: 1.6;
  color: #0B1E3F;
  white-space: pre-wrap;
  -webkit-overflow-scrolling: touch;
}
.quiz-source-host--docx .quiz-source-docx h1,
.quiz-source-host--docx .quiz-source-docx h2,
.quiz-source-host--docx .quiz-source-docx h3 {
  font-family: var(--font-game); color: #0B1E3F; margin: 14px 0 6px;
}
.quiz-source-host--docx .quiz-source-docx p { margin: 0 0 10px; }
/* Excerpt highlight inside textual viewers — the moment the question
   came from glows in the kid's quiz yellow. scrollIntoView centres
   the first match on mount. */
.quiz-source-mark {
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  color: #0B1E3F;
  padding: 2px 4px; border-radius: 6px;
  box-shadow: 0 0 0 2px rgba(240, 192, 64, 0.55);
}
.quiz-source-missing {
  position: absolute; inset: 0;
  display: grid; place-items: center; text-align: center;
  padding: 24px;
  font-family: var(--font-game); font-size: 16px;
  color: var(--navy);
  background: #FFFCF3;
}
.quiz-source-dl {
  display: inline-block;
  padding: 10px 18px;
  background: linear-gradient(180deg, #FFE38A, #F0C040);
  border: 3px solid var(--navy); border-radius: 12px;
  font-family: var(--font-game); font-size: 14px;
  color: var(--navy); letter-spacing: 0.6px;
  box-shadow: 0 4px 0 0 var(--navy);
  text-decoration: none;
}

/* Scoped: bare .quiz-card was leaking display:grid into #view-quiz's
   question card (which expects block flow + absolute-positioned head). */
.quiz-overlay .quiz-card {
  background: var(--q-card-bg);
  border: 3px solid var(--q-card-border);
  border-radius: 22px;
  padding: 18px 28px 24px;
  box-shadow: 0 6px 0 0 var(--q-card-border), 0 0 32px var(--q-accent-glow);
  position: relative;
  max-width: 880px;
  width: 100%;
  margin: 0 auto;
  /* Acellus question cards have a subject icon on the left + the
     question text taking the remaining width. align-items:start so
     long multi-line questions flow downward instead of pushing the
     icon down with vertical-center math. */
  display: grid; grid-template-columns: auto 1fr; gap: 18px;
  align-items: start;
}
.quiz-card .quiz-stripe {
  position: absolute; top: 0; left: 0; right: 0; height: 8px;
  background: linear-gradient(90deg, var(--q-stripe-1) 0%, var(--q-stripe-2) 50%, var(--q-stripe-3) 100%);
  border-radius: 18px 18px 0 0;
}
.quiz-card .quiz-subject-ico {
  width: 72px; height: 72px; flex-shrink: 0;
  border-radius: 16px;
  border: 2.5px solid var(--q-card-border);
  background: rgba(0,0,0,0.18);
  display: grid; place-items: center;
  font-size: 38px; line-height: 1;
  box-shadow: inset 0 0 18px var(--q-accent-glow);
}
.quiz-card .quiz-q-col {
  display: flex; flex-direction: column; gap: 4px;
  min-width: 0;
}
.quiz-card .quiz-kicker {
  font-family: var(--font-ui); font-size: 11px; font-weight: 800;
  color: var(--q-kicker); letter-spacing: 0.14em; text-transform: uppercase;
  text-align: left;
  display: flex; align-items: center; gap: 8px;
}
.quiz-card .quiz-kicker::before {
  content: ""; display: inline-block;
  width: 18px; height: 4px; border-radius: 2px;
  background: var(--q-accent);
  box-shadow: 0 0 8px var(--q-accent-glow);
}
.quiz-card .quiz-type {
  font-family: var(--font-ui); font-size: 11px; font-weight: 800;
  color: var(--q-kicker); letter-spacing: 0.12em; text-transform: uppercase;
  text-align: left;
}
.quiz-card .quiz-q {
  margin: 4px 0 0; font-family: var(--font-game);
  font-size: clamp(22px, 2.4vw, 32px);
  color: var(--q-card-text); line-height: 1.2;
  text-align: left;
  text-wrap: balance;
  letter-spacing: -0.01em;
  /* Wrap long lines so the kid always sees the whole prompt —
     `text-wrap: balance` alone doesn't break unhyphenated runs. */
  overflow-wrap: anywhere;
  word-break: break-word;
  white-space: normal;
}

.quiz-toggle {
  display: flex; gap: 8px; justify-content: center;
}
.quiz-tog {
  background: rgba(0,0,0,0.22);
  border: 2px solid var(--q-pill-border);
  border-radius: 999px;
  padding: 8px 18px;
  font-family: var(--font-game); font-size: 13px;
  color: var(--q-text-dim); letter-spacing: 0.6px;
  white-space: nowrap;
  line-height: 1;
}
.quiz-tog.active {
  background: var(--q-pill-bg);
  color: var(--q-pill-text);
  border-color: var(--q-pill-border);
  box-shadow: var(--q-pill-shadow);
}
/* Locked variant — shown for Family Free kids in place of the FREE
   RESPONSE pill. Visually distinct (dimmer, dashed border) so the kid
   reads it as "you can't use this yet" rather than another active
   choice. Click opens the parent-facing upgrade prompt. */
.quiz-tog-locked {
  background: rgba(255, 255, 255, 0.08);
  color: var(--q-text-dim);
  border-style: dashed;
  opacity: 0.85;
  font-size: 11px;
  letter-spacing: 0.4px;
  cursor: pointer;
}
.quiz-tog-locked:hover {
  background: rgba(255, 255, 255, 0.14);
  opacity: 1;
}

/* Acellus-style answer pills — wide rounded rectangles, single line of
   text, no A/B/C/D letter circle. The `.letter` element from the
   old design is hidden so existing markup still works without breaking. */
.quiz-choices {
  display: flex; flex-direction: column; gap: 12px;
}
.quiz-choice {
  display: flex; align-items: center; justify-content: center;
  background: var(--q-pill-bg);
  border: 2.5px solid var(--q-pill-border);
  border-radius: 16px;
  padding: 14px 18px;
  box-shadow: var(--q-pill-shadow);
  text-align: center;
  min-height: 56px;
  transition: transform 80ms ease, box-shadow 80ms ease, background 100ms ease;
  cursor: pointer;
}
.quiz-choice .letter { display: none; }
.quiz-choice:hover  { transform: translateY(-1px); }
.quiz-choice:active { transform: translateY(2px); box-shadow: 0 0 0 1px var(--q-pill-border); }
.quiz-choice .choice-text {
  font-family: var(--font-ui); font-size: 16px; font-weight: 700;
  color: var(--q-pill-text); line-height: 1.35;
}
.quiz-choice.correct {
  background: linear-gradient(180deg, rgba(78,214,184,0.85), rgba(46,139,94,0.85));
  border-color: rgba(78,214,184,0.95);
  box-shadow: 0 0 22px rgba(78,214,184,0.45);
}
.quiz-choice.correct .choice-text { color: #fff; }
.quiz-choice.wrong {
  background: linear-gradient(180deg, rgba(255,165,165,0.9), rgba(192,57,43,0.9));
  border-color: rgba(255,165,165,0.95);
  box-shadow: 0 0 22px rgba(192,57,43,0.45);
}
.quiz-choice.wrong .choice-text { color: #fff; }
.quiz-choice.picked-other { opacity: 0.55; }

.quiz-dunno {
  align-self: center;
  background: transparent;
  border: 2.5px dashed var(--q-text-dim);
  border-radius: 14px;
  padding: 10px 26px;
  font-family: var(--font-game); font-size: 13px;
  color: var(--q-text); letter-spacing: 0.6px;
  white-space: nowrap; line-height: 1;
}
.quiz-dunno:hover { border-color: #fff; color: #fff; }

.quiz-nav {
  display: flex; align-items: center; justify-content: center; gap: 18px;
  margin-top: 6px; padding-bottom: 4px;
}
.quiz-nav .arrow {
  width: 56px; height: 56px; border-radius: 14px;
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  display: grid; place-items: center; color: var(--navy);
  box-shadow: 0 4px 0 0 var(--navy);
}
.quiz-nav .arrow:active { transform: translateY(2px); box-shadow: 0 2px 0 0 var(--navy); }
.quiz-nav .arrow:disabled { opacity: 0.45; box-shadow: 0 2px 0 0 var(--navy); transform: translateY(2px); }
.quiz-nav .label {
  font-family: var(--font-game); font-size: 15px; color: #fff;
  letter-spacing: 0.6px; text-shadow: 0 2px 0 rgba(0,0,0,0.4);
  white-space: nowrap; line-height: 1;
}

/* ----- Quiz victory screen (Acellus "Assignment Complete" style) ----- */
.quiz-victory {
  display: grid; place-items: center;
  min-height: 480px;
  text-align: center;
  gap: 16px;
}
.quiz-victory h3 {
  font-family: var(--font-game); font-size: clamp(28px, 4vw, 44px); color: var(--q-text);
  letter-spacing: 4px; line-height: 1;
  text-shadow: 0 0 18px var(--q-accent-glow);
  margin: 0;
  text-transform: uppercase;
}
.quiz-victory .vict-sub {
  font-family: var(--font-ui); font-size: 14px; font-weight: 700;
  color: var(--q-accent);
  letter-spacing: 0.08em; text-transform: uppercase;
}
/* Hexagonal score badge — clip-path polygon gives the 6-point shape
   without needing SVG. Two-layer (outer glow ring + inner score)
   for the Acellus depth. */
.quiz-victory .vict-hex {
  position: relative;
  width: 240px; height: 268px;
  display: grid; place-items: center;
}
.quiz-victory .vict-hex::before {
  content: "";
  position: absolute; inset: 0;
  background: var(--q-accent);
  clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
  opacity: 0.45;
  filter: blur(2px);
}
.quiz-victory .vict-hex-inner {
  position: relative;
  width: 224px; height: 252px;
  background: linear-gradient(180deg, rgba(20,60,80,0.94) 0%, rgba(8,28,42,0.94) 100%);
  clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
  /* Three rows: label, avatars, percent — stacked vertically. The
     hex's polygon pinches the top + bottom, so keep content inside
     the widest band (between the 25% and 75% horizontal cuts) with
     extra vertical padding. */
  display: grid;
  grid-template-rows: auto auto auto;
  align-content: center;
  justify-items: center;
  gap: 4px;
  padding: 40px 14px;
  text-align: center;
}
.quiz-victory .vict-hex-label {
  font-family: var(--font-ui); font-size: 11px; font-weight: 800;
  color: var(--q-text-dim);
  letter-spacing: 0.18em; text-transform: uppercase;
  margin-bottom: 4px;
}
.quiz-victory .vict-hex-pct {
  font-family: var(--font-game); font-size: 64px;
  color: var(--q-accent);
  text-shadow: 0 0 14px var(--q-accent-glow);
  line-height: 1;
}
/* Trophy emoji centered between the "Your score" label and the
   percentage. Sized to fill the hex's narrow middle band. */
.vict-trophy {
  font-size: 76px;
  line-height: 1;
  filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.45))
          drop-shadow(0 0 18px rgba(255, 227, 138, 0.45));
  animation: vict-trophy-bob 2.4s ease-in-out infinite;
}
@keyframes vict-trophy-bob {
  0%, 100% { transform: translateY(0) rotate(-2deg); }
  50%      { transform: translateY(-4px) rotate(2deg); }
}

.vict-rewards { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
.vict-reward {
  background: linear-gradient(180deg, rgba(15,42,58,0.85), rgba(8,28,42,0.85));
  border: 2px solid var(--q-pill-border);
  border-radius: 14px;
  padding: 10px 16px;
  display: flex; align-items: center; gap: 10px;
  box-shadow: var(--q-pill-shadow);
  font-family: var(--font-game); font-size: 20px;
  color: var(--q-text);
}
.quiz-overlay[data-quiz-theme="sky"] .vict-reward {
  background: linear-gradient(180deg, #FFFCF3 0%, #F2E4B6 100%);
  border: 3px solid var(--navy);
  box-shadow: 0 4px 0 0 var(--navy);
  color: var(--navy);
}

/* Theme-toggle button in the quiz top bar — small pill so it doesn't
   visually fight the BACK / HOME chunky buttons. */
.quiz-theme-toggle {
  background: rgba(0,0,0,0.25);
  border: 2px solid var(--q-pill-border);
  border-radius: 999px;
  padding: 6px 12px;
  font-family: var(--font-game);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--q-text);
  text-transform: uppercase;
  display: inline-flex; align-items: center; gap: 6px;
  white-space: nowrap;
  cursor: pointer;
  line-height: 1;
}
.quiz-theme-toggle:hover { background: rgba(0,0,0,0.4); }
.quiz-theme-toggle .swatch {
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--q-accent);
  box-shadow: 0 0 8px var(--q-accent-glow);
}

/* ----- Free response answer area ----- */
.quiz-free-input {
  width: 100%;
  background: linear-gradient(180deg, #FFFCF3 0%, #FBF3DC 100%);
  border: 3px solid var(--navy);
  border-radius: 16px;
  padding: 14px 16px;
  box-shadow: 0 4px 0 0 var(--navy);
  font-family: var(--font-ui);
  font-size: 16px;
  font-weight: 600;
  color: var(--navy);
  resize: vertical;
  min-height: 110px;
  outline: none;
  box-sizing: border-box;
}
.quiz-free-input::placeholder { color: rgba(16, 96, 144, 0.45); font-weight: 500; }
.quiz-free-input:focus { box-shadow: 0 4px 0 0 var(--navy), 0 0 0 3px rgba(255, 226, 138, 0.55); }
.quiz-free-input:disabled { opacity: 0.85; cursor: default; }

/* Post-answer feedback panel — mirrors the adult /view-quiz card:
   green/red title, correct answer revealed, stage badge + next-review
   line. Cream-on-navy theme to fit the rest of the kid quiz. */
.quiz-feedback {
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px 16px;
  border-radius: 16px;
  border: 3px solid var(--navy);
  box-shadow: 0 4px 0 0 var(--navy);
  background: linear-gradient(180deg, #FFFCF3 0%, #FBF3DC 100%);
  color: var(--navy);
}
.quiz-feedback.is-correct { background: linear-gradient(180deg, #DDF7E5 0%, #B7EAC8 100%); }
.quiz-feedback.is-wrong   { background: linear-gradient(180deg, #FFE3E3 0%, #FFC7C7 100%); }
.quiz-feedback .qfb-msg {
  font-family: var(--font-game);
  font-size: 18px;
  letter-spacing: 0.6px;
  color: var(--navy);
  text-shadow: 0 2px 0 rgba(255,255,255,0.4);
}
.quiz-feedback .qfb-answer {
  font-family: var(--font-ui);
  font-size: 14px;
  font-weight: 600;
  color: var(--navy);
  line-height: 1.35;
}
.quiz-feedback .qfb-answer strong { font-weight: 800; }
.quiz-feedback .qfb-srs {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 2px;
}

.quiz-feedback .qfb-stage {
  display: inline-flex; align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  border: 2px solid var(--navy);
  background: linear-gradient(180deg, #B0E5FF, #2C7AC9);
  color: #fff;
  font-family: var(--font-game);
  font-size: 12px;
  letter-spacing: 0.6px;
  line-height: 1;
  white-space: nowrap;
}
.quiz-feedback .qfb-stage-new        { background: linear-gradient(180deg, #B0E5FF, #2C7AC9); }
.quiz-feedback .qfb-stage-hatchling  { background: linear-gradient(180deg, #FFE38A, #F0C040); color: var(--navy); }
.quiz-feedback .qfb-stage-fledgling  { background: linear-gradient(180deg, #FFCFA0, #F09020); color: var(--navy); }
.quiz-feedback .qfb-stage-hunter     { background: linear-gradient(180deg, #C9F2D6, #4ED6B8); color: var(--navy); }
.quiz-feedback .qfb-stage-sage-owl   { background: linear-gradient(180deg, #E0D0FF, #8B5DC7); }
.quiz-feedback .qfb-stage-elder-owl  { background: linear-gradient(180deg, #FFD2D2, #C0392B); }
.quiz-feedback .qfb-next {
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 700;
  color: rgba(11,30,63,0.75);
}

.quiz-fr-check {
  align-self: stretch;
  width: 100%;
  background: linear-gradient(180deg, var(--q-yellow) 0%, var(--q-accent) 60%, var(--q-yellow-deep) 100%);
  border: 3px solid var(--q-card-border);
  border-radius: 14px;
  padding: 14px 18px;
  font-family: var(--font-game); font-size: 18px;
  color: var(--navy); letter-spacing: 0.8px;
  box-shadow: 0 5px 0 0 var(--q-card-border), 0 0 22px var(--q-accent-glow);
  white-space: nowrap; line-height: 1;
}
.quiz-overlay[data-quiz-theme="sky"] .quiz-fr-check {
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 60%, #C18C12 100%);
  border-color: var(--navy);
  box-shadow: 0 5px 0 0 var(--navy);
  text-shadow: 0 2px 0 rgba(255,255,255,0.4);
}

/* Big NEXT button that replaces the small < REVIEWED > arrow row
   after the kid answers. Matches the .lesson-btn.start golden
   gradient so it's visually consistent with CHECK MY ANSWER. */
.quiz-next-big {
  align-self: stretch;
  width: 100%;
  background: linear-gradient(180deg, var(--q-accent) 0%, var(--q-yellow-deep) 100%);
  border: 3px solid var(--q-card-border);
  border-radius: 14px;
  padding: 16px 18px;
  font-family: var(--font-game); font-size: 20px;
  color: var(--navy); letter-spacing: 1px;
  box-shadow: 0 5px 0 0 var(--q-card-border), 0 0 22px var(--q-accent-glow);
  white-space: nowrap; line-height: 1;
}
/* Action row that holds the post-answer buttons (Replay + NEXT).
   Sticky-bottom inside the scrolling .quiz-body so the kid can
   reach either button without scrolling past the feedback box. */
.quiz-action-row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: stretch;
  position: sticky;
  bottom: 0;
  z-index: 2;
}
.quiz-action-row:has(.quiz-next-big:only-child) { grid-template-columns: 1fr; }
.quiz-action-row .quiz-next-big { grid-column: -2 / -1; }
/* Replay button — secondary affordance, cream-gradient instead of
   the gold NEXT, narrower (fits its label width). Same chunky
   border + drop shadow style so they read as a pair. */
.quiz-replay-big {
  background: linear-gradient(180deg, #FFFCF3, #F2E4B6);
  color: var(--navy);
  border: 3px solid var(--q-card-border);
  border-radius: 14px;
  padding: 14px 22px;
  font-family: var(--font-game); font-size: 16px;
  letter-spacing: 0.5px;
  box-shadow: 0 5px 0 0 var(--q-card-border);
  white-space: nowrap; line-height: 1;
  cursor: pointer;
  transition: transform 100ms ease, box-shadow 100ms ease;
}
.quiz-overlay[data-quiz-theme="sky"] .quiz-replay-big {
  border-color: var(--navy);
  box-shadow: 0 5px 0 0 var(--navy);
}
.quiz-replay-big:hover  { transform: translateY(-1px); box-shadow: 0 6px 0 0 var(--q-card-border); }
.quiz-replay-big:active { transform: translateY(2px);  box-shadow: 0 2px 0 0 var(--q-card-border); }
.quiz-overlay[data-quiz-theme="sky"] .quiz-next-big {
  background: linear-gradient(180deg, #FFE38A 0%, #F0C040 60%, #C18C12 100%);
  border-color: var(--navy);
  box-shadow: 0 5px 0 0 var(--navy);
  text-shadow: 0 2px 0 rgba(255,255,255,0.4);
}
.quiz-next-big:hover  { transform: translateY(-1px); }
.quiz-next-big:active { transform: translateY(3px); }
.quiz-fr-check:hover { transform: translateY(-1px); box-shadow: 0 5px 0 0 var(--navy); }
.quiz-fr-check:active { transform: translateY(2px); box-shadow: 0 2px 0 0 var(--navy); }
.quiz-fr-check:disabled { opacity: 0.5; box-shadow: 0 2px 0 0 var(--navy); transform: translateY(2px); cursor: not-allowed; }

/* =====================================================================
 *  gamesOff (academic-only mode) — compact bottom-row rules
 *  ---------------------------------------------------------------------
 *  When the parent flips Settings → Learning preferences → Game features
 *  off, the kid dashboard hides the Owl Pass, coin / gem / xp / streak
 *  chips, Games dock, pets, character picker, etc. The home grid's
 *  bottom row is still rendered, but the leftmost column (Owl Pass) is
 *  now an empty string — it leaves a 280-px gap and squeezes Today's
 *  Goals into a too-narrow middle column, which then wraps onto many
 *  lines and pushes the REVIEW button off the visible viewport.
 *
 *  When .screen.cgd-games-off is on, regardless of width:
 *   - Drop the Owl-Pass column from .bottom (2 columns: 1fr + 360 px).
 *   - Hide the Today's-Goals badge icon + verbose sub-line and trim
 *     padding. Same compact treatment as the ≤1100-px breakpoint.
 *   - Trim play-block padding and shrink the REVIEW button so the row
 *     fits the screen with breathing room.
 *  ================================================================== */
.screen.cgd-games-off .bottom {
  grid-template-columns: 1fr 360px;
  align-items: start;
}
.screen.cgd-games-off .event.event-goals {
  grid-template-columns: 1fr auto;
  padding: 10px 12px;
  gap: 10px;
}
.screen.cgd-games-off .event.event-goals .badge-icon { display: none; }
.screen.cgd-games-off .event.event-goals .event-sub  { display: none; }
.screen.cgd-games-off .event.event-goals .event-name { font-size: 18px; }
.screen.cgd-games-off .goal-event-boxes { max-width: 100%; }
.screen.cgd-games-off .event { padding: 8px 12px; }
.screen.cgd-games-off .play-wrap { gap: 5px; }
.screen.cgd-games-off .token-bar { padding: 3px 10px 3px 3px; }
.screen.cgd-games-off .token-bar .ico { width: 36px; height: 36px; font-size: 18px; }
.screen.cgd-games-off .token-bar .meter-num { font-size: 14px; }
.screen.cgd-games-off .token-bar .meter-hint { font-size: 9px; margin-top: 2px; line-height: 1.25; }
.screen.cgd-games-off .play-btn {
  flex: 0 0 auto;
  font-size: 22px;
  padding: 10px 14px;
  border-radius: 14px;
  box-shadow: 0 4px 0 0 var(--navy), 0 7px 18px -4px rgba(0,0,0,0.4);
  animation: none;
}
/* Narrow viewports already stack to 1fr; reinforce that under gamesOff
 * so the side-by-side layout doesn't sneak back in via specificity. */
@media (max-width: 720px) {
  .screen.cgd-games-off .bottom { grid-template-columns: 1fr; }
}

/* =====================================================================
 *  Responsive breakpoints for the kid home screen
 *  ---------------------------------------------------------------------
 *  The home layout was tuned for ~1280-px tablets. On narrower viewports
 *  the side docks, center character, owl pass, and bottom action block
 *  used to overflow / clip; the rules below scale each region down so
 *  every key affordance (level, reviews, goals, dock buttons) stays
 *  visible right down to phone widths. Only sizes change — colors and
 *  affordances stay identical to the wide layout.
 * ===================================================================== */

@media (max-width: 1100px) {
  .screen {
    grid-template-rows: 64px 1fr auto;
    grid-template-columns: 102px 1fr 102px;
    padding: 12px;
  }
  .dock { padding-top: 18px; gap: 10px; }
  .dock-btn { width: 84px; height: 84px; }
  .dock-btn .glyph { font-size: 30px; }
  .dock-btn .label { font-size: 11px; margin-bottom: 6px; }
  .character { width: 520px; }
  .character img { width: 520px; }
  .character-floor { width: 460px; height: 96px; }
  .character-platform { width: 360px; height: 36px; }
  .bottom { grid-template-columns: 240px 1fr 320px; gap: 10px; align-items: start; }
  .profile-tab { min-width: 190px; padding: 3px 10px 3px 3px; }
  .profile-tab .avatar { width: 44px; height: 44px; }
  .profile-tab .avatar img { width: 38px; height: 38px; }
  .profile-tab .name { font-size: 16px; }
  .chip { font-size: 16px; min-width: 78px; padding: 3px 12px 3px 3px; }
  .chip .ico { width: 30px; height: 30px; }

  /* Today's Goals — drop the purple/yellow star badge and the
   * verbose "1/1 done · tap a course to start ›" sub-line. Just
   * the header "TODAY'S GOALS" + the course chips remain. */
  .event.event-goals { grid-template-columns: 1fr auto; padding: 10px 12px; gap: 10px; }
  .event.event-goals .badge-icon { display: none; }
  .event.event-goals .event-sub { display: none; }
  .event.event-goals .event-name { font-size: 18px; }
  .goal-event-boxes { max-width: 100%; }

  /* Owl pass + event cards — tighter padding so they don't tower
   * over the available bottom space. */
  .event, .pass { padding: 8px 12px; }
  .pass .pass-bar { height: 10px; }

  /* Review block — schedule above, REVIEW button below. Both
   * pinned to their natural minimum so the play-btn doesn't
   * balloon to fill the row. */
  .play-wrap { gap: 5px; }
  .token-bar { padding: 3px 10px 3px 3px; }
  .token-bar .ico { width: 36px; height: 36px; font-size: 18px; }
  .token-bar .meter-num { font-size: 14px; }
  .token-bar .meter-num .reward { font-size: 11px; }
  .token-bar .meter-hint { font-size: 9px; margin-top: 2px; line-height: 1.25; }
  .play-btn {
    flex: 0 0 auto;
    font-size: 22px;
    padding: 10px 14px;
    border-radius: 14px;
    box-shadow: 0 4px 0 0 var(--navy), 0 7px 18px -4px rgba(0,0,0,0.4);
    animation: none; /* the giant pulse loses its purpose at small size */
  }
}

@media (max-width: 900px) {
  .screen {
    grid-template-rows: 56px 1fr auto;
    grid-template-columns: 86px 1fr 86px;
    padding: 10px;
  }
  .dock { padding-top: 12px; gap: 8px; }
  .dock-btn { width: 72px; height: 72px; border-radius: 14px; }
  .dock-btn .glyph { font-size: 26px; }
  .dock-btn .label { font-size: 10px; margin-bottom: 5px; }
  .character { width: 380px; }
  .character img { width: 380px; }
  .character-floor { width: 360px; height: 80px; }
  .character-platform { width: 280px; height: 30px; }
  .rank-plate .pill { font-size: 14px; padding: 4px 12px 4px 4px; }
  .rank-plate .pill .ico { width: 24px; height: 24px; font-size: 13px; }
  .bottom { grid-template-columns: 200px 1fr 260px; gap: 8px; }
  .profile-tab { min-width: 164px; }
  .profile-tab .name { font-size: 14px; }
  .profile-tab .tag { font-size: 9px; }
  .chip { font-size: 14px; min-width: 64px; padding: 3px 10px 3px 3px; }
  .chip .ico { width: 26px; height: 26px; }
  .pass .pass-chest { width: 40px; height: 40px; font-size: 22px; }
  .pass .pass-title { font-size: 18px; }
  .pass .pass-sub { font-size: 10px; }

  /* Carry the 1100-px shrink further. */
  .event, .pass { padding: 7px 10px; }
  .event.event-goals .event-name { font-size: 16px; }
  .play-btn { font-size: 19px; padding: 8px 12px; }
  .token-bar .ico { width: 32px; height: 32px; font-size: 16px; }
  .token-bar .meter-num { font-size: 13px; }
  .token-bar .meter-hint { font-size: 9px; }
}

@media (max-width: 720px) {
  .screen {
    grid-template-rows: 52px 1fr auto;
    grid-template-columns: 72px 1fr 72px;
    padding: 8px;
    gap: 6px;
  }
  .dock { padding-top: 8px; gap: 7px; }
  .dock-btn { width: 60px; height: 60px; border-radius: 12px; }
  .dock-btn .glyph { font-size: 22px; }
  .dock-btn .label { font-size: 8.5px; margin-bottom: 4px; letter-spacing: 0.25px; }
  .character { width: 280px; }
  .character img { width: 280px; }
  .character-floor { width: 280px; height: 60px; }
  .character-platform { width: 200px; height: 24px; }
  .rank-plate { top: 8px; gap: 6px; }
  .rank-plate .pill { font-size: 12px; padding: 3px 10px 3px 3px; }
  .rank-plate .pill .ico { width: 20px; height: 20px; font-size: 11px; }
  /* Bottom row stacks vertically so each piece keeps its own min-width. */
  .bottom { grid-template-columns: 1fr; gap: 6px; padding-top: 6px; }
  .profile-tab { min-width: 0; gap: 0; padding: 2px 8px 2px 2px; }
  .profile-tab .avatar { width: 36px; height: 36px; }
  .profile-tab .avatar img { width: 30px; height: 30px; }
  .profile-tab .name { font-size: 13px; padding-left: 6px; }
  .profile-tab .tag { display: none; }
  .chip { font-size: 12px; min-width: 0; padding: 2px 9px 2px 2px; gap: 6px; }
  .chip .ico { width: 22px; height: 22px; }
  .hud { gap: 6px; }
  .hud-left, .hud-right { gap: 6px; }
}

@media (max-width: 520px) {
  .screen {
    grid-template-columns: 60px 1fr 60px;
    grid-template-rows: 46px 1fr auto;
    padding:
      max(6px, env(safe-area-inset-top))
      max(6px, env(safe-area-inset-right))
      max(6px, env(safe-area-inset-bottom))
      max(6px, env(safe-area-inset-left));
  }
  .dock { padding-top: 6px; gap: 6px; }
  .dock-btn { width: 52px; height: 52px; border-radius: 10px; border-width: 2.5px; box-shadow: 0 3px 0 0 var(--navy); }
  .dock-btn .glyph { font-size: 18px; }
  .dock-btn .label { font-size: 7.5px; margin-bottom: 3px; letter-spacing: 0; }
  .character { width: 200px; }
  .character img { width: 200px; }
  .character-floor { width: 200px; height: 44px; }
  .character-platform { width: 150px; height: 18px; }
  .rank-plate .pill { font-size: 10px; padding: 2px 8px 2px 2px; }
  .rank-plate .pill .ico { width: 16px; height: 16px; font-size: 9px; }
  .chip { font-size: 11px; }
  .chip .ico { width: 20px; height: 20px; }
}

/* Tiny phones (≤380 px — older / mini devices, narrow split-screen).
 * Dock columns shrink to 48 px so the character has room to breathe. */
@media (max-width: 380px) {
  .screen {
    grid-template-columns: 48px 1fr 48px;
    grid-template-rows: 42px 1fr auto;
    padding:
      max(4px, env(safe-area-inset-top))
      max(4px, env(safe-area-inset-right))
      max(4px, env(safe-area-inset-bottom))
      max(4px, env(safe-area-inset-left));
  }
  .dock-btn { width: 42px; height: 42px; border-radius: 9px; border-width: 2px; box-shadow: 0 2px 0 0 var(--navy); }
  .dock-btn .glyph { font-size: 16px; }
  .dock-btn .label { font-size: 7px; margin-bottom: 2px; }
  .character, .character img { width: 170px; }
  .character-floor { width: 170px; height: 36px; }
  .character-platform { width: 130px; height: 16px; }
  .profile-tab .name { font-size: 11px; }
  .chip { font-size: 10px; gap: 4px; padding: 2px 7px 2px 2px; }
  .chip .ico { width: 18px; height: 18px; }
  .play-btn { font-size: 16px; padding: 6px 10px; border-width: 2.5px; }
}

/* Short viewports — most often landscape phones (height ≈ 350–500 px).
 * The bottom row stays auto-sized, but the character image gets capped
 * so it doesn't push the row off-screen, and HUD/chrome shrink so the
 * board still has breathing room. */
@media (max-height: 520px) {
  .screen { grid-template-rows: 52px 1fr auto; }
  .character img { max-height: 100%; }
  .character-floor { display: none; }
  .character-platform { height: 16px; }
  .rank-plate { top: 4px; }
}
@media (max-height: 420px) {
  .screen { grid-template-rows: 44px 1fr auto; padding: 6px; }
  .dock-btn { width: 50px; height: 50px; }
  .dock-btn .glyph { font-size: 18px; }
  .dock-btn .label { font-size: 8px; }
  .character, .character img { width: clamp(140px, 30vw, 220px); }
  /* The 132-px bottom row was for a fixed-height legacy layout; in
   * the new auto-sized bottom row, the Owl Pass + Today's Goals +
   * Review block stack vertically on phones via the 720 px width
   * breakpoint, which keeps them readable even at 420 px height. */
}

/* Accuracy-tier bonus chip on the quiz victory screen — sits
   inside the gold .vict-reward and reads "+N bonus". Fires
   alongside the floating-coin animation that originates at
   the accuracy hex and lands on the coin counter. */
.vict-bonus-chip {
  display: inline-block;
  margin-left: 6px;
  padding: 2px 8px;
  border-radius: 999px;
  background: #FFE48A;
  color: #0B1E3F;
  border: 2px solid #0B1E3F;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  vertical-align: middle;
  animation: cgdBonusChipPop 360ms cubic-bezier(.34,1.56,.64,1);
}
@keyframes cgdBonusChipPop {
  0%   { transform: scale(0.6); opacity: 0; }
  60%  { transform: scale(1.15); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
