/*!
 * Udaan, © 2026 Shoolini University. All rights reserved.
 * Designed & built in-house by Divya Mohan · AI Product Developer · Shoolini Online.
 * Portfolio https://dmj.one/work/ · Proprietary & confidential, see /COPYRIGHT.
 * SPDX-License-Identifier: LicenseRef-Shoolini-Proprietary
 */
/* ============================================================
   UDAAN, design system (single source of style)
   Light, professional, enterprise-grade. Edit the :root tokens
   and the whole product re-themes. Nothing else carries colour.
   ============================================================ */
:root {
  /* surfaces, warm dawn paper, not sterile white */
  --bg:        #FFFDF7;
  --surface:   #FFFFFF;
  --surface-2: #FFF8EE;
  --surface-3: #FBEFDD;
  --line:      #EFE6D6;
  --line-2:    #E2D6C2;

  /* ink */
  --ink:       #1B1B2F;
  --ink-soft:  #5B5B73;
  --ink-faint: #9A9AB0;

  /* brand, sky-lift indigo (structure/trust) + saffron-amber accent (action/wins) */
  --primary:      #6366F1;
  --primary-2:    #818CF8;
  --primary-deep: #4F46E5;
  --primary-soft: #ECECFE;
  --accent:       #F59E0B;
  --accent-soft:  #FEF3D7;

  /* status, green=win, soft amber=try again, NO harsh red */
  --ok:   #16A34A;  --ok-soft:   #E6F6EC;
  --warn: #D97706;  --warn-soft: #FDF0DC;
  --err:  #E0683C;  --err-soft:  #FCEDE4;   /* warm coral, never alarming red */
  --info: #6366F1;  --info-soft: #ECECFE;

  /* shape + motion */
  --r-xs: 7px; --r-sm: 10px; --r-md: 14px; --r-lg: 20px; --r-xl: 28px;
  --shadow-sm: 0 1px 2px rgba(16,24,40,.05);
  --shadow:    0 4px 18px -6px rgba(16,24,40,.12), 0 1px 3px rgba(16,24,40,.05);
  --shadow-lg: 0 22px 48px -16px rgba(16,24,40,.22);
  --ring: 0 0 0 3px rgba(99,102,241,.22);
  --ease: cubic-bezier(.22,.61,.36,1);
  --dawn-grad: linear-gradient(135deg, #6366F1 0%, #FB7185 55%, #F59E0B 100%);
  --accent-warm: #FB7185;   /* dawn pink: encouragement / celebration */

  /* Indic + Perso-Arabic script fallbacks for the 32-language UI. Listed AFTER
     the Latin display/body/mono faces so Latin keeps rendering in Inter / Space
     Grotesk / JetBrains; the browser then auto-selects the matching Noto face
     per glyph (via each @font-face unicode-range) and lazy-downloads it ONLY
     when that script actually renders — one ~15-170KB file per chosen language.
     CJK (zh/ja/ko) is intentionally left to the system font (kept the repo
     light); Cyrillic (ru) likewise falls back to the system font. */
  --noto-indic: 'Noto Sans Devanagari','Noto Sans Bengali','Noto Sans Tamil','Noto Sans Telugu','Noto Sans Gujarati','Noto Sans Kannada','Noto Sans Malayalam','Noto Sans Gurmukhi','Noto Sans Oriya','Noto Sans Meetei Mayek','Noto Sans Ol Chiki','Noto Sans Arabic';
  --display: 'Space Grotesk', var(--noto-indic), 'Inter', system-ui, sans-serif;
  --font:    'Inter', var(--noto-indic), -apple-system, system-ui, 'Segoe UI', sans-serif;
  --mono:    'JetBrains Mono', var(--noto-indic), ui-monospace, 'Courier New', monospace;

  --maxw: 1180px;
  --appbar-h: 60px;

  /* foundations stars, warm gold for an earned star, cool grey for unearned */
  --star-gold:   #E8A317;
  --star-glow:   #F6C752;
  --star-deep:   #B5740C;
  --star-dim:    #D2D6DE;
  --star-soft:   #FBF1D8;

  /* onboarding palette, the learner's first impression. Calm,
     trustworthy depth (a deep ink-blue) carries stability; warm
     optimistic accents (amber / coral / a hopeful green) carry energy
     and momentum. Scoped to the welcome only, so the wider product
     theme is untouched. Red is never used here, a beginner makes no
     "errors" on a welcome screen. */
  --onb-trust:      #1E3A8A;   /* deep, dependable blue, anchors the screen */
  --onb-trust-2:    #2747A6;
  --onb-warm:       #F59E0B;   /* amber, hope, momentum, the prize         */
  --onb-warm-deep:  #C2740A;
  --onb-coral:      #FB7185;   /* soft coral, human warmth, never alarm    */
  --onb-grow:       #0F9D58;   /* growth green, "you are getting there"    */
  --onb-grow-soft:  #E4F4EC;
}

/* ============================================================
   Dark theme, indigo night that lifts toward dawn. Only token
   values change; every component re-themes automatically. Set by
   app.js (data-theme on <html>), persisted, defaults to OS scheme.
   ============================================================ */
[data-theme="dark"] {
  --bg:        #0F1020;   /* indigo night, not pure black */
  --surface:   #181A30;
  --surface-2: #1F2140;
  --surface-3: #262A4D;
  --line:      #2C2F52;
  --line-2:    #3A3E66;

  --ink:       #ECECF5;
  --ink-soft:  #A6A7C0;
  --ink-faint: #7A7C99;

  --primary:      #818CF8;
  --primary-2:    #A5B0FF;
  --primary-deep: #6366F1;
  --primary-soft: #23264A;
  --accent:       #FBBF24;
  --accent-soft:  #2A2410;
  --accent-warm:  #FB7185;

  --ok:   #34D399;  --ok-soft:   #10301F;
  --warn: #FBBF24;  --warn-soft: #2A2410;
  --err:  #FB9B6F;  --err-soft:  #2E1D14;
  --info: #818CF8;  --info-soft: #23264A;

  --shadow-sm: 0 1px 2px rgba(0,0,0,.4);
  --shadow:    0 4px 18px -6px rgba(0,0,0,.55), 0 1px 3px rgba(0,0,0,.4);
  --shadow-lg: 0 22px 48px -16px rgba(0,0,0,.65);
  --ring: 0 0 0 3px rgba(129,140,248,.30);
}

/* ============================================================
   LIVING ATMOSPHERE — a cinematic, signal-reactive space backdrop
   behind the whole app. DAY (light theme) = a daytime sky lifting to
   space; NIGHT (dark theme) = deep space. It reacts to real signals via
   CSS custom properties the controller (fx/atmosphere.js,
   window.UdaanAtmos) sets on <html>:
     --atmos-prog   0..1  journey progress -> star / nebula richness
     --atmos-smog   0..1  rocket-paste "pollution" (a recoverable haze)
     --atmos-paste  0..1  a paste "red glow" (recoverable)
   smog + paste accumulate on the event and DIFFUSE over time (the
   controller decays them; heavier intensity lingers longer), ALWAYS
   recovering fully — never a permanent mark, never a public shame.
   GPU-cheap (gradients + opacity + transform only, no animated blur);
   idle twinkle/drift run only on capable devices (.atmos:not(.atmos-static)),
   and the global prefers-reduced-motion rule freezes everything.
   ============================================================ */
.atmos { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; contain: layout paint; }
.atmos > div { position: absolute; inset: 0; }

/* ---- DAY (light theme): a soft dawn sky lifting toward space ---- */
.atmos-sky { background: linear-gradient(180deg, #D6E7FF 0%, #E9F1FF 26%, #FBF4E8 68%, var(--bg) 100%); }
.atmos-neb { background:
  radial-gradient(38% 32% at 84% 6%, rgba(255,214,140,.55), transparent 70%),
  radial-gradient(46% 40% at 10% 2%, rgba(170,198,255,.42), transparent 72%); }
.atmos-stars { opacity: calc(.04 + .22 * var(--atmos-prog, 0));
  background:
    radial-gradient(1.5px 1.5px at 18% 22%, rgba(60,70,110,.9), transparent 60%),
    radial-gradient(1.3px 1.3px at 72% 16%, rgba(60,70,110,.8), transparent 60%),
    radial-gradient(1.2px 1.2px at 50% 38%, rgba(60,70,110,.7), transparent 60%),
    radial-gradient(1.4px 1.4px at 33% 64%, rgba(60,70,110,.8), transparent 60%),
    radial-gradient(1.2px 1.2px at 86% 54%, rgba(60,70,110,.7), transparent 60%); }
.atmos-stars2 { opacity: 0; }

/* ---- NIGHT (dark theme): deep space, nebula, a rich starfield ---- */
[data-theme="dark"] .atmos-sky { background:
  radial-gradient(125% 90% at 50% -12%, rgba(20,24,54,.55) 0%, transparent 60%),
  linear-gradient(180deg, #0a0e22 0%, #070912 52%, #05060d 100%); }
[data-theme="dark"] .atmos-neb { background:
  radial-gradient(44% 34% at 80% 12%, rgba(99,102,241,.32), transparent 70%),
  radial-gradient(50% 42% at 16% 22%, rgba(168,85,247,.22), transparent 72%),
  radial-gradient(30% 24% at 62% 82%, rgba(20,184,166,.16), transparent 70%); }
[data-theme="dark"] .atmos-stars { opacity: calc(.4 + .6 * var(--atmos-prog, 0));
  background:
    radial-gradient(1.6px 1.6px at 12% 18%, #fff, transparent 60%),
    radial-gradient(1.5px 1.5px at 28% 52%, #eef, transparent 60%),
    radial-gradient(1.3px 1.3px at 44% 28%, #fff, transparent 60%),
    radial-gradient(1.7px 1.7px at 60% 64%, #fff, transparent 60%),
    radial-gradient(1.3px 1.3px at 76% 36%, #dde, transparent 60%),
    radial-gradient(1.5px 1.5px at 88% 70%, #fff, transparent 60%),
    radial-gradient(1.2px 1.2px at 20% 80%, #fff, transparent 60%),
    radial-gradient(1.2px 1.2px at 66% 14%, #fff, transparent 60%),
    radial-gradient(1.4px 1.4px at 38% 86%, #eef, transparent 60%),
    radial-gradient(1.2px 1.2px at 54% 6%, #fff, transparent 60%),
    radial-gradient(1.3px 1.3px at 8% 44%, #fff, transparent 60%),
    radial-gradient(1.2px 1.2px at 94% 24%, #dde, transparent 60%); }
[data-theme="dark"] .atmos-stars2 { opacity: 0;
  background:
    radial-gradient(1.5px 1.5px at 24% 34%, #fff, transparent 60%),
    radial-gradient(1.4px 1.4px at 58% 44%, #fff, transparent 60%),
    radial-gradient(1.3px 1.3px at 80% 58%, #cfe, transparent 60%),
    radial-gradient(1.4px 1.4px at 40% 72%, #fff, transparent 60%),
    radial-gradient(1.3px 1.3px at 70% 22%, #fff, transparent 60%); }

/* idle motion — capable devices only (frozen by reduced-motion globally) */
.atmos:not(.atmos-static) .atmos-neb { animation: atmos-drift 44s ease-in-out infinite alternate; }
[data-theme="dark"] .atmos:not(.atmos-static) .atmos-stars2 { animation: atmos-twinkle 4.5s ease-in-out infinite; }
@keyframes atmos-drift { to { transform: translate3d(2%, 1%, 0) scale(1.06); } }
@keyframes atmos-twinkle { 0%, 100% { opacity: calc((.12 + .25 * var(--atmos-prog, 0)) * (.25 + .75 * var(--atmos-alt, 0))); } 50% { opacity: calc((.4 + .5 * var(--atmos-prog, 0)) * (.25 + .75 * var(--atmos-alt, 0))); } }

/* ---- SMOG: rocket-paste pollution, rises from below, dims the scene ---- */
.atmos-smog { opacity: var(--atmos-smog, 0); transition: opacity .6s ease;
  background:
    radial-gradient(120% 72% at 50% 110%, rgba(86,78,66,.62), transparent 66%),
    linear-gradient(0deg, rgba(74,68,60,.4) 0%, transparent 52%); }
[data-theme="dark"] .atmos-smog { background:
    radial-gradient(120% 72% at 50% 110%, rgba(58,52,44,.72), transparent 66%),
    linear-gradient(0deg, rgba(38,34,28,.52) 0%, transparent 52%); }

/* ---- PASTE GLOW: a recoverable red glow at the edges, deepens on repeat ----
   It BREATHES (a slow pulse) while present, and because the keyframes scale by
   --atmos-paste, the breath grows fainter as the glow diffuses, until the sky
   is undisturbed again. Reduced-motion / low-end devices get a steady glow that
   still diffuses (no pulse). */
.atmos-paste { opacity: var(--atmos-paste, 0); transition: opacity .5s ease;
  background: radial-gradient(120% 100% at 50% 50%, transparent 52%, rgba(210,38,38,.42) 100%);
  box-shadow: inset 0 0 150px 34px rgba(220,40,40,.38); }
.atmos:not(.atmos-static) .atmos-paste { animation: atmos-breathe 2.6s ease-in-out infinite; }
@keyframes atmos-breathe {
  0%, 100% { opacity: calc(var(--atmos-paste, 0) * .5); }
  50%      { opacity: calc(var(--atmos-paste, 0) * 1); }
}

/* ---- ALTITUDE DEPTH (F2): the scene deepens stage by stage as the learner
   clears real curriculum stages. --atmos-alt (set by UdaanAtmos.setAltitude,
   driven by UdaanAscent.altitudeFor = honest per-stage completion) fades in a
   SECOND, deeper parallax starfield. --atmos-prog still drives the primary
   richness; alt is the staged depth on top. Opacity/transform/gradient only;
   the global reduced-motion rule freezes the drift + the ascent pulse. ---- */
.atmos-stars2 { opacity: calc(.30 * var(--atmos-alt, 0));
  background:
    radial-gradient(1.1px 1.1px at 24% 34%, rgba(60,70,110,.7), transparent 60%),
    radial-gradient(1px 1px at 58% 44%, rgba(60,70,110,.6), transparent 60%),
    radial-gradient(1.1px 1.1px at 80% 58%, rgba(60,70,110,.6), transparent 60%),
    radial-gradient(1px 1px at 40% 72%, rgba(60,70,110,.6), transparent 60%),
    radial-gradient(1.1px 1.1px at 70% 22%, rgba(60,70,110,.6), transparent 60%); }
[data-theme="dark"] .atmos-stars2 { opacity: calc(.55 * var(--atmos-alt, 0)); }

/* a brief one-shot "lift" when a solve completes a stage (UdaanAtmos.ascendPulse
   toggles .atmos-ascend on the root). The root has no other animation, so this
   never conflicts with the nebula drift / twinkle. */
.atmos.atmos-ascend { animation: atmos-ascend-pulse 1.5s ease-out; }
@keyframes atmos-ascend-pulse { 0% { transform: translateY(1.6%); } 40% { transform: translateY(-0.7%); } 100% { transform: none; } }

/* EXAM-INTEGRITY: the persistent paste marker (raised by app.js examPasteAlertShow
   when a paste lands in a locked exam editor). A fixed, NON-decaying red frame +
   a neutral banner, visible to an invigilator across the room; it stays until the
   exam ends. pointer-events:none so it never intercepts the editor. No animation
   (it must not hide after a delay), so reduced-motion needs no special case. */
.exam-paste-alert{ position:fixed; inset:0; z-index:10000; pointer-events:none; }
.exam-paste-alert .epa-frame{ position:absolute; inset:0; border:7px solid #e11414;
  box-shadow:inset 0 0 0 2px rgba(255,255,255,.35), inset 0 0 48px 8px rgba(225,20,20,.55); }
.exam-paste-alert .epa-tag{ position:absolute; top:0; left:50%; transform:translateX(-50%);
  max-width:92vw; padding:6px 16px; border-radius:0 0 10px 10px;
  background:#e11414; color:#fff; font:700 13px/1.4 var(--display, system-ui);
  letter-spacing:.02em; box-shadow:0 2px 10px rgba(0,0,0,.25); }

/* worked-example reveal: the box ITSELF is the affordance. Hovering it turns the
   CURSOR into a "+" (no widget, no outline box) and shows the corner hint;
   clicking the box (or Enter/Space) detonates the blast and floats the next
   example in; earlier boxes stay. Keyboard focus still shows a ring (a11y).
   The "+" cursor is a data-URI SVG (white glyph + dark halo, legible on any
   theme) with the native `cell` plus as fallback if data cursors are blocked. */
.casecard.case-expandable{ position:relative;
  cursor: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHBhdGggZD0iTTEyIDQuNVYxOS41TTQuNSAxMkgxOS41IiBzdHJva2U9IiMwMDAiIHN0cm9rZS1vcGFjaXR5PSIuMzUiIHN0cm9rZS13aWR0aD0iNS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMTIgNC41VjE5LjVNNC41IDEySDE5LjUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIzLjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvc3ZnPg==') 12 12, cell; }
.casecard.case-expandable:focus-visible{ box-shadow:0 0 0 2px var(--primary, #6366f1); outline:none; }
.case-add-hint{ position:absolute; bottom:8px; right:12px; font:600 11px/1 var(--display, system-ui); color:var(--ink-soft, #6b7280);
  opacity:0; transition:opacity .18s ease; pointer-events:none; }
.casecard.case-expandable:hover .case-add-hint, .casecard.case-expandable:focus-visible .case-add-hint{ opacity:.9; }
@keyframes caseFloatIn{ from{ opacity:0; transform:translateY(16px) scale(.96); } to{ opacity:1; transform:none; } }
.casecard.case-floatin{ animation:caseFloatIn .55s cubic-bezier(.2,.8,.2,1) both; }
.casecard + .casecard{ margin-top:8px; }
@media (prefers-reduced-motion: reduce){
  .casecard.case-floatin{ animation:none; }
  .case-add-hint{ transition:none; }
}

/* practice paste cue: a brief red edge pulse on the code editor, then it fades.
   Pasting is allowed in practice, so this is a light "noticed" cue, NOT the
   exam's persistent marker. Reduced-motion shows a brief static ring instead. */
.monaco-host.paste-flash{ animation: paste-flash .9s ease-out; }
@keyframes paste-flash{
  0%{ box-shadow:0 0 0 3px rgba(225,20,20,.85), 0 0 22px 6px rgba(225,20,20,.5); }
  100%{ box-shadow:0 0 0 0 rgba(225,20,20,0), 0 0 0 0 rgba(225,20,20,0); }
}
@media (prefers-reduced-motion: reduce){
  .monaco-host.paste-flash{ animation:none; box-shadow:0 0 0 3px rgba(225,20,20,.55); }
}

/* ============================================================
   Self-hosted web fonts (no third-party Google Fonts dependency).
   woff2 served from same origin (assets/fonts/*), so CSP needs no
   fonts.googleapis.com / fonts.gstatic.com origins and there is no
   privacy leak to a third party. Each family ships as a VARIABLE
   font (one file per subset covers the whole weight axis), so a
   single @font-face per (family, subset) with a font-weight RANGE
   serves every weight the UI uses:
     Space Grotesk 500/600/700, Inter 400-800, JetBrains Mono 400/500.
   latin + latin-ext subsets only (English + Hindi-Latin UI). The
   unicode-range values are copied verbatim from Google's css2 output
   so the browser fetches latin-ext only when a glyph needs it.
   font-display: swap keeps text visible during font load.
   ============================================================ */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/space-grotesk-latin.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/space-grotesk-latin-ext.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-latin.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-latin-ext.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("fonts/jetbrains-mono-latin.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("fonts/jetbrains-mono-latin-ext.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ============================================================
   Indic + Perso-Arabic web fonts for the 32-language UI (self-hosted Noto Sans,
   one script subset per file). Each is scoped by unicode-range so the browser
   downloads it ONLY when a glyph of that script renders (lazy, per selected
   language). Referenced via --noto-indic in the font stacks above. RTL
   direction (Urdu/Kashmiri/Sindhi/Arabic) is set on <html dir> by app.js.
   CJK is intentionally NOT self-hosted (system font fallback).
   ============================================================ */
@font-face {
  font-family: 'Noto Sans Devanagari';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-devanagari.woff2") format('woff2');
  unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
}
@font-face {
  font-family: 'Noto Sans Bengali';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-bengali.woff2") format('woff2');
  unicode-range: U+0951-0952, U+0964-0965, U+0980-09FE, U+1CD0, U+1CD2, U+1CD5-1CD6, U+1CD8, U+1CE1, U+1CEA, U+1CED, U+1CF2, U+1CF5-1CF7, U+200C-200D, U+20B9, U+25CC, U+A8F1;
}
@font-face {
  font-family: 'Noto Sans Tamil';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-tamil.woff2") format('woff2');
  unicode-range: U+0964-0965, U+0B82-0BFA, U+200C-200D, U+20B9, U+25CC;
}
@font-face {
  font-family: 'Noto Sans Telugu';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-telugu.woff2") format('woff2');
  unicode-range: U+0951-0952, U+0964-0965, U+0C00-0C7F, U+1CDA, U+1CF2, U+200C-200D, U+25CC;
}
@font-face {
  font-family: 'Noto Sans Gujarati';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-gujarati.woff2") format('woff2');
  unicode-range: U+0951-0952, U+0964-0965, U+0A80-0AFF, U+200C-200D, U+20B9, U+25CC, U+A830-A839;
}
@font-face {
  font-family: 'Noto Sans Kannada';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-kannada.woff2") format('woff2');
  unicode-range: U+0951-0952, U+0964-0965, U+0C80-0CF3, U+1CD0, U+1CD2-1CD3, U+1CDA, U+1CF2, U+1CF4, U+200C-200D, U+20B9, U+25CC, U+A830-A835;
}
@font-face {
  font-family: 'Noto Sans Malayalam';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-malayalam.woff2") format('woff2');
  unicode-range: U+0307, U+0323, U+0951-0952, U+0964-0965, U+0D00-0D7F, U+1CDA, U+1CF2, U+200C-200D, U+20B9, U+25CC, U+A830-A832;
}
@font-face {
  font-family: 'Noto Sans Gurmukhi';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-gurmukhi.woff2") format('woff2');
  unicode-range: U+0951-0952, U+0964-0965, U+0A01-0A76, U+200C-200D, U+20B9, U+25CC, U+262C, U+A830-A839;
}
@font-face {
  font-family: 'Noto Sans Oriya';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-oriya.woff2") format('woff2');
  unicode-range: U+0951-0952, U+0964-0965, U+0B01-0B77, U+1CDA, U+1CF2, U+200C-200D, U+20B9, U+25CC;
}
@font-face {
  font-family: 'Noto Sans Meetei Mayek';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-meetei.woff2") format('woff2');
  unicode-range: U+200C-200D, U+25CC, U+AAE0-AAF6, U+ABC0-ABFF;
}
@font-face {
  font-family: 'Noto Sans Ol Chiki';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-olchiki.woff2") format('woff2');
  unicode-range: U+1C50-1C7F, U+20B9;
}
@font-face {
  font-family: 'Noto Sans Arabic';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/noto-arabic.woff2") format('woff2');
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }
a { color: inherit; text-decoration: none; }
img, svg { max-width: 100%; }
button { font-family: inherit; }
/* the BOOT loader is a LAUNCH-DAY LAUNCHPAD: the rocket waits on green grass
   under a blue sky with a sun and drifting clouds; bootReveal() then lifts it
   off through that same sky (shared with the takeoff cover) and tears it open
   to reveal the app, one continuous climb. */
.boot { position:relative; overflow:hidden;
  display:flex; flex-direction:column; justify-content:flex-end; align-items:center;
  height:100vh; padding-bottom:9vh; font-weight:600; color:#27452f; }
/* ============================================================
   PHOTOREAL NATURE SCENE, pure inline-SVG feTurbulence + CSS (CSP-safe),
   composed by the nature-render team. `.scene` fills the boot launchpad and
   the takeoff cover; it is an isolated stacking context, so every layer sits
   BELOW the rocket/gantry/label. Sun = upper-right; all lighting keys off it.
   Layers: sky(0) far-clouds(1) atmosphere+haze(2) near-clouds(3) grass(4)
   grade/vignette(5). ============================================================ */
.scene{ position:absolute; inset:0; z-index:0; isolation:isolate; overflow:hidden; }
.scene .sky{ position:absolute; inset:0; z-index:0;
  background:
    radial-gradient(120% 90% at 86% 10%, rgba(255,233,176,.45) 0%, rgba(255,233,176,0) 42%),
    linear-gradient(to bottom,#1E63B8 0%,#2C74C6 26%,#3E86D6 50%,#79A9DB 74%,#AFCAE0 88%,#CFE0EA 100%); }
.scene .cloud-layer{ position:absolute; inset:-15% -35%; width:170%; height:130%; pointer-events:none; will-change:transform; }
.scene .cloud-layer svg{ position:absolute; inset:0; width:100%; height:100%; }
.scene .far-clouds{ z-index:1; opacity:.55; filter:blur(1.4px); animation:driftFar 120s linear infinite alternate; }
.scene .near-clouds{ z-index:3; opacity:.93; animation:driftNear 72s linear infinite alternate; }
@keyframes driftFar{ from{ transform:translate3d(-6%,0,0);} to{ transform:translate3d(8%,0,0);} }
@keyframes driftNear{ from{ transform:translate3d(-10%,0,0);} to{ transform:translate3d(12%,0,0);} }
.scene .atmosphere{ position:absolute; inset:0; z-index:2; pointer-events:none; }
.scene .godrays{ position:absolute; top:10%; right:14%; width:170vmax; height:170vmax; transform:translate(50%,-50%);
  background:conic-gradient(from 200deg at 50% 50%,transparent 0deg,rgba(255,243,210,.20) 4deg,transparent 9deg,transparent 16deg,rgba(255,243,210,.14) 20deg,transparent 25deg,transparent 33deg,rgba(255,243,210,.22) 38deg,transparent 44deg,transparent 55deg,rgba(255,243,210,.12) 60deg,transparent 66deg,transparent 80deg,rgba(255,243,210,.18) 86deg,transparent 92deg,transparent 360deg);
  -webkit-mask-image:radial-gradient(closest-side,#000 0%,rgba(0,0,0,.5) 38%,transparent 70%); mask-image:radial-gradient(closest-side,#000 0%,rgba(0,0,0,.5) 38%,transparent 70%);
  mix-blend-mode:screen; opacity:.5; transform-origin:50% 50%; animation:raydrift 26s ease-in-out infinite alternate; }
.scene .sun-bloom{ position:absolute; top:10%; right:14%; width:60vmax; height:60vmax; transform:translate(50%,-50%);
  background:radial-gradient(closest-side,rgba(255,246,224,.85) 0%,rgba(255,233,176,.55) 14%,rgba(255,224,150,.28) 30%,rgba(255,224,150,.10) 50%,transparent 70%); mix-blend-mode:screen; animation:sunpulse 7s ease-in-out infinite; }
.scene .sun-disc{ position:absolute; top:10%; right:14%; width:7.5vmax; height:7.5vmax; transform:translate(50%,-50%); border-radius:50%;
  background:radial-gradient(closest-side,#fffefb 0%,#FFF6E0 42%,#FFE9B0 72%,rgba(255,233,176,0) 100%); box-shadow:0 0 6vmax 2.5vmax rgba(255,243,210,.55); mix-blend-mode:screen; }
.scene .flare{ position:absolute; border-radius:50%; mix-blend-mode:screen; pointer-events:none; }
.scene .flare.a{ top:24%; right:26%; width:2.2vmax; height:2.2vmax; background:radial-gradient(closest-side,rgba(255,210,150,.6),transparent 70%); }
.scene .flare.b{ top:38%; right:38%; width:5vmax; height:5vmax; background:radial-gradient(closest-side,rgba(150,200,255,.16),rgba(150,200,255,.05) 60%,transparent 72%); }
.scene .flare.c{ top:50%; left:50%; width:1.2vmax; height:1.2vmax; transform:translate(-50%,-50%); background:radial-gradient(closest-side,rgba(255,255,255,.55),transparent 70%); }
.scene .flare.d{ bottom:34%; left:34%; width:3.4vmax; height:3.4vmax; background:radial-gradient(closest-side,rgba(180,255,210,.14),transparent 70%); }
.scene .flare.e{ bottom:20%; left:22%; width:7vmax; height:7vmax; background:radial-gradient(closest-side,rgba(255,220,170,.12),rgba(255,220,170,.04) 60%,transparent 74%); }
.scene .flare.f{ bottom:12%; left:14%; width:1.6vmax; height:1.6vmax; background:radial-gradient(closest-side,rgba(200,180,255,.30),transparent 70%); }
.scene .horizon-haze{ position:absolute; left:0; right:0; bottom:0; height:34%; z-index:2; pointer-events:none;
  background:linear-gradient(to bottom,rgba(207,224,234,0) 0%,rgba(207,224,234,.28) 55%,rgba(214,228,236,.55) 80%,rgba(220,232,240,.72) 100%);
  -webkit-mask-image:linear-gradient(to bottom,transparent,#000 60%); mask-image:linear-gradient(to bottom,transparent,#000 60%); }
.scene svg.grass{ position:absolute; left:0; right:0; bottom:0; width:100%; height:44%; z-index:4; display:block; }
.scene .grade{ position:absolute; inset:0; z-index:5; pointer-events:none; }
.scene .grade-warm{ position:absolute; inset:0; mix-blend-mode:soft-light; opacity:.22; background:linear-gradient(118deg,rgba(40,70,120,.55) 0%,rgba(255,238,205,0) 48%,rgba(255,210,150,.6) 100%); }
.scene .grade-vignette{ position:absolute; inset:0; mix-blend-mode:multiply; background:radial-gradient(135% 120% at 80% 16%,rgba(255,255,255,0) 0%,rgba(255,255,255,0) 55%,rgba(150,158,176,.55) 84%,rgba(74,82,104,.80) 100%); }
@keyframes raydrift{ from{ transform:translate(50%,-50%) rotate(-2.2deg);} to{ transform:translate(50%,-50%) rotate(2.2deg);} }
@keyframes sunpulse{ 0%,100%{ opacity:.9;} 50%{ opacity:1; filter:brightness(1.06);} }
@media (prefers-reduced-motion: reduce){ .scene .far-clouds, .scene .near-clouds, .scene .godrays, .scene .sun-bloom{ animation:none; } }
.boot .rocket-load{ position:relative; z-index:3; padding:0; gap:18px; }
.boot .rl-label{ order:-1; color:#fff; text-shadow:0 1px 4px rgba(18,40,28,.5); }  /* readable on sky/grass */
/* the drawn rocket on the pad, idling with a gentle hover */
.rl-craft{ position:relative; width:46px; height:104px; animation:rl-hover 2.6s ease-in-out infinite; }
.rk{ display:block; filter:drop-shadow(0 6px 9px rgba(20,40,30,.3)); }
@keyframes rl-hover{ 0%,100%{ transform:translateY(0); } 50%{ transform:translateY(-5px); } }
/* the engine flame, white-hot core fading to orange. Sits just under the
   nozzle (top:100% of the craft). Idle puff on the pad, long burn on liftoff. */
.rk-flame{ position:absolute; left:50%; top:100%; transform:translateX(-50%); transform-origin:50% 0;
  width:15px; height:38px; pointer-events:none; filter:blur(.6px);
  border-radius:48% 48% 50% 50% / 60% 60% 42% 42%;
  background:radial-gradient(ellipse at 50% 16%, #fff 0%, #ffe487 24%, #ff9d2f 52%, #ff5a2b 74%, rgba(255,80,40,0) 100%); }
.rk-idle{ height:24px; width:12px; margin-top:-3px; animation:flame-flick .26s ease-in-out infinite alternate; }
.rk-burn{ height:128px; width:20px; margin-top:-3px; animation:flame-flick .1s ease-in-out infinite alternate; }
@keyframes flame-flick{ from{ transform:translateX(-50%) scale(.95,.92); opacity:.86; }
  to{ transform:translateX(-50%) scale(1.05,1.07); opacity:1; } }
@media (prefers-reduced-motion: reduce){ .rl-craft, .rk-flame{ animation:none; }
  .boot::after, .uv-zip-cover::after{ animation:none; } }

/* ============================================================
   NIGHT LAUNCH, the night twin of the day launchpad above.
   Shows ONLY when the orchestrator sets `.scene.is-night` (driven by
   LOCAL TIME OF DAY / weather-API is_day, NOT the app's [data-theme]).
   The day scene is the unprefixed base and is left completely untouched:
   at night the same sky/cloud/grass layers are re-painted to a
   moonlit night and the whole sun system (.atmosphere) is hidden,
   while a moon + three starfields + a Milky Way band + an occasional
   shooting star fade in. These night layers are added as elements
   INSIDE .scene, so the boot splash AND the cloned takeoff cover both
   get them for free (bootReveal clones .boot .scene). GPU-cheap only:
   gradient starfields, transform/opacity motion, static filters, no
   lighting filters, no animated blur (boot-scene perf budget). The
   global reduced-motion rule above (* { animation:none !important })
   already stills every animation here; base states stay invisible
   (shoot) or lit (stars), so nothing freezes mid-frame.
   ============================================================ */
/* night-only layers: absent from the day scene, zero layout cost */
.scene .night{ display:none; }
.scene.is-night .night{ display:block; position:absolute; inset:0; z-index:3; pointer-events:none; }

/* 1 · repaint the existing sky gradient as deep night lifting toward dawn */
.scene.is-night .sky{
  background:
    radial-gradient(120% 95% at 84% 12%, rgba(150,170,255,.16) 0%, rgba(150,170,255,0) 46%),
    linear-gradient(to bottom,#070A1E 0%,#0B1030 26%,#121A47 52%,#1B2455 72%,#2A2F63 88%,#3A3A6E 100%); }
/* 2 · hide the whole sun system (godrays + bloom + disc + lens flares) */
.scene.is-night .atmosphere{ display:none; }
/* 3 · clouds become faint cool moonlit wisps (static filter, painted once) */
.scene.is-night .far-clouds{ opacity:.20; filter:brightness(.42) saturate(.5) blur(1.4px); }
.scene.is-night .near-clouds{ opacity:.30; filter:brightness(.5) saturate(.55); }
/* 4 · horizon + grass + grade: moonlit, desaturated, cool */
.scene.is-night .horizon-haze{
  background:linear-gradient(to bottom,rgba(40,52,110,0) 0%,rgba(40,52,110,.30) 55%,rgba(34,44,96,.55) 80%,rgba(28,36,82,.72) 100%); }
.scene.is-night svg.grass{ filter:brightness(.40) saturate(.6) hue-rotate(-6deg); }
.scene.is-night .grade-warm{
  background:linear-gradient(118deg,rgba(20,28,70,.6) 0%,rgba(120,130,200,0) 50%,rgba(150,165,255,.30) 100%); }
.scene.is-night .grade-vignette{
  background:radial-gradient(135% 120% at 82% 16%,rgba(0,0,0,0) 0%,rgba(0,0,0,0) 50%,rgba(6,8,24,.55) 84%,rgba(3,4,14,.82) 100%); }

/* 5 · Milky Way, a soft diagonal light band (gradient softness, no blur) */
.scene.is-night .night .mw{ position:absolute; inset:-20% -10%;
  background:
    radial-gradient(60% 24% at 52% 40%, rgba(196,206,255,.16) 0%, rgba(150,170,255,.07) 45%, transparent 72%),
    radial-gradient(40% 14% at 46% 44%, rgba(255,236,214,.10) 0%, transparent 70%);
  transform:rotate(-24deg); mix-blend-mode:screen; opacity:.9; }
/* 6 · three tiled starfields, drifting at different rates for parallax depth */
.scene.is-night .night .stars{ position:absolute; inset:-50% -50%; background-repeat:repeat; }
.scene.is-night .night .stars.far{
  background-image:
    radial-gradient(1px 1px at 18px 32px,#cdd6ff 50%,transparent),
    radial-gradient(1px 1px at 92px 14px,#ffffff 50%,transparent),
    radial-gradient(1px 1px at 160px 90px,#bcd0ff 50%,transparent),
    radial-gradient(1px 1px at 240px 50px,#e7ecff 50%,transparent),
    radial-gradient(1px 1px at 300px 140px,#ffffff 50%,transparent);
  background-size:340px 340px; opacity:.7; animation:starDrift 150s linear infinite; }
.scene.is-night .night .stars.mid{
  background-image:
    radial-gradient(1.4px 1.4px at 60px 60px,#ffffff 50%,transparent),
    radial-gradient(1.4px 1.4px at 200px 120px,#dfe6ff 50%,transparent),
    radial-gradient(1.2px 1.2px at 130px 200px,#fff4e0 50%,transparent),
    radial-gradient(1.4px 1.4px at 280px 30px,#cfe0ff 50%,transparent);
  background-size:420px 420px; opacity:.85; animation:starDrift 100s linear infinite reverse; }
.scene.is-night .night .stars.near{
  background-image:
    radial-gradient(2px 2px at 120px 80px,#ffffff 50%,transparent),
    radial-gradient(1.8px 1.8px at 320px 220px,#eaf0ff 50%,transparent),
    radial-gradient(2.2px 2.2px at 40px 260px,#fff6e6 50%,transparent);
  background-size:560px 560px; opacity:.95; animation:starTwinkle 4.2s ease-in-out infinite, starDrift 70s linear infinite; }
@keyframes starDrift{ from{ transform:translate3d(0,0,0);} to{ transform:translate3d(-340px,0,0);} }
@keyframes starTwinkle{ 0%,100%{ opacity:.95;} 45%{ opacity:.5;} 70%{ opacity:1;} }
/* 7 · the moon, where the sun was (upper-right), softly glowing, faint maria */
.scene.is-night .night .moon{ position:absolute; top:11%; right:14%;
  width:8.5vmax; height:8.5vmax; border-radius:50%;
  background:radial-gradient(circle at 38% 34%,#fdfdf6 0%,#eef0f6 42%,#cdd2e2 72%,#aab0c6 100%);
  box-shadow:0 0 .6vmax .15vmax rgba(255,255,255,.5), inset -1.6vmax -1.6vmax 2.4vmax rgba(40,48,92,.45); }
.scene.is-night .night .moon-halo{ position:absolute; left:50%; top:50%; width:240%; height:240%;
  transform:translate(-50%,-50%); border-radius:50%; mix-blend-mode:screen;
  background:radial-gradient(closest-side,rgba(214,224,255,.42) 0%,rgba(190,205,255,.18) 38%,transparent 70%);
  animation:moonGlow 7s ease-in-out infinite; }
.scene.is-night .night .moon-mare{ position:absolute; border-radius:50%;
  background:radial-gradient(circle at 40% 38%,rgba(150,158,186,.5),rgba(150,158,186,0) 72%); }
.scene.is-night .night .moon-mare.a{ width:30%; height:30%; top:26%; left:30%; }
.scene.is-night .night .moon-mare.b{ width:20%; height:20%; top:52%; left:54%; }
.scene.is-night .night .moon-mare.c{ width:14%; height:14%; top:38%; left:60%; }
@keyframes moonGlow{ 0%,100%{ opacity:.85;} 50%{ opacity:1;} }
/* 8 · an occasional shooting star, a rare GPU-cheap streak across the sky */
.scene.is-night .night .shoot{ position:absolute; top:16%; left:-8%;
  width:14vmax; height:2px; border-radius:2px; opacity:0; transform:rotate(16deg);
  background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,.9));
  filter:drop-shadow(0 0 3px rgba(190,210,255,.8)); animation:shoot 11s ease-in infinite; }
@keyframes shoot{
  0%,86%{ opacity:0; transform:translate3d(0,0,0) rotate(16deg);}
  88%{ opacity:0;} 90%{ opacity:1;}
  100%{ opacity:0; transform:translate3d(64vw,20vh,0) rotate(16deg);} }

/* ============================================================
   WEATHER MOODS, the launchpad sky is never the same twice.
   The orchestrator drops one `wx-*` class on .scene per visit (from real
   local weather); it pairs with `.is-day` / `.is-night`, so every mood has
   a DAY face (unprefixed base) and a NIGHT face (`.scene.is-night.wx-*`).
   Clear sky is the base (no rules needed); these layer cloudy / windy /
   overcast / mist / rain / storm / snow on top, with an optional
   `wx-i1|wx-i2|wx-i3` intensity that deepens rain. The .wx
   fx layers (cloudbank, fog, rain, wind) live inside .scene, so they
   ride the cloned takeoff cover and stay behind the rocket, and are
   inert until their mood switches them on. All GPU-cheap: gradients +
   transform / opacity / background-position, no lighting filters, no
   animated blur (boot-scene perf budget). The global reduced-motion
   rule (* { animation:none !important }) stills all motion; base states
   stay legible, so a mood reads fine frozen.
   ============================================================ */
.scene .wx{ position:absolute; inset:0; pointer-events:none; }
.scene .wx > *{ position:absolute; inset:0; display:none; }
/* OVERSCAN the drifting/transformed overlays horizontally: cloudbank (driftFar/
   Near ±8%), fog (fogDrift ±4%), rain (skewX) and wind (±14%) translate
   sideways, and at 100% width that slid them off-edge and revealed an
   uncovered vertical strip near the screen edge (the mist/snow "break"). Making
   them wider than the viewport means the slide never exposes a gap. */
.scene .wx-cloudbank, .scene .wx-fog, .scene .wx-rain{ left:-16%; right:-16%; }
.scene .wx-wind{ left:-24%; right:-24%; }

/* ---- CLOUDY: the REAL feTurbulence clouds carry it, fuller & brighter,
   scaled up a touch for more sky cover, kept white; softened sun. The flat
   gradient cloudbank is gone: natural cloud SHAPES read as cloud, not a blob.
   (Far-clouds keeps its base blur(1.4px); near-clouds stays crisp.) ---- */
.scene.wx-cloudy .far-clouds{ opacity:.85; }
.scene.wx-cloudy .far-clouds svg{ transform:scale(1.14); }
.scene.wx-cloudy .near-clouds{ opacity:1; animation-duration:96s; }
.scene.wx-cloudy .near-clouds svg{ transform:scale(1.1); }
.scene.wx-cloudy .sun-bloom{ opacity:.5; }
.scene.wx-cloudy .godrays{ opacity:.25; }
.scene.is-night.wx-cloudy .far-clouds{ opacity:.42; filter:brightness(.5) saturate(.55) blur(1.4px); }
.scene.is-night.wx-cloudy .near-clouds{ opacity:.52; filter:brightness(.56) saturate(.6); }
.scene.is-night.wx-cloudy .night .stars{ opacity:.5; }
.scene.is-night.wx-cloudy .night .moon-halo{ opacity:.6; }

/* ---- WINDY: clouds race, the rocket leans, thin wind streaks ---- */
.scene.wx-windy .far-clouds{ animation-duration:42s; }
.scene.wx-windy .near-clouds{ animation-duration:24s; opacity:.8; }
.scene.wx-windy .wx-wind{ display:block; z-index:3; opacity:.45; mix-blend-mode:screen;
  background:repeating-linear-gradient(4deg, rgba(255,255,255,0) 0, rgba(255,255,255,0) 84px, rgba(255,255,255,.14) 88px, rgba(255,255,255,0) 96px);
  animation:wind 4.5s linear infinite; }
@keyframes wind{ 0%{ transform:translate3d(-14%,0,0); opacity:.18;} 50%{ opacity:.5;} 100%{ transform:translate3d(14%,0,0); opacity:.18;} }
/* the rocket on the pad leans into the wind (this mood only; .rocket-load
   is a sibling of .scene, so the general-sibling combinator reaches it) */
.scene.wx-windy ~ .rocket-load .rl-craft{ animation:rl-sway 3.4s ease-in-out infinite; }
@keyframes rl-sway{ 0%,100%{ transform:translateY(0) rotate(-2.4deg);} 50%{ transform:translateY(-4px) rotate(2.4deg);} }
.scene.is-night.wx-windy .wx-wind{ opacity:.3;
  background:repeating-linear-gradient(86deg, rgba(190,205,255,0) 0, rgba(190,205,255,0) 60px, rgba(190,205,255,.12) 64px, rgba(190,205,255,0) 70px); }

/* ---- HEAVY CLOUD CEILING, a DENSE grey feTurbulence sheet (#heavyCloud in
   the markup), built the SAME way as the natural day clouds (real turbulence,
   not a gradient). This is what makes overcast/rain/storm read as a genuine
   cloudy sky instead of a flat wash. It sits at z-index:3 (topmost sky layer,
   above the faint gradient cloudbank and wispy near-clouds, below grass/rocket),
   hidden until those moods switch it on, tinted per mood + day/night with a
   cheap STATIC filter, the turbulence bitmap is cached, so the slow drift
   stays GPU-cheap (no per-frame re-raster). ---- */
.scene .heavy-clouds{ display:none; z-index:3; opacity:0; animation:driftNear 96s linear infinite alternate; }
.scene.wx-overcast .heavy-clouds,
.scene.wx-rain .heavy-clouds,
.scene.wx-storm .heavy-clouds{ display:block; }
.scene.wx-overcast .heavy-clouds{ opacity:.96; }
.scene.wx-rain .heavy-clouds{ opacity:.93; filter:brightness(.9) saturate(.85); }
.scene.wx-storm .heavy-clouds{ opacity:1; filter:brightness(.5) saturate(.7); }
.scene.is-night.wx-overcast .heavy-clouds{ opacity:1; filter:brightness(.36) saturate(.5); }
.scene.is-night.wx-rain .heavy-clouds{ opacity:.97; filter:brightness(.32) saturate(.5); }
.scene.is-night.wx-storm .heavy-clouds{ opacity:1; filter:brightness(.22) saturate(.45); }

/* ---- OVERCAST: a heavy grey CLOUD CEILING. The real turbulence clouds go
   full-opacity, greyed and scaled up so their natural shapes fill the sky as
   a brooding lid; the gradient cloudbank stays only as a faint tonal wash
   behind them (a darker brooding underside + a lighter break), never the star.
   Day = greyed clouds; night = clouds crushed dark. ---- */
.scene.wx-overcast .atmosphere{ opacity:.22; }
.scene.wx-overcast .far-clouds{ opacity:1; filter:brightness(.7) saturate(.4) blur(1.4px); }
.scene.wx-overcast .far-clouds svg{ transform:scale(1.3) translateY(-4%); }
.scene.wx-overcast .near-clouds{ opacity:1; animation-duration:120s; filter:brightness(.62) saturate(.35); }
.scene.wx-overcast .near-clouds svg{ transform:scale(1.24) translateY(-3%); }
.scene.wx-overcast .grade-warm{ opacity:.08; }
.scene.wx-overcast svg.grass{ filter:brightness(.9) saturate(.82); }
.scene.wx-overcast .wx-cloudbank{ display:block; z-index:2; opacity:.5;
  background:
    radial-gradient(120% 55% at 30% 88%, rgba(150,160,176,.5), rgba(150,160,176,0) 64%),
    radial-gradient(80% 40% at 72% 30%, rgba(238,243,248,.42), rgba(238,243,248,0) 70%),
    linear-gradient(to bottom, rgba(196,204,214,.7) 0%, rgba(210,217,226,.55) 45%, rgba(220,226,234,.3) 75%, rgba(220,226,234,0) 100%);
  animation:driftFar 140s linear infinite alternate; }
.scene.is-night.wx-overcast .far-clouds{ opacity:1; filter:brightness(.32) saturate(.4) blur(1.4px); }
.scene.is-night.wx-overcast .near-clouds{ opacity:1; filter:brightness(.3) saturate(.35); }
.scene.is-night.wx-overcast .wx-cloudbank{ opacity:.55;
  background:
    radial-gradient(120% 55% at 30% 88%, rgba(8,11,28,.55), rgba(8,11,28,0) 64%),
    radial-gradient(80% 40% at 72% 30%, rgba(54,62,104,.4), rgba(54,62,104,0) 70%),
    linear-gradient(to bottom, rgba(18,24,50,.7) 0%, rgba(26,32,62,.55) 45%, rgba(32,38,72,.32) 75%, rgba(32,38,72,0) 100%); }
.scene.is-night.wx-overcast .night .stars{ opacity:.16; }
.scene.is-night.wx-overcast .night .moon{ opacity:.5; }
.scene.is-night.wx-overcast .night .moon-halo{ opacity:.32; }
.scene.is-night.wx-overcast svg.grass{ filter:brightness(.32) saturate(.5); }

/* ---- MIST: low fog + soft haze, dreamy ---- */
.scene.wx-mist .far-clouds{ opacity:.3; }
.scene.wx-mist .sun-disc{ opacity:.72; }
.scene.wx-mist .wx-fog{ display:block; z-index:4;
  background:
    linear-gradient(to top, rgba(244,247,250,.9) 0%, rgba(244,247,250,.55) 22%, rgba(244,247,250,.18) 42%, rgba(244,247,250,0) 60%),
    radial-gradient(120% 50% at 50% 100%, rgba(255,255,255,.5), rgba(255,255,255,0) 70%);
  animation:fogDrift 60s ease-in-out infinite alternate; }
@keyframes fogDrift{ from{ transform:translateX(-4%);} to{ transform:translateX(4%);} }
.scene.is-night.wx-mist .wx-fog{
  background:
    linear-gradient(to top, rgba(40,52,96,.92) 0%, rgba(44,56,104,.6) 22%, rgba(48,60,110,.22) 44%, rgba(48,60,110,0) 62%),
    radial-gradient(120% 50% at 50% 100%, rgba(120,140,210,.4), rgba(120,140,210,0) 72%); }
.scene.is-night.wx-mist .night .moon-halo{ width:320%; height:320%; opacity:.7; }
.scene.is-night.wx-mist .night .stars{ opacity:.5; }

/* ---- RAIN: the real turbulence clouds go grey & full, a wet rain-streak
   overlay falls, ground darkens. Cloudbank is just a faint tonal wash behind
   the real clouds now. ---- */
.scene.wx-rain .atmosphere{ opacity:.2; }
.scene.wx-rain .far-clouds{ opacity:1; filter:brightness(.74) saturate(.5) blur(1.4px); }
.scene.wx-rain .far-clouds svg{ transform:scale(1.22) translateY(-3%); }
.scene.wx-rain .near-clouds{ opacity:1; filter:brightness(.68) saturate(.5); }
.scene.wx-rain .near-clouds svg{ transform:scale(1.16) translateY(-2%); }
.scene.wx-rain .grade-warm{ opacity:.05; }
.scene.wx-rain svg.grass{ filter:brightness(.85) saturate(.85); }
.scene.wx-rain .wx-cloudbank{ display:block; z-index:2; opacity:.55;
  background:linear-gradient(to bottom, rgba(150,160,176,.7) 0%, rgba(172,182,196,.55) 50%, rgba(186,196,208,.26) 80%, rgba(186,196,208,0) 100%);
  animation:driftFar 120s linear infinite alternate; }
/* falling rain, a feTurbulence STREAK tile (the same natural-noise idea as the
   clouds, not a uniform hatch): turbulence stretched tall+thin into rain
   streaks, baked into a tiled data: SVG image (CSP allows img-src data:), then
   "fallen" with a GPU-cheap transform (skew for the slant + translateY), NOT
   background-position (which would repaint every frame). The layer is
   overscanned 280px top+bottom so the fall never reveals a gap; one tile
   (240px) of translate loops seamlessly. Light + sparse by default; storm
   drives it harder. ---- */
.scene.wx-rain .wx-rain, .scene.wx-storm .wx-rain{ display:block; z-index:4; pointer-events:none;
  top:-280px; height:calc(100% + 560px);
  background-repeat:repeat; background-size:240px 240px; will-change:transform;
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='r'><feTurbulence type='fractalNoise' baseFrequency='0.34 0.011' numOctaves='2' seed='5' stitchTiles='stitch' result='n'/><feColorMatrix in='n' type='matrix' values='0 0 0 0 0.9  0 0 0 0 0.94  0 0 0 0 1  0 0 0 0.72 -0.34'/></filter><rect width='240' height='240' filter='url(%23r)'/></svg>");
  animation:rainfall .95s linear infinite; }
@keyframes rainfall{ from{ transform:skewX(-9deg) translateY(0);} to{ transform:skewX(-9deg) translateY(240px);} }
.scene.wx-rain .wx-rain{ opacity:.45; }
.scene.is-night.wx-rain .far-clouds{ opacity:1; filter:brightness(.34) saturate(.5) blur(1.4px); }
.scene.is-night.wx-rain .near-clouds{ opacity:1; filter:brightness(.3) saturate(.5); }
.scene.is-night.wx-rain .wx-cloudbank{ opacity:.5;
  background:linear-gradient(to bottom, rgba(14,18,40,.7) 0%, rgba(22,28,56,.55) 50%, rgba(28,34,64,.3) 80%, rgba(28,34,64,0) 100%); }
.scene.is-night.wx-rain .wx-rain{ opacity:.36; }
.scene.is-night.wx-rain .night .stars{ opacity:.08; }
.scene.is-night.wx-rain .night .moon{ opacity:.3; }
.scene.is-night.wx-rain .night .moon-halo{ opacity:.2; }
.scene.is-night.wx-rain svg.grass{ filter:brightness(.3) saturate(.5); }

/* ---- RAIN INTENSITY (optional): wx-i1 light · wx-i2 medium · wx-i3 heavy.
   Only deepens the rain sky a touch, the falling drops themselves are the
   canvas's job. Subtle so a missing intensity class still reads as rain. ---- */
.scene.wx-rain.wx-i1 .atmosphere{ opacity:.26; }
.scene.wx-rain.wx-i2 .near-clouds{ filter:brightness(.6) saturate(.46); }
.scene.wx-rain.wx-i2 .far-clouds{ filter:brightness(.66) saturate(.46) blur(1.4px); }
.scene.wx-rain.wx-i2 svg.grass{ filter:brightness(.78) saturate(.82); }
.scene.wx-rain.wx-i3 .near-clouds{ filter:brightness(.52) saturate(.42); }
.scene.wx-rain.wx-i3 .far-clouds{ filter:brightness(.58) saturate(.42) blur(1.4px); }
.scene.wx-rain.wx-i3 svg.grass{ filter:brightness(.72) saturate(.8); }
.scene.is-night.wx-rain.wx-i2 .near-clouds{ filter:brightness(.24) saturate(.46); }
.scene.is-night.wx-rain.wx-i2 .far-clouds{ filter:brightness(.27) saturate(.46) blur(1.4px); }
.scene.is-night.wx-rain.wx-i3 .near-clouds{ filter:brightness(.2) saturate(.42); }
.scene.is-night.wx-rain.wx-i3 .far-clouds{ filter:brightness(.22) saturate(.42) blur(1.4px); }

/* ---- STORM: rain's darker, angrier cousin, a low churning cloudbank,
   light crushed out, wet dark ground. (The lightning FLASH is canvas; here
   we only make the sky READ as storm so it's complete without the canvas.)
   Reuses the shared .wx-cloudbank + .wx-rain fx layers. ---- */
.scene.wx-storm .atmosphere{ opacity:.12; }
.scene.wx-storm .far-clouds{ opacity:1; filter:brightness(.42) saturate(.6) blur(1.4px); }
.scene.wx-storm .far-clouds svg{ transform:scale(1.34) translateY(-3%); }
.scene.wx-storm .near-clouds{ opacity:1; filter:brightness(.35) saturate(.55); animation-duration:44s; }
.scene.wx-storm .near-clouds svg{ transform:scale(1.28) translateY(-2%); }
.scene.wx-storm .grade-warm{ opacity:.03; }
.scene.wx-storm .grade-vignette{
  background:radial-gradient(135% 120% at 80% 16%,rgba(40,46,58,0) 0%,rgba(40,46,58,0) 42%,rgba(28,33,44,.6) 80%,rgba(16,20,28,.9) 100%); }
.scene.wx-storm svg.grass{ filter:brightness(.6) saturate(.7); }
.scene.wx-storm .wx-cloudbank{ display:block; z-index:2; opacity:.6;
  background:linear-gradient(to bottom, rgba(74,82,96,.7) 0%, rgba(92,101,116,.55) 38%, rgba(116,126,142,.3) 72%, rgba(116,126,142,0) 100%);
  animation:driftFar 90s linear infinite alternate; }
.scene.wx-storm .wx-rain{ opacity:.62; animation-duration:.6s; }
.scene.is-night.wx-storm .sky{
  background:
    radial-gradient(120% 95% at 84% 12%, rgba(120,140,210,.10) 0%, rgba(120,140,210,0) 46%),
    linear-gradient(to bottom,#03040C 0%,#05071A 30%,#090C24 58%,#0E1230 80%,#13183C 100%); }
.scene.is-night.wx-storm .far-clouds{ opacity:1; filter:brightness(.16) saturate(.5) blur(1.4px); }
.scene.is-night.wx-storm .near-clouds{ opacity:1; filter:brightness(.14) saturate(.5); }
.scene.is-night.wx-storm .wx-cloudbank{ opacity:.6;
  background:linear-gradient(to bottom, rgba(6,8,18,.7) 0%, rgba(12,15,32,.55) 38%, rgba(18,22,44,.3) 72%, rgba(18,22,44,0) 100%); }
.scene.is-night.wx-storm .wx-rain{ opacity:.5; animation-duration:.6s; }
.scene.is-night.wx-storm .night .stars{ opacity:.04; }
.scene.is-night.wx-storm .night .moon{ opacity:.22; }
.scene.is-night.wx-storm .night .moon-halo{ opacity:.14; }
.scene.is-night.wx-storm svg.grass{ filter:brightness(.24) saturate(.45); }

/* ---- SNOW: a soft, flat, hushed sky. DAY = cold white-grey overcast lid;
   NIGHT = muted grey-blue. (The falling flakes are canvas; the sky is ours,
   and stays complete without it.) Reuses the .wx-cloudbank lid. ---- */
.scene.wx-snow .atmosphere{ opacity:.16; }
.scene.wx-snow .sky{
  background:
    radial-gradient(120% 90% at 86% 10%, rgba(255,255,255,.4) 0%, rgba(255,255,255,0) 44%),
    linear-gradient(to bottom,#C3CCD6 0%,#CDD6DE 30%,#D8DFE6 58%,#E2E8ED 80%,#EAEEF1 100%); }
.scene.wx-snow .far-clouds{ opacity:.7; filter:brightness(1.04) saturate(.7); }
.scene.wx-snow .near-clouds{ opacity:.85; filter:brightness(1.02) saturate(.72); animation-duration:120s; }
.scene.wx-snow .grade-warm{ opacity:.04; }
.scene.wx-snow .grade-vignette{
  background:radial-gradient(135% 120% at 80% 16%,rgba(255,255,255,0) 0%,rgba(255,255,255,0) 58%,rgba(176,186,198,.42) 84%,rgba(150,162,178,.62) 100%); }
.scene.wx-snow svg.grass{ filter:brightness(1.42) saturate(.22) hue-rotate(150deg) contrast(.86); }
.scene.wx-snow .wx-cloudbank{ display:block; z-index:3; opacity:.94;
  background:linear-gradient(to bottom, rgba(226,232,238,.96) 0%, rgba(232,237,242,.78) 48%, rgba(236,240,244,.34) 78%, rgba(236,240,244,0) 100%);
  animation:driftFar 150s linear infinite alternate; }
.scene.is-night.wx-snow .sky{
  background:
    radial-gradient(120% 95% at 84% 12%, rgba(150,170,210,.16) 0%, rgba(150,170,210,0) 46%),
    linear-gradient(to bottom,#1A2238 0%,#222C46 30%,#2B3654 58%,#33405F 80%,#3C4A6B 100%); }
.scene.is-night.wx-snow .wx-cloudbank{ opacity:.7;
  background:linear-gradient(to bottom, rgba(54,66,96,.9) 0%, rgba(64,77,108,.72) 48%, rgba(72,86,118,.34) 78%, rgba(72,86,118,0) 100%); }
.scene.is-night.wx-snow .night .stars{ opacity:.1; }
.scene.is-night.wx-snow .night .moon{ opacity:.55; }
.scene.is-night.wx-snow .night .moon-halo{ opacity:.4; }
.scene.is-night.wx-snow svg.grass{ filter:brightness(.66) saturate(.28) hue-rotate(168deg) contrast(.82); }

/* ---- FX CANVAS LAYERS (heavy mode only; absent on low-end / reduced-motion,
   in which case the CSS scene + moods above carry the whole look). Both are
   full-bleed and never shift layout. fx-field (wind streaks / snow particles)
   sits BELOW the rocket-load (z-index:3) but above the scene (z-index:0).
   fx-glass (rain on the viewer's own glass) sits ABOVE everything in .boot. ---- */
/* width/height:100% are REQUIRED, a <canvas> is a replaced element, so
   inset:0 alone leaves it at its intrinsic 300x150; the explicit size makes
   it truly full-bleed (the module then matches its drawing buffer to this). */
.boot canvas.fx-field{ position:absolute; inset:0; width:100%; height:100%; z-index:2; pointer-events:none; }
.boot canvas.fx-glass{ position:absolute; inset:0; width:100%; height:100%; z-index:6; pointer-events:none; }

/* ============================================================
   TERRAIN LIFE, drifting cloud shadows, a distant treeline, swaying
   foreground grass + wildflowers, and day birds / night fireflies.
   All GPU-cheap: tiled data: SVGs (CSP img-src data:), gradients, and
   transform/opacity animation only, no blur, no per-frame repaint.
   Themed to match the hills (night darken, snow frost) and gated by
   mood (sun-shadows only under open sky; birds by day, fireflies by
   night). Sits above the hills, below the rocket + rain-on-glass. ==== */
.scene .terra{ position:absolute; inset:0; pointer-events:none; }
.scene .terra > *{ position:absolute; }

/* drifting cloud shadows, soft dapples sliding over the hills (open sky only) */
.scene .terra .cshadow{ left:-30%; right:-30%; bottom:0; height:44%; z-index:4; mix-blend-mode:multiply; opacity:.45;
  background:radial-gradient(34% 58% at 18% 38%, rgba(28,46,28,.5), rgba(28,46,28,0) 70%), radial-gradient(28% 50% at 52% 58%, rgba(28,46,28,.42), rgba(28,46,28,0) 72%), radial-gradient(40% 62% at 84% 44%, rgba(28,46,28,.46), rgba(28,46,28,0) 70%);
  background-repeat:no-repeat; animation:cshadow 40s linear infinite alternate; }
@keyframes cshadow{ from{ transform:translateX(-9%);} to{ transform:translateX(9%);} }

/* distant treeline along the horizon ridge (tiled silhouette, slightly hazy) */
.scene .terra .treeline{ left:-4%; right:-4%; top:57%; height:11%; z-index:4; opacity:.92;
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='440' height='90'><g fill='%23476b34'><ellipse cx='40' cy='86' rx='34' ry='26'/><ellipse cx='82' cy='88' rx='24' ry='18'/><path d='M120,88 l15,-42 l15,42 Z'/><ellipse cx='178' cy='86' rx='30' ry='22'/><ellipse cx='222' cy='88' rx='20' ry='15'/><path d='M270,88 l13,-36 l13,36 Z'/><ellipse cx='330' cy='85' rx='38' ry='27'/><ellipse cx='384' cy='87' rx='26' ry='19'/><ellipse cx='420' cy='88' rx='18' ry='13'/></g></svg>");
  background-repeat:repeat-x; background-position:bottom; background-size:auto 100%; }

/* swaying foreground grass blades + a few wildflower specks */
.scene .terra .fg-grass{ left:-6%; right:-6%; bottom:0; height:15%; z-index:6; transform-origin:50% 100%;
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='300' height='140'><g fill='%231d3a16'><path d='M8,140 C6,96 12,74 9,44 C15,78 18,104 15,140Z'/><path d='M30,140 C30,104 26,80 31,52 C34,84 36,110 37,140Z'/><path d='M54,140 C50,98 58,72 52,40 C60,76 64,104 60,140Z'/><path d='M80,140 C82,108 76,84 82,58 C86,92 88,114 87,140Z'/><path d='M106,140 C102,100 110,72 104,42 C112,80 116,108 112,140Z'/><path d='M132,140 C134,106 128,82 134,54 C138,88 140,112 139,140Z'/><path d='M158,140 C154,98 162,72 156,40 C164,78 168,106 164,140Z'/><path d='M184,140 C186,108 180,84 186,56 C190,90 192,114 191,140Z'/><path d='M210,140 C206,100 214,74 208,44 C216,80 220,108 216,140Z'/><path d='M238,140 C240,106 234,82 240,52 C244,86 246,112 245,140Z'/><path d='M266,140 C262,98 270,72 264,42 C272,78 276,106 272,140Z'/><path d='M292,140 C288,104 296,80 290,54 C298,86 300,112 298,140Z'/></g><circle cx='46' cy='112' r='3.4' fill='%23f4d23a'/><circle cx='150' cy='120' r='3' fill='%23ef6f9c'/><circle cx='236' cy='108' r='3' fill='%23ffffff'/></svg>");
  background-repeat:repeat-x; background-position:bottom; background-size:auto 100%; animation:gsway 5s ease-in-out infinite; }
@keyframes gsway{ 0%,100%{ transform:skewX(-1.6deg);} 50%{ transform:skewX(1.6deg);} }
.scene.wx-windy .terra .fg-grass, .scene.wx-storm .terra .fg-grass{ animation-name:gswaywind; animation-duration:1.7s; }
@keyframes gswaywind{ 0%,100%{ transform:skewX(-5deg);} 50%{ transform:skewX(4deg);} }

/* critters, 3 day birds drifting high / 6 night fireflies glinting over the hills */
.scene .terra .critters i{ display:none; }
.scene.is-day .terra .critters i:nth-child(-n+3){ display:block; width:22px; height:10px; top:16%; left:-6%; opacity:.55;
  background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='22' height='10'><path d='M1,8 Q6,1 11,6 Q16,1 21,8' stroke='%233a4150' stroke-width='1.6' fill='none' stroke-linecap='round'/></svg>") center/contain no-repeat;
  animation:birdfly 30s linear infinite; }
.scene.is-day .terra .critters i:nth-child(2){ top:20%; transform:scale(.78); animation-delay:-11s; }
.scene.is-day .terra .critters i:nth-child(3){ top:12%; transform:scale(1.12); animation-delay:-21s; }
@keyframes birdfly{ from{ transform:translateX(0);} to{ transform:translateX(120vw);} }
.scene.is-night .terra .critters i{ display:block; width:4px; height:4px; border-radius:50%;
  background:radial-gradient(circle, rgba(255,244,170,.95), rgba(255,224,120,0) 70%);
  box-shadow:0 0 6px 2px rgba(255,236,150,.45); animation:firefly 7s ease-in-out infinite; }
.scene.is-night .terra .critters i:nth-child(1){ left:18%; bottom:23%; animation-delay:0s; }
.scene.is-night .terra .critters i:nth-child(2){ left:33%; bottom:16%; animation-delay:-1.4s; }
.scene.is-night .terra .critters i:nth-child(3){ left:50%; bottom:25%; animation-delay:-2.8s; }
.scene.is-night .terra .critters i:nth-child(4){ left:66%; bottom:18%; animation-delay:-4.2s; }
.scene.is-night .terra .critters i:nth-child(5){ left:80%; bottom:27%; animation-delay:-5.6s; }
.scene.is-night .terra .critters i:nth-child(6){ left:43%; bottom:20%; animation-delay:-3.5s; }
@keyframes firefly{ 0%,100%{ opacity:0; transform:translate(0,0);} 30%{ opacity:1;} 50%{ transform:translate(9px,-7px);} 70%{ opacity:.55;} }

/* THEME + MOOD treatment of the terrain life (mirror the hills) */
.scene.is-night .terra .treeline, .scene.is-night .terra .fg-grass{ filter:brightness(.4) saturate(.6); }
.scene.wx-snow .terra .treeline, .scene.wx-snow .terra .fg-grass{ filter:brightness(1.4) saturate(.25) hue-rotate(150deg); }
.scene.is-night.wx-snow .terra .treeline, .scene.is-night.wx-snow .terra .fg-grass{ filter:brightness(.66) saturate(.3) hue-rotate(165deg); }
.scene.wx-rain .terra .fg-grass, .scene.wx-storm .terra .fg-grass{ filter:brightness(.8) saturate(.85); }
.scene.is-night.wx-rain .terra .fg-grass, .scene.is-night.wx-storm .terra .fg-grass{ filter:brightness(.34) saturate(.5); }
.scene.wx-overcast .terra .treeline, .scene.wx-rain .terra .treeline, .scene.wx-storm .terra .treeline{ filter:brightness(.78) saturate(.7); }
/* cloud shadows need sun, hide them under a covered sky or at night */
.scene.wx-overcast .terra .cshadow, .scene.wx-rain .terra .cshadow, .scene.wx-storm .terra .cshadow,
.scene.wx-snow .terra .cshadow, .scene.wx-mist .terra .cshadow, .scene.is-night .terra .cshadow{ display:none; }
/* no critters in heavy/closed weather (keeps them to clear/cloudy/mist) */
.scene.wx-overcast .terra .critters, .scene.wx-rain .terra .critters,
.scene.wx-storm .terra .critters, .scene.wx-snow .terra .critters{ display:none; }

/* ---------- LAYOUT ---------- */
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }
.view { padding: 30px 0 64px; }
.row { display: flex; gap: 14px; align-items: center; }
.row.wrap { flex-wrap: wrap; }
.row.top { align-items: flex-start; }
.stack { display: flex; flex-direction: column; gap: 14px; }
.spacer { flex: 1; }
/* quiet, clearly-secondary prev/next strip on the problem page, sits below
   the result, never competes with the primary Run/Hint actions */
.probnav { display: flex; justify-content: space-between; align-items: center;
  gap: 14px; margin-top: 28px; padding-top: 16px; border-top: 1px solid var(--line); }

/* ---------- APP BAR (enterprise nav) ---------- */
.appbar {
  position: sticky; top: 0; z-index: 50; height: var(--appbar-h);
  background: var(--surface); border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: 8px; padding: 0 24px;
}
.brand { display: flex; align-items: center; gap: 10px; font-family: var(--display); font-weight: 700; font-size: 19px; letter-spacing: -.01em; }
.brand-mark {
  width: 30px; height: 30px; border-radius: 8px; flex-shrink: 0;
  background: linear-gradient(135deg, var(--primary), var(--primary-2));
  color: #fff; display: grid; place-items: center; font-weight: 700; font-size: 16px;
}
.nav { display: flex; gap: 2px; margin-left: 18px; }
.nav-item {
  position: relative;
  display: flex; align-items: center; gap: 7px;
  padding: 8px 14px; border-radius: var(--r-sm); font-weight: 600; font-size: 14px;
  color: var(--ink-soft); transition: background .14s, color .14s, transform .16s var(--ease);
}
.nav-item:hover { background: var(--surface-2); color: var(--ink); transform: translateY(-1px); }
.nav-item.active { background: var(--primary-soft); color: var(--primary-deep); transform: translateY(-1px); }
/* a small rising indicator under the current page, "you are here, climbing" */
.nav-item.active::after {
  content: ""; position: absolute; left: 50%; bottom: 3px; transform: translateX(-50%);
  width: 18px; height: 2px; border-radius: 2px; background: var(--primary);
}
.nav-item .ic { font-size: 15px; }
@media (prefers-reduced-motion: reduce){ .nav-item:hover, .nav-item.active { transform: none; } }
.appbar-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
/* the brand and the status cluster keep their natural size, they never get
   flex-compressed (which previously squeezed the XP pill into "4…"). The
   flexible space lives in .spacer; the nav gives way via the breakpoints above. */
.brand, .appbar-right > * { flex-shrink: 0; }
.pill-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 11px; border-radius: 999px; font-size: 13px; font-weight: 700;
  background: var(--surface-2); border: 1px solid var(--line); color: var(--ink-soft);
}
.pill-chip.streak { color: var(--warn); background: var(--warn-soft); border-color: transparent; }
.pill-chip.xp     { color: var(--primary-deep); background: var(--primary-soft); border-color: transparent; max-width: 168px; min-width: 0; }
/* the LEVEL is the headline (never clipped); the raw Skill-Score number is detail
   that truncates with an ellipsis when the bar is tight. */
.pill-chip.xp .xp-num { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pill-chip.xp .xp-lv  { flex: 0 0 auto; white-space: nowrap; }
.pill-chip.xp .xp-lv::before { content: "·"; margin: 0 5px 0 -1px; color: var(--primary); opacity: .55; }
.ai-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ink-faint); }
.ai-dot.on { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-soft); }

/* ---------- BREADCRUMBS ---------- */
.crumbs { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--ink-faint); font-weight: 600; margin-bottom: 16px; flex-wrap: wrap; }
.crumbs a:hover { color: var(--primary); }
.crumbs .sep { opacity: .6; }
.crumbs .here { color: var(--ink-soft); }

/* ---------- HEADINGS ---------- */
.page-title { font-family: var(--display); font-size: clamp(23px,3vw,30px); font-weight: 700; letter-spacing: -.02em; }
.page-sub { color: var(--ink-soft); font-size: 14.5px; margin-top: 3px; }
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 22px; }
.section-title { font-family: var(--display); font-size: clamp(20px,2.4vw,26px); font-weight: 700; letter-spacing: -.015em; }
.section-sub { color: var(--ink-soft); font-size: 14.5px; margin-top: 3px; margin-bottom: 18px; }

/* ---------- BUTTONS ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 18px; border-radius: var(--r-sm);
  font-weight: 700; font-size: 14px; border: 1px solid transparent; cursor: pointer;
  transition: transform .12s var(--ease), box-shadow .16s, background .16s, border-color .16s;
  white-space: nowrap;
}
.btn:active { transform: scale(.97); }
.btn-primary { background: var(--primary); color: #fff; box-shadow: 0 6px 16px -6px rgba(79,70,229,.55); }
.btn-primary:hover { background: var(--primary-deep); }
.btn-ok { background: var(--ok); color: #fff; }
.btn-ok:hover { filter: brightness(.95); }
.btn-soft { background: var(--primary-soft); color: var(--primary-deep); }
.btn-soft:hover { background: #E0E0FD; }
.btn-ghost { background: var(--surface); color: var(--ink); border-color: var(--line-2); }
.btn-ghost:hover { border-color: var(--primary); color: var(--primary-deep); }
.btn-lg { padding: 14px 26px; font-size: 15.5px; border-radius: var(--r-md); }
.btn-sm { padding: 7px 12px; font-size: 13px; }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

/* ---------- CARDS ---------- */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 22px; box-shadow: var(--shadow-sm); }
.card-hover { transition: transform .16s var(--ease), box-shadow .18s, border-color .16s; cursor: pointer; }
.card-hover:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: var(--line-2); }

/* ---------- HERO ---------- */
.hero { padding: 56px 0 30px; }
.hero-grid { display: grid; grid-template-columns: 1.15fr .85fr; gap: 40px; align-items: center; }
.hero-eyebrow {
  display: inline-flex; align-items: center; gap: 8px; margin-bottom: 18px;
  padding: 6px 13px; border-radius: 999px; background: var(--primary-soft);
  color: var(--primary-deep); font-size: 13px; font-weight: 700;
}
.hero h1 { font-family: var(--display); font-size: clamp(32px,4.6vw,52px); line-height: 1.08; letter-spacing: -.025em; font-weight: 700; }
.hero h1 .grad { background: linear-gradient(100deg, var(--primary), var(--accent)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.hero-lead { font-size: clamp(15px,1.6vw,18px); color: var(--ink-soft); margin: 16px 0 26px; max-width: 540px; }
.hero-art {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg); padding: 20px; overflow: hidden;
}

/* ---------- STAT GRID ---------- */
.statgrid { display: grid; grid-template-columns: repeat(4,1fr); gap: 12px; }
.stat { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); padding: 16px 18px; }
.stat-num { font-family: var(--display); font-size: 26px; font-weight: 700; color: var(--primary-deep); letter-spacing: -.01em; }
.stat-label { font-size: 12px; font-weight: 600; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .05em; margin-top: 1px; }

/* ---------- FEATURE GRID ---------- */
.feature-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; }
.feature { display: flex; flex-direction: column; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); padding: 20px; }
.feature-ic { width: 40px; height: 40px; border-radius: 10px; background: var(--primary-soft); color: var(--primary-deep); display: grid; place-items: center; font-size: 19px; }
.feature-t { font-weight: 700; font-size: 15.5px; margin: 13px 0 5px; }
.feature-d { color: var(--ink-soft); font-size: 13.5px; }

/* ---------- JOURNEY MAP ---------- */
.stage { margin-bottom: 30px; }
.stage-head { display: flex; align-items: center; gap: 13px; margin-bottom: 6px; }
.stage-badge { width: 42px; height: 42px; border-radius: 11px; display: grid; place-items: center; font-family: var(--display); font-weight: 700; font-size: 18px; color: #fff; flex-shrink: 0; }
.stage-badge.a { background: linear-gradient(135deg,#0EA5E9,#4F46E5); }
.stage-badge.b { background: linear-gradient(135deg,#4F46E5,#7C3AED); }
.stage-badge.c { background: linear-gradient(135deg,#7C3AED,#DB2777); }
.stage-head h3 { font-family: var(--display); font-size: 19px; font-weight: 700; letter-spacing: -.01em; }
.stage-head .meta { font-size: 12.5px; color: var(--ink-faint); font-weight: 600; }
.stage-line { color: var(--ink-soft); font-size: 14px; margin: 4px 0 14px; }

.block-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; }
.block { display: flex; flex-direction: column; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); padding: 17px; box-shadow: var(--shadow-sm); transition: transform .15s var(--ease), box-shadow .16s, border-color .15s; cursor: pointer; }
.block:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: var(--primary); }
.block-tag { font-size: 11px; font-weight: 700; color: var(--primary); letter-spacing: .06em; }
.block-name { font-weight: 700; font-size: 15.5px; margin: 5px 0 4px; line-height: 1.3; overflow-wrap: anywhere; }
.block-meta { font-size: 12.5px; color: var(--ink-faint); margin-bottom: 12px; }
.progress { height: 7px; background: var(--surface-3); border-radius: 999px; overflow: hidden; margin-top: auto; }
.progress > i { display: block; height: 100%; background: linear-gradient(90deg,var(--primary),var(--accent)); border-radius: 999px; transition: width .5s var(--ease); }

/* ---------- RUNGS ---------- */
.rungs { display: grid; grid-template-columns: repeat(4,1fr); gap: 8px; margin: 14px 0; }
.rung { text-align: center; padding: 12px 6px; border-radius: var(--r-sm); background: var(--surface); border: 1px solid var(--line); }
.rung .ri { font-size: 20px; }
.rung .rn { font-size: 11px; font-weight: 700; color: var(--ink-soft); margin-top: 3px; }

/* ---------- PROBLEM LIST ---------- */
.plist { display: flex; flex-direction: column; gap: 8px; }
.pitem {
  display: flex; align-items: center; gap: 14px; padding: 13px 16px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
  cursor: pointer; transition: border-color .14s, transform .14s var(--ease), box-shadow .14s;
}
.pitem:hover { border-color: var(--primary); transform: translateX(3px); box-shadow: var(--shadow-sm); }
.pitem-no { width: 36px; height: 36px; flex-shrink: 0; border-radius: 9px; background: var(--surface-3); color: var(--ink-soft); display: grid; place-items: center; font-weight: 700; font-size: 13px; }
.pitem.done .pitem-no { background: var(--ok); color: #fff; }
.pitem-body { flex: 1; min-width: 0; }
.pitem-title { font-weight: 600; font-size: 14.5px; overflow-wrap: anywhere; }
.pitem-tags { display: flex; gap: 6px; margin-top: 5px; flex-wrap: wrap; }
.pitem-go { color: var(--ink-faint); font-size: 18px; }

/* ---------- TAGS & BADGES ---------- */
.tag { display: inline-flex; align-items: center; gap: 4px; padding: 3px 9px; border-radius: 6px; font-size: 11px; font-weight: 700; white-space: nowrap; }
.tag.exam  { background: var(--accent-soft); color: #0B6F95; }
.tag.ai    { background: #F3E8FF; color: #7C3AED; }
.tag.rung  { background: var(--surface-3); color: var(--ink-soft); }
.tag.score { background: var(--warn-soft); color: var(--warn); }
.tag.diff  { background: var(--surface-3); color: var(--ink-soft); }
.badge { display: inline-flex; align-items: center; gap: 5px; padding: 4px 11px; border-radius: 999px; font-size: 11.5px; font-weight: 700; }
.badge.pass { background: var(--ok-soft); color: var(--ok); }
.badge.fail { background: var(--err-soft); color: var(--err); }
.badge.warn { background: var(--warn-soft); color: var(--warn); }
.badge.info { background: var(--info-soft); color: var(--info); }
.badge.neutral { background: var(--surface-3); color: var(--ink-soft); }

/* ---------- TABS ---------- */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin-bottom: 18px; flex-wrap: wrap; }
.tab { padding: 10px 16px; font-weight: 700; font-size: 13.5px; cursor: pointer; color: var(--ink-faint); background: none; border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px; transition: color .14s, border-color .14s; }
.tab:hover { color: var(--ink-soft); }
.tab.active { color: var(--primary-deep); border-bottom-color: var(--primary); }

/* ---------- CODE / EDITOR ---------- */
.editor {
  width: 100%; min-height: 230px; resize: vertical;
  background: #FBFCFE; border: 1px solid var(--line-2); border-radius: var(--r-md);
  font-family: var(--mono); font-size: 13.5px; line-height: 1.7; color: #1E2230; padding: 15px;
  tab-size: 4;
}
.editor:focus { outline: none; border-color: var(--primary); box-shadow: var(--ring); }

/* ---------- MONACO · the VS Code-grade code editor ---------- */
.monaco-host {
  width: 100%; height: 440px;
  border: 1px solid var(--line-2); border-radius: var(--r-md);
  overflow: hidden; background: #1E1E1E; box-shadow: var(--shadow-sm);
}
.monaco-host-sm { height: 260px; }
.monaco-host:focus-within { border-color: var(--primary); box-shadow: var(--ring); }
.monaco-host .monaco-editor,
.monaco-host .monaco-editor .overflow-guard { border-radius: var(--r-md); }
pre.code { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-md); padding: 14px 16px; overflow-x: auto; font-family: var(--mono); font-size: 13px; line-height: 1.65; color: var(--ink); margin: 12px 0; }
code.inline { background: var(--surface-3); padding: 1px 6px; border-radius: 5px; font-family: var(--mono); font-size: .88em; color: var(--primary-deep); }

/* ---------- RESULT PANEL ---------- */
.result { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); box-shadow: var(--shadow-sm); overflow: hidden; }
.metrics { display: flex; gap: 10px; flex-wrap: wrap; padding: 16px; border-bottom: 1px solid var(--line); background: var(--surface-2); }
.metric { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 10px 14px; min-width: 92px; }
.metric .mv { font-family: var(--display); font-size: 19px; font-weight: 700; }
.metric .ml { font-size: 10.5px; font-weight: 700; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .05em; margin-top: 1px; }
.metric.ok .mv { color: var(--ok); } .metric.bad .mv { color: var(--err); } .metric.brand .mv { color: var(--primary-deep); }
/* dark mode: the tile bg (--surface) is darker than the --surface-2 pane, so the
   verdict tiles read as dark holes and the --ink-faint labels / --primary-deep
   score vanish. Lift the tile above the pane, strengthen the label + score. */
[data-theme="dark"] .metric { background: var(--surface-3); border-color: var(--line-2); }
[data-theme="dark"] .metric .ml { color: var(--ink-soft); }
[data-theme="dark"] .metric.brand .mv { color: var(--primary); }
.result-tabs { display: flex; gap: 2px; padding: 8px 12px 0; border-bottom: 1px solid var(--line); }
.tcase { display: flex; align-items: center; gap: 12px; padding: 11px 16px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.tcase:last-child { border-bottom: 0; }
.tcase-name { font-weight: 700; font-size: 13px; min-width: 80px; }
.tcase-vis { font-size: 12px; color: var(--ink-faint); }
.tcase-detail { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 11px 13px; margin: 0 16px 12px; font-family: var(--mono); font-size: 12.5px; white-space: pre-wrap; color: var(--ink); overflow-x: auto; }
.coach-box { padding: 16px; }
.coach-head { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; }
.coach-avatar { width: 32px; height: 32px; border-radius: 9px; background: linear-gradient(135deg,var(--primary),var(--primary-2)); color: #fff; display: grid; place-items: center; font-size: 16px; }
.coach-body { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-md); padding: 14px 16px; font-size: 14px; }
.coach-body strong { color: var(--ink); }
.coach-body p { margin: 8px 0; color: var(--ink-soft); }
.coach-body p:first-child { margin-top: 0; }
.coach-tag { font-size: 11px; font-weight: 700; color: var(--ink-faint); }

/* analysis bars */
.abar { display: flex; align-items: center; gap: 12px; margin: 9px 0; }
.abar .al { font-size: 13px; font-weight: 600; min-width: 150px; color: var(--ink-soft); }
.abar .at { flex: 1; height: 9px; background: var(--surface-3); border-radius: 999px; overflow: hidden; }
.abar .at > i { display: block; height: 100%; background: linear-gradient(90deg,var(--primary),var(--accent)); border-radius: 999px; }
.abar .av { font-size: 12.5px; font-weight: 700; min-width: 54px; text-align: right; }

/* ---------- ANALYSIS / CHARTS ---------- */
.dash-grid { display: grid; grid-template-columns: repeat(2,1fr); gap: 24px; }
/* defensive: any two stacked chart-cards outside a grid still get breathing room */
.chart-card + .chart-card { margin-top: 24px; }
/* min-width:0 lets a card shrink below the intrinsic width of its SVG chart
   (grid/flex items default to min-width:auto), so charts scale on narrow screens
   instead of forcing horizontal overflow. */
.chart-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 26px 28px; box-shadow: var(--shadow-sm); min-width: 0; }
.chart-card.full { grid-column: 1 / -1; }
.chart-title { font-family: var(--display); font-weight: 700; font-size: 16px; margin-bottom: 6px; }
.chart-sub { font-size: 13px; color: var(--ink-faint); margin-bottom: 18px; }
.chart { min-width: 0; }
.chart svg { display: block; width: 100%; height: auto; overflow: visible; }
.legend { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 12px; font-size: 12.5px; color: var(--ink-soft); }
.legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; }
.sw-list { display: flex; flex-direction: column; gap: 8px; }
.sw-row { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: var(--r-sm); background: var(--surface-2); border: 1px solid var(--line); }
.sw-row .swi { width: 26px; height: 26px; border-radius: 7px; display: grid; place-items: center; font-size: 14px; flex-shrink: 0; }
.sw-row.good .swi { background: var(--ok-soft); } .sw-row.bad .swi { background: var(--err-soft); }
.sw-row .swt { font-weight: 600; font-size: 14px; flex: 1; min-width: 0; overflow-wrap: anywhere; }

/* ---------- FORMS ---------- */
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-size: 12px; font-weight: 700; color: var(--ink-soft); letter-spacing: .02em; }
.input, .select, .textarea {
  width: 100%; background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--r-sm);
  color: var(--ink); font-family: var(--font); font-size: 14px; padding: 10px 12px;
}
.textarea { font-family: var(--mono); font-size: 13px; resize: vertical; }
.input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--primary); box-shadow: var(--ring); }
/* interface-language picker (Profile → Language), a plain, accessible native
   select; capped width so it doesn't stretch edge-to-edge on desktop. */
.lang-select { width: 100%; max-width: 360px; margin-top: 4px; background: var(--surface);
  border: 1px solid var(--line-2); border-radius: var(--r-sm); color: var(--ink);
  font-family: var(--font); font-size: 14px; font-weight: 600; padding: 10px 12px; cursor: pointer; }
.lang-select:focus { outline: none; border-color: var(--primary); box-shadow: var(--ring); }
/* transient "translating…" badge shown only while first-time strings are fetched */
#tr-indicator { position: fixed; left: 16px; bottom: 16px; z-index: 1400; display: none;
  align-items: center; gap: 8px; padding: 8px 14px; border-radius: 999px;
  background: var(--primary-deep, #2D2A78); color: #fff; font-size: 13px; font-weight: 600;
  box-shadow: 0 8px 24px -8px rgba(15,16,32,.5); pointer-events: none; }
#tr-indicator .tr-spin { width: 13px; height: 13px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,.35); border-top-color: #fff; animation: tr-spin .7s linear infinite; }
@keyframes tr-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { #tr-indicator .tr-spin { animation: none; } }
@media (max-width: 680px) { #tr-indicator { bottom: calc(70px + env(safe-area-inset-bottom)); } }

/* ---------- TABLES ---------- */
.table-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-sm); overflow: hidden; }
.table-bar { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--line); flex-wrap: wrap; background: var(--surface-2); }
.table-scroll { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; }
.table th { text-align: left; font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-faint); padding: 12px 16px; border-bottom: 1px solid var(--line); white-space: nowrap; }
.table td { padding: 13px 16px; border-bottom: 1px solid var(--line); font-size: 14px; vertical-align: middle; }
.table tr:last-child td { border-bottom: 0; }
.table tbody tr.click { cursor: pointer; transition: background .12s; }
.table tbody tr.click:hover { background: var(--surface-2); }
.t-main { font-weight: 600; color: var(--ink); }
.t-soft { color: var(--ink-soft); }

/* ---------- AVATAR / CHIPS ---------- */
.avatar { width: 32px; height: 32px; border-radius: 50%; background: linear-gradient(135deg,var(--primary),var(--primary-2)); color: #fff; display: inline-grid; place-items: center; font-weight: 700; font-size: 12px; flex-shrink: 0; vertical-align: middle; }
.avatar.sm { width: 26px; height: 26px; font-size: 11px; }
.chips { display: flex; flex-wrap: wrap; gap: 7px; }
.chip { display: inline-flex; align-items: center; gap: 7px; padding: 5px 10px 5px 6px; border-radius: 999px; background: var(--surface-2); border: 1px solid var(--line); font-size: 12.5px; font-weight: 600; }
.chip button { background: none; border: 0; color: var(--ink-faint); cursor: pointer; font-size: 13px; line-height: 1; padding: 0 2px; }
.chip button:hover { color: var(--err); }

/* ---------- NOTES / CALLOUTS ---------- */
.note { border-radius: var(--r-md); padding: 14px 16px; margin: 14px 0; border: 1px solid var(--line); background: var(--surface-2); font-size: 14px; }
.note .nt { font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: .05em; margin-bottom: 5px; }
.note.tip   { background: var(--ok-soft);   border-color: #C9E9D4; } .note.tip .nt   { color: var(--ok); }
.note.warn  { background: var(--warn-soft); border-color: #EFD9AE; } .note.warn .nt  { color: var(--warn); }
.note.ai    { background: #F3E8FF;          border-color: #E2CDFB; } .note.ai .nt    { color: #7C3AED; }
.note.story { background: var(--primary-soft); border-color: #D9D9FB; } .note.story .nt { color: var(--primary-deep); }
.note.exam  { background: var(--accent-soft); border-color: #C7E8F5; } .note.exam .nt { color: #0B6F95; }
/* W3 frontier nudge: a GENTLE pacing note (you're getting ahead), the calm
   --info indigo tone, deliberately not warn/alarm, so it reads as a kind heads-up
   the learner is free to dismiss. */
.note.frontier-nudge { background: var(--info-soft); border-color: var(--info-soft); border-left: 3px solid var(--info); }
.note.frontier-nudge .nt { color: var(--info); }
.note p { color: var(--ink-soft); margin: 6px 0 0; }

/* ---------- ARTICLE ---------- */
.article { max-width: 760px; }
.article h1 { font-family: var(--display); font-size: clamp(26px,3.6vw,36px); font-weight: 700; letter-spacing: -.02em; line-height: 1.15; }
.article h2 { font-family: var(--display); font-size: 22px; font-weight: 700; margin: 30px 0 10px; letter-spacing: -.01em; }
.article h3 { font-size: 17px; font-weight: 700; margin: 22px 0 7px; }
.article p { color: var(--ink-soft); margin-bottom: 13px; }
.article ul, .article ol { color: var(--ink-soft); margin: 0 0 13px 22px; }
.article li { margin-bottom: 6px; }
.article strong { color: var(--ink); }
.read-time { color: var(--ink-faint); font-weight: 600; font-size: 13px; }

/* ---------- EMPTY STATE ---------- */
.empty { text-align: center; padding: 44px 20px; color: var(--ink-faint); }
.empty .ei { font-size: 32px; margin-bottom: 6px; }

/* ---------- TOAST ---------- */
.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%) translateY(140px);
  background: var(--ink); color: #fff; border-radius: var(--r-md); padding: 12px 20px;
  font-weight: 700; font-size: 14px; z-index: 100; box-shadow: var(--shadow-lg);
  transition: transform .38s var(--ease);
}
.toast.show { transform: translateX(-50%) translateY(0); }

/* ---------- FOOTER ---------- */
.footer { border-top: 1px solid var(--line); background: var(--surface); padding: 26px 0; color: var(--ink-faint); font-size: 13px; }

/* ---------- MOTIVATION BANNER ---------- */
.banner {
  background: linear-gradient(120deg,#4F46E5,#6D5BF2 55%,#0EA5E9); color:#fff;
  border-radius: var(--r-lg); padding: 22px 24px; margin-bottom: 16px;
  display: flex; gap: 22px; align-items: center; flex-wrap: wrap; box-shadow: var(--shadow);
}
.banner-lvl { width: 66px; height: 66px; border-radius: 50%; background: rgba(255,255,255,.16);
  display: grid; place-items: center; font-family: var(--display); font-weight: 700; flex-shrink: 0; }
.banner-lvl .bl-n { font-size: 22px; line-height: 1; } .banner-lvl .bl-l { font-size: 9px; opacity: .85; letter-spacing: .08em; }
.banner-main { flex: 1; min-width: 220px; }
.banner-title { font-family: var(--display); font-weight: 700; font-size: 20px; }
.banner-sub { font-size: 13px; opacity: .92; margin: 2px 0 10px; }
.banner-bar { height: 8px; background: rgba(255,255,255,.22); border-radius: 999px; overflow: hidden; max-width: 360px; }
.banner-bar > i { display: block; height: 100%; background: #fff; border-radius: 999px; }
.banner-msg { font-size: 14px; font-weight: 600; max-width: 280px; opacity: .96; }

/* ---------- MINI-QUEST (a quest within a quest) ---------- */
.miniquest {
  border: 1.5px solid var(--primary); border-left-width: 5px; border-radius: var(--r-md);
  background: linear-gradient(180deg, var(--primary-soft), var(--surface) 70%);
  padding: 16px 18px; margin-top: 14px;
}
.mq-badge { display: inline-block; background: var(--primary); color: #fff;
  font-size: 10.5px; font-weight: 800; letter-spacing: .06em; padding: 4px 10px; border-radius: 6px; }
/* the two ways forward from a fail, practise (mini-quest) + learn (mini-lesson) */
.mq-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
/* MINI-LESSON, the on-the-fly concept lesson, teal/learn-tinted to read as
   "knowledge" (distinct from the primary mini-quest practice card) */
.minilesson { border: 1.5px solid var(--ok, #1FA97A); border-left-width: 5px; border-radius: var(--r-md);
  background: linear-gradient(180deg, var(--ok-soft, #E6F6EF), var(--surface) 72%);
  padding: 16px 18px; margin-top: 12px; }
.ml-badge { display: inline-block; background: var(--ok, #1FA97A); color: #fff;
  font-size: 10.5px; font-weight: 800; letter-spacing: .06em; padding: 4px 10px; border-radius: 6px; }
.ml-title { font-family: var(--display); font-weight: 700; font-size: 16.5px; margin: 10px 0 4px; }
.ml-why { color: var(--ink); font-size: 14px; margin: 4px 0 8px; line-height: 1.55; }
.ml-points { margin: 8px 0 0; padding-left: 20px; color: var(--ink-soft); font-size: 13.5px; line-height: 1.6; }
.ml-points li { margin: 4px 0; }
.ml-tip { font-size: 13px; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 9px 11px; margin-top: 12px; }
.ml-more { margin-top: 12px; }
.mq-title { font-family: var(--display); font-weight: 700; font-size: 16.5px; margin: 9px 0 3px; }
.mq-intro { color: var(--ink-soft); font-size: 13.5px; }
.mq-task { font-size: 14px; margin: 11px 0; }
.mq-why { font-size: 12.5px; color: var(--primary-deep); background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 9px 11px; margin-top: 12px; }

/* ---------- CONFIDENCE CALIBRATION (staged, compact) ---------- */
/* Calibration is a GATE before Run, so it has to read like one. Warm border,
   bolder type, gentle pulse while still required (the .needs-pick state). The
   matching Run-button disabled style sits with .btn:disabled below. */
.calib {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 14px 18px; border-radius: var(--r-md);
  background: var(--accent-soft, #FFF4E5);
  border: 1px solid var(--accent, #F59E0B);
  border-left-width: 4px;
}
.calib.needs-pick { animation: cta-pulse 2.4s ease-in-out infinite; }
.calib-q { font-size: 14px; font-weight: 800; color: var(--ink); letter-spacing: .005em; }
.calib-opt {
  padding: 7px 14px; border-radius: 999px; font-size: 13.5px; font-weight: 700;
  background: var(--surface); border: 1.5px solid var(--line-2); color: var(--ink);
  cursor: pointer; transition: background .14s, border-color .14s, color .14s, transform .14s;
}
.calib-opt:hover { border-color: var(--primary); color: var(--primary-deep); transform: translateY(-1px); }
.calib-opt.on { background: var(--primary-soft); border-color: var(--primary); color: var(--primary-deep); }
.calib-hint { font-size: 13px; font-weight: 600; color: var(--accent-deep, #B45309); margin-left: auto; }

/* When a button is disabled (the Run gate, mainly) it must LOOK disabled,
   otherwise a learner just clicks it and wonders why nothing happens. */
.btn:disabled, .btn[disabled] {
  opacity: .5; cursor: not-allowed; filter: grayscale(.35);
  box-shadow: none; transform: none !important;
}
.btn:disabled:hover, .btn[disabled]:hover { transform: none !important; }

/* ---------- REFLECTION CARD ---------- */
.reflect {
  border: 1px solid #C9E9D4; background: var(--ok-soft);
  border-radius: var(--r-md); padding: 14px 16px; margin-top: 14px;
}
.reflect-q { font-weight: 700; font-size: 14px; color: var(--ink); margin-bottom: 10px; }
.reflect-opts { display: flex; gap: 8px; flex-wrap: wrap; }
.reflect-opt {
  padding: 8px 13px; border-radius: var(--r-sm); font-size: 13px; font-weight: 700;
  background: var(--surface); border: 1px solid var(--line-2); color: var(--ink);
  cursor: pointer; transition: border-color .14s, transform .12s var(--ease);
}
.reflect-opt:hover { border-color: var(--ok); transform: translateY(-1px); }
.reflect-done { font-weight: 700; font-size: 14px; color: var(--ok); }

/* ---------- COACH GUARDRAIL ---------- */
.coach-verify { font-size: 12px; color: var(--ink-faint); margin-top: 8px; }
.coach-flag {
  background: none; border: 0; cursor: pointer; padding: 0;
  font-size: 12px; font-weight: 700; color: var(--ink-faint);
  text-decoration: underline; margin-top: 6px;
}
.coach-flag:hover { color: var(--err); }

/* ---------- ACTION PLAN ---------- */
.action-item { display: flex; gap: 13px; padding: 14px 16px; border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--line); margin-bottom: 10px; }
.action-item:last-child { margin-bottom: 0; }
.action-ic { width: 38px; height: 38px; border-radius: 10px; background: var(--primary-soft);
  display: grid; place-items: center; font-size: 18px; flex-shrink: 0; }
.action-t { font-weight: 700; font-size: 14.5px; }
.action-d { color: var(--ink-soft); font-size: 13.5px; margin-top: 2px; }

/* ---------- MISC ---------- */
.spin { width: 18px; height: 18px; border: 2px solid var(--line-2); border-top-color: var(--primary); border-radius: 50%; display: inline-block; animation: sp .7s linear infinite; vertical-align: -3px; }
@keyframes sp { to { transform: rotate(360deg); } }
.reveal { opacity: 0; transform: translateY(14px); animation: rise .55s var(--ease) forwards; }
.reveal:nth-child(2){animation-delay:.05s} .reveal:nth-child(3){animation-delay:.1s}
.reveal:nth-child(4){animation-delay:.15s} .reveal:nth-child(5){animation-delay:.2s}
@keyframes rise { to { opacity: 1; transform: translateY(0); } }

/* ---------- RESPONSIVE ----------
   The chrome adapts in three layers (order matters, smaller wins):
     > 1080px   full top nav (labels) + all status chips
     681–1080   icon-only top nav, lean chips (no room for labels+chips)
     ≤ 680px    primary nav becomes a fixed BOTTOM TAB BAR (thumb-reachable),
                top bar compacts to brand + essential chips
     ≤ 360px    drop the wordmark so the smallest phones never overflow
   Pure CSS, no DOM changes, the same <nav> just relocates. */
/* full nav labels + all status chips only when there is room for everything at
   its natural size (~1200px+). Below that the bar would have to compress the
   chips (the XP pill was truncating to "4…"), so go icon-only + lean instead. */
@media (max-width: 1200px) {
  .nav { margin-left: 8px; }
  .nav-item { padding: 8px 10px; }
  .nav-item .lbl { display: none; }   /* icon-only top nav */
  .hide-sm { display: none; }          /* drop secondary status chips */
}
@media (max-width: 920px) {
  .hero-grid { grid-template-columns: 1fr; gap: 24px; }
  .hero-art { display: none; }
  .feature-grid, .block-grid { grid-template-columns: repeat(2,1fr); }
  .dash-grid { grid-template-columns: 1fr; }
}
@media (max-width: 680px) {
  .wrap { padding: 0 16px; }
  .feature-grid, .block-grid { grid-template-columns: 1fr; }
  .statgrid { grid-template-columns: repeat(2,1fr); }
  .hero { padding: 32px 0 20px; }
  /* the welcome banner reuses .hero-eyebrow (a one-line pill on desktop); on
     phones its sentence wraps to several lines, so give it room to breathe and
     a softer radius instead of the cramped lozenge. */
  .hero-eyebrow { align-items: flex-start; padding: 12px 16px; border-radius: 16px; line-height: 1.45; }
  /* compact top bar */
  .appbar { padding: 0 10px; gap: 6px; }
  .brand { font-size: 17px; }
  .appbar-right { gap: 6px; }
  /* primary nav → fixed bottom tab bar */
  .nav {
    position: fixed; left: 0; right: 0; bottom: 0; top: auto; margin: 0; z-index: 60;
    display: flex; gap: 0; justify-content: space-around; align-items: stretch;
    background: var(--surface); border-top: 1px solid var(--line);
    padding: 5px 2px calc(5px + env(safe-area-inset-bottom));
    box-shadow: 0 -4px 18px -12px rgba(15,16,32,.35);
  }
  .nav-item { flex: 1 1 0; min-width: 0; flex-direction: column; gap: 3px; padding: 4px 2px; border-radius: 10px; transform: none; }
  .nav-item:hover, .nav-item.active { transform: none; }
  .nav-item .ic { font-size: 20px; line-height: 1; }
  .nav-item .lbl { display: block !important; font-size: 10px; font-weight: 600; line-height: 1; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .nav-item.active::after { top: 1px; bottom: auto; }
  /* reserve space so scrolled content never hides behind the bar */
  body { padding-bottom: calc(60px + env(safe-area-inset-bottom)); }
  .toast { bottom: calc(74px + env(safe-area-inset-bottom)); }
}
@media (max-width: 360px) {
  .brand .brand-word { display: none; }
  .appbar { gap: 4px; padding: 0 8px; }
  .pill-chip.xp { max-width: 124px; }
}

/* ============================================================
   R2 · ADAPTIVE CORE, readiness-gated feedback surfaces.
   The result panel re-shapes itself per learner: calm for
   beginners and strugglers, robust for those who have earned it.
   ============================================================ */

/* calm private-test summary, shown instead of an edge-case wall */
.priv-calm {
  margin: 12px 16px 4px; padding: 12px 14px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-sm); font-size: 13px; color: var(--ink-soft); line-height: 1.55;
}

/* gentle encouragement, calm and safety modes */
.encourage {
  padding: 14px 16px; background: var(--ok-soft); border: 1px solid #CBE9D5;
  border-radius: var(--r-md); font-size: 14px; color: #0F6B39; line-height: 1.6; font-weight: 600;
}

/* safety card, leads the panel when a learner is genuinely stuck */
.safety {
  padding: 16px; margin-bottom: 14px;
  background: var(--info-soft); border: 1px solid #D6D4FB; border-radius: var(--r-md);
}
.safety-h { font-family: var(--display); font-weight: 700; font-size: 15px; color: var(--primary-deep); margin-bottom: 6px; }
.safety p { font-size: 13.5px; color: var(--ink-soft); line-height: 1.6; margin: 0; }

/* growth offer, surfaced when only the hidden edge cases failed */
.growth {
  padding: 16px; background: var(--surface-2);
  border: 1px solid var(--line); border-left: 3px solid var(--ok); border-radius: var(--r-md);
}
.growth-h { font-family: var(--display); font-weight: 700; font-size: 15px; color: var(--ink); margin-bottom: 6px; }
.growth p { font-size: 13.5px; color: var(--ink-soft); line-height: 1.6; margin: 0 0 12px; }

/* test heatmap, a visual map of every test at a glance (robust mode) */
.heat-wrap { margin: 4px 16px 16px; }
.heat-label { font-size: 12px; font-weight: 700; color: var(--ink-faint); margin-bottom: 7px; }
.heat { display: flex; flex-wrap: wrap; gap: 6px; }
.heat-cell {
  width: 28px; height: 28px; border-radius: 7px; display: grid; place-items: center;
  font-size: 11px; font-weight: 700; color: #fff; cursor: default;
}
.heat-cell.hpass { background: var(--ok); }
.heat-cell.hfail { background: var(--err); }
.heat-cell.herr  { background: var(--warn); }
.heat-cell.hhidden { box-shadow: inset 0 0 0 2px rgba(255,255,255,.6); }

/* concrete expected-vs-got diff, robust mode, failed public test */
.diff { display: flex; flex-direction: column; gap: 7px; }
.diff-row {
  display: flex; align-items: stretch; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-xs); overflow: hidden;
}
.diff-tag {
  flex-shrink: 0; width: 84px; padding: 8px 10px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--ink-faint); background: rgba(16,24,40,.03);
}
.diff-row pre { flex: 1; margin: 0; padding: 8px 10px; font-size: 12px; white-space: pre-wrap; word-break: break-word; }
.diff-exp { background: var(--ok-soft); border-color: #CBE9D5; }
.diff-got { background: var(--err-soft); border-color: #F2CDCF; }
.diff-hint { font-size: 12px; color: var(--ink-soft); font-style: italic; }

/* W3 errHelp: the plain-language decode of a failing test's error, shown inside
   the test detail beside the raw error. Indigo "help" tone (--info), deliberately
   NOT error-red, so it reads as guidance, not another alarm. font-family resets to
   the body font (the detail block is monospace) so the prose reads naturally. */
.errhelp {
  margin-top: 10px; padding: 10px 12px; border: 1px solid var(--info-soft);
  border-left: 3px solid var(--info); border-radius: var(--r-xs);
  background: var(--info-soft); font-family: var(--font); white-space: normal;
}
.errhelp-h { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--info); margin-bottom: 5px; }
.errhelp-what { font-size: 13px; color: var(--ink); line-height: 1.5; }
.errhelp-hi   { font-size: 12.5px; color: var(--ink-soft); line-height: 1.55; margin-top: 3px; }
.errhelp-first { font-size: 12.5px; color: var(--ink); line-height: 1.5; margin-top: 7px; }
.errhelp-tag { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--info); margin-right: 5px; }

/* edge-case coverage donut, robust mode */
.cov { margin-top: 14px; padding: 14px; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-md); }
.cov-note { font-size: 12px; color: var(--ink-soft); line-height: 1.55; margin-top: 6px; text-align: center; }

/* readiness card, faculty insights */
.rd-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 12px; margin-top: 12px; }
.rd-cell { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-md); padding: 14px; text-align: center; }
.rd-v { font-family: var(--display); font-weight: 700; font-size: 22px; color: var(--ink); }
.rd-l { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-faint); margin-top: 3px; }
@media (max-width: 620px) { .rd-grid { grid-template-columns: 1fr; } }

/* ============================================================
   R3 · RESILIENCE & REACH, accessibility (WCAG 2.2 AA).
   Keyboard, screen-reader and reduced-motion support.
   ============================================================ */

/* skip link, the first focusable element, hidden until focused */
.skip-link {
  position: fixed; top: 8px; left: 8px; z-index: 9999;
  padding: 10px 16px; background: var(--primary); color: #fff;
  border-radius: var(--r-sm); font-weight: 700; font-size: 14px;
  text-decoration: none; transform: translateY(-150%);
  transition: transform .15s var(--ease);
}
.skip-link:focus { transform: translateY(0); }

/* present to assistive tech, invisible on screen */
.sr-only {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

/* a clear, consistent focus ring for keyboard users everywhere */
a:focus-visible, button:focus-visible, select:focus-visible,
input:focus-visible, textarea:focus-visible,
[tabindex]:focus-visible, [role="link"]:focus-visible {
  outline: 3px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
/* <main> is focused on every route change as a screen-reader landing
   point, it is not interactive, so it carries no visible ring */
main:focus, main:focus-visible { outline: none; }

/* card and table-row navigations driven by data-href */
[data-href] { cursor: pointer; }

/* honour a reduced-motion preference across the whole product */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* language switcher, R3 · Vernacular */
.lang-sel {
  font-family: var(--font); font-size: 13px; font-weight: 700;
  color: var(--ink-soft); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 6px 10px; cursor: pointer;
}
.lang-sel:hover { border-color: var(--line-2); color: var(--ink); }

/* offline chip, R3 · §1 Offline resilience */
.pill-chip.offline { color: var(--warn); background: var(--warn-soft); border-color: transparent; }

/* ============================================================
   Coding language, picker, chips, per-language analysis
   ============================================================ */
.codebar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin: 18px 0 4px;
}
.codebar-h { font-size: 14px; margin: 0; }
.langpick {
  display: inline-flex; gap: 3px; padding: 3px;
  background: var(--surface-3); border-radius: 999px;
}
.langopt {
  appearance: none; border: 0; cursor: pointer; font: inherit;
  font-size: 12.5px; font-weight: 600;
  color: var(--ink-soft); background: transparent;
  padding: 7px 14px; border-radius: 999px;
  transition: background .16s var(--ease), color .16s var(--ease);
}
.langopt:hover:not(:disabled):not(.on) { color: var(--ink); }
.langopt.on {
  background: var(--surface); color: var(--primary-deep);
  box-shadow: var(--shadow-sm); font-weight: 700;
}
.langopt:disabled { opacity: .4; cursor: not-allowed; }
.langopt:focus-visible { outline: none; box-shadow: var(--ring); }
.codebar-hint { font-size: 12px; color: var(--ink-faint); margin: 0 0 8px; }

/* ============================================================
   EXAM WORKSPACE · the real coding-exam panel layout
   On roomy screens the problem tab becomes a two-pane workspace:
   the problem statement on the LEFT, and on the RIGHT the editor with
   a tabbed console (Output / Coach) below — the panel layout learners
   meet in real placement exams (TCS NQT, HackerRank, …). It collapses
   to a single, mobile-friendly column on tablets and phones. Built by
   examLayout() in app.js, which only MOVES the rendered nodes, so every
   id/handler (and thus every feature) is preserved. The Monaco suggest
   popup renders at <body> level (monaco-editor.js), so the panel's
   overflow never clips it, and the taller editor drops it BELOW the caret.
   ============================================================ */
.exam { display: block; }
.console { margin-top: 16px; border: 1px solid var(--line-2); border-radius: var(--r-md); overflow: hidden; background: var(--surface); }
.console-tabs { display: flex; gap: 2px; padding: 5px 6px 0; background: var(--surface-3); border-bottom: 1px solid var(--line); }
.ctab { appearance: none; border: 0; background: none; font: inherit; font-size: 12.5px; font-weight: 700; color: var(--ink-faint); padding: 8px 15px; cursor: pointer; border-radius: 9px 9px 0 0; transition: color .14s, background .14s; }
.ctab:hover { color: var(--ink-soft); }
.ctab.on { background: var(--surface); color: var(--primary-deep); box-shadow: 0 -2px 0 var(--primary) inset; }
.ctab:focus-visible { outline: none; box-shadow: var(--ring); }
.console-body { padding: 14px; }
.console-pane[hidden] { display: none; }
.console-coach-intro { font-size: 12.5px; color: var(--ink-faint); margin: 0 0 8px; line-height: 1.5; }

@media (min-width: 1000px) {
  /* full-bleed: the problem route uses the screen width, not the 1180 reading
     cap — set on the route's .wrap by examLayout() so ONLY this route widens. */
  .wrap-exam { max-width: 1660px; }
  /* compact the problem-route HEADER (padding-top) so the panel gets real
     height; keep a MODERATE gap below the Previous/Next row so it never
     collides with the footer, but not so large it reads as a "false bottom"
     above the footer. The "Read the lesson" button is left untouched. */
  .view-exam { padding-top: 6px; padding-bottom: 36px; }
  .wrap-exam .page-title { font-size: 23px; margin: 2px 0 0; }
  .wrap-exam .pitem-tags { margin-top: 5px !important; }
  .wrap-exam .tabs { margin-top: 10px !important; margin-bottom: 8px; }
  /* a full-length two-pane workspace: problem on the LEFT, editor + tabbed
     console on the RIGHT. NOTHING is trapped in a fixed-height box and nothing
     scrolls inside a pane — both sides flow at their natural length and the
     PAGE scrolls. Each side keeps its own height (align-items:start); only a
     thin divider separates them, no enclosing box. The editor keeps a generous
     height (Monaco needs a pixel height) and long code scrolls inside the
     editor itself, exactly as in any IDE. */
  .exam {
    display: grid; grid-template-columns: minmax(300px, 34%) 1fr;
    align-items: start; margin-top: 4px;
  }
  .exam-problem { min-width: 0; padding: 16px 26px 24px 0; }
  .exam-work { display: flex; flex-direction: column; min-width: 0; padding: 12px 0 16px 22px; gap: 10px; border-left: 1px solid var(--line); }
  .exam-work > .codebar { margin: 0; }
  /* the editor is generous and fixed-height (Monaco); the console grows to fit
     its content so the Output (results, complexity, hints, solution) and Coach
     never clip — no inner scrollbar, the page scrolls instead. */
  .exam-work .monaco-host { height: clamp(360px, 48vh, 580px); box-shadow: none; }
  .exam-work .console { margin: 0; }
  .exam-work .console-body { padding: 12px 14px; min-height: 140px; }
  .exam-work .row.wrap { margin-top: 2px; }
}
@media (min-width: 1440px) { .exam { grid-template-columns: minmax(330px, 30%) 1fr; } }

/* per-language chip, one accent per language, used in tables + cards */
.lang-chip {
  display: inline-flex; align-items: center; padding: 3px 9px;
  border-radius: 6px; font-size: 11px; font-weight: 700; white-space: nowrap;
}
.lang-python { background: #E3F4FC; color: #0B6F95; }
.lang-c      { background: #EAEEF6; color: #3A4A63; }
.lang-cpp    { background: #ECE9FE; color: #4A3CC0; }
.lang-java   { background: #FBEEDD; color: #9A5B07; }

/* per-language analysis cards */
.lang-grid {
  display: grid; gap: 12px; margin-top: 12px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}
.lang-card {
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-2); padding: 14px;
}
.lang-card-h { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.lang-ac { font-size: 12px; font-weight: 700; color: var(--ink-soft); }
.lang-stats {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 6px; margin: 12px 0 10px;
}
.lang-stats > div { text-align: center; }
.lang-stats b { display: block; font-size: 16px; color: var(--ink); }
.lang-stats b small { font-size: 10px; color: var(--ink-faint); font-weight: 600; }
.lang-stats span { font-size: 10px; color: var(--ink-faint); }
.lang-tip {
  margin-top: 10px; font-size: 11.5px; color: var(--ink-soft);
  line-height: 1.5; border-top: 1px solid var(--line); padding-top: 8px;
}

/* ============================================================
   multicode, one example, four languages, behind tabs
   (article reference material; tabs sync with the editor)
   ============================================================ */
.multicode { margin: 16px 0; }
.mc-title {
  font-size: 12.5px; font-weight: 700; color: var(--ink-soft);
  margin-bottom: 6px; letter-spacing: .01em;
}
.mc-tabs {
  display: flex; gap: 2px; padding: 3px;
  background: var(--surface-3); border-radius: var(--r-sm) var(--r-sm) 0 0;
  border: 1px solid var(--line); border-bottom: 0; width: fit-content;
}
.mc-tab {
  appearance: none; border: 0; cursor: pointer; font: inherit;
  font-size: 12px; font-weight: 600; color: var(--ink-soft);
  background: transparent; padding: 6px 14px; border-radius: var(--r-xs);
  transition: background .15s var(--ease), color .15s var(--ease);
}
.mc-tab:hover:not(:disabled):not(.on) { color: var(--ink); }
.mc-tab.on {
  background: #1E1E1E; color: #fff; font-weight: 700; box-shadow: var(--shadow-sm);
}
.mc-tab:disabled { opacity: .35; cursor: not-allowed; }
.mc-tab:focus-visible { outline: none; box-shadow: var(--ring); }
/* each pane is a live playground: an editable code surface, a run bar,
   and an inline output block, read, tinker, run, see, all in the lesson */
.mc-pane { margin: 0; }
.mc-code {
  display: block; width: 100%; box-sizing: border-box;
  background: #1E1E1E; color: #D4D4D4; border: 0; margin: 0;
  border-radius: 0 var(--r-md) 0 0;
  padding: 14px 16px; min-height: 44px; overflow: hidden;
  font-family: var(--mono); font-size: 13px; line-height: 1.65;
  resize: vertical; outline: none; tab-size: 4;
}
.mc-code:focus { box-shadow: inset 3px 0 0 var(--primary-2); }
.mc-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: #252526; padding: 8px 10px;
  border-radius: 0 0 var(--r-md) var(--r-md);
}
.mc-run {
  appearance: none; border: 0; cursor: pointer; font: inherit;
  font-size: 12.5px; font-weight: 700; color: #fff;
  background: var(--ok); padding: 6px 13px; border-radius: var(--r-xs);
}
.mc-run:hover:not(:disabled) { filter: brightness(1.08); }
.mc-run:disabled { opacity: .6; cursor: default; }
.mc-reset {
  appearance: none; cursor: pointer; font: inherit; font-size: 12px; font-weight: 600;
  color: #C6C6C6; background: transparent; border: 1px solid #3A3A3A;
  padding: 5px 11px; border-radius: var(--r-xs);
}
.mc-reset:hover { color: #fff; border-color: #5A5A5A; }
.mc-stdin {
  flex: 1; min-width: 150px; font: inherit; font-size: 12px;
  font-family: var(--mono);
  background: #1E1E1E; color: #D4D4D4; border: 1px solid #3A3A3A;
  border-radius: var(--r-xs); padding: 6px 9px; outline: none;
}
.mc-stdin:focus { border-color: var(--primary-2); }
.mc-run:focus-visible, .mc-reset:focus-visible { outline: none; box-shadow: var(--ring); }
.mc-hint { font-size: 11px; color: #8A8A8A; }
.mc-out {
  margin: 8px 0 0; white-space: pre-wrap; word-break: break-word;
  background: #F7F8FC; border: 1px solid var(--line);
  border-left: 3px solid var(--ok);
  border-radius: var(--r-sm); padding: 10px 13px;
  font-family: var(--mono); font-size: 12.5px; line-height: 1.6; color: #2A2F3D;
}
.mc-out.mc-err {
  border-left-color: var(--err); background: var(--err-soft); color: #7A1E22;
}

/* effort-earned article block, a perk, so it should feel like one */
.note.note-earned {
  position: relative;
  background: linear-gradient(180deg, #FBF7FF, var(--surface));
  border-color: #D9C9F5;
}
.earned-tag {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10.5px; font-weight: 800; letter-spacing: .04em;
  text-transform: uppercase; color: #7C3AED;
  background: #F3E8FF; border-radius: 999px;
  padding: 3px 9px; margin-bottom: 8px;
}
/* DARK-MODE fixes for the callout cards. A few variants use hardcoded LIGHT
   fills (the AI "WITH AI" card, the effort-earned "peek ahead" card + its tag),
   which in dark mode left a light card with light, invisible body text. Re-skin
   those dark here; the token-based variants (tip/warn/story/exam) already adapt,
   so we only need to darken their hardcoded light borders + a couple of labels. */
[data-theme="dark"] .note.ai      { background: #231A3C; border-color: #3A2A5E; }
[data-theme="dark"] .note.ai .nt  { color: #C4A6FF; }
[data-theme="dark"] .note.note-earned {
  background: linear-gradient(180deg, #251B3F, var(--surface));
  border-color: #3A2A5E;
}
[data-theme="dark"] .earned-tag   { background: #2C2048; color: #C8ACFF; }
[data-theme="dark"] .note.tip     { border-color: #1F4030; }
[data-theme="dark"] .note.warn    { border-color: #4A3A1A; }
[data-theme="dark"] .note.story   { border-color: #33365C; }
[data-theme="dark"] .note.exam    { border-color: #1D4456; }
[data-theme="dark"] .note.exam .nt{ color: #5BB8DA; }
[data-theme="dark"] .note.optimal-advisory { border-color: #4A3A1A; }
[data-theme="dark"] .examgate-measured     { border-color: #1F4030; }

/* ============================================================
   MULTI-TENANT · LEADERBOARD
   A competitive surface, podium, streak flames, climbing
   deltas, "you are #N", that still renders from one API call.
   ============================================================ */

/* the window toggle (all-time / this week) */
.lb-toggle {
  display: inline-flex; gap: 3px; padding: 3px;
  background: var(--surface-3); border-radius: 999px;
}
.lb-toggle button {
  appearance: none; border: 0; cursor: pointer; font: inherit;
  font-size: 13px; font-weight: 700; color: var(--ink-soft);
  background: transparent; padding: 8px 16px; border-radius: 999px;
  transition: background .16s var(--ease), color .16s var(--ease);
}
.lb-toggle button:hover:not(.on) { color: var(--ink); }
.lb-toggle button.on {
  background: var(--surface); color: var(--primary-deep);
  box-shadow: var(--shadow-sm);
}
.lb-toggle button:focus-visible { outline: none; box-shadow: var(--ring); }

/* the podium, top three, raised and celebratory */
.podium {
  display: grid; grid-template-columns: 1fr 1.15fr 1fr;
  gap: 12px; align-items: end; margin: 4px 0 22px;
}
.pod {
  position: relative; text-align: center; border-radius: var(--r-lg);
  padding: 18px 12px 16px; border: 1px solid var(--line);
  background: var(--surface); box-shadow: var(--shadow-sm);
}
.pod-1 {
  background: linear-gradient(180deg, #FFF7E0, var(--surface) 78%);
  border-color: #F0DDA6; padding-top: 28px; padding-bottom: 24px;
  box-shadow: 0 14px 34px -14px rgba(181,116,12,.4);
}
.pod-2 { background: linear-gradient(180deg, #F2F4F8, var(--surface) 78%); border-color: var(--line-2); }
.pod-3 { background: linear-gradient(180deg, #FBEEE2, var(--surface) 78%); border-color: #ECCFB4; }
.pod-crown { font-size: 26px; line-height: 1; margin-bottom: 4px; }
.pod-medal {
  position: absolute; top: -14px; left: 50%; transform: translateX(-50%);
  width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  font-weight: 800; font-size: 13px; color: #fff; box-shadow: var(--shadow-sm);
}
.pod-medal.m1 { background: linear-gradient(135deg,#F5B731,#E08C0B); }
.pod-medal.m2 { background: linear-gradient(135deg,#C2C9D4,#8C95A4); }
.pod-medal.m3 { background: linear-gradient(135deg,#DDA06A,#B5740C); }
.pod-av {
  width: 56px; height: 56px; border-radius: 50%; margin: 0 auto 9px;
  display: grid; place-items: center; font-weight: 800; font-size: 19px; color: #fff;
  background: linear-gradient(135deg,var(--primary),var(--primary-2));
}
.pod-1 .pod-av { width: 66px; height: 66px; font-size: 22px;
  background: linear-gradient(135deg,#F5B731,#E08C0B); }
.pod-name { font-weight: 700; font-size: 14px; overflow-wrap: anywhere; }
.pod-xp { font-family: var(--display); font-weight: 700; font-size: 20px; color: var(--primary-deep); margin-top: 3px; }
.pod-1 .pod-xp { font-size: 24px; }
.pod-meta { font-size: 11.5px; color: var(--ink-faint); font-weight: 600; margin-top: 2px; }

/* the ranked rows below the podium */
.lb-row {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 16px; border-bottom: 1px solid var(--line);
}
.lb-row:last-child { border-bottom: 0; }
.lb-row.me {
  background: var(--primary-soft);
  box-shadow: inset 3px 0 0 var(--primary);
}
.lb-rank {
  width: 38px; flex-shrink: 0; text-align: center;
  font-family: var(--display); font-weight: 700; font-size: 16px; color: var(--ink-soft);
}
.lb-row.me .lb-rank { color: var(--primary-deep); }
.lb-id { flex: 1; min-width: 0; display: flex; align-items: center; gap: 11px; }
.lb-name { font-weight: 600; font-size: 14.5px; overflow-wrap: anywhere; }
.lb-sub  { font-size: 12px; color: var(--ink-faint); font-weight: 600; }
.lb-you-tag {
  font-size: 10px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  color: var(--primary-deep); background: var(--surface);
  border: 1px solid var(--primary); border-radius: 999px; padding: 2px 7px;
}
.lb-stat { text-align: right; min-width: 56px; }
.lb-stat b { font-family: var(--display); font-weight: 700; font-size: 15px; color: var(--ink); display: block; }
.lb-stat span { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-faint); }
.lb-flame { color: var(--warn); font-weight: 700; font-size: 13px; white-space: nowrap; }
.lb-delta {
  min-width: 46px; text-align: right; font-size: 12.5px; font-weight: 700; white-space: nowrap;
}
.lb-delta.up   { color: var(--ok); }
.lb-delta.down { color: var(--err); }
.lb-delta.flat { color: var(--ink-faint); }

/* the sticky "you are #N of M" banner */
.lb-mecard {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  background: linear-gradient(120deg,#4F46E5,#6D5BF2 60%,#0EA5E9); color: #fff;
  border-radius: var(--r-lg); padding: 16px 20px; margin-bottom: 18px;
  box-shadow: var(--shadow);
}
.lb-mecard .me-rank { font-family: var(--display); font-weight: 700; font-size: 30px; line-height: 1; }
.lb-mecard .me-lead { flex: 1; min-width: 180px; }
.lb-mecard .me-lead b { font-size: 15px; }
.lb-mecard .me-lead div { font-size: 12.5px; opacity: .92; margin-top: 2px; }
.lb-mecard .me-fig { text-align: center; }
.lb-mecard .me-fig b { font-family: var(--display); font-size: 19px; }
.lb-mecard .me-fig span { font-size: 10px; opacity: .85; text-transform: uppercase; letter-spacing: .05em; display: block; }

/* a row climbing into place on render */
@keyframes lb-climb { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
.lb-anim .lb-row, .lb-anim .pod { animation: lb-climb .4s var(--ease) backwards; }
.lb-anim .pod:nth-child(1){animation-delay:.10s} .lb-anim .pod:nth-child(2){animation-delay:0s} .lb-anim .pod:nth-child(3){animation-delay:.18s}
.lb-anim .lb-row:nth-child(n+1){animation-delay:.04s}

/* ============================================================
   MULTI-TENANT · MANAGEMENT PORTAL
   Role-aware admin surface, user roster, group management,
   problem assignment. Reuses the shared table/card system.
   ============================================================ */
.role-pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 9px; border-radius: 6px; font-size: 11px; font-weight: 700;
  white-space: nowrap; text-transform: capitalize;
}
.role-student { background: var(--surface-3);  color: var(--ink-soft); }
.role-teacher { background: var(--accent-soft); color: #0B6F95; }
.role-hos     { background: #F3E8FF;            color: #7C3AED; }
.role-admin   { background: var(--primary-soft); color: var(--primary-deep); }
.role-super_admin { background: var(--warn-soft); color: var(--warn); }

.status-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; vertical-align: 0; }
.status-active   { background: var(--ok); }
.status-suspended{ background: var(--warn); }
.status-archived { background: var(--ink-faint); }

/* the role-scoped portal landing tiles */
.portal-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; margin-bottom: 22px; }
@media (max-width: 920px) { .portal-grid { grid-template-columns: repeat(2,1fr); } .podium { grid-template-columns: 1fr; } .pod-1 { order: -1; } }
@media (max-width: 620px) { .portal-grid { grid-template-columns: 1fr; } }

/* a compact modal-less inline editor row for a user */
.mini-form { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
.mini-form .field { min-width: 150px; }

/* ============================================================
   R4 · PROOF, verified credentials
   ============================================================ */
.cred-card {
  position: relative; background: var(--surface);
  border: 1px solid var(--line-2); border-radius: var(--r-lg);
  padding: 24px 22px; margin-bottom: 14px; box-shadow: var(--shadow-sm);
  background-image: linear-gradient(135deg, var(--primary-soft) 0%, transparent 42%);
}
.cred-seal { position: absolute; top: 18px; right: 20px; font-size: 30px; }
.cred-issuer {
  font-size: 11px; font-weight: 700; letter-spacing: .12em; color: var(--primary-deep);
}
.cred-title {
  font-family: var(--display); font-size: 21px; font-weight: 700;
  color: var(--ink); margin: 8px 0 4px; letter-spacing: -.01em; padding-right: 40px;
}
.cred-sub { font-size: 14px; color: var(--ink-soft); }
.cred-detail { font-size: 13.5px; color: var(--ink-soft); margin-top: 6px; }
.cred-meta {
  font-size: 11.5px; color: var(--ink-faint); margin-top: 12px; font-family: var(--mono);
  word-break: break-word;
}

/* ============ FOUNDATIONS STARS ============ */
/* --- app-bar star chip --- */
.star-chip {
  gap: 0; padding: 5px 10px;
  background: var(--star-soft); border-color: transparent;
  text-decoration: none;
}
.star-chip:hover { box-shadow: var(--shadow-sm); }
.star-chip-glyphs { display: inline-flex; gap: 1px; line-height: 1; }
.sc-star {
  font-size: 13px; color: var(--star-dim);
  transition: color .2s var(--ease), text-shadow .2s var(--ease), transform .2s var(--ease);
}
.sc-star.lit {
  color: var(--star-gold);
  text-shadow: 0 0 5px rgba(232,163,23,.6);
}
.star-chip:hover .sc-star.lit { transform: scale(1.12); }
/* --- app-bar wings chip (transformed) --- */
.wings-chip {
  gap: 5px; padding: 5px 12px; text-decoration: none; font-weight: 700;
  color: var(--star-deep);
  background: linear-gradient(135deg, var(--star-soft), #FFF6E0);
  border-color: var(--star-glow);
  box-shadow: 0 0 0 1px rgba(232,163,23,.18), 0 2px 8px -3px rgba(181,116,12,.4);
}
.wings-chip .wings-glyph { font-size: 14px; filter: drop-shadow(0 0 4px rgba(246,199,82,.7)); }
.wings-chip:hover { box-shadow: 0 0 0 1px rgba(232,163,23,.3), 0 4px 12px -3px rgba(181,116,12,.5); }

/* --- home star panel --- */
.star-panel {
  position: relative; overflow: hidden;
  background:
    radial-gradient(120% 140% at 90% -10%, rgba(246,199,82,.16), transparent 55%),
    var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 24px 26px;
  box-shadow: var(--shadow);
}
.star-panel-head { display: flex; align-items: flex-start; gap: 16px; }
.star-panel-eyebrow {
  font-size: 11.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--star-deep);
}
.star-panel-title {
  font-family: var(--display); font-size: 21px; font-weight: 700;
  color: var(--ink); letter-spacing: -.01em; margin-top: 3px;
}
.star-panel-sub { color: var(--ink-soft); font-size: 14px; margin-top: 7px; max-width: 560px; }
.star-panel-count {
  margin-left: auto; flex-shrink: 0;
  font-family: var(--display); font-size: 30px; font-weight: 700; line-height: 1;
  color: var(--star-gold);
}
.star-panel-count span { font-size: 16px; color: var(--ink-faint); }

/* --- the five large tactile stars --- */
.big-stars {
  display: flex; gap: clamp(10px, 3vw, 26px); justify-content: center;
  flex-wrap: wrap; margin: 22px 0 4px;
}
.big-star {
  position: relative; width: 76px; height: 76px;
  display: grid; place-items: center;
}
.big-star .bs-glyph {
  font-size: 62px; line-height: 1;
  color: var(--star-dim);
  text-shadow: 0 1px 0 #fff, 0 2px 3px rgba(16,24,40,.14);
  transition: color .4s var(--ease), text-shadow .4s var(--ease), transform .3s var(--ease);
}
.big-star .bs-tier {
  position: absolute; bottom: 2px;
  font-size: 11px; font-weight: 700; color: var(--ink-faint);
  background: var(--surface); padding: 0 6px; border-radius: 999px;
  border: 1px solid var(--line);
}
.big-star .bs-rays {
  position: absolute; inset: -8px; border-radius: 50%;
  background: radial-gradient(circle, rgba(246,199,82,.55), transparent 62%);
  opacity: 0; transform: scale(.6);
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}
/* an earned star, warm, glowing, raised */
.big-star.earned .bs-glyph {
  color: var(--star-gold);
  text-shadow:
    0 0 14px rgba(246,199,82,.85),
    0 1px 0 #fff, 0 3px 5px rgba(181,116,12,.35);
  animation: star-pop .6s var(--ease) both;
}
.big-star.earned .bs-rays { opacity: 1; transform: scale(1); }
.big-star.earned .bs-tier { color: var(--star-deep); border-color: var(--star-glow); }
/* the next star to earn, a soft, inviting pulse */
.big-star.next .bs-glyph { color: #C9A86A; }
.big-star.next .bs-rays {
  opacity: .5; transform: scale(.9);
  background: radial-gradient(circle, rgba(246,199,82,.3), transparent 65%);
  animation: star-beckon 2.6s ease-in-out infinite;
}
@keyframes star-pop {
  0%   { transform: scale(.4) rotate(-22deg); }
  60%  { transform: scale(1.18) rotate(6deg); }
  100% { transform: scale(1) rotate(0); }
}
@keyframes star-beckon {
  0%,100% { opacity: .35; transform: scale(.85); }
  50%     { opacity: .7;  transform: scale(1.05); }
}

/* --- panel footer: progress to next star --- */
.star-panel-foot { margin-top: 16px; }
.star-progress {
  height: 7px; border-radius: 999px; background: var(--surface-3);
  overflow: hidden; margin-bottom: 9px;
}
.star-progress > i {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--star-gold), var(--star-glow));
  transition: width .6s var(--ease);
}
.star-panel-line { font-size: 14px; font-weight: 600; color: var(--ink-soft); text-align: center; }
.star-panel-line .spl-count { color: var(--ink-faint); font-weight: 600; }

/* all five stars earned, the climb to 100 still on, a warm gold frame
   that sets the panel apart from the mid-climb state without stealing the
   full Wings celebration reserved for transformation. */
.star-panel.allstars {
  border-color: var(--star-glow);
  background:
    radial-gradient(120% 150% at 50% -20%, rgba(246,199,82,.2), transparent 60%),
    var(--surface);
  box-shadow: 0 0 0 1px rgba(232,163,23,.16), var(--shadow);
}
.star-panel.allstars .star-progress > i {
  background: linear-gradient(90deg, var(--star-deep), var(--star-gold), var(--star-glow));
}

/* --- transformed: the radiant Wings badge --- */
.star-panel.wings {
  display: flex; align-items: center; gap: 22px; flex-wrap: wrap;
  background:
    radial-gradient(130% 160% at 0% 0%, rgba(246,199,82,.22), transparent 58%),
    linear-gradient(135deg, #FFFCF2, var(--surface));
  border-color: var(--star-glow);
}
.wings-badge {
  position: relative; flex-shrink: 0;
  width: 96px; height: 96px; border-radius: 50%;
  display: grid; place-items: center;
  background: radial-gradient(circle, #FFF1CC, var(--star-soft));
  box-shadow:
    0 0 0 6px rgba(246,199,82,.18),
    0 0 36px rgba(246,199,82,.6),
    inset 0 2px 8px rgba(255,255,255,.9);
}
.wings-badge .wb-core {
  font-size: 52px; line-height: 1;
  filter: drop-shadow(0 2px 6px rgba(181,116,12,.45));
}
.wings-badge::after {
  content: ""; position: absolute; inset: -10px; border-radius: 50%;
  background: conic-gradient(from 0deg, transparent, rgba(246,199,82,.5), transparent 60%);
  animation: wings-halo 6s linear infinite;
}
.star-panel.wings .star-panel-copy { flex: 1; min-width: 240px; }
@keyframes wings-halo { to { transform: rotate(360deg); } }

@media (max-width: 560px) {
  .big-star { width: 56px; height: 56px; }
  .big-star .bs-glyph { font-size: 44px; }
  .star-panel { padding: 20px; }
}
/* motion-sensitive learners: keep the meaning, drop the movement */
@media (prefers-reduced-motion: reduce) {
  .big-star.earned .bs-glyph,
  .big-star.next .bs-rays,
  .wings-badge::after { animation: none; }
}

/* ============================================================
   ONBOARDING, the first-run welcome
   The learner's first impression, so it carries the most weight.
   A full-bleed, three-slide experience: the promise, the runway to
   the job, and the 5-minute first win. The palette leads with a
   calm, trustworthy deep blue and lifts it with a warm amber glow, 
   safe and uplifting, never clinical, never alarming. Skeuomorphic
   depth (a raised card, a soft inner top-light, a slow aurora) so a
   demotivated learner on a budget phone feels something is being
   handed to them. Generous type sizes carry weak eyesight and weak
   English. Every animation also has a still form for
   prefers-reduced-motion at the foot of this block.
   ============================================================ */
.onboard {
  position: relative; min-height: 100vh; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  padding: 32px 18px;
  /* a calm trust-blue wash, warmed at the corners with optimistic amber */
  background:
    radial-gradient(900px 560px at 16% 10%, rgba(30,58,138,.16), transparent 60%),
    radial-gradient(820px 540px at 88% 92%, rgba(245,158,11,.16), transparent 62%),
    var(--bg);
}
/* the aurora, a slow, soft drift of light behind the card. It pairs
   trust-blue with a hopeful amber so the screen feels warm, not cold.
   aria-hidden; it carries no meaning, only mood. */
.onb-aurora {
  position: absolute; inset: -25%; z-index: 0; pointer-events: none;
  background:
    radial-gradient(440px 440px at 28% 32%, rgba(39,71,166,.34), transparent 65%),
    radial-gradient(400px 400px at 74% 66%, rgba(245,158,11,.30), transparent 65%);
  filter: blur(48px);
  animation: onb-drift 24s var(--ease) infinite alternate;
}
@keyframes onb-drift {
  to { transform: translate3d(5%, -4%, 0) scale(1.12); }
}

.onb-shell {
  position: relative; z-index: 1;
  width: 100%; max-width: 780px;
  display: flex; flex-direction: column; gap: 18px;
}

/* top row, brand wordmark and the always-available Skip */
.onb-top {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.onb-brand {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--display); font-weight: 700; font-size: 16px; color: var(--ink);
}
/* Skip, present and honest, but quiet. No dark pattern: the way out
   is always one obvious tap, never hidden. */
.onb-skip {
  background: var(--surface); border: 1px solid var(--line-2); cursor: pointer;
  color: var(--ink-soft); font-weight: 700; font-size: 13.5px;
  padding: 9px 16px; border-radius: 999px;
  transition: border-color .15s, color .15s, background .15s;
}
.onb-skip:hover { border-color: var(--onb-trust); color: var(--onb-trust); }

/* the slide card, raised, with a soft inner top-light (skeuomorphic) */
.onb-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow:
    var(--shadow-lg),
    inset 0 1px 0 rgba(255,255,255,.9);
  padding: 34px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 32px; align-items: center;
}
.onb-art {
  display: flex; flex-direction: column; justify-content: center;
  min-height: 240px;
}
/* eyebrow, a warm, welcoming pill in trust-blue */
.onb-eyebrow {
  display: inline-block; align-self: flex-start;
  margin-bottom: 13px; padding: 7px 14px; border-radius: 999px;
  background: rgba(30,58,138,.08); color: var(--onb-trust);
  font-size: 13px; font-weight: 700; letter-spacing: .01em;
}
/* generous, confident, friendly, large enough for weak eyesight */
.onb-title {
  font-family: var(--display); font-weight: 700;
  font-size: clamp(25px, 3.6vw, 34px); line-height: 1.16;
  letter-spacing: -.02em; color: var(--ink);
}
.onb-body {
  margin-top: 13px; font-size: 16px; line-height: 1.68; color: var(--ink-soft);
}
/* reassurance line, the "you will not be made to feel stupid" promise,
   set on a calm trust-blue ground so it reads as safety, not noise */
.onb-reassure {
  display: flex; align-items: flex-start; gap: 9px;
  margin-top: 15px; padding: 12px 14px; border-radius: var(--r-md);
  background: rgba(30,58,138,.06);
  font-size: 14.5px; line-height: 1.55; font-weight: 600; color: var(--onb-trust);
}
.onb-reassure-ic { font-size: 17px; line-height: 1.4; flex-shrink: 0; }
.onb-ready {
  margin-top: 15px; font-weight: 700; font-size: 15.5px; color: var(--onb-warm-deep);
}

/* SLIDE 1, the transformation: zero coding -> a real tech career.
   One idea, shown as a journey between two warm nodes. */
.onb-transform {
  display: flex; align-items: center; justify-content: center; gap: 6px;
}
.onb-tf-node {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 20px 12px; border-radius: var(--r-lg); text-align: center;
}
.onb-tf-node.from {
  background: var(--onb-grow-soft); border: 1px solid #BFE3CF;
}
.onb-tf-node.to {
  background: linear-gradient(155deg, var(--onb-trust-2), var(--onb-trust));
  color: #fff;
  box-shadow: 0 16px 34px -14px rgba(30,58,138,.55), inset 0 1px 0 rgba(255,255,255,.22);
}
.onb-tf-ic { font-size: 38px; line-height: 1; }
.onb-tf-lbl {
  font-family: var(--display); font-weight: 700; font-size: 14px; line-height: 1.25;
}
.onb-tf-node.from .onb-tf-lbl { color: var(--onb-grow); }
/* the amber arrow, the momentum between the two states */
.onb-tf-arrow {
  flex-shrink: 0; width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  background: linear-gradient(150deg, var(--onb-warm), var(--onb-warm-deep));
  color: #fff; font-size: 12px;
  box-shadow: 0 8px 18px -6px rgba(194,116,10,.6);
  animation: onb-pulse 2.6s var(--ease) infinite;
}
.onb-tf-arrow::after { content: "→"; font-size: 18px; font-weight: 700; }
@keyframes onb-pulse {
  0%,100% { transform: scale(1); }
  50%     { transform: scale(1.12); }
}

/* SLIDE 2, the runway: three rungs climbing to the salary prize. */
.onb-map { list-style: none; display: flex; flex-direction: column; gap: 9px; }
.onb-map-row {
  display: flex; align-items: flex-start; gap: 12px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 12px 14px;
}
.onb-map-badge {
  flex-shrink: 0; width: 32px; height: 32px; border-radius: 9px;
  display: grid; place-items: center;
  font-family: var(--display); font-weight: 700; font-size: 14px; color: #fff;
}
/* the climb warms as it rises: trust-blue, to teal, to the amber summit */
.onb-map-badge.a { background: linear-gradient(150deg,#2747A6,#1E3A8A); }
.onb-map-badge.b { background: linear-gradient(150deg,#0EA5E9,#0B6F95); }
.onb-map-badge.c { background: linear-gradient(150deg,var(--onb-warm),var(--onb-warm-deep)); }
.onb-map-text { font-size: 13.5px; line-height: 1.5; color: var(--ink-soft); }
.onb-map-text strong { display: block; color: var(--ink); font-size: 14px; }
/* the prize at the top of the runway, a warm amber card, the summit */
.onb-prize {
  position: relative; margin-top: 11px;
  background: linear-gradient(155deg, var(--onb-warm), var(--onb-warm-deep));
  color: #fff; border-radius: var(--r-lg);
  padding: 18px 16px; text-align: center;
  box-shadow: 0 16px 34px -14px rgba(194,116,10,.6), inset 0 1px 0 rgba(255,255,255,.28);
}
.onb-prize::after {
  content: ""; position: absolute; inset: 0; border-radius: var(--r-lg);
  background: linear-gradient(120deg, rgba(255,255,255,.24), transparent 46%);
  pointer-events: none;
}
.onb-prize-job {
  font-size: 12px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; opacity: .9;
}
.onb-prize-fig {
  font-family: var(--display); font-weight: 700; font-size: clamp(28px,4.6vw,38px);
  line-height: 1.05; margin: 6px 0 3px;
}
.onb-prize-cap { font-size: 12.5px; opacity: .9; }
.onb-prize-line {
  margin-top: 9px; padding-top: 9px; font-size: 13px; font-weight: 600;
  border-top: 1px solid rgba(255,255,255,.28);
}

/* SLIDE 3, the first-win preview: code accepted, ten green checks. */
.onb-win {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 18px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.8);
}
.onb-win-bar {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 12px;
}
.onb-win .code { margin: 0; }
.onb-win-checks {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px;
}
/* a calm growth-green tick, success shown warmly, never as alarm */
.onb-tick {
  width: 27px; height: 27px; border-radius: 7px;
  display: grid; place-items: center;
  background: var(--onb-grow-soft); color: var(--onb-grow);
  font-weight: 700; font-size: 13px;
  transform: scale(0); animation: onb-pop .34s var(--ease) forwards;
}
.onb-tick:nth-child(1){animation-delay:.05s} .onb-tick:nth-child(2){animation-delay:.1s}
.onb-tick:nth-child(3){animation-delay:.15s} .onb-tick:nth-child(4){animation-delay:.2s}
.onb-tick:nth-child(5){animation-delay:.25s} .onb-tick:nth-child(6){animation-delay:.3s}
.onb-tick:nth-child(7){animation-delay:.35s} .onb-tick:nth-child(8){animation-delay:.4s}
.onb-tick:nth-child(9){animation-delay:.45s} .onb-tick:nth-child(10){animation-delay:.5s}
@keyframes onb-pop { to { transform: scale(1); } }
.onb-win-cap {
  margin-top: 12px; font-weight: 700; font-size: 13.5px; color: var(--onb-grow);
  text-align: center;
}

/* the navigation row, Back, progress dots, forward / call-to-action */
.onb-nav {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
}
.onb-dots { display: inline-flex; gap: 8px; }
.onb-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--line-2); transition: width .2s var(--ease), background .2s;
}
.onb-dot.on { width: 22px; border-radius: 999px; background: var(--onb-trust); }
/* the one unmistakable call-to-action, warm amber, the colour of the
   prize, so the eye is pulled to the single obvious next step */
.onb-cta {
  background: linear-gradient(150deg, var(--onb-warm), var(--onb-warm-deep));
  color: #fff;
  box-shadow: 0 12px 26px -8px rgba(194,116,10,.62);
}
.onb-cta:hover { background: var(--onb-warm-deep); }

/* phones, stack the card, keep every control reachable with one thumb */
@media (max-width: 620px) {
  .onb-card { grid-template-columns: 1fr; gap: 22px; padding: 24px; }
  .onb-art { min-height: 0; order: -1; }
  .onb-nav { flex-wrap: wrap; }
  .onb-nav .btn { flex: 1 1 auto; }
  .onb-dots { order: -1; width: 100%; justify-content: center; margin-bottom: 4px; }
}

/* motion-sensitive learners: the aurora rests, the arrow stops
   pulsing, the ticks appear at once. The meaning, promise, runway,
   instant win, is carried entirely by the text and layout, so
   nothing is lost. */
@media (prefers-reduced-motion: reduce) {
  .onb-aurora { animation: none; }
  .onb-tf-arrow { animation: none; }
  .onb-tick { transform: scale(1); animation: none; }
}

/* ============================================================
   REDESIGN, Dawn / First Flight components (2026-05)
   Brand, footer, nav toggle, hero, stage cards, Learn hub,
   lesson links, dashboard. Token-driven; light + dark safe.
   ============================================================ */
.brand-logo{ height:30px; width:auto; display:block; color:var(--ink); }
/* header brand: Udaan wordmark (product) + Shoolini Online co-brand */
.brand{ display:flex; align-items:center; gap:10px; transition:transform .16s var(--ease); }
.brand:hover{ transform:translateY(-1px); }   /* a small lift, home is the launchpad */
.brand-word{ font:700 22px/1 var(--display); letter-spacing:-.01em;
  background:var(--dawn-grad); -webkit-background-clip:text; background-clip:text; color:transparent; }
.brand-co{ height:22px; width:auto; display:inline-block; }
.brand-co.d{ display:none; }
[data-theme="dark"] .brand-co.l{ display:none; }
[data-theme="dark"] .brand-co.d{ display:inline-block; }

/* ===== THE LIVING FOOTER ===== a mood-set "spark" hero + a slim credit strip.
   Each mood sets two accent colours (--m1,--m2) that tint the ✦ glyph, the
   spark's soft glow, and a thin top accent, so the footer's emotional colour
   shifts with the message. Text stays high-contrast for readability. */
.site-footer{ position:relative; border-top:1px solid var(--line); margin-top:8px; padding:22px 0 16px; background:var(--surface-2); overflow:hidden; }
.site-footer .wrap{ text-align:center; }

/* mood palette (defaults = ascend) */
.foot-spark{ --m1:#4F46E5; --m2:#0EA5E9; }
.foot-spark.mood-dawn  { --m1:#F59E0B; --m2:#FB7185; }
.foot-spark.mood-ignite{ --m1:#F97316; --m2:#DB2777; }
.foot-spark.mood-ascend{ --m1:#4F46E5; --m2:#0EA5E9; }
.foot-spark.mood-regroup{ --m1:#0D9488; --m2:#22C55E; }
.foot-spark.mood-cosmic{ --m1:#6366F1; --m2:#A855F7; }
.foot-spark.mood-night { --m1:#475569; --m2:#6366F1; }

.foot-spark{ position:relative; display:inline-flex; align-items:center; gap:9px;
  max-width:760px; margin:0 auto; padding:9px 16px; border-radius:999px;
  background:linear-gradient(90deg, rgba(79,70,229,.05), rgba(14,165,233,.05));
  transition:background .6s var(--ease); }
/* a faint mood-tinted glow behind the spark */
.foot-spark::before{ content:""; position:absolute; inset:-40% -10%; z-index:-1; pointer-events:none;
  background:radial-gradient(60% 120% at 50% 50%, var(--m1), transparent 70%); opacity:.07;
  transition:opacity .6s var(--ease); }
.fs-glyph{ flex:0 0 auto; font-size:15px; line-height:1; font-weight:700;
  background:linear-gradient(90deg,var(--m1),var(--m2)); -webkit-background-clip:text; background-clip:text; color:transparent;
  animation:fs-twinkle 3.6s ease-in-out infinite; }
.fs-text{ font-size:13.5px; line-height:1.5; color:var(--ink); font-weight:500;
  transition:opacity .36s var(--ease); }
.fs-by{ color:var(--ink-faint); font-style:italic; font-weight:600; white-space:nowrap; }
.foot-spark.is-wonder .fs-text{ color:var(--ink-soft); }
.fs-next{ flex:0 0 auto; background:none; border:0; cursor:pointer; color:var(--ink-faint);
  font-size:13px; line-height:1; padding:3px 5px; border-radius:50%; opacity:.55;
  transition:transform .4s var(--ease), opacity .2s, color .2s; }
.fs-next:hover{ opacity:1; color:var(--primary-deep); transform:rotate(180deg); }
.fs-next:focus-visible{ outline:none; box-shadow:var(--ring); opacity:1; }
@keyframes fs-twinkle{ 0%,100%{ opacity:.85; transform:scale(1); } 50%{ opacity:1; transform:scale(1.18); } }

/* brand finale, bigger, centered logo + the proud India lines */
.foot-brand{ margin:18px 0 2px; text-align:center; }
.brand-logo.foot{ height:38px; width:auto; opacity:.95; display:inline-block; margin:0 auto 10px; }
.brand-logo.foot.d{ display:none; }
[data-theme="dark"] .brand-logo.foot.l{ display:none; }
[data-theme="dark"] .brand-logo.foot.d{ display:inline-block; }
.foot-tag{ margin:0; font-size:13px; font-weight:700; color:var(--ink-soft); letter-spacing:.01em; }
.foot-india{ margin:5px 0 0; font-size:15px; font-weight:800; letter-spacing:.01em;
  background:linear-gradient(90deg,#FF9933,#138808); -webkit-background-clip:text; background-clip:text; color:transparent; }
.foot-hash{ -webkit-text-fill-color:initial; color:var(--primary-deep); font-weight:800; }
.foot-rhyme{ margin:6px 0 0; font-size:12.5px; font-style:italic; color:var(--ink-faint); }
/* slim credit strip */
.foot-legal{ margin:12px 0 0; font-size:11.5px; color:var(--ink-faint); line-height:1.6; }
.foot-legal a{ color:inherit; font-weight:600; }
.foot-legal a:hover{ color:var(--primary-deep); }
.foot-author{ text-decoration:none; border-bottom:1px dotted var(--ink-faint); }
.foot-author:hover{ border-bottom-color:var(--primary-deep); }
/* discreet maker's mark at the foot of the Profile page */
.profile-credit{ margin:22px 0 4px; text-align:center; font-size:11.5px; color:var(--ink-faint); }
.profile-credit a{ color:inherit; font-weight:600; border-bottom:1px dotted var(--ink-faint); text-decoration:none; }
.profile-credit a:hover{ color:var(--primary-deep); border-bottom-color:var(--primary-deep); }
.foot-rocket{ background:none; border:0; cursor:pointer; font-size:14px; line-height:1; padding:0 3px;
  vertical-align:middle; opacity:.5; transition:transform .25s var(--ease), opacity .2s; }
.foot-rocket:hover{ opacity:1; transform:translateY(-3px) rotate(-12deg); }
.foot-rocket:active{ transform:translateY(1px) scale(.92); }
.foot-rocket:focus-visible{ outline:none; box-shadow:var(--ring); border-radius:8px; opacity:1; }
@media (prefers-reduced-motion: reduce){
  .fs-glyph{ animation:none; } .fs-next, .foot-rocket{ transition:none; }
  .fs-text{ transition:none; } .foot-spark, .foot-spark::before{ transition:none; }
}
@media (max-width:680px){ .foot-spark{ flex-wrap:wrap; border-radius:16px; } .fs-text{ font-size:13px; } }

/* ---- Learn hub ---- */
.learn-hub{ margin-top:8px; }
/* sticky stage jump-nav, docks just under the app bar, one tap to any stage */
.learn-nav{ position:sticky; top:var(--appbar-h); z-index:20; display:flex; flex-wrap:wrap; gap:8px;
  margin:14px 0 6px; padding:10px 0; background:var(--bg); }
.learn-nav-pill{ display:inline-flex; align-items:center; gap:8px; padding:6px 14px 6px 7px;
  background:var(--surface); border:1px solid var(--line); border-radius:999px; box-shadow:var(--shadow-sm);
  font:700 13px var(--font); color:var(--ink); transition:transform .15s var(--ease), box-shadow .15s var(--ease); }
.learn-nav-pill .stage-badge{ width:24px; height:24px; border-radius:7px; font-size:12px; }
.learn-nav-pill:hover{ transform:translateY(-1px); box-shadow:var(--shadow); }
.learn-nav-pill:focus-visible{ box-shadow:var(--ring); outline:none; }
.learn-section{ scroll-margin-top:calc(var(--appbar-h) + 64px); }
.learn-stage{ margin:24px 0 14px; display:flex; align-items:center; gap:10px; font:700 18px var(--display); color:var(--ink); }
.lesson-row{ display:grid; grid-template-columns:repeat(auto-fill,minmax(248px,1fr)); gap:16px; }
.lesson-card{ position:relative; background:var(--surface); border:1px solid var(--line); border-radius:var(--r-md);
  padding:16px; display:flex; flex-direction:column; gap:8px; box-shadow:var(--shadow-sm);
  transition:transform .2s var(--ease), box-shadow .2s var(--ease); }
.lesson-card:hover{ transform:translateY(-2px); box-shadow:var(--shadow); }
.lesson-card.guide{ background:var(--primary-soft); border-color:transparent; }
/* a block-card reads as a tangible "block": a stage-tinted top edge, a count
   chip, and a progress fill, completion is legible at a glance. */
.block-card{ overflow:hidden; padding-top:18px; }
.block-card::before{ content:""; position:absolute; inset:0 0 auto 0; height:4px; }
.block-card.a::before{ background:linear-gradient(135deg,#0EA5E9,#4F46E5); }
.block-card.b::before{ background:linear-gradient(135deg,#4F46E5,#7C3AED); }
.block-card.c::before{ background:linear-gradient(135deg,#7C3AED,#DB2777); }
.block-card.done{ border-color:var(--ok); background:var(--ok-soft); }
.block-card.done::before{ background:var(--ok); }
.lc-head{ display:flex; align-items:center; justify-content:space-between; gap:8px; }
.lc-count{ font:700 12px var(--mono); color:var(--ink-soft); font-variant-numeric:tabular-nums; }
.lc-count.ok{ color:var(--ok); }
.lc-bar{ height:6px; border-radius:999px; background:var(--surface-3); overflow:hidden; }
.lc-bar i{ display:block; height:100%; border-radius:999px; background:var(--primary);
  transition:width .4s var(--ease); }
.block-card.done .lc-bar i{ background:var(--ok); }
.lc-kind,.lc-block{ font-size:11px; font-weight:700; letter-spacing:.04em; text-transform:uppercase; color:var(--primary-deep); }
.lc-title{ font:600 16px var(--font); color:var(--ink); }
.lc-actions{ display:flex; gap:14px; align-items:center; margin-top:auto; }
/* "Practise" is a quiet trailing link, not a co-equal button, "Read" first,
   then practise. Removes the two-CTA decision tax on each lesson card. */
.lc-practise{ font:600 13px var(--font); color:var(--primary-deep); white-space:nowrap; }
.lc-practise:hover{ text-decoration:underline; }
.lc-practise:focus-visible{ box-shadow:var(--ring); outline:none; border-radius:var(--r-xs); }
@media (prefers-reduced-motion: reduce){ .lesson-card{ transition:none; } }

.theme-toggle{ background:var(--surface-2); border:1px solid var(--line); border-radius:999px;
  width:38px; height:38px; font-size:16px; line-height:1; cursor:pointer; color:var(--ink);
  display:inline-flex; align-items:center; justify-content:center; transition:transform .2s var(--ease); }
.theme-toggle:hover{ transform:translateY(-1px); }
.theme-toggle:focus-visible{ box-shadow:var(--ring); outline:none; }
@media (prefers-reduced-motion: reduce){ .theme-toggle{ transition:none; } }

/* sign-out (power) button in the app bar */
.power-btn{ display:inline-flex; align-items:center; justify-content:center; width:38px; height:38px;
  border-radius:999px; background:var(--surface-2); border:1px solid var(--line); color:var(--ink-soft);
  font-size:16px; line-height:1; text-decoration:none;
  transition:transform .2s var(--ease), color .2s var(--ease), border-color .2s var(--ease); }
.power-btn:hover{ transform:translateY(-1px); color:var(--err); border-color:var(--err); }
.power-btn:focus-visible{ box-shadow:var(--ring); outline:none; }
@media (prefers-reduced-motion: reduce){ .power-btn{ transition:none; } }

/* mini-quest I/O, make "what goes in / what's expected" unmissable */
.mq-io-title{ font-size:12px; font-weight:700; letter-spacing:.03em; text-transform:uppercase;
  color:var(--primary-deep); margin:12px 0 6px; }
.mq-eg .io-k{ display:inline-block; min-width:120px; color:var(--ink-faint); font-weight:700;
  text-transform:uppercase; font-size:10px; letter-spacing:.04em; }
.mq-tcase{ border:1px solid var(--line); border-radius:var(--r-sm); padding:8px 10px; margin-bottom:8px; }
.mq-tcase.ok{ border-left:3px solid var(--ok); }
.mq-tcase.bad{ border-left:3px solid var(--accent); }
.mq-io{ margin-top:6px; display:flex; flex-direction:column; gap:3px; font-size:13px; }
.mq-io > div{ display:flex; gap:8px; align-items:baseline; }
.mq-io .io-k{ min-width:78px; color:var(--ink-faint); font-weight:700; text-transform:uppercase;
  font-size:10px; letter-spacing:.04em; }
.mq-io code{ font-family:var(--mono); font-size:12.5px; background:var(--surface-2);
  padding:1px 6px; border-radius:6px; color:var(--ink); white-space:pre-wrap; word-break:break-word; }
.mq-io code.io-bad{ background:var(--err-soft); color:var(--err); }
.mq-io.err{ color:var(--err); font-size:13px; }

/* dashboard insight tiles */
.statgrid.insight .stat{ position:relative; cursor:default; }
.statgrid.insight .stat-ic{ font-size:20px; line-height:1; margin-bottom:4px; }
.stat-why{ margin-top:8px; font-size:11px; line-height:1.4; color:var(--ink-faint); }
.insight-coherence{ text-align:center; color:var(--ink-faint); font-size:12px; margin:12px 0 0; }

/* evidence-based feedback card: real strength · next focus · how to improve */
.insight-card{ background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
  padding:18px 20px; margin-top:18px; display:flex; flex-direction:column; gap:12px; box-shadow:var(--shadow-sm); }
.insight-card.forming{ background:var(--primary-soft); border-color:transparent; color:var(--ink); font-size:14px; }
.ins-row{ display:flex; gap:14px; align-items:baseline; flex-wrap:wrap; }
.ins-k{ flex:0 0 168px; font-weight:700; font-size:13px; display:inline-flex; gap:6px; align-items:center; }
.ins-k.s-strong{ color:var(--ok); }
.ins-k.s-focus{ color:var(--warn); }
.ins-k.s-how{ color:var(--primary-deep); }
.ins-v{ flex:1; min-width:180px; color:var(--ink); font-size:14px; }
@media (max-width:560px){ .ins-k{ flex-basis:100%; } }

/* "Why this matters" disclosure, a native <details> per insight tile.
   Native so it is keyboard-focusable and screen-reader-announced with no
   extra ARIA, and works under our strict CSP. Styling is pure polish; the
   affordance is fully usable with none of it. */
.stat-why-d{ margin-top:8px; }
.stat-why-sum{ display:inline-flex; align-items:center; gap:5px; cursor:pointer;
  font-size:11px; font-weight:700; letter-spacing:.02em; color:var(--primary-deep);
  list-style:none; border-radius:var(--r-xs); padding:2px 4px; margin:-2px -4px;
  transition:background .15s var(--ease); }
.stat-why-sum::-webkit-details-marker{ display:none; }
.stat-why-sum::before{ content:"›"; display:inline-block; font-weight:700;
  transition:transform .15s var(--ease); }
.stat-why-d[open] .stat-why-sum::before{ transform:rotate(90deg); }
.stat-why-sum:hover{ background:var(--primary-soft); }
.stat-why-sum:focus-visible{ box-shadow:var(--ring); outline:none; }
.stat-why-body{ margin-top:6px; }
.stat-why-body p{ margin:0 0 6px; font-size:11px; line-height:1.45; color:var(--ink-soft); }
.stat-why-body p:last-child{ margin-bottom:0; }
.sw-action .sw-k{ font-weight:700; color:var(--primary-deep); }
.sw-evidence{ font-style:italic; color:var(--ink-faint) !important; }

/* "Dive deeper" disclosure on the Analysis page, folds the secondary
   calibration + self-reliance cards away so the main page stays focused.
   Native <details>, so keyboard- and screen-reader-accessible by default. */
.dig-deeper > summary{ display:inline-flex; align-items:center; gap:6px; cursor:pointer;
  font:700 15px var(--display,var(--font)); color:var(--primary-deep);
  list-style:none; border-radius:var(--r-xs); padding:2px 4px; margin:-2px -4px; }
.dig-deeper > summary::-webkit-details-marker{ display:none; }
.dig-deeper > summary::before{ content:"›"; display:inline-block; font-weight:700;
  transition:transform .15s var(--ease); }
.dig-deeper[open] > summary::before{ transform:rotate(90deg); }
.dig-deeper > summary:focus-visible{ box-shadow:var(--ring); outline:none; }

/* a tile shown as a model estimate, a calm dashed border signals "not a
   guarantee" without alarm */
.statgrid.insight .stat.stat-est{ border-style:dashed; }
/* the small "still calibrating" caveat under an estimate tile's value */
.statgrid.insight .stat-est-note{ margin-top:6px; font-size:10px; line-height:1.35;
  font-style:italic; color:var(--ink-faint); }

/* the small "estimate" tag beside the Exam-readiness chart title */
.est-tag{ display:inline-block; margin-left:8px; vertical-align:middle;
  font-size:10px; font-weight:700; letter-spacing:.04em; text-transform:uppercase;
  color:var(--warn); background:var(--warn-soft); border-radius:999px; padding:2px 9px;
  cursor:help; }
.est-tag:focus-visible{ box-shadow:var(--ring); outline:none; }
@media (prefers-reduced-motion: reduce){
  .stat-why-sum, .stat-why-sum::before{ transition:none; }
}

/* XP → unlock panel: points tied to a concrete reward, never decoration.
   Lives on the dashboard hero, below the insight tiles. */
.xpu{ background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
  padding:16px 18px; margin-top:18px; box-shadow:var(--shadow-sm); }
.xpu-next{ display:flex; align-items:center; gap:10px; font:700 15px var(--display); color:var(--ink); }
.xpu-ic{ font-size:20px; line-height:1; }
.xpu-chips{ display:flex; flex-wrap:wrap; gap:8px; margin-top:12px; }
.xpu-chip{ display:inline-flex; align-items:center; gap:5px; font-size:12px; font-weight:600;
  border-radius:999px; padding:5px 11px; border:1px solid var(--line);
  background:var(--surface-2); color:var(--ink-faint); }
.xpu-chip.on{ background:var(--ok-soft); color:var(--ok); border-color:transparent; }
.xpu-why{ margin:12px 0 0; font-size:12px; line-height:1.45; color:var(--ink-faint); }

/* ---- Hero + 3-stage spine ---- */
.hero{ background:radial-gradient(1200px 420px at 72% -12%, var(--accent-soft), transparent 60%); }
.hero-h1{ font:700 clamp(34px,6vw,60px)/1.04 var(--display); letter-spacing:-.02em; max-width:15ch; }
.hero-h1 .grad{ background:var(--dawn-grad); -webkit-background-clip:text; background-clip:text; color:transparent; }
.hero-lead{ font-size:clamp(16px,2.2vw,20px); color:var(--ink-soft); max-width:54ch; }
.stage-cards{ display:grid; grid-template-columns:repeat(3,1fr); gap:16px; margin-top:30px; }
@media (max-width:760px){ .stage-cards{ grid-template-columns:1fr; } }
.stage-card{ position:relative; background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
  padding:20px; display:flex; flex-direction:column; gap:6px; box-shadow:var(--shadow-sm);
  transition:transform .2s var(--ease), box-shadow .2s var(--ease); }
.stage-card:hover{ transform:translateY(-3px); box-shadow:var(--shadow-lg); }
.stage-card:focus-visible{ box-shadow:var(--ring); outline:none; }
.sc-num{ font:700 14px var(--mono); color:var(--accent); }
.sc-ring{ --p:0; width:64px; height:64px; border-radius:50%; display:grid; place-items:center; margin:4px 0;
  background:conic-gradient(var(--primary) calc(var(--p)*1%), var(--surface-3) 0); }
.sc-ring span{ width:50px; height:50px; border-radius:50%; background:var(--surface); display:grid; place-items:center;
  font:700 13px var(--font); color:var(--ink); }
.sc-name{ font:700 20px var(--display); color:var(--ink); }
.sc-tag{ color:var(--ink-soft); font-size:14px; }
.sc-range{ margin-top:auto; font-size:12px; font-weight:600; color:var(--ink-faint); }
/* plain-language intro above the cards, tells learners what the row is + to tap */
.stage-cards-head{ text-align:center; max-width:640px; margin:64px auto 0; }
.stage-cards-head h2{ font:700 clamp(20px,2.6vw,26px) var(--display); color:var(--ink); margin:0 0 7px; }
.stage-cards-head p{ color:var(--ink-soft); font-size:14.5px; line-height:1.55; margin:0; }
/* the newcomer call-to-action, loud + glowing so a skimmer cannot miss it */
.stage-start-cta{ display:inline-flex; align-items:center; gap:8px; margin-top:16px;
  font:800 15px var(--font); color:#fff; background:var(--dawn-grad);
  border-radius:999px; padding:11px 22px; box-shadow:var(--shadow);
  animation:cta-pulse 2.6s ease-in-out infinite;
  transition:transform .15s var(--ease), gap .15s var(--ease); }
.stage-start-cta:hover{ transform:translateY(-2px); gap:11px; }
.stage-start-cta:focus-visible{ outline:none; box-shadow:var(--ring); }
/* "build your foundations first" course-correction, a warm guiding tone so it
   reads as help (go learn this), not as a generic start button */
.stage-start-cta.sca-fix{ background:linear-gradient(135deg,#F59E0B,#FB7185); }
@keyframes cta-pulse{ 0%,100%{ box-shadow:var(--shadow); }
  50%{ box-shadow:0 0 0 7px rgba(99,102,241,.16), var(--shadow); } }
/* the per-card call-to-action, a pill that makes "this is tappable" obvious */
.sc-go{ margin-top:13px; align-self:flex-start; display:inline-flex; align-items:center; gap:6px;
  font:700 13px var(--font); color:#fff; background:var(--primary); border-radius:999px;
  padding:8px 15px; transition:gap .15s var(--ease), background .15s var(--ease); }
.stage-card:hover .sc-go{ gap:10px; background:var(--primary-deep); }
@media (prefers-reduced-motion: reduce){ .stage-card{ transition:none; } }

/* ---- lesson<->coding interweave link ---- */
.lesson-link{ display:inline-flex; align-items:center; gap:9px; background:var(--primary-soft);
  color:var(--primary-deep); border-radius:999px; padding:10px 18px; font-weight:600; font-size:14px;
  line-height:1.25; border:1px solid transparent; transition:transform .15s var(--ease); }
.lesson-link .ll-ic{ flex:0 0 auto; font-size:15px; line-height:1; }
.lesson-link:hover{ transform:translateY(-1px); }
.lesson-link:focus-visible{ box-shadow:var(--ring); outline:none; }
/* the lesson door is now a <button> (opens a modal, no navigation); reset the UA
   button chrome so it looks identical to the old <a> chip. */
button.lesson-link{ appearance:none; -webkit-appearance:none; border:0; font:inherit; color:inherit; cursor:pointer; text-align:left; }
@media (prefers-reduced-motion: reduce){ .lesson-link{ transition:none; } }
/* Profile → Guides: stack the standalone guide links; each is full-width on phones */
.guide-links{ display:flex; flex-wrap:wrap; gap:10px; margin-top:10px; }
@media (max-width:680px){ .guide-links{ flex-direction:column; } .guide-links .lesson-link{ width:100%; } }

/* ---- adaptive pathway (Practice) ---- */
.pathway-summary{ font:600 15px var(--font); color:var(--ink-soft); margin:28px 0 16px;
  display:flex; align-items:center; gap:8px; }
.struggle-card{ background:var(--accent-soft); border:1px solid var(--line); border-left:4px solid var(--accent);
  border-radius:var(--r-md); padding:16px; margin:0 0 28px; }
/* the runway focus, Block A is the journey's start; this card keeps the eyes
   there until the foundations are cleared. Warm, aspirational, never a scold. */
.focus-card{ position:relative; overflow:hidden; border-radius:var(--r-lg);
  border:1px solid var(--line); border-left:4px solid #0EA5E9;
  background:linear-gradient(135deg, var(--primary-soft) 0%, var(--surface) 62%);
  padding:18px 20px; margin:0 0 28px; box-shadow:var(--shadow-sm); }
.fc-eyebrow{ font:700 11px var(--font); letter-spacing:.06em; text-transform:uppercase; color:var(--primary-deep); }
.fc-title{ font:700 19px var(--display); color:var(--ink); margin-top:4px; }
.fc-sub{ color:var(--ink-soft); font-size:14px; line-height:1.55; margin-top:6px; max-width:62ch; }
.fc-bar{ height:7px; border-radius:999px; background:var(--surface-3); overflow:hidden; margin-top:14px; }
.fc-bar i{ display:block; height:100%; border-radius:999px; background:linear-gradient(90deg,#0EA5E9,#4F46E5);
  transition:width .4s var(--ease); }
.fc-meta{ font:600 12px var(--mono); color:var(--ink-soft); margin-top:8px; font-variant-numeric:tabular-nums; }
.fc-actions{ display:flex; flex-wrap:wrap; gap:10px; margin-top:14px; }
.struggle-card .sc-h{ font:700 16px var(--display); color:var(--ink); }
.struggle-card .sc-why{ color:var(--ink-soft); margin-top:6px; font-size:14px; }
.struggle-card .sc-note{ color:var(--ink-soft); margin-top:8px; font-size:13px; font-style:italic; }
.blk-status{ font-size:10px; font-weight:700; letter-spacing:.02em; margin-left:6px; opacity:.95; }
.block.blk-mastered{ border-color:var(--ok); }
.block.blk-mastered .blk-status{ color:var(--ok); }
.block.blk-active{ border-color:var(--primary); box-shadow:0 0 0 2px var(--primary-soft); }
.block.blk-active .blk-status{ color:var(--primary-deep); }
.block.blk-needs-practice{ border-color:var(--accent); }
.block.blk-needs-practice .blk-status{ color:var(--warn); }
.block.blk-locked{ opacity:.62; }
.block.blk-locked .blk-status{ color:var(--ink-faint); }

/* ---- onboarding taste chips ---- */
.onb-prefs{ display:flex; flex-direction:column; gap:10px; text-align:left; width:100%; }
.onb-q{ font:600 15px var(--font); color:var(--ink); margin-top:6px; }
.chip-pick{ display:flex; flex-wrap:wrap; gap:8px; }
.chip-pick .pick{ border:1.5px solid var(--line-2); background:var(--surface); color:var(--ink);
  border-radius:999px; padding:8px 14px; font-weight:600; font-size:14px; cursor:pointer;
  transition:transform .12s var(--ease), border-color .12s var(--ease), background .12s var(--ease); }
.chip-pick .pick:hover{ transform:translateY(-1px); }
.chip-pick .pick:focus-visible{ box-shadow:var(--ring); outline:none; }
.chip-pick .pick.sel{ border-color:var(--primary); background:var(--primary-soft); color:var(--primary-deep); }
@media (prefers-reduced-motion: reduce){ .chip-pick .pick{ transition:none; } }

/* ---- W3: the type-along warm-up slide ---- */
.onb-type{ width:100%; text-align:left; }
.onb-type-list{ list-style:none; margin:0 0 12px; padding:0; display:flex; flex-direction:column; gap:8px; }
.onb-type-row{ display:flex; align-items:center; gap:11px; padding:8px 10px; border-radius:10px;
  background:var(--surface); border:1px solid var(--line-2); transition:opacity .2s var(--ease); }
.onb-type-row.todo{ opacity:.5; }
.onb-type-row.active{ border-color:var(--primary); background:var(--primary-soft); }
.onb-type-row.done{ opacity:1; }
.onb-type-k{ flex:none; width:24px; height:24px; border-radius:7px; display:inline-flex;
  align-items:center; justify-content:center; font:700 12px var(--mono); background:var(--surface-3); color:var(--ink-soft); }
.onb-type-row.done .onb-type-k{ background:var(--primary); color:#fff; }
.onb-type-b{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.onb-type-lbl{ font-size:12px; color:var(--ink-soft); }
.onb-type-target{ font:600 14px var(--mono); color:var(--ink); word-break:break-all; }
.onb-type-tab{ display:inline-block; min-width:20px; padding:0 5px; margin-right:4px; border-radius:5px;
  background:var(--surface-3); color:var(--primary-deep); font-weight:700; text-align:center; }

.onb-type-entry{ display:flex; flex-direction:column; gap:6px; }
.onb-type-elbl{ font-size:12.5px; color:var(--ink-soft); }
.onb-type-in{ width:100%; box-sizing:border-box; border:1.5px solid var(--line-2); border-radius:10px;
  background:var(--surface); color:var(--ink); padding:11px 13px; font:600 15px var(--mono);
  transition:border-color .12s var(--ease), box-shadow .12s var(--ease); }
.onb-type-in:focus{ outline:none; border-color:var(--primary); box-shadow:var(--ring); }
.onb-type-in.ok{ border-color:var(--primary); background:var(--primary-soft); }
.onb-type-in.err{ border-color:var(--warn); }
.onb-type-tip{ margin:2px 0 0; font-size:12.5px; color:var(--ink-soft); }
.onb-type-skip{ align-self:flex-start; margin-top:4px; background:none; border:none; padding:4px 0;
  color:var(--ink-soft); text-decoration:underline; font-size:12.5px; cursor:pointer; }
.onb-type-skip:focus-visible{ outline:2px solid var(--primary); outline-offset:2px; }
.onb-type-win{ display:flex; align-items:center; gap:10px; padding:14px 16px; border-radius:12px;
  background:var(--primary-soft); color:var(--ink); font-weight:600; font-size:14.5px; line-height:1.5; }
.onb-type-win-ic{ font-size:22px; line-height:1; }
.onb-type-first .onb-type-win{ animation:udaan-lift .4s var(--ease) both; }
@media (prefers-reduced-motion: reduce){
  .onb-type-row, .onb-type-in{ transition:none; }
  .onb-type-first .onb-type-win{ animation:none; }
}

/* ---- W3: the ungraded number-sense diagnostic ---- */
.onb-num{ width:100%; text-align:left; }
.onb-num-prog{ font:700 10px/1 var(--mono); letter-spacing:.12em; text-transform:uppercase;
  color:var(--ink-soft); margin-bottom:8px; }
.onb-num-q{ font:600 15.5px/1.5 var(--font); color:var(--ink); margin-bottom:12px; }
.onb-num-choices{ display:flex; flex-direction:column; gap:9px; }
.onb-num-choice{ text-align:left; padding:11px 14px; border:1.5px solid var(--line-2); border-radius:11px;
  background:var(--surface); color:var(--ink); font:600 15px var(--mono); cursor:pointer;
  transition:border-color .12s var(--ease), background .12s var(--ease); }
.onb-num-choice:hover:not(:disabled){ border-color:var(--primary); }
.onb-num-choice:focus-visible{ outline:none; box-shadow:var(--ring); }
.onb-num-choice:disabled{ cursor:default; }
.onb-num-choice.right{ border-color:var(--ok,#2FAE66); background:var(--ok-soft,#E7F6EC); color:var(--ink); }
.onb-num-choice.wrong{ border-color:var(--warn); background:var(--surface-3); }
.onb-num-reveal{ margin-top:4px; }
.onb-num-why{ margin-top:12px; padding:12px 14px; border-radius:11px; background:var(--surface-3);
  color:var(--ink-soft); font-size:13.5px; line-height:1.55; }
.onb-num-why.good{ background:var(--ok-soft,#E7F6EC); }
.onb-num-why strong{ color:var(--ink); }
.onb-num-done{ display:flex; flex-direction:column; align-items:flex-start; gap:10px; padding:14px 16px;
  border-radius:12px; background:var(--primary-soft); color:var(--ink); font-size:14px; line-height:1.55; }
.onb-num-done-ic{ font-size:24px; line-height:1; }
.onb-num-done p{ margin:0; }
[data-theme="dark"] .onb-num-choice.right, [data-theme="dark"] .onb-num-why.good{ background:#14301F; }
@media (prefers-reduced-motion: reduce){ .onb-num-choice{ transition:none; } }

/* ---- personalized dashboard hero ---- */
.dash-hero{ background:radial-gradient(1200px 420px at 28% -12%, var(--primary-soft), transparent 60%); }
.dash-nudge{ margin-top:16px; display:flex; align-items:flex-start; gap:10px;
  background:var(--accent-soft); color:var(--ink); border-radius:var(--r-md);
  padding:12px 16px; font-weight:600; font-size:14px; line-height:1.55; }
.dash-nudge .dn-ic{ flex:0 0 auto; line-height:1.55; }

/* ---- gentle "lift" when a result/verdict appears ---- */
@keyframes udaan-lift{ 0%{ transform:translateY(6px); opacity:0; } 100%{ transform:translateY(0); opacity:1; } }
.lift-in{ animation:udaan-lift .4s var(--ease) both; }
@media (prefers-reduced-motion: reduce){ .lift-in{ animation:none; } }

/* ============================================================
   Wave-2, Today's plan, exam simulation, Socratic hint.
   All polish; each surface stays fully usable with none of it.
   CSP-safe (no inline style/script), keyboard- and SR-friendly.
   ============================================================ */

/* ---- Today's plan: an ordered, performance-driven list of steps ---- */
.plan{ display:flex; flex-direction:column; gap:12px; margin-top:18px; }
.plan-item{ background:var(--surface); border:1px solid var(--line); border-left:4px solid var(--primary);
  border-radius:var(--r-md); padding:14px 16px; box-shadow:var(--shadow-sm);
  display:flex; flex-direction:column; gap:8px; }
/* the colored spine encodes the kind of step at a glance, never by color alone
   (the kind chip carries the word too) */
.plan-item.k-next{ border-left-color:var(--primary); }
.plan-item.k-review{ border-left-color:var(--accent); }
.plan-item.k-shore-up{ border-left-color:var(--warn); }
.plan-item.k-simulate{ border-left-color:var(--ok); }
.plan-item-top{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.plan-kind{ display:inline-flex; align-items:center; gap:5px; font-size:11px; font-weight:700;
  letter-spacing:.03em; text-transform:uppercase; border-radius:999px; padding:3px 10px;
  background:var(--surface-2); color:var(--ink-faint); border:1px solid var(--line); }
.plan-item.k-next .plan-kind{ background:var(--primary-soft); color:var(--primary-deep); border-color:transparent; }
.plan-item.k-review .plan-kind{ background:var(--accent-soft); color:var(--ink); border-color:transparent; }
.plan-item.k-shore-up .plan-kind{ background:var(--warn-soft); color:var(--warn); border-color:transparent; }
.plan-item.k-simulate .plan-kind{ background:var(--ok-soft); color:var(--ok); border-color:transparent; }
.plan-title{ font:700 16px var(--display); color:var(--ink); flex:1; min-width:0; }
.plan-cta{ flex:0 0 auto; white-space:normal; }
/* on phones the CTA label (e.g. "Open problem 26 in 'Conditionals'") is long, 
   give it the full row and let it wrap instead of forcing horizontal overflow */
@media (max-width:680px){ .plan-item-top .plan-cta{ flex:1 1 100%; max-width:100%; text-align:center; } }
/* the plan reuses the Wave-1 "Why this matters" disclosure verbatim
   (.stat-why-d / .stat-why-sum / .stat-why-body), so nothing new is needed
   for the why/evidence/action body. */

/* the honest exam-ready gate, never a fake 100% */
.examgate{ background:var(--primary-soft); border:1px solid transparent; border-radius:var(--r-lg);
  padding:16px 18px; margin-top:18px; display:flex; flex-direction:column; gap:10px; }
.examgate-h{ font:700 16px var(--display); color:var(--ink); display:flex; align-items:center; gap:8px; }
.examgate-h .examgate-n{ background:var(--surface); color:var(--primary-deep); border-radius:999px;
  padding:1px 10px; font:700 14px var(--font); }
.examgate-list{ display:flex; flex-direction:column; gap:6px; margin:0; padding:0; list-style:none; }
.examgate-list li{ display:flex; align-items:center; gap:8px; font-size:14px; color:var(--ink); }
.examgate-list li::before{ content:"○"; color:var(--primary-deep); font-weight:700; }
.examgate-note{ font-size:12px; line-height:1.45; color:var(--ink-faint); font-style:italic; margin:0; }
/* readiness bar, leads with how-close-you-are, not a wall of what's-missing */
.examgate-bar{ height:8px; border-radius:999px; background:var(--surface); overflow:hidden; }
.examgate-bar > i{ display:block; height:100%; border-radius:999px;
  background:linear-gradient(90deg,var(--primary),var(--primary-deep)); transition:width .4s var(--ease); }
.examgate-cue{ margin:0; font:700 13px var(--font); color:var(--ink-soft); }
.examgate-more > summary{ cursor:pointer; font:600 13px var(--font); color:var(--primary-deep);
  list-style:none; padding:2px 0; }
.examgate-more > summary::-webkit-details-marker{ display:none; }
.examgate-more > summary::before{ content:"›"; display:inline-block; margin-right:5px; font-weight:700;
  transition:transform .15s var(--ease); }
.examgate-more[open] > summary::before{ transform:rotate(90deg); }
.examgate-more > summary:focus-visible{ box-shadow:var(--ring); outline:none; border-radius:var(--r-xs); }
.examgate-more .examgate-list{ margin-top:8px; }
/* MEASURED state (audit #5 / gap G): once a real outcome is logged the gate is
   no longer an estimate. A small chip names the evidence; a left accent marks
   the card as measured-fact, not a model guess. */
.examgate-measured{ display:inline-flex; align-items:center; font:700 11px var(--font);
  text-transform:uppercase; letter-spacing:.04em; padding:2px 9px; border-radius:999px;
  background:var(--ok-soft); color:var(--ok); border:1px solid #C9E9D4; }
.examgate.examgate-is-measured{ border-left:3px solid var(--ok); }
.examgate.examgate-is-measured .examgate-note{ font-style:normal; color:var(--ink-soft); }
/* the exam-ready OUTCOME ASK: a calm, dismissible invite to log a real result,
   shown only at exam-ready and never once measured (no-nag). */
.examgate-ask{ background:var(--surface); border:1px dashed var(--line); border-radius:var(--r-md);
  padding:12px 14px; display:flex; flex-direction:column; gap:8px; }
.examgate-ask .oask-t{ font:700 14px var(--display); color:var(--ink); }
.examgate-ask .oask-sub{ font-size:13px; line-height:1.45; color:var(--ink-soft); }
.examgate-ask .oask-row{ display:flex; gap:10px; flex-wrap:wrap; }
.examgate-ask .oask-done{ font-size:13px; color:var(--ink-soft); font-style:italic; }
/* OPTIMAL-COMPLEXITY advisory (audit #7): an honest, non-punitive cue on the
   problems that authored an `optimal`; sits on the .note base with an amber
   accent (a nudge toward the efficient approach, never a warning/penalty). */
.note.optimal-advisory{ background:var(--warn-soft); border-color:#EFD9AE; }
.note.optimal-advisory .nt{ color:var(--warn); }

/* ---- timed exam simulation ---- */
.sim-bar{ position:sticky; top:0; z-index:5; display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-md);
  padding:12px 16px; box-shadow:var(--shadow-sm); margin-bottom:16px; }
.sim-clock{ font:700 22px var(--mono); color:var(--ink); display:inline-flex; align-items:center; gap:8px;
  font-variant-numeric:tabular-nums; }
.sim-clock .sim-ic{ font-size:18px; }
/* a calm-then-urgent clock: under a minute it warms to the warn color, with a
   gentle pulse that reduced-motion users never see */
.sim-clock.warn{ color:var(--warn); }
.sim-clock.warn .sim-ic{ animation:sim-pulse 1s steps(2,start) infinite; }
@keyframes sim-pulse{ 50%{ opacity:.35; } }
@media (prefers-reduced-motion: reduce){ .sim-clock.warn .sim-ic{ animation:none; } }
.sim-progress{ font-size:13px; font-weight:600; color:var(--ink-soft); }
.sim-list{ display:flex; flex-direction:column; gap:10px; }
.sim-q{ background:var(--surface); border:1px solid var(--line); border-radius:var(--r-md);
  padding:14px 16px; display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  transition:transform .15s var(--ease), box-shadow .15s var(--ease); }
.sim-q:hover{ transform:translateY(-1px); box-shadow:var(--shadow-sm); }
@media (prefers-reduced-motion: reduce){ .sim-q{ transition:none; } }
.sim-q.done{ border-color:var(--ok); }
.sim-q-n{ font:700 13px var(--mono); color:var(--accent); flex:0 0 auto; }
.sim-q-title{ font:600 15px var(--font); color:var(--ink); flex:1; min-width:0; }
.sim-foot{ display:flex; align-items:center; gap:12px; margin-top:18px; }

/* the simulation result + AI debrief */
.sim-result{ background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
  padding:20px; box-shadow:var(--shadow-sm); }
.sim-debrief{ margin-top:16px; }
.sim-debrief .coach-verify{ margin-top:10px; font-size:12px; color:var(--ink-faint); font-style:italic; }
/* per-weak-topic drill in the debrief (W5B), "sharpen this before next time" */
.sim-drill{ margin-top:18px; padding-top:16px; border-top:1px solid var(--line); }
.sim-drill .sd-head{ font:700 15px var(--display); color:var(--ink); }
.sim-drill .sd-sub{ margin:4px 0 12px; font-size:13px; line-height:1.45; color:var(--ink-soft); }

/* ---- adventurous-journey cursor: a launch rocket over the code panels ----
   The whole app is उड़ान, takeoff, so the mouse becomes a launch rocket when it
   hovers a code panel. Scoped to the READ-ONLY code displays (`pre.code`: the
   examples, reference solutions, lesson snippets) ONLY, the live editor's text
   cursor, caret, selection and the editable textareas are left fully NATIVE and
   undisturbed. Self-contained data-URI SVG (CSP-safe under img-src data:),
   legible on the light code panels; falls back to `auto`. */
:root{
  --rocket-cursor: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'><g stroke='%2310203f' stroke-width='1.4' stroke-linejoin='round'><path d='M16 2C21 7 23 14 23 20l0 5-14 0 0-5C9 14 11 7 16 2Z' fill='%23eef2fb'/><path d='M16 2c3 4 4.6 8 5.3 11.5l-10.6 0C11.4 10 13 6 16 2Z' fill='%23ef4444'/><circle cx='16' cy='15.5' r='3.1' fill='%235aa9e6' stroke-width='1'/><path d='M9 20 4 27 9 24.6Z' fill='%23ef4444'/><path d='M23 20 28 27 23 24.6Z' fill='%23ef4444'/><path d='M12.6 24.6 16 31 19.4 24.6Z' fill='%23ffb13b' stroke='none'/></g></svg>") 16 2;
}
pre.code{ cursor: var(--rocket-cursor), auto; }
/* ---- worked-example "bomb" cursor: detonate a case to fetch the next one ----
   A worked example / test-case block can be DETONATED to reveal the next case
   (see UdaanCaseBlast). Over such a block the mouse becomes a lit bomb so the
   afford­ance reads instantly. Same self-contained data-URI SVG treatment as
   --rocket-cursor (CSP-safe under img-src data:), legible on the light code
   panels; falls back to `pointer`. The case block carries `.case-code`, so this
   wins over the inherited rocket cursor on those blocks only. */
:root{
  --bomb-cursor: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 32 32'><g stroke='%2310203f' stroke-width='1.3' stroke-linejoin='round'><circle cx='15' cy='20' r='9' fill='%231f2430'/><circle cx='12' cy='17' r='2.4' fill='%23596073' stroke='none'/><path d='M21 12l3-3' stroke='%2310203f' stroke-width='2.2' fill='none' stroke-linecap='round'/><path d='M23 9l2.4-1.2' stroke='%23c9a227' stroke-width='2.2' fill='none' stroke-linecap='round'/></g><g stroke='none'><path d='M25.4 7.8c1.6-.6 3 .4 2.6 1.9-.3 1.2-1.9 1.5-2.6.4-.3-.5-.8-.6-1.3-.3' fill='%23ffb13b'/><circle cx='27' cy='7' r='1.8' fill='%23ff5b2e'/><circle cx='27' cy='6.6' r='.9' fill='%23fff0b8'/></g></svg>") 15 20;
}
pre.code.case-code{ cursor: var(--bomb-cursor), pointer; }
/* a single, non-revealable example: a calm reading box, never the rocket
   cursor (which only belongs on the reference solution) and never the bomb
   (there is nothing more to blast). */
pre.code.case-static{ cursor: text; }
/* keyboard parity: the box is the control, so it earns a visible focus ring. */
pre.code.case-code:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(255,122,69,.5); border-radius:8px; }
/* the idle-hover nudge ("psst… click and see"), shared by the case box (💣)
   and the reference-solution box (🚀). Hidden until the pointer rests in the
   box (.on, added by wireIdleHint) or the reveal is exhausted (.done). */
.casebox{ position:relative; }
.case-hint{
  margin:7px 0 2px; font-size:12.5px; font-weight:600; color:var(--ink-soft);
  opacity:0; transform:translateY(-3px); pointer-events:none;
  transition:opacity .2s ease, transform .2s ease;
}
.case-hint.on{ opacity:1; transform:translateY(0); }
.case-hint.done{ opacity:1; transform:none; color:var(--primary); }
.sol-hint{ margin-top:8px; }
@media (prefers-reduced-motion: reduce){ .case-hint{ transition:none; } }
/* ✨ reference-solution rocket cinematic, fly-to-editor, burst into code,
   shard-to-Run. All fixed-position overlays + transform/opacity, GPU-cheap. */
.rk-fly,.rk-shard{ position:fixed; z-index:9999; width:32px; height:32px; margin:-16px 0 0 -16px;
  font-size:30px; line-height:32px; text-align:center; pointer-events:none;
  filter:drop-shadow(0 5px 12px rgba(0,0,0,.45)); }
.rk-frag{ position:fixed; z-index:9998; width:8px; height:8px; margin:-4px 0 0 -4px; border-radius:2px;
  pointer-events:none; background:var(--primary); box-shadow:0 0 9px var(--primary); }
.ed-slam{ animation:ed-slam .55s var(--ease); }
@keyframes ed-slam{ 0%{ box-shadow:0 0 0 4px var(--primary), 0 0 32px var(--primary); filter:brightness(1.25); }
  100%{ box-shadow:none; filter:none; } }
.run-hit{ animation:run-hit .42s var(--ease); }
@keyframes run-hit{ 0%,100%{ transform:none; } 35%{ transform:scale(1.13); box-shadow:0 0 0 7px rgba(99,102,241,.32); } }

/* ---- Socratic hint: a thinking nudge, never the solution ---- */
.nudge{ background:var(--accent-soft); border:1px solid transparent; border-left:4px solid var(--accent);
  border-radius:var(--r-md); padding:14px 16px; margin-top:12px; }
.nudge-h{ font:700 14px var(--display); color:var(--ink); display:flex; align-items:center; gap:8px; }
.nudge-body{ margin-top:6px; font-size:14px; line-height:1.5; color:var(--ink); }
.nudge-foot{ margin:8px 0 0; font-size:11px; line-height:1.4; color:var(--ink-faint); font-style:italic; }
/* the hint button sits disabled until the learner has run code at least once,
   exactly like the AI-feedback gate; the disabled state explains why on hover
   and to a screen reader via its title/aria-disabled. */
#hintNudgeBtn[disabled]{ opacity:.55; cursor:not-allowed; }

/* language-bridge hint (W5B), a quiet, table-driven "same idea, new
   language" note shown when the active language differs from the learner's
   most-used solved language. Calm and informative, never alarming. */
.lang-bridge{ background:var(--info-soft); border:1px solid var(--info); border-radius:var(--r-md);
  padding:12px 14px; margin:10px 0 4px; }
.lang-bridge .lb-h{ font:700 13px var(--display); color:var(--ink); display:flex; align-items:center; gap:7px; }
.lang-bridge .lb-lead{ margin:5px 0 9px; font-size:12.5px; line-height:1.45; color:var(--ink-soft); }
/* fully self-defined so the GENERIC .lb-row (the leaderboard's flex/bg/radius)
   can never bleed in: a stacked, transparent, comfortably-padded row. */
.lang-bridge .lb-row{ display:block; background:transparent; border:0;
  border-top:1px solid var(--info); border-radius:0; padding:10px 2px; }
.lang-bridge .lb-row:first-of-type{ border-top:none; padding-top:2px; }
.lang-bridge .lb-k{ font-weight:700; font-size:12px; color:var(--ink); margin-bottom:6px; }
.lang-bridge .lb-v{ font-size:12.5px; line-height:1.55; color:var(--ink-soft); margin:4px 0; }
.lang-bridge .lb-from,.lang-bridge .lb-to{ display:inline-block; min-width:42px; text-align:center;
  font-weight:700; font-size:11px; padding:2px 9px; margin-right:8px; border-radius:99px; line-height:1.4; }
.lang-bridge .lb-from{ background:var(--accent-soft); color:var(--accent); }
.lang-bridge .lb-to{ background:var(--brand-soft,var(--accent-soft)); color:var(--brand,var(--accent)); }

/* post-struggle weak-concept WHY (W5B), one calm line under the growth
   areas: why the weakest concept matters and the one move to improve it. */
.weak-why{ display:flex; align-items:flex-start; gap:8px; margin:12px 4px 4px;
  padding:11px 13px; background:var(--accent-soft); border-radius:var(--r-md);
  font-size:13px; line-height:1.5; color:var(--ink); }
.weak-why .ww-ic{ flex:none; font-size:15px; line-height:1.4; }

/* industry-skills roadmap (Wave 6), the path from "it works" to job-ready.
   Each rung is done / in-progress / locked; locked rungs read aspirationally,
   so a beginner sees a motivating journey, never a wall of jargon. */
.roadmap{ display:flex; flex-direction:column; gap:0; margin-top:12px; }
.rm-rung{ display:flex; align-items:flex-start; gap:12px; padding:13px 4px;
  border-top:1px solid var(--line,#E6E9EF); position:relative; }
.rm-rung:first-child{ border-top:none; }
.rm-ic{ flex:none; width:26px; height:26px; border-radius:50%; display:flex;
  align-items:center; justify-content:center; font-size:13px; font-weight:700; margin-top:1px; }
.rm-done    .rm-ic{ background:var(--ok-soft);  color:var(--ok); }
.rm-progress .rm-ic{ background:var(--accent-soft); color:var(--accent); }
.rm-locked  .rm-ic{ background:var(--bg-soft,#F1F3F7); color:var(--ink-faint); font-size:12px; }
.rm-main{ flex:1; min-width:0; }
.rm-t{ font:700 14px var(--display); color:var(--ink); display:flex; align-items:center;
  gap:8px; flex-wrap:wrap; }
.rm-locked .rm-t{ color:var(--ink-soft); }
.rm-tag{ font:600 10.5px/1 var(--sans,inherit); text-transform:uppercase; letter-spacing:.04em;
  padding:3px 7px; border-radius:999px; }
.rm-done    .rm-tag{ background:var(--ok-soft);  color:var(--ok); }
.rm-progress .rm-tag{ background:var(--accent-soft); color:var(--accent); }
.rm-locked  .rm-tag{ background:var(--bg-soft,#F1F3F7); color:var(--ink-faint); }
.rm-d{ margin-top:4px; font-size:12.5px; line-height:1.5; color:var(--ink-soft); }
.rm-asp{ font-style:italic; color:var(--ink-faint); }

/* ============================================================
   CITATION / RESEARCH VIEW  (citeMode only)
   The verbose provenance surfaces, shown ONLY to the dedicated
   `citation` account. A distinct indigo-tinted, dashed-edged look
   makes it unmistakable that this is the research / evidence trail,
   not the clean view a real learner sees. Reuses the existing tokens
   so it stays on-brand and theme-aware (light/dark) for free.
   ============================================================ */
/* the always-on eyebrow that labels the surface as the research view */
.cite-eyebrow{ display:inline-flex; align-items:center; gap:7px; margin:0 0 14px;
  padding:5px 12px; border-radius:999px; font-size:11px; font-weight:700;
  letter-spacing:.05em; text-transform:uppercase; color:var(--primary-deep);
  background:var(--primary-soft); border:1px dashed var(--primary-deep); }
.cite-eyebrow-dot{ font-size:9px; line-height:1; }
/* a labelled key/value row, shared by the problem block and the methods list */
.cite-row{ display:grid; grid-template-columns:140px 1fr; gap:6px 14px;
  padding:8px 0; border-top:1px solid var(--line); align-items:start; }
.cite-row:first-of-type{ border-top:0; }
.cite-k{ font-size:11px; font-weight:700; letter-spacing:.04em; text-transform:uppercase;
  color:var(--ink-faint); padding-top:1px; }
.cite-v{ font-size:14px; line-height:1.5; color:var(--ink); }
.cite-doi{ color:var(--primary-deep); font-weight:600; word-break:break-all; }
.cite-doi:focus-visible{ box-shadow:var(--ring); outline:none; border-radius:var(--r-xs); }
@media (max-width:560px){
  .cite-row{ grid-template-columns:1fr; gap:2px; padding:10px 0; }
}
/* the per-problem provenance block (problem page) */
.cite-block{ margin:16px 0; padding:16px 18px; border-radius:var(--r-md);
  background:var(--surface); border:1px dashed var(--primary-deep);
  box-shadow:var(--shadow-sm); }
.cite-block-h{ font:700 14px var(--display); color:var(--primary-deep);
  display:flex; align-items:center; gap:8px; margin-bottom:8px; }
/* the Methods & Citations list */
.cite-methods{ display:grid; gap:16px; }
.cite-method{ padding:18px 20px; border-radius:var(--r-lg); background:var(--surface);
  border:1px solid var(--line); box-shadow:var(--shadow-sm); }
.cite-method-h{ font:700 17px var(--display); color:var(--ink); margin:0 0 10px;
  padding-bottom:10px; border-bottom:2px solid var(--primary-soft); }

/* ============================================================
   Skill-Score: the solve delight card + the Standing surface
   ============================================================ */
/* award card, shown on a first-ever solve, above the result metrics */
.award-card{ margin:0 16px 14px; padding:22px; border-radius:var(--r-lg);
  background:linear-gradient(135deg, var(--primary-soft, #EEF) 0%, var(--surface-2) 70%);
  border:1px solid var(--primary); box-shadow:var(--shadow-sm); }
.award-card.flagged{ background:linear-gradient(135deg, var(--accent-soft) 0%, var(--surface-2) 70%);
  border-color:var(--accent); }
.aw-head{ display:flex; align-items:baseline; gap:8px; margin-bottom:10px; }
.aw-spark{ font-size:20px; }
.aw-total{ font:800 30px/1 var(--display, inherit); color:var(--primary);
  letter-spacing:-.02em; }
.award-card.flagged .aw-total{ color:var(--accent); }
.aw-cap{ font-weight:700; font-size:12px; text-transform:uppercase; letter-spacing:.04em;
  color:var(--ink-faint); }
.aw-lines{ display:grid; gap:5px; }
.aw-line{ display:flex; align-items:center; justify-content:space-between; gap:12px;
  font-size:14px; color:var(--ink-soft); }
.aw-line .aw-l{ font-weight:600; }
.aw-line .aw-p{ font-weight:800; color:var(--ok); font-variant-numeric:tabular-nums; }
.aw-line.aw-neg .aw-p{ color:var(--bad, #D63C44); }
.aw-line.aw-neg .aw-l{ color:var(--bad, #D63C44); }
.aw-note{ margin-top:10px; padding-top:10px; border-top:1px solid var(--line);
  font-size:13px; line-height:1.5; color:var(--ink-soft); }

/* Standing page */
.standing-hero{ display:flex; flex-wrap:wrap; align-items:center; gap:22px;
  padding:24px; margin:4px 0 20px; border-radius:var(--r-lg);
  background:linear-gradient(135deg, var(--primary) 0%, #8B5CF6 100%);
  color:#fff; box-shadow:var(--shadow); }
.sh-score{ display:flex; flex-direction:column; }
.sh-num{ font:800 52px/1 var(--display, inherit); letter-spacing:-.03em; }
.sh-spark{ font-size:22px; }
.sh-cap{ font-weight:700; font-size:13px; opacity:.92; margin-top:4px; }
.sh-stats{ display:flex; gap:14px; flex-wrap:wrap; margin-left:auto; }
.sh-stats .stat{ background:rgba(255,255,255,.14); border:0; min-width:96px; }
.sh-stats .stat-num{ color:#fff; }
.sh-stats .stat-label{ color:rgba(255,255,255,.85); }
/* leaderboard rows */
.lb{ display:grid; gap:6px; margin-top:6px; }
.lb-row{ display:flex; align-items:center; gap:12px; padding:10px 14px;
  border-radius:var(--r-md); background:var(--surface-2); border:1px solid var(--line); }
.lb-row.me{ background:var(--primary-soft, #EEF); border-color:var(--primary); }
.lb-rank{ font-weight:800; color:var(--ink-faint); min-width:46px; font-variant-numeric:tabular-nums; }
.lb-name{ font-weight:600; color:var(--ink); flex:1; }
.lb-you{ font-size:11px; font-weight:800; text-transform:uppercase; letter-spacing:.04em;
  color:var(--primary); margin-left:6px; }
.lb-xp{ font-weight:800; color:var(--primary); font-variant-numeric:tabular-nums; }
/* how-points-work explainer */
.hpw{ display:grid; gap:12px; margin-top:6px; }
.hpw-row{ display:flex; gap:13px; align-items:flex-start; }
.hpw-ic{ font-size:20px; line-height:1.3; flex-shrink:0; }
.hpw-row strong{ display:block; color:var(--ink); font-size:14px; }
.hpw-d{ display:block; color:var(--ink-soft); font-size:13px; line-height:1.5; margin-top:2px; }

/* ============================================================
   WAVE 4, kind retention mechanics (streak shield, daily quest,
   endowed-progress bar, first-try combo, earned titles, mock pacing).
   Calm, tactile, never loud. No FOMO, no countdown pressure.
   ============================================================ */
/* app-bar streak shield, the banked rest days riding the streak chip */
.streak-shield{ margin-left:5px; font-size:11px; opacity:.85; font-variant-numeric:tabular-nums; }

/* daily quest, a self-set, gentle goal with a calm progress ring */
.daily-quest{ display:flex; align-items:center; gap:16px; background:var(--surface);
  border:1px solid var(--line); border-radius:var(--r-lg); padding:16px 18px; margin:14px 0; box-shadow:var(--shadow-sm); }
.daily-quest.met{ border-color:var(--ok); background:var(--ok-soft); }
.dq-ring{ --p:0; width:58px; height:58px; flex-shrink:0; border-radius:50%; display:grid; place-items:center;
  background:conic-gradient(var(--primary) calc(var(--p)*1%), var(--surface-3) 0); }
.daily-quest.met .dq-ring{ background:conic-gradient(var(--ok) calc(var(--p)*1%), var(--surface-3) 0); }
.dq-ring span{ width:44px; height:44px; border-radius:50%; background:var(--surface);
  display:flex; flex-direction:column; align-items:center; justify-content:center; line-height:1;
  font:800 16px var(--font); color:var(--ink); }
.dq-ring span i{ font-style:normal; font-size:11px; line-height:1; margin-top:2px; color:var(--ink-faint); font-weight:600; }
.dq-copy{ min-width:0; }
.dq-title{ font:700 16px var(--display); color:var(--ink); }
.dq-sub{ color:var(--ink-soft); font-size:13px; line-height:1.5; margin-top:3px; }

/* endowed-progress bar, the current block's fill, never a flat zero */
.endowed-bar{ background:var(--surface); border:1px solid var(--line); border-radius:var(--r-md);
  padding:14px 16px; margin:10px 0; box-shadow:var(--shadow-sm); }
.eb-head{ display:flex; justify-content:space-between; align-items:baseline; gap:10px; margin-bottom:8px; }
.eb-name{ font-weight:700; color:var(--ink); font-size:14px; }
.eb-left{ font-size:12px; font-weight:600; color:var(--primary); }
.eb-track{ height:9px; background:var(--surface-3); border-radius:999px; overflow:hidden; }
.eb-track i{ display:block; height:100%; border-radius:999px;
  background:linear-gradient(90deg, var(--primary), var(--primary-2)); transition:width .5s var(--ease); }

/* earned-title chips (dashboard strip) */
.badge-strip{ display:flex; flex-wrap:wrap; gap:8px; margin:10px 0; }
/* compact rarity chip — same cosmic DNA as the You-hub trophy case, calm
   on the dashboard (rarity rim + a mini porthole, no perpetual motion). The
   rarity custom-props (--rar/--rar-glow/--rar-neb) are set by the shared
   .badge-chip.t-* rules in the trophy-case block. */
.badge-chip{ display:inline-flex; align-items:center; gap:8px; padding:6px 13px 6px 7px; border-radius:999px;
  background:linear-gradient(135deg, var(--surface-2), var(--surface)); border:1px solid var(--line);
  color:var(--ink); font-size:13px; font-weight:700;
  transition:transform .18s var(--ease), box-shadow .18s var(--ease); }
.badge-chip:hover{ transform:translateY(-2px); box-shadow:0 7px 16px -7px var(--rar-glow); }
.bc-orb{ width:24px; height:24px; border-radius:50%; display:grid; place-items:center; font-size:13px; flex:none;
  background:radial-gradient(62% 62% at 50% 32%, var(--rar-neb), #0a0f24);
  box-shadow:inset 0 1px 1px rgba(255,255,255,.4), 0 0 0 1.5px var(--rar), 0 0 8px -2px var(--rar-glow); }

/* first-try combo ribbon inside the award card */
.aw-combo{ margin:8px 0 2px; padding:7px 12px; border-radius:var(--r-sm);
  background:var(--ok-soft); color:var(--ink); font-weight:700; font-size:13px; }
/* dark mode: --ok-soft is a near-black green, so the "on a roll" ribbon reads as a
   dull dark bar. Use a vibrant translucent green with bright-green text + a soft
   green edge so the celebration actually pops and stays readable. */
[data-theme="dark"] .aw-combo{ background:rgba(52,211,153,.13);
  color:var(--ok); border:1px solid rgba(52,211,153,.30); }

/* private, opt-in coach nudge on a stuck run */
.coach-nudge{ display:flex; align-items:center; gap:10px; padding:12px 14px; border-radius:var(--r-md);
  background:var(--info-soft); border:1px solid var(--info); }
.coach-nudge .cn-ic{ font-size:18px; }
.coach-nudge .cn-t{ flex:1; color:var(--ink); font-size:13px; line-height:1.45; }

/* F1: proactive, dismissible "stuck coach" offer, prepended into #result after
   real struggle + a quiet pause. Same calm tokens as .coach-nudge (WCAG AA in
   both themes). GPU-cheap entrance (transform/opacity only); the global
   prefers-reduced-motion rule above auto-freezes it to a plain appear. */
.stuck-offer{ display:flex; align-items:center; gap:10px 12px; flex-wrap:wrap;
  margin:0 16px 12px; padding:12px 14px; border-radius:var(--r-md);
  background:var(--info-soft); border:1px solid var(--info);
  animation:stuckIn .28s ease-out both; }
.stuck-offer .so-ic{ font-size:18px; flex:none; }
.stuck-offer .so-body{ flex:1 1 200px; min-width:0; }
.stuck-offer .so-t{ font-weight:700; color:var(--ink); font-size:13px; }
.stuck-offer .so-s{ color:var(--ink-soft); font-size:13px; line-height:1.45; margin-top:2px; }
.stuck-offer .so-s p{ margin:.35em 0 0; }
.stuck-offer .so-actions{ display:flex; gap:8px; flex:none; margin-left:auto; }
@keyframes stuckIn{ from{ opacity:0; transform:translateY(-6px); } to{ opacity:1; transform:none; } }

/* F2: the at-solve Skill-RATING rise chip (prepended into #result on a genuine
   rise only). A calm "win" accent (the ok tokens), readable in both themes; the
   entrance reuses the GPU-cheap stuckIn keyframe, frozen by reduced-motion. */
.skill-rise{ display:flex; align-items:center; gap:8px; margin:0 16px 12px; padding:10px 14px;
  border-radius:var(--r-md); background:var(--ok-soft); border:1px solid var(--ok);
  animation:stuckIn .3s ease-out both; }
.skill-rise .sr-ic{ font-size:16px; }
.skill-rise .sr-lbl{ font-weight:700; color:var(--ink); font-size:13px; }
.skill-rise .sr-move{ color:var(--ink); font-size:14px; font-variant-numeric:tabular-nums; }
.skill-rise .sr-move b{ font-weight:800; }
.skill-rise .sr-arrow{ color:var(--ink-faint); margin:0 2px; }
.skill-rise .sr-delta{ margin-left:auto; font-weight:800; color:var(--ok); font-size:13px; }
/* F2: the "since last visit" rise badge on the You-hub Skill stat. */
.pc-rise{ display:inline-block; margin-left:5px; font-size:10px; font-weight:800; color:var(--ok); vertical-align:middle; }

/* F3: the spaced-review "due today" queue (journey) + the from-memory banner.
   Calm tokens, readable both themes; only ever shown when something is genuinely
   due (an empty queue renders nothing, no manufactured urgency). */
.review-queue{ margin:14px 0 0; padding:13px 15px; border-radius:var(--r-md); background:var(--surface-2); border:1px solid var(--line); }
.review-queue .rq-h{ display:flex; align-items:center; gap:8px; }
.review-queue .rq-ic{ font-size:18px; }
.review-queue .rq-t{ font-weight:800; color:var(--ink); font-size:15px; }
.review-queue .rq-n{ margin-left:auto; font-weight:800; font-size:13px; color:#fff; background:#6366F1; border-radius:999px; min-width:22px; text-align:center; padding:1px 8px; }
.review-queue .rq-sub{ color:var(--ink-soft); font-size:12.5px; line-height:1.45; margin:5px 0 10px; }
.review-queue .rq-list{ margin:0; }
.review-queue .rq-list+.rq-list{ margin-top:8px; }
/* .plan sets display:flex, which overrides the UA [hidden] rule, so the folded
   rows need an explicit (higher-specificity) hide. */
.review-queue .rq-extra[hidden]{ display:none; }
.review-queue .rq-toggle{ display:inline-block; margin-top:9px; padding:2px 0; background:none; border:0; cursor:pointer;
  color:var(--ink-soft); font-size:12.5px; font-weight:700; text-decoration:underline; text-underline-offset:3px; }
.review-queue .rq-toggle:hover{ color:var(--ink); }
.review-queue .rq-toggle:focus-visible{ outline:none; box-shadow:var(--ring); border-radius:4px; }
.review-banner{ display:flex; align-items:flex-start; gap:10px; margin:14px 0 0; padding:12px 14px; border-radius:var(--r-md); background:var(--info-soft); border:1px solid var(--info); }
.review-banner .rb-ic{ font-size:18px; }
.review-banner .rb-t{ font-weight:700; color:var(--ink); font-size:13px; }
.review-banner .rb-s{ color:var(--ink-soft); font-size:13px; line-height:1.45; margin-top:2px; }

/* F4: read/debug/explain micro-drills surface. Theme-safe tokens throughout; the
   code block uses surface-2 so it reads in both themes. */
.drill-picker{ display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:12px; margin:18px 0; }
.drill-pick{ display:flex; flex-direction:column; align-items:flex-start; gap:4px; text-align:left; padding:16px; border-radius:var(--r-md); background:var(--surface-2); border:1px solid var(--line); cursor:pointer; transition:transform .15s ease, border-color .15s ease; }
.drill-pick:hover{ transform:translateY(-2px); border-color:#8B5CF6; }
.drill-pick-ic{ font-size:24px; }
.drill-pick-t{ font-weight:800; color:var(--ink); font-size:15px; }
.drill-pick-s{ color:var(--ink-soft); font-size:12.5px; line-height:1.4; }
.drill-card{ margin:8px 0 0; padding:18px; border-radius:var(--r-md); background:var(--surface-1,var(--surface-2)); border:1px solid var(--line); }
.drill-kindrow{ display:flex; align-items:center; gap:10px; margin-bottom:10px; flex-wrap:wrap; }
.drill-kind{ font-weight:800; font-size:11px; letter-spacing:.04em; text-transform:uppercase; color:#fff; background:#8B5CF6; padding:3px 9px; border-radius:999px; }
.drill-kind.read{ background:#6366F1; } .drill-kind.debug{ background:#E0683C; } .drill-kind.explain{ background:#16A34A; }
.drill-prob{ color:var(--ink-soft); font-size:13px; font-weight:600; }
.drill-q{ color:var(--ink); font-size:14.5px; line-height:1.5; margin:0 0 12px; }
.drill-code{ font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:13px; line-height:1.6; background:var(--surface-2); border:1px solid var(--line); border-radius:10px; padding:10px 0; margin:0 0 12px; overflow:auto; }
.drill-line{ display:flex; width:100%; gap:12px; padding:1px 14px; color:var(--ink); background:transparent; border:0; text-align:left; font:inherit; }
.drill-code.pick .drill-line{ cursor:pointer; }
.drill-code.pick .drill-line:hover{ background:rgba(139,92,246,.14); }
.drill-line.picked{ background:rgba(139,92,246,.26); box-shadow:inset 2px 0 0 #8B5CF6; }
.drill-line.isbug{ background:rgba(224,104,60,.22); box-shadow:inset 2px 0 0 #E0683C; }
.dl-n{ color:var(--ink-faint); user-select:none; min-width:22px; text-align:right; flex:none; }
.dl-c{ white-space:pre; }
.drill-io,.drill-seg{ margin:0 0 12px; }
.dio-l{ display:block; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--ink-faint); margin-bottom:4px; }
.drill-input{ font-family:ui-monospace,Menlo,monospace; font-size:13px; background:var(--surface-2); border:1px solid var(--line); border-radius:8px; padding:8px 10px; margin:0; white-space:pre-wrap; color:var(--ink); }
.drill-anslabel{ display:block; font-size:13px; font-weight:700; color:var(--ink); margin:0 0 6px; }
.drill-actions{ display:flex; gap:8px; margin-top:12px; flex-wrap:wrap; }
.drill-hint{ color:var(--ink-soft); font-size:13px; margin:6px 0 0; }
.drill-feedback{ display:flex; gap:10px; padding:12px 14px; border-radius:var(--r-md); margin:12px 0 0; font-size:14px; line-height:1.5; color:var(--ink); }
.drill-feedback .df-ic{ font-weight:800; flex:none; }
.drill-feedback.ok{ background:var(--ok-soft); border:1px solid var(--ok); }
.drill-feedback.off{ background:var(--info-soft); border:1px solid var(--info); }
.drill-feedback.partial{ background:var(--info-soft); border:1px solid var(--info); }
.drill-feedback.unverified{ background:var(--surface-2); border:1px solid var(--line); color:var(--ink-soft); }
.df-why{ color:var(--ink-soft); }
.dcode{ font-family:ui-monospace,Menlo,monospace; background:var(--surface-2); padding:1px 6px; border-radius:5px; }

/* mock-only pacing readout, the ONLY place speed is shown */
.sim-pacing{ margin:14px 0; padding:14px 16px; border-radius:var(--r-md);
  background:var(--surface-2); border:1px solid var(--line); }
.sim-pacing.ok{ background:var(--ok-soft); border-color:var(--ok); }
.sp-head{ font-weight:700; color:var(--ink); font-size:14px; margin-bottom:10px; }
.sp-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:10px; }
.sp-cell{ text-align:center; }
.sp-v{ font:800 18px var(--display); color:var(--ink); font-variant-numeric:tabular-nums; }
.sp-l{ font-size:11px; color:var(--ink-faint); font-weight:600; margin-top:2px; }
.sp-note{ color:var(--ink-soft); font-size:13px; line-height:1.5; margin:10px 0 0; }

/* onboarding daily-goal note */
.onb-goal-note{ color:var(--ink-soft); font-size:12px; line-height:1.5; margin:6px 0 0; }

@media (prefers-reduced-motion: reduce){ .eb-track i{ transition:none; } }

/* ============================================================
   Modal overlay, the pop-up Mini-Quest (and any future dialog).
   Darkened, blurred backdrop "on top of all"; the card lifts in
   (a small takeoff), disabled under prefers-reduced-motion.
   ============================================================ */
.modal-overlay{ position:fixed; inset:0; z-index:1000; display:flex;
  align-items:flex-start; justify-content:center; padding:5vh 16px;
  overflow-y:auto; background:rgba(12,12,28,.55); backdrop-filter:blur(4px);
  -webkit-backdrop-filter:blur(4px); opacity:0; transition:opacity .22s var(--ease); }
.modal-overlay.on{ opacity:1; }
.modal-card{ position:relative; width:100%; max-width:680px; margin:auto;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-xl);
  box-shadow:var(--shadow-lg); padding:24px 22px;
  transform:translateY(22px) scale(.985); opacity:.6;
  transition:transform .26s var(--ease), opacity .26s var(--ease); }
.modal-overlay.on .modal-card{ transform:translateY(0) scale(1); opacity:1; }
.modal-x{ position:absolute; top:12px; right:12px; width:34px; height:34px;
  border-radius:50%; border:1px solid var(--line); background:var(--surface-2);
  color:var(--ink-soft); font-size:15px; cursor:pointer; line-height:1;
  display:grid; place-items:center; transition:background .14s, color .14s; }
.modal-x:hover{ background:var(--surface-3); color:var(--ink); }
.modal-body{ margin-top:4px; }

/* lift-off celebration on clearing a drill, a rising rocket + the credit */
.lift-cel{ position:relative; overflow:hidden; }
.liftoff{ font-size:26px; line-height:1; margin-bottom:6px;
  animation:liftoff 1s var(--ease) both; transform-origin:50% 100%; }
@keyframes liftoff{
  0%{ transform:translateY(10px) scale(.7); opacity:0; }
  35%{ transform:translateY(0) scale(1.08); opacity:1; }
  100%{ transform:translateY(-2px) scale(1); opacity:1; }
}
.mq-credit{ margin-top:10px; font-weight:800; color:var(--primary);
  font-variant-numeric:tabular-nums; }

@media (prefers-reduced-motion: reduce){
  .modal-overlay{ transition:none; }
  .modal-card{ transition:none; transform:none; opacity:1; }
  .liftoff{ animation:none; }
}

/* ============================================================
   Complexity result tab, measured facts + an estimated Big-O.
   ============================================================ */
.cx-facts{ display:grid; grid-template-columns:repeat(auto-fit,minmax(120px,1fr));
  gap:10px; margin-bottom:14px; }
.cx-fact{ background:var(--surface-2); border:1px solid var(--line);
  border-radius:var(--r-md); padding:12px 14px; text-align:center; }
.cx-v{ font:800 22px var(--display); color:var(--ink); font-variant-numeric:tabular-nums; }
.cx-u{ font-size:12px; font-weight:600; color:var(--ink-faint); }
.cx-l{ font-size:11px; font-weight:600; color:var(--ink-faint); margin-top:2px;
  text-transform:uppercase; letter-spacing:.03em; }
.cx-est{ background:var(--surface-2); border:1px solid var(--line);
  border-radius:var(--r-md); padding:16px; color:var(--ink-soft); }
.cx-bigo{ display:flex; gap:24px; flex-wrap:wrap; }
.cx-o{ display:flex; flex-direction:column; }
.cx-o-k{ font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.04em;
  color:var(--ink-faint); }
.cx-o-v{ font:800 24px var(--display); color:var(--primary); font-variant-numeric:tabular-nums; }
.cx-why{ color:var(--ink-soft); font-size:14px; line-height:1.55; margin:12px 0 0; }
.cx-src{ font-size:11px; color:var(--ink-faint); font-weight:600; margin-top:10px;
  text-transform:uppercase; letter-spacing:.03em; }
.cx-note{ color:var(--ink-faint); font-size:12px; line-height:1.5; margin:12px 0 0; }
/* beginner plain-language complexity line (no Big-O jargon) */
.cx-plain{ background:var(--surface-2); border:1px solid var(--line); border-radius:var(--r-md);
  padding:14px 16px; color:var(--ink-soft); font-size:14px; line-height:1.55; }

/* ============================================================
   UDAAN VIBE, the flight of a career taking off.
   Four restrained, GPU-cheap moments (transform + opacity only),
   each with a reduced-motion off-switch (also caught by the global
   reset at the top of this file). Decoration that does not serve
   the takeoff → climb → soar arc does not live here.
   ============================================================ */

/* ---- BOOT REVEAL, the rocket unzips the splash ----
   The cover (a solid splash-coloured panel) tears open from the bottom up as
   the rocket climbs out the top: a clip-path V-notch whose apex rises with the
   rocket, like a zipper. Pointer-events off; fully skipped under reduced-motion
   (the JS also early-returns so no node is built). */
.uv-zip{ position:fixed; inset:0; z-index:1500; pointer-events:none; overflow:hidden; }
/* ignition kick, a brief camera shake as the engines light */
.uv-zip.go{ animation:uvzip-shake .42s ease-in-out .14s 2; }
@keyframes uvzip-shake{ 0%,100%{ transform:translate(0,0); } 20%{ transform:translate(-2px,1px); }
  45%{ transform:translate(2px,-1px); } 70%{ transform:translate(-1px,2px); } }
.uv-zip-cover{ position:absolute; inset:0; overflow:hidden;
  /* the cloned sky scene is wiped away by a soft-edged mask that climbs from the
     bottom up in lock-step with the rocket. Animating mask-position only re-composites
     the already-rasterised layer, no per-frame blur/filter re-raster (i5-friendly). */
  -webkit-mask-image:linear-gradient(to bottom,#000 30%,rgba(0,0,0,0) 56%);
  mask-image:linear-gradient(to bottom,#000 30%,rgba(0,0,0,0) 56%);
  -webkit-mask-size:100% 360%; mask-size:100% 360%;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-position:0 0%; mask-position:0 0%;
  will-change:-webkit-mask-position, mask-position; }
/* TURBULENT exhaust smoke, independent puffs that rise, drift sideways, swell
   and curl as they fade, billowing like a real launch plume. */
.uv-zip-smoke{ position:absolute; left:50%; bottom:1%; width:150px; height:62%; transform:translateX(-50%);
  pointer-events:none; z-index:3; }
.uv-zip-smoke i{ position:absolute; bottom:0; left:50%; width:56px; height:56px; border-radius:50%; opacity:0;
  filter:blur(5px); transform:translate(-50%,0) scale(.4);
  background:radial-gradient(circle at 45% 40%, rgba(250,250,253,.92), rgba(222,226,237,.55) 58%, transparent 72%); }
.uv-zip.go .uv-zip-smoke i{ animation:smoke-puff 1.5s ease-out forwards; }
.uv-zip.go .uv-zip-smoke i:nth-child(1){ animation-delay:.06s; --dx:-46px; --rot:-22deg; }
.uv-zip.go .uv-zip-smoke i:nth-child(2){ animation-delay:.15s; --dx:44px;  --rot:18deg; }
.uv-zip.go .uv-zip-smoke i:nth-child(3){ animation-delay:.23s; --dx:-80px; --rot:-30deg; }
.uv-zip.go .uv-zip-smoke i:nth-child(4){ animation-delay:.30s; --dx:76px;  --rot:28deg; }
.uv-zip.go .uv-zip-smoke i:nth-child(5){ animation-delay:.11s; --dx:-10px; --rot:-9deg; }
.uv-zip.go .uv-zip-smoke i:nth-child(6){ animation-delay:.19s; --dx:16px;  --rot:12deg; }
@keyframes smoke-puff{
  0%{   opacity:0;  transform:translate(-50%,12%) scale(.4) rotate(0deg); }
  18%{  opacity:.9; }
  100%{ opacity:0;  transform:translate(calc(-50% + var(--dx,0px)), -190%) scale(2.3) rotate(var(--rot,0deg)); } }
@media (prefers-reduced-motion: reduce){ .uv-zip-smoke i{ animation:none; } }
.uv-zip-seam{ position:absolute; left:50%; top:0; bottom:0; width:3px; transform:translateX(-50%);
  opacity:0; box-shadow:0 0 22px 6px rgba(255,170,90,.7);
  background:linear-gradient(to bottom, transparent, #fff 28%, #ffb15e 58%, transparent); }
/* the launch craft, the drawn SVG rocket + its burn flame, climbing upright */
.uv-zip-rocket{ position:absolute; left:50%; bottom:calc(9vh + 18px); transform:translateX(-50%);
  width:46px; height:104px; z-index:4; }
.uv-zip-rocket .rk{ filter:drop-shadow(0 8px 16px rgba(40,30,10,.35)); }
/* the launch gantry + pad silhouette, sits at the base and STAYS as the
   rocket climbs away from it. Shared by the launchpad and the takeoff. */
.launch-base{ position:absolute; left:50%; transform:translateX(-50%); pointer-events:none; }
.boot .launch-base{ bottom:calc(9vh - 16px); z-index:2; }
.uv-zip .launch-base{ bottom:calc(9vh - 16px); z-index:1; }
.gantry{ display:block; }
/* heat-haze shimmer rising off the exhaust, a faint warm waver */
.rk-haze{ position:absolute; left:50%; top:100%; margin-top:8px; transform:translateX(-50%);
  width:26px; height:96px; border-radius:50%; pointer-events:none; opacity:.5; filter:blur(6px);
  background:radial-gradient(ellipse at 50% 26%, rgba(255,206,150,.5), transparent 70%);
  animation:rk-haze .2s ease-in-out infinite alternate; }
@keyframes rk-haze{ from{ transform:translateX(-50%) scaleX(.9) skewX(-3deg); opacity:.38; }
  to{ transform:translateX(-52%) scaleX(1.12) skewX(3deg); opacity:.6; } }
@media (prefers-reduced-motion: reduce){ .rk-haze{ animation:none; } }
/* REAL PHYSICS: the rocket barely moves at ignition (thrust just beating
   gravity), then accelerates hard as it burns, an ease-IN climb, not a glide. */
/* the sky is REVEALED bottom-to-top, the wipe edge climbs with the rocket, at
   the same pace (identical duration + easing as uvzip-fly), so the natural
   background clears exactly where the rocket has already passed. */
.uv-zip.go .uv-zip-cover{ animation:uvzip-climb 1.5s cubic-bezier(.5,.04,.86,.32) forwards; }
/* the launcher fades out as the rocket leaves it, so it never lingers over the
   revealed content. */
.uv-zip.go .launch-base{ animation:gantry-fade 1.05s cubic-bezier(.4,0,.2,1) .3s forwards; }
.uv-zip.go .uv-zip-smoke{ animation:uvzip-smoke 1.5s ease-out .1s forwards; }
.uv-zip.go .uv-zip-seam{ animation:uvzip-seam 1.2s ease-out .16s forwards; }
.uv-zip.go .uv-zip-rocket{ animation:uvzip-fly 1.5s cubic-bezier(.5,.04,.86,.32) forwards; }
@keyframes uvzip-fly{
  0%{   bottom:calc(9vh + 18px); transform:translateX(-50%); }
  16%{  bottom:8.4vh;            transform:translateX(-50%); }   /* hold on the pad, building thrust */
  100%{ bottom:140%;            transform:translateX(-50%); } }
@keyframes uvzip-seam{ 0%{ opacity:0; } 18%{ opacity:.85; } 100%{ opacity:0; } }
@keyframes uvzip-smoke{
  0%{   opacity:0;   transform:translateX(-50%) scale(.34) translateY(16%); }
  22%{  opacity:.95; }
  100%{ opacity:0;   transform:translateX(-50%) scale(1.7) translateY(-46%); } }
/* climbing reveal, the soft mask edge sweeps upward following the rocket: it
   holds low while thrust builds on the pad (0–16%, matching uvzip-fly), then
   races up as the rocket accelerates away. Pure mask-position = GPU-composited. */
@keyframes uvzip-climb{
  0%{   -webkit-mask-position:0 0%;   mask-position:0 0%; }
  16%{  -webkit-mask-position:0 4%;   mask-position:0 4%; }
  100%{ -webkit-mask-position:0 100%; mask-position:0 100%; } }
@keyframes gantry-fade{ 0%{ opacity:1; transform:translateX(-50%) translateY(0); }
  100%{ opacity:0; transform:translateX(-50%) translateY(8px); } }
@media (prefers-reduced-motion: reduce){ .uv-zip{ display:none; } }

/* ---- 1 · FIRST-SOLVE TAKEOFF, the emotional core ----
   A one-shot, ~1.5s, skippable overlay built once in JS (uv-takeoff).
   A dawn wash rises, a plane climbs off the runway and out of frame,
   a single line of credit. Behind nothing interactive; clicking it
   (or its timer) removes it. Never blocks input, pointer-events off
   on the canvas, only the skip affordance is the whole layer. */
.uv-takeoff{ position:fixed; inset:0; z-index:1200; display:grid; place-items:center;
  pointer-events:auto; cursor:pointer; overflow:hidden;
  background:radial-gradient(130% 100% at 50% 122%, var(--accent-soft) 0%, rgba(251,113,133,.20) 40%, transparent 66%);
  opacity:0; animation:uv-tk-fade 2.2s var(--ease) both; }
@keyframes uv-tk-fade{ 0%{ opacity:0; } 10%{ opacity:1; } 82%{ opacity:1; } 100%{ opacity:0; } }
/* a sunrise burst of light that swells from the horizon behind the climb */
.uv-takeoff::before{ content:""; position:absolute; left:50%; bottom:-12%;
  width:170vmax; height:170vmax; transform:translateX(-50%) scale(.35); transform-origin:50% 100%;
  opacity:0; pointer-events:none;
  background:radial-gradient(circle at 50% 100%, rgba(255,196,140,.55) 0%, rgba(251,113,133,.20) 24%, transparent 50%);
  animation:uv-tk-sun 2.2s var(--ease) both; }
@keyframes uv-tk-sun{ 0%{ transform:translateX(-50%) scale(.35); opacity:0; }
  28%{ opacity:.95; } 72%{ opacity:.85; } 100%{ transform:translateX(-50%) scale(1); opacity:0; } }
/* the rising dawn band, a horizon that lifts as the plane leaves it */
.uv-takeoff .uv-horizon{ position:absolute; left:0; right:0; bottom:0; height:54%;
  background:linear-gradient(0deg, var(--accent-soft) 0%, rgba(251,113,133,.14) 46%, transparent 100%);
  transform:translateY(45%); opacity:0;
  animation:uv-tk-horizon 2.2s var(--ease) both; }
@keyframes uv-tk-horizon{ 0%{ transform:translateY(45%); opacity:0; }
  18%{ opacity:1; } 72%{ opacity:1; } 100%{ transform:translateY(-4%); opacity:0; } }
/* the plane, climbs from lower-left, gaining real altitude, then off-frame */
.uv-takeoff .uv-plane{ position:absolute; left:50%; top:64%; font-size:clamp(64px,13vw,128px);
  line-height:1; filter:drop-shadow(0 16px 28px rgba(16,24,40,.24));
  transform:translate(-230px,190px) rotate(-5deg) scale(.8);
  animation:uv-tk-plane 2.2s cubic-bezier(.28,.08,.18,1) both; }
@keyframes uv-tk-plane{
  0%{ transform:translate(-250px,210px) rotate(-3deg) scale(.78); opacity:0; }
  16%{ opacity:1; }
  100%{ transform:translate(480px,-360px) rotate(-27deg) scale(1.18); opacity:0; }
}
/* the one line of credit, rises and settles, then fades with the layer */
.uv-takeoff .uv-credit{ position:relative; text-align:center; transform:translateY(18px);
  animation:uv-tk-credit 2.2s var(--ease) both; }
.uv-takeoff .uv-credit b{ display:block; font:800 clamp(26px,5.4vw,44px)/1.08 var(--display);
  background:var(--dawn-grad); -webkit-background-clip:text; background-clip:text; color:transparent;
  letter-spacing:-.015em; }
.uv-takeoff .uv-credit span{ display:block; margin-top:10px; font:600 clamp(14px,2vw,17px) var(--font); color:var(--ink-soft); }
@keyframes uv-tk-credit{ 0%{ transform:translateY(18px); opacity:0; }
  24%{ transform:translateY(0); opacity:1; } 78%{ opacity:1; } 100%{ opacity:0; } }

/* ---- 2 · DAWN HORIZON behind the home / dashboard hero ----
   A second radial of dawn light below the existing accent glow, that
   gently rises into place on arrival, daybreak. Behind content (z<0),
   never touches text contrast. The hero keeps its own background; this
   is an ::after layer so both gradients coexist. */
.hero{ position:relative; isolation:isolate; }
.hero::after{ content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:
    radial-gradient(58% 40% at 50% 104%, rgba(255,193,135,.34) 0%, transparent 62%),   /* the rising sun */
    radial-gradient(150% 130% at 50% 124%, rgba(251,113,133,.22) 0%, transparent 60%);  /* dawn-pink wash */
  transform:translateY(34px); opacity:0;
  animation:uv-dawn 1.4s var(--ease) .05s both; }
@keyframes uv-dawn{ to{ transform:translateY(0); opacity:1; } }
/* hold steady once risen if the page lingers (no infinite loop) */

/* ---- the 3-stage card row ----
   These cards once "ascended" (each one higher + tilted, as a launch metaphor),
   but learners read the staggered, tilted row as misaligned and were not sure it
   was a menu they could tap. Flattened to a clean, aligned row of three tappable
   cards; the gentle fade-up on entrance stays. Stage order now reads from the
   "Stage N" label, the progress ring, and the intro above, not from tilting. */
.stage-cards{ margin-top:18px; }
.stage-card.a{ --uv-alt:0px; --uv-tilt:0deg; }
.stage-card.b{ --uv-alt:0px; --uv-tilt:0deg; }
.stage-card.c{ --uv-alt:0px; --uv-tilt:0deg; }
.stage-card.a, .stage-card.b, .stage-card.c{
  transform:translateY(var(--uv-alt)) rotate(var(--uv-tilt));
  animation:uv-ascent .7s var(--ease) both; }
.stage-card.b{ animation-delay:.1s; }
.stage-card.c{ animation-delay:.2s; }
@keyframes uv-ascent{ from{ transform:translateY(calc(var(--uv-alt) + 32px)) rotate(0deg); opacity:0; }
  to{ transform:translateY(var(--uv-alt)) rotate(var(--uv-tilt)); opacity:1; } }
/* hover keeps the per-stage altitude/tilt while lifting (overrides the base
   .stage-card:hover so C does not "drop" to the runway on hover) */
.stage-card.a:hover{ transform:translateY(calc(var(--uv-alt) - 8px)) rotate(var(--uv-tilt)); }
.stage-card.b:hover{ transform:translateY(calc(var(--uv-alt) - 8px)) rotate(var(--uv-tilt)); }
.stage-card.c:hover{ transform:translateY(calc(var(--uv-alt) - 8px)) rotate(var(--uv-tilt)); }
/* the soaring stage earns a warmer ring on its progress dial, the prize */
.stage-card.c .sc-ring{ background:conic-gradient(var(--accent) calc(var(--p)*1%), var(--surface-3) 0); }
/* on narrow screens the cards stack, altitude/tilt would look like a glitch,
   so flatten to a clean column (entrance fade still applies) */
@media (max-width:760px){
  .stage-card.a, .stage-card.b, .stage-card.c{ transform:none; }
  .stage-card.a:hover, .stage-card.b:hover, .stage-card.c:hover{ transform:translateY(-3px); }
  .stage-card.b, .stage-card.c{ animation-delay:0s; }
  @keyframes uv-ascent{ from{ transform:translateY(14px); opacity:0; } to{ transform:none; opacity:1; } }
}

/* ---- reduced-motion: a calm, static, fully-functional UI ----
   (The global reset at line ~120 already neutralizes animations; these
   rules additionally remove the resting transforms so nothing sits askew,
   and hide the one-shot takeoff layer entirely.) */
@media (prefers-reduced-motion: reduce){
  .uv-takeoff{ display:none !important; }
  .hero::after{ animation:none; transform:none; opacity:1; }
  .stage-card.a, .stage-card.b, .stage-card.c{ transform:none; animation:none; }
  .stage-card.a:hover, .stage-card.b:hover, .stage-card.c:hover{ transform:none; }
  .stage-card.c .sc-ring{ background:conic-gradient(var(--accent) calc(var(--p)*1%), var(--surface-3) 0); }
}

/* the always-visible "Practise this skill" affordance under a failed verdict */
.practise-cta{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.practise-cta-note{ font-size:12px; color:var(--ink-soft); }

/* ============================================================
   ROCKET LOADER, loading the udaan portal feels like takeoff.
   A powered rocket hovers/ascends with a flickering flame while a
   page prepares. Pure transform/opacity; stilled under reduced-motion.
   ============================================================ */
.rocket-load{ display:grid; place-items:center; gap:14px; padding:48px 16px; }
.rl-sky{ position:relative; width:60px; height:64px; }
.rl-rocket{ position:absolute; left:50%; bottom:14px; transform:translateX(-50%) rotate(-45deg);
  font-size:34px; line-height:1; filter:drop-shadow(0 8px 14px rgba(16,24,40,.16));
  animation:rl-bob 1.1s ease-in-out infinite; }
.rl-trail{ position:absolute; left:50%; bottom:6px; width:6px; height:16px; transform:translateX(-50%);
  border-radius:0 0 50% 50%; opacity:.7;
  background:linear-gradient(0deg, transparent 0%, var(--accent) 40%, var(--accent-warm) 100%);
  animation:rl-flame .34s ease-in-out infinite alternate; }
@keyframes rl-bob{ 0%,100%{ transform:translateX(-50%) translateY(0) rotate(-45deg); }
  50%{ transform:translateX(-50%) translateY(-9px) rotate(-45deg); } }
@keyframes rl-flame{ from{ opacity:.35; height:10px; } to{ opacity:.9; height:22px; } }
.rl-label{ color:var(--ink-soft); font-weight:600; font-size:14px; }
@media (prefers-reduced-motion: reduce){
  .rl-rocket{ animation:none; transform:translateX(-50%) rotate(-45deg); }
  .rl-trail{ animation:none; opacity:.55; height:14px; }
}

/* every page ascends in, a gentle rise+settle on each route render, so
   moving through Udaan feels like gaining altitude. Stilled under reduce. */
.route-enter{ animation:route-in .34s var(--ease) both; }
@keyframes route-in{ from{ opacity:0; transform:translateY(12px); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce){ .route-enter{ animation:none; } }

/* ============================================================
   BEYOND THE SUMMIT, the hidden, off-the-record tier (#/beyond).
   The warm 280-problem course tops out at base camp; above it lies
   "thin air": Beyond the Summit (281-300) and The Death Zone
   (301-311, ending at #311 "The Unclimbed Peak"). This space is a
   SECRET, found only via scattered easter eggs, so it deliberately
   breaks from the warm dawn palette into a cold, premium high-altitude
   night: deep indigo sky, a cold-blue→violet aurora, a faint starfield.
   ADDITIVE ONLY: nothing here touches a public rule. It carries its
   own dark surface, so it reads the same in light or dark theme, at
   this altitude there is no daylight. Pure CSS, transform/opacity motion
   only, no external assets (CSP-safe). Every motion has a
   still form under prefers-reduced-motion at the foot of this block;
   the global kill-switch (top of file) already covers it, this is
   belt-and-braces for the load-bearing ones.
   ============================================================ */

/* ---- INVISIBLE HOOKS ----------------------------------------
   .bz-year (footer ©), .bz-total (the "280"), .bz-pct (analysis %)
   wrap existing PUBLIC text and are deliberately left UNSTYLED, any
   rule risks changing the public look, and they need none (the wrapping
   span inherits its surroundings). They serve as click-targets only.
   EXCEPTION: .bz-dot is a faint "·" hidden in the Exam Playbook, a
   barely-there low-opacity glyph with a pointer, hiding in plain sight
   as an unobtrusive full-stop. Nothing more. */
.bz-dot{ opacity:.5; cursor:pointer; }

/* ---- LOCAL TOKENS -------------------------------------------
   Scoped to the hidden view so the rest of the product is untouched.
   Cold night-sky ink, a glacier-blue → violet range. The view brings
   its own dark surface, so it reads the same in light or dark theme:
   at this altitude there is no daylight. */
.bz-view{
  --bz-night:    #070A1A;   /* near-black indigo, the void above the clouds */
  --bz-night-2:  #0C1230;
  --bz-ink:      #E3E7FB;   /* cold starlight text, AA on the night surface */
  --bz-ink-soft: #AAB2DC;   /* muted, still ≥4.5:1 on the card surface       */
  --bz-ink-faint:#7A83B5;   /* faint, used only on non-essential hint text   */
  --bz-line:     rgba(150,170,255,.14);
  --bz-glacier:  #8FC0FF;   /* cold blue, links/accents, AA on dark         */
  --bz-violet:   #B7A4FF;   /* aurora violet                                  */
  --bz-frost:    #E6EEFF;   /* high-altitude white-blue, headings           */
  --bz-aurora:   linear-gradient(120deg, #9FC6FF 0%, #C2B0FF 60%, #A9B0FF 100%);

  position:relative; min-height:100vh; overflow:hidden;
  padding:clamp(28px,6vw,72px) 18px 96px;
  color:var(--bz-ink);
  font-family:var(--font);
  /* the sky itself: a cold radial wash deepening to the void at the top */
  background:
    radial-gradient(120% 80% at 50% 110%, rgba(99,102,241,.18), transparent 60%),
    radial-gradient(90% 60% at 80% -10%, rgba(167,139,250,.14), transparent 60%),
    linear-gradient(180deg, var(--bz-night) 0%, var(--bz-night-2) 70%, #0A1026 100%);
}

/* faint starfield, same gradient-tile idiom as the boot scene (no blur,
   GPU-cheap), drifting almost imperceptibly. aria-hidden mood only. */
.bz-view::before{
  content:""; position:absolute; inset:-50%; z-index:0; pointer-events:none;
  background-repeat:repeat; background-size:380px 380px; opacity:.6;
  background-image:
    radial-gradient(1px 1px at 30px 40px,#cdd6ff 50%,transparent),
    radial-gradient(1px 1px at 130px 90px,#ffffff 50%,transparent),
    radial-gradient(1.4px 1.4px at 220px 160px,#bcd0ff 50%,transparent),
    radial-gradient(1px 1px at 300px 60px,#e7ecff 50%,transparent),
    radial-gradient(1.2px 1.2px at 90px 260px,#dfe6ff 50%,transparent);
  animation:bz-drift 220s linear infinite;
}
@keyframes bz-drift{ from{ transform:translate3d(0,0,0);} to{ transform:translate3d(-380px,0,0);} }

/* the aurora, a slow cold-blue→violet drift behind everything. screen
   blend so it reads as light, not paint. The signature of thin air. */
.bz-view::after{
  content:""; position:absolute; inset:-30% -20% auto -20%; height:70%; z-index:0;
  pointer-events:none; mix-blend-mode:screen; opacity:.5;
  background:
    radial-gradient(60% 40% at 30% 30%, rgba(111,168,255,.55), transparent 70%),
    radial-gradient(50% 38% at 72% 46%, rgba(167,139,250,.5), transparent 70%);
  animation:bz-aurora 28s var(--ease) infinite alternate;
}
@keyframes bz-aurora{ to{ transform:translate3d(4%,2%,0) scale(1.12); } }

/* everything sits above the sky layers */
.bz-view > *{ position:relative; z-index:1; }

/* ---- HERO --------------------------------------------------- */
.bz-hero{
  max-width:760px; margin:0 auto clamp(28px,5vw,56px); text-align:center;
}
.bz-h{ margin:0; }   /* the heading element wrapping the title; layout-neutral */
.bz-eyebrow{
  font-family:var(--mono); font-size:12px; letter-spacing:3px; text-transform:uppercase;
  color:var(--bz-ink-soft);
}
.bz-title{
  display:inline-block; margin-top:10px;
  font-family:var(--display); font-weight:700;
  font-size:clamp(28px,5vw,46px); line-height:1.05; letter-spacing:-.5px;
  background:var(--bz-aurora); -webkit-background-clip:text; background-clip:text;
  color:transparent; text-shadow:0 0 28px rgba(111,168,255,.18);
}
/* a non-clip fallback colour so the title is never invisible if a
   browser ignores background-clip:text */
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .bz-title{ color:var(--bz-frost); }
}
.bz-lead{ margin-top:12px; color:var(--bz-ink-soft); font-size:clamp(14px,2vw,16px); line-height:1.5; }

/* ---- SECTION (a tier band) ---------------------------------- */
.bz-section{ max-width:760px; margin:clamp(28px,5vw,48px) auto 0; }
.bz-h2{
  display:flex; align-items:center; gap:14px;
  font-family:var(--display); font-weight:600; font-size:clamp(16px,2.4vw,22px);
  color:var(--bz-frost); letter-spacing:.3px; margin-bottom:6px;
}
.bz-h2::after{ content:""; flex:1; height:1px; background:linear-gradient(90deg, var(--bz-line), transparent); }
.bz-sub{ color:var(--bz-ink-soft); font-size:13px; margin-bottom:18px; }
.bz-empty{ color:var(--bz-ink-faint); font-size:13px; font-style:italic; padding:14px 0; }

/* The Death Zone (301-311), a degree more severe than the 281-300 band:
   colder edges, a faint warning-frost on the heading. */
.bz-section.bz-death .bz-h2{ color:#DCE6FF; }
.bz-section.bz-death .bz-h2::after{ background:linear-gradient(90deg, rgba(183,164,255,.28), transparent); }
.bz-section.bz-death .bz-card{ border-color:rgba(183,164,255,.18); }

/* ---- GRID --------------------------------------------------- */
.bz-grid{
  display:grid; grid-template-columns:repeat(auto-fill,minmax(210px,1fr));
  gap:14px;
}

/* ---- CARD --------------------------------------------------- */
/* a bonus-problem card, a slab of cold glass raised off the night.
   Reuses the house radius/shadow tokens. */
.bz-card{
  position:relative; display:block; padding:18px 18px 16px;
  border-radius:var(--r-md);
  border:1px solid var(--bz-line);
  background:linear-gradient(180deg, rgba(28,36,72,.72), rgba(16,22,52,.72));
  box-shadow:var(--shadow), inset 0 1px 0 rgba(180,200,255,.08);
  -webkit-backdrop-filter:blur(2px); backdrop-filter:blur(2px);
  color:inherit; text-decoration:none;
  transition:transform .28s var(--ease), box-shadow .28s var(--ease), border-color .28s var(--ease);
}
.bz-card:hover, .bz-card:focus-visible{
  transform:translateY(-3px); outline:none;
  border-color:rgba(143,192,255,.45);
  box-shadow:var(--shadow-lg), inset 0 1px 0 rgba(180,200,255,.14), 0 0 0 1px rgba(143,192,255,.22);
}
/* a thin difficulty rail down the left edge, med → hard → vhard climbs
   from glacier-blue toward a colder violet. Colour is reinforced by the
   tag text, never the only signal. */
.bz-card::before{
  content:""; position:absolute; left:0; top:14px; bottom:14px; width:3px;
  border-radius:3px; background:var(--bz-glacier); opacity:.55;
}
.bz-card.med::before  { background:#8FC0FF; }
.bz-card.hard::before { background:#A9A8FF; }
.bz-card.vhard::before{ background:#C2A0FF; opacity:.8; }

.bz-n{ font-family:var(--mono); font-size:12px; color:var(--bz-glacier); letter-spacing:.5px; }
.bz-t{ margin-top:6px; font-family:var(--display); font-weight:600; font-size:16px; color:var(--bz-frost); }
.bz-ai{ margin-top:10px; font-size:12px; color:var(--bz-ink-soft); line-height:1.45; }

/* ---- LOCKED CARD (a "???" placeholder) ---------------------- */
/* bz-locked is a modifier ON bz-card. Ghost it down and swap the cold
   glass for a faint dashed void, "there is more here" without a reveal.
   It is non-interactive. */
.bz-card.bz-locked{
  border-style:dashed; border-color:rgba(150,170,255,.20);
  background:rgba(255,255,255,.015);
  box-shadow:none; opacity:.5;
  display:grid; place-items:center; text-align:center; min-height:96px;
  cursor:default; pointer-events:none; user-select:none;
}
.bz-card.bz-locked::before{ display:none; }              /* no difficulty rail on a mystery */
.bz-card.bz-locked:hover, .bz-card.bz-locked:focus-visible{ transform:none; box-shadow:none; border-color:rgba(150,170,255,.20); }
.bz-card.bz-locked .bz-n{ color:var(--bz-ink-faint); opacity:.8; }
/* the "???" rides on the title span (span.bz-t.bz-q), the compound
   selector overrides the normal title look into a ghosted mystery. */
.bz-t.bz-q{
  font-family:var(--display); font-weight:700; font-size:26px; letter-spacing:4px;
  color:var(--bz-ink-faint);
}
.bz-lock{ display:block; margin-top:6px; font-size:15px; opacity:.7; filter:grayscale(.3); }

/* ---- PROBLEM VIEW badges/notes (#/problem/281..311) --------- */
.bz-problem{ position:relative; }
/* "off the record, banks nothing": a small, quiet italic pill */
.bz-offrecord{
  display:inline-flex; align-items:center; gap:5px;
  padding:2px 9px; border-radius:999px;
  font-size:10.5px; font-style:italic; font-weight:500; letter-spacing:.3px;
  color:var(--bz-ink-soft);
  background:rgba(167,139,250,.12);
  border:1px solid rgba(167,139,250,.26);
}
.bz-offrecord::before{ content:""; width:5px; height:5px; border-radius:50%; background:var(--bz-violet); opacity:.75; }
/* the off-the-record line inside a run result, and the #311 "no passing
   submission" note. Both sit on the already-styled .note.tip, so we only
   nudge the accent toward the cold violet to mark them as bonus, and make
   #311's note a touch more stark/italic. */
.bz-note{ font-style:italic; }
.bz-nosubmit{ font-style:italic; letter-spacing:.2px; }

/* ---- THE PEAK (#311 "The Unclimbed Peak") ------------------- */
/* the index-view summit: the most stark, cold, near-monochrome treatment.
   `shrouded` = not yet found (faint, unreachable); `found` = revealed. */
.bz-peak{
  margin:clamp(40px,7vw,80px) auto 0; max-width:560px;
}
/* the found summit is rendered as a.bz-card.bz-peak-card, so it inherits
   the .bz-card base; these rules override that into the starkest, near-
   monochrome treatment and we suppress the inherited difficulty rail. */
.bz-peak-card{
  position:relative; overflow:hidden; display:block;
  padding:clamp(30px,5vw,48px) 28px; text-align:center;
  border-radius:var(--r-lg);
  border:1px solid rgba(207,224,255,.18);
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(207,224,255,.10), transparent 60%),
    linear-gradient(180deg, rgba(20,28,60,.9), rgba(8,12,30,.95));
  box-shadow:var(--shadow-lg), inset 0 1px 0 rgba(207,224,255,.14);
  color:inherit; text-decoration:none;
}
.bz-peak-card::after{ content:none; }   /* belt-and-braces: no stray .bz-card pseudo */
/* suppress the inherited .bz-card difficulty rail, the peak has no tier */
.bz-card.bz-peak-card::before{
  content:""; position:absolute; inset:0; left:0; top:0; bottom:0; width:auto;
  border-radius:0; background:linear-gradient(110deg, transparent 35%, rgba(207,224,255,.16) 50%, transparent 65%);
  opacity:1; transform:translateX(-60%); animation:bz-shimmer 7.5s var(--ease) infinite; z-index:0;
}
/* the found summit still lifts gently on hover; keep its own glow, not the
   generic card ring */
.bz-card.bz-peak-card:hover, .bz-card.bz-peak-card:focus-visible{
  transform:translateY(-3px); outline:none;
  border-color:rgba(207,224,255,.4);
  box-shadow:var(--shadow-lg), inset 0 1px 0 rgba(207,224,255,.2), 0 0 0 1px rgba(207,224,255,.22);
}
@keyframes bz-shimmer{ 0%{ transform:translateX(-60%);} 60%,100%{ transform:translateX(60%);} }
.bz-peak-card > *{ position:relative; z-index:1; }
.bz-peak-glyph{
  font-size:30px; line-height:1; display:block;
  filter:grayscale(.35) drop-shadow(0 0 18px rgba(207,224,255,.3));
}
.bz-peak-card .bz-n{ display:block; margin-top:10px; letter-spacing:2px; color:var(--bz-ink-soft); }
.bz-peak-card .bz-t{
  font-size:clamp(24px,4.5vw,38px); line-height:1.04; letter-spacing:-.4px;
  color:var(--bz-frost); text-shadow:0 0 30px rgba(207,224,255,.22);
}
.bz-peak-hint{ margin-top:14px; color:var(--bz-ink-soft); font-size:13px; font-style:italic; }

/* found, #311 once earned: the peak is rendered AS an a.bz-card.bz-peak-card
   (styled above). Just a touch warmer-bright on the glyph. */
.bz-peak.found .bz-peak-glyph{ filter:grayscale(.15) drop-shadow(0 0 22px rgba(207,224,255,.4)); }

/* shrouded, #311 before it's earned: there is NO card here, only the glyph
   and the hint sit directly in .bz-peak.shrouded. We treat the wrapper itself
   as the faint, unreachable summit: a cold panel, dimmed, not clickable. The
   summit you can see but cannot yet touch. (.found and .shrouded are mutually
   exclusive.) */
.bz-peak.shrouded{
  position:relative; overflow:hidden; text-align:center;
  padding:clamp(30px,5vw,48px) 28px;
  border-radius:var(--r-lg);
  border:1px dashed rgba(207,224,255,.16);
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(207,224,255,.06), transparent 60%),
    linear-gradient(180deg, rgba(18,24,52,.85), rgba(8,12,28,.92));
  box-shadow:var(--shadow), inset 0 1px 0 rgba(207,224,255,.08);
  opacity:.7; pointer-events:none; user-select:none;
}
.bz-peak.shrouded .bz-peak-glyph{ filter:grayscale(.7); opacity:.65; }
.bz-peak.shrouded .bz-peak-hint{ color:var(--bz-ink-faint); }

/* ---- KEEP-CLIMBING affordance ------------------------------- */
/* a faint, easily-missed "the air is thin up here…" link. Whisper-quiet:
   low contrast, no button chrome. Meant to be almost overlooked; the
   curious will find it. */
.bz-climb{ display:flex; justify-content:center; margin:clamp(20px,4vw,36px) 0 0; }
.bz-climb-link{
  display:inline-flex; align-items:center; gap:7px;
  padding:6px 4px;
  font-size:12px; letter-spacing:.4px;
  color:var(--ink-faint);                                   /* uses the PUBLIC faint ink, it lives on the public problem page, not in .bz-view */
  background:none; border:0; text-decoration:none; cursor:pointer;
  opacity:.5; transition:opacity .4s var(--ease), color .4s var(--ease);
}
.bz-climb-link:hover, .bz-climb-link:focus-visible{ opacity:.95; color:var(--primary); outline:none; }
.bz-climb-link::after{
  content:"\2191";   /* a faint up-arrow, keep climbing */
  font-size:13px; transform:translateY(0);
  animation:bz-climb-beckon 3.4s ease-in-out infinite;
}
@keyframes bz-climb-beckon{ 0%,100%{ transform:translateY(0); opacity:.6; } 50%{ transform:translateY(-3px); opacity:1; } }

/* ---- REDUCED MOTION ----------------------------------------
   Motion-sensitive climbers: the sky rests, the shimmer and aurora
   still, the arrow stops. Stillness is also a valid summit. The
   global reduce rule (top of file) already disables animations; this
   is belt-and-braces for the load-bearing layered effects. */
@media (prefers-reduced-motion: reduce){
  .bz-view::before{ animation:none; }
  .bz-view::after{ animation:none; transform:none; }
  .bz-card.bz-peak-card::before{ animation:none; transform:none; opacity:.45; }
  .bz-climb-link::after{ animation:none; }
  .bz-card{ transition:none; }
  .bz-climb-link{ transition:none; }
}

/* ============================================================
   CODE-BLAST CANVAS OVERLAY (owned by the cinematic module)
   The hyper-real blast is drawn on a <canvas> the cinematic creates, appends to
   document.body, and removes at teardown, this is just a styling/QA hook (the
   cinematic also sets these same values inline, so the class is belt-and-braces).
   It is a FULL-VIEWPORT fixed overlay (NOT scoped to #ed): the rocket flies in
   from the clicked reference pre and a shard flies out to the Run button, both
   OUTSIDE the editor's box, so the canvas spans the viewport and the blast is
   drawn at the editor's coordinates internally; a canvas clipped to #ed would
   crop the animation. z-index 60 is the SINGLE SOURCE OF TRUTH for the canvas:
   per code-blast.js, the cinematic sets every layout/behaviour property INLINE
   (position/left/top/width/height/pointer-events) but DELIBERATELY NOT z-index,
   leaving this class to own it, because the frontend owns the app's z-index
   scale. So there is no inline-beats-class conflict on z; this value renders. 60
   sits cleanly above Monaco's stacking (~z 1-10) and below our toast (200) /
   modal (1000); the blast is pointer-events:none and transient (~3s, ≤4s cap)
   with no modal co-occurring, so 60 is sufficient. (The legacy .rk-fly / .rk-shard
   DOM overlays at z 9999 are the FALLBACK path, used only when UdaanCodeBlast is
   absent, they never co-occur with this canvas, so the difference is harmless.) */
.code-blast-canvas{
  position:fixed; inset:0; width:100%; height:100%;
  pointer-events:none;      /* never eats a click or a keystroke from the editor */
  z-index:60;               /* single source of truth: cinematic does NOT set z inline; above Monaco, below toast(200)/modal(1000) */
}

/* ✨ worked-example BOMB DETONATION cinematic (UdaanCaseBlast). Same overlay
   contract as .code-blast-canvas: the cinematic sets every layout/behaviour
   property INLINE but DELIBERATELY NOT z-index, leaving this class to own it,
   the frontend owns the z-index scale. 60 sits above Monaco (~z 1-10) and below
   toast(200)/modal(1000); the blast is pointer-events:none and transient
   (~1.5s, ≤2.3s cap), so 60 is sufficient and never co-occurs with a modal. */
.case-blast-canvas{
  position:fixed; inset:0; width:100%; height:100%;
  pointer-events:none;      /* never eats a click or keystroke from the page */
  z-index:60;               /* single source of truth: cinematic does NOT set z inline */
}

/* the case <pre> shakes ONCE at detonation. Transform-only on a real element
   (the canvas overlay is pointer-events:none + full-viewport, so shaking it
   would show nothing). will-change keeps it on the compositor; no layout thrash. */
.case-shake{ animation: case-shake .34s cubic-bezier(.36,.07,.19,.97) both; will-change: transform; }
@keyframes case-shake{
  0%   { transform: translate3d(0,0,0); }
  12%  { transform: translate3d(-5px,2px,0) rotate(-.5deg); }
  26%  { transform: translate3d(6px,-3px,0) rotate(.6deg); }
  42%  { transform: translate3d(-7px,3px,0) rotate(-.4deg); }
  58%  { transform: translate3d(5px,-2px,0) rotate(.4deg); }
  74%  { transform: translate3d(-3px,2px,0) rotate(-.2deg); }
  88%  { transform: translate3d(2px,-1px,0); }
  100% { transform: translate3d(0,0,0); }
}
@media (prefers-reduced-motion: reduce){ .case-shake{ animation:none; } }

/* the bomb button that triggers the detonation (`#caseBomb`, classes
   `btn btn-ghost btn-sm case-bomb`). Tactile + faintly explosive: a warm ember
   glow on hover, a sharp press on active, an accessible focus ring. The fuse
   spark sits in the corner via a pseudo-element so it never shifts layout. */
.case-bomb{ position:relative; overflow:visible; isolation:isolate;
  transition: transform .12s var(--ease), box-shadow .18s, border-color .16s, background .16s, color .16s; }
.case-bomb:hover{
  border-color:#ff7a45; color:#b3320f;
  background:linear-gradient(180deg,#FFF4EC 0%,#FFE9DC 100%);
  box-shadow:0 0 0 1px #ff7a45, 0 6px 18px -8px rgba(255,77,30,.55);
}
.case-bomb::after{ /* fuse spark, idle, brightens on hover */
  content:""; position:absolute; top:-2px; right:-2px; width:6px; height:6px;
  border-radius:50%; background:radial-gradient(circle,#fff0b8 0%,#ff5b2e 70%,transparent 72%);
  opacity:0; transform:scale(.6); pointer-events:none;
  transition:opacity .18s var(--ease), transform .18s var(--ease);
}
.case-bomb:hover::after{ opacity:1; transform:scale(1); animation:case-fuse .9s ease-in-out infinite; }
@keyframes case-fuse{ 0%,100%{ box-shadow:0 0 4px 1px rgba(255,91,46,.7); }
  50%{ box-shadow:0 0 8px 3px rgba(255,179,59,.9); } }
.case-bomb:active{ transform:scale(.94); box-shadow:0 0 0 1px #ff5b2e, 0 0 14px 2px rgba(255,91,46,.45); }
.case-bomb:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(255,122,69,.5); }
@media (prefers-reduced-motion: reduce){
  .case-bomb,.case-bomb::after{ transition:none; }
  .case-bomb:hover::after{ animation:none; }
}

/* ============================================================
   COMPREHENSION CHALLENGE, "you launched the answer, now own it"
   A warm, distinctly-NOT-a-scold card shown after a reference-rocket paste.
   It invites the learner to explain one isolated part for a separate
   Understanding bonus. Reuses the AI-note violet family so it reads as the
   coach speaking, with its own structure. Fully self-contained classes so no
   generic .code / .note rule can bleed in unexpectedly. */
.comprehension{
  margin:16px; padding:16px 18px;
  background:linear-gradient(180deg,#F6EEFF 0%,#F3E8FF 100%);
  border:1px solid #E2CDFB; border-radius:var(--r-lg);
  box-shadow:0 6px 22px rgba(124,58,237,.10);
}
.cmp-head{ display:flex; align-items:flex-start; gap:12px; }
.cmp-ic{ flex:none; font-size:26px; line-height:1.1;
  filter:drop-shadow(0 3px 6px rgba(124,58,237,.30)); }
.cmp-title{ font:800 16px var(--display); color:#5B21B6; letter-spacing:-.01em; }
.cmp-sub{ margin-top:4px; font-size:13px; line-height:1.5; color:var(--ink-soft); }
/* the isolated code, its OWN styling (not the read-only pre.code rocket
   cursor, which must not apply here): a calm card the eye can rest on */
pre.code.cmp-seg{
  margin:14px 0 0; cursor:auto;
  background:#FBF8FF; border:1px solid #E6D4FB; border-left:3px solid #A855F7;
  color:#3A2A5E;
}
.cmp-q{ display:flex; align-items:flex-start; gap:8px; margin:14px 0 0;
  font:600 14px var(--display); color:var(--ink); line-height:1.5; }
.cmp-q-ic{ flex:none; font-size:15px; line-height:1.5; }
.cmp-hint{ margin:8px 0 0; font-size:12.5px; line-height:1.5; color:var(--ink-soft); font-style:italic; }
.cmp-ans{ margin:12px 0 0; width:100%; resize:vertical; }
.cmp-actions{ display:flex; align-items:center; gap:10px; margin:12px 0 0; flex-wrap:wrap; }
.cmp-skip{ color:var(--ink-soft); }
/* the graded verdict, four honest states, none punitive */
.cmp-result{ margin:14px 0 0; padding:12px 14px; border-radius:var(--r-md);
  border:1px solid var(--line); background:var(--surface-2); animation:udaan-lift .35s var(--ease) both; }
.cmp-r-head{ font:700 14px var(--display); }
.cmp-r-fb{ margin:6px 0 0; font-size:13px; line-height:1.5; color:var(--ink-soft); }
.cmp-result.cmp-ok{ background:var(--ok-soft); border-color:#C9E9D4; }
.cmp-result.cmp-ok .cmp-r-head{ color:var(--ok); }
.cmp-result.cmp-partial{ background:var(--accent-soft); border-color:#EFD9AE; }
.cmp-result.cmp-partial .cmp-r-head{ color:var(--warn); }
.cmp-result.cmp-off{ background:var(--info-soft); border-color:#D9D9FB; }
.cmp-result.cmp-off .cmp-r-head{ color:var(--info); }
.cmp-result.cmp-unverified{ background:var(--surface-2); border-color:var(--line); }
.cmp-result.cmp-unverified .cmp-r-head{ color:var(--ink-soft); }
/* the separate Understanding reward, a warm, star-led line, never confused
   with the (paste-zeroed) solve score */
.cmp-bonus{ display:flex; align-items:center; gap:8px; margin:10px 0 0;
  font:700 13.5px var(--display); color:#7C3AED; }
.cmp-xp-total{ font:600 12px var(--display); color:var(--ink-soft); }
/* the negative (paste-penalty) reclaim line, and the locked "Next" affordance
   while a rocket-paste explanation is still owed (the no-bypass gate). The locked
   link keeps pointer-events so its click handler can explain why it is blocked. */
.cmp-bonus.cmp-neg{ color:var(--bad,#D63C44); }
.cmp-gate{ border-color:var(--primary); }
.btn.is-locked{ opacity:.45; cursor:not-allowed; }
@media (prefers-reduced-motion: reduce){
  .comprehension{ animation:none; }
  .cmp-result{ animation:none; }
}
/* dark theme, mirror the AI-note violet family used elsewhere */
[data-theme="dark"] .comprehension{
  background:linear-gradient(180deg,#241A3E 0%,#231A3C 100%);
  border-color:#3A2A5E; box-shadow:0 6px 22px rgba(0,0,0,.35);
}
[data-theme="dark"] .cmp-title{ color:#C4A6FF; }
[data-theme="dark"] pre.code.cmp-seg{
  background:#1C1633; border-color:#3A2A5E; border-left-color:#A855F7; color:#D8CBF2;
}
[data-theme="dark"] .cmp-bonus{ color:#C4A6FF; }

/* ============================================================
   ADMIN PORTAL REDESIGN  (portal.js, Users pagination, Map tool,
   CSV import control, Cohort dashboard). All theme-token based so
   dark mode and reduced-motion are inherited, never hard-coded.
   ============================================================ */

/* the search + filter bar above a paged table */
.udp-filterbar{ display:flex; gap:10px; flex-wrap:wrap; align-items:center; margin:0 0 14px; }
.udp-filterbar .udp-search{ flex:1 1 260px; min-width:200px; max-width:420px; }
.udp-filterbar .select{ max-width:200px; }

/* the "Load more" footer under a paged table */
.udp-loadmore{ display:flex; align-items:center; gap:8px; justify-content:center;
  padding:14px 16px; border-top:1px solid var(--line); background:var(--surface-2); min-height:18px; }
.udp-loadmore:empty{ display:none; }

/* a roster name that links into the student detail */
.udp-link{ color:var(--primary-deep); font-weight:700; text-decoration:none; }
.udp-link:hover{ text-decoration:underline; }

/* ---- CSV import control (replaces the bare file input) ---- */
.csv-drop{ position:relative; display:flex; align-items:center; gap:14px;
  padding:18px 20px; border:2px dashed var(--line-2); border-radius:var(--r-md);
  background:var(--surface-2); cursor:pointer; transition:border-color .15s, background .15s; }
.csv-drop:hover{ border-color:var(--primary); }
.csv-drop:focus-visible{ outline:none; box-shadow:var(--ring); border-color:var(--primary); }
.csv-drop.drag{ border-color:var(--primary); background:var(--primary-soft); }
/* the real input stays focusable for keyboard + screen readers, but is
   visually hidden so the styled zone is the visible target (no double-click
   conflict: the input does not overlay the zone). */
.csv-input{ position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
.csv-input:focus-visible + .csv-ic{ box-shadow:var(--ring); border-radius:8px; }
.csv-ic{ font-size:26px; line-height:1; flex:0 0 auto; }
.csv-copy{ display:flex; flex-direction:column; gap:2px; }
.csv-cta{ font-weight:700; color:var(--primary-deep); font-size:14px; }
.csv-hint{ color:var(--ink-soft); font-size:12.5px; }
.csv-file{ margin-left:auto; font-size:12.5px; color:var(--ink); font-weight:600;
  max-width:40%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.csv-file:empty::before{ content:""; }
@media (prefers-reduced-motion: reduce){ .csv-drop{ transition:none; } }

/* ---- map-students tool ---- */
.map-toolbar{ display:flex; gap:12px; flex-wrap:wrap; align-items:flex-end; margin-bottom:14px; }
.map-toolbar .field{ display:flex; flex-direction:column; gap:4px; }
.map-lbl{ font-size:12px; font-weight:700; color:var(--ink-soft); }
.map-check{ width:18px; height:18px; accent-color:var(--primary); cursor:pointer; vertical-align:middle; }

/* ---- cohort dashboard rollup ---- */
.cohort-bar{ display:inline-block; width:84px; height:8px; border-radius:999px;
  background:var(--surface-3); overflow:hidden; vertical-align:middle; margin-right:8px; }
.cohort-fill{ display:block; height:100%; border-radius:999px;
  background:linear-gradient(90deg,var(--primary-2),var(--primary)); transition:width .4s ease; }
.cohort-pct{ font-size:12.5px; color:var(--ink-soft); font-weight:600; vertical-align:middle; }
.cohort-risk{ color:var(--warn); font-weight:700; }
.table tr.row-risk{ background:var(--warn-soft); }
@media (prefers-reduced-motion: reduce){ .cohort-fill{ transition:none; } }
@media (max-width: 620px){
  .udp-filterbar .select{ max-width:none; flex:1 1 auto; }
  .csv-file{ max-width:100%; margin-left:0; }
}

/* ============================================================
   ROLE PANEL HOMES, teacher & HoS panel landings (portal.js)
   The teaching/section homes lead with stats, then "my batch"
   cards and quick-action lanes. Built from the existing design
   tokens so they sit consistently alongside the admin console.
   ============================================================ */

/* "my batches", a responsive card grid; each card drills into the
   per-batch surface. Reuses .card-hover for the lift affordance. */
.rp-batch-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr));
  gap:14px; }
.rp-batch{ display:flex; flex-direction:column; gap:8px; background:var(--surface);
  border:1px solid var(--line); border-radius:var(--r-md); padding:16px 18px;
  cursor:pointer; box-shadow:var(--shadow-sm); }
.rp-batch:focus-visible{ outline:none; box-shadow:var(--ring); }
.rp-batch-head{ display:flex; align-items:center; justify-content:space-between; gap:8px; }
.rp-batch-name{ font-family:var(--display); font-weight:700; font-size:15.5px;
  color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rp-batch-sec{ font-size:12.5px; color:var(--ink-soft); font-weight:600; margin-top:-2px; }
.rp-batch-stats{ display:flex; gap:16px; margin-top:4px; }
.rp-bs{ display:flex; flex-direction:column; }
.rp-bs b{ font-size:18px; font-weight:800; color:var(--primary-deep); line-height:1.1; }
.rp-bs span{ font-size:11px; color:var(--ink-soft); font-weight:600; }
.rp-batch-open{ margin-top:auto; padding-top:4px; color:var(--primary-deep);
  font-weight:700; font-size:12.5px; }

/* quick-action lanes, a stacked list of icon + label + purpose + chevron */
.rp-lanes{ display:grid; grid-template-columns:repeat(2,1fr); gap:12px; }
.rp-lane{ display:flex; align-items:center; gap:14px; background:var(--surface);
  border:1px solid var(--line); border-radius:var(--r-md); padding:14px 16px;
  cursor:pointer; box-shadow:var(--shadow-sm); }
.rp-lane:focus-visible{ outline:none; box-shadow:var(--ring); }
.rp-lane-ic{ width:40px; height:40px; flex:0 0 auto; border-radius:10px;
  background:var(--primary-soft); color:var(--primary-deep); display:grid;
  place-items:center; font-size:19px; }
.rp-lane-body{ flex:1; min-width:0; }
.rp-lane-t{ font-weight:700; font-size:14.5px; color:var(--ink); }
.rp-lane-d{ font-size:12.5px; color:var(--ink-soft); }
.rp-lane-go{ flex:0 0 auto; color:var(--primary-deep); font-weight:800; font-size:18px;
  transition:transform .15s ease; }
.rp-lane:hover .rp-lane-go{ transform:translateX(3px); }

@media (max-width: 720px){
  .rp-lanes{ grid-template-columns:1fr; }
}
@media (prefers-reduced-motion: reduce){
  .rp-lane-go{ transition:none; }
  .rp-lane:hover .rp-lane-go{ transform:none; }
}

/* the "at-risk only" filter toggle in the class roster filter bar */
.cq-toggle{ display:inline-flex; align-items:center; gap:7px; font-size:13px;
  font-weight:600; color:var(--ink-soft); cursor:pointer; white-space:nowrap;
  padding:0 4px; }
.cq-toggle input{ width:17px; height:17px; accent-color:var(--primary); cursor:pointer; }

/* ============================================================
   CLASSROOM-LMS LEARNER SURFACES
   Progress markers, stacked certificates, the KIND attendance widget,
   doubts/Q&A, assignment badges and the course-window banner. All built
   on the :root tokens; reduced-motion + responsive at the foot of each
   group. Celebratory and light, feedback, never gates.
   ============================================================ */

/* ---- Layer-1 progress markers ---- */
/* compact endowed-progress chip (block lists, journey) */
.marker-chip{ display:inline-flex; align-items:center; gap:5px; font-size:11.5px;
  font-weight:700; color:var(--primary-deep); background:var(--primary-soft);
  border:1px solid transparent; border-radius:999px; padding:3px 9px; line-height:1.2; }
.marker-chip .mc-ic{ font-size:11px; }
.marker-chip.mastered{ color:var(--star-deep); background:var(--star-soft);
  border-color:var(--star-glow); }

/* the block-view progress strip */
.block-progress{ background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-md); padding:14px 16px; margin:14px 0 4px; box-shadow:var(--shadow-sm);
  background-image:linear-gradient(135deg, var(--primary-soft) 0%, transparent 48%); }
.block-progress .bp-top{ display:flex; align-items:center; justify-content:space-between;
  gap:10px; flex-wrap:wrap; }
.bp-seq{ font-size:12px; font-weight:700; letter-spacing:.04em; color:var(--ink-soft);
  text-transform:uppercase; }
.bp-count{ font-size:13.5px; font-weight:800; color:var(--primary-deep); }
.bp-marker{ font-size:13px; font-weight:800; color:var(--star-deep); }
.bp-bar{ height:8px; border-radius:999px; background:var(--surface-3); overflow:hidden;
  margin:10px 0 8px; }
.bp-bar i{ display:block; height:100%; border-radius:999px;
  background:linear-gradient(90deg, var(--primary), var(--primary-2));
  transition:width .5s var(--ease); }
.block-progress.mastered .bp-bar i,
.bp-marker ~ .bp-bar i{ background:linear-gradient(90deg, var(--star-gold), var(--star-glow)); }
.bp-note{ font-size:12.5px; color:var(--ink-soft); margin:0; }

/* one-off mastery marker injected into the solve result */
.solve-marker{ display:flex; align-items:center; gap:12px; margin:0 0 12px;
  padding:12px 16px; border-radius:var(--r-md);
  background:linear-gradient(135deg, var(--star-soft), #FFF6E0);
  border:1px solid var(--star-glow);
  box-shadow:0 0 0 1px rgba(232,163,23,.16), 0 4px 14px -6px rgba(181,116,12,.4); }
.solve-marker .sm-ic{ font-size:24px; filter:drop-shadow(0 0 5px rgba(246,199,82,.7)); }
.sm-t{ font-weight:800; color:var(--star-deep); font-size:15px; }
.sm-seq{ font-size:12px; color:var(--ink-soft); }
/* journey block mastered accent */
.block.mastered .block-star{ filter:drop-shadow(0 0 4px rgba(246,199,82,.7)); }
.block.mastered .progress i{ background:linear-gradient(90deg, var(--star-gold), var(--star-glow)); }

/* ---- Layer-2 stacked certificates ---- */
.cred-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(290px,1fr));
  gap:14px; }
/* the nested "part of a whole" line on an earned card */
.cred-nest{ font-size:11.5px; font-weight:700; letter-spacing:.04em; color:var(--accent);
  text-transform:uppercase; margin-bottom:4px; }
.cred-block .cred-seal{ font-size:26px; }
/* the programme capstone, the milestone, given extra presence */
.cred-capstone{ background-image:var(--dawn-grad); color:#fff; border-color:transparent;
  box-shadow:var(--shadow-lg); }
.cred-capstone .cred-issuer{ color:#FFE9C7; }
.cred-capstone .cred-nest{ color:#FFE9C7; }
.cred-capstone .cred-title{ color:#fff; }
.cred-capstone .cred-sub,.cred-capstone .cred-detail{ color:rgba(255,255,255,.92); }
.cred-capstone .cred-meta{ color:rgba(255,255,255,.78); }
.cred-capstone-wrap{ margin-bottom:8px; }
.cred-capstone-wrap .cred-preview.cred-capstone{ background-image:var(--dawn-grad); color:#fff; }
.cred-capstone-wrap .cred-capstone .cp-nest,
.cred-capstone-wrap .cred-capstone .cp-title{ color:#fff; }
.cred-capstone-wrap .cred-capstone .cp-status{ color:rgba(255,255,255,.92); }

/* locked / eligible preview cards, honest about what is not yet earned */
.cred-preview{ position:relative; background:var(--surface); border:1px solid var(--line-2);
  border-radius:var(--r-lg); padding:20px 18px; box-shadow:var(--shadow-sm); }
.cred-preview.locked{ opacity:.92; background:var(--surface-2);
  border-style:dashed; }
.cred-preview.eligible{ border-color:var(--ok);
  background-image:linear-gradient(135deg, var(--ok-soft) 0%, transparent 46%); }
.cp-seal{ position:absolute; top:16px; right:18px; font-size:26px; }
.cp-nest{ font-size:11px; font-weight:700; letter-spacing:.05em; color:var(--accent);
  text-transform:uppercase; }
.cp-title{ font-family:var(--display); font-size:18px; font-weight:700; color:var(--ink);
  margin:5px 0 6px; padding-right:36px; letter-spacing:-.01em; }
.cp-status{ font-size:12.5px; font-weight:600; color:var(--ink-faint); }
.cp-status.eligible{ color:var(--ok); font-weight:800; }
.cp-bar{ height:7px; border-radius:999px; background:var(--surface-3); overflow:hidden;
  margin:10px 0 6px; }
.cp-bar i{ display:block; height:100%; border-radius:999px;
  background:linear-gradient(90deg, var(--primary), var(--primary-2)); transition:width .5s var(--ease); }
.cred-preview.eligible .cp-bar i{ background:linear-gradient(90deg, var(--ok), #34D399); }
.cp-count{ font-size:12px; color:var(--ink-soft); font-weight:600; }

/* ---- attendance (KIND, up-only) ---- */
.attend-card{ background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-md); padding:16px 18px; margin:0 0 16px; box-shadow:var(--shadow-sm);
  background-image:linear-gradient(135deg, var(--accent-soft) 0%, transparent 50%); }
.at-head{ display:flex; align-items:center; gap:8px; margin-bottom:6px; }
.at-ic{ font-size:18px; }
.at-title{ font-weight:800; font-size:14px; color:var(--ink); letter-spacing:.01em; }
.at-headline{ font-size:17px; font-weight:800; color:var(--ink); line-height:1.35; }
.at-bar{ height:9px; border-radius:999px; background:var(--surface-3); overflow:hidden;
  margin:11px 0 9px; }
.at-bar i{ display:block; height:100%; border-radius:999px;
  background:linear-gradient(90deg, var(--accent), var(--accent-warm)); transition:width .6s var(--ease); }
.at-chips{ display:flex; flex-wrap:wrap; gap:8px; margin:6px 0 4px; }
.at-chip{ font-size:12px; font-weight:700; color:var(--star-deep); background:var(--star-soft);
  border:1px solid var(--star-glow); border-radius:999px; padding:3px 10px; }
.at-note{ font-size:12.5px; color:var(--ink-soft); margin:8px 0 0; line-height:1.5; }
.at-note.good{ color:var(--ok); font-weight:600; }

/* ---- assignment labels (overlay, never a gate) ---- */
.assign-chip{ display:inline-flex; align-items:center; gap:4px; font-size:11px;
  font-weight:800; color:var(--primary-deep); background:var(--primary-soft);
  border:1px solid var(--primary-2); border-radius:999px; padding:2px 8px; line-height:1.3;
  white-space:nowrap; }
.assign-chip.req{ color:#9A3412; background:var(--warn-soft); border-color:var(--warn); }
.assign-chip .ac-pin{ font-size:10px; }
.pitem.assigned{ box-shadow:inset 3px 0 0 var(--primary); }
.block.assigned{ box-shadow:inset 0 0 0 1.5px var(--primary-2), var(--shadow-sm); }
.assign-banner{ background:var(--primary-soft); border:1px solid var(--primary-2);
  border-radius:var(--r-md); padding:12px 16px; margin:14px 0 0;
  border-left:4px solid var(--primary); }
.ab-head{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.ab-pin{ font-size:14px; }
.ab-title{ font-weight:800; font-size:14px; color:var(--primary-deep); }
.ab-due{ font-size:12px; font-weight:700; color:#9A3412; background:var(--warn-soft);
  border-radius:999px; padding:2px 9px; margin-left:auto; }
.ab-why{ font-size:13px; color:var(--ink-soft); margin:6px 0 0; line-height:1.5; }

/* ---- course-window banner (informational only) ---- */
.course-window{ display:flex; align-items:flex-start; gap:12px; margin:14px 0 0;
  padding:12px 16px; border-radius:var(--r-md);
  background:var(--surface-2); border:1px solid var(--line); }
.course-window.cw-closed{ background:var(--surface-3); }
.cw-ic{ font-size:20px; flex:0 0 auto; line-height:1.2; }
.cw-head{ font-weight:800; font-size:14px; color:var(--ink); }
.cw-sec{ font-weight:600; color:var(--ink-soft); }
.cw-sub{ font-size:12.5px; color:var(--ink-soft); margin:3px 0 0; line-height:1.5; }

/* ---- doubts / Q&A ---- */
.doubts{ background:var(--surface); border:1px solid var(--line); border-radius:var(--r-md);
  padding:16px 18px; box-shadow:var(--shadow-sm); }
.doubts-head{ display:flex; align-items:center; gap:8px; }
.dh-ic{ font-size:18px; }
.dh-t{ font-weight:800; font-size:15px; color:var(--ink); }
.doubts-sub{ font-size:13px; color:var(--ink-soft); margin:5px 0 12px; line-height:1.5; }
.doubt-compose .textarea{ width:100%; }
.doubt-list{ display:flex; flex-direction:column; gap:10px; margin-top:12px; }
.doubt-card{ border:1px solid var(--line); border-radius:var(--r-sm); padding:12px 14px;
  background:var(--surface-2); }
.doubt-card.answered{ background:var(--ok-soft); border-color:#BBE7C9; }
.dc-top{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:7px; }
.doubt-badge{ font-size:11px; font-weight:800; border-radius:999px; padding:2px 9px;
  letter-spacing:.02em; }
.doubt-badge.open{ color:var(--warn); background:var(--warn-soft); }
.doubt-badge.answered{ color:var(--ok); background:#D7F2E0; }
.dc-prob{ font-size:12px; font-weight:700; color:var(--primary-deep); text-decoration:none; }
.dc-prob:hover{ text-decoration:underline; }
.dc-when{ font-size:11.5px; color:var(--ink-faint); margin-left:auto; }
.dc-q{ font-size:13.5px; color:var(--ink); line-height:1.5; white-space:pre-wrap; }
.dc-answer{ margin-top:10px; padding-top:10px; border-top:1px dashed var(--line-2); }
.dc-a-head{ font-size:12px; font-weight:800; color:var(--ok); margin-bottom:4px; }
.dc-a-body{ font-size:13px; color:var(--ink-soft); line-height:1.55; white-space:pre-wrap; }
.empty.small{ padding:14px; text-align:center; color:var(--ink-faint); font-size:13px; }

@media (max-width: 720px){
  .cred-grid{ grid-template-columns:1fr; }
  .ab-due{ margin-left:0; }
}
@media (prefers-reduced-motion: reduce){
  .bp-bar i,.cp-bar i,.at-bar i,.block.mastered .progress i{ transition:none; }
  .solve-marker .sm-ic,.attend-card .at-ic{ filter:none; }
}

/* ---- authored problems ("Your teacher's problems") ---- */
.authored-head{ display:flex; align-items:flex-start; gap:12px; margin:8px 0 12px; }
.authored-head .ah-ic{ font-size:24px; flex:0 0 auto; line-height:1.1; }
.authored-list .pitem-no{ color:var(--primary-deep); }

/* ---- dark mode ---- */
[data-theme="dark"] .block-progress{ background-image:linear-gradient(135deg, #231A3C 0%, transparent 48%); }
[data-theme="dark"] .marker-chip{ background:#231A3C; color:#C4B5FF; }
[data-theme="dark"] .marker-chip.mastered{ background:#2C2410; color:#F6C752; border-color:#4A3A1A; }
[data-theme="dark"] .solve-marker{ background:linear-gradient(135deg, #2C2410, #221B0C); border-color:#4A3A1A; }
[data-theme="dark"] .cred-preview.locked{ background:#1B1B2F; }
[data-theme="dark"] .cred-preview.eligible{ background-image:linear-gradient(135deg, #14301F 0%, transparent 46%); }
[data-theme="dark"] .attend-card{ background-image:linear-gradient(135deg, #2C2410 0%, transparent 50%); }
[data-theme="dark"] .at-chip{ background:#2C2410; color:#F6C752; border-color:#4A3A1A; }
[data-theme="dark"] .assign-chip{ background:#231A3C; color:#C4B5FF; }
[data-theme="dark"] .assign-chip.req{ background:#33260F; color:#F0C27A; border-color:#5A431A; }
[data-theme="dark"] .assign-banner{ background:#231A3C; border-color:#3A2A5E; }
[data-theme="dark"] .ab-title{ color:#C4B5FF; }
[data-theme="dark"] .ab-due{ background:#33260F; color:#F0C27A; }
[data-theme="dark"] .doubt-card.answered{ background:#14301F; border-color:#1F4030; }
[data-theme="dark"] .doubt-badge.answered{ background:#1F4030; }

/* ============================================================
   WAVE 2, AI-SKILL SURFACES, prompt the AI, pair with it, judge it.
   Tactile, on-brand: soft surfaces, hairline borders, the indigo accent,
   micro-transitions disabled under reduced-motion. No new colour tokens.
   ============================================================ */
.ai-skill{ border:1px solid var(--line); border-radius:14px; background:var(--surface-2);
  margin-bottom:12px; overflow:hidden; }
.ai-skill[open]{ box-shadow:0 2px 14px rgba(79,70,229,.07); }
.ai-skill-sum{ list-style:none; cursor:pointer; padding:13px 15px; font-weight:700;
  display:flex; align-items:center; gap:9px; color:var(--ink); user-select:none;
  transition:background .14s var(--ease); }
.ai-skill-sum::-webkit-details-marker{ display:none; }
.ai-skill-sum:hover{ background:var(--surface-3); }
.ai-skill-sum:focus-visible{ outline:2px solid var(--primary-deep); outline-offset:-2px; }
.ai-skill-ic{ font-size:18px; }
.ai-skill-tag{ margin-left:auto; font-size:11px; font-weight:700; letter-spacing:.02em;
  color:var(--primary-deep); background:var(--primary-soft); padding:3px 9px; border-radius:999px; }
.ai-skill-body{ padding:4px 15px 16px; }
.ai-skill-lead{ color:var(--ink-soft); font-size:13.5px; line-height:1.55; margin:0 0 12px; }
.ai-skill-label{ display:block; font-size:13px; font-weight:600; color:var(--ink-soft); margin:0 0 6px; }
.ai-skill-input{ width:100%; box-sizing:border-box; border:1px solid var(--line); border-radius:10px;
  background:var(--surface); color:var(--ink); padding:10px 12px; font-size:14px; font-family:inherit;
  resize:vertical; transition:border-color .14s var(--ease), box-shadow .14s var(--ease); }
.ai-skill-input:focus{ outline:none; border-color:var(--primary-deep); box-shadow:0 0 0 3px var(--primary-soft); }
.ai-skill-left{ font-size:12.5px; color:var(--ink-faint); }
.ai-skill-result{ margin-top:14px; }
.ai-skill-hint{ font-size:13px; color:var(--ink-soft); background:var(--surface-3);
  border-radius:10px; padding:11px 13px; line-height:1.5; }
.ai-gen-head{ display:flex; align-items:center; gap:10px; margin-bottom:8px; font-size:13px; }
.ai-gen-code{ max-height:280px; overflow:auto; }

/* the AI-assisted disclosure, deliberately calm + honest, never alarming */
.ai-assist-disclose{ margin:2px 0 12px; }

/* pair-programming conversation */
.ai-pair-log{ display:flex; flex-direction:column; gap:9px; max-height:340px; overflow-y:auto;
  padding:4px 2px; }
.ai-pair-opener{ font-size:13px; color:var(--ink-soft); background:var(--surface-3);
  border-radius:10px; padding:11px 13px; line-height:1.5; }
.ai-bubble{ display:flex; flex-direction:column; gap:2px; max-width:88%; padding:9px 12px;
  border-radius:13px; font-size:13.5px; line-height:1.5; }
.ai-bubble-who{ font-size:10.5px; font-weight:700; letter-spacing:.03em; text-transform:uppercase; opacity:.7; }
.ai-bubble-me{ align-self:flex-end; background:var(--primary-soft); color:var(--ink); border-bottom-right-radius:4px; }
.ai-bubble-ai{ align-self:flex-start; background:var(--surface-3); color:var(--ink); border-bottom-left-radius:4px; }
.ai-bubble-think{ color:var(--ink-faint); }
.ai-bubble-txt{ white-space:pre-wrap; word-break:break-word; }

/* judge-the-AI card */
.judge-card{ padding:20px; }
.judge-framing{ font-size:15px; font-weight:600; color:var(--ink); line-height:1.5; margin-bottom:10px; }
.judge-concept{ margin-bottom:12px; }
.judge-code{ max-height:340px; overflow:auto; margin:0 0 16px; }
.judge-verdict{ display:flex; gap:10px; flex-wrap:wrap; }
.judge-opt{ flex:1; min-width:140px; }
.judge-opt.on{ background:var(--primary-soft); color:var(--primary-deep); border-color:var(--primary-deep); }
.judge-opt:focus-visible{ outline:2px solid var(--primary-deep); outline-offset:2px; }
.judge-result{ margin-top:4px; }
.judge-outcome{ margin-top:16px; border-radius:12px; padding:14px 16px; }
.judge-outcome.good{ background:var(--ok-soft, #E7F6EC); }
.judge-outcome.bad{ background:var(--surface-3); }
.judge-outcome-h{ font-weight:700; font-size:15px; color:var(--ink); }
.judge-outcome-fb{ margin:7px 0 0; font-size:13.5px; color:var(--ink-soft); line-height:1.55; }
.judge-grade{ margin-top:8px; font-size:12.5px; font-weight:700; color:var(--primary-deep); }

[data-theme="dark"] .ai-skill[open]{ box-shadow:0 2px 14px rgba(0,0,0,.3); }
[data-theme="dark"] .judge-outcome.good{ background:#14301F; }

@media (prefers-reduced-motion: reduce){
  .ai-skill-sum, .ai-skill-input, .nav-item{ transition:none; }
}

/* ============================================================
   APTITUDE PRACTICE (#/aptitude) — Wave 4. Off-record timed decks.
   Reuses .sim-bar / .sim-clock for the countdown; the rest is local.
   ============================================================ */
.apt-picker{ display:grid; grid-template-columns:repeat(2,1fr); gap:12px; margin:6px 0 22px; }
@media (max-width:480px){ .apt-picker{ grid-template-columns:1fr; } }
.apt-pick{ display:flex; align-items:center; gap:12px; text-align:left; padding:16px 18px;
  border:1px solid var(--line); border-radius:14px; background:var(--surface); color:var(--ink);
  cursor:pointer; font:inherit; box-shadow:0 1px 0 rgba(0,0,0,.03);
  transition:border-color .14s var(--ease), transform .14s var(--ease), box-shadow .14s var(--ease); }
.apt-pick:hover{ border-color:var(--primary-deep); transform:translateY(-1px); box-shadow:0 4px 16px rgba(0,0,0,.07); }
.apt-pick:focus-visible{ outline:2px solid var(--primary-deep); outline-offset:2px; }
.apt-pick-ic{ font-size:24px; line-height:1; }
.apt-pick-l{ font-size:15px; font-weight:600; }

.apt-bar{ margin-bottom:16px; }
.apt-card{ padding:20px; }
.apt-sec-tag{ margin-bottom:12px; display:inline-block; }
.apt-passage{ font-size:14px; color:var(--ink-soft); line-height:1.6; background:var(--surface-3);
  border-radius:10px; padding:12px 14px; margin-bottom:14px; white-space:pre-wrap; }
.apt-q{ font-size:16px; font-weight:600; color:var(--ink); line-height:1.55; margin-bottom:16px; white-space:pre-wrap; }

.apt-choices{ display:flex; flex-direction:column; gap:10px; }
.apt-choice{ display:flex; align-items:center; gap:12px; text-align:left; width:100%;
  padding:12px 14px; border:1px solid var(--line); border-radius:12px; background:var(--surface);
  color:var(--ink); cursor:pointer; font:inherit;
  transition:border-color .12s var(--ease), background .12s var(--ease); }
.apt-choice:hover:not(:disabled){ border-color:var(--primary-deep); }
.apt-choice:focus-visible{ outline:2px solid var(--primary-deep); outline-offset:2px; }
.apt-choice:disabled{ cursor:default; opacity:.85; }
.apt-choice.picked{ background:var(--primary-soft); border-color:var(--primary-deep); }
.apt-choice.apt-correct{ background:var(--ok-soft,#E7F6EC); border-color:#2Fae66; }
.apt-choice-k{ flex:none; width:26px; height:26px; border-radius:7px; display:inline-flex;
  align-items:center; justify-content:center; font:700 13px var(--mono); background:var(--surface-3);
  color:var(--ink-soft); }
.apt-choice.apt-correct .apt-choice-k{ background:#2FAE66; color:#fff; }
.apt-choice-t{ font-size:14.5px; line-height:1.4; }

.apt-numeric{ margin-top:4px; }
.apt-num-in{ max-width:200px; font-family:var(--mono); }

.apt-reveal{ margin-top:4px; }
.apt-outcome{ margin-top:16px; border-radius:12px; padding:14px 16px; }
.apt-outcome.good{ background:var(--ok-soft,#E7F6EC); }
.apt-outcome.bad{ background:var(--surface-3); }
.apt-outcome-h{ font-weight:700; font-size:15px; color:var(--ink); }
.apt-method{ margin:8px 0 0; font-size:13.5px; color:var(--ink-soft); line-height:1.6; white-space:pre-wrap; }

/* the practice summary under the picker */
.apt-summary{ padding:18px 20px; margin-top:4px; }
.apt-summary-h{ font-size:14px; font-weight:700; color:var(--ink); margin-bottom:12px; }
.apt-overall{ display:flex; align-items:baseline; gap:10px; margin-bottom:14px; }
.apt-overall-n{ font:800 30px var(--mono); color:var(--primary-deep); line-height:1; }
.apt-overall-l{ font-size:13px; color:var(--ink-soft); }
.apt-est{ font-size:10.5px; font-weight:700; letter-spacing:.04em; text-transform:uppercase;
  color:var(--ink-faint); background:var(--surface-3); padding:1px 6px; border-radius:6px; vertical-align:middle; }
.apt-srow{ display:flex; align-items:center; gap:10px; margin:8px 0; }
.apt-srow-l{ flex:none; width:34%; font-size:13px; color:var(--ink-soft); }
.apt-srow-bar{ flex:1; height:8px; border-radius:5px; background:var(--surface-3); overflow:hidden; }
.apt-srow-fill{ display:block; height:100%; background:var(--primary-deep); border-radius:5px;
  transition:width .4s var(--ease); }
.apt-srow-pct{ flex:none; width:42px; text-align:right; font:700 13px var(--mono); color:var(--ink); }

/* the end-of-deck card */
.apt-done{ padding:28px 24px; text-align:center; }
.apt-done-ic{ font-size:42px; line-height:1; }
.apt-done-line{ font-size:15.5px; color:var(--ink); margin:10px 0 0; }
.apt-done-sub{ font-size:13px; color:var(--ink-soft); margin:8px 0 0; line-height:1.55; }
.apt-done .row{ justify-content:center; }

[data-theme="dark"] .apt-outcome.good{ background:#14301F; }
[data-theme="dark"] .apt-choice.apt-correct{ background:#14301F; }

@media (prefers-reduced-motion: reduce){
  .apt-pick, .apt-choice, .apt-srow-fill{ transition:none; }
  .apt-pick:hover{ transform:none; }
}

/* ============================================================
   MOCK INTERVIEW (#/interview) — Wave 4. Chat-turn UI reusing the
   pair-panel bubbles (.ai-bubble*, .ai-pair-log); the rest is local.
   ============================================================ */
.ivw-picker{ display:flex; flex-direction:column; gap:12px; margin:6px 0 8px; }
.ivw-pick{ display:flex; align-items:flex-start; gap:14px; text-align:left; padding:16px 18px;
  border:1px solid var(--line); border-radius:14px; background:var(--surface); color:var(--ink);
  cursor:pointer; font:inherit; box-shadow:0 1px 0 rgba(0,0,0,.03);
  transition:border-color .14s var(--ease), transform .14s var(--ease), box-shadow .14s var(--ease); }
.ivw-pick:hover{ border-color:var(--primary-deep); transform:translateY(-1px); box-shadow:0 4px 16px rgba(0,0,0,.07); }
.ivw-pick:focus-visible{ outline:2px solid var(--primary-deep); outline-offset:2px; }
.ivw-pick-ic{ font-size:24px; line-height:1.1; }
.ivw-pick-b{ display:flex; flex-direction:column; gap:3px; }
.ivw-pick-l{ font-size:15px; font-weight:600; }
.ivw-pick-d{ font-size:13px; color:var(--ink-soft); line-height:1.5; }

.ivw-head{ display:flex; align-items:center; gap:12px; padding:12px 14px; margin-bottom:14px;
  border:1px solid var(--line); border-radius:12px; background:var(--surface); }
.ivw-head-ic{ font-size:22px; line-height:1; }
.ivw-head-l{ font-size:15px; font-weight:700; color:var(--ink); }
.ivw-head-sub{ font-size:12.5px; color:var(--ink-soft); }
.ivw-log{ max-height:50vh; min-height:160px; }
.ivw-compose{ margin-top:12px; }
.ivw-wrapup{ display:flex; align-items:center; gap:14px; flex-wrap:wrap; padding:12px 0; }
.ivw-wrapup-l{ font-size:14px; color:var(--ink); margin:0; flex:1; min-width:200px; }

.ivw-rubric{ margin-top:8px; }
.ivw-rubric-card{ padding:18px 20px; }
.ivw-rubric-h{ font-size:14px; font-weight:700; color:var(--ink); margin-bottom:14px; }
.ivw-axis{ display:flex; align-items:center; gap:10px; margin:9px 0; }
.ivw-axis-l{ flex:none; width:42%; font-size:13px; color:var(--ink-soft); }
.ivw-axis-bar{ flex:1; height:8px; border-radius:5px; background:var(--surface-3); overflow:hidden; }
.ivw-axis-fill{ display:block; height:100%; background:var(--primary-deep); border-radius:5px;
  transition:width .4s var(--ease); }
.ivw-axis-n{ flex:none; width:30px; text-align:right; font:700 13px var(--mono); color:var(--ink); }
.ivw-note{ margin:12px 0 0; font-size:13.5px; color:var(--ink-soft); line-height:1.6;
  background:var(--surface-3); border-radius:10px; padding:11px 13px; }

@media (prefers-reduced-motion: reduce){
  .ivw-pick, .ivw-axis-fill{ transition:none; }
  .ivw-pick:hover{ transform:none; }
}

/* ============================================================
   COMMUNICATION HUB (#/communication) — the phased communication track.
   The hub cards are local; the in-mock chat + STAR rubric REUSE the
   mock-interview tokens (.ivw-head / .ivw-log / .ivw-axis* / .ivw-note)
   and the labelled-estimate chip (.apt-est), so the surfaces stay
   visually one family. All colour comes from theme variables (dark-theme
   parity is automatic). i18n / a11y: focus-visible rings, no colour-only cues.
   ============================================================ */
.comm-hub{ display:flex; flex-direction:column; gap:14px; margin:6px 0 8px; }
.comm-card{ display:flex; align-items:flex-start; gap:14px; padding:16px 18px;
  border:1px solid var(--line); border-radius:14px; background:var(--surface);
  box-shadow:0 1px 0 rgba(0,0,0,.03); }
.comm-card-ic{ font-size:26px; line-height:1.1; flex:none; }
.comm-card-body{ flex:1; min-width:0; }
.comm-card-t{ font-size:15.5px; font-weight:700; color:var(--ink); display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.comm-card-d{ font-size:13.5px; color:var(--ink-soft); line-height:1.55; margin-top:5px; }
/* the live card carries a hairline accent so the active phase reads first */
.comm-card-live{ border-color:var(--primary-deep); box-shadow:0 4px 16px rgba(0,0,0,.06); }
/* "coming soon" cards are visibly dimmed and non-interactive (no hover lift,
   not focusable), so the roadmap is honest, never a dead button */
.comm-card-soon{ opacity:.62; }
.comm-soon-tag{ font-size:10.5px; font-weight:700; letter-spacing:.04em; text-transform:uppercase;
  color:var(--warn); background:var(--warn-soft); border-radius:999px; padding:2px 9px; }

/* the long-form answer textarea (STAR answers run long) */
.comm-answer{ width:100%; box-sizing:border-box; border:1px solid var(--line); border-radius:10px;
  background:var(--surface); color:var(--ink); padding:10px 12px; font-size:14px; font-family:inherit;
  line-height:1.55; resize:vertical; min-height:96px;
  transition:border-color .14s var(--ease), box-shadow .14s var(--ease); }
.comm-answer:focus{ outline:none; border-color:var(--primary-deep); box-shadow:0 0 0 3px var(--primary-soft); }
.comm-hint{ font-size:12px; }

/* the STAR rubric extras (the bars/note reuse .ivw-*) */
.comm-rubric-sub{ margin:-6px 0 10px; font-size:12.5px; }
/* the honest estimate banner, shown only when the rubric is a heuristic floor */
.comm-est-note{ font-size:12.5px; color:var(--ink-soft); background:var(--warn-soft);
  border:1px solid var(--warn); border-radius:10px; padding:9px 12px; line-height:1.5; margin:0 0 12px; }
/* provenance shown to EVERY learner (why this matters / what to do next) — these
   are growth feedback, NOT the citeMode-gated research provenance */
.comm-prov{ margin-top:12px; }
.comm-prov-k{ font-size:11.5px; font-weight:700; letter-spacing:.02em; text-transform:uppercase; color:var(--primary-deep); }
.comm-prov-v{ margin:3px 0 0; font-size:13.5px; color:var(--ink-soft); line-height:1.6; }

/* ============================================================
   STEP-THROUGH visualiser (the "Step through it" tab) — Wave 3.
   GPU-cheap (transform/opacity/background only; no animated blur), keyboard-
   first, reduced-motion aware. Watches Python run line by line.
   ============================================================ */
.trace-host{ padding:4px 0; }
.trace-setup{ display:flex; gap:10px; align-items:flex-end; flex-wrap:wrap; margin-bottom:14px; }
.trace-in-lbl{ display:block; font-size:12.5px; font-weight:600; color:var(--ink-soft); margin:0 0 5px; }
.trace-in{ box-sizing:border-box; border:1px solid var(--line); border-radius:10px; background:var(--surface);
  color:var(--ink); padding:9px 12px; font-family:var(--mono); font-size:13.5px; min-width:200px; }
.trace-in:focus{ outline:none; border-color:var(--primary-deep); box-shadow:0 0 0 3px var(--primary-soft); }

.trace-grid{ display:grid; grid-template-columns:1.5fr 1fr; gap:14px; align-items:start; }
@media (max-width:680px){ .trace-grid{ grid-template-columns:1fr; } }

.trace-code{ margin:0; max-height:340px; overflow:auto; border-radius:12px;
  background:var(--surface-3); padding:10px 0; box-shadow:inset 0 0 0 1px var(--line);
  font-family:var(--mono); font-size:13px; line-height:1.6; }
.trace-code-line{ display:flex; gap:0; padding:0 12px; white-space:pre;
  transition:background .18s var(--ease); border-left:3px solid transparent; }
.trace-code-line.on{ background:var(--primary-soft); border-left-color:var(--primary-deep); }
.trace-gutter{ flex:none; width:30px; text-align:right; padding-right:12px; color:var(--ink-faint);
  user-select:none; }
.trace-code-line.on .trace-gutter{ color:var(--primary-deep); font-weight:700; }
.trace-code-txt{ color:var(--ink); }

.trace-side{ display:flex; flex-direction:column; gap:12px; }
.trace-side-h{ font-size:11px; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  color:var(--ink-soft); margin-bottom:7px; }
.trace-vars-box, .trace-out-box{ border:1px solid var(--line); border-radius:12px; padding:12px 13px;
  background:var(--surface); }
.trace-vars{ display:flex; flex-direction:column; gap:6px; max-height:170px; overflow:auto; }
.trace-var{ display:flex; gap:8px; align-items:baseline; font-family:var(--mono); font-size:13px; }
.trace-var-k{ flex:none; color:var(--primary-deep); font-weight:700; }
.trace-var-v{ color:var(--ink); word-break:break-all;
  /* a freshly-changed value gets a brief tint; pure background, GPU-cheap */
  border-radius:5px; }
.trace-var-empty{ font-size:12.5px; color:var(--ink-faint); font-style:italic; }
.trace-out{ margin:0; max-height:140px; overflow:auto; font-family:var(--mono); font-size:13px;
  line-height:1.5; color:var(--ink); white-space:pre-wrap; word-break:break-word; min-height:20px; }

.trace-controls{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:14px; }
.trace-step-count{ font-size:12.5px; color:var(--ink-soft); font-variant-numeric:tabular-nums; }
.trace-trunc{ font-size:11px; font-weight:700; color:var(--ink-faint); background:var(--surface-3);
  padding:2px 8px; border-radius:6px; }

@media (prefers-reduced-motion: reduce){
  .trace-code-line{ transition:none; }
}

/* ============================================================
   SQL PRACTICE (#/sql, "Talk to data") — Wave 4. Off-record drills.
   Light textarea (no Monaco), schema + target-table display, rows diff.
   ============================================================ */
.sql-list{ display:flex; flex-direction:column; gap:10px; margin-top:6px; }
.sql-drill-row{ display:flex; align-items:center; gap:13px; text-align:left; width:100%;
  padding:14px 16px; border:1px solid var(--line); border-radius:13px; background:var(--surface);
  color:var(--ink); cursor:pointer; font:inherit; box-shadow:0 1px 0 rgba(0,0,0,.03);
  transition:border-color .14s var(--ease), transform .14s var(--ease), box-shadow .14s var(--ease); }
.sql-drill-row:hover{ border-color:var(--primary-deep); transform:translateY(-1px); box-shadow:0 4px 16px rgba(0,0,0,.07); }
.sql-drill-row:focus-visible{ outline:2px solid var(--primary-deep); outline-offset:2px; }
.sql-drill-ic{ font-size:22px; line-height:1; }
.sql-drill-b{ flex:1; min-width:0; display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.sql-drill-t{ font-size:15px; font-weight:600; }
.sql-drill-band{ font:700 10px/1 var(--mono); letter-spacing:.05em; text-transform:uppercase;
  color:var(--ink-soft); background:var(--surface-3); padding:3px 7px; border-radius:6px; }
.sql-drill-go{ color:var(--primary-deep); font-weight:700; }

.sql-card{ padding:20px; }
.sql-prompt{ font-size:15.5px; font-weight:600; color:var(--ink); line-height:1.55; margin-bottom:14px; }
.sql-side-h{ font:700 11px/1 var(--mono); letter-spacing:.05em; text-transform:uppercase;
  color:var(--ink-soft); margin-bottom:7px; }
.sql-schema-box{ margin-bottom:6px; }
.sql-schema{ margin:0; max-height:300px; overflow:auto; border-radius:12px; padding:13px 15px;
  background:var(--surface-3); box-shadow:inset 0 0 0 1px var(--line);
  font-family:var(--mono); font-size:12.5px; line-height:1.6; color:var(--ink); white-space:pre; }
.sql-input{ width:100%; box-sizing:border-box; border:1px solid var(--line); border-radius:11px;
  background:var(--surface); color:var(--ink); padding:12px 14px; font-family:var(--mono); font-size:14px;
  line-height:1.55; resize:vertical; transition:border-color .14s var(--ease), box-shadow .14s var(--ease); }
.sql-input:focus{ outline:none; border-color:var(--primary-deep); box-shadow:0 0 0 3px var(--primary-soft); }

.sql-result{ margin-top:6px; }
.sql-outcome{ margin-top:16px; border-radius:12px; padding:14px 16px; }
.sql-outcome.good{ background:var(--ok-soft,#E7F6EC); }
.sql-outcome.bad{ background:var(--surface-3); }
.sql-outcome-h{ font-weight:700; font-size:15px; color:var(--ink); }
.sql-outcome-tip{ margin:7px 0 0; font-size:13.5px; color:var(--ink-soft); line-height:1.55; }
.sql-diff{ display:flex; gap:14px; flex-wrap:wrap; margin-top:12px; }
.sql-diff-err{ flex-basis:100%; font-family:var(--mono); font-size:12.5px; color:var(--warn); }
.sql-diff-col{ flex:1; min-width:160px; }
.sql-diff-h{ font:700 10px/1 var(--mono); letter-spacing:.05em; text-transform:uppercase;
  color:var(--ink-soft); margin-bottom:5px; }
.sql-diff-col pre{ margin:0; max-height:180px; overflow:auto; border-radius:9px; padding:9px 11px;
  background:var(--surface); box-shadow:inset 0 0 0 1px var(--line);
  font-family:var(--mono); font-size:12px; line-height:1.5; color:var(--ink); white-space:pre; }
.sql-reveal{ margin-top:16px; border-top:1px solid var(--line); padding-top:14px; }
.sql-reveal-h{ font-size:13px; font-weight:700; color:var(--ink); margin-bottom:8px; }
.sql-reveal-code{ margin:0; border-radius:11px; padding:13px 15px; background:var(--surface-3);
  box-shadow:inset 0 0 0 1px var(--line); font-family:var(--mono); font-size:13px; line-height:1.6;
  color:var(--ink); white-space:pre-wrap; word-break:break-word; }

[data-theme="dark"] .sql-outcome.good{ background:#14301F; }
@media (prefers-reduced-motion: reduce){
  .sql-drill-row{ transition:none; }
  .sql-drill-row:hover{ transform:none; }
}

/* ============================================================
   OUTCOME FUNNEL CHECK-IN — Wave 4. A kind, consented, dismissible card.
   ============================================================ */
.funnel-card{ margin:24px 0 14px; padding:18px 20px;
  background:radial-gradient(900px 200px at 20% -40%, var(--primary-soft), transparent 70%), var(--surface); }
.funnel-head{ display:flex; align-items:flex-start; gap:12px; margin-bottom:14px; }
.funnel-ic{ font-size:24px; line-height:1; }
.funnel-t{ font-size:16px; font-weight:700; color:var(--ink); }
.funnel-sub{ font-size:13px; color:var(--ink-soft); line-height:1.5; margin-top:2px; }
.funnel-stages{ display:flex; flex-wrap:wrap; gap:9px; }
.funnel-stage{ padding:8px 14px; border:1.5px solid var(--line-2); border-radius:999px;
  background:var(--surface); color:var(--ink); font-weight:600; font-size:13.5px; cursor:pointer;
  transition:border-color .12s var(--ease), background .12s var(--ease), color .12s var(--ease); }
.funnel-stage:hover{ border-color:var(--primary); }
.funnel-stage:focus-visible{ outline:none; box-shadow:var(--ring); }
.funnel-stage.on{ border-color:var(--primary); background:var(--primary-soft); color:var(--primary-deep); }
.funnel-co-lbl{ display:block; font-size:12.5px; font-weight:600; color:var(--ink-soft); margin:0 0 5px; }
.funnel-co{ width:100%; max-width:340px; box-sizing:border-box; border:1px solid var(--line); border-radius:10px;
  background:var(--surface); color:var(--ink); padding:9px 12px; font-size:14px; }
.funnel-co:focus{ outline:none; border-color:var(--primary-deep); box-shadow:0 0 0 3px var(--primary-soft); }
.funnel-consent{ display:flex; align-items:flex-start; gap:9px; margin-top:14px; font-size:12.5px;
  color:var(--ink-soft); line-height:1.5; cursor:pointer; }
.funnel-consent input{ margin-top:2px; flex:none; }
.funnel-msg{ margin-top:8px; }
.funnel-done{ font-size:14px; color:var(--ink); padding:6px 0; }
@media (prefers-reduced-motion: reduce){ .funnel-stage{ transition:none; } }

/* ============================================================
   LESSON-FIRST · the block's lesson shown as STEP 1 before the
   learner's first problem in that block (concept before practice).
   The lesson BODY reuses the shared .article + .note styling; only
   the step-1 banner, the foot actions and the skip link are new.
   Colours come from the design tokens, so dark mode follows for
   free, and the only motion respects prefers-reduced-motion.
   (Deliberately scoped under .lesson-first / .lf-* to stay clear of
   every other surface, including the exam workspace section above.)
   ============================================================ */
.lesson-first{ max-width:760px; }
.lf-step{ display:flex; align-items:flex-start; gap:14px; padding:16px 18px; margin:6px 0 22px;
  border:1px solid var(--line); border-left:3px solid var(--primary-deep);
  border-radius:var(--r-md); background:var(--primary-soft); }
.lf-badge{ flex:0 0 auto; font-size:22px; line-height:1; }
.lf-eyebrow{ font-family:var(--display); font-size:12px; font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; color:var(--primary-deep); }
.lf-lede{ margin:5px 0 0; color:var(--ink-soft); font-size:14px; line-height:1.5; }
.lf-actions{ display:flex; flex-wrap:wrap; align-items:center; gap:14px 18px;
  margin-top:28px; padding-top:20px; border-top:1px solid var(--line); }
.lf-skip{ font-size:14px; font-weight:600; color:var(--ink-soft); text-decoration:none;
  border-bottom:1px dashed var(--line-2); padding-bottom:1px; transition:color .15s ease; }
.lf-skip:hover{ color:var(--ink); }
.lf-skip:focus-visible{ outline:none; border-radius:4px; box-shadow:var(--ring); }
@media (max-width:680px){
  .lf-actions{ flex-direction:column; align-items:stretch; }
  .lf-actions .btn{ width:100%; }
  .lf-skip{ text-align:center; }
}
@media (prefers-reduced-motion: reduce){ .lf-skip{ transition:none; } }

/* ============================================================
   LEARNER "YOU" HUB + JOURNEY "TODAY" (2026-06 control-panel redesign)
   Identity + glanceable numbers, every deeper read behind a tap.
   Built only from the :root tokens, like the rest of the system, so a
   theme change re-skins it for free. Motion is stilled globally under
   prefers-reduced-motion (see the * rule above).
   ============================================================ */
.hub-hero{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin:4px 0 14px;
  padding:18px 20px;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r-lg);box-shadow:var(--shadow-sm)}
.hub-ava{width:56px;height:56px;flex:0 0 auto;border-radius:50%;display:grid;place-items:center;
  font-family:var(--display);font-weight:700;font-size:22px;color:#fff;
  background:linear-gradient(135deg,var(--primary),var(--primary-2));box-shadow:var(--shadow-sm)}
.hub-id{flex:1 1 160px;min-width:0}
.hub-name{font-family:var(--display);font-weight:700;font-size:20px;line-height:1.2;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0 0 6px}
.hub-id .badge{margin:0 6px 0 0}
.hub-pills{display:flex;gap:6px;flex-wrap:wrap}
.hub-mirror{margin:0;color:var(--ink-soft);line-height:1.6}

/* collapsible section, the depth-on-demand container (native details/summary,
   so it is keyboard- and screen-reader-accessible with no extra ARIA) */
details.hub-sec{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-sm);margin:12px 0;overflow:hidden}
details.hub-sec>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:10px;
  padding:15px 18px;font-weight:600;color:var(--ink);user-select:none}
details.hub-sec>summary::-webkit-details-marker{display:none}
details.hub-sec>summary::after{content:"";flex:0 0 auto;width:8px;height:8px;margin-left:4px;
  border-right:2px solid var(--ink-faint);border-bottom:2px solid var(--ink-faint);
  transform:rotate(-45deg);transition:transform .2s var(--ease)}
details.hub-sec[open]>summary::after{transform:rotate(45deg)}
details.hub-sec[open]>summary{border-bottom:1px solid var(--line)}
.hub-sec-t{font-size:15px}
.hub-sec-v{margin-left:auto;color:var(--primary-deep);font-weight:700;font-family:var(--display);font-size:15px}
.hub-sec-v:empty{display:none}
.hub-sec-body{padding:16px 18px}
.hub-sec-body>.dash-grid:first-child,.hub-sec-body>.sw-list:first-child{margin-top:0}

/* section heading for the visible (non-collapsed) groups */
.hub-h{font-family:var(--display);font-weight:700;font-size:16px;color:var(--ink);margin:22px 0 10px}

/* low-text launcher tiles (proof on the You hub, practice on Journey) */
.hub-launch{display:grid;grid-template-columns:repeat(auto-fit,minmax(116px,1fr));gap:10px}
.hub-launch-i{display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center;
  padding:16px 10px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-sm);text-decoration:none;color:var(--ink);
  transition:transform .16s var(--ease),box-shadow .18s,border-color .16s}
.hub-launch-i:hover{transform:translateY(-3px);box-shadow:var(--shadow);border-color:var(--primary)}
.hub-launch-ic{font-size:26px;line-height:1}
.hub-launch-l{font-size:13px;font-weight:600}

/* settings rows */
.hub-set{display:flex;flex-direction:column;gap:14px}
.hub-set-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.hub-set-row>label{flex:0 0 116px;font-weight:600;font-size:14px;color:var(--ink)}
@media(max-width:560px){.hub-set-row>label{flex-basis:100%}}

/* Journey "Today" card, the folded-in daily suggestion (review + momentum +
   exam gate). Sits above the pathway map; quiet, never a competing CTA. */
.today-card{background:linear-gradient(135deg,var(--primary-soft),var(--surface));
  border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-sm);
  padding:16px 18px;margin:24px 0 16px}
.today-card .today-h{display:flex;align-items:center;gap:8px;font-family:var(--display);
  font-weight:700;font-size:15px;color:var(--primary-deep);margin:0 0 10px}
.today-card .today-h::before{content:"\2600\FE0F";font-size:16px}

/* ============================================================
   PLAYER CARD + BENTO + DATA-VIZ (2026-06 visual-first You hub).
   A game stat-card identity built on the existing tokens. The single
   signature is the player card; the bento around it stays disciplined.
   All motion below is stilled by the global prefers-reduced-motion rule.
   ============================================================ */
.pc-wrap { max-width: 1180px; }

/* ---- the player card: the one-glance hook ---- */
.player-card {
  position: relative; overflow: hidden; border-radius: var(--r-xl);
  border: 1px solid var(--line); box-shadow: var(--shadow);
  background:
    radial-gradient(130% 150% at 100% -10%, rgba(99,102,241,.26), transparent 55%),
    radial-gradient(120% 150% at -5% 110%, rgba(245,158,11,.18), transparent 52%),
    linear-gradient(180deg, var(--surface-2), var(--surface) 62%);
  padding: 24px 24px 22px;
}
.player-card::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 4px; background: var(--dawn-grad); }
.pc-head { display: flex; align-items: center; gap: 14px; margin-bottom: 10px; }
.pc-ava {
  width: 56px; height: 56px; flex: 0 0 auto; border-radius: 16px; display: grid; place-items: center;
  font-family: var(--display); font-weight: 700; font-size: 22px; color: #fff;
  background: linear-gradient(135deg, var(--primary), #0EA5E9);
  box-shadow: 0 6px 18px -6px rgba(99,102,241,.7);
}
.pc-idtext { min-width: 0; }
.pc-name { font-family: var(--display); font-weight: 700; font-size: 20px; line-height: 1.15; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pc-sub { font-size: 13px; font-weight: 600; color: var(--ink-soft); margin-top: 3px; }
/* symmetric body: two stat tiles | radar | two stat tiles */
.pc-body { display: grid; grid-template-columns: 188px minmax(0,1fr) 188px; align-items: center; gap: 16px; max-width: 940px; margin: 0 auto; }
.pc-side { display: grid; gap: 12px; min-width: 0; }
.pc-stat {
  text-align: center; padding: 16px 10px; border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--line); border-top: 3px solid var(--va, var(--primary));
  box-shadow: var(--shadow-sm);
}
.pc-stat-n { font-family: var(--display); font-weight: 800; font-size: 36px; line-height: 1; color: var(--va, var(--primary-deep)); }
.pc-stat-l { font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-soft); margin-top: 6px; }
.pc-radar { display: flex; justify-content: center; padding: 0 6px; }
.pc-radar .viz-radar { width: 100%; max-width: 352px; height: auto; overflow: visible; }
.viz-radar-poly { transform-box: fill-box; transform-origin: center; animation: radar-pop .7s var(--ease) both; }
.pc-xp { max-width: 580px; margin: 18px auto 0; }
.pc-xp-bar { height: 9px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.pc-xp-bar > i { display: block; height: 100%; border-radius: 999px; background: var(--dawn-grad); }
.pc-xp-lbl { margin-top: 6px; font-size: 12px; font-weight: 600; color: var(--ink-soft); text-align: center; }

/* ---- the bento grid of viz tiles ---- */
.bento { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin-top: 16px; }
@media (max-width: 900px) { .bento { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 460px) { .bento { grid-template-columns: 1fr; } }
.vtile {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm); padding: 16px 18px; min-width: 0; display: flex; flex-direction: column;
  transition: transform .16s var(--ease), box-shadow .18s, border-color .16s;
}
.vtile:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: var(--line-2); }
.vtile-wide { grid-column: 1 / -1; }
.vtile-h { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 12px; }
.vtile-t { font-family: var(--display); font-weight: 700; font-size: 14px; color: var(--ink); }
.vtile-sub { font-family: var(--display); font-weight: 800; font-size: 15px; color: var(--primary-deep); }
.vtile-cap { font-size: 12px; color: var(--ink-soft); margin-top: 10px; }
.vtag { font-size: 11.5px; font-weight: 800; padding: 3px 9px; border-radius: 999px; }
.vtag.up { color: var(--ok); background: var(--ok-soft); }
.vtag.down { color: var(--warn); background: var(--warn-soft); }
.vtag.flat { color: var(--ink-soft); background: var(--surface-3); }
.vtile-legend { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 10px; font-size: 11px; font-weight: 600; color: var(--ink-soft); }
.vtile-legend i { display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 4px; vertical-align: middle; }

/* ---- viz sizing + motion ---- */
.viz-area { width: 100%; height: 130px; display: block; }
.viz-area-line { stroke-dasharray: 600; animation: viz-draw 1.1s var(--ease) both; }
.viz-skillmap, .viz-heat { width: 100%; height: auto; display: block; }
.viz-empty { padding: 18px 6px; font-size: 13px; color: var(--ink-faint); text-align: center; }
.viz-arc { animation: viz-fill 1s var(--ease) both; }
.viz-ring { display: block; }
.form-strip { display: flex; flex-wrap: wrap; gap: 5px; align-content: flex-start; }
.form-dot { width: 13px; height: 13px; border-radius: 4px; }
.ms-row { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
.ms-num { font-family: var(--display); font-weight: 800; font-size: 38px; line-height: 1; color: var(--star-deep); }
.ms-lbl { font-size: 13px; font-weight: 600; color: var(--ink-soft); }

/* ---- attribute bars (tucked "what your attributes mean") ---- */
.attr-row { margin-bottom: 14px; }
.attr-bar { display: flex; align-items: center; gap: 10px; }
.attr-l { flex: 0 0 96px; font-size: 13px; font-weight: 700; color: var(--ink); }
.attr-t { flex: 1; height: 9px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.attr-t > i { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--primary), #0EA5E9); }
.attr-v { flex: 0 0 auto; font-family: var(--display); font-weight: 800; font-size: 14px; color: var(--primary-deep); min-width: 28px; text-align: right; }

@keyframes radar-pop { from { transform: scale(.55); opacity: 0; } }
@keyframes viz-fill { from { stroke-dashoffset: var(--c); } }
@keyframes viz-draw { from { stroke-dashoffset: 600; } to { stroke-dashoffset: 0; } }

/* per-tile colour accent + game-feel motion (all stilled by reduced-motion) */
.vtile { position: relative; overflow: hidden; }
.vtile::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--va, transparent); }
.vtile-ic { margin-right: 6px; }
.vtile-sub { color: var(--va, var(--primary-deep)); }
.hub-sec-body .attr-t > i, .vtile .progress > i, .jstat-bar > i, .pc-xp-bar > i { transform-origin: left; animation: grow-x .9s var(--ease) both; }
.pc-stat { animation: badge-in .55s var(--ease) both; }

/* launcher tiles -> game "mode select" cards: a tinted icon chip + accent hover */
.hub-launch-i { --va: var(--primary); }
.hub-launch-ic { width: 44px; height: 44px; border-radius: 13px; display: grid; place-items: center;
  background: color-mix(in srgb, var(--va) 16%, var(--surface-2)); }
.hub-launch-i:hover { border-color: var(--va); box-shadow: 0 12px 24px -14px var(--va); }
.launch-lg .hub-launch-i { padding: 18px 12px; gap: 10px; }
.launch-lg .hub-launch-ic { width: 50px; height: 50px; border-radius: 15px; }
.hub-launch-sub { font-size: 11.5px; font-weight: 600; color: var(--ink-faint); margin-top: 2px; }
.hub-launch.ach { max-width: 660px; margin: 14px auto 0; grid-template-columns: 1fr 1fr; }
.hub-launch.ach3 { max-width: 880px; grid-template-columns: repeat(3, 1fr); }
@media (max-width: 620px) { .hub-launch.ach3 { grid-template-columns: 1fr; } }

/* Journey campaign-progress bar */
.jstats { margin: 6px 0 2px; }
.jstat-bar { height: 10px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.jstat-bar > i { display: block; height: 100%; border-radius: 999px; background: var(--dawn-grad); }
.jstat-lbl { margin-top: 6px; font-size: 12.5px; font-weight: 600; color: var(--ink-soft); }
.jstat-lbl strong { color: var(--primary-deep); font-family: var(--display); }
@keyframes grow-x { from { transform: scaleX(0); } }
@keyframes badge-in { from { transform: scale(.55); opacity: 0; } }
@keyframes badge-glow {
  0%, 100% { box-shadow: inset 0 0 0 4px var(--primary), 0 12px 28px -12px rgba(99,102,241,.55); }
  50% { box-shadow: inset 0 0 0 4px var(--primary-2), 0 14px 34px -10px rgba(99,102,241,.85); }
}

@media (max-width: 680px) {
  .pc-body { grid-template-columns: 1fr; gap: 14px; }
  .pc-side { grid-template-columns: 1fr 1fr; }
  .pc-radar { order: -1; }
}
@media (max-width: 560px) {
  .pc-stat-n { font-size: 30px; }
}

/* ============ SEGMENTED PILL TABS + interactive bits (2026) ============ */
.ptabs {
  display: flex; gap: 5px; margin: 18px 0 16px; padding: 5px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line); overflow-x: auto; scrollbar-width: none;
}
.ptabs::-webkit-scrollbar { display: none; }
.ptab {
  flex: 1 1 0; min-width: max-content; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 10px 14px; border: none; border-radius: 999px; background: transparent; cursor: pointer;
  font-family: var(--display); font-weight: 700; font-size: 13.5px; color: var(--ink-soft);
  white-space: nowrap; transition: background .18s var(--ease), color .18s, box-shadow .18s;
}
.ptab-ic { font-size: 15px; line-height: 1; }
.ptab:hover { color: var(--ink); }
.ptab.active { background: var(--surface); color: var(--primary-deep); box-shadow: var(--shadow-sm); }
.ptab-body { min-height: 220px; }
.ptab-anim { animation: ptab-in .26s var(--ease) both; }
@keyframes ptab-in { from { opacity: 0; transform: translateY(7px); } }
.ptab-h { font-family: var(--display); font-weight: 700; font-size: 15px; color: var(--ink); margin: 22px 0 12px; }
@media (max-width: 560px) { .ptab-l { display: none; } .ptab { flex: 1 1 0; padding: 11px 8px; } .ptab-ic { font-size: 18px; } }

/* interactive "how measured": tap a bar to reveal its why (show, then tell) */
.attr-sub { font-size: 12.5px; color: var(--ink-faint); margin-bottom: 12px; }
.attr-why > summary { list-style: none; cursor: pointer; }
.attr-why > summary::-webkit-details-marker { display: none; }
.attr-why > summary:hover .attr-q { border-color: var(--primary); }
.attr-q { flex: 0 0 auto; width: 19px; height: 19px; border-radius: 50%; border: 1.5px solid var(--ink-faint); position: relative; transition: border-color .15s; }
.attr-q::after { content: "?"; position: absolute; inset: 0; display: grid; place-items: center; font-size: 11px; font-weight: 800; color: var(--ink-faint); }
.attr-why[open] .attr-q { border-color: var(--primary); }
.attr-why[open] .attr-q::after { content: "\2715"; color: var(--primary); }
.attr-why-b { padding: 8px 0 4px; }
.attr-why-b p { margin: 5px 0; font-size: 13px; color: var(--ink-soft); line-height: 1.5; }
.attr-next strong { color: var(--ink); }
.attr-cite { font-size: 11.5px; color: var(--ink-faint); }

/* climb chart axes: y (max -> 0) on the left, x (12 weeks ago -> now) below */
.varea-row { display: flex; align-items: stretch; gap: 8px; }
.varea-y { display: flex; flex-direction: column; justify-content: space-between; font-size: 10px; font-weight: 700; color: var(--ink-faint); padding: 2px 0; }
.varea-row .viz-area { flex: 1; }
.varea-x { display: flex; justify-content: space-between; font-size: 10.5px; font-weight: 600; color: var(--ink-faint); margin-top: 5px; padding-left: 24px; }

/* daily quest ring + trophy showcase (calm gamification) */
.quest-card { display: flex; align-items: center; gap: 16px; margin-top: 14px; padding: 14px 18px;
  border-radius: var(--r-lg); border: 1px solid var(--line); box-shadow: var(--shadow-sm);
  background: radial-gradient(120% 160% at 0% 0%, rgba(22,163,74,.12), transparent 55%), var(--surface); }
.quest-ring { flex: 0 0 auto; }
.quest-ring .viz-ring { width: 86px; height: 86px; }
.quest-t { font-family: var(--display); font-weight: 800; font-size: 17px; color: var(--ink); }
.quest-sub { font-size: 13.5px; color: var(--ink-soft); margin-top: 4px; }
/* ============================================================
   TROPHY CASE — cinematic, space-themed achievement medallions.
   Each trophy is a "mission-patch" porthole into deep space, and its
   grandeur scales with RARITY (common -> legendary). Rarity is carried
   by the rim colour, a text caption AND the animation intensity, never
   colour alone. All idle motion is GPU-cheap (transform / opacity / mask
   only — no animated blur or SVG-lighting that stalls a low-end CPU),
   capped to the rarest tiers (the catalog has at most 1 legendary +
   2 epic + 4 rare, so the perpetual-motion load is small and bounded),
   and frozen to a tasteful static state under prefers-reduced-motion.
   ============================================================ */
.trophies { margin-top: 18px; }
.trophies-h { font-family: var(--display); font-weight: 800; font-size: 15px; color: var(--ink);
  margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
.trophies-h .th-ic { font-size: 18px; filter: drop-shadow(0 1px 3px rgba(245,158,11,.5)); }
.trophies-n { display: inline-grid; place-items: center; min-width: 24px; height: 24px; padding: 0 7px;
  border-radius: 999px; background: var(--dawn-grad); color: #fff; font-size: 12px; font-weight: 800;
  box-shadow: 0 2px 8px -2px rgba(99,102,241,.5); }
.trophies-row { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 16px 10px; }

/* rarity palettes — rim / AA-text / glow / deep-space nebula interior */
.trophy.t-common,    .badge-chip.t-common    { --rar:#64748B; --rar-ink:#475569; --rar-glow:rgba(100,116,139,.45); --rar-neb:#243049; }
.trophy.t-uncommon,  .badge-chip.t-uncommon  { --rar:#14B8A6; --rar-ink:#0F766E; --rar-glow:rgba(20,184,166,.5);   --rar-neb:#0c3b3b; }
.trophy.t-rare,      .badge-chip.t-rare      { --rar:#6366F1; --rar-ink:#4F46E5; --rar-glow:rgba(99,102,241,.55);  --rar-neb:#1e2150; }
.trophy.t-epic,      .badge-chip.t-epic      { --rar:#A855F7; --rar-ink:#7E22CE; --rar-glow:rgba(168,85,247,.6);   --rar-neb:#2e1747; }
.trophy.t-legendary, .badge-chip.t-legendary { --rar:#F59E0B; --rar-ink:#B5740C; --rar-glow:rgba(245,158,11,.66);  --rar-neb:#3a2a0c; }

.trophy { display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;
  padding: 4px 2px; border-radius: var(--r-md); transition: transform .22s var(--ease);
  animation: trophy-in .5s var(--ease) backwards; animation-delay: calc(var(--i, 0) * 55ms); }
.trophy:hover { transform: translateY(-4px); }

.trophy-mw { position: relative; width: 68px; height: 68px; display: grid; place-items: center; }

/* rotating aurora ring — epic + legendary only */
.trophy-orbit { position: absolute; inset: -6px; border-radius: 50%; z-index: 0; opacity: 0; }
.t-epic .trophy-orbit, .t-legendary .trophy-orbit { opacity: 1;
  background: conic-gradient(from 0deg, transparent 0 58%, var(--rar) 78%, transparent 92%);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3px));
          mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3px));
  animation: trophy-spin 6s linear infinite; }
.t-legendary .trophy-orbit { inset: -8px; animation-duration: 4.5s;
  background: conic-gradient(from 0deg, transparent 0 48%, var(--rar) 68%, #fff5d6 80%, var(--rar) 88%, transparent 96%); }

/* the medallion — a porthole into deep space */
.trophy-medal { position: relative; width: 68px; height: 68px; border-radius: 50%; display: grid;
  place-items: center; isolation: isolate; overflow: hidden;
  background:
    radial-gradient(62% 62% at 50% 30%, var(--rar-neb), #0a0f24 72%),
    radial-gradient(1.4px 1.4px at 22% 28%, rgba(255,255,255,.9), transparent 60%),
    radial-gradient(1.2px 1.2px at 70% 22%, rgba(255,255,255,.75), transparent 60%),
    radial-gradient(1px 1px at 80% 64%, rgba(255,255,255,.8), transparent 60%),
    radial-gradient(1.3px 1.3px at 33% 74%, rgba(255,255,255,.7), transparent 60%),
    radial-gradient(1px 1px at 54% 52%, rgba(255,255,255,.55), transparent 60%);
  box-shadow:
    inset 0 1.5px 1px rgba(255,255,255,.5), inset 0 -4px 7px rgba(0,0,0,.55),
    0 0 0 2px var(--rar), 0 0 13px -2px var(--rar-glow),
    0 6px 14px -5px var(--rar-glow), 0 2px 5px rgba(16,24,40,.22);
  transition: box-shadow .25s var(--ease); }
.trophy:hover .trophy-medal { box-shadow:
    inset 0 1.5px 1px rgba(255,255,255,.6), inset 0 -4px 7px rgba(0,0,0,.5),
    0 0 0 2px var(--rar), 0 0 22px 0 var(--rar-glow),
    0 11px 22px -6px var(--rar-glow), 0 3px 6px rgba(16,24,40,.28); }

/* shimmer sweep — hover for all, slow + perpetual for rare and up */
.trophy-medal::before { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: 50%;
  background: linear-gradient(115deg, transparent 32%, rgba(255,255,255,.38) 48%, rgba(255,255,255,.05) 56%, transparent 70%);
  transform: translateX(-120%); }
.trophy:hover .trophy-medal::before { animation: trophy-sweep .9s var(--ease); }
.t-rare .trophy-medal::before { animation: trophy-sweep 5s var(--ease) infinite; }
.t-epic .trophy-medal::before { animation: trophy-sweep 4.2s var(--ease) infinite; }
.t-legendary .trophy-medal::before { animation: trophy-sweep 3.4s var(--ease) infinite; }

/* twinkling stars overlay — epic + legendary */
.trophy-medal::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: 50%; opacity: 0;
  background:
    radial-gradient(1.5px 1.5px at 30% 38%, #fff, transparent 60%),
    radial-gradient(1.5px 1.5px at 66% 30%, #fff, transparent 60%),
    radial-gradient(1.2px 1.2px at 50% 68%, #fff, transparent 60%); }
.t-epic .trophy-medal::after, .t-legendary .trophy-medal::after { animation: trophy-twinkle 2.4s ease-in-out infinite; }

/* pulsing aura ring — legendary only */
.t-legendary .trophy-mw::after { content: ""; position: absolute; inset: 0; border-radius: 50%; z-index: -1;
  border: 2px solid var(--rar); opacity: .6; animation: trophy-pulse 2.8s ease-out infinite; }

.trophy-ic { position: relative; z-index: 2; font-size: 30px; line-height: 1; filter: drop-shadow(0 2px 3px rgba(0,0,0,.5)); }
.trophy-l { font-family: var(--display); font-size: 12.5px; font-weight: 700; line-height: 1.2; color: var(--ink); max-width: 12ch; }
.trophy-rarity { font-size: 9.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: var(--rar-ink); }

@keyframes trophy-in { from { opacity: 0; transform: translateY(8px) scale(.8); } to { opacity: 1; transform: none; } }
@keyframes trophy-sweep { from { transform: translateX(-120%); } to { transform: translateX(120%); } }
@keyframes trophy-twinkle { 0%, 100% { opacity: .2; } 50% { opacity: .9; } }
@keyframes trophy-spin { to { transform: rotate(360deg); } }
@keyframes trophy-pulse { 0% { transform: scale(1); opacity: .6; } 80% { transform: scale(1.5); opacity: 0; } 100% { opacity: 0; } }

@media (max-width: 560px) {
  .trophies-row { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 14px 8px; }
  .trophy-mw, .trophy-medal { width: 62px; height: 62px; }
  .trophy-ic { font-size: 27px; }
}
@media (prefers-reduced-motion: reduce) {
  .trophy, .trophy-medal::before, .trophy-medal::after, .trophy-orbit, .t-legendary .trophy-mw::after { animation: none !important; }
  .trophy { opacity: 1; transform: none; }
}
@media (max-width: 560px) { .quest-ring .viz-ring { width: 74px; height: 74px; } .quest-t { font-size: 16px; } }

/* ============================================================
   THE JOURNEY, timelined winding "ascent path" (2026 redesign).
   A premium space-flight climb: hero -> winding path of checkpoint
   nodes (rocket = you are here) -> the golden FUTURE at the top.
   ============================================================ */

/* ---- hero: where you are + where you're going (the 2s hook) ---- */
.jh-view { padding-bottom: 0; }
.jhero { display: flex; flex-direction: column; gap: 13px;
  background: radial-gradient(120% 150% at 100% 0%, rgba(99,102,241,.12), transparent 58%), var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-xl); padding: 18px 20px; box-shadow: var(--shadow); }
.jhero-main { display: flex; align-items: center; gap: 16px; }
.jhero-ring { --p: 0; --ang: 0deg; flex: none; width: 92px; height: 92px; border-radius: 50%; position: relative;
  display: grid; place-items: center; isolation: isolate;
  background: conic-gradient(var(--primary) calc(var(--p) * 1%), var(--surface-3) 0); }
.jhero-ring::before { content: ""; position: absolute; inset: 7px; border-radius: 50%; background: var(--surface); z-index: 0; }
/* the rocket rides the END of its progress arc: the track rotates to --ang
   (the learner's % round the ring) and the rocket sits at its top, so the
   rocket literally marks how far they have climbed. */
.jhr-track { position: absolute; inset: 0; z-index: 1; transform: rotate(var(--ang)); }
/* the rocket points along the CLOCKWISE TANGENT (forward), so the blue progress
   arc behind it reads as its exhaust. The track already rotates to the progress
   angle; this constant offset turns the up-right emoji to face the direction of
   travel (the emoji nose sits ~45deg up-right of horizontal). */
.jhr-rocket { position: absolute; top: -9px; left: 50%; transform: translateX(-50%) rotate(45deg); font-size: 20px;
  filter: drop-shadow(0 2px 4px rgba(16,24,40,.28)); }
.jhr-aura { position: absolute; top: -11px; left: 50%; width: 30px; height: 30px; transform: translateX(-50%);
  border-radius: 50%; background: radial-gradient(circle, rgba(245,158,11,.6), transparent 68%); z-index: -1; }
.jhr-pct { position: relative; z-index: 1; font-family: var(--display); font-weight: 700; font-size: 23px; color: var(--ink); }
.jhero-tx { min-width: 0; }
.jhero-eyebrow { font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--primary-deep); }
.jhero-h { font-family: var(--display); font-size: 25px; line-height: 1.1; margin: 3px 0 5px; color: var(--ink); }
.jhero-sub { font-size: 14px; color: var(--ink-soft); }
.jhero-sub strong { color: var(--ink); font-size: 16px; font-weight: 700; }
.jhero-dot { color: var(--ink-faint); }
/* ONE coherent launch console (replaces the mismatched mission strip + goal
   chip): a single segmented readout, every segment the same shape, thin
   dividers between. Mission (info) · T-minus (tap -> the current block) ·
   Destination (tap -> the future card). */
.jh-console { display: flex; flex-wrap: wrap; gap: 1px; border-radius: var(--r-md); overflow: hidden;
  border: 1px solid var(--line-2); background: var(--line-2); }
.jh-seg { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: var(--surface);
  flex: 1 1 auto; min-width: 0; font-size: 13px; text-decoration: none; }
.jh-seg-ic { font-size: 15px; flex: none; }
.jh-seg-k { font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-soft); flex: none; }
.jh-seg-v { font-family: var(--display); font-weight: 700; font-size: 14px; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.jh-seg-v.tm { color: var(--accent); font-size: 17px; }
.jh-seg-x { font-size: 12px; font-weight: 700; color: var(--star-deep); flex: none; }
.jh-seg-act { cursor: pointer; border: none; text-align: left; transition: background .15s var(--ease); }
.jh-seg-act:hover { background: var(--surface-2); }
.jh-seg-tm:hover { background: var(--accent-soft); }
.jh-seg-act:focus-visible { outline: none; box-shadow: var(--ring) inset; }
.jh-seg-dest { flex: 1 1 100%; }   /* destination on its own full-width row, the clear CTA */
.jh-seg-dest:hover { background: var(--accent-soft); }
.jh-seg-go { margin-left: auto; font-size: 16px; font-weight: 800; color: var(--star-deep); flex: none; }

/* ---- "Pending flights" ribbon: the daily Today signal + the spaced-review
        queue folded into ONE glanceable line inside the launch console, its
        floating tooltip, and the UNIFIED journey backdrop so the top zone
        shares the map's warm dawn in BOTH themes (var(--bg)-based, never a
        light-only colour, so it adapts to dark). ---- */
#jTop { background:
    radial-gradient(96% 52% at 50% -16%, rgba(245,158,11,.15), transparent 60%),
    radial-gradient(60% 42% at 14% 22%, rgba(124,58,237,.12), transparent 60%),
    radial-gradient(60% 42% at 88% 12%, rgba(99,102,241,.13), transparent 60%),
    linear-gradient(180deg, var(--bg) 55%, color-mix(in oklab, #F59E0B 9%, var(--bg)) 100%);
  padding-bottom: 16px; }
.jp-view { margin-top: 0; }

/* the chip row WRAPS instead of horizontal-scrolling: the old overflow-x
   left an ugly scrollbar on the dark hero AND pushed "+N"/"See all" off the
   right edge (unreachable for a mouse). Wrapping keeps every pill, +N and
   See-all visible with no scrollbar; "+N" reveals the hidden reviews inline. */
.flight-ribbon { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  row-gap: 7px; margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--line);
  overflow: visible; }
.fr-lead { flex: none; display: flex; align-items: center; gap: 6px; cursor: help;
  font-size: 10.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-soft); }
.fr-lead:focus-visible { outline: none; box-shadow: var(--ring); border-radius: 6px; }
.fr-count { font-size: 10.5px; font-weight: 800; color: var(--primary-deep);
  background: color-mix(in oklab, var(--primary) 14%, transparent); padding: 0 7px; border-radius: 99px; }
.patch { flex: none; display: flex; align-items: center; gap: 6px; padding: 5px 11px; border-radius: 99px;
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow); cursor: pointer;
  font: inherit; white-space: nowrap; transition: transform .14s var(--ease), box-shadow .14s var(--ease); }
/* the collapsed ribbon pre-renders the overflow reviews as [hidden] patches
   that "+N" reveals inline. `.patch{display:flex}` outranks the UA [hidden]
   rule (equal specificity, later source), so hidden patches would otherwise
   stay visible, all of them, which is what forced the scrollbar. This higher-
   specificity rule makes [hidden] actually hide them until +N removes it. */
.patch[hidden] { display: none; }
.patch:hover { transform: translateY(-1px); box-shadow: 0 6px 14px -6px rgba(16, 24, 40, .3); }
.patch:focus-visible { outline: none; box-shadow: var(--ring); }
.patch .pi { font-size: 12px; }
.patch .pt { font-size: 12px; font-weight: 600; color: var(--ink); }
.patch.today { border-color: color-mix(in oklab, var(--primary) 50%, var(--line));
  background: color-mix(in oklab, var(--primary) 9%, var(--surface)); }
.patch.today .pt { color: var(--primary-deep); font-weight: 700; }
.patch.rev { border-color: color-mix(in oklab, var(--accent) 32%, var(--line));
  background: color-mix(in oklab, var(--accent) 7%, var(--surface)); }
.patch.more { background: var(--surface-2); font-weight: 800; color: var(--ink-soft); }
.fr-all { flex: none; margin-left: auto; white-space: nowrap; font: inherit;
  font-size: 11.5px; font-weight: 700; color: var(--primary-deep); background: none; border: none;
  cursor: pointer; padding: 3px 8px; border-radius: 99px; }
.fr-all:hover { background: var(--surface-2); }
.fr-all:focus-visible { outline: none; box-shadow: var(--ring); }
.pend-expand { margin-top: 2px; }

/* the floating tooltip escapes the ribbon's horizontal-scroll clip (a CSS
   ::after tooltip would be cut off by overflow-x); inverts per theme via
   --ink / --surface, so it reads in light AND dark. */
#udx-tip { position: fixed; z-index: 99999; max-width: 250px; pointer-events: none;
  background: var(--ink); color: var(--surface); font-size: 11.5px; font-weight: 600; line-height: 1.4;
  padding: 7px 10px; border-radius: 9px; box-shadow: 0 10px 28px -8px rgba(0, 0, 0, .5);
  opacity: 0; transform: translateY(4px); transition: opacity .12s, transform .12s; }
#udx-tip.on { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { #udx-tip, .patch { transition: none; } }

/* ---- the winding path ---- */
/* the path is a launch from the dawn runway (warm, top) up into deep space
   (the destination, bottom): a darkening indigo veil over the theme bg, so it
   reads as "space" in BOTH light and dark themes. */
.jp-view { position: relative; overflow: hidden; padding-top: 16px; padding-bottom: 0;
  background:
    radial-gradient(72% 28% at 50% 6%, rgba(245,158,11,.11), transparent 60%),
    radial-gradient(46% 26% at 26% 80%, rgba(124,58,237,.22), transparent 62%),
    radial-gradient(44% 24% at 78% 67%, rgba(99,102,241,.18), transparent 62%),
    linear-gradient(180deg, transparent 0%, rgba(79,70,229,.12) 38%, rgba(40,42,92,.60) 74%, #141229 96%, #141229 100%),
    var(--bg); }
.jp-view .wrap { position: relative; z-index: 1; }
/* twinkling parallax starfield, masked to appear only as the path climbs into
   the darker "space" lower region (invisible up in the warm dawn launch zone) */
.jp-sky { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.jp-sky::before, .jp-sky::after { content: ""; position: absolute; left: 0; right: 0; top: -12%; bottom: -12%;
  background-repeat: repeat;
  -webkit-mask: linear-gradient(180deg, transparent 26%, #000 70%); mask: linear-gradient(180deg, transparent 26%, #000 70%); }
.jp-sky::before {
  background-image:
    radial-gradient(1.5px 1.5px at 12% 18%, rgba(255,255,255,.95), transparent),
    radial-gradient(1.3px 1.3px at 28% 62%, rgba(255,255,255,.8), transparent),
    radial-gradient(1.7px 1.7px at 47% 33%, rgba(246,199,82,.9), transparent),
    radial-gradient(1.3px 1.3px at 63% 80%, rgba(255,255,255,.85), transparent),
    radial-gradient(1.5px 1.5px at 82% 26%, rgba(255,255,255,.9), transparent),
    radial-gradient(1.3px 1.3px at 91% 66%, rgba(190,200,255,.85), transparent),
    radial-gradient(1.2px 1.2px at 38% 90%, rgba(255,255,255,.75), transparent),
    radial-gradient(1.4px 1.4px at 73% 50%, rgba(255,255,255,.85), transparent),
    radial-gradient(1.3px 1.3px at 7% 47%, rgba(214,224,255,.85), transparent),
    radial-gradient(1.6px 1.6px at 56% 8%, rgba(255,255,255,.9), transparent),
    radial-gradient(2px 2px at 24% 38%, rgba(246,199,82,.8), transparent);
  background-size: 280px 270px; }
.jp-sky::after {
  background-image:
    radial-gradient(1px 1px at 20% 40%, rgba(255,255,255,.7), transparent),
    radial-gradient(1px 1px at 55% 18%, rgba(255,255,255,.6), transparent),
    radial-gradient(1px 1px at 78% 72%, rgba(255,255,255,.65), transparent),
    radial-gradient(1px 1px at 33% 78%, rgba(200,210,255,.6), transparent),
    radial-gradient(1px 1px at 88% 46%, rgba(255,255,255,.6), transparent),
    radial-gradient(1px 1px at 12% 88%, rgba(255,255,255,.55), transparent),
    radial-gradient(1px 1px at 66% 60%, rgba(210,220,255,.55), transparent);
  background-size: 190px 205px; opacity: .8; }
.jp-comet { position: absolute; top: 0; left: 0; width: 2px; height: 2px; border-radius: 50%;
  background: #fff; box-shadow: 0 0 7px 1px rgba(255,255,255,.9); opacity: 0; }
.jp-comet::before { content: ""; position: absolute; right: 1px; top: 50%; width: 64px; height: 1.6px;
  transform: translateY(-50%); background: linear-gradient(90deg, transparent, rgba(255,255,255,.85)); }
.jpath { position: relative; z-index: 1; list-style: none; margin: 4px auto 0; padding: 0; width: min(640px, 94%); }
.jp-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; z-index: 0; }
.jp-line-bg { fill: none; stroke: var(--line-2); stroke-width: 6; stroke-linecap: round; opacity: .85;
  stroke-dasharray: 1 13; }            /* dotted "route not yet flown" */
.jp-line-on { fill: none; stroke: url(#jpGrad); stroke-width: 7; stroke-linecap: round;
  filter: drop-shadow(0 1px 5px rgba(245,158,11,.35)); }

/* gate = a stage checkpoint on the path */
.jp-gate { position: absolute; left: 50%; transform: translate(-50%, -50%); width: max-content; max-width: 94%;
  z-index: 2; text-align: center; }
.jp-gate-card { display: inline-flex; align-items: center; gap: 9px; background: var(--surface);
  border: 1px solid var(--line-2); border-radius: 999px; padding: 6px 15px 6px 6px; box-shadow: var(--shadow); }
.jp-gate-badge { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  font-family: var(--display); font-weight: 700; font-size: 15px; color: #fff; }
.jp-gate-badge.a { background: linear-gradient(135deg,#0EA5E9,#4F46E5); }
.jp-gate-badge.b { background: linear-gradient(135deg,#4F46E5,#7C3AED); }
.jp-gate-badge.c { background: linear-gradient(135deg,#7C3AED,#DB2777); }
.jp-gate-name { font-family: var(--display); font-weight: 700; font-size: 15px; color: var(--ink); }
.jp-gate-sub { font-size: 12px; color: var(--ink-soft); }
.jp-gate-lock { font-size: 13px; margin-left: 2px; }
.jp-gate.locked .jp-gate-card { opacity: .72; }
.jp-stars { margin-top: 7px; display: flex; gap: 4px; justify-content: center; }
.jp-star { font-size: 15px; color: var(--star-dim); }
.jp-star.on { color: var(--star-gold); text-shadow: 0 0 6px rgba(246,199,82,.65); }

/* a block node (checkpoint) on the path */
.jp-node { position: absolute; transform: translate(-50%, -50%); width: 54px; height: 54px; z-index: 1; }
.jp-dot { position: relative; display: grid; place-items: center; width: 54px; height: 54px; border-radius: 50%;
  text-decoration: none; background: var(--surface); border: 2.5px solid var(--line-2); box-shadow: var(--shadow-sm);
  transition: transform .15s var(--ease), box-shadow .15s var(--ease); }
.jp-dot:hover { transform: scale(1.12); box-shadow: 0 0 0 5px rgba(99,102,241,.14), var(--shadow); }
.jp-dot:active { transform: scale(1.02); }
.jp-dot:focus-visible { outline: none; box-shadow: var(--ring), var(--shadow); }
.st-done .jp-dot:hover { box-shadow: 0 0 0 5px rgba(246,199,82,.22), var(--shadow); }
.jp-node:hover .jp-label { color: var(--ink); border-color: var(--primary); }
.jp-ring { position: absolute; inset: -3px; border-radius: 50%;
  background: conic-gradient(var(--ok) calc(var(--p) * 1%), transparent 0);
  -webkit-mask: radial-gradient(closest-side, transparent 73%, #000 74%);
          mask: radial-gradient(closest-side, transparent 73%, #000 74%); }
.jp-glyph { position: relative; z-index: 1; font-family: var(--display); font-weight: 700; }
/* SEGMENTED progress ring: one bar per problem in the block, filled when solved
   (shows out-of-order / deviation solves too). Shown on open/current/upcoming;
   a mastered block keeps its gold star instead. Scales with the node. */
/* 0707 legibility: the per-problem ring reads at a glance now. One segment
   per problem in the block (jpSegRing emits exactly ps.length bars):
   GREEN = solved, RED = attempted but not cracked yet (server-honest,
   painted post-resolve), faint gray = untouched. Thicker + pushed out so
   the states are identifiable on the dark path. */
/* the ring exactly overlays the dot: inset:0 + width/height:100% fills the
   dot's box concentrically and squarely at ANY dot size. The old rule set
   both `inset:-6px` AND `width/height:calc(100%+12px)`, over-constraining the
   absolutely-positioned SVG on the bordered, larger current-node dot, so the
   browser resolved it to a non-square, off-centre box (the ring floated off
   the rim). A negative outset with auto sizing does not reliably stretch a
   viewBox-only SVG, so the ring sits flush on the dot instead. Verified
   concentric + square live at both 54px and 66px dots. */
.jp-segring { position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; transform-origin: center center; }
.jp-seg { fill: none; stroke: var(--line, #c7c9d6); stroke-width: 4; opacity: .38; }
.jp-seg.on { stroke: #10B981; opacity: 1; }
.jp-seg.tried { stroke: #EF4444; opacity: .95; }
.st-done .jp-segring { display: none; }
/* a deviated block (solved ahead of the path) is NOT dimmed, so its filled bars
   are clearly visible -- that is the whole point of showing the deviation. */
.jp-node.deviated .jp-dot { border-style: dashed; border-color: var(--accent); opacity: 1; }
.jp-pin { position: absolute; top: -6px; right: -6px; font-size: 13px; z-index: 2; }
.jp-label { position: absolute; top: 100%; left: 50%; transform: translateX(-50%); margin-top: 10px;
  max-width: 160px; white-space: nowrap; font-size: 11.5px; font-weight: 600; color: var(--ink-soft);
  background: var(--surface); padding: 2px 9px; border-radius: 999px; border: 1px solid var(--line);
  box-shadow: var(--shadow-sm); }
/* states */
.st-open .jp-dot { border-color: var(--primary); }
.st-open .jp-glyph { color: var(--primary-deep); font-size: 18px; }
.st-done .jp-dot { background: linear-gradient(160deg, var(--star-glow), var(--star-gold)); border-color: var(--star-gold); }
.st-done .jp-glyph { color: #fff; font-size: 22px; text-shadow: 0 1px 2px rgba(16,24,40,.3); }
.st-done .jp-ring { display: none; }
.st-upcoming .jp-dot { background: var(--surface-2); border-color: var(--line); opacity: .6; }
.st-upcoming .jp-glyph { color: var(--ink-faint); font-size: 16px; }
.st-upcoming .jp-ring { display: none; }
.st-upcoming .jp-label { color: var(--ink-faint); opacity: .85; }
.st-current { width: 66px; height: 66px; z-index: 3; }
.st-current .jp-dot { width: 66px; height: 66px; border-color: var(--accent);
  background: radial-gradient(circle, var(--surface) 55%, var(--accent-soft));
  box-shadow: 0 0 0 4px rgba(245,158,11,.18), var(--shadow); animation: jpPulse 2.1s var(--ease) infinite; }
/* the you-are-here rocket points FORWARD along the path (down, toward the
   destination), so the bright completed trail above it reads as its exhaust.
   The path tangent is vertical at every node, so a fixed down-rotation holds
   at any width. */
.st-current .jp-glyph { font-size: 30px; display: inline-block; transform: rotate(132deg); }
.st-current .jp-label { display: none; }
@keyframes jpPulse { 0%,100% { box-shadow: 0 0 0 4px rgba(245,158,11,.20), var(--shadow); }
  50% { box-shadow: 0 0 0 10px rgba(245,158,11,.04), var(--shadow); } }
/* 0707: the you-are-here callout mounts to the SIDE of the rocket (flip =
   node winds right of centre), so it never collides with the previous
   checkpoint's label like the old above-the-node chip did. */
.jp-here { position: absolute; top: 50%; left: 100%; transform: translateY(-50%); margin-left: 14px;
  white-space: nowrap; font-size: 11px; font-weight: 800; letter-spacing: .03em; text-transform: uppercase;
  color: var(--ink); background: var(--accent); padding: 3px 9px; border-radius: 999px; box-shadow: var(--shadow-sm); }
.jp-here::after { content: ""; position: absolute; right: 100%; top: 50%; transform: translateY(-50%);
  border: 5px solid transparent; border-right-color: var(--accent); }
.jp-here.flip { left: auto; right: 100%; margin-left: 0; margin-right: 14px; }
.jp-here.flip::after { right: auto; left: 100%; border-right-color: transparent; border-left-color: var(--accent); }
.jp-cont { position: absolute; top: calc(100% + 9px); left: 50%; transform: translateX(-50%); white-space: nowrap;
  font-size: 12px; font-weight: 700; color: #fff; background: var(--primary-deep); padding: 5px 13px;
  border-radius: 999px; text-decoration: none; box-shadow: var(--shadow-sm); }
.jp-cont:hover { background: var(--primary); }
.jp-node.assigned .jp-dot { border-color: var(--accent); }

/* ---- THE FUTURE: the golden destination at the top of the runway ---- */
/* the destination sits IN space: the deep void continues straight out of the
   path (no hard cut), a starfield around it, fading back to the page bg only
   below the card so the practice tiles return to daylight. */
.fut-view { position: relative; padding-top: 30px;
  background: linear-gradient(180deg, #141229 0%, #141229 8%, #1a1840 34%, #2b2954 56%, var(--bg) 92%); }
.fut-view::before { content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none; background-repeat: repeat;
  background-image:
    radial-gradient(1.5px 1.5px at 14% 12%, rgba(255,255,255,.9), transparent),
    radial-gradient(1.3px 1.3px at 32% 38%, rgba(255,255,255,.72), transparent),
    radial-gradient(1.8px 1.8px at 52% 16%, rgba(246,199,82,.85), transparent),
    radial-gradient(1.3px 1.3px at 70% 46%, rgba(255,255,255,.8), transparent),
    radial-gradient(1.5px 1.5px at 86% 22%, rgba(255,255,255,.85), transparent),
    radial-gradient(1.2px 1.2px at 24% 58%, rgba(200,210,255,.7), transparent),
    radial-gradient(1.3px 1.3px at 93% 58%, rgba(255,255,255,.68), transparent),
    radial-gradient(1.2px 1.2px at 8% 40%, rgba(214,224,255,.7), transparent);
  background-size: 300px 280px;
  -webkit-mask: linear-gradient(180deg, #000 0%, #000 44%, transparent 76%);
          mask: linear-gradient(180deg, #000 0%, #000 44%, transparent 76%); }
.fut-view .wrap { position: relative; z-index: 1; }
.fut-bridge { margin-bottom: 14px; }
.future-card { position: relative; overflow: hidden; border-radius: var(--r-xl); padding: 26px 24px; color: #fff;
  background: linear-gradient(165deg, #161427 0%, #2A2350 58%, #3C3019 100%);
  border: 1px solid var(--star-gold); box-shadow: var(--shadow-lg); }
.fut-aura { position: absolute; top: -45%; right: -18%; width: 62%; height: 130%; pointer-events: none;
  background: radial-gradient(circle, rgba(246,199,82,.36), transparent 62%); }
.fut-top { position: relative; display: flex; align-items: center; gap: 10px; }
.fut-ic { font-size: 22px; filter: drop-shadow(0 0 8px rgba(246,199,82,.5)); }
.fut-eyebrow { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--star-glow); }
.fut-role { position: relative; font-family: var(--display); font-size: 22px; font-weight: 700; margin: 11px 0 2px; }
.fut-pay { position: relative; display: flex; flex-direction: column; gap: 2px; margin: 10px 0; }
.fut-pay-n { font-family: var(--display); font-size: 38px; font-weight: 700; line-height: 1; color: var(--star-glow);
  text-shadow: 0 2px 20px rgba(246,199,82,.45); }
.fut-pay-l { font-size: 12px; color: rgba(255,255,255,.72); }
.fut-cos { position: relative; display: flex; flex-wrap: wrap; gap: 7px; margin: 13px 0; }
.fut-co { font-size: 12.5px; font-weight: 600; color: rgba(255,255,255,.9); background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.16); border-radius: 999px; padding: 4px 11px; }
.fut-co.mine { background: rgba(246,199,82,.18); border-color: var(--star-gold); color: #fff; }
.fut-co.mine b { color: var(--star-glow); font-weight: 700; }
.fut-stretch { position: relative; margin-top: 4px; padding-top: 13px; border-top: 1px solid rgba(255,255,255,.13); }
.fut-stretch-h { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: rgba(255,255,255,.62); margin-bottom: 7px; }
.fut-stretch ul { margin: 0; padding-left: 17px; display: flex; flex-direction: column; gap: 4px; }
.fut-stretch li { font-size: 13px; color: rgba(255,255,255,.86); }
.fut-src { position: relative; margin-top: 13px; }
.fut-src summary { font-size: 11px; color: rgba(255,255,255,.6); cursor: pointer; }
.fut-src p { font-size: 11px; color: rgba(255,255,255,.55); margin: 6px 0 0; line-height: 1.5; }

/* ============================================================
   UDAAN MAGIC, space immersion + cinematic animation at the junctions.
   ALL effects are transform / opacity / box-shadow / stroke-dashoffset
   (GPU-cheap, never animated blur or SVG lighting filters), and ALL are
   disabled under prefers-reduced-motion (single guard at the bottom).
   ============================================================ */


/* ---- rocket THRUST: trails UPWARD from the rocket (which now points down),
   merging into the bright completed trail above, so the exhaust + trail read
   as one continuous plume. ---- */
.jp-thrust { position: absolute; left: 50%; bottom: 56%; width: 14px; height: 30px; transform: translateX(-50%);
  background: linear-gradient(0deg, rgba(245,158,11,.95), rgba(251,113,133,.55) 48%, transparent);
  border-radius: 60% 60% 0 0 / 100% 100% 0 0; filter: blur(1.2px); transform-origin: bottom center; z-index: 0; opacity: .9; }

/* ---- the next-2 upcoming checkpoints: a "what's next?" mystery shimmer ---- */
.jp-node.nextup .jp-glyph { color: var(--primary); }

/* ---- THE FUTURE as a breathing destination planet, with an orbit ---- */
.fut-orbit { position: absolute; right: -54px; top: -54px; width: 210px; height: 210px; border-radius: 50%;
  border: 1.5px dashed rgba(246,199,82,.30); pointer-events: none; z-index: 0; }
.fut-orbit::after { content: ""; position: absolute; top: 11%; left: 50%; width: 8px; height: 8px; margin-left: -4px;
  border-radius: 50%; background: var(--star-glow); box-shadow: 0 0 10px 2px rgba(246,199,82,.7); }

/* ---- continuous ambient motion (disabled wholesale under reduced-motion) -- */
@media (prefers-reduced-motion: no-preference) {
  /* the climbed trail FADES in over the dotted route (a reveal that never
     clips the line; stroke-dash + non-scaling-stroke left it cut off, since
     non-scaling-stroke forces the dash into screen px and pathLength is then
     ignored, so the solid trail is animated by opacity, never geometry). */
  .jp-line-on { opacity: 0; animation: jpReveal 1.3s var(--ease) .2s forwards; }
  /* every checkpoint POPS in, staggered down the path (the reveal) */
  .jp-node, .jp-gate { animation: jpPop .55s var(--ease) backwards; animation-delay: calc(var(--i, 0) * 48ms + .12s); }
  /* the you-are-here rocket flies DOWN into the current block on load (a taste
     of "fly on to the next block"), keeping its forward-pointing rotation. */
  .st-current .jp-glyph { animation: jpRocketIn 1.1s var(--ease) .45s backwards; }
  /* starfield: slow twinkle + downward parallax drift (ascent) */
  .jp-sky::before { animation: jpTwinkle 4.6s ease-in-out infinite, jpDriftA 24s linear infinite; }
  .jp-sky::after  { animation: jpTwinkle 6.2s ease-in-out infinite reverse, jpDriftB 34s linear infinite; }
  .jp-comet { animation: jpComet 9s ease-in 3.5s infinite; }
  .jp-thrust { animation: jpThrust .5s ease-in-out infinite; }
  .jp-node.nextup .jp-dot { animation: jpMystery 2.2s ease-in-out infinite; }
  .jh-seg-v.tm { animation: jhTmPulse 2s ease-in-out infinite; transform-origin: center; display: inline-block; }
  .jhr-aura { animation: jhAura 2.4s ease-in-out infinite; }
  .fut-aura { animation: futBreathe 5s ease-in-out infinite; }
  .fut-orbit { animation: futOrbit 20s linear infinite; }
}
@keyframes jpReveal { from { opacity: 0; } to { opacity: 1; } }
@keyframes jpPop { from { opacity: 0; transform: translate(-50%, -50%) scale(.3); }
  to { opacity: 1; transform: translate(-50%, -50%) scale(1); } }
@keyframes jpTwinkle { 0%, 100% { opacity: .9; } 50% { opacity: .5; } }
@keyframes jpDriftA { from { transform: translateY(0); } to { transform: translateY(30px); } }
@keyframes jpDriftB { from { transform: translateY(0); } to { transform: translateY(48px); } }
@keyframes jpComet {
  0% { opacity: 0; transform: translate(-12vw, 6vh) rotate(20deg); }
  5% { opacity: 1; } 15% { opacity: 0; }
  100% { opacity: 0; transform: translate(82vw, 58vh) rotate(20deg); } }
@keyframes jpRocketIn { from { transform: translateY(-44px) rotate(132deg); opacity: 0; } 55% { opacity: 1; } to { transform: translateY(0) rotate(132deg); opacity: 1; } }
@keyframes jpThrust { 0%, 100% { transform: translateX(-50%) scaleY(1) scaleX(1); opacity: .9; }
  50% { transform: translateX(-50%) scaleY(1.4) scaleX(.78); opacity: .6; } }
@keyframes jpMystery { 0%, 100% { box-shadow: var(--shadow-sm); }
  50% { box-shadow: 0 0 0 5px rgba(99,102,241,.14), var(--shadow-sm); } }
@keyframes jhTmPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.045); } }
@keyframes jhAura { 0%, 100% { opacity: .55; transform: translateX(-50%) scale(1); } 50% { opacity: .9; transform: translateX(-50%) scale(1.25); } }
@keyframes futBreathe { 0%, 100% { opacity: .8; transform: scale(1); } 50% { opacity: 1; transform: scale(1.12); } }
@keyframes futOrbit { to { transform: rotate(360deg); } }

/* ---- responsive ---- */
@media (max-width: 560px) {
  .jhero-ring { width: 78px; height: 78px; } .jhr-pct { font-size: 20px; }
  .jhero-h { font-size: 22px; }
  .jpath { width: 96%; }
  .jp-label { max-width: 132px; font-size: 11px; }
  .fut-pay-n { font-size: 32px; } .fut-role { font-size: 19px; }
  .fut-orbit { width: 150px; height: 150px; right: -40px; top: -40px; }
}

/* ---- reduced motion: a global `* { animation:none }` rule already kills all
   motion; here we only ensure the line/path rest at their FINAL shown state
   (opacity 1, not the animation's 0) and drop the comet entirely. ---- */
@media (prefers-reduced-motion: reduce) {
  .jp-line-on { opacity: 1 !important; }
  .jp-node, .jp-gate { opacity: 1 !important; }
  .jp-comet { display: none; }
}


/* ============================================================
   GAMIFIED "TODAY" (show, not tell): compact objective rows + a readiness
   GAUGE with tappable problem "targets" in place of prose lists.
   ============================================================ */
.today-card .tg-item, .review-queue .tg-item { display: flex; flex-direction: row; align-items: center; justify-content: flex-start; gap: 11px; padding: 11px 13px; }
.tg-item-ic { font-size: 18px; flex: none; line-height: 1; }
.tg-item-r { flex: 1; min-width: 0; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.tg-item .plan-cta { flex: none; }

.tg-gate { display: flex; flex-direction: row; align-items: center; justify-content: flex-start; gap: 14px; flex-wrap: wrap; }
.tg-gauge { --p: 0; flex: none; width: 60px; height: 60px; border-radius: 50%; position: relative;
  display: grid; place-items: center; background: conic-gradient(var(--ok) calc(var(--p) * 1%), var(--surface-3) 0); }
.tg-gauge::before { content: ""; position: absolute; inset: 5px; border-radius: 50%; background: var(--surface); }
.tg-gauge-n { position: relative; z-index: 1; font-family: var(--display); font-weight: 700; font-size: 18px; color: var(--ink); }
.tg-gauge-u { font-size: 11px; color: var(--ink-soft); }
.tg-gauge.full { background: var(--ok-soft); }
.tg-gauge-ic { position: relative; z-index: 1; font-size: 26px; }
.tg-gate-b { flex: 1; min-width: 170px; }
.tg-gate-h { font-family: var(--display); font-weight: 700; font-size: 14px; color: var(--ink); margin-bottom: 7px; }
.tg-gate-k { color: var(--ink-soft); font-weight: 600; }
.tg-targets { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.tg-target { display: inline-grid; place-items: center; min-width: 36px; height: 32px; padding: 0 9px; border-radius: 9px;
  background: var(--surface); border: 1.5px solid var(--primary); color: var(--primary-deep);
  font-family: var(--display); font-weight: 700; font-size: 13px; text-decoration: none;
  transition: transform .12s var(--ease), background .12s var(--ease), box-shadow .12s var(--ease); }
.tg-target:hover { transform: translateY(-2px); background: var(--primary-soft); box-shadow: var(--shadow-sm); }
.tg-target:focus-visible { outline: none; box-shadow: var(--ring); }
.tg-target.tg-more { border-style: dashed; border-color: var(--line-2); color: var(--ink-soft); }
.tg-target-n { font-size: 13px; color: var(--ink-soft); font-weight: 600; }
.tg-note { font-size: 11px; color: var(--ink-faint); margin: 9px 0 0; }
@media (prefers-reduced-motion: reduce) { .tg-target { transition: none; } }

/* mobile: the review objective's CTA wraps to its own full-width row so the
   reason line is never squeezed into a narrow column beside the button */
@media (max-width: 560px) {
  .today-card .tg-item, .review-queue .tg-item { flex-wrap: wrap; }
  .today-card .tg-item .plan-cta, .review-queue .tg-item .plan-cta { flex: 1 1 100%; margin-top: 9px; justify-content: center; }
}

/* ============================================================
   PER-BLOCK COMPLETION FLIGHT (cinematic): the rocket flies ON from the
   cleared block to the next, a brief skippable celebration overlay.
   ============================================================ */
.uv-bflight { position: fixed; inset: 0; z-index: 9999; display: grid; place-items: center; padding: 24px;
  background: radial-gradient(120% 100% at 50% 42%, rgba(28,26,62,.95), rgba(8,7,22,.97)); animation: bfIn .35s var(--ease); }
.uv-bflight::before { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .7; background-repeat: repeat; background-size: 260px 240px;
  background-image:
    radial-gradient(1.5px 1.5px at 14% 18%, rgba(255,255,255,.9), transparent),
    radial-gradient(1.6px 1.6px at 52% 14%, rgba(246,199,82,.8), transparent),
    radial-gradient(1.3px 1.3px at 72% 48%, rgba(255,255,255,.8), transparent),
    radial-gradient(1.3px 1.3px at 30% 60%, rgba(200,210,255,.7), transparent),
    radial-gradient(1.2px 1.2px at 88% 28%, rgba(255,255,255,.7), transparent); }
.bf-scene { position: relative; width: min(440px, 86vw); height: 76px; z-index: 1; }
.bf-node { position: absolute; top: 50%; transform: translateY(-50%); width: 56px; height: 56px; border-radius: 50%;
  display: grid; place-items: center; font-family: var(--display); font-weight: 700; }
.bf-done { left: 0; background: linear-gradient(160deg, var(--star-glow), var(--star-gold)); color: #fff; font-size: 26px;
  box-shadow: 0 0 24px 5px rgba(246,199,82,.6); }
.bf-next { right: 0; background: rgba(255,255,255,.07); border: 1.5px solid rgba(255,255,255,.28); color: rgba(255,255,255,.85); font-size: 20px;
  animation: bfNextLight 2.9s var(--ease) both; }
.bf-trail { position: absolute; top: 50%; left: 52px; right: 52px; height: 4px; transform: translateY(-50%) scaleX(0); transform-origin: left center;
  background: linear-gradient(90deg, var(--star-gold), #FB7185 55%, var(--primary-2)); border-radius: 3px;
  box-shadow: 0 0 14px rgba(251,113,133,.6); animation: bfTrail 1.9s var(--ease) .25s both; }
.bf-rocket { position: absolute; top: 50%; left: 28px; transform: translate(-50%,-50%) rotate(45deg); font-size: 30px; z-index: 2;
  filter: drop-shadow(0 0 12px rgba(245,158,11,.75)); animation: bfFly 1.9s var(--ease) .25s both; }
.bf-cap { text-align: center; margin-top: 30px; color: #fff; z-index: 1; animation: bfCap .55s var(--ease) 1.5s both; }
.bf-cap b { display: block; font-family: var(--display); font-size: 21px; }
.bf-cap span { display: block; font-size: 14px; color: rgba(255,255,255,.78); margin-top: 5px; }
@keyframes bfIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes bfFly { from { left: 28px; } to { left: calc(100% - 28px); } }
@keyframes bfTrail { to { transform: translateY(-50%) scaleX(1); } }
@keyframes bfCap { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes bfNextLight { 0%, 62% { box-shadow: none; } 100% { box-shadow: 0 0 20px 4px rgba(129,140,248,.55); border-color: var(--primary-2); color: #fff; } }

/* ============================================================
   CINEMATIC LIGHTING: focal bloom on the things that matter (the cleared gold
   checkpoints, the you-are-here rocket, the progress meters, the destination
   planet). Not a glow outline on every element (that reads as noise); the
   focal points genuinely glow, everything around them stays disciplined.
   ============================================================ */
.st-done .jp-dot { box-shadow: 0 0 18px 2px rgba(246,199,82,.42), var(--shadow-sm); }
.st-current .jp-dot { filter: drop-shadow(0 0 12px rgba(245,158,11,.5)); }
.jhero-ring { box-shadow: 0 0 26px -6px rgba(99,102,241,.5); }
.tg-gauge { box-shadow: 0 0 18px -2px rgba(22,163,74,.4); }
.future-card { box-shadow: 0 0 46px -10px rgba(246,199,82,.32), var(--shadow-lg); }
.fut-ic { filter: drop-shadow(0 0 11px rgba(246,199,82,.75)); }
.fut-pay-n { text-shadow: 0 2px 26px rgba(246,199,82,.55); }

/* ============================================================
   MISSION CONTROL, the AI coach console on the Journey (space-themed).
   Surfaces one live Zsapiens diagnosis line + the exact drills. One line,
   not a wall (research: the coach speaks, it does not lecture).
   ============================================================ */
.mission-ctl { position: relative; overflow: hidden; display: flex; gap: 14px; align-items: flex-start; margin-top: 14px;
  padding: 16px 18px; border-radius: var(--r-lg); color: #fff;
  background: linear-gradient(120deg, #161430, #221f48 70%, #1b1840);
  border: 1px solid rgba(129,140,248,.45); box-shadow: 0 0 30px -10px rgba(99,102,241,.5), var(--shadow); }
.mc-sky { position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: .6; background-repeat: repeat; background-size: 220px 200px;
  background-image:
    radial-gradient(1.4px 1.4px at 18% 22%, rgba(255,255,255,.9), transparent),
    radial-gradient(1.3px 1.3px at 62% 16%, rgba(246,199,82,.8), transparent),
    radial-gradient(1.2px 1.2px at 82% 60%, rgba(255,255,255,.75), transparent),
    radial-gradient(1.2px 1.2px at 36% 72%, rgba(200,210,255,.7), transparent); }
.mc-bot { position: relative; z-index: 1; flex: none; width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center; font-size: 24px;
  background: radial-gradient(circle, rgba(129,140,248,.42), rgba(99,102,241,.1)); box-shadow: 0 0 18px -2px rgba(129,140,248,.7); }
.mc-body { position: relative; z-index: 1; flex: 1; min-width: 0; }
.mc-eyebrow { font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--star-glow); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mc-sig { font-size: 10px; font-weight: 700; color: #fff; background: rgba(255,255,255,.12); border-radius: 999px; padding: 2px 8px; text-transform: none; letter-spacing: 0; }
.mc-say { font-family: var(--display); font-size: 16px; font-weight: 600; line-height: 1.35; margin: 7px 0 0; color: #fff; }
.mc-do { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 11px; }
.mc-do-k { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: rgba(255,255,255,.6); }
.mc-targets { display: flex; gap: 6px; flex-wrap: wrap; }
.mc-target { display: inline-grid; place-items: center; min-width: 34px; height: 30px; padding: 0 9px; border-radius: 9px; text-decoration: none;
  background: rgba(255,255,255,.1); border: 1.5px solid rgba(129,140,248,.6); color: #fff; font-family: var(--display); font-weight: 700; font-size: 13px;
  transition: transform .12s var(--ease), background .12s var(--ease); }
.mc-target:hover { transform: translateY(-2px); background: rgba(129,140,248,.32); }
.mc-target:focus-visible { outline: none; box-shadow: var(--ring); }
.mc-src { font-size: 11px; color: rgba(255,255,255,.52); margin-top: 11px; }

/* ---- PROGRESSIVE space: the world deepens as the learner climbs. --prog
   (0..100, the real journey %) is set on .jp-view; it drives an aurora that
   intensifies with progress. Static gradient + opacity only (never blur). --- */
.jp-aurora { position: absolute; left: 0; right: 0; bottom: 0; height: 62%; z-index: 0; pointer-events: none;
  opacity: calc(.10 + var(--prog, 0) * .0042);
  background:
    radial-gradient(58% 50% at 24% 92%, rgba(124,58,237,.55), transparent 70%),
    radial-gradient(54% 46% at 78% 82%, rgba(14,165,233,.42), transparent 70%); }
.jp-comet.c2 { top: 16%; }
.jp-comet.c3 { top: 42%; }

@media (prefers-reduced-motion: no-preference) {
  .mc-bot { animation: mcBotFloat 3s ease-in-out infinite; }
  .jp-aurora { animation: jpAurora 17s ease-in-out infinite; }
  .jp-comet.c2 { animation: jpComet 9s ease-in 5.5s infinite; }
  .jp-comet.c3 { animation: jpComet 9s ease-in 12s infinite; }
}
@keyframes mcBotFloat { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
@keyframes jpAurora { 0%,100% { transform: translateX(0); } 50% { transform: translateX(3%); } }

/* ============================================================
   YOU HUB header, kept neat and clean: the same card-first hero feel as the
   Journey. The player card IS the hero; no decorative crown band, so the
   card sits in normal flow under the app bar (the .view/.wrap padding gives
   the clean top gap).
   ============================================================ */
.you-hub { position: relative; }
.you-hub > .wrap { position: relative; z-index: 1; }

/* ============================================================
   Phase 0 · journey command-center kit (spec 2026-07-07).
   Pre-flight empties, the mini rocket loader, the signal-lost
   screen, the self-altitude strip. All positioning on the strip
   is logical (inset-inline-*) so RTL mirrors for free. Motion
   here is minimal; the global reduced-motion rule plus the
   belt-and-braces block below still all of it.
   ============================================================ */
.pre-flight{ text-align:center; padding:34px 18px; }
.pre-flight .pf-ic{ font-size:30px; display:block; margin-bottom:8px; opacity:.85; }
.pre-flight .pf-t{ font-weight:700; margin:0 0 4px; }
.pre-flight .pf-s{ margin:0; color:var(--ink-faint); font-size:14px; }
.pre-flight .pf-a{ margin-top:14px; display:inline-block; }

.rk-mini{ display:inline-flex; align-items:center; gap:8px; padding:4px 2px; }
.rk-mini .rl-sky{ width:26px; height:26px; min-height:0; display:inline-block; }
.rk-mini .rl-rocket{ font-size:15px; }
.rk-mini .rl-label{ display:inline; margin:0; font-size:13px; color:var(--ink-faint); }

.fatal-link .fl-panel{ max-width:440px; margin:0 auto; text-align:center; padding:30px 20px; }
.fatal-link .fl-ic{ font-size:34px; }
.fatal-link .fl-h{ font-size:20px; margin:10px 0 6px; }
.fatal-link .fl-s{ color:var(--ink-faint,#5A6273); margin:0 0 14px; }
.fatal-link .fl-d{ margin-top:16px; text-align:start; font-size:13px; color:var(--ink-faint,#5A6273); }
.fatal-link .fl-d summary{ cursor:pointer; font-weight:600; }

.alt-strip{ position:relative; height:46px; margin:8px 0 2px; }
.alt-strip .as-track{ position:absolute; inset-inline:0; top:20px; height:8px; border-radius:6px; overflow:hidden; display:block; background:var(--surface-3); }
.alt-strip .as-band{ position:absolute; top:0; bottom:0; opacity:.55; background:#4F46E5; }
.alt-strip .as-band.b0{ background:linear-gradient(90deg,#22D3EE,#4F46E5); }
.alt-strip .as-band.b1{ background:linear-gradient(90deg,#4F46E5,#7C3AED); }
.alt-strip .as-band.b2{ background:linear-gradient(90deg,#7C3AED,#DB2777); }
.alt-strip .as-labels .as-lb{ position:absolute; top:2px; font-size:10px; font-weight:700; color:var(--ink-faint); padding-inline-start:2px; }
.alt-strip .as-marker{ position:absolute; top:9px; margin-inline-start:-8px; font-size:15px; transition:inset-inline-start .5s ease-out; }
.as-line{ margin:2px 0 0; font-size:13px; color:var(--ink-faint); }
.as-line.as-resting{ font-weight:600; }

@media (prefers-reduced-motion: reduce){
  .alt-strip .as-marker{ transition:none; }
  .rk-mini .rl-rocket, .rk-mini .rl-trail{ animation:none; }
}

/* ============================================================
   Phase 1 · the command-center frame + consoles (spec 2026-07-07).
   The deck is the ONLY element allowed will-change here; everything
   else is static 2D. Deck motion is JS transform (rAF, gated); no
   CSS animation to kill, but the belt-and-braces block still pins
   the new interactive transitions under reduced motion.
   ============================================================ */
.cmdc{ position:relative; }
.cmdc-deck{ position:fixed; inset-inline:0; top:52px; height:38vh; z-index:-1; pointer-events:none;
  background:linear-gradient(180deg, transparent 0%, color-mix(in oklab, var(--bg) 82%, #101533) 78%, transparent 100%);
  opacity:.5; will-change:transform; }
.cmdc-near{ position:relative; }

.jh-prefill{ display:inline-flex; align-items:center; gap:7px; margin-top:10px; font-size:13px; color:var(--ink-faint); }

.jp-appr-h{ display:block; margin-top:7px; font-size:9.5px; font-weight:800; letter-spacing:.5px; text-transform:uppercase; color:var(--ink-faint); }
.jp-appr{ display:flex; flex-wrap:wrap; gap:5px; margin-top:4px; justify-content:center; }
.jp-appr-co{ font-size:10px; font-weight:700; padding:2px 8px; border-radius:999px; background:color-mix(in oklab, var(--surface-3) 72%, transparent); }
.jp-appr-floor{ font-size:10px; font-weight:600; color:var(--ink-faint); padding:2px 4px; }

.mission-ctl.mc-comms{ box-shadow:0 0 0 1px color-mix(in oklab, #6366F1 28%, transparent), 0 12px 34px -20px #6366F1; }

.hub-launch.bays .hub-launch-i{ transition:transform .18s ease; }
.hub-launch.bays .hub-launch-i:hover, .hub-launch.bays .hub-launch-i:focus-visible{ transform:translateY(-3px); }

.gc-console .authored-head{ border-inline-start:3px solid color-mix(in oklab, #6366F1 55%, transparent); padding-inline-start:12px; }

@media (prefers-reduced-motion: reduce){
  .hub-launch.bays .hub-launch-i{ transition:none; transform:none; }
}

/* ============================================================
   Phases 2-4 · ship identity, telemetry, orbit, focus (spec
   2026-07-07-journey-phases-2-4). Motion here is one orbit
   keyframe pair (transform/opacity only) + tiny chip affordances;
   everything pinned under reduced motion below.
   ============================================================ */
.jh-seg-ship .jh-seg-v{ max-width:180px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.jh-sts{ font-weight:800; letter-spacing:.3px; }
.ship-form{ display:inline-flex; align-items:center; gap:6px; }
.ship-form .ship-in{ width:150px; padding:6px 9px; border-radius:9px; border:1px solid var(--surface-3); background:var(--surface-1,#fff); color:var(--ink); font:inherit; font-size:13px; }

.jh-hull{ display:flex; gap:6px; justify-content:center; margin-top:8px; }
.jh-pip{ width:22px; height:6px; border-radius:4px; background:var(--surface-3); opacity:.75; }
.jh-pip.lit{ background:linear-gradient(90deg,#22D3EE,#6366F1); opacity:1; box-shadow:0 0 8px -2px #6366F1; }

.mc-callsign{ font-weight:800; }

.tele-line{ display:flex; flex-wrap:wrap; gap:6px; align-items:baseline; padding:10px 16px 0; font-size:13.5px; }
.tele-line .tl-h{ font-weight:800; }
.tele-line .tl-s{ color:var(--ink-faint); }
.tele-line.st-go .tl-h{ color:#15924C; }
.tele-line.st-near .tl-h{ color:#B5740C; }
.tele-line.st-miss .tl-h, .tele-line.st-err .tl-h{ color:#D63C44; }

.waypoint{ margin:10px 16px 0; font-size:13.5px; }
.waypoint a{ font-weight:700; text-decoration:none; }
.waypoint a:hover, .waypoint a:focus-visible{ text-decoration:underline; }

.orbit-scene{ position:fixed; inset:0; z-index:10010; display:flex; align-items:center; justify-content:center;
  background:color-mix(in oklab, #060a18 78%, transparent); }
.orbit-scene .os-card{ max-width:420px; margin:16px; padding:26px 22px; text-align:center; border-radius:18px;
  background:var(--surface-1,#0e1226); color:var(--ink,#fff); box-shadow:0 30px 80px -30px #000; }
.orbit-scene .os-viz{ position:relative; width:150px; height:150px; margin:0 auto 10px; }
.orbit-scene .os-planet{ position:absolute; inset:40px; border-radius:50%;
  background:radial-gradient(circle at 32% 30%, #7C3AED, #1e1b4b 70%); }
.orbit-scene .os-ring{ position:absolute; inset:8px; border-radius:50%; border:1.5px dashed color-mix(in oklab, #22D3EE 55%, transparent); }
.orbit-scene .os-craft{ position:absolute; top:50%; left:50%; font-size:17px; margin:-9px 0 0 -9px;
  transform:rotate(0deg) translateX(66px); animation:osOrbit 5.2s linear infinite; }
@keyframes osOrbit{ from{ transform:rotate(0deg) translateX(66px); } to{ transform:rotate(360deg) translateX(66px); } }
.orbit-scene .os-h{ font-size:21px; margin:6px 0 6px; }
.orbit-scene .os-p{ font-size:14px; color:var(--ink-faint,#aab); margin:0 0 14px; }
.orbit-scene.static .os-craft{ animation:none; }

/* §4.2 focus-flight: hide ONLY the ambient chrome. MUST-KEEP (never listed
   here, by design): the impersonation banner, #sr-live, the problem toolbar
   (carries the toggle), editor, tests, result, any exam surface. */
body.focus-flight header[role="banner"]{ display:none; }
body.focus-flight footer[role="contentinfo"]{ display:none; }
body.focus-flight .crumbs{ display:none; }
#humBtn{ display:none; }
body.focus-flight #humBtn{ display:inline-flex; }

/* the focus-mode explainer bar: hidden normally, sticky at the very top ONLY in
   focus mode (where the header/nav are gone), so the learner always sees why the
   menu vanished and has the exit right there. */
.focus-banner{ display:none; }
body.focus-flight .focus-banner{
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  position:sticky; top:0; z-index:60; margin:0 0 16px; padding:10px 16px;
  border:1px solid color-mix(in oklab, var(--primary) 40%, var(--line));
  border-radius:var(--r-md);
  background:linear-gradient(100deg, color-mix(in oklab, var(--primary) 14%, var(--surface)), var(--surface));
  box-shadow:var(--shadow);
  transition:transform .22s var(--ease), opacity .22s var(--ease);
}
/* auto-tuck: app.js adds .tucked while the learner scrolls down or types, so the
   banner slides up out of the way; it slides back at the top when they stop. */
body.focus-flight .focus-banner.tucked{ transform:translateY(-135%); opacity:0; pointer-events:none; }
.focus-banner .fb-txt{ font-size:13.5px; font-weight:600; color:var(--ink); min-width:0; }
.focus-banner .fb-exit{ margin-left:auto; flex:none; }
.focus-banner .fb-exit.btn{ background:var(--primary); color:#fff; border-color:var(--primary); font-weight:700; }
.focus-banner .fb-exit.btn:hover{ filter:brightness(1.06); }
@media (max-width:560px){ .focus-banner .fb-exit{ margin-left:0; width:100%; } }

@media (prefers-reduced-motion: reduce){
  .orbit-scene .os-craft{ animation:none; }
  .jh-pip.lit{ box-shadow:none; }
  .focus-banner{ transition:none; }
}

/* feedback 0707: "+N" reveals the hidden review patches inline; the ribbon
   wraps onto new lines once open instead of scrolling. */


/* ============ 0707 journey-path cinematics (GPU-cheap, reduce-killed) ===== */
/* the per-problem ring sweeps in with its checkpoint: a small settle-spin,
   transform/opacity only, staggered on the same --i rhythm as the nodes. */
@media (prefers-reduced-motion: no-preference) {
  .jp-segring { animation: jpSegIn .7s var(--ease) backwards; animation-delay: calc(var(--i, 0) * 48ms + .28s); }
  .jp-here { animation: jpHereIn .5s var(--ease) .9s backwards; }
}
@keyframes jpSegIn { from { transform: rotate(-42deg) scale(.72); opacity: 0; } to { transform: rotate(0deg) scale(1); opacity: 1; } }
@keyframes jpHereIn { from { opacity: 0; transform: translateY(-50%) translateX(-6px); } to { opacity: 1; transform: translateY(-50%) translateX(0); } }
@media (prefers-reduced-motion: reduce) {
  .jp-segring, .jp-here { animation: none; }
}
