
        *,
        *::before,
        *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0
        }

        :root {
            --slate-950: #ffffff;
            --slate-900: #f8f9ff;
            --slate-850: #f0f4ff;
            --slate-800: #e8eeff;
            --slate-700: #d4dcf7;
            --slate-600: #b8c4e8;
            --slate-500: #7b8cc4;
            --slate-400: #5468a8;
            --slate-300: #3d4f8a;
            --slate-200: #2a3668;
            --slate-100: #1a2448;
            --slate-50: #0f172a;

            --violet: #5b50e8;
            --violet-dim: #4338ca;
            --violet-shade: #3d33c4;
            --violet-glow: rgba(91, 80, 232, 0.15);
            --cyan: #18c0dd;
            --grad-hero: linear-gradient(135deg, #7b6cff 0%, #5b50e8 50%, #4338ca 100%);
            --grad-brand: linear-gradient(135deg, #6d5cff 0%, #8b5cf6 100%);
            --grad-cta: linear-gradient(135deg, #6a5cf0 0%, #5b50e8 100%);

            --emerald: #059669;
            --emerald-dim: #047857;
            --emerald-bg: rgba(5, 150, 105, 0.07);
            --emerald-border: rgba(5, 150, 105, 0.25);

            --rose: #e11d48;
            --rose-bg: rgba(225, 29, 72, 0.06);
            --rose-border: rgba(225, 29, 72, 0.22);

            --amber: #d97706;
            --amber-bg: rgba(217, 119, 6, 0.08);
            --amber-border: rgba(217, 119, 6, 0.25);

            --text-primary: #111827;
            --text-secondary: #4b5563;
            --text-muted: #6b7280;   /* a11y: was #9ca3af (~2.6:1) — now ≥4.5:1 on light bg */

            --card-bg: #ffffff;
            --card-border: rgba(91, 80, 232, 0.12);
            --card-border-hover: rgba(91, 80, 232, 0.35);

            --r: 16px;
            --r-sm: 12px;
            --r-lg: 20px;

            /* One study typeface, with hierarchy carried by size and weight. */
            --font-display: var(--font-ui);
            --font-ui: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

            /* Layered shadow scale for depth without heaviness */
            --shadow-sm: 0 1px 2px rgba(17, 24, 39, 0.05), 0 1px 3px rgba(91, 80, 232, 0.04);
            --shadow-md: 0 2px 4px rgba(17, 24, 39, 0.04), 0 8px 24px rgba(91, 80, 232, 0.08);
            --shadow-lg: 0 4px 8px rgba(17, 24, 39, 0.05), 0 18px 48px rgba(91, 80, 232, 0.12);
        }

        /* ─────────── DARK MODE ─────────── */
        [data-dark] {
            /* brand violet is ~3:1 as text on dark — links use the purple ramp */
            --violet-text: #9d94ff;
            /* Surface ladder — page → major surface → elevated card → interactive.
               Neutral charcoal by design: the brand purple is an accent
               (CTAs, active/selected, progress, branding), never a surface tint. */
            --surface-0: #111113;   /* page ground */
            --surface-1: #18181B;   /* nav, rail, recessed tracks */
            --surface-2: #1D1D21;   /* elevated cards and panels */
            --surface-3: #232327;   /* inputs, chips, secondary controls */
            --line: rgba(255, 255, 255, 0.08);   /* subtle divider */
            --line-strong: #34343A;              /* structural divider */
            /* --text-muted is 4.29:1 on --surface-3; use this tone for muted
               text that sits ON an interactive/secondary surface. */
            --text-muted-raised: #9B9BA4;

            --text-primary: #F5F5F7;
            --text-secondary: #B4B4BD;
            --text-muted: #85858F;
            --card-bg: var(--surface-2);
            --card-border: var(--line);
            --card-border-hover: rgba(255, 255, 255, 0.16);
            --emerald-bg: rgba(5, 150, 105, 0.13);
            --emerald-border: rgba(5, 150, 105, 0.32);
            --rose-bg: rgba(225, 29, 72, 0.11);
            --rose-border: rgba(225, 29, 72, 0.28);
            --amber-bg: rgba(217, 119, 6, 0.13);
            --amber-border: rgba(217, 119, 6, 0.3);
            --violet-glow: rgba(91, 80, 232, 0.3);
        }

        /* Match the light theme: same 40px grid, no aurora glows — tuned to
           read on the dark navy backdrop. */
        [data-dark] body {
            background-color: #111113;
            background-image:
                linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
                linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
            background-size: 40px 40px, 40px 40px;
        }

        [data-dark] nav {
            background: rgba(24, 24, 27, 0.96);
            border-bottom-color: rgba(255, 255, 255, 0.14);
        }
        [data-dark] .nav-logo-mark {
            background: #5b50e8;
        }

        [data-dark] nav.scrolled {
            box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
        }

        [data-dark] .input-card,
        [data-dark] .question-card,
        [data-dark] #scoreCard,
        [data-dark] #achievementsPanel,
        [data-dark] .review-panel,
        [data-dark] #sideMenu,
        [data-dark] .auth-modal,
        [data-dark] #badgeToast {
            background: #1D1D21;
        }

        /* section pages share the main app's dark background, not a flat panel */
        [data-dark] .section-page {
            background-color: #111113;
            /* canonical dark backdrop — same base + grid as every other page */
            background-image:
                linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
                linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
            background-size: 40px 40px, 40px 40px;
        }

        [data-dark] .tabs,
        [data-dark] .auth-tabs {
            background: #111113;
            border-color: rgba(255, 255, 255, 0.08);
        }

        [data-dark] .tab-slider {
            background: #232327;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
        }

        [data-dark] .auth-tab.active {
            background: #232327;
            color: var(--violet);
        }

        [data-dark] .option {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.14);
            box-shadow: none;
        }

        [data-dark] .option:hover {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.22);
            box-shadow: none;
        }

        [data-dark] .opt-letter {
            background: rgba(255, 255, 255, 0.08);
            border-color: rgba(255, 255, 255, 0.14);
            color: var(--text-muted);
        }

        [data-dark] .select-styled {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.14);
            color: var(--text-primary);
        }

        [data-dark] .select-styled option {
            background: #232327;
            color: var(--text-primary);
        }

        [data-dark] .input-text,
        [data-dark] .textarea-notes,
        [data-dark] .written-textarea {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.14);
            color: var(--text-primary);
        }

        [data-dark] .auth-field input {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.14);
            color: var(--text-primary);
        }

        [data-dark] .auth-field input:focus {
            background: #232327;
        }

        [data-dark] .score-stat {
            background: linear-gradient(135deg, #232327, #1D1D21);
        }

        [data-dark] .ach-card {
            background: #1D1D21;
            border-color: rgba(255, 255, 255, 0.08);
        }

        [data-dark] .ach-icon {
            background: rgba(255, 255, 255, 0.08) !important;
        }

        [data-dark] .qa-card {
            background: #1D1D21;
            border-color: rgba(255, 255, 255, 0.14);
        }

        [data-dark] .qa-card:hover {
            border-color: rgba(255, 255, 255, 0.22);
            box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
        }

        [data-dark] .section-card,
        [data-dark] .trend-chart-card,
        [data-dark] .heatmap-card {
            background: #1D1D21;
        }

        [data-dark] .question-chart {
            background: #1D1D21 !important;
            border-color: rgba(255, 255, 255, 0.14);
        }

        /* SVG has inline style="background:…" so needs !important to override */
        [data-dark] .question-chart svg {
            background: #1D1D21 !important;
        }

        /* Plot-area background rect (class added in JS) — presentation attr, CSS wins */
        [data-dark] .cplot-bg {
            fill: #18181B !important;
            stroke: rgba(91, 80, 232, 0.15) !important;
        }

        /* Axis / tick / title text inside chart SVG */
        [data-dark] .question-chart svg text {
            fill: #B4B4BD;
        }

        /* X-axis label div below SVG */
        [data-dark] .question-chart>div[style] {
            color: #B4B4BD !important;
            background: transparent !important;
        }

        [data-dark] .btn-retry {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.08);
            color: var(--text-secondary);
        }

        [data-dark] .btn-retry:hover {
            background: #34343A;
            color: var(--text-primary);
        }

        [data-dark] .menu-item:hover {
            background: rgba(255, 255, 255, 0.055);
        }

        /* Toggle switch — off-state track was #dde1f0 (visually white in dark) */
        [data-dark] .toggle-switch {
            background: #34343A;
        }

        [data-dark] .toggle-thumb {
            background: #F5F5F7;
        }

        /* Daily quiz usage meter — was hardcoded #f8f9ff */
        [data-dark] .usage-meter {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.14);
        }

        [data-dark] .usage-meter.warn {
            background: rgba(217, 119, 6, 0.08);
            border-color: rgba(217, 119, 6, 0.3);
        }

        [data-dark] .usage-meter.full {
            background: rgba(225, 29, 72, 0.08);
            border-color: rgba(225, 29, 72, 0.3);
        }

        [data-dark] .kbd-hint {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.14);
            color: #9d94ff;
        }

        [data-dark] .upload-preview-img {
            background: #18181B;
        }

        [data-dark] .progress-bar-track {
            background: rgba(91, 80, 232, 0.18) !important;
        }

        /* Progress wrap sticky bar */
        [data-dark] .progress-wrap {
            background: rgba(24, 24, 27, 0.92) !important;
            border-color: rgba(91, 80, 232, 0.18);
        }

        /* "∞ No timer" badge */
        [data-dark] .timer-off-badge {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.14);
            color: var(--text-muted-raised);
        }

        /* Previous button */
        [data-dark] .btn-prev {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.14);
            color: var(--text-secondary);
        }

        [data-dark] .btn-prev:hover {
            background: #34343A;
            color: var(--text-primary);
        }

        /* Answer states are full solid colour fills — white text works on
           both themes, so dark mode keeps it */
        [data-dark] .option.correct .opt-text,
        [data-dark] .option.wrong .opt-text,
        [data-dark] .option.timeout-correct .opt-text {
            color: #ffffff;
        }

        [data-dark] .option.disabled:hover {
            background: #232327;
        }

        /* Explanation boxes */
        [data-dark] .explanation-box.correct-exp {
            background: rgba(5, 150, 105, 0.12);
            color: #6ee7b7;
        }

        [data-dark] .explanation-box.wrong-exp {
            background: rgba(217, 119, 6, 0.1);
            color: #fcd34d;
        }

        [data-dark] .explanation-box.timeout-exp {
            background: rgba(225, 29, 72, 0.1);
            color: #fca5a5;
        }

        [data-dark] .load-dot {
            background: #34343A;
        }

        [data-dark] .hamburger div {
            background: var(--text-secondary);
        }

        [data-dark] .bp-l {
            stroke: rgba(91, 80, 232, 0.38);
        }

        [data-dark] .bp-la {
            stroke: rgba(91, 80, 232, 0.65);
        }

        [data-dark] .bp-ld {
            stroke: rgba(91, 80, 232, 0.22);
        }

        [data-dark] .bp-dash {
            stroke: rgba(91, 80, 232, 0.3);
        }

        [data-dark] .bp-fillm {
            fill: rgba(91, 80, 232, 0.18);
        }

        [data-dark] .bp-dot {
            fill: rgba(91, 80, 232, 0.75);
        }

        [data-dark] .bp-text {
            fill: rgba(91, 80, 232, 0.65);
        }

        [data-dark] .bp-texts {
            fill: rgba(91, 80, 232, 0.45);
        }

        body {
            font-family: var(--font-ui);
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
            text-rendering: optimizeLegibility;
            /* Clean, professional backdrop (Quizlet/Duolingo calm): a soft
               light base with two gentle aurora glows — no busy grid. Depth
               comes from the grain overlay + the cards, not background noise. */
            background-color: #f5f6fc;
            background-image:
                radial-gradient(ellipse 1100px 680px at 12% -5%, rgba(91, 80, 232, .10) 0%, transparent 62%),
                radial-gradient(ellipse 900px 620px at 92% 8%, rgba(34, 195, 221, .07) 0%, transparent 60%);
            color: var(--text-primary);
            min-height: 100dvh;
            padding: 80px 20px 40px;
            overflow-x: hidden;
        }

        /* Fine grain overlay — adds premium depth and ties the app to the
           homepage + results-debrief texture. Imperceptible but it kills the
           flat-gradient "AI slop" look. Sits below nav/modals, blocks nothing. */
        body::before {
            content: '';
            position: fixed;
            inset: 0;
            pointer-events: none;
            z-index: 0;
            opacity: .02;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
        }
        [data-dark] body::before { opacity: .035; }

        /* Professional, consistent keyboard focus ring (mouse clicks unaffected) */
        a:focus-visible,
        button:focus-visible,
        input:focus-visible,
        textarea:focus-visible,
        select:focus-visible,
        [tabindex]:focus-visible,
        .csel-trigger:focus-visible,
        .option:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
            border-radius: 8px;
        }

        @media(max-width:600px) {
            body {
                padding: 70px 16px 120px
            }
        }

        .container {
            max-width: 760px;
            margin: 0 auto;
            position: relative;
            z-index: 1;
        }

        /* ── NAV ── */
        nav {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            z-index: 1005;   /* above tool/section pages (1003) so it stays visible */
            background: rgba(246, 248, 255, 0.92);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border-bottom: 1px solid rgba(91, 80, 232, 0.1);
            padding: 0 24px;
            height: 60px;
            display: flex;
            align-items: center;
        }

        .nav-inner {
            max-width: 1240px;
            margin: 0 auto;
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 8px;
        }

        /* ── Quizlet-style nav: Study tools / Subjects dropdowns + search + Create
              (mirrors homepage.html, themed with the app's variables) ── */
        .nav-left { display: flex; align-items: center; gap: 4px; min-width: 0; }
        .nav-left-menu { display: flex; align-items: center; gap: 2px; list-style: none; margin: 0 0 0 6px; padding: 0; }
        .nav-dd { position: relative; }
        /* The "Your work" menu holds rows, not links: a title and a sub-line.
           Capped and scrollable so twenty decks cannot run the menu off the
           bottom of the screen. */
        .nav-dd-menu--mine { max-height: min(70vh, 460px); overflow-y: auto; overscroll-behavior: contain; }
        .nav-mine-row {
            display: flex; flex-direction: column; gap: 1px;
            padding: 7px 12px; border: none; background: none; width: 100%;
            font: inherit; text-align: left; cursor: var(--cur-point, pointer);
            color: var(--text-primary); text-decoration: none;
        }
        .nav-mine-row:hover, .nav-mine-row:focus-visible { background: var(--violet-glow); }
        .nav-mine-title { font-weight: 700; font-size: .86rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
        .nav-mine-sub { font-size: .72rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
        .nav-mine-empty { padding: 7px 12px; font-size: .78rem; color: var(--text-muted); }
        .nav-mine-all { display: block; padding: 8px 12px; font-weight: 700; font-size: .82rem; }

        /* The allowance, standing on its own in the nav now that the Study
           tools dropdown is gone. Reuses .usage-ring so there is one ring in
           the app, but carries its own warn/full rules rather than the
           .usage-dock ones — syncDockOpenState queries '.usage-dock,
           .allowance' to sync popovers and this readout has none. */
        /* The app's one allowance indicator, sitting in the nav. Reuses
           .usage-ring so there is a single ring in the app; it carries its own
           warn/full rules rather than the .usage-dock ones because
           syncDockOpenState queries '.usage-dock, .allowance' for popover
           syncing and this is neither. */
        .nav-usage { display: flex; align-items: center; margin-left: 8px; }
        .nav-usage[hidden] { display: none; }
        .nav-usage-btn {
            display: inline-flex; align-items: center; gap: 7px;
            /* A bare <button> brings its own padding, border, background and
               font — which made this 69px tall in a 60px nav. */
            padding: 4px 11px 4px 5px;
            border: 1px solid var(--card-border);
            border-radius: 999px;
            background: var(--card-bg);
            color: var(--text-primary);
            font: inherit;
            line-height: 1;
            cursor: var(--cur-point, pointer);
            transition: border-color .2s, background .2s;
        }
        .nav-usage-btn:hover { border-color: var(--card-border-hover); }
        .nav-usage-btn:focus-visible {
            outline: none; border-color: var(--violet);
            box-shadow: 0 0 0 3px var(--violet-glow);
        }
        .nav-usage-btn[aria-expanded="true"] {
            border-color: var(--violet); background: var(--violet-glow);
        }
        .nav-usage .usage-ring { width: 20px; height: 20px; flex: none; transform: rotate(-90deg); }
        /* One line: a nav bar is 60px and the panel carries the detail. */
        .nav-usage-text { display: inline-flex; align-items: baseline; gap: 4px; white-space: nowrap; }
        .nav-usage-pct { font-weight: 800; font-size: .8rem; font-variant-numeric: tabular-nums; }
        .nav-usage-sub { font-size: .72rem; color: var(--text-muted); }
        .nav-usage.warn .usage-ring-fill { stroke: var(--amber); }
        .nav-usage.warn .usage-ring-track { stroke: var(--amber); opacity: .26; }
        .nav-usage.full .usage-ring-fill { stroke: var(--rose); }
        .nav-usage.full .usage-ring-track { stroke: var(--rose); opacity: .34; }
        @media (max-width: 560px) { .nav-usage-sub { display: none; } }
        /* The Free count pill ("7 of 12") names no unit on its own the way
           "58%" did, and the nav pill is the only usage indicator on
           phones — so unlike the percentage variant, its label has to
           survive the hide above. updateQuizCounter/paintNavUsage set
           is-count and shorten the wording to fit ("quizzes" vs "quizzes
           left") once the viewport is too narrow for the full phrase. */
        @media (max-width: 560px) { .nav-usage.is-count .nav-usage-sub { display: inline; } }

        .nav-dd-btn {
            display: inline-flex; align-items: center; gap: 5px; background: none; border: none; cursor: var(--cur-point, pointer);
            font-family: var(--font-ui); font-weight: 700; font-size: .9rem; color: var(--text-primary);
            padding: 7px 10px; border-radius: 999px; white-space: nowrap;
        }
        .nav-dd-btn:hover { background: var(--violet-glow); color: var(--violet); }
        .nav-dd-menu {
            position: absolute; top: calc(100% + 10px); left: 0; transform: translateY(6px);
            width: 248px; background: #fff; border: 1px solid rgba(91, 80, 232, .12);
            border-radius: 16px; box-shadow: 0 16px 44px rgba(20, 20, 60, .16); padding: 8px;
            opacity: 0; visibility: hidden; transition: opacity .18s, transform .18s; z-index: 1300;
        }
        [data-dark] .nav-dd-menu { background: #1D1D21; border-color: rgba(255, 255, 255, .1); }
        .nav-dd[data-open="1"] .nav-dd-menu { opacity: 1; visibility: visible; transform: translateY(0); }
        .nav-dd-menu a {
            display: flex; align-items: center; gap: 10px; padding: 9px 11px; border-radius: 10px;
            font-size: .9rem; font-weight: 600; color: var(--text-primary); text-decoration: none;
        }
        .nav-dd-menu a:hover { background: var(--violet-glow); color: var(--violet); }
        .nav-dd-menu a svg { color: var(--violet); flex-shrink: 0; }
        .nav-dd-sep { font-size: .68rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 800; color: var(--text-muted); padding: 10px 11px 4px; }
        .nav-dd-subcat { font-size: .64rem; text-transform: uppercase; letter-spacing: .05em; font-weight: 800; color: var(--text-muted); opacity: .75; padding: 7px 11px 2px; }
        #navSubjectsDd .nav-dd-menu { max-height: min(74vh, 540px); overflow-y: auto; }

        .nav-search { position: relative; flex: 1; min-width: 170px; max-width: 420px; margin: 0 14px; }
        .nav-search-ico { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); width: 16px; height: 16px; color: var(--text-muted); pointer-events: none; }
        .nav-search input {
            width: 100%; height: 40px; padding: 0 14px 0 40px; border-radius: 999px;
            border: 1.5px solid rgba(91, 80, 232, .18); background: #fff; color: var(--text-primary);
            font-family: var(--font-ui); font-size: .9rem; transition: border-color .15s, box-shadow .15s;
        }
        [data-dark] .nav-search input { background: #232327; border-color: rgba(255, 255, 255, .12); }
        .nav-search input:focus-visible { border-color: var(--violet); box-shadow: 0 0 0 4px var(--violet-glow); }
        .nav-search-results {
            position: absolute; top: calc(100% + 8px); left: 0; right: 0; background: #fff;
            border: 1px solid rgba(91, 80, 232, .12); border-radius: 14px; box-shadow: 0 16px 44px rgba(20, 20, 60, .16);
            padding: 6px; max-height: 64vh; overflow-y: auto; display: none; z-index: 1300;
        }
        [data-dark] .nav-search-results { background: #1D1D21; border-color: rgba(255, 255, 255, .1); }
        .nav-search-results.open { display: block; }
        .nav-search-results a { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border-radius: 9px; font-size: .9rem; font-weight: 600; color: var(--text-primary); text-decoration: none; }
        .nav-search-results a:hover { background: var(--violet-glow); color: var(--violet); }
        .nav-search-results a svg { color: var(--violet); flex-shrink: 0; }
        .nav-search-cat { font-size: .64rem; text-transform: uppercase; letter-spacing: .05em; font-weight: 800; color: var(--text-muted); opacity: .75; padding: 8px 11px 3px; }
        .nav-search-make { color: var(--violet) !important; font-weight: 700 !important; border-top: 1px solid rgba(91, 80, 232, .12); margin-top: 4px; }
        .nav-create {
            display: inline-flex; align-items: center; gap: 6px; background: var(--violet); color: #fff;
            font-family: var(--font-ui); font-weight: 700; font-size: .85rem; padding: 8px 14px; border-radius: 999px;
            text-decoration: none; box-shadow: 0 4px 12px rgba(91, 80, 232, .28); white-space: nowrap; cursor: var(--cur-point, pointer); border: none;
        }
        .nav-create:hover { transform: translateY(-1px); }
        /* Teacher "Host" mode — outlined special-purpose look, distinct from student "Join" */
        .nav-create.host {
            background: var(--card) !important; color: var(--violet) !important;
            border: 1.5px solid rgba(91, 80, 232, .45);
            box-shadow: 0 2px 8px rgba(91, 80, 232, .14) !important;
        }
        .nav-create.host:hover { background: var(--violet) !important; color: #fff !important; }
        [data-dark] .nav-create.host { background: #1D1D21 !important; color: #b9b2ff !important; border-color: rgba(255, 255, 255, 0.22); }
        [data-dark] .nav-create.host:hover { background: var(--violet) !important; color: #fff !important; }
        /* 1180, not 980. These two are the widest things in the bar and they
           come back long before there is room for them: between 981 and 1180
           the row is over-subscribed, and because .nav-search is `flex: 1`
           (basis 0, so it never gives any width back) the whole shortfall was
           taken out of .nav-left — which at 1024px crushed the brand to 8px
           and the allowance ring to nothing. */
        @media (max-width: 1180px) { .nav-search, .nav-left-menu { display: none; } }
        /* Hide only the LABEL on narrow screens, never the icon. `.nav-create span`
           matched both spans, so the button collapsed to its own padding — a 30px
           blank violet pill with nothing in it, which is what every phone showed
           for the Join (and teacher Host) CTA. */
        /* 640, matching the width at which topnav.css turns this button into a
           36px circle. At 560 the two disagreed, so between 561 and 640 the
           word "Join" was being laid out inside a 36px circle with
           `padding: 0` — the same overflowing-label fault the note above
           describes, one breakpoint over. */
        @media (max-width: 640px) {
            .nav-create #navCreateLabel { display: none; }
            .nav-create { padding: 8px; min-width: 40px; justify-content: center; }
        }

        .nav-brand {
            display: flex;
            align-items: center;
            gap: 10px;
            text-decoration: none;
        }

        .nav-logo-mark {
            width: 34px;
            height: 34px;
            background: #5b50e8;
            border-radius: 9px;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: none;
            overflow: hidden;
            flex-shrink: 0;
            align-self: center;
            aspect-ratio: 1 / 1;
        }

        .nav-logo-mark svg,
        .nav-logo-mark img {
            width: 100%;
            height: 100%;
            object-fit: contain;
        }

        .brand-sub {
            font-weight: 700;
            opacity: .6;
            white-space: nowrap;
        }

        @media (max-width: 360px) {
            .brand-sub { display: none; }
        }

        .nav-brand-name {
            font-family: var(--font-display);
            font-size: 1.1rem;
            font-weight: 800;
            color: var(--violet);
            letter-spacing: -0.02em;
        }

        .nav-right {
            display: flex;
            align-items: center;
            gap: 12px;
        }

        #navScorePill {
            display: none;
            align-items: center;
            gap: 6px;
            background: rgba(91, 80, 232, 0.08);
            border: 1px solid rgba(91, 80, 232, 0.2);
            color: var(--violet);
            font-weight: 600;
            font-size: 0.8rem;
            padding: 5px 12px;
            border-radius: 99px;
            animation: fadeUp 0.3s ease;
        }

        #navScorePill .sn {
            font-weight: 700;
            color: var(--text-primary);
        }

        #navStreakPill {
            display: none;
            align-items: center;
            gap: 5px;
            background: rgba(245, 158, 11, 0.1);
            border: 1px solid rgba(245, 158, 11, 0.3);
            color: #d97706;
            font-weight: 800;
            font-size: 0.8rem;
            padding: 5px 12px;
            border-radius: 999px;
            cursor: var(--cur-point, pointer);
            animation: fadeUp 0.3s ease;
        }

        [data-dark] #navStreakPill {
            color: #fbbf24;
        }

        .nav-dash-btn {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            background: rgba(91, 80, 232, 0.08);
            border: 1px solid rgba(91, 80, 232, 0.2);
            color: var(--violet);
            font-family: inherit;
            font-weight: 700;
            font-size: 0.8rem;
            padding: 6px 13px;
            border-radius: 999px;
            cursor: var(--cur-point, pointer);
            transition: background 0.2s, box-shadow 0.2s, transform 0.2s;
        }

        .nav-dash-btn:hover {
            background: rgba(91, 80, 232, 0.14);
            box-shadow: 0 2px 12px var(--violet-glow);
            transform: translateY(-1px);
        }

        /* declutter the nav: Dashboard + points are reachable via the
           menu / streak pill / quiz card, so drop them to stop the hamburger
           getting pushed off-screen.

           820, not 600. The intent was right and the number was not: with
           Dashboard (115px), the points pill and the account email all back
           at 601px the row still needed ~70px it did not have, so this was
           the band where the hamburger left the screen on a landscape phone.
           820 is where the bar genuinely has room for them again. */
        @media(max-width:820px) {
            .nav-dash-btn {
                display: none;
            }

            #navScorePill {
                display: none !important;
            }

            .nav-user-email {
                display: none;
            }

            .nav-right {
                gap: 8px;
            }
        }

        .hamburger {
            display: flex;
            flex-direction: column;
            gap: 5px;
            cursor: var(--cur-point, pointer);
            padding: 4px;
        }

        .hamburger div {
            width: 22px;
            height: 1.5px;
            background: var(--text-secondary);
            border-radius: 2px;
            transition: all 0.2s;
        }

        /* ── HERO HEADER ── */
        .hero-header {
            margin-bottom: 24px;
            animation: fadeUp 0.7s ease both;
        }

        @keyframes dotPulse {

            0%,
            100% {
                opacity: 1;
                transform: scale(1)
            }

            50% {
                opacity: 0.5;
                transform: scale(0.7)
            }
        }

        /* "See everything you can do" — surfaces features that aren't in the
           side menu (timer/written/exam-mode toggles, Daily Review,
           achievements, mistake bank, heatmap, weak-topic practice) */
        .features-list-item {
            display: flex;
            align-items: flex-start;
            gap: 14px;
            text-align: left;
        }

        .features-list-icon {
            width: 38px;
            height: 38px;
            flex-shrink: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            color: rgba(91, 80, 232, .8);
            background: rgba(91, 80, 232, 0.08);
            border: 1px solid rgba(91, 80, 232, 0.16);
            border-radius: 12px;
        }

        .features-list-title {
            font-weight: 700;
            font-size: 0.88rem;
            color: var(--text-primary);
            margin-bottom: 3px;
        }

        .features-list-desc {
            font-size: 0.8rem;
            color: var(--text-secondary);
            line-height: 1.55;
        }

        button.section-card.features-list-item {
            width: 100%;
            font-family: var(--font-ui);
            cursor: var(--cur-point, pointer);
            transition: transform .15s ease, border-color .15s ease;
        }

        button.section-card.features-list-item:hover {
            transform: translateX(3px);
            border-color: rgba(91, 80, 232, 0.3);
        }

        #featuresPage.section-page {
            animation: slideUp .42s cubic-bezier(0.4, 0, 0.2, 1) both;
        }

        #featuresPage .features-list-item {
            opacity: 0;
            animation: fadeUp .45s ease both;
        }

        #featuresPage .features-list-item:nth-child(1) {
            animation-delay: .05s;
        }

        #featuresPage .features-list-item:nth-child(2) {
            animation-delay: .11s;
        }

        #featuresPage .features-list-item:nth-child(3) {
            animation-delay: .17s;
        }

        #featuresPage .features-list-item:nth-child(4) {
            animation-delay: .23s;
        }

        #featuresPage .features-list-item:nth-child(5) {
            animation-delay: .29s;
        }

        .features-list-arrow {
            margin-left: auto;
            align-self: center;
            color: var(--violet);
            font-size: 1.05rem;
            flex-shrink: 0;
        }

        /* ── INPUT CARD ── */
        .input-card {
            background: #ffffff;
            border: 1px solid rgba(91, 80, 232, 0.1);
            border-radius: 20px;
            padding: 28px;
            box-shadow: var(--shadow-md);
            animation: fadeUp 0.7s 0.2s ease backwards;
        }

            to {
                opacity: 1
            }
        }

        /* ── Quick-access study-mode cards ── */
        .quick-access-row {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 10px;
            margin-top: 14px;
        }

        .qa-card {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            gap: 6px;
            background: #ffffff;
            border: 1px solid rgba(91, 80, 232, 0.12);
            border-radius: 16px;
            padding: 14px 15px;
            cursor: var(--cur-point, pointer);
            text-align: left;
            color: var(--violet);
            transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;
            font-family: inherit;
        }

        .qa-card:hover {
            transform: translateY(-2px);
            border-color: rgba(91, 80, 232, 0.3);
            box-shadow: 0 6px 18px rgba(91, 80, 232, 0.12);
        }

        .qa-card .qa-label {
            font-weight: 700;
            font-size: 0.92rem;
            color: var(--text-primary);
        }

        .qa-card .qa-sub {
            font-size: 0.74rem;
            color: var(--text-muted);
        }

        /* ── Leaderboard ── */
        .lb-you {
            display: flex;
            align-items: center;
            gap: 14px;
            padding: 16px;
            border-radius: 16px;
            background: linear-gradient(120deg, var(--violet), #8b5cf6);
            color: #fff;
            box-shadow: var(--shadow-md);
            margin-bottom: 18px;
        }

        .lb-you-avatar {
            width: 46px;
            height: 46px;
            border-radius: 50%;
            overflow: hidden;
            flex-shrink: 0;
            background: transparent;
        }

        .lb-you-avatar svg { width: 100%; height: 100%; display: block; }
        .lb-you-main { flex: 1; min-width: 0; }
        .lb-you-name { font-weight: 800; font-size: 1rem; }
        .lb-you-sub { font-size: 0.78rem; opacity: 0.92; }

        .lb-you-rank {
            text-align: right;
            flex-shrink: 0;
        }

        .lb-you-rank .n {
            font-family: var(--font-display);
            font-weight: 800;
            font-size: 1.5rem;
            line-height: 1;
        }

        .lb-you-rank .l { font-size: 0.68rem; text-transform: uppercase; opacity: 0.9; letter-spacing: 0.04em; }

        .lb-level-pill {
            display: inline-flex;
            align-items: center;
            gap: 5px;
            background: rgba(255, 255, 255, 0.22);
            border-radius: 999px;
            padding: 2px 9px;
            font-size: 0.72rem;
            font-weight: 700;
            margin-top: 3px;
        }

        .lb-row {
            display: flex;
            align-items: center;
            gap: 12px;
            padding: 11px 14px;
            border: 1px solid var(--card-border);
            border-radius: 12px;
            background: var(--card-bg, #fff);
            margin-bottom: 8px;
        }

        .lb-row.is-me {
            border-color: var(--violet);
            box-shadow: 0 0 0 1px var(--violet);
        }

        .lb-rank {
            width: 30px;
            flex-shrink: 0;
            font-family: var(--font-display);
            font-weight: 800;
            font-size: 1.05rem;
            color: var(--text-muted);
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .lb-rank svg { display: block; }

        .lb-row.top1 .lb-rank { color: #f59e0b; }
        .lb-row.top2 .lb-rank { color: #94a3b8; }
        .lb-row.top3 .lb-rank { color: #d97706; }

        .lb-avatar {
            width: 34px;
            height: 34px;
            border-radius: 50%;
            overflow: hidden;
            flex-shrink: 0;
            background: transparent;
        }

        .lb-avatar svg { width: 100%; height: 100%; display: block; }
        .lb-name { flex: 1; min-width: 0; font-weight: 700; font-size: 0.9rem; color: var(--text-primary);
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
        .lb-points { flex-shrink: 0; font-weight: 800; color: var(--violet); font-size: 0.9rem; }

        [data-dark] .lb-row { background: #1D1D21; }

        .lb-champ {
            display: flex;
            align-items: center;
            gap: 12px;
            padding: 12px 14px;
            margin-bottom: 14px;
            border-radius: 14px;
            background: linear-gradient(120deg, rgba(252, 211, 77, 0.18), rgba(224, 164, 21, 0.08));
            border: 1px solid rgba(224, 164, 21, 0.4);
        }

        /* ── Account level card ── */
        .level-card {
            display: flex;
            align-items: center;
            gap: 16px;
            padding: 18px;
            border-radius: 18px;
            background: linear-gradient(120deg, var(--violet), #8b5cf6 70%, #6366f1);
            color: #fff;
            box-shadow: var(--shadow-md);
            margin-bottom: 18px;
        }

        .level-ring {
            width: 58px;
            height: 58px;
            border-radius: 50%;
            flex-shrink: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            background: rgba(255, 255, 255, 0.18);
            border: 2px solid rgba(255, 255, 255, 0.5);
            font-family: var(--font-display);
            font-weight: 800;
            font-size: 1.35rem;
            line-height: 1;
        }

        .level-main { flex: 1; min-width: 0; }
        .level-title { font-weight: 800; font-size: 1.02rem; }
        .level-title .lt-sub { font-weight: 600; opacity: 0.9; font-size: 0.82rem; }

        .level-bar {
            height: 8px;
            border-radius: 999px;
            background: rgba(255, 255, 255, 0.25);
            overflow: hidden;
            margin: 8px 0 5px;
        }

        .level-bar-fill {
            height: 100%;
            border-radius: 999px;
            background: #fff;
            box-shadow: 0 0 8px rgba(255, 255, 255, 0.6);
            transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
        }

        .level-xp { font-size: 0.76rem; opacity: 0.92; }

        .lb-champ-crown { flex-shrink: 0; display: flex; }
        .lb-champ-label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--amber); font-weight: 800; }
        .lb-champ-name { font-weight: 700; font-size: 0.92rem; color: var(--text-primary); }

        /* ── ATAR estimator ── */
        /* Keeps the calculator a sane, readable width and centred on large
           screens — without this, rows stretch full-bleed while #atarSystem
           (capped narrower) ends up looking orphaned off to one side. */
        .atar-wrap {
            max-width: 640px;
            margin: 0 auto;
        }

        .atar-row {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 10px;
        }

        .atar-row .atar-subj {
            flex: 1;
            min-width: 0;
        }

        .atar-row .atar-score {
            width: 90px;
            flex-shrink: 0;
            text-align: center;
        }

        .atar-row .atar-del {
            flex-shrink: 0;
            background: none;
            border: none;
            color: var(--text-muted);
            font-size: 1.1rem;
            cursor: var(--cur-point, pointer);
            padding: 4px 6px;
            line-height: 1;
        }

        .atar-row .atar-del:hover { color: var(--rose); }
        select.atar-subj { cursor: var(--cur-point, pointer); }
        .atar-brk { margin: 14px 0 4px; text-align: left; }
        .atar-brk-row { display: flex; justify-content: space-between; gap: 12px; font-size: .85rem; padding: 6px 0; border-bottom: 1px solid rgba(91, 80, 232, 0.08); }
        .atar-brk-row span:first-child { font-weight: 700; color: var(--text-primary); }
        .atar-brk-row span:last-child { color: var(--text-muted); font-variant-numeric: tabular-nums; }
        .atar-brk-row em { color: var(--violet); font-style: normal; font-weight: 700; font-size: .72rem; }
        .atar-warn { background: rgba(245, 158, 11, .12); color: #b45309; border-radius: var(--r-sm, 12px); padding: 9px 12px; font-size: .82rem; font-weight: 600; margin: 10px 0; }
        [data-dark] .atar-warn { color: #fcd34d; }

        .atar-add {
            background: var(--violet-glow);
            border: 1px dashed rgba(91, 80, 232, 0.4);
            color: var(--violet);
            border-radius: 999px;
            padding: 10px;
            width: 100%;
            font-family: inherit;
            font-weight: 700;
            font-size: 0.88rem;
            cursor: var(--cur-point, pointer);
            margin-top: 4px;
        }

        .atar-add:hover { background: rgba(91, 80, 232, 0.14); }

        .atar-result {
            margin-top: 24px;
            text-align: center;
            background: linear-gradient(135deg, rgba(91, 80, 232, 0.08), rgba(94, 234, 246, 0.06));
            border: 1px solid var(--card-border);
            border-radius: 20px;
            padding: 28px 20px;
            box-shadow: var(--shadow-md);
            animation: popIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
        }

        .atar-result .atar-big {
            font-family: var(--font-display);
            font-weight: 800;
            font-size: 3.4rem;
            line-height: 1;
            letter-spacing: -0.02em;
            color: var(--violet);
        }

        .atar-result .atar-cap { font-size: 0.8rem; color: var(--text-muted); margin-top: 4px; }
        .atar-result .atar-band {
            display: inline-block;
            margin-top: 12px;
            background: var(--violet);
            color: #fff;
            border-radius: 999px;
            padding: 5px 14px;
            font-weight: 700;
            font-size: 0.85rem;
        }

        .atar-result .atar-meta {
            margin-top: 14px;
            font-size: 0.8rem;
            color: var(--text-secondary);
            line-height: 1.5;
        }

        /* ── Flashcards setup (overhauled) ── */
        /* Not a card. The quiz builder puts its fields straight on the
           ground with a hairline between sections, and wrapping the same kind
           of form in a white panel is what made every tool page read as
           "boxed" next to it. Depth on these screens belongs to the things
           IN the form — the pills, the CTA — not to a container around it. */
        .fc-setup-card {
            background: transparent;
            border: 0;
            border-radius: 0;
            padding: 4px 0 0;
            box-shadow: none;
        }



        .fc-count-pills {
            display: flex;
            gap: 8px;
        }

        .fc-count-pills button {
            flex: 1;
            background: #f8f9ff;
            border: 1.5px solid rgba(91, 80, 232, 0.12);
            border-radius: 999px;
            padding: 11px 0;
            font-family: var(--font-display);
            font-weight: 800;
            font-size: 1rem;
            color: var(--text-muted);
            cursor: var(--cur-point, pointer);
            transition: all 0.15s;
        }

        .fc-count-pills button:hover { border-color: rgba(91, 80, 232, 0.3); color: var(--text-secondary); }
        .fc-count-pills button.active {
            background: var(--violet);
            border-color: var(--violet);
            color: #fff;
        }

        [data-dark] .fc-count-pills button { background: #232327; }
        [data-dark] .fc-count-pills button.active { background: var(--violet); }

        /* ── Study timer (Pomodoro) ── */
        .tt-card {
            background: #fff; border: 1px solid rgba(91, 80, 232, 0.1); border-radius: 20px;
            padding: 32px 24px; text-align: center; box-shadow: var(--shadow-md);
        }
        [data-dark] .tt-card { background: #1D1D21; }
        .tt-phase {
            font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.1em; font-weight: 800;
            color: var(--violet); margin-bottom: 8px;
        }
        .tt-card.break .tt-phase { color: var(--emerald); }
        .tt-clock {
            font-family: var(--font-display); font-weight: 800; font-size: 4.2rem; line-height: 1;
            color: var(--text-primary); letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
        }
        .tt-controls { display: flex; gap: 10px; justify-content: center; margin: 24px 0 18px; flex-wrap: wrap; }
        .tt-secondary {
            background: var(--violet-glow); border: none; color: var(--violet); border-radius: 999px;
            padding: 0 18px; font-family: inherit; font-weight: 700; font-size: 0.9rem; cursor: var(--cur-point, pointer);
        }
        .tt-secondary:hover { background: rgba(91, 80, 232, 0.16); }

        /* inline primary button for tools (never sticks to the bottom like .btn-generate) */
        .tool-cta {
            background: var(--grad-cta);
            color: #fff; border: none; border-radius: 999px; padding: 0 28px; height: 50px;
            font-family: inherit; font-weight: 800; font-size: 0.98rem; cursor: var(--cur-point, pointer);
            box-shadow: 0 8px 18px rgba(91, 80, 232, .26);
            transition: transform 0.12s ease, box-shadow 0.12s ease, filter 0.12s;
        }
        .tool-cta:hover { filter: brightness(1.05); transform: translateY(-1px); box-shadow: 0 11px 22px rgba(91, 80, 232, .34); }
        .tool-cta:active { transform: translateY(4px); box-shadow: 0 2px 6px rgba(91, 80, 232, .3); }
        .tt-len { display: flex; gap: 8px; align-items: center; justify-content: center; flex-wrap: wrap; }
        .tt-len-label { font-size: 0.78rem; color: var(--text-muted); margin-right: 4px; }
        .tt-len button {
            background: #f8f9ff; border: 1.5px solid rgba(91, 80, 232, 0.12); border-radius: 999px;
            padding: 6px 14px; font-family: inherit; font-weight: 700; font-size: 0.82rem;
            color: var(--text-muted); cursor: var(--cur-point, pointer);
        }
        .tt-len button.active { background: var(--violet); border-color: var(--violet); color: #fff; }
        [data-dark] .tt-len button { background: #232327; }
        .tt-sessions { margin-top: 18px; font-size: 0.85rem; color: var(--text-secondary); }

        /* ── Match game ── */
        .match-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
        .match-timer {
            font-family: var(--font-display); font-weight: 800; font-size: 1.4rem; color: var(--violet);
            font-variant-numeric: tabular-nums;
        }

        /* ── live stats: progress bar + score + combo ── */
        .match-stats { margin: 0 0 14px; }
        .match-progress {
            height: 8px; border-radius: 999px; background: rgba(91, 80, 232, 0.1); overflow: hidden;
        }
        [data-dark] .match-progress { background: rgba(91, 80, 232, 0.18); }
        .match-progress-fill {
            height: 100%; width: 0%; border-radius: 999px;
            background: linear-gradient(90deg, var(--violet), var(--cyan, #5EEAF6));
            transition: width 0.35s cubic-bezier(.34,1.56,.64,1);
        }
        .match-stats-row { display: flex; align-items: center; justify-content: space-between; margin-top: 8px; }
        .match-score {
            font-family: var(--font-display); font-weight: 800; font-size: 1.05rem; color: var(--violet);
            font-variant-numeric: tabular-nums;
        }
        .match-combo {
            display: inline-flex; align-items: center; gap: 4px; font-weight: 800; font-size: 0.85rem;
            color: #d97706; background: rgba(217, 119, 6, 0.1); border-radius: 999px; padding: 3px 10px;
            animation: comboPop 0.3s cubic-bezier(.34,1.56,.64,1);
        }
        @keyframes comboPop { from { transform: scale(0.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }

        .match-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
        @media(max-width:520px) { .match-grid { grid-template-columns: repeat(2, 1fr); } }
        .match-tile {
            position: relative;
            min-height: 92px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;
            padding: 12px; background: var(--card-bg, #fff); border: 1.5px solid rgba(91, 80, 232, 0.12); border-radius: 16px;
            font-size: 0.82rem; font-weight: 600; color: var(--text-primary); cursor: var(--cur-point, pointer); line-height: 1.3;
            box-shadow: 0 2px 8px rgba(91, 80, 232, 0.05);
            transition: transform 0.12s, border-color 0.12s, background 0.12s, opacity 0.25s, box-shadow 0.12s;
            animation: matchPop 0.4s cubic-bezier(.34,1.56,.64,1) both;
        }
        .match-tile:active:not(.gone):not(.sel):not(.correct):not(.wrong) { transform: scale(0.96); }
        .match-tile.correct::after {
            content: ''; position: absolute; top: 8px; right: 8px; width: 22px; height: 22px; border-radius: 50%;
            background: var(--emerald);
            -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4L19 7'/%3E%3C/svg%3E") center/14px no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4L19 7'/%3E%3C/svg%3E") center/14px no-repeat;
            animation: checkPop 0.3s cubic-bezier(.34,1.56,.64,1) both;
        }
        @keyframes checkPop { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: 1; } }
        .match-tile-label {
            font-size: 0.62rem; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
            color: var(--text-muted); opacity: 0.55; margin-bottom: 4px;
        }
        @keyframes matchPop { from { opacity: 0; transform: scale(0.7) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } }
        [data-dark] .match-tile { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); }
        .match-tile:hover:not(.gone):not(.sel) { border-color: rgba(91, 80, 232, 0.4); transform: translateY(-2px); box-shadow: 0 6px 16px rgba(91, 80, 232, 0.12); }
        .match-tile.sel { border-color: var(--violet); background: var(--violet-glow); transform: scale(0.97); box-shadow: 0 0 0 3px rgba(91, 80, 232, 0.12); }
        .match-tile.wrong { border-color: var(--rose); background: var(--rose-bg); animation: shake 0.4s ease; }
        .match-tile.correct { animation: matchCorrect 0.5s ease both; }
        @keyframes matchCorrect {
            0% { border-color: var(--emerald); background: var(--emerald-bg); transform: scale(1); }
            40% { border-color: var(--emerald); background: var(--emerald-bg); transform: scale(1.07); }
            100% { border-color: var(--emerald); background: var(--emerald-bg); transform: scale(1); opacity: 0; }
        }
        .match-tile.gone { opacity: 0; pointer-events: none; transform: scale(0.7); }
        @media (prefers-reduced-motion: reduce) {
            .match-tile { animation: none; }
            .match-tile.correct { animation: none; opacity: 0; }
        }
        .match-win { text-align: center; padding: 30px 16px; animation: popIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); }
        .match-win .mw-time { font-family: var(--font-display); font-weight: 800; font-size: 3rem; color: var(--violet); }
        .match-win .mw-stars { display: flex; justify-content: center; gap: 6px; margin: 4px 0 10px; }
        .match-win .mw-stars svg { width: 30px; height: 30px; animation: comboPop 0.4s cubic-bezier(.34,1.56,.64,1) both; }
        .match-win .mw-score { font-weight: 800; color: var(--violet); }

        /* ── shared deck picker + empty state for Match / Write ── */
        .study-deck-bar { display: flex; align-items: center; gap: 10px; margin: 2px 0 18px; }
        .study-deck-bar label { font-weight: 700; font-size: 0.85rem; color: var(--text-muted); white-space: nowrap; }
        .study-deck-bar .csel { flex: 1; min-width: 0; }   /* enhanced dropdown fills the row */
        .study-deck-select {
            flex: 1; min-width: 0; height: 44px; padding: 0 14px; border-radius: var(--r-sm, 12px);
            border: 1.5px solid rgba(91, 80, 232, 0.18); background: #fff; color: var(--text-primary);
            font-family: var(--font-ui); font-weight: 600; font-size: 0.92rem; cursor: var(--cur-point, pointer);
        }
        [data-dark] .study-deck-select { background: #232327; border-color: rgba(255,255,255,.12); color: #F5F5F7; }
        .study-empty {
            text-align: center; padding: 36px 18px; background: #fff; border-radius: var(--r, 16px);
            border: 1.5px dashed rgba(91, 80, 232, 0.25);
        }
        [data-dark] .study-empty { background: #1D1D21; border-color: rgba(255,255,255,.14); }
        .study-empty p { color: var(--text-muted); margin: 0 0 16px; }
        /* "start a new set" generator on Match / Write */
        /* Same reasoning as .fc-setup-card: the generator sits on the ground,
           separated by a rule rather than boxed in a panel. */
        .study-gen {
            background: transparent; border: 0;
            border-bottom: 1px solid var(--card-border, rgba(91, 80, 232, .12));
            border-radius: 0; padding: 4px 0 18px; margin-bottom: 18px;
            box-shadow: none;
        }
        .study-gen-title { font-weight: 700; font-size: 0.85rem; color: var(--text-muted); margin-bottom: 10px; }
        .study-gen-row { display: flex; flex-wrap: wrap; gap: 8px; }
        .study-gen-row .study-deck-select,
        .study-gen-row .study-gen-topic { flex: 1 1 140px; min-width: 0; margin: 0; }
        .study-gen-row .study-gen-topic {
            height: 44px; padding: 0 14px; border-radius: var(--r-sm, 12px);
            border: 1.5px solid rgba(91, 80, 232, 0.18); background: #fff; color: var(--text-primary);
            font-family: var(--font-ui); font-size: 0.92rem;
        }
        [data-dark] .study-gen-row .study-gen-topic { background: #18181B; border-color: rgba(255,255,255,.12); color: #F5F5F7; }
        .study-gen-row .study-gen-btn { flex: 0 0 auto; height: 44px; margin: 0; }
        .study-hint { color: var(--text-muted); font-size: 0.9rem; padding: 8px 2px 0; }

        /* ── Learn mode (adaptive) ── */
        .learn-counts { font-weight: 700; color: var(--text-muted); font-size: 0.9rem; font-variant-numeric: tabular-nums; }
        /* Learn options = same chunky 3D tiles as the main quiz (.option) */
        .learn-choices { display: grid; gap: 12px; margin-top: 6px; counter-reset: learnopt; }
        .learn-choice {
            display: flex; align-items: center; gap: 14px; text-align: left;
            padding: 16px 18px; border-radius: 15px;
            border: 2px solid #e7e6f7; background: #fff; color: var(--text-primary);
            font-family: var(--font-ui); font-weight: 600; font-size: 0.95rem; cursor: var(--cur-point, pointer);
            box-shadow: none; line-height: 1.35; counter-increment: learnopt;
            transition: transform 0.12s ease, border-color 0.15s, background 0.15s, box-shadow 0.12s;
        }
        .learn-choice::before {
            content: counter(learnopt, upper-alpha);
            flex: 0 0 auto; width: 28px; height: 28px; border-radius: 8px;
            background: #eeefff; border: 1px solid rgba(91, 80, 232, 0.15); color: var(--violet);
            font-weight: 800; font-size: 0.8rem; display: flex; align-items: center; justify-content: center;
            transition: all 0.18s;
        }
        [data-dark] .learn-choice { background: #1D1D21; border-color: rgba(255, 255, 255, 0.14); box-shadow: none; }
        [data-dark] .learn-choice::before { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.14); }
        .learn-choice:hover:not(:disabled) { border-color: rgba(91, 80, 232, 0.45); background: #f6f5ff; box-shadow: none; }
        .learn-choice:not(:disabled):active { transform: translateY(3px); box-shadow: 0 0 0 rgba(91, 80, 232, 0.28); }
        .learn-choice:disabled { cursor: default; }
        .learn-choice.correct { border-color: #059669; background: linear-gradient(135deg, #10b981 0%, #059669 100%); color: #fff; box-shadow: 0 6px 20px rgba(16, 185, 129, 0.32); }
        .learn-choice.wrong { border-color: #e11d48; background: linear-gradient(135deg, #f43f5e 0%, #e11d48 100%); color: #fff; box-shadow: 0 6px 20px rgba(225, 29, 72, 0.3); }
        .learn-choice.correct::before, .learn-choice.wrong::before { background: rgba(255, 255, 255, 0.22); border-color: rgba(255, 255, 255, 0.45); color: #fff; }

        /* Avi mascot in each study-tool heading */
        .tool-avi { display: inline-flex; align-items: center; }
        .tool-avi svg { display: block; }
        /* Settings → "Show Avi" off hides every mascot */
        body.avi-off .tool-avi,
        body.avi-off #quizBuddy { display: none !important; }

        /* ── Settings page rows ── */
        .set-row {
            display: flex; align-items: center; justify-content: space-between; gap: 14px;
            padding: 16px; background: #fff; border: 1.5px solid rgba(91, 80, 232, 0.12);
            border-radius: var(--r, 16px); margin-bottom: 12px;
        }
        [data-dark] .set-row { background: #1D1D21; border-color: rgba(255, 255, 255, 0.08); }
        .set-row-title { font-weight: 700; color: var(--text-primary); }
        .set-row-sub { font-size: 0.83rem; color: var(--text-muted); margin-top: 2px; }

        /* Appearance is the one settings row with a three-way control instead of
           a switch. It keeps the row's shape on a wide screen and drops under
           the label on a phone, where three options beside the text would
           squeeze both. */
        .set-row--stack .preset-switch { flex: 0 0 auto; min-width: 232px; }
        @media (max-width: 560px) {
            .set-row--stack { flex-wrap: wrap; }
            .set-row--stack .preset-switch { flex: 1 0 100%; min-width: 0; }
        }

        /* aviBob and aviDot keep their later definitions further down this
           sheet; the Test build's loader was the only user of the rules that
           sat here. */

        /* ── Write mode ── */
        .write-progress { font-weight: 700; color: var(--text-muted); font-size: 0.9rem; }
        .write-bar { height: 6px; background: #e8ecf5; border-radius: 99px; overflow: hidden; margin: 12px 0 18px; }
        [data-dark] .write-bar { background: #111113; }
        .write-bar-fill { height: 100%; background: linear-gradient(90deg, var(--violet), #818cf8); border-radius: 99px; transition: width 0.4s ease; }
        .write-card {
            background: #fff; border: 1px solid rgba(91, 80, 232, 0.1); border-radius: 18px; padding: 24px;
            box-shadow: var(--shadow-md);
        }
        [data-dark] .write-card { background: #1D1D21; }
        .write-prompt { font-size: 1.15rem; font-weight: 700; color: var(--text-primary); line-height: 1.4; margin-bottom: 16px; }
        .write-feedback { margin-top: 12px; font-size: 0.9rem; line-height: 1.5; display: none; }
        .write-feedback.ok { color: var(--emerald); display: block; }
        .write-feedback.no { color: var(--rose); display: block; }
        .write-feedback .wf-ans { color: var(--text-secondary); }
        .write-feedback .wf-override {
            display: inline-block; margin-top: 8px; background: var(--violet-glow); color: var(--violet);
            border: none; border-radius: 999px; padding: 5px 11px; font-family: inherit; font-weight: 700; font-size: 0.8rem; cursor: var(--cur-point, pointer);
        }
        .write-done { text-align: center; padding: 30px 16px; }
        .write-done .wd-score { font-family: var(--font-display); font-weight: 800; font-size: 3rem; color: var(--violet); }

        /* ── Cheat sheet ── */
        .cs-sheet {
            background: #fff; border: 1px solid rgba(91, 80, 232, 0.1); border-radius: 16px; padding: 22px;
            box-shadow: var(--shadow-md); animation: fadeIn 0.3s ease;
        }
        [data-dark] .cs-sheet { background: #1D1D21; }
        .cs-sheet h3 {
            font-family: var(--font-display); font-weight: 800; font-size: 1.05rem; color: var(--violet);
            margin: 16px 0 6px; letter-spacing: -0.01em;
        }
        .cs-sheet h3:first-child { margin-top: 0; }
        .cs-sheet ul { margin: 0 0 4px; padding-left: 18px; }
        .cs-sheet li { font-size: 0.9rem; line-height: 1.55; color: var(--text-secondary); margin-bottom: 4px; }
        .cs-sheet li b { color: var(--text-primary); font-weight: 700; }

        .fc-make-hint { font-size: 0.82rem; color: var(--text-muted); margin-top: 8px; }
        /* The tabs' geometry and the five deck-mode segments live in the
           FLASHCARDS block at the foot of this sheet, with the rest of the
           page. `.set-modes` / `.set-mode` are used on that page and nowhere
           else, so there is nothing left here to override. */
        .set-terms { margin-top: 24px; }
        .set-terms-head { font-family: var(--font-display); font-weight: 800; font-size: 1.05rem; color: var(--text-primary); margin-bottom: 12px; }
        .set-term-row {
            display: grid; grid-template-columns: 1fr 1.4fr; gap: 14px; align-items: start;
            padding: 14px 16px; background: #fff; border: 1.5px solid rgba(91, 80, 232, 0.1);
            border-radius: var(--r-sm, 12px); margin-bottom: 8px;
        }
        [data-dark] .set-term-row { background: #1D1D21; border-color: rgba(255, 255, 255, 0.07); }
        .set-term-front { font-weight: 700; color: var(--text-primary); }
        .set-term-back { color: var(--text-muted); border-left: 1.5px solid rgba(91, 80, 232, 0.14); padding-left: 14px; }
        @media (max-width: 540px) { .set-term-row { grid-template-columns: 1fr; gap: 6px; } .set-term-back { border-left: none; padding-left: 0; } }

        .fc-modes { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 4px 0 14px; }
        .fc-modes-label { font-size: 0.8rem; color: var(--text-muted); margin-right: 2px; }
        .fc-mode-btn {
            background: var(--violet-glow); border: 1px solid rgba(91, 80, 232, 0.18); color: var(--violet);
            border-radius: 999px; padding: 6px 16px; font-family: inherit; font-weight: 700; font-size: 0.82rem; cursor: var(--cur-point, pointer);
        }
        .fc-mode-btn:hover { background: rgba(91, 80, 232, 0.16); }

        /* ── Today strip: group the daily/spaced-repetition banners ── */
        #todayStrip {
            display: flex;
            flex-direction: column;
            gap: 8px;
            margin: 18px 0;
        }

        #todayStrip:empty,
        #todayStrip.is-empty { display: none; }

        /* strip's own gap handles spacing — drop each banner's outer margin and
           tighten the padding so several can stack without filling the screen */
        #todayStrip .daily-challenge-banner,
        #todayStrip .review-due-banner { margin: 0; }

        #todayStrip .daily-challenge-banner { padding: 13px 16px; }

        #todayStrip .review-due-banner { padding: 11px 14px; }

        #todayStrip .review-due-icon { width: 32px; height: 32px; }

        /* ── Phone: the day-planning strip is desktop furniture ──
           On a phone the first screen of /app should be the thing you came to
           do, not a stack of prompts about other things you could be doing.
           Daily goal, Daily Challenge and the two review banners are hidden at
           this width; the exam countdown stays, because it is a dated deadline
           rather than a review nudge (say the word and it goes too).

           Hidden, not deleted: the same nodes still drive the desktop layout
           and every function that populates them is untouched, so nothing about
           XP, streaks or spaced repetition changes — only what a phone shows.
           !important because the JS sets `display` inline on these. */
        @media (max-width: 560px) {
            #todayDaily,
            #upNext,
            #dailyChallengeBanner,
            #dailyReviewBanner,
            #fcDueBanner { display: none !important; }

            /* With those gone the strip is usually empty, and an empty flex
               column still carries its own margin — so move the spacing onto
               the one banner that can still appear. */
            #todayStrip { margin: 0; }
            #todayStrip #examCountdownBanner { margin: 18px 0; }
        }

        /* ── TABS ── */
        .tabs {
            display: flex;
            background: #f3f4f8;
            border: 1px solid rgba(91, 80, 232, 0.1);
            border-radius: 999px;
            padding: 3px;
            margin-bottom: 20px;
            position: relative;
        }

        .tab-slider {
            position: absolute;
            top: 3px;
            left: 3px;
            width: calc(33.33% - 2px);
            height: calc(100% - 6px);
            background: #ffffff;
            border: 1px solid rgba(91, 80, 232, 0.15);
            border-radius: 999px;
            transition: left 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            z-index: 0;
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
        }

        .tab-btn {
            flex: 1;
            padding: 10px;
            border: none;
            background: transparent;
            font-family: var(--font-ui);
            font-size: 0.875rem;
            font-weight: 500;
            cursor: var(--cur-point, pointer);
            position: relative;
            z-index: 1;
            transition: color 0.3s;
            border-radius: 999px;
        }

        .tab-btn.active {
            color: var(--text-primary);
        }

        .tab-btn:not(.active) {
            color: var(--text-muted);
        }

        /* ── Image upload panel ── */
        .upload-area {
            border: 2px dashed rgba(91, 80, 232, .22);
            border-radius: 16px;
            padding: 28px 20px;
            text-align: center;
            cursor: var(--cur-point, pointer);
            transition: all .2s;
            background: rgba(91, 80, 232, .02);
            position: relative;
        }

        .upload-area:hover,
        .upload-area.drag-over {
            border-color: var(--violet);
            background: rgba(91, 80, 232, .05);
        }

        .upload-area input[type="file"] {
            position: absolute;
            inset: 0;
            opacity: 0;
            cursor: var(--cur-point, pointer);
            width: 100%;
            height: 100%;
        }

        .upload-icon {
            width: 44px;
            height: 44px;
            background: rgba(91, 80, 232, .08);
            border: 1px solid rgba(91, 80, 232, .15);
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 0 auto 12px;
        }

        .upload-title {
            font-size: .9rem;
            font-weight: 700;
            color: var(--text-primary);
            margin-bottom: 4px;
        }

        .upload-sub {
            font-size: .75rem;
            color: var(--text-muted);
        }

        .upload-preview {
            display: none;
            margin-top: 14px;
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, .12);
            border-radius: 12px;
            overflow: hidden;
        }

        .upload-preview-img {
            width: 100%;
            max-height: 200px;
            object-fit: contain;
            display: block;
            background: #fff;
        }

        .upload-preview-bar {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 8px 12px;
            gap: 8px;
        }

        .upload-preview-name {
            font-size: .78rem;
            font-weight: 600;
            color: var(--text-secondary);
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .upload-clear {
            background: none;
            border: none;
            cursor: var(--cur-point, pointer);
            font-size: .75rem;
            font-weight: 700;
            color: var(--rose);
            white-space: nowrap;
            padding: 2px 6px;
        }

        .upload-clear:hover {
            text-decoration: underline;
        }

        /* ── FORM ELEMENTS ── */
        .field-label {
            display: block;
            font-size: 0.75rem;
            font-weight: 500;
            color: var(--text-muted);
            text-transform: uppercase;
            letter-spacing: 0.06em;
            margin-bottom: 8px;
        }

        .select-styled {
            width: 100%;
            padding: 11px 14px;
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, 0.12);
            border-radius: var(--r-sm);
            color: var(--text-primary);
            font-family: var(--font-ui);
            font-size: 0.9rem;
            appearance: none;
            -webkit-appearance: none;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' fill='none' stroke='%239ca3af' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
            background-repeat: no-repeat;
            background-position: right 12px center;
            cursor: var(--cur-point, pointer);
            transition: border-color 0.2s;
        }

        .select-styled:focus-visible {
            border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, 0.08);
        }

        .select-styled option {
            background: #ffffff;
            color: var(--text-primary);
        }

        /* ── Custom designed dropdowns (replace native select popups) ──
           The native <select> stays in the DOM (hidden) so all existing
           JS that reads .value / dispatches change keeps working; the
           .csel trigger + panel are the visible, designed UI. */
        .csel {
            position: relative;
        }

        .csel.open {
            z-index: 70;
        }

        .csel>select {
            display: none;
        }

        .csel-trigger {
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 8px;
            padding: 11px 14px;
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, 0.12);
            border-radius: var(--r-sm);
            color: var(--text-primary);
            font-family: var(--font-ui);
            font-size: 0.9rem;
            text-align: left;
            cursor: var(--cur-point, pointer);
            transition: border-color 0.2s, box-shadow 0.2s;
        }

        .csel-trigger .csel-value {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .csel-trigger.placeholder .csel-value {
            color: var(--text-muted);
        }

        /* the trigger is --surface-3, where --text-muted lands at 4.29:1 */
        [data-dark] .csel-trigger.placeholder .csel-value { color: var(--text-muted-raised); }

        .csel.open .csel-trigger,
        .csel-trigger:focus-visible {
            border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, 0.08);
        }

        .csel-chev {
            flex-shrink: 0;
            color: var(--text-muted);
            transition: transform .25s cubic-bezier(.34, 1.56, .64, 1), color .2s;
        }

        .csel.open .csel-chev {
            transform: rotate(180deg);
            color: var(--violet);
        }

        .csel-panel {
            position: absolute;
            top: calc(100% + 6px);
            left: 0;
            min-width: 100%;
            width: max-content;
            max-width: min(290px, 86vw);
            background: #ffffff;
            border: 1px solid rgba(91, 80, 232, .16);
            border-radius: 12px;
            padding: 6px;
            box-shadow: 0 14px 40px rgba(91, 80, 232, .18), 0 3px 10px rgba(0, 0, 0, .06);
            max-height: 264px;
            overflow-y: auto;
            overscroll-behavior: contain;
            opacity: 0;
            transform: translateY(-6px) scale(.98);
            pointer-events: none;
            transition: opacity .16s ease, transform .16s ease;
            z-index: 60;
        }

        .csel.open .csel-panel {
            opacity: 1;
            transform: none;
            pointer-events: auto;
        }

        .csel.up .csel-panel {
            top: auto;
            bottom: calc(100% + 6px);
        }

        /* Right-align the panel when it would spill past the viewport edge */
        .csel.flip-x .csel-panel {
            left: auto;
            right: 0;
        }

        .csel-group {
            font-size: .66rem;
            font-weight: 800;
            letter-spacing: .07em;
            text-transform: uppercase;
            color: var(--text-muted);
            padding: 9px 10px 4px;
        }

        .csel-opt {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 8px;
            width: 100%;
            padding: 8.5px 10px;
            border: 0;
            border-radius: 8px;
            background: transparent;
            font-family: var(--font-ui);
            font-size: .875rem;
            font-weight: 600;
            color: var(--text-secondary);
            text-align: left;
            cursor: var(--cur-point, pointer);
            transition: background .12s, color .12s;
        }

        .csel-opt:hover {
            background: rgba(91, 80, 232, .07);
            color: var(--text-primary);
        }

        .csel-opt .csel-check {
            opacity: 0;
            color: var(--violet);
            flex-shrink: 0;
        }

        .csel-opt.selected {
            color: var(--violet);
            background: rgba(91, 80, 232, .08);
            font-weight: 700;
        }

        .csel-opt.selected .csel-check {
            opacity: 1;
        }

        [data-dark] .csel-trigger {
            background: #232327;
            border-color: rgba(255, 255, 255, 0.14);
            color: var(--text-primary);
        }

        [data-dark] .csel-panel {
            background: #1D1D21;
            border-color: rgba(255, 255, 255, 0.14);
            box-shadow: 0 14px 40px rgba(0, 0, 0, .55), 0 3px 10px rgba(0, 0, 0, .3);
        }

        [data-dark] .csel-opt:hover {
            background: rgba(255, 255, 255, 0.08);
        }

        [data-dark] .csel-opt.selected {
            background: rgba(91, 80, 232, .18);
        }

        .input-text {
            width: 100%;
            padding: 11px 14px;
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, 0.12);
            border-radius: var(--r-sm);
            color: var(--text-primary);
            font-family: var(--font-ui);
            font-size: 0.9rem;
            transition: border-color 0.2s, box-shadow 0.2s;
        }

        .input-text::placeholder {
            color: var(--text-muted);
        }

        .input-text:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
            border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, 0.08);
        }

        .textarea-notes {
            width: 100%;
            height: 160px;
            padding: 12px 14px;
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, 0.12);
            border-radius: var(--r-sm);
            color: var(--text-primary);
            font-family: var(--font-ui);
            font-size: 0.9rem;
            resize: vertical;
            line-height: 1.6;
            transition: border-color 0.2s, box-shadow 0.2s;
        }

        .notes-keep {
            display: flex; align-items: flex-start; gap: 8px;
            margin-top: 10px; cursor: pointer;
            font-size: .82rem; color: var(--text-muted); line-height: 1.4;
        }
        .notes-keep input {
            margin-top: 2px; flex: none; accent-color: var(--violet);
        }

        .textarea-notes::placeholder {
            color: var(--text-muted);
        }

        .textarea-notes:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
            border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, 0.08);
        }

        .row-2 {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 16px;
            margin-top: 16px;
        }

        @media(max-width:500px) {
            .row-2 {
                grid-template-columns: 1fr;
            }
        }

        /* ── GENERATE BUTTON ── */
        .btn-generate {
            width: 100%;
            margin-top: 20px;
            padding: 16px;
            background: var(--grad-cta);
            border: none;
            border-radius: 999px;
            color: white;
            font-family: var(--font-display, 'Plus Jakarta Sans'), sans-serif;
            font-size: 1.08rem;
            font-weight: 800;
            cursor: var(--cur-point, pointer);
            letter-spacing: 0.01em;
            /* Duolingo-style 3D base: a solid darker edge under the button */
            box-shadow: 0 7px 16px rgba(91, 80, 232, 0.26);
            transition: transform 0.12s ease, box-shadow 0.12s ease, opacity 0.15s, filter 0.12s;
            position: relative;
            overflow: hidden;
            animation: fadeUp 0.7s 0.4s ease both;
            opacity: 0;
        }

        .btn-generate::before {
            content: '';
            position: absolute;
            top: 0;
            left: -100%;
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.06), transparent);
            transition: left 0.5s ease;
        }

        .btn-generate:hover {
            filter: brightness(1.06);
            transform: translateY(-1px);
            box-shadow: 0 10px 22px rgba(91, 80, 232, 0.32);
        }

        .btn-generate:hover::before {
            left: 100%;
        }

        /* press down onto the 3D base */
        .btn-generate:active {
            transform: translateY(4px);
            box-shadow: 0 0 0 var(--violet-shade), 0 2px 6px rgba(91, 80, 232, 0.3);
        }

        .btn-generate:disabled {
            /* !important because the entrance animation's fill sits above normal
               declarations in the cascade — without it the button reads as fully
               enabled while being unclickable, which is where a signed-out
               student now ends up after their free quizzes. */
            opacity: 0.55 !important;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }

        @media(max-width:600px) {
            .btn-generate {
                position: fixed;
                bottom: 20px;
                left: 16px;
                right: 16px;
                width: calc(100% - 32px);
                border-radius: 999px;
                padding: 17px;
                font-size: 1.05rem;
                margin-top: 0;
                z-index: 99;
            }

            /* A page may only dock ONE button. This rule matches every
               .btn-generate on the page, so a screen with two of them pinned
               both to bottom:20px/left:16px/right:16px and painted them on the
               same 358x56 rect. On /planner that stacked "Add" (a study goal)
               underneath "Open Exam Planner" pixel for pixel: elementsFromPoint
               returned the planner button first at 306 of 315 sampled points,
               so every tap opened the planner and the Add control could not be
               reached by touch at all.

               A button that lives inside a form row is an inline control, not
               the page's primary action, so it stays where it was written. */
            .row-2 .btn-generate,
            .row-4 .btn-generate,
            .study-gen .btn-generate {
                position: static;
                width: auto;
                margin-top: 0;
                padding: 12px 18px;
                font-size: .95rem;
                z-index: auto;
            }

            /* `.section-page > *` gives EVERY child position:relative;z-index:1,
               so each one opens its own stacking context at the same level and
               the later sibling wins outright — a docked button's z-index:99 is
               resolved INSIDE its parent and can never climb out. That is why
               the Check button on /write was painted under the "how it works"
               card at every scroll position but the last 18px of the page, and
               why /learn and /flashcards lost their CTA over most of the scroll
               range. Lift whichever child actually holds the docked button.
               (`.section-page > .path-controls { z-index: 20 }` above is the
               same fix, discovered once and applied to one page.) */
            .section-page > *:has(.btn-generate) { z-index: 30; }

            /* The quiz builder's own dock must stand down while a study tool
               is covering the app. `section-open` is already on <html> for
               exactly this state, but nothing told the docked CTA about it —
               so "Build my quiz" stayed pinned to the bottom of /write,
               /learn, /flashcards, /planner and /atar, on top of whichever
               button those pages dock themselves. Two pills land within 2px
               of each other, so roughly half of every tap on the tool's own
               action hit the builder's instead: the Check button on /write
               measured 0.489 exposed with the rest of the surface belonging
               to a button for a different screen. */
            html.section-open #generateBtn { display: none; }
        }

        /* Section pages start hidden (display:none), so the fadeUp entrance
           animation never plays — leave their buttons stuck at opacity:0. */
        .section-page .btn-generate {
            opacity: 1;
            animation: none;
        }

        /* ── LOADING ── */
        #loading {
            display: none;
            text-align: center;
            margin-top: 28px;
            animation: fadeIn 0.3s ease;
        }

        .spinner {
            width: 44px;
            height: 44px;
            border: 2px solid rgba(124, 106, 247, 0.15);
            border-top-color: var(--violet);
            border-radius: 50%;
            animation: spin 0.9s linear infinite;
            margin: 0 auto 14px;
        }

        .loading-text {
            font-size: 0.9rem;
            color: var(--text-secondary);
        }

        .loading-sub {
            font-size: 0.8rem;
            color: var(--text-muted);
            margin-top: 4px;
        }

        /* ── "Avi is thinking" loading state ── */
        .avi-think {
            position: relative;
            width: 78px;
            height: 70px;
            margin: 4px auto 22px;
        }

        .avi-think-face {
            width: 56px;
            height: 56px;
            margin: 14px auto 0;
            border-radius: 16px;
            overflow: hidden;
            position: relative;
            z-index: 2;
            box-shadow: 0 6px 18px rgba(91, 80, 232, 0.22);
            animation: aviThinkBob 2.6s ease-in-out infinite;
        }

        .avi-think-face svg {
            width: 100%;
            height: 100%;
            display: block;
        }

        /* soft glow that breathes behind Avi */
        .avi-think::after {
            content: '';
            position: absolute;
            left: 50%;
            top: 42px;
            width: 64px;
            height: 64px;
            transform: translate(-50%, -50%);
            background: radial-gradient(circle, rgba(124, 106, 247, 0.4) 0%, rgba(124, 106, 247, 0) 70%);
            z-index: 1;
            animation: aviThinkGlow 2.6s ease-in-out infinite;
        }

        /* thought-bubble dots, top-right */
        .avi-think-dots {
            position: absolute;
            top: -2px;
            right: 6px;
            display: flex;
            gap: 4px;
            z-index: 3;
        }

        .avi-think-dots span {
            width: 6px;
            height: 6px;
            border-radius: 50%;
            background: var(--violet);
            opacity: 0.35;
            animation: aviThinkDot 1.4s ease-in-out infinite;
        }

        .avi-think-dots span:nth-child(2) { animation-delay: 0.2s; }
        .avi-think-dots span:nth-child(3) { animation-delay: 0.4s; }

        @keyframes aviThinkBob {
            0%, 100% { transform: translateY(0) rotate(-3deg); }
            50%      { transform: translateY(-7px) rotate(3deg); }
        }

        @keyframes aviThinkGlow {
            0%, 100% { opacity: 0.45; transform: translate(-50%, -50%) scale(0.85); }
            50%      { opacity: 0.9;  transform: translate(-50%, -50%) scale(1.08); }
        }

        @keyframes aviThinkDot {
            0%, 100% { opacity: 0.3; transform: translateY(0); }
            40%      { opacity: 1;   transform: translateY(-4px); }
        }

        @media (prefers-reduced-motion: reduce) {
            .avi-think-face, .avi-think::after, .avi-think-dots span { animation: none; }
        }

        /* ── QUIZ SECTION ── */
        #quizSection {
            display: none;
            margin-top: 28px;
        }

        /* PROGRESS */
        .progress-wrap {
            background: rgba(255, 255, 255, 0.95);
            border: 1px solid rgba(91, 80, 232, 0.1);
            border-radius: 12px;
            padding: 14px 18px;
            margin-bottom: 20px;
            display: flex;
            align-items: center;
            gap: 14px;
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
            position: sticky;
            top: 68px;
            z-index: 50;
            backdrop-filter: blur(12px);
            -webkit-backdrop-filter: blur(12px);
        }

        .progress-bar-track {
            flex: 1;
            height: 4px;
            background: #e8ecf5;
            border-radius: 99px;
            overflow: hidden;
        }

        .progress-bar-fill {
            height: 100%;
            background: var(--violet);
            border-radius: 99px;
            transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
            box-shadow: 0 0 6px rgba(91, 80, 232, 0.25);
            position: relative;
            overflow: hidden;
        }

        /* a light sweep travels along the filled portion */
        .progress-bar-fill::after {
            content: '';
            position: absolute;
            inset: 0;
            background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.55), transparent);
            transform: translateX(-100%);
            animation: progressSheen 2.4s ease-in-out infinite;
        }

        @keyframes progressSheen {
            0%   { transform: translateX(-100%); }
            60%, 100% { transform: translateX(100%); }
        }

        @media (prefers-reduced-motion: reduce) {
            .progress-bar-fill::after { animation: none; }
        }

        .progress-label {
            font-size: 0.8rem;
            font-weight: 500;
            color: var(--text-muted);
            white-space: nowrap;
        }

        .streak-badge {
            display: none;
            align-items: center;
            gap: 5px;
            background: rgba(217, 119, 6, 0.08);
            border: 1px solid rgba(217, 119, 6, 0.2);
            border-radius: 99px;
            padding: 3px 10px;
            font-size: 0.75rem;
            font-weight: 600;
            color: var(--amber);
            white-space: nowrap;
        }

        /* QUESTION CARD */
        .question-card {
            background: #ffffff;
            border: 1px solid rgba(91, 80, 232, 0.1);
            border-radius: 20px;
            padding: 28px;
            box-shadow: var(--shadow-md);
            animation: slideUp 0.35s cubic-bezier(0.4, 0, 0.2, 1) both;
            margin-bottom: 16px;
        }

        /* replayed each time a question is navigated to (added in JS) */
        .question-card.q-enter {
            animation: qStep 0.34s cubic-bezier(0.34, 1.2, 0.64, 1) both;
        }

        @keyframes qStep {
            from { opacity: 0; transform: translateY(12px) scale(0.99); }
            to   { opacity: 1; transform: none; }
        }

        @media (prefers-reduced-motion: reduce) {
            .question-card.q-enter { animation: none; }
        }

        /* TIMER ROW */
        .timer-row {
            display: flex;
            align-items: center;
            gap: 14px;
            margin-bottom: 22px;
            padding-bottom: 18px;
            border-bottom: 1px solid rgba(91, 80, 232, 0.08);
        }

        .timer-fill {
            fill: none;
            stroke: var(--violet);
            stroke-width: 4;
            stroke-linecap: round;
            stroke-dasharray: 132;
            stroke-dashoffset: 0;
            transition: stroke-dashoffset 1s linear, stroke 0.4s;
            filter: drop-shadow(0 0 3px rgba(91, 80, 232, 0.3));
        }

        .timer-fill.warning {
            stroke: var(--rose);
            filter: drop-shadow(0 0 3px rgba(225, 29, 72, 0.4));
            animation: pulsStroke 0.7s infinite alternate;
        }

        @keyframes pulsStroke {
            from {
                filter: drop-shadow(0 0 2px rgba(225, 29, 72, 0.3))
            }

            to {
                filter: drop-shadow(0 0 6px rgba(225, 29, 72, 0.6))
            }
        }

        .score-chip {
            background: rgba(91, 80, 232, 0.07);
            border: 1px solid rgba(91, 80, 232, 0.15);
            border-radius: 999px;
            padding: 5px 13px;
            font-size: 0.8rem;
            font-weight: 600;
            color: var(--text-muted);
            white-space: nowrap;
            flex-shrink: 0;
        }

        .score-chip strong {
            color: var(--violet);
        }

        /* QUESTION TEXT */
        .question-num {
            font-size: 0.72rem;
            font-weight: 600;
            color: var(--violet);
            text-transform: uppercase;
            letter-spacing: 0.1em;
            margin-bottom: 10px;
        }

        .question-text {
            font-family: var(--font-ui);
            font-size: 1.15rem;
            line-height: 1.55;
            color: var(--text-primary);
            margin-bottom: 22px;
            font-style: italic;
        }

        /* OPTIONS */
        .options-list {
            display: flex;
            flex-direction: column;
            gap: 9px;
        }

        .option {
            display: flex;
            align-items: center;
            gap: 14px;
            padding: 17px 18px;
            background: #ffffff;
            border: 2px solid #e7e6f7;
            border-radius: 15px;
            cursor: var(--cur-point, pointer);
            /* Duolingo-style chunky base under each option */
            box-shadow: none;
            transition: transform 0.12s ease, border-color 0.15s, background 0.15s, box-shadow 0.12s;
            position: relative;
            overflow: hidden;
        }

        .option::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(91, 80, 232, 0.03);
            opacity: 0;
            transition: opacity 0.18s;
        }

        .option:hover {
            border-color: rgba(91, 80, 232, 0.45);
            background: #f6f5ff;
            box-shadow: none;
        }

        .option:hover::before {
            opacity: 1;
        }

        .opt-letter {
            width: 28px;
            height: 28px;
            border-radius: 8px;
            background: #eeefff;
            border: 1px solid rgba(91, 80, 232, 0.15);
            color: var(--violet);
            font-family: var(--font-ui);
            font-size: 0.8rem;
            font-weight: 800;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
            transition: all 0.18s;
        }

        .option:hover .opt-letter {
            background: rgba(91, 80, 232, 0.12);
            border-color: rgba(91, 80, 232, 0.3);
            color: var(--violet);
        }

        /* tactile press: depress onto the 3D base before the answer locks in */
        .option:not(.disabled):not(.correct):not(.wrong):active {
            transform: translateY(3px);
            background: #efeeff;
            box-shadow: 0 0 0 rgba(91, 80, 232, 0.28);
        }

        .option:hover .opt-letter {
            transform: scale(1.06);
        }

        .opt-text {
            font-size: 0.95rem;
            color: var(--text-primary);
            line-height: 1.4;
            font-weight: 600;
        }

        .option.correct {
            border-color: #059669;
            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
            box-shadow: 0 6px 20px rgba(16, 185, 129, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.18);
            transform: none;
            cursor: default;
            animation: popIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
        }

        .option.correct .opt-letter {
            background: rgba(255, 255, 255, 0.22);
            border-color: rgba(255, 255, 255, 0.45);
            color: #ffffff;
            font-weight: 800;
        }

        .option.correct .opt-text {
            color: #ffffff;
            font-weight: 700;
            text-shadow: 0 1px 2px rgba(4, 90, 60, 0.25);
        }

        .option.wrong {
            border-color: #e11d48;
            background: linear-gradient(135deg, #f43f5e 0%, #e11d48 100%);
            box-shadow: 0 6px 20px rgba(225, 29, 72, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.18);
            transform: none;
            cursor: default;
            animation: shake 0.4s ease;
        }

        .option.wrong .opt-letter {
            background: rgba(255, 255, 255, 0.22);
            border-color: rgba(255, 255, 255, 0.45);
            color: #ffffff;
            font-weight: 800;
        }

        .option.wrong .opt-text {
            color: #ffffff;
            font-weight: 700;
            text-shadow: 0 1px 2px rgba(136, 19, 55, 0.3);
        }

        .option.timeout-correct {
            border-color: #059669;
            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
            box-shadow: 0 6px 20px rgba(16, 185, 129, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.18);
            cursor: default;
        }

        .option.timeout-correct .opt-letter {
            background: rgba(255, 255, 255, 0.22);
            border-color: rgba(255, 255, 255, 0.45);
            color: #ffffff;
            font-weight: 800;
        }

        .option.timeout-correct .opt-text {
            color: #ffffff;
            font-weight: 700;
        }

        .option.disabled {
            cursor: default;
        }

        .option.disabled:hover {
            border-color: rgba(91, 80, 232, 0.1);
            transform: none;
            background: #f8f9ff;
        }

        .option.disabled:hover::before {
            opacity: 0;
        }

        .option.dimmed {
            opacity: 0.35;
        }

        .option.dimmed:hover {
            opacity: 0.35;
        }

        .explanation-box {
            margin-top: 16px;
            padding: 14px 16px;
            border-radius: 12px;
            font-size: 0.875rem;
            line-height: 1.65;
            animation: fadeIn 0.35s ease;
            border-left: 3px solid;
        }

        .explanation-box.correct-exp {
            background: rgba(5, 150, 105, 0.06);
            border-color: var(--emerald);
            color: #065f46;
        }

        .explanation-box.wrong-exp {
            background: rgba(217, 119, 6, 0.06);
            border-color: var(--amber);
            color: #92400e;
        }

        .explanation-box.timeout-exp {
            background: rgba(225, 29, 72, 0.05);
            border-color: var(--rose);
            color: #9f1239;
        }

        .explanation-box strong {
            font-weight: 600;
        }

        .explain-differently-btn {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            margin-top: 12px;
            padding: 8px 16px;
            background: rgba(91, 80, 232, .1);
            border: none;
            border-radius: 999px;
            color: var(--violet);
            font-family: var(--font-ui);
            font-size: .8rem;
            font-weight: 700;
            cursor: var(--cur-point, pointer);
            transition: all .18s;
        }

        .explain-differently-btn:hover:not(:disabled) {
            background: rgba(91, 80, 232, .18);
            transform: translateY(-1px);
        }

        .explain-differently-btn:disabled {
            opacity: .65;
            cursor: default;
            transform: none;
        }

        .explain-alt-box {
            margin-top: 12px;
            padding: 13px 15px;
            border-radius: 12px;
            background: rgba(91, 80, 232, .07);
            border-left: 3px solid var(--violet);
            font-size: .875rem;
            line-height: 1.65;
            color: var(--text-primary);
            animation: fadeIn .35s ease;
        }

        .explain-alt-box .explain-alt-label {
            display: flex;
            align-items: center;
            font-size: .68rem;
            font-weight: 700;
            color: var(--violet);
            text-transform: uppercase;
            letter-spacing: .06em;
            margin-bottom: 6px;
        }

        /* Avi flies in beside his explanation */
        .explain-alt-box.avi-asking {
            display: flex;
            gap: 12px;
            align-items: flex-start;
        }

        .avi-fig {
            width: 60px;
            height: 101px;
            flex-shrink: 0;
            margin: -6px 4px 0 -2px;
            transform-origin: 50% 70%;
            animation: aviBob 2.8s ease-in-out infinite;
        }

        .avi-fig.avi-peek {
            animation: aviFlyIn .9s cubic-bezier(.34, 1.7, .5, 1), aviBob 2.8s ease-in-out .9s infinite;
        }

        @keyframes aviFlyIn {
            0% { transform: translate(-60px, 46px) scale(.25) rotate(-22deg); opacity: 0; }
            45% { transform: translate(8px, -10px) scale(1.18) rotate(8deg); opacity: 1; }
            70% { transform: translate(-3px, 3px) scale(.96) rotate(-3deg); }
            100% { transform: translate(0, 0) scale(1) rotate(0); opacity: 1; }
        }

        @keyframes aviBob {
            0%, 100% { transform: translateY(0) rotate(0); }
            50% { transform: translateY(-4px) rotate(-1.5deg); }
        }

        .avi-fig .avi-orb { animation: aviOrb 1.4s ease-in-out infinite; }

        @keyframes aviOrb {
            0%, 100% { opacity: 1; }
            50% { opacity: .4; }
        }

        .avi-fig .avi-thrust { animation: aviThrust .25s ease-in-out infinite alternate; transform-origin: 256px 236px; }

        @keyframes aviThrust {
            from { transform: scaleX(.7); opacity: .3; }
            to { transform: scaleX(1.05); opacity: .6; }
        }

        .avi-speech { flex: 1; min-width: 0; }

        .avi-said { animation: aviSaid .4s ease both; }

        @keyframes aviSaid {
            from { opacity: 0; transform: translateY(4px); }
            to { opacity: 1; transform: translateY(0); }
        }

        /* "thinking" dots while Avi works it out */
        .avi-think {
            display: flex;
            gap: 5px;
            padding: 4px 0 2px;
        }

        .avi-think span {
            width: 7px;
            height: 7px;
            border-radius: 50%;
            background: var(--violet);
            opacity: .35;
            animation: aviDot 1.1s ease-in-out infinite;
        }

        .avi-think span:nth-child(2) { animation-delay: .18s; }
        .avi-think span:nth-child(3) { animation-delay: .36s; }

        @keyframes aviDot {
            0%, 100% { opacity: .3; transform: translateY(0); }
            40% { opacity: 1; transform: translateY(-4px); }
        }

        @media (prefers-reduced-motion: reduce) {
            .avi-fig, .avi-fig.avi-peek, .avi-orb, .avi-thrust, .avi-said { animation: none !important; }
        }

        .nav-btns {
            display: flex;
            gap: 10px;
            margin-top: 20px;
        }

        .btn-prev,
        .btn-next {
            flex: 1;
            padding: 12px 16px;
            border-radius: 999px;
            font-family: var(--font-ui);
            font-size: 0.9rem;
            font-weight: 600;
            cursor: var(--cur-point, pointer);
            transition: all 0.18s;
            border: none;
        }

        .btn-prev {
            background: #f3f4f8;
            border: 1px solid rgba(91, 80, 232, 0.1);
            color: var(--text-secondary);
        }

        .btn-prev:hover {
            background: #e8ecf5;
            color: var(--text-primary);
        }

        .btn-next {
            background: linear-gradient(135deg, var(--violet), var(--violet-dim));
            color: white;
            box-shadow: 0 4px 16px rgba(91, 80, 232, 0.25);
        }

        .btn-next:hover {
            transform: translateY(-1px);
            box-shadow: 0 6px 20px rgba(91, 80, 232, 0.35);
        }

        /* SCORE CARD */
        #scoreCard {
            display: none;
            background: #ffffff;
            border: 1px solid rgba(91, 80, 232, 0.1);
            border-radius: 20px;
            padding: 40px 32px;
            text-align: center;
            box-shadow: 0 4px 24px rgba(91, 80, 232, 0.06);
            animation: slideUp 0.4s ease;
        }

        /* ── Lesson-end recap chips (Duolingo-style) ── */
        .score-recap { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin: 4px 0 18px; }
        .recap-chip { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-radius: 999px; background: rgba(91, 80, 232, 0.07); border: 1.5px solid rgba(91, 80, 232, 0.16); }
        [data-dark] .recap-chip { background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.08); }
        .recap-chip.gold { background: rgba(245, 158, 11, .12); border-color: rgba(245, 158, 11, .4); }
        .recap-chip-ico { width: 26px; height: 26px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; color: var(--violet); }
        .recap-chip.gold .recap-chip-ico { color: #f59e0b; }
        .recap-chip-val { font-family: var(--font-display); font-weight: 800; font-size: 1.05rem; color: var(--text-primary); line-height: 1; }
        .recap-chip-lbl { font-size: .72rem; color: var(--text-muted); font-weight: 700; margin-top: 2px; }

        /* ── Learning Path (syllabus skill tree) ── */
        .path-controls { display: flex; gap: 10px; margin-bottom: 14px; }
        /* Sit above the sibling progress bar/label/nodes (all .section-page > *
           with z-index:1) so an open subject dropdown isn't painted under them. */
        .section-page > .path-controls { z-index: 20; }
        .path-controls .select-styled { flex: 1; min-width: 0; }
        .path-progress { height: 8px; background: rgba(91, 80, 232, 0.12); border-radius: 99px; overflow: hidden; }
        [data-dark] .path-progress { background: rgba(255, 255, 255, 0.08); }
        .path-progress-fill { height: 100%; background: linear-gradient(90deg, var(--violet), #8b5cf6); border-radius: 99px; transition: width .5s ease; width: 0; }
        .path-progress-label { font-size: .8rem; color: var(--text-muted); font-weight: 700; margin: 6px 2px 16px; }
        /* The winding lesson path keeps completion and current-node states visible. */
        .path-nodes { position: relative; display: flex; flex-direction: column; align-items: center; gap: 30px; padding: 30px 0 30px; }
        /* dotted connecting spine running down behind the nodes */
        .path-nodes::before {
            content: ''; position: absolute; top: 56px; bottom: 70px; left: 50%; width: 0;
            border-left: 5px dotted rgba(91, 80, 232, .22); transform: translateX(-50%); z-index: 0;
        }
        [data-dark] .path-nodes::before { border-left-color: rgba(255, 255, 255, .14); }
        .path-node { display: flex; flex-direction: column; align-items: center; gap: 9px; position: relative; z-index: 1; }
        .path-circle {
            width: 76px; height: 76px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
            color: #fff; transition: transform .12s, box-shadow .12s; border: none; padding: 0;
        }
        .path-circle svg { width: 34px; height: 34px; }
        .path-node.done .path-circle { background: #f5b021; box-shadow: 0 4px 10px rgba(121, 86, 18, .16); cursor: var(--cur-point, pointer); }
        .path-node.current .path-circle { background: var(--violet); box-shadow: 0 4px 12px rgba(91, 80, 232, .22); cursor: var(--cur-point, pointer); }
        .path-node.locked .path-circle { background: #d7dbf0; box-shadow: none; color: #fff; }
        [data-dark] .path-node.locked .path-circle { background: #34343A; box-shadow: none; color: #85858F; }
        .path-node.done .path-circle:hover { transform: translateY(-2px); box-shadow: 0 6px 14px rgba(121, 86, 18, .18); }
        .path-node.current .path-circle:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(91, 80, 232, .26); }
        .path-node.done .path-circle:active, .path-node.current .path-circle:active { transform: translateY(5px); box-shadow: none; }
        .path-circle:focus-visible { outline: 3px solid var(--violet); outline-offset: 4px; border-radius: 50%; }
        [data-dark] .path-circle:focus-visible { outline-color: #8b7cf8; }
        @media (hover: none) { .path-node.done .path-circle:hover, .path-node.current .path-circle:hover { transform: none; } }
        .path-label { font-size: .8rem; color: var(--text-muted); font-weight: 700; text-align: center; max-width: 220px; line-height: 1.3; }
        @media (max-width: 560px) { .path-label { max-width: 150px; font-size: .72rem; } .path-circle { width: 66px; height: 66px; } }
        /* The single Avi guide + scattered decoration along the path */
        .path-avi { position: absolute; top: -8px; width: 84px; height: auto; animation: aviBob 3.2s ease-in-out infinite; z-index: 2; }
        .path-avi.left { right: calc(100% + 14px); }
        .path-avi.right { left: calc(100% + 14px); }
        .path-avi svg { width: 100%; height: auto; filter: drop-shadow(0 6px 8px rgba(20, 20, 60, .22)); }
        .pd-bubble { position: absolute; top: -14px; left: 50%; transform: translateX(-50%); white-space: nowrap; background: #fff; color: var(--violet); font-weight: 800; font-size: .62rem; padding: 3px 9px; border-radius: 9px; box-shadow: 0 3px 7px rgba(20,20,60,.16); }
        .pd-bubble::after { content: ''; position: absolute; bottom: -4px; left: 50%; transform: translateX(-50%) rotate(45deg); width: 8px; height: 8px; background: inherit; }
        [data-dark] .pd-bubble { background: #232327; }
        .path-spark { position: absolute; opacity: .7; animation: aviBob 4s ease-in-out infinite; }
        .path-spark svg { display: block; }
        @media (max-width: 560px) { .path-avi, .path-spark { display: none; } }
        .path-goal { margin-top: 10px; }
        .path-trophy { width: 88px; height: 88px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: linear-gradient(160deg, #eef1fb, #d9ddf2); box-shadow: 0 12px 16px rgba(0,0,0,.14); color: #b9bcd6; }
        [data-dark] .path-trophy { background: linear-gradient(160deg, #34343A, #232327); box-shadow: none; color: #4A4A52; }
        .path-trophy svg { width: 46px; height: 46px; }
        .path-goal.reached .path-trophy { background: linear-gradient(160deg, #ffe79a, #f5b021); box-shadow: 0 12px 18px rgba(245,176,33,.4); color: #fff; }
        .path-node.current .path-label { color: var(--violet); }
        /* Coverage marks. Three states, no red: nothing on this page is wrong,
           it is only untested. The tick and ring take their colour from the
           study-tool tokens so dark mode needs no second rule; the flame is
           the app's own amber SVG and carries its colour with it. */
        .path-cov { display: inline-flex; vertical-align: -2px; margin-right: 5px; }
        .path-cov svg { width: 13px; height: 13px; }
        .cov-untested { color: var(--study-muted, var(--text-muted)); opacity: .75; }
        .cov-solid { color: var(--study-accent, var(--violet)); }
        .path-cov-line { display: flex; flex-wrap: wrap; align-items: center; font-size: .78rem; font-weight: 700; color: var(--study-muted, var(--text-muted)); margin: -10px 2px 16px; }
        .path-cov-line .pcl-item { display: inline-flex; align-items: center; gap: 4px; }
        .path-cov-line .pcl-item::before { content: '\00b7'; margin: 0 8px; opacity: .55; }
        .path-cov-line .pcl-item svg { width: 12px; height: 12px; }
        .path-start {
            position: absolute; top: -36px; left: 50%; transform: translateX(-50%); white-space: nowrap;
            background: var(--violet); color: #fff; font-family: var(--font-display); font-weight: 800; font-size: .72rem;
            letter-spacing: .05em; padding: 6px 13px; border-radius: 11px; box-shadow: 0 4px 10px rgba(91,80,232,.34);
            animation: startBounce 1.4s ease-in-out infinite;
        }
        .path-start::after { content: ''; position: absolute; bottom: -4px; left: 50%; transform: translateX(-50%) rotate(45deg); width: 10px; height: 10px; background: inherit; }
        @keyframes startBounce { 0%, 100% { transform: translateX(-50%) translateY(0); } 50% { transform: translateX(-50%) translateY(-5px); } }

        /* ── Streak nudge / freeze ── */
        .streak-nudge { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 12px;
            background: rgba(245, 158, 11, 0.1); border: 1px solid rgba(245, 158, 11, 0.32); }
        .streak-nudge .sn-flame { width: 34px; height: 34px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
        .streak-nudge .sn-text { flex: 1; min-width: 0; }
        .streak-nudge .sn-title { font-weight: 800; font-size: .9rem; color: var(--text-primary); }
        .streak-nudge .sn-sub { font-size: .8rem; color: var(--text-muted); }
        .streak-freeze-pill { display: inline-flex; align-items: center; gap: 5px; font-size: .76rem; font-weight: 800; color: #0ea5e9; background: rgba(14,165,233,.12); padding: 3px 9px; border-radius: 999px; }

        /* ── Leagues (tiered weekly leaderboard) ── */
        .lb-league { display: flex; align-items: center; gap: 14px; padding: 16px 18px; border-radius: var(--r, 16px); margin-bottom: 16px; color: #fff; position: relative; overflow: hidden; box-shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 8px 22px rgba(20,20,60,.18); }
        .lb-league::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(120deg, rgba(255,255,255,.22) 0%, rgba(255,255,255,0) 38%); }
        .lb-league-medal { flex-shrink: 0; width: 60px; height: 60px; display: flex; align-items: center; justify-content: center; filter: drop-shadow(0 3px 5px rgba(0,0,0,.3)); }
        .lb-league-name { font-family: var(--font-display); font-weight: 800; font-size: 1.25rem; }
        .lb-league-sub { font-size: .85rem; opacity: .9; margin-top: 2px; }
        .lb-league-tiers { display: flex; gap: 5px; margin-top: 8px; }
        .lb-league-tiers span { width: 22px; height: 5px; border-radius: 99px; background: rgba(255,255,255,.3); }
        .lb-league-tiers span.on { background: #fff; }
        .lb-row.promote-zone { box-shadow: inset 3px 0 0 var(--emerald); }
        .lb-row.relegate-zone { box-shadow: inset 3px 0 0 var(--rose); }
        .lb-zone-divider { display: flex; align-items: center; gap: 8px; margin: 8px 2px; font-size: .72rem; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); }
        .lb-zone-divider::before, .lb-zone-divider::after { content: ''; flex: 1; height: 1px; background: rgba(91,80,232,.14); }
        .lb-zone-divider.promote { color: var(--emerald); }
        .lb-zone-divider.relegate { color: var(--rose); }
        /* friendly empty state — soft violet trophy badge above the message */
        .lb-empty { text-align: center; padding: 30px 16px; color: var(--text-muted); }
        .lb-empty-ico { width: 56px; height: 56px; margin: 0 auto 14px; border-radius: var(--r, 16px); display: flex; align-items: center; justify-content: center; background: var(--violet-glow); color: var(--violet); }
        .lb-empty p { margin: 0; }

        /* ── Daily Quests + goal (Duolingo-style) ── */
        .daily-card { background: #fff; border: 1.5px solid rgba(91, 80, 232, 0.14); border-radius: var(--r, 16px); padding: 18px 18px 14px; margin-bottom: 18px; }
        [data-dark] .daily-card { background: #1D1D21; border-color: rgba(255, 255, 255, 0.08); }
        .daily-top { display: flex; align-items: center; gap: 16px; }
        .daily-ring { flex-shrink: 0; }
        .daily-ring-track { stroke: rgba(91, 80, 232, 0.22); }
        .daily-ring-fill { stroke: var(--violet); transition: stroke-dashoffset .6s cubic-bezier(.2,.8,.2,1); }
        .daily-ring-done .daily-ring-fill { stroke: var(--emerald); }
        .daily-ring-label { font-family: var(--font-display); font-weight: 800; fill: var(--text-primary); }
        .daily-top-text { flex: 1; min-width: 0; }
        .daily-title { font-family: var(--font-display); font-weight: 800; font-size: 1.05rem; color: var(--text-primary); }
        .daily-sub { font-size: .85rem; color: var(--text-muted); margin-top: 2px; }
        .daily-quests { display: grid; gap: 8px; margin-top: 14px; }
        .quest { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: var(--r-sm, 12px); background: rgba(91, 80, 232, 0.05); border: 1px solid rgba(91, 80, 232, 0.1); }
        [data-dark] .quest { background: rgba(255, 255, 255, 0.03); border-color: rgba(255, 255, 255, 0.06); }
        .quest.done { background: var(--emerald-bg); border-color: var(--emerald); }
        .quest-ico { width: 30px; height: 30px; flex-shrink: 0; border-radius: 9px; display: flex; align-items: center; justify-content: center; background: var(--violet-glow); color: var(--violet); }
        .quest.done .quest-ico { background: var(--emerald); color: #fff; }
        .quest-body { flex: 1; min-width: 0; }
        .quest-label { font-weight: 700; font-size: .88rem; color: var(--text-primary); }
        .quest-bar { height: 6px; background: rgba(91, 80, 232, 0.12); border-radius: 99px; overflow: hidden; margin-top: 5px; }
        [data-dark] .quest-bar { background: rgba(255, 255, 255, 0.08); }
        .quest-bar-fill { height: 100%; background: var(--violet); border-radius: 99px; transition: width .5s ease; }
        .quest.done .quest-bar-fill { background: var(--emerald); }
        .quest-xp { flex-shrink: 0; font-weight: 800; font-size: .78rem; color: var(--violet); }
        .quest.done .quest-xp { color: var(--emerald); }
        .daily-review-row {
            display: flex; align-items: center; gap: 10px; width: 100%; min-height: 46px;
            margin-top: 12px; padding: 12px 2px 2px; border: 0; border-top: 1px solid rgba(91, 80, 232, 0.12);
            background: none; font-family: var(--font-ui); text-align: left; cursor: var(--cur-point, pointer);
        }
        [data-dark] .daily-review-row { border-top-color: rgba(255, 255, 255, 0.08); }
        .daily-review-row .daily-review-label {
            font-size: .62rem; font-weight: 800; letter-spacing: .13em; text-transform: uppercase;
            color: var(--text-muted);
        }
        .daily-review-row .daily-review-figure {
            flex: 1; min-width: 0; font-size: .9rem; font-weight: 800; color: var(--text-primary);
        }
        .daily-review-row .daily-review-arrow { color: var(--violet); transition: transform .16s ease; }
        @media (hover: hover) {
            .daily-review-row:hover .daily-review-figure { color: var(--violet); }
            .daily-review-row:hover .daily-review-arrow { transform: translateX(3px); }
        }
        @media (prefers-reduced-motion: reduce) {
            .daily-review-row:hover .daily-review-arrow { transform: none; }
            .daily-review-row .daily-review-arrow { transition: none; }
        }
        .daily-review-row:focus-visible { outline: 3px solid var(--violet); outline-offset: 2px; border-radius: 10px; }
        [data-dark] .daily-review-row:focus-visible { outline-color: #9d94ff; }
        /* Compact today-strip daily card */
        .today-daily { display: flex; align-items: center; gap: 12px; cursor: var(--cur-point, pointer); padding: 12px 14px; background: rgba(91, 80, 232, 0.06); border: 1px solid rgba(91, 80, 232, 0.18); border-radius: 12px; transition: transform .15s, border-color .15s; }
        .today-daily:hover { transform: translateY(-1px); border-color: var(--violet); }
        .today-daily:focus-visible { outline: 3px solid var(--violet); outline-offset: 2px; border-radius: 12px; }
        [data-dark] .today-daily:focus-visible { outline-color: #9d94ff; }
        @media (hover: none) { .today-daily:hover { transform: none; } }
        .today-daily .td-text { flex: 1; min-width: 0; }
        .today-daily .td-title { font-weight: 600; font-size: .9rem; color: var(--text-primary); }
        .today-daily .td-sub { font-size: .8rem; color: var(--text-muted); }
        .today-daily .review-due-arrow { margin-left: auto; color: var(--violet); }

        /* Floating "+N points" reward on a correct answer (shows hidden bonuses) */
        .points-float {
            position: fixed; z-index: 1200; pointer-events: none; transform: translate(-50%, -50%);
            display: flex; flex-direction: column; align-items: center; gap: 3px;
            animation: pointsFloat 1.05s cubic-bezier(.2, .8, .2, 1) forwards;
        }
        .points-float .pf-main {
            font-family: var(--font-display); font-weight: 800; font-size: 1.6rem; color: var(--emerald);
            text-shadow: 0 2px 10px rgba(5, 150, 105, .35);
        }
        .points-float .pf-tag {
            font-size: .68rem; font-weight: 800; letter-spacing: .02em; color: var(--violet);
            background: var(--violet-glow); padding: 2px 8px; border-radius: 99px; white-space: nowrap;
        }
        @keyframes pointsFloat {
            0%   { opacity: 0; transform: translate(-50%, -25%) scale(.8); }
            18%  { opacity: 1; transform: translate(-50%, -55%) scale(1.06); }
            70%  { opacity: 1; }
            100% { opacity: 0; transform: translate(-50%, -165%) scale(1); }
        }

        /* ── Combo meter ── */
        .combo-badge {
            position: fixed;
            top: 66px;
            left: 50%;
            transform: translateX(-50%) translateY(-10px) scale(.9);
            display: flex;
            align-items: center;
            gap: 6px;
            padding: 7px 15px;
            background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%);
            color: #fff;
            font-family: var(--font-display);
            font-weight: 800;
            font-size: .92rem;
            letter-spacing: -.01em;
            border-radius: 999px;
            box-shadow: 0 6px 22px rgba(239, 68, 68, .42), inset 0 1px 0 rgba(255, 255, 255, .25);
            opacity: 0;
            pointer-events: none;
            z-index: 1150;
            transition: opacity .26s ease, transform .26s cubic-bezier(.2, .8, .2, 1);
        }
        .combo-badge.show { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
        .combo-badge.milestone {
            background: linear-gradient(135deg, #fbbf24 0%, #f43f5e 55%, #a855f7 100%);
            box-shadow: 0 10px 30px rgba(168, 85, 247, .5), inset 0 1px 0 rgba(255, 255, 255, .3);
        }
        .combo-badge.pop { animation: comboPop .5s ease; }
        @keyframes comboPop {
            0%   { transform: translateX(-50%) scale(1); }
            42%  { transform: translateX(-50%) scale(1.16); }
            100% { transform: translateX(-50%) scale(1); }
        }

        @media (prefers-reduced-motion: reduce) {
            .combo-badge.pop { animation: none; }
            .combo-badge { transition: opacity .26s ease; }
        }

        .score-stats {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 10px;
            margin-bottom: 28px;
        }

        .score-stat {
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, 0.08);
            border-radius: 12px;
            padding: 14px 8px;
        }

        .score-stat-val {
            font-family: var(--font-display);
            font-weight: 800;
            font-size: 1.6rem;
            color: var(--violet);
            line-height: 1;
            letter-spacing: -0.01em;
            margin-bottom: 4px;
        }

        .score-stat-label {
            font-size: 0.7rem;
            color: var(--text-muted);
            text-transform: uppercase;
            letter-spacing: 0.06em;
        }

        /* ── SCORE HISTORY SPARKLINE ── */
        #scoreHistoryWrap {
            display: none;
            margin: 10px 0 6px;
            padding: 12px 14px 10px;
            background: rgba(91,80,232,.05);
            border: 1.5px solid rgba(91,80,232,.14);
            border-radius: 16px;
        }
        .sh-label {
            font-size: 0.68rem;
            text-transform: uppercase;
            letter-spacing: .07em;
            color: var(--text-muted);
            margin-bottom: 8px;
            font-family: var(--font-ui);
        }
        .sh-bars {
            display: flex;
            align-items: flex-end;
            gap: 5px;
            height: 44px;
        }
        .sh-bar {
            flex: 1;
            border-radius: 4px 4px 0 0;
            min-height: 4px;
            cursor: default;
            transition: opacity .15s;
        }
        .sh-bar.sh-current {
            outline: 2px solid var(--violet);
            outline-offset: 2px;
        }
        [data-dark] #scoreHistoryWrap {
            background: rgba(255, 255, 255, 0.055);
            border-color: rgba(255, 255, 255, 0.14);
        }

        /* SUBJECT QUIZ HISTORY CHIP */
        #subjectHistoryChip {
            display: none;
            align-items: center;
            gap: 6px;
            margin: 6px 0 8px;
            padding: 5px 13px;
            border-radius: 999px;
            background: rgba(91,80,232,.07);
            border: 1.5px solid rgba(91,80,232,.18);
            font-family: var(--font-ui);
            font-size: .75rem;
            font-weight: 700;
            color: var(--text-primary);
            width: fit-content;
        }
        #subjectHistoryChip .sjc-name { color: var(--text-muted); }
        #subjectHistoryChip .sjc-avg  { color: var(--violet); }
        [data-dark] #subjectHistoryChip {
            background: rgba(255, 255, 255, 0.055);
            border-color: rgba(255, 255, 255, 0.14);
        }

        /* PERSONAL BEST BANNER */
        #pbBanner {
            display: none;
            align-items: center;
            justify-content: center;
            gap: 6px;
            margin: 4px 0 6px;
            padding: 9px 18px;
            border-radius: 14px;
            background: linear-gradient(135deg, rgba(91,80,232,.10) 0%, rgba(34,195,221,.08) 100%);
            border: 1.5px solid rgba(91,80,232,.28);
            font-family: var(--font-ui);
            font-size: .85rem;
            font-weight: 800;
            color: var(--violet, #5b50e8);
            text-align: center;
            width: fit-content;
            align-self: center;
        }
        @keyframes pbPop {
            from { opacity: 0; transform: scale(.82) translateY(8px); }
            to   { opacity: 1; transform: scale(1)  translateY(0); }
        }
        #pbBanner.pb-visible {
            animation: pbPop .42s cubic-bezier(.18,.89,.32,1.28) both;
        }
        [data-dark] #pbBanner {
            background: rgba(255, 255, 255, 0.08);
            border-color: rgba(255, 255, 255, 0.22);
            color: #a89ffb;
        }
        @media (prefers-reduced-motion: reduce) {
            #pbBanner.pb-visible { animation: none; }
        }

        .score-actions {
            display: flex;
            gap: 10px;
            justify-content: center;
            flex-wrap: wrap;
        }

        .btn-share {
            background: linear-gradient(135deg, var(--violet), var(--violet-dim));
            color: white;
            padding: 12px 22px;
            border: none;
            border-radius: 999px;
            font-family: var(--font-ui);
            font-size: 0.9rem;
            font-weight: 600;
            cursor: var(--cur-point, pointer);
            transition: all 0.18s;
            box-shadow: 0 4px 16px rgba(91, 80, 232, 0.25);
        }

        .btn-share:hover {
            transform: translateY(-1px);
            box-shadow: 0 6px 20px rgba(91, 80, 232, 0.35);
        }

        .btn-retry {
            background: #f3f4f8;
            border: 1px solid rgba(91, 80, 232, 0.1);
            color: var(--text-secondary);
            padding: 12px 22px;
            border-radius: 999px;
            font-family: var(--font-ui);
            font-size: 0.9rem;
            font-weight: 600;
            cursor: var(--cur-point, pointer);
            transition: all 0.18s;
        }

        .btn-retry:hover {
            background: #e8ecf5;
            color: var(--text-primary);
        }

        #achievementsPanel {
            display: none;
            margin-top: 20px;
            background: #ffffff;
            border: 1px solid rgba(91, 80, 232, 0.1);
            border-radius: 20px;
            padding: 24px;
            box-shadow: 0 4px 24px rgba(91, 80, 232, 0.05);
            animation: slideUp 0.4s 0.1s ease both;
        }

        #achievementsPanel h3 {
            font-family: var(--font-ui);
            font-size: 1rem;
            color: var(--text-secondary);
            margin-bottom: 16px;
            font-style: italic;
        }

        .achievements-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 8px;
        }

        .ach-card {
            display: flex;
            align-items: center;
            gap: 12px;
            padding: 12px 14px;
            border-radius: 12px;
            border: 1px solid rgba(91, 80, 232, 0.08);
            background: #f8f9ff;
            transition: all 0.2s;
        }

        .ach-card.unlocked {
            background: rgba(217, 119, 6, 0.04);
            border-color: rgba(217, 119, 6, 0.18);
        }

        .ach-icon {
            width: 36px;
            height: 36px;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.1rem;
            background: #eeeeff;
            flex-shrink: 0;
        }

        .ach-card.unlocked .ach-icon {
            background: rgba(217, 119, 6, 0.1);
            color: var(--amber);
            animation: float 3s ease infinite;
        }

        @keyframes float {

            0%,
            100% {
                transform: translateY(0)
            }

            50% {
                transform: translateY(-3px)
            }
        }

        .ach-name {
            font-size: 0.8rem;
            font-weight: 600;
            color: var(--text-muted);
        }

        .ach-card.unlocked .ach-name {
            color: var(--amber);
        }

        .ach-desc {
            font-size: 0.7rem;
            color: var(--text-muted);
            margin-top: 1px;
            line-height: 1.3;
        }

        #badgeToast {
            position: fixed;
            bottom: 28px;
            left: 50%;
            transform: translateX(-50%) translateY(60px);
            background: #ffffff;
            border: 1px solid rgba(217, 119, 6, 0.25);
            color: var(--amber);
            padding: 10px 20px;
            border-radius: 99px;
            font-weight: 600;
            font-size: 0.85rem;
            z-index: 9999;
            box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
            transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
            white-space: nowrap;
        }

        #badgeToast.show {
            transform: translateX(-50%) translateY(0);
        }

        /* ── avatar unlock celebration ── */
        .av-unlock-overlay {
            display: none; position: fixed; inset: 0; z-index: 10001;
            background: rgba(20, 16, 60, .55); backdrop-filter: blur(4px);
            align-items: center; justify-content: center; padding: 24px;
        }
        .av-unlock-overlay.show { display: flex; animation: avFade .25s ease; }
        @keyframes avFade { from { opacity: 0 } to { opacity: 1 } }
        .av-unlock-card {
            position: relative; width: 100%; max-width: 340px; text-align: center;
            background: var(--card-bg, #fff); border-radius: 26px; padding: 30px 26px 24px;
            box-shadow: 0 24px 60px rgba(20, 16, 60, .35); overflow: hidden;
            animation: avPop .45s cubic-bezier(.16, 1, .3, 1);
        }
        @keyframes avPop { from { transform: scale(.82) translateY(20px); opacity: 0 } to { transform: none; opacity: 1 } }
        [data-dark] .av-unlock-card { background: #1D1D21; }
        .av-unlock-glow {
            position: absolute; top: -40px; left: 50%; transform: translateX(-50%);
            width: 220px; height: 220px; border-radius: 50%; pointer-events: none;
            background: radial-gradient(circle, rgba(91,80,232,.22), transparent 65%);
        }
        .av-unlock-tier {
            display: inline-block; color: #fff; font-family: var(--font-display);
            font-weight: 800; font-size: .68rem; letter-spacing: .08em; text-transform: uppercase;
            padding: 4px 12px; border-radius: 99px; margin-bottom: 14px; position: relative;
        }
        .av-unlock-art { position: relative; margin: 0 auto 6px; width: 120px; height: 120px; animation: avBob 1.6s ease-in-out infinite; }
        .av-unlock-art svg { width: 120px; height: 120px; border-radius: 50%; }
        @keyframes avBob { 0%,100% { transform: translateY(0) } 50% { transform: translateY(-7px) } }
        .av-unlock-kicker { color: var(--violet); font-family: var(--font-display); font-weight: 800; font-size: .8rem; letter-spacing: .04em; text-transform: uppercase; margin-top: 8px; }
        .av-unlock-name { font-family: var(--font-display); font-weight: 800; font-size: 1.7rem; margin: 2px 0 4px; }
        .av-unlock-sub { color: var(--muted, #64748b); font-weight: 600; font-size: .9rem; margin: 0 0 20px; }
        .av-unlock-btns { display: flex; flex-direction: column; gap: 10px; }
        .av-unlock-equip {
            background: var(--violet); color: #fff; border: none; border-radius: 999px;
            padding: 14px; font-family: var(--font-display); font-weight: 800; font-size: 1rem;
            cursor: var(--cur-point, pointer); box-shadow: none; transition: transform .1s ease, box-shadow .1s ease;
        }
        .av-unlock-equip:active { transform: translateY(3px); box-shadow: none; }
        .av-unlock-later { background: none; border: none; color: var(--muted, #94a3b8); font-weight: 700; font-size: .9rem; cursor: var(--cur-point, pointer); padding: 6px; }

        #menuOverlay {
            display: none;
            position: fixed;
            inset: 0;
            background: rgba(0, 0, 0, 0.2);
            z-index: 2010;   /* above nav (1005) */
            backdrop-filter: blur(4px);
        }

        #sideMenu {
            position: fixed;
            top: 0;
            right: -300px;
            width: 280px;
            height: 100%;
            background: #ffffff;
            border-left: 1px solid rgba(91, 80, 232, 0.1);
            z-index: 2020;   /* above nav + overlay */
            padding: 28px 24px;
            transition: right 0.3s cubic-bezier(0.4, 0, 0.2, 1),
                        background-color 0.35s ease, border-color 0.35s ease;
            box-shadow: -8px 0 40px rgba(0, 0, 0, 0.08);
            /* The menu is a fixed, viewport-tall panel but its contents run
               taller than the viewport on short screens (~1300px of items in
               860px), so the overflow was simply unreachable. Scroll it, and
               contain the overscroll so hitting the end doesn't scroll the
               quiz behind this modal. */
            overflow-y: auto;
            overscroll-behavior: contain;
        }

        .menu-item {
            padding: 14px 16px;
            border-radius: 12px;
            cursor: var(--cur-point, pointer);
            font-weight: 500;
            color: var(--text-secondary);
            font-size: 0.95rem;
            transition: all 0.2s;
        }

        .menu-item:hover {
            background: #f0f2ff;
            color: var(--text-primary);
        }

        /* .menu-item was written for <div>s, which are block by default; a
           link needs that spelled out or its padding collapses. */
        a.menu-item { display: block; text-decoration: none; }


        /* ── Technical 3D blueprints (decorative, behind study-tool content) ── */
        .bp { position: absolute; pointer-events: none; z-index: 0 }
        .bp-w { stroke: rgba(91,80,232,.45); fill: none; stroke-width: .8 }
        .bp-d { stroke: rgba(91,80,232,.26); fill: none; stroke-width: .5 }
        .bp-b { stroke: rgba(91,80,232,.7); fill: none; stroke-width: 1.1 }
        .bp-dash { stroke: rgba(91,80,232,.34); fill: none; stroke-width: .6; stroke-dasharray: 6 4 }
        .bp-f { fill: rgba(91,80,232,.09) }
        .bp-fm { fill: rgba(91,80,232,.16) }
        .bp-dot { fill: rgba(91,80,232,.68) }
        .bp-t { fill: rgba(91,80,232,.6); font-family:'Courier New',monospace; font-size:9px; letter-spacing:.05em }
        .bp-ts { fill: rgba(91,80,232,.42); font-family:'Courier New',monospace; font-size:7px }
        /* beat `.section-page > *` (relative/centered/maxwidth) so blueprints stay absolute behind content */
        .section-page > svg.bp { position: absolute; z-index: 0; max-width: none; margin: 0 }
        [data-dark] .bp { opacity: .95 }
        [data-dark] .bp-w { stroke: rgba(91,80,232,.65) }
        [data-dark] .bp-d { stroke: rgba(91,80,232,.38) }
        [data-dark] .bp-b { stroke: rgba(91,80,232,.85) }
        [data-dark] .bp-dash { stroke: rgba(91,80,232,.48) }
        [data-dark] .bp-f { fill: rgba(91,80,232,.1) }
        [data-dark] .bp-fm { fill: rgba(91,80,232,.2) }
        [data-dark] .bp-dot { fill: rgba(91,80,232,.75) }
        [data-dark] .bp-t { fill: rgba(91,80,232,.7) }
        [data-dark] .bp-ts { fill: rgba(91,80,232,.6) }
        @media(max-width:900px){ .section-page > svg.bp { display: none !important } }

        /* Landing on /flashcards or /library directly left no way back: the
           rail only exists above 1280px with a real pointer, and the tools
           referred to a "back arrow" that was never rendered. Browser-back was
           the only exit on a phone. */
        .section-back {
            position: fixed;
            top: max(74px, calc(env(safe-area-inset-top) + 66px));
            left: 18px;
            z-index: 1004;
            display: none;
            align-items: center;
            gap: 7px;
            padding: 9px 15px 9px 12px;
            border: 1px solid var(--card-border, rgba(91, 80, 232, .14));
            border-radius: 999px;
            background: var(--card-bg, #fff);
            color: var(--text-primary);
            font-family: var(--font-ui, 'Plus Jakarta Sans'), sans-serif;
            font-size: .86rem;
            font-weight: 800;
            cursor: var(--cur-point, pointer);
            box-shadow: 0 4px 14px rgba(91, 80, 232, .12);
            transition: border-color .14s ease, transform .14s ease;
        }

        html.section-open .section-back { display: inline-flex; }
        .section-back:hover { border-color: rgba(91, 80, 232, .4); transform: translateX(-2px); }
        .section-back svg { flex: none; }

        /* On the wide layout the rail already shows where you are and offers
           every other tool, so the button would be a third way to navigate in
           the same 200px. */
        @media (min-width: 1280px) and (min-height: 600px) and (hover: hover) {
            body.rail-left .section-back { display: none; }
        }

        /* The button is fixed, so it takes no space in flow and landed on top
           of the page's eyebrow. Reserve the room — but only under the same
           conditions that show it, or the rail layout gains 40px of dead space
           at the top of every tool. */
        @media (max-width: 1279px), (max-height: 599px), (hover: none) {
            html.section-open .section-page { padding-top: 126px; }
        }

        /* Quizlet-style study-mode switcher.

           The five study modes were only reachable from the desktop study
           rail, which needs 1280px and a real pointer — so on a phone there
           was no way to move between Flashcards, Learn, Test, Match and Write
           at all. This is that navigation, on the surface it belongs to. */
        .mode-bar {
            display: flex;
            gap: 6px;
            overflow-x: auto;
            scrollbar-width: none;
            margin: 0 0 20px;
            padding-bottom: 2px;
            -webkit-overflow-scrolling: touch;
        }

        .mode-bar::-webkit-scrollbar { display: none; }

        .mode-bar a {
            flex: none;
            padding: 8px 15px;
            border: 1px solid var(--card-border, rgba(91, 80, 232, .14));
            border-radius: 999px;
            background: var(--card-bg, #fff);
            color: var(--text-secondary, #4b5563);
            font-family: var(--font-ui, 'Plus Jakarta Sans'), sans-serif;
            font-size: .85rem;
            font-weight: 800;
            text-decoration: none;
            white-space: nowrap;
            transition: border-color .14s ease, color .14s ease;
        }

        .mode-bar a:hover { border-color: rgba(91, 80, 232, .4); color: var(--violet); }

        .mode-bar a[aria-current="page"] {
            background: var(--violet);
            border-color: var(--violet);
            color: #fff;
        }

        /* This used to be hidden on desktop because "the rail already shows every
           mode and marks the current one". The rail no longer lists Learn, Test,
           Match and Write — they are modes of a flashcard set, not destinations —
           so this bar is now the only mode control, and hiding it here would
           leave a desktop student with no way into any of the four. It is the
           same control at every width now, which is also why there is still only
           one list of modes (STUDY_MODES) rather than two to drift apart. */

        .section-page {
            display: none;
            position: fixed;
            inset: 0;
            background-color: #f4f6ff;
            /* Canonical backdrop — identical base + 40px grid as every other page */
            background-image:
                linear-gradient(rgba(91, 80, 232, .05) 1px, transparent 1px),
                linear-gradient(90deg, rgba(91, 80, 232, .05) 1px, transparent 1px);
            background-size: 40px 40px, 40px 40px;
            z-index: 1003;
            padding: 84px 24px 40px;   /* top clears the fixed 60px nav (kept visible) */
            overflow-y: auto;
            overscroll-behavior: contain;   /* don't chain scroll to the quiz behind */
            animation: sectionOpen .26s cubic-bezier(.2, .7, .2, 1);
        }
        /* Subtle open animation when a tool page (Planner, Marks, etc.) appears. */
        @keyframes sectionOpen {
            from { opacity: 0; transform: scale(.985) translateY(8px); }
            to   { opacity: 1; transform: scale(1) translateY(0); }
        }
        @media (prefers-reduced-motion: reduce) { .section-page { animation: none; } }

        /* ── Signature "clay tap" — a soft, springy press-squish on tappable cards,
           menu items and banners (your buttons already squish; this extends the same
           tactile, claymorphic feel everywhere for a cohesive, distinctive touch). */
        .menu-item, .nav-dd-menu a, .review-due-banner, .dc-card, .exam-countdown-banner {
            transition: transform .14s cubic-bezier(.34, 1.45, .64, 1), background .15s ease,
                        border-color .15s ease, box-shadow .16s ease, color .15s ease;
        }
        .menu-item:active, .nav-dd-menu a:active, .review-due-banner:active,
        .dc-card:active, .exam-countdown-banner:active { transform: scale(.972); }
        @media (prefers-reduced-motion: reduce) {
            .menu-item:active, .nav-dd-menu a:active, .review-due-banner:active,
            .dc-card:active, .exam-countdown-banner:active { transform: none; }
        }

        /* While a tool page is open, freeze the page behind it so the quiz can't
           scroll into view on mobile (the overlay scrolls internally instead).
           The scroll container is <html>, so the lock must live there. */
        html.section-open, html.section-open body { overflow: hidden; height: 100%; }

        /* (Blueprint backdrop removed — every page now shares the same plain grid.) */

        /* keep section-page content at the same width as the quiz (centered),
           above the blueprint decoration */
        .section-page > * {
            position: relative; z-index: 1;
            max-width: 760px;
            margin-left: auto;
            margin-right: auto;
        }
        /* An open dropdown has to clear its own later siblings. The rule above
           gives EVERY section-page child position:relative;z-index:1, so the
           panel's z-index:60 is resolved INSIDE whichever child holds it and
           the later `.tool-steps` wins outright — the bottom 94px of the
           "Number of cards" menu was painted under, and clicked through to,
           the "how it works" cards on Flashcards, Learn, Test, Write, Match,
           Concept map and Cheat sheet. Lift whichever child is holding the
           open menu. (`#inputSection:has(.csel.open)` below is the same fix,
           found once, for the quiz builder's own card.) */
        .section-page > *:has(.csel.open) { z-index: 80; }
        /* Bare form controls (input/textarea/button/select) default to
           inline-block, so the auto margins above can't centre them and they
           drop to the left edge. Force block so they sit in the 760 column. */
        .section-page > .input-text,
        .section-page > .textarea-notes,
        .section-page > .btn-generate,
        .section-page > .select-styled {
            display: block;
        }

        .section-page > button {
            text-align: left;   /* keep the back arrow at the left of the band */
        }
        /* Back arrows shrink-wrap by default (UA button sizing), so auto-margins
           centre them. Make them fill the 760 column so ← sits at its left edge,
           aligned with the heading + grid below. */
        .section-page > button[aria-label="Back"] {
            width: 100%;
            background: none;
            border: none;
            font-size: 1.5rem;
            cursor: var(--cur-point, pointer);
            color: var(--text-muted);
            margin-bottom: 24px;
            display: block;
            padding: 4px 6px;
            border-radius: 8px;
            transition: color .15s ease;
        }
        .section-page > button[aria-label="Back"]:hover {
            color: var(--violet);
        }
        .section-page > button[aria-label="Back"]:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 3px;
            color: var(--violet);
        }
        @media (hover: none) {
            .section-page > button[aria-label="Back"]:hover { color: var(--text-muted); }
        }

        .section-page h2 {
            font-family: var(--font-display);
            font-size: 1.5rem;
            font-weight: 800;
            color: var(--text-primary);
            margin-bottom: 24px;
            letter-spacing: -0.02em;
        }

        .section-page p {
            color: var(--text-secondary);
            line-height: 1.8;
            font-size: 0.95rem;
        }

        .section-card {
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, 0.08);
            border-radius: 16px;
            padding: 20px;
        }

        .section-card-title {
            font-weight: 700;
            color: var(--violet);
            margin-bottom: 8px;
        }

        /* ── ESSAY FEEDBACK ── */
        .essay-prompt-banner {
            display: none;
            align-items: center;
            gap: 12px;
            margin-top: 20px;
            padding: 14px 16px;
            background: var(--violet-glow);
            border: 1px solid rgba(91, 80, 232, .25);
            border-radius: 12px;
            cursor: var(--cur-point, pointer);
            transition: transform .15s ease, border-color .15s ease;
        }

        .essay-prompt-banner:hover {
            transform: translateY(-1px);
            border-color: rgba(91, 80, 232, .5);
        }

        .essay-prompt-icon {
            width: 38px;
            height: 38px;
            flex-shrink: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            background: linear-gradient(135deg, var(--violet), var(--violet-dim));
            border-radius: 12px;
            box-shadow: 0 4px 14px rgba(91, 80, 232, .32);
        }

        .essay-prompt-title {
            font-weight: 700;
            font-size: .88rem;
            color: var(--text-primary);
        }

        .essay-prompt-sub {
            font-size: .8rem;
            color: var(--text-secondary);
            margin-top: 2px;
        }

        .essay-prompt-arrow {
            margin-left: auto;
            color: var(--violet);
            font-size: 1.1rem;
            flex-shrink: 0;
        }

        /* ── Daily Review banner (spaced repetition nudge) ── */
        .review-due-banner {
            display: none;
            align-items: center;
            gap: 12px;
            margin: 20px 0;
            padding: 14px 16px;
            background: var(--emerald-bg);
            border: 1px solid var(--emerald-border);
            border-radius: 12px;
            cursor: var(--cur-point, pointer);
            transition: transform .15s ease, border-color .15s ease;
            animation: fadeIn .4s ease;
        }

        .review-due-banner:hover {
            transform: translateY(-1px);
            border-color: var(--emerald);
        }

        .review-due-banner:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
            border-radius: 12px;
        }

        [data-dark] .review-due-banner:focus-visible { outline-color: #9d94ff; }

        @media (hover: none) {
            .review-due-banner:hover { transform: none; }
        }

        .review-due-icon {
            width: 38px;
            height: 38px;
            flex-shrink: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            background: linear-gradient(135deg, var(--emerald), var(--emerald-dim));
            border-radius: 12px;
            box-shadow: 0 4px 14px rgba(5, 150, 105, .32);
        }

        .review-due-title {
            font-weight: 700;
            font-size: .88rem;
            color: var(--text-primary);
        }

        .review-due-sub {
            font-size: .8rem;
            color: var(--text-secondary);
            margin-top: 2px;
        }

        .review-due-arrow {
            margin-left: auto;
            color: var(--emerald);
            font-size: 1.1rem;
            flex-shrink: 0;
        }

        .review-due-close {
            flex-shrink: 0; background: none; border: none; color: var(--text-muted);
            font-size: .95rem; line-height: 1; cursor: var(--cur-point, pointer); padding: 5px 7px; border-radius: 999px;
            opacity: .55; transition: opacity .15s, background .15s;
        }
        .review-due-close:hover { opacity: 1; background: rgba(0, 0, 0, .06); }
        [data-dark] .review-due-close:hover { background: rgba(255, 255, 255, .1); }

        /* ── FEATURE 8 — Exam countdown banner: amber variant of .review-due-banner.
           Reuses the whole review-due-* family (icon/title/sub/arrow layout) and
           only overrides the accent colour, exactly like .exam-timer-low layers
           a rose accent onto .exam-timer-bar in Feature 7. ── */
        .exam-countdown-banner {
            background: var(--amber-bg);
            border: 1px solid var(--amber-border);
        }

        .exam-countdown-banner:hover {
            border-color: var(--amber);
        }

        .exam-countdown-banner .review-due-icon {
            background: linear-gradient(135deg, var(--amber), #b45309);
            box-shadow: 0 4px 14px rgba(217, 119, 6, .32);
        }

        .exam-countdown-banner .review-due-arrow {
            color: var(--amber);
        }

        /* ── Free-quiz meter (signed out): counts the guest allowance down and
           points at the account that unlocks more. Neutral while quizzes remain,
           amber once they're gone — same shape as .review-due-banner but it
           isn't itself clickable (the CTA button is), so no hover lift. ── */
        .guest-limit-banner {
            display: none;
            align-items: center;
            gap: 12px;
            margin: 20px 0;
            padding: 14px 16px;
            background: #f7f8fd;
            border: 1px solid #dfe3eb;
            border-radius: 12px;
            animation: fadeIn .4s ease;
        }

        [data-dark] .guest-limit-banner { background: #18181B; border-color: #34343A; }
        [data-dark] .glb-icon { background: #34343A; }
        [data-dark] .guest-limit-banner.glb-spent { background: var(--amber-bg); border-color: var(--amber-border); }

        .guest-limit-banner.glb-spent {
            background: var(--amber-bg);
            border-color: var(--amber-border);
        }

        .glb-icon {
            width: 38px;
            height: 38px;
            flex-shrink: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            background: var(--text-secondary);
            border-radius: 8px;
            box-shadow: none;
        }

        .guest-limit-banner.glb-spent .glb-icon {
            background: var(--amber);
            box-shadow: none;
        }

        .glb-text { flex: 1; min-width: 0; }

        .glb-title {
            font-weight: 600;
            font-size: .88rem;
            color: var(--text-primary);
        }

        .glb-sub {
            font-size: .8rem;
            color: var(--text-secondary);
            margin-top: 2px;
        }

        .guest-limit-banner .glb-cta { flex-shrink: 0; min-height: 44px; border: 1px solid #8791a3; border-radius: 8px; background: transparent; color: var(--text-primary); box-shadow: none; font-weight: 600; }
        .guest-limit-banner .glb-cta:hover { background: var(--violet-glow); color: var(--text-primary); box-shadow: none; transform: none; }

        @media (max-width: 460px) {
            .guest-limit-banner { flex-wrap: wrap; }
            .glb-cta { width: 100%; }
        }

        /* ── Exam Planner page: countdown cards + add-exam mini-form ── */
        .exam-plan-card {
            background: var(--card-bg);
            border: 1px solid var(--card-border);
            border-radius: 16px;
            padding: 16px;
            margin-bottom: 10px;
            animation: fadeUp .35s ease both;
        }

        .exam-plan-head {
            display: flex;
            align-items: flex-start;
            justify-content: space-between;
            gap: 12px;
        }

        .exam-plan-subject {
            font-weight: 700;
            font-size: .95rem;
            color: var(--text-primary);
        }

        .exam-plan-date {
            font-size: .8rem;
            color: var(--text-muted);
            margin-top: 2px;
        }

        .exam-plan-actions {
            display: flex;
            align-items: center;
            gap: 10px;
            flex-shrink: 0;
        }

        .exam-plan-countdown {
            font-size: .76rem;
            font-weight: 700;
            color: var(--amber);
            background: var(--amber-bg);
            border: 1px solid var(--amber-border);
            border-radius: 99px;
            padding: 4px 11px;
            white-space: nowrap;
        }

        .exam-plan-delete {
            background: none;
            border: none;
            color: var(--text-muted);
            font-size: .95rem;
            cursor: var(--cur-point, pointer);
            line-height: 1;
            padding: 4px;
            border-radius: 999px;
            transition: color .15s ease, background .15s ease;
        }

        .exam-plan-delete:hover {
            color: var(--rose);
            background: var(--rose-bg);
        }

        .exam-plan-tip {
            font-size: .82rem;
            color: var(--text-secondary);
            line-height: 1.5;
            margin: 10px 0 0;
            padding-top: 10px;
            border-top: 1px solid var(--card-border);
        }

        .exam-planner-form .btn-generate {
            margin-top: 16px;
        }

        #dailyReview.section-page {
            animation: slideUp .42s cubic-bezier(0.4, 0, 0.2, 1) both;
        }

        .essay-type-row {
            display: flex;
            gap: 8px;
            flex-wrap: wrap;
            margin: 4px 0 18px;
        }

        .essay-type-chip {
            padding: 7px 14px;
            border-radius: 999px;
            border: 1px solid var(--card-border);
            background: var(--card-bg);
            color: var(--text-secondary);
            font-family: var(--font-ui);
            font-size: 0.8rem;
            font-weight: 600;
            cursor: var(--cur-point, pointer);
            transition: all .15s;
        }

        .essay-type-chip.active {
            background: linear-gradient(135deg, var(--violet), var(--violet-dim));
            border-color: transparent;
            color: #fff;
        }

        .essay-word-count {
            text-align: right;
            font-size: .75rem;
            color: var(--text-muted);
            margin-top: 6px;
        }

        .btn-essay {
            width: 100%;
            margin-top: 18px;
            padding: 15px;
            background: linear-gradient(135deg, var(--violet) 0%, var(--violet-dim) 100%);
            border: none;
            border-radius: 999px;
            color: #fff;
            font-family: var(--font-ui);
            font-size: 1rem;
            font-weight: 600;
            cursor: var(--cur-point, pointer);
            box-shadow: 0 4px 20px rgba(124, 106, 247, 0.3);
            transition: transform .15s, box-shadow .15s, opacity .15s;
        }

        .btn-essay:hover {
            transform: translateY(-2px);
            box-shadow: 0 8px 26px rgba(124, 106, 247, 0.4);
        }

        .btn-essay:disabled {
            opacity: .55;
            cursor: not-allowed;
            transform: none;
        }

        .btn-essay-ghost {
            background: var(--card-bg) !important;
            color: var(--text-secondary) !important;
            border: 1px solid var(--card-border) !important;
            box-shadow: none !important;
        }

        .essay-band {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            background: var(--violet-glow);
            border: 1px solid rgba(91, 80, 232, .3);
            color: var(--violet);
            font-weight: 700;
            font-size: .82rem;
            padding: 7px 16px;
            border-radius: 999px;
            margin-bottom: 14px;
        }

        .essay-summary {
            color: var(--text-secondary);
            line-height: 1.7;
            margin-bottom: 22px;
            font-size: .92rem;
        }

        .essay-fb-block {
            margin-bottom: 20px;
        }

        .essay-fb-heading {
            display: flex;
            align-items: center;
            gap: 7px;
            font-weight: 700;
            font-size: .8rem;
            text-transform: uppercase;
            letter-spacing: .05em;
            margin-bottom: 10px;
        }

        .essay-fb-heading.good {
            color: #059669;
        }

        .essay-fb-heading.improve {
            color: #b45309;
        }

        [data-dark] .essay-fb-heading.good {
            color: #6ee7b7;
        }

        [data-dark] .essay-fb-heading.improve {
            color: #fcd34d;
        }

        .essay-fb-list {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .essay-fb-item {
            display: flex;
            gap: 10px;
            align-items: flex-start;
            border-radius: 12px;
            padding: 12px 14px;
            font-size: .87rem;
            line-height: 1.55;
            color: var(--text-primary);
        }

        .essay-fb-item.good {
            background: var(--emerald-bg);
            border: 1px solid var(--emerald-border);
        }

        .essay-fb-item.improve {
            background: var(--amber-bg);
            border: 1px solid var(--amber-border);
        }

        .essay-fb-icon {
            flex-shrink: 0;
        }

        .essay-fb-icon.good {
            color: #059669;
        }

        .essay-fb-icon.improve {
            color: #b45309;
        }

        [data-dark] .essay-fb-icon.good {
            color: #6ee7b7;
        }

        [data-dark] .essay-fb-icon.improve {
            color: #fcd34d;
        }

        .essay-next-step {
            background: var(--violet-glow);
            border: 1px solid rgba(91, 80, 232, .25);
            border-radius: 16px;
            padding: 16px;
            font-size: .87rem;
            color: var(--text-primary);
            line-height: 1.6;
        }

        .essay-next-step b {
            color: var(--violet);
        }

        /* ── ESSAY FEEDBACK: motion ── */
        /* Panel glides up into view whenever the section opens */
        #essayFeedback.section-page {
            animation: slideUp .42s cubic-bezier(0.4, 0, 0.2, 1) both;
        }

        /* The essay form on the builder's primitives: the textarea sits in the
           same 1080 column as everything else (study-tools.css lets it run to
           the pane edge), and the action is the builder's solid 54px primary
           spanning that column, not a 210px gradient pill at the left edge.
           #essayFeedback beats study-tools' :is() selectors on specificity, so
           the shared sheet and its digest pin stay untouched.

           The radius follows the tool set rather than this page's own history:
           of the 19 primaries across the study tools, 14 are 12px and 3 are
           8px — the only two 999px pills in the set were this page's own
           buttons, which read as a different component from every other
           action a student meets. Width stays full: that is shared with
           Flashcards, Timer, Write and Learn, so it is a pattern here, not an
           outlier. Chips keep their pill — those ARE round everywhere. */
        #essayFeedback #essayText {
            max-width: 1080px;
        }

        #essayFeedback .btn-essay {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 100%;
            max-width: 1080px;
            min-height: 54px;
            margin: 22px auto 0;
            padding: 12px 24px;
            border: 0;
            border-radius: 12px;
            background: var(--violet);
            background-image: none;
            box-shadow: none;
            color: #fff;
            font-family: var(--font-display);
            font-size: 1.05rem;
            font-weight: 800;
            letter-spacing: 0;
            transition: background .16s ease;
        }

        #essayFeedback .btn-essay:hover:not(:disabled),
        #essayFeedback .btn-essay:active:not(:disabled) {
            transform: none;
            filter: none;
            background: var(--violet-shade);
            box-shadow: none;
        }

        @media (hover: none) {
            #essayFeedback .btn-essay:hover:not(:disabled) {
                background: var(--violet);
            }
        }

        #essayFeedback .btn-essay:disabled {
            opacity: .55;
            transform: none;
        }

        #essayFeedback .essay-feedback-result .btn-essay {
            margin-top: 14px;
        }

        /* Contextual nudge softly fades in when an essay subject is picked */
        .essay-prompt-banner {
            animation: fadeIn .4s ease;
        }

        /* Essay-type chip gives a little confirming pop when selected */
        .essay-type-chip.active {
            animation: popIn .3s cubic-bezier(0.34, 1.56, 0.64, 1);
        }

        /* Loading state breathes gently while the model reads the essay */
        #essayLoading {
            animation: fadeIn .35s ease;
        }

        #essayLoading p:last-of-type {
            animation: thinkPulse 1.8s ease-in-out infinite;
        }

        @keyframes thinkPulse {

            0%,
            100% {
                opacity: .5;
            }

            50% {
                opacity: 1;
            }
        }

        /* Results cascade in piece by piece — the "reveal" moment */
        .essay-feedback-result .essay-band {
            animation: fadeUp .4s ease both;
        }

        .essay-feedback-result .essay-summary {
            animation: fadeUp .4s .06s ease both;
        }

        .essay-feedback-result .essay-fb-heading.good {
            animation: fadeUp .4s .12s ease both;
        }

        .essay-feedback-result .essay-fb-heading.improve {
            animation: fadeUp .4s .4s ease both;
        }

        .essay-feedback-result .essay-fb-item {
            animation: fadeUp .4s ease both;
        }

        .essay-feedback-result .essay-next-step {
            animation: fadeUp .4s .78s ease both;
        }

        .essay-feedback-result .btn-essay-ghost {
            animation: fadeIn .4s .86s ease both;
        }

        /* ── ESSAY FEEDBACK: marking history strip ── */
        .essay-marks-strip {
            background: var(--card-bg);
            border: 1px solid var(--card-border);
            border-radius: var(--r-sm);
            padding: 12px 14px;
            margin-bottom: 16px;
            animation: fadeIn .35s ease;
        }

        .essay-marks-strip .em-head {
            font-weight: 800;
            font-size: .8rem;
            color: var(--text-secondary);
            text-transform: uppercase;
            letter-spacing: .04em;
            margin-bottom: 8px;
        }

        .essay-marks-strip .em-row {
            display: flex;
            flex-wrap: wrap;
            gap: 6px;
        }

        .essay-marks-strip .em-chip {
            font-size: .78rem;
            font-weight: 700;
            color: var(--text-primary);
            background: var(--violet-glow);
            border: 1px solid var(--card-border);
            border-radius: 999px;
            padding: 3px 10px;
        }

        .essay-marks-strip .em-weak {
            font-size: .82rem;
            color: var(--text-muted);
            margin-top: 8px;
        }

        .essay-marks-strip .em-weak b {
            color: var(--violet);
        }

        /* ── PRO gating ── */
        .pro-chip {
            display: inline-block;
            margin-left: 7px;
            padding: 1px 7px 2px;
            font-size: .62rem;
            font-weight: 800;
            letter-spacing: .08em;
            color: #fff;
            background: linear-gradient(135deg, var(--violet), var(--violet-dim));
            border-radius: 999px;
            vertical-align: 2px;
        }

        /* Student-and-up features carry both pills; a second violet one would
           read as a rendering fault, so this rung takes the cyan accent. */
        body.has-paid-tools .pro-chip[data-paid-tool] { display: none; }
        .pro-chip--student {
            margin-left: 5px;
            background: linear-gradient(135deg, var(--cyan, #22c3dd), #0369a1);
        }

        .pro-gate-card {
            display: none;
            background: var(--card-bg);
            border: 1px solid var(--card-border);
            border-radius: var(--r);
            padding: 22px 20px;
            text-align: center;
            margin-top: 14px;
            animation: fadeIn .35s ease;
        }

        .pro-gate-card h3 {
            font-family: var(--font-display);
            font-weight: 800;
            margin-bottom: 6px;
        }

        .pro-gate-card p {
            color: var(--text-muted);
            font-size: .9rem;
            margin-bottom: 14px;
        }

        .pro-gate-card .pro-gate-cta {
            display: inline-block;
            padding: 11px 26px;
            border-radius: 999px;
            font-weight: 800;
            color: #fff;
            background: linear-gradient(135deg, var(--violet), var(--violet-dim));
            text-decoration: none;
        }

        /* ANIMATIONS */
        @keyframes fadeUp {
            from {
                opacity: 0;
                transform: translateY(20px)
            }

            to {
                opacity: 1;
                transform: translateY(0)
            }
        }
        }

        @keyframes slideUp {
            from {
                opacity: 0;
                transform: translateY(16px)
            }

            to {
                opacity: 1;
                transform: translateY(0)
            }
        }

        @keyframes fadeIn {
            from {
                opacity: 0
            }

            to {
                opacity: 1
            }
        }

        @keyframes spin {
            to {
                transform: rotate(360deg)
            }
        }

        @keyframes popIn {
            0% {
                transform: scale(1)
            }

            50% {
                transform: scale(1.015)
            }

            100% {
                transform: scale(1)
            }
        }

        @keyframes shake {

            0%,
            100% {
                transform: translateX(0)
            }

            20%,
            60% {
                transform: translateX(-4px)
            }

            40%,
            80% {
                transform: translateX(4px)
            }
        }

        canvas#shareCanvas {
            display: none;
        }

        /* ── BLUEPRINT DECORATIONS ── */
        .bp-l {
            stroke: rgba(91, 80, 232, 0.16);
            fill: none;
            stroke-width: 0.65;
        }

        .bp-la {
            stroke: rgba(91, 80, 232, 0.32);
            fill: none;
            stroke-width: 1;
        }

        .bp-ld {
            stroke: rgba(91, 80, 232, 0.09);
            fill: none;
            stroke-width: 0.5;
        }

        .bp-dash {
            stroke: rgba(91, 80, 232, 0.13);
            fill: none;
            stroke-width: 0.55;
            stroke-dasharray: 4 3;
        }

        .bp-fillm {
            fill: rgba(91, 80, 232, 0.07);
            stroke: none;
        }

        .bp-dot {
            fill: rgba(91, 80, 232, 0.4);
        }

        .bp-text {
            fill: rgba(91, 80, 232, 0.32);
            font-family: var(--font-ui);
            font-size: 7.5px;
            letter-spacing: 0.04em;
        }

        .bp-texts {
            fill: rgba(91, 80, 232, 0.2);
            font-family: var(--font-ui);
            font-size: 6px;
        }


        /* ══════════════════════════════════════
           INDEX PAGE DESIGN UPGRADE — v2
        ══════════════════════════════════════ */

        /* Clean background: subtle grid only, no aurora glows (matches the
           homepage + dark theme — same 40px mesh in both). */
        body {
            background-color: #f4f6ff;
            background-image:
                linear-gradient(rgba(91, 80, 232, .05) 1px, transparent 1px),
                linear-gradient(90deg, rgba(91, 80, 232, .05) 1px, transparent 1px);
            background-size: 40px 40px, 40px 40px;
        }

        /* Nav glass */
        nav {
            background: rgba(244, 246, 255, .92);
            box-shadow: 0 1px 0 rgba(91, 80, 232, .08);
            transition: box-shadow .3s;
        }

        nav.scrolled {
            box-shadow: 0 4px 24px rgba(91, 80, 232, .1), 0 1px 0 rgba(91, 80, 232, .08);
        }

        /* Tabs */
        .tabs {
            box-shadow: 0 1px 4px rgba(91, 80, 232, .06) inset;
        }

        .tab-slider {
            box-shadow: 0 2px 8px rgba(91, 80, 232, .12), 0 1px 2px rgba(0, 0, 0, .05);
        }

        .tab-btn.active {
            font-weight: 700;
            color: var(--text-primary) !important;
        }

        /* Generate button — animated shimmer (3D tactile press, matches the tools) */
        .btn-generate {
            background: var(--grad-cta);
            box-shadow: 0 8px 18px rgba(91, 80, 232, .28);
            letter-spacing: .02em;
        }

        .btn-generate:hover {
            box-shadow: 0 11px 24px rgba(91, 80, 232, .34);
        }

        /* Progress bar */
        .progress-wrap {
            box-shadow: 0 2px 12px rgba(91, 80, 232, .07);
            border: 1px solid rgba(91, 80, 232, .08);
        }

        .progress-bar-track {
            height: 5px;
            background: #e4e8f5;
        }

        .progress-bar-fill {
            background: var(--violet);
            box-shadow: 0 0 8px rgba(91, 80, 232, .35);
        }

        /* Question card */
        .question-card {
            box-shadow: 0 8px 32px rgba(91, 80, 232, .07), 0 1px 4px rgba(0, 0, 0, .04);
            border: 1px solid rgba(91, 80, 232, .1);
            position: relative;
            overflow: hidden;
        }

        .question-card::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 2px;
            background: linear-gradient(90deg, var(--violet), #818cf8, #a78bfa);
            opacity: .7;
        }

        /* Question number chip */
        .question-num {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            background: rgba(91, 80, 232, .07);
            border: 1px solid rgba(91, 80, 232, .14);
            border-radius: 99px;
            padding: 3px 10px;
            font-size: .7rem;
            font-weight: 700;
            color: var(--violet);
            letter-spacing: .06em;
            text-transform: uppercase;
            margin-bottom: 12px;
        }

        /* Question text */
        .question-text {
            font-size: 1.1rem;
            font-weight: 600;
            font-style: normal;
            color: var(--text-primary);
            line-height: 1.6;
            letter-spacing: -.01em;
        }

        /* Option buttons */
        .option {
            background: #f8f9ff;
            border: 1.5px solid rgba(91, 80, 232, .1);
            border-radius: 12px;
            transition: all .18s cubic-bezier(.4, 0, .2, 1);
        }

        .option:hover {
            border-color: rgba(91, 80, 232, .32);
            background: #eef0ff;
            transform: translateX(4px);
            box-shadow: 0 2px 12px rgba(91, 80, 232, .1);
        }

        .opt-letter {
            width: 30px;
            height: 30px;
            border-radius: 8px;
            font-size: .78rem;
            font-weight: 700;
            background: #eeefff;
            border: 1.5px solid rgba(91, 80, 232, .14);
        }

        .option:hover .opt-letter {
            background: rgba(91, 80, 232, .14);
            border-color: rgba(91, 80, 232, .3);
            color: var(--violet);
        }

        .opt-text {
            font-size: .9rem;
            font-weight: 500;
        }

        /* Correct / wrong states — full solid colour fills */
        .option.correct {
            border-color: #059669;
            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
            box-shadow: 0 6px 20px rgba(16, 185, 129, .35), inset 0 1px 0 rgba(255, 255, 255, .18);
        }

        .option.correct .opt-letter {
            background: rgba(255, 255, 255, .22);
            border-color: rgba(255, 255, 255, .45);
            color: #ffffff;
        }

        .option.wrong {
            border-color: #e11d48;
            background: linear-gradient(135deg, #f43f5e 0%, #e11d48 100%);
            box-shadow: 0 6px 20px rgba(225, 29, 72, .32), inset 0 1px 0 rgba(255, 255, 255, .18);
        }

        .option.wrong .opt-letter {
            background: rgba(255, 255, 255, .22);
            border-color: rgba(255, 255, 255, .45);
            color: #ffffff;
        }

        /* Explanation box */
        .explanation-box {
            border-radius: 12px;
            font-weight: 500;
        }

        .explanation-box.correct-exp {
            background: rgba(5, 150, 105, .07);
            border-color: var(--emerald);
        }

        .explanation-box.wrong-exp {
            background: rgba(217, 119, 6, .07);
            border-color: var(--amber);
        }

        .explanation-box.timeout-exp {
            background: rgba(225, 29, 72, .06);
            border-color: var(--rose);
        }

        /* Nav buttons */
        .btn-prev,
        .btn-next {
            border-radius: 999px;
            font-weight: 700;
        }

        .btn-next {
            background: linear-gradient(135deg, #6356e8, var(--violet-dim));
            box-shadow: 0 4px 16px rgba(91, 80, 232, .28);
        }

        .btn-next:hover {
            box-shadow: 0 6px 24px rgba(91, 80, 232, .4);
            transform: translateY(-2px);
        }

        /* Score card */
        #scoreCard {
            box-shadow: 0 12px 40px rgba(91, 80, 232, .1), 0 2px 6px rgba(0, 0, 0, .04);
            border: 1px solid rgba(91, 80, 232, .1);
            position: relative;
            overflow: hidden;
        }

        #scoreCard::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 3px;
            background: linear-gradient(90deg, var(--violet), #818cf8, #a78bfa);
        }

        .score-stat {
            background: linear-gradient(135deg, #f8f9ff, #f0f2ff);
            border: 1px solid rgba(91, 80, 232, .1);
            border-radius: 12px;
            box-shadow: 0 2px 8px rgba(91, 80, 232, .05);
        }

        .score-stat-val {
            background: linear-gradient(135deg, var(--violet), #818cf8);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
            font-size: 1.8rem;
        }

        /* Achievement cards */
        #achievementsPanel {
            box-shadow: 0 8px 32px rgba(91, 80, 232, .07);
            border: 1px solid rgba(91, 80, 232, .1);
        }

        .ach-card {
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, .08);
            border-radius: 12px;
            transition: transform .2s, box-shadow .2s;
        }

        .ach-card:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 16px rgba(91, 80, 232, .1);
        }

        .ach-card.unlocked {
            background: linear-gradient(135deg, rgba(217, 119, 6, .05), rgba(245, 158, 11, .03));
            border-color: rgba(217, 119, 6, .2);
            box-shadow: 0 2px 12px rgba(217, 119, 6, .1);
        }

        .ach-icon {
            border-radius: 12px;
        }

        /* Loading spinner */
        .spinner {
            width: 48px;
            height: 48px;
            border: 2.5px solid rgba(91, 80, 232, .1);
            border-top-color: var(--violet);
            box-shadow: 0 0 16px rgba(91, 80, 232, .15);
        }

        /* Side menu */
        #sideMenu {
            box-shadow: -12px 0 60px rgba(0, 0, 0, .1);
        }

        .menu-item {
            border-radius: 12px;
            font-weight: 600;
        }

        .menu-item:hover {
            background: linear-gradient(135deg, #f0f2ff, #eef0ff);
        }

        /* ── Upgrade is the only paid row in here, so it stops being a row ──
           Below 400px the nav pill is hidden and this list is the ONLY upgrade
           button on the phone — and it was set as violet bold text, the same
           treatment as "Join a live game" two lines down and no louder than
           the twelve grey rows around it. The one thing in the menu that costs
           money looked exactly like the twelve that don't.

           Filled, in the same violet ramp as the nav pill, so the two read as
           the same button in two places. Everything else about the row is
           unchanged — same 12px radius, same padding, same copy. */
        .menu-item-pro {
            margin: 4px 0 6px;
            color: #fff !important;
            background: linear-gradient(180deg, #6f61f4 0%, #5b50e8 55%, #4c40cf 100%);
            box-shadow:
                0 1px 2px rgba(16, 12, 60, .2),
                0 4px 12px -6px rgba(16, 12, 60, .5),
                inset 0 1px 0 rgba(255, 255, 255, .26);
        }

        /* `.menu-item:hover` above is a gradient shorthand, which would wipe
           this one and leave white text on a near-white tint — the same trap
           topnav.css documents for the nav pill. Restate it, a shade up. */
        .menu-item-pro:hover {
            background: linear-gradient(180deg, #7d70f6 0%, #6a5eee 55%, #5a4ddb 100%);
            color: #fff;
        }

        .menu-item-pro:active {
            box-shadow: inset 0 1px 3px rgba(16, 12, 60, .34);
        }

        [data-dark] .menu-item-pro:hover {
            background: linear-gradient(180deg, #7d70f6 0%, #6a5eee 55%, #5a4ddb 100%);
        }

        /* Share button */
        .btn-share {
            background: linear-gradient(135deg, #6356e8, var(--violet-dim));
            box-shadow: 0 4px 20px rgba(91, 80, 232, .3);
            border-radius: 999px;
        }

        .btn-share:hover {
            box-shadow: 0 6px 28px rgba(91, 80, 232, .4);
            transform: translateY(-2px);
        }

        .btn-retry {
            border-radius: 999px;
            font-weight: 700;
        }

        /* ── Chart / visual aid container ── */
        .question-chart {
            margin: 0 0 22px 0;
            background: #fff;
            border: 1px solid rgba(91, 80, 232, 0.14);
            border-radius: 12px;
            overflow: hidden;
            animation: fadeIn .4s ease;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.07);
        }

        .question-chart>svg {
            display: block;
            max-width: 100%;
            height: auto;
        }

        .chart-label {
            display: flex;
            align-items: center;
            gap: 7px;
            font-size: .68rem;
            font-weight: 700;
            color: rgba(91, 80, 232, 0.6);
            text-transform: uppercase;
            letter-spacing: .09em;
            padding: 7px 14px 5px;
            border-bottom: 1px solid rgba(91, 80, 232, 0.08);
        }

        .chart-label svg {
            opacity: .7;
            width: 11px;
            height: 11px;
            flex-shrink: 0;
        }

        /* Honest-graph footnote: auto-drawn visual aids can occasionally be
           wrong, and a student who trusts a bad graph over the question's own
           numbers loses marks — own the limitation quietly under every chart. */
        .chart-accuracy-note {
            padding: 6px 14px 8px;
            border-top: 1px solid rgba(91, 80, 232, 0.08);
            font-size: .7rem;
            line-height: 1.45;
            color: #8a8fa8;
        }
        [data-dark] .chart-accuracy-note {
            color: #85858F;
            border-top-color: rgba(255, 255, 255, 0.08);
        }
        /* Hotspot charts aren't inside the labelled card — the note stands alone. */
        .chart-accuracy-note--bare {
            border-top: 0;
            padding: 6px 2px 0;
            margin-bottom: 14px;
        }

        /* Sketch prompt — shown in place of a chart that can't be drawn.
           Sketching a graph yourself beats reading one, so a failed visual aid
           becomes the better exercise rather than a hole in the question. */
        .sketch-axis-chip {
            font-size: .78rem; font-weight: 700; padding: 4px 10px; border-radius: 999px;
            background: rgba(91, 80, 232, .09); color: var(--violet, #5b50e8);
            border: 1px solid rgba(91, 80, 232, .18);
        }
        [data-dark] .sketch-axis-chip {
            background: rgba(255, 255, 255, 0.08); color: #a89ffb;
            border-color: rgba(255, 255, 255, 0.14);
        }

        /* KaTeX formula display in questions */
        .question-formula {
            margin: 0 0 18px 0;
            padding: 14px 18px;
            background: rgba(91, 80, 232, .04);
            border: 1px solid rgba(91, 80, 232, .12);
            border-radius: 12px;
            text-align: center;
            animation: fadeIn .4s ease;
            overflow-x: auto;
        }

        .katex-display {
            margin: 0 !important;
        }

        /* ── Formula highlighting (fxInline / fxLines) ──
           Equations arrive as plain Unicode inside the sentence; the chip
           sets them in a maths face so they read as maths, and the strip
           repeats the stem's equations on their own lines underneath. */
        .fx {
            font-family: 'STIX Two Math', 'Cambria Math', 'Latin Modern Math', Georgia, 'Times New Roman', serif;
            font-style: normal;
            font-size: 1.06em;
            padding: .05em .38em;
            border-radius: 6px;
            background: rgba(91, 80, 232, .08);
            color: inherit;
            box-decoration-break: clone;
            -webkit-box-decoration-break: clone;
            /* A short equation reads as one token, so it never breaks across
               lines; a long one has to wrap or it would overflow a phone. */
            white-space: nowrap;
        }
        .fx.fx-long { white-space: normal; }
        .fx-strip {
            display: flex;
            flex-direction: column;
            gap: 6px;
            margin: -8px 0 18px;
        }
        .fx-line {
            font-family: 'STIX Two Math', 'Cambria Math', 'Latin Modern Math', Georgia, 'Times New Roman', serif;
            font-size: 1.15rem;
            line-height: 1.45;
            padding: 8px 14px;
            border-radius: 10px;
            background: rgba(91, 80, 232, .05);
            border: 1px solid rgba(91, 80, 232, .12);
            color: var(--text-primary);
            overflow-x: auto;
            white-space: nowrap;
            max-width: 100%;
        }
        [data-dark] .fx { background: rgba(157, 148, 255, 0.16); }
        [data-dark] .fx-line { background: rgba(157, 148, 255, 0.08); border-color: rgba(157, 148, 255, 0.22); }

        /* ══════════════════════════════════════════════════════════════
           GENERATION LOADER

           This screen holds a student for 14s (a plain 5-question quiz) to
           77s (a verified 20-question one), so it is not a page load — it is
           a long job someone has to be held through honestly. Three rules
           follow from that, and every choice below serves one of them:

           1. Never imply a finish time we do not have. The rail counts
              STAGES, not percent, and the ghost questions never "complete" —
              we genuinely do not know how many are written yet.
           2. Prove the thing is alive. A pulsing dot alone reads as frozen,
              which is exactly what a student sitting through verification
              reported; the shimmer moves, the stage advances, and past the
              last stage the elapsed count takes over.
           3. Show the shape of what is coming. The ghosts are the real
              question card's proportions, so the wait previews the product
              instead of decorating the absence of it.

           Deliberately NOT a card: the ghosts are cards, and a card of cards
           is the one nesting that always reads as filler.
           ══════════════════════════════════════════════════════════════ */
        .gen {
            max-width: 460px;
            margin: 0 auto;
            text-align: left;
        }

        .gen-head {
            display: flex;
            align-items: center;
            gap: 14px;
            margin-bottom: 18px;
        }

        .gen-title {
            font-family: var(--font-display, var(--font-ui));
            font-size: 1.28rem;
            font-weight: 800;
            line-height: 1.15;
            color: var(--text-primary);
            margin: 0;
            letter-spacing: -.01em;
        }

        /* Their own request, read back to them. The reassurance on a long
           wait is not "please hold" — it is proof we understood the brief. */
        .gen-meta {
            display: flex;
            flex-wrap: wrap;
            gap: 6px;
            margin: 7px 0 0;
        }

        .gen-chip {
            font-size: .72rem;
            font-weight: 700;
            line-height: 1;
            padding: 5px 9px;
            border-radius: 999px;
            color: var(--violet);
            background: rgba(91, 80, 232, .08);
            border: 1px solid rgba(91, 80, 232, .16);
            white-space: nowrap;
        }

        [data-dark] .gen-chip {
            color: #a89ffb;
            background: rgba(255, 255, 255, 0.08);
            border-color: rgba(255, 255, 255, 0.14);
        }

        /* ── Avi, at work in the margin ── */
        .gen-avi {
            position: relative;
            flex: none;
            width: 52px;
            height: 52px;
        }

        .gen-avi-face {
            width: 52px;
            height: 52px;
            display: block;
            border-radius: 15px;
            box-shadow: 0 6px 18px rgba(91, 80, 232, .22);
            /* Deliberately still. The scan ring is anchored to .gen-avi, which
               does not move, so a bobbing face drifted out of the outline the
               shine is meant to be tracing. Avi holds position and the ring
               carries the motion — one moving part, not two fighting. */
            position: relative;
            z-index: 2;
        }

        .gen-avi::after {
            content: '';
            position: absolute;
            left: 50%;
            top: 50%;
            width: 62px;
            height: 62px;
            transform: translate(-50%, -50%);
            background: radial-gradient(circle, rgba(124, 106, 247, .34) 0%, rgba(124, 106, 247, 0) 70%);
            z-index: 1;
            /* Steady, not breathing. The halo sits directly behind a violet
               icon on a violet-tinted ground, so scaling it read as the icon
               itself moving — the thing holding Avi still was meant to stop.
               The travelling ring is the only motion here now. */
        }

        /* A light band of violet travelling down Avi's outline, over and over.
           Built as a 2px ring rather than a glow so it reads as a scan across
           a working machine, not a halo: the gradient is 260% tall and its
           position animates, so the bright part enters at the top, runs down
           and leaves, then comes round again.

           The ring is a padded box masked to its own border — content-box and
           border-box masks composited to cancel — which is what leaves the
           middle transparent so Avi still shows through. */
        .gen-avi-ring {
            position: absolute;
            inset: -4px;
            border-radius: 19px;
            padding: 2.5px;
            z-index: 3;
            pointer-events: none;
            /* A tight band, not a wash: the stops sit close together so the
               shine reads as one travelling highlight, and the drop-shadow
               below blooms it off the ring so it is visible on white. */
            background: linear-gradient(180deg,
                rgba(157, 141, 255, 0) 42%,
                rgba(157, 141, 255, .5) 47%,
                #8f7dff 50%,
                rgba(157, 141, 255, .5) 53%,
                rgba(157, 141, 255, 0) 58%);
            filter: drop-shadow(0 0 5px rgba(157, 141, 255, .85));
            background-size: 100% 260%;
            background-repeat: no-repeat;
            -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            -webkit-mask-composite: xor;
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask-composite: exclude;
            animation: genAviScan 2.8s cubic-bezier(.45, 0, .3, 1) infinite;
        }

        [data-dark] .gen-avi-ring {
            background: linear-gradient(180deg,
                rgba(255, 255, 255, 0.03) 42%,
                rgba(255, 255, 255, 0.18) 47%,
                #ded9ff 50%,
                rgba(255, 255, 255, 0.18) 53%,
                rgba(255, 255, 255, 0.03) 58%);
            background-size: 100% 260%;
            background-repeat: no-repeat;
            filter: drop-shadow(0 0 7px rgba(255, 255, 255, 0.22));
        }

        /* ── Stage rail ──
           Segments, not a percentage bar: we know which STAGE the server is
           in and nothing finer, and a bar that fills smoothly to 90% and
           stops is the lie every one of these screens tells. */
        .gen-rail {
            display: flex;
            gap: 5px;
            margin-bottom: 11px;
        }

        .gen-seg {
            flex: 1;
            height: 6px;
            border-radius: 999px;
            background: rgba(91, 80, 232, .13);
            overflow: hidden;
            position: relative;
        }

        [data-dark] .gen-seg { background: rgba(255, 255, 255, 0.08); }

        .gen-seg--done { background: var(--violet); }
        [data-dark] .gen-seg--done { background: #7d70f6; }

        /* The live stage carries a solid base UNDER the sweep. With the sweep
           alone the segment fell back to track colour at each end of the
           cycle, so the one thing the rail exists to say — which stage is
           running — blinked out twice a second. */
        .gen-seg--active { background: rgba(91, 80, 232, .38); }
        [data-dark] .gen-seg--active { background: rgba(157, 148, 255, 0.42); }

        /* The travelling highlight is the proof of life. Transform only, so
           it never touches layout on a screen that may sit for a minute. */
        .gen-seg--active::after {
            content: '';
            position: absolute;
            inset: 0;
            border-radius: inherit;
            background: linear-gradient(90deg,
                rgba(91, 80, 232, .18) 0%,
                var(--violet) 45%,
                rgba(91, 80, 232, .18) 100%);
            transform: translateX(-100%);
            animation: genSweep 1.5s cubic-bezier(.4, 0, .2, 1) infinite;
        }

        [data-dark] .gen-seg--active::after {
            background: linear-gradient(90deg,
                rgba(157, 148, 255, 0.2) 0%,
                #9d94ff 45%,
                rgba(157, 148, 255, 0.2) 100%);
        }

        .gen-status {
            font-size: .92rem;
            font-weight: 700;
            color: var(--text-primary);
            margin: 0 0 3px;
            transition: opacity .22s ease;
        }

        /* How long the WHOLE thing takes, set once and never counted down.
           The status line above says what is happening now; this says what to
           expect, so a student knows at second three whether to sit and wait
           or go and get a drink. Deliberately vague — "about a minute", not
           "48 seconds" — because a range we can stand behind beats a precise
           number we would miss. */
        .gen-eta {
            font-size: .82rem;
            font-weight: 600;
            color: var(--text-muted);
            margin: 0 0 20px;
        }

        .gen-eta:empty { display: none; }

        /* The two things a student actually wants to know while they wait:
           how big the quiz is, and whether the answer check is running yet.
           Both are FACTS, not animation — the count is their own request read
           back, and the verification cell only exists when that pass will
           genuinely run, exactly like the stage it mirrors on the rail. */
        .gen-facts {
            display: flex;
            gap: 9px;
            margin: 0 0 18px;
        }

        .gen-fact {
            /* flex-basis 0 with min-width 0: a row of equal cells that is
               allowed to shrink. Without min-width a long label sets the
               floor and the row overflows a 390px phone. */
            flex: 1 1 0;
            min-width: 0;
            padding: 10px 12px;
            border-radius: 12px;
            background: rgba(91, 80, 232, .06);
            border: 1px solid rgba(91, 80, 232, .13);
            transition: background .3s ease, border-color .3s ease;
        }

        [data-dark] .gen-fact {
            background: rgba(255, 255, 255, 0.055);
            border-color: rgba(255, 255, 255, 0.14);
        }

        .gen-fact-num {
            display: block;
            font-family: var(--font-display, var(--font-ui));
            font-size: 1.12rem;
            font-weight: 800;
            line-height: 1.15;
            color: var(--text-primary);
            font-variant-numeric: tabular-nums;
            letter-spacing: -.01em;
        }

        .gen-fact-label {
            display: block;
            margin-top: 2px;
            font-size: .74rem;
            font-weight: 600;
            line-height: 1.35;
            color: var(--text-muted);
        }

        /* Lit only while the verification pass is the live stage. */
        .gen-fact--live {
            background: rgba(91, 80, 232, .13);
            border-color: rgba(91, 80, 232, .30);
        }

        [data-dark] .gen-fact--live {
            background: rgba(157, 148, 255, 0.18);
            border-color: rgba(157, 148, 255, 0.38);
        }

        .gen-fact--live .gen-fact-num { color: var(--violet); }
        [data-dark] .gen-fact--live .gen-fact-num { color: #a89ffb; }

        .gen-fact--live .gen-fact-num::before {
            content: '';
            display: inline-block;
            width: 7px;
            height: 7px;
            margin-right: 7px;
            border-radius: 50%;
            vertical-align: middle;
            background: currentColor;
            animation: genFactPulse 1.4s ease-in-out infinite;
        }

        .gen-fact[hidden] { display: none; }

        /* Unverified quizzes have only the count to show, and one cell on
           flex:1 stretches to 460px of mostly empty box. Let it size to its
           own content instead. */
        .gen-facts--solo .gen-fact { flex: 0 1 auto; }

        @keyframes genFactPulse {
            0%, 100% { opacity: 1; transform: scale(1); }
            50%      { opacity: .35; transform: scale(.72); }
        }

        .gen-status--swap { opacity: 0; }

        /* ── The sheet: what is being written ── */
        .gen-sheet {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .gen-q {
            background: var(--card-bg, #fff);
            border: 1px solid rgba(91, 80, 232, .1);
            border-radius: 14px;
            padding: 15px 16px;
            box-shadow: 0 4px 16px rgba(91, 80, 232, .05);
        }

        [data-dark] .gen-q {
            border-color: rgba(255, 255, 255, 0.08);
            box-shadow: 0 4px 16px rgba(0, 0, 0, .28);
        }

        .gen-line {
            display: block;
            height: 9px;
            border-radius: 999px;
            margin-bottom: 8px;
        }

        .gen-line:last-of-type { margin-bottom: 12px; }

        /* One sweep shared by every placeholder: a single animated gradient
           on a common background-size reads as ONE light crossing the sheet
           rather than eight independent shimmers, which is the difference
           between "being written" and "loading spinner, eight times". */
        .gen-line,
        .gen-opts i {
            background: linear-gradient(90deg,
                rgba(91, 80, 232, .09) 0%,
                rgba(91, 80, 232, .19) 50%,
                rgba(91, 80, 232, .09) 100%);
            background-size: 260% 100%;
            animation: genInk 1.9s ease-in-out infinite;
        }

        [data-dark] .gen-line,
        [data-dark] .gen-opts i {
            background: linear-gradient(90deg,
                rgba(255, 255, 255, 0.055) 0%,
                rgba(255, 255, 255, 0.12) 50%,
                rgba(255, 255, 255, 0.055) 100%);
            background-size: 260% 100%;
        }

        .gen-opts {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 7px;
        }

        .gen-opts i {
            height: 26px;
            border-radius: 8px;
        }

        /* Staggered so the sheet fills like writing rather than switching on.
           Each row carries its own delay on the SHARED sweep. */
        .gen-q:nth-child(2) .gen-line,
        .gen-q:nth-child(2) .gen-opts i { animation-delay: .22s; }
        .gen-q:nth-child(3) .gen-line,
        .gen-q:nth-child(3) .gen-opts i { animation-delay: .44s; }

        /* The third ghost is the one that makes the sheet read as a PAPER
           rather than a pair of boxes, and it is also the first thing a
           390px screen cannot afford. */
        .gen-q:nth-child(3) { display: none; }

        @media (min-height: 760px) {
            .gen-q:nth-child(3) { display: block; }
        }

        /* ── Footer: the tip earns the wait, the clock proves it is alive ── */
        .gen-foot {
            display: flex;
            align-items: flex-start;
            justify-content: space-between;
            gap: 14px;
            margin-top: 18px;
        }

        .gen-tip {
            display: flex;
            align-items: flex-start;
            gap: 8px;
            margin: 0;
            font-size: .82rem;
            line-height: 1.5;
            color: var(--text-secondary);
            transition: opacity .4s ease;
        }

        .gen-tip svg {
            flex: none;
            margin-top: 2px;
            color: var(--violet);
        }

        [data-dark] .gen-tip svg { color: #a89ffb; }

        .gen-elapsed {
            flex: none;
            margin: 0;
            font-size: .76rem;
            font-weight: 700;
            color: var(--text-muted);
            font-variant-numeric: tabular-nums;
            white-space: nowrap;
            padding-top: 1px;
        }

        .gen-elapsed[hidden] { display: none; }

        @keyframes genSweep {
            0%   { transform: translateX(-100%); }
            100% { transform: translateX(100%); }
        }

        @keyframes genInk {
            0%   { background-position: 130% 0; }
            100% { background-position: -130% 0; }
        }

        @keyframes genAviScan {
            0%   { background-position: 0 100%; }
            100% { background-position: 0 0%; }
        }

        /* Reduced motion keeps every STATE and drops only the movement: the
           stage rail still fills, the active stage still reads as active. */
        @media (prefers-reduced-motion: reduce) {
            .gen-line,
            .gen-opts i { animation: none; }

            .gen-avi-ring {
                animation: none;
                background: rgba(167, 155, 255, .55);
            }

            .gen-seg--active::after {
                animation: none;
                transform: none;
                background: var(--violet);
                opacity: .55;
            }

            .gen-status { transition: none; }
            .gen-fact--live .gen-fact-num::before { animation: none; }
            .gen-fact { transition: none; }
        }

        @media (max-width: 420px) {
            .gen-title { font-size: 1.15rem; }
            .gen-head { gap: 11px; margin-bottom: 15px; }
            .gen-avi, .gen-avi-face { width: 46px; height: 46px; }
            .gen-foot { flex-direction: column; gap: 9px; }
            .gen-facts { gap: 8px; }
            .gen-elapsed { align-self: flex-start; }
        }

        /* Animated Toggle Switch */
        .toggle-switch {
            position: relative;
            width: 50px;
            height: 27px;
            background: #dde1f0;
            border: none;
            border-radius: 99px;
            cursor: var(--cur-point, pointer);
            transition: background 0.35s cubic-bezier(0.4, 0, 0.2, 1);
            flex-shrink: 0;
            padding: 0;
        }

        .toggle-switch:focus-visible {
            outline: 2px solid var(--violet);
            outline-offset: 2px;
        }

        .toggle-switch[aria-checked="true"] {
            background: linear-gradient(135deg, var(--violet), var(--violet-dim));
        }

        .toggle-thumb {
            position: absolute;
            top: 3.5px;
            left: 3.5px;
            width: 20px;
            height: 20px;
            background: white;
            border-radius: 50%;
            transition: left 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
            box-shadow: 0 1px 5px rgba(0, 0, 0, 0.18);
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .toggle-switch[aria-checked="true"] .toggle-thumb {
            left: 26.5px;
        }

        .timer-preset-label {
            font-size: 0.72rem;
            color: var(--text-muted);
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.05em;
            white-space: nowrap;
        }

        /* Timer disabled state on question card */
        .timer-off-badge {
            display: inline-flex;
            align-items: center;
            gap: 5px;
            background: #f3f4f8;
            border: 1px solid rgba(0, 0, 0, 0.07);
            border-radius: 99px;
            padding: 4px 11px;
            font-size: 0.72rem;
            color: var(--text-muted);
            font-weight: 500;
        }

        /* Flash overlay for timer pulse effects */
        @keyframes timerWarnPulse {

            0%,
            100% {
                background: transparent;
            }

            50% {
                background: rgba(225, 29, 72, 0.04);
            }
        }

        /* Glowing ring enhancement */
        .timer-fill {
            filter: drop-shadow(0 0 4px rgba(91, 80, 232, 0.35));
        }

        /* Enhanced score-chip micro-interaction */
        .score-chip {
            transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
        }

        .score-chip.bump {
            transform: scale(1.15);
        }

        /* ── row-4 for the four settings selects ── */
        .row-4 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 14px;
            margin-top: 16px;
        }

        /* On tablets/phones: 2x2 grid so selects don't squish */
        @media(max-width:580px) {
            .row-4 {
                grid-template-columns: 1fr 1fr;
            }
        }

        @media(max-width:420px) {
            .row-4 {
                grid-template-columns: 1fr;
                gap: 10px;
            }
        }

        /* ── Difficulty badge on question card ── */
        .diff-badge {
            display: inline-flex;
            align-items: center;
            gap: 5px;
            border-radius: 99px;
            padding: 3px 10px;
            font-size: 0.7rem;
            font-weight: 700;
            letter-spacing: .04em;
        }

        .diff-badge.standard {
            background: rgba(91, 80, 232, .07);
            border: 1px solid rgba(91, 80, 232, .15);
            color: var(--violet);
        }

        .diff-badge.hard {
            background: rgba(217, 119, 6, .08);
            border: 1px solid rgba(217, 119, 6, .2);
            color: var(--amber);
        }

        .diff-badge.exam {
            background: rgba(225, 29, 72, .07);
            border: 1px solid rgba(225, 29, 72, .18);
            color: var(--rose);
        }

        /* ── Keyboard hint on option letters ── */
        .opt-letter {
            position: relative;
        }

        .kbd-hint {
            position: absolute;
            bottom: -6px;
            right: -4px;
            font-size: 8px;
            font-weight: 700;
            color: rgba(91, 80, 232, .4);
            background: white;
            border: 1px solid rgba(91, 80, 232, .15);
            border-radius: 3px;
            padding: 0 2px;
            line-height: 1.4;
            opacity: 0;
            transition: opacity .2s;
            pointer-events: none;
        }

        /* Only show keyboard hints on non-touch devices */
        @media(hover: hover) and (pointer: fine) {
            .quiz-active .option:not(.disabled) .kbd-hint {
                opacity: 1;
            }
        }

        /* ── Mobile-specific overrides ── */
        @media(max-width:600px) {

            /* Truncate long sub-labels on narrow screens */
            .sound-sub {
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }

            /* Force label to its own row so buttons get full width */
            .timer-preset-label {
                width: 100%;
            }

            /* Question card: keep timer row single-line on mobile */
            .timer-row {
                flex-wrap: nowrap;
                gap: 8px;
            }

            .score-chip {
                font-size: 0.72rem;
                padding: 4px 8px;
            }

            /* Charts: ensure main chart SVG never overflows card (not the label icon) */
            .question-chart>svg {
                width: 100% !important;
                height: auto !important;
            }

            /* Review panel answers: stack on narrow */
            .review-answers {
                flex-direction: column;
                gap: 6px;
            }

            /* Score stats: smaller font on tiny screens */
            .score-stat-val {
                font-size: 1.4rem;
            }
        }

        .sound-label {
            font-size: .82rem;
            font-weight: 700;
            color: var(--text-primary);
        }

        .sound-sub {
            font-size: .7rem;
            color: var(--text-muted);
            margin-top: 1px;
        }

        /* ── Mistake review panel ── */
        .review-panel {
            display: none;
            margin-top: 20px;
            background: #fff;
            border: 1px solid rgba(225, 29, 72, .15);
            border-radius: 16px;
            padding: 22px 20px;
            box-shadow: 0 4px 20px rgba(225, 29, 72, .06);
            animation: slideUp .4s ease;
        }

        .review-panel h3 {
            font-size: .9rem;
            color: var(--rose);
            font-weight: 700;
            margin-bottom: 14px;
            display: flex;
            align-items: center;
            gap: 7px;
        }

        .review-item {
            padding: 14px 0;
            border-bottom: 1px solid rgba(91, 80, 232, .07);
        }

        .review-item:last-child {
            border-bottom: none;
        }

        .review-q {
            font-size: .875rem;
            font-weight: 600;
            color: var(--text-primary);
            margin-bottom: 8px;
            line-height: 1.5;
        }

        .review-answers {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
            margin-bottom: 7px;
        }

        .review-ans {
            display: inline-flex;
            align-items: center;
            gap: 5px;
            font-size: .78rem;
            font-weight: 600;
            padding: 3px 10px;
            border-radius: 99px;
        }

        .review-ans.wrong-ans {
            background: rgba(225, 29, 72, .07);
            color: var(--rose);
            border: 1px solid rgba(225, 29, 72, .2);
        }

        .review-ans.right-ans {
            background: rgba(5, 150, 105, .07);
            color: var(--emerald);
            border: 1px solid rgba(5, 150, 105, .2);
        }

        .review-exp {
            font-size: .78rem;
            color: var(--text-secondary);
            line-height: 1.6;
        }

        /* ── Daily quiz usage meter ── */
        /* ── Usage dock ─────────────────────────────────────────────────
           Tokens are the app's own: --violet is the accent, --card-* the
           surface, --text-* the type ramp. An earlier pass hard-coded #00795E
           here, which is a DIFFERENT PRODUCT's green — hence a ring that never
           matched anything around it. */
        .usage-dock {
            position: relative; margin: 12px 0 0;
            display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
        }
        /* Opens UPWARD, and the dock is lifted while open. Two reasons, both
           learned the hard way: the Generate button is position:fixed at
           z-index 99, so a panel opening downward paints BEHIND the primary
           CTA and reads as clipped; and the dock carries a reveal transform,
           which makes it a stacking context, so the panel's own z-index could
           never out-rank anything outside it. Lifting the DOCK moves the whole
           context above the button. */
        .usage-dock.is-open { z-index: 120; }

        .usage-ring-btn {
            display: inline-flex; align-items: center; gap: 10px;
            min-height: 44px; padding: 5px 14px 5px 6px;
            border: 1px solid var(--card-border); border-radius: 999px;
            background: var(--card-bg); color: var(--text-primary);
            font: inherit; cursor: pointer;
            transition: border-color .16s ease, background .16s ease,
                        box-shadow .16s ease;
        }
        .usage-ring-btn:hover { border-color: var(--card-border-hover); }
        .usage-ring-btn:focus-visible {
            outline: none;
            border-color: var(--violet);
            box-shadow: 0 0 0 3px var(--violet-glow);
        }
        .usage-ring-btn:active { transform: translateY(.5px); }
        /* Was byte-identical to :focus-visible, so "this popover is open"
           and "this button has keyboard focus" were the same picture. The open
           state is a filled chip; focus stays the ring around it. */
        .usage-ring-btn[aria-expanded="true"] {
            border-color: var(--violet);
            background: var(--violet-glow);
        }
        .usage-ring { width: 28px; height: 28px; flex: none; transform: rotate(-90deg); }
        .usage-ring circle { fill: none; stroke-width: 3.5; }
        .usage-ring-track { stroke: var(--slate-700); }
        .usage-ring-fill {
            stroke: var(--violet); stroke-linecap: round;
            /* r=15.5 -> circumference 97.39; JS sets the spent portion. */
            stroke-dasharray: 97.39; stroke-dashoffset: 0;
            /* The ring was loudest in the state where nothing is wrong. At 100%
               it is a closed, fully saturated violet circle — the densest mark
               on the builder row, heavier than the model pill beside it — and
               that is what a student sees nearly every visit. Weight now tracks
               urgency instead of contradicting it: recede while there is
               plenty, come up to full strength as it runs down. */
            opacity: .58;
            transition: stroke-dashoffset .4s cubic-bezier(.22, 1, .36, 1),
                        stroke .2s ease, opacity .2s ease;
        }
        .usage-dock.warn .usage-ring-fill,
        .usage-dock.full .usage-ring-fill,
        .nav-usage.warn .usage-ring-fill,
        .nav-usage.full .usage-ring-fill { opacity: 1; }
        .usage-dock.warn .usage-ring-fill { stroke: var(--amber); }
        .usage-dock.full .usage-ring-fill { stroke: var(--rose); }
        /* At 0% the arc is empty BY DESIGN — drawing one would claim there is
           something left. So the track carries "you are out": the ring reads
           as a complete rose circle rather than the pale nothing it showed
           before. Same idea one step earlier, where the arc is a sliver the
           track needs to be legible behind. */
        .usage-dock.full .usage-ring-track { stroke: var(--rose); opacity: .34; }
        .usage-dock.warn .usage-ring-track { stroke: var(--amber); opacity: .26; }
        .usage-ring-pct {
            font-size: 1.3rem; font-weight: 650;
            font-variant-numeric: tabular-nums;   /* stops the pill twitching 9%->10% */
            letter-spacing: -.01em;
        }
        .usage-ring-text { font-size: 1.15rem; color: var(--text-muted); }

        /* Fixed and PORTALLED to <body> when open, rather than absolute inside
           the dock. Two ancestor properties were deciding its fate and both
           are outside this component's control: the dock's reveal transform
           makes it a containing block AND a stacking context, so an absolute
           child inherits its clipping and can never out-rank the fixed CTA —
           and if that positioning is ever lost, `left: 0` resolves against the
           document and the panel lands at the page's left edge.
           Positioned from the trigger's rect in JS; see placeDockPop. */
        .usage-panel {
            /* Above .section-page (1003) and the nav (1005). At 1000 it opened
               BEHIND every study-tool pane — the ring reported itself expanded
               and the panel was there in the DOM, but the pane's own controls
               painted over it, so on /flashcards and friends tapping the ring
               appeared to do nothing. placeDockPop already keeps it clear of
               the nav band, so sitting above the nav costs nothing and removes
               the last surface that could cover it. Modals stay far higher
               (2000+). */
            position: fixed; z-index: 1006; left: 0; top: 0;
            width: max-content; min-width: 300px;
            max-width: min(360px, calc(100vw - 32px));
            padding: 12px 14px 13px;
            border: 1px solid var(--card-border); border-radius: 14px;
            background: var(--card-bg);
            box-shadow: 0 1px 2px rgba(14, 18, 32, .04), 0 8px 24px rgba(14, 18, 32, .06);
            transform-origin: bottom left;
            overflow-y: auto; overscroll-behavior: contain;
            animation: usagePanelIn .16s cubic-bezier(.22, 1, .36, 1);
            /* Fixed elements do not inherit the dock's is-open lift, so the
               tint classes are mirrored onto the panel itself. */
        }
        @keyframes usagePanelIn {
            from { opacity: 0; transform: translateY(4px); }
            to   { opacity: 1; transform: none; }
        }
        @media (prefers-reduced-motion: reduce) {
            .usage-panel { animation: none; }
            .usage-ring-fill, .up-bar i { transition: none; }
        }
        .usage-panel[hidden] { display: none; }

        .up-head {
            display: flex; align-items: baseline; justify-content: space-between;
            gap: 12px; margin-bottom: 10px;
        }
        .up-title {
            font-size: .8rem; font-weight: 650; letter-spacing: .04em;
            text-transform: uppercase; color: var(--text-muted);
        }
        .up-more {
            font-size: .8rem; font-weight: 600; color: var(--violet);
            text-decoration: none; white-space: nowrap;
        }
        .up-more:hover { text-decoration: underline; text-underline-offset: 2px; }

        /* Label left, when-it-resets and how-much-is-left right. The middle
           column takes the slack so the percentage always lands on the same
           edge and the eye can run straight down it. */
        .up-row {
            display: grid; grid-template-columns: auto 1fr auto;
            align-items: baseline; gap: 8px; margin-top: 9px;
        }
        .up-label { font-size: .85rem; font-weight: 600; color: var(--text-primary); }
        .up-meta {
            font-size: .78rem; color: var(--text-muted);
            text-align: right; white-space: nowrap;
            overflow: hidden; text-overflow: ellipsis;
        }
        .up-pct {
            font-size: .82rem; font-weight: 650; color: var(--text-secondary);
            font-variant-numeric: tabular-nums; white-space: nowrap;
        }
        /* A hairline, not the old full-width slab. It reads as a measurement
           beside the number rather than competing with it. */
        .up-bar {
            height: 3px; margin-top: 5px; border-radius: 99px;
            background: var(--slate-800); overflow: hidden;
        }
        .up-bar i {
            display: block; height: 100%; width: 0; border-radius: 99px;
            background: var(--violet);
            transition: width .4s cubic-bezier(.22, 1, .36, 1), background .2s ease;
        }
        .up-note {
            margin: 5px 0 1px;
            font-size: .78rem; color: var(--text-muted);
        }
        .up-note[hidden] { display: none; }
        .usage-dock.warn .up-bar i,
        .usage-panel.warn .up-bar i { background: var(--amber); }
        .usage-dock.full .up-bar i,
        .usage-panel.full .up-bar i { background: var(--rose); }

        [data-dark] .usage-ring-track { stroke: rgba(255, 255, 255, 0.14); }
        [data-dark] .up-bar { background: rgba(255, 255, 255, 0.08); }
        [data-dark] .usage-panel,
        [data-dark] .usage-ring-btn { background: #1D1D21; border-color: rgba(255, 255, 255, 0.14); }
        [data-dark] .usage-panel {
            box-shadow: 0 2px 4px rgba(0, 0, 0, .3), 0 8px 24px rgba(0, 0, 0, .35);
        }

        /* ── Model pill + menu ─────────────────────────────────────────────
           The pill shares .usage-ring-btn's recipe; the menu shares
           .usage-panel's (fixed, portalled, placed by placeDockPop). Rows
           follow the model-picker shape — name and one line of character on
           the left, a check on the chosen row — and locked rungs are greyed
           but readable, shown ON PURPOSE so a student can see what they would
           be choosing. Real colours, not opacity: opacity makes contrast a
           function of whatever is behind the element. */
        .model-pick-btn { gap: 7px; padding: 5px 13px 5px 11px; }
        .model-pick-btn[hidden] { display: none; }
        .model-pick-spark { width: 16px; height: 16px; flex: none; color: var(--violet); }
        .model-pick-name { font-size: 1.05rem; font-weight: 650; }
        .model-pick-chev {
            width: 14px; height: 14px; flex: none; color: var(--text-muted);
            transition: transform .16s ease;
        }
        .model-pick-btn[aria-expanded="true"] .model-pick-chev { transform: rotate(180deg); }

        .model-menu { padding: 6px; }
        .model-menu-list { display: flex; flex-direction: column; gap: 2px; }
        .model-opt {
            display: flex; align-items: center; justify-content: space-between;
            gap: 12px; width: 100%; padding: 9px 10px; box-sizing: border-box;
            border: 0; border-radius: 10px; background: transparent;
            font: inherit; text-align: left; cursor: pointer;
            transition: background .14s ease;
        }
        .model-opt:hover { background: rgba(91, 80, 232, .07); }
        .model-opt:focus-visible { outline: 2px solid var(--violet); outline-offset: -2px; }
        .model-opt-name {
            display: flex; align-items: center; gap: 7px;
            font-size: .95rem; font-weight: 650; color: var(--text-primary);
            line-height: 1.25;
        }
        .model-opt-mult {
            font-size: .68rem; font-weight: 650;
            color: var(--text-muted); border: 1px solid var(--card-border);
            border-radius: 5px; padding: 0 5px 1px;
        }
        .model-opt-desc {
            display: block; margin-top: 1px;
            font-size: .8rem; color: var(--text-muted); line-height: 1.4;
        }
        .model-opt-check { width: 16px; height: 16px; flex: none; color: var(--violet); opacity: 0; }
        .model-opt[aria-checked="true"] .model-opt-check { opacity: 1; }
        .model-opt[aria-disabled="true"] { cursor: default; }
        .model-opt[aria-disabled="true"]:hover { background: transparent; }
        .model-opt[aria-disabled="true"] .model-opt-name { color: var(--text-muted); }
        .model-opt-lock { width: 14px; height: 14px; flex: none; color: var(--text-muted); }

        .model-menu-plans {
            display: block; padding: 7px 10px 6px;
            font-size: .8rem; font-weight: 650; color: var(--violet);
            text-decoration: none; border-radius: 8px;
        }
        .model-menu-plans:hover {
            background: rgba(91, 80, 232, .07);
            text-decoration: underline; text-underline-offset: 2px;
        }
        .model-menu-plans[hidden] { display: none; }

        .model-menu-foot {
            padding: 8px 10px 4px; border-top: 1px solid var(--card-border);
            font-size: .78rem; color: var(--text-muted);
        }
        .model-menu-foot[hidden] { display: none; }

        [data-dark] .model-opt:hover,
        [data-dark] .model-menu-plans:hover { background: rgba(255, 255, 255, 0.055); }
        [data-dark] .model-opt[aria-disabled="true"]:hover { background: transparent; }
        /* Brand violet on the dark panel is 2.9:1 — under the 3:1 non-text
           minimum — so the two indicators that carry state lighten up. */
        [data-dark] .model-opt-check { color: #9a91ff; }
        [data-dark] .model-opt:focus-visible { outline-color: #9a91ff; }

        .usage-cost {
            margin-top: 9px; font-size: .78rem; color: var(--text-muted);
        }

        .usage-meter {
            margin-top: 18px;
            padding: 14px 16px;
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, .1);
            border-radius: 12px;
            transition: border-color .3s, background .3s;
        }

        .usage-meter.warn {
            background: rgba(217, 119, 6, .04);
            border-color: rgba(217, 119, 6, .22);
        }

        .usage-meter.full {
            background: rgba(225, 29, 72, .04);
            border-color: rgba(225, 29, 72, .22);
        }

        .usage-meter-top {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 10px;
        }

        .usage-meter-label {
            font-size: .75rem;
            font-weight: 700;
            color: var(--text-muted);
            text-transform: uppercase;
            letter-spacing: .06em;
            display: flex;
            align-items: center;
            gap: 6px;
        }

        .usage-meter-count {
            font-size: .82rem;
            font-weight: 700;
            color: var(--text-secondary);
        }

        .usage-meter.warn .usage-meter-count {
            color: var(--amber);
        }

        .usage-meter.full .usage-meter-count {
            color: var(--rose);
        }

        .usage-dots {
            display: flex;
            gap: 5px;
            margin-bottom: 10px;
        }

        .usage-dot {
            flex: 1;
            height: 5px;
            border-radius: 99px;
            background: rgba(91, 80, 232, .12);
            transition: background .3s;
        }

        .usage-dot.used {
            background: var(--violet);
        }

        .usage-meter.warn .usage-dot.used {
            background: var(--amber);
        }

        .usage-meter.full .usage-dot.used {
            background: var(--rose);
        }

        .usage-msg {
            font-size: .75rem;
            color: var(--text-muted);
            font-weight: 500;
        }

        /* Credit meter: a single remaining-balance bar replaces the per-quiz
           dots for signed-in accounts (2,000+ credits cannot be dots). */
        .usage-bar {
            height: 6px;
            border-radius: 99px;
            background: rgba(91, 80, 232, .12);
            overflow: hidden;
            margin-bottom: 8px;
        }
        .usage-bar i {
            display: block;
            height: 100%;
            border-radius: 99px;
            background: var(--violet);
            transition: width .3s ease;
        }
        .usage-meter.warn .usage-bar i { background: var(--amber); }
        .usage-meter.full .usage-bar i { background: var(--rose); }
        .usage-burst {
            font-size: .72rem;
            color: var(--text-muted);
            font-weight: 600;
            margin-top: 4px;
        }
        .usage-cost {
            font-size: .74rem;
            color: var(--violet);
            font-weight: 700;
            margin-top: 6px;
        }
        [data-dark] .usage-cost { color: #b9b2ff; }

        /* The way out of a refusal, shown only once a limit is actually met.
           A .usage-* class, not a builder- or pane-specific one, because both
           meters are the same component and this line has to look identical
           in both. 32px min-height is the tap target — it is a link a blocked
           student is meant to hit on a phone. */
        .usage-upgrade {
            display: inline-flex;
            align-items: center;
            min-height: 32px;
            margin-top: 6px;
            color: var(--violet);
            font-size: .78rem;
            font-weight: 800;
            text-decoration: none;
        }
        .usage-upgrade:hover { text-decoration: underline; }
        [data-dark] .usage-upgrade { color: #b9b2ff; }
        .usage-upgrade[hidden] { display: none; }

        /* Top of the ladder: the same slot, saying why there is no link. */
        .usage-topplan {
            display: block;
            margin-top: 6px;
            font-size: .72rem;
            color: var(--text-muted);
            font-weight: 600;
        }
        .usage-topplan[hidden] { display: none; }

        .usage-meter.warn .usage-msg {
            color: var(--amber);
            font-weight: 600;
        }

        .usage-meter.full .usage-msg {
            color: var(--rose);
            font-weight: 700;
        }

        /* ── Loading tip ── */
        .loading-tip {
            margin-top: 18px;
            padding: 12px 14px;
            background: rgba(91, 80, 232, .05);
            border: 1px solid rgba(91, 80, 232, .1);
            border-radius: 12px;
            font-size: .8rem;
            color: var(--text-secondary);
            line-height: 1.55;
            text-align: left;
            min-height: 52px;
            transition: opacity .4s ease;
        }

        .loading-tip-label {
            font-size: .68rem;
            font-weight: 700;
            color: var(--violet);
            text-transform: uppercase;
            letter-spacing: .06em;
            margin-bottom: 4px;
        }

        /* ── Streak section in score card ── */
        .streak-section {
            margin: 18px 0;
            padding: 16px;
            background: linear-gradient(135deg, rgba(91, 80, 232, .05), rgba(91, 80, 232, .02));
            border: 1px solid rgba(91, 80, 232, .1);
            border-radius: 16px;
            text-align: center;
        }

        .streak-headline {
            font-size: 1.6rem;
            font-weight: 900;
            margin-bottom: 4px;
        }

        .streak-sub {
            font-size: .8rem;
            color: var(--text-muted);
            margin-bottom: 12px;
        }

        .week-dots {
            display: flex;
            justify-content: center;
            gap: 6px;
        }

        .week-dot {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 4px;
        }

        .week-dot-circle {
            width: 28px;
            height: 28px;
            border-radius: 50%;
            background: rgba(91, 80, 232, .08);
            border: 1.5px solid rgba(91, 80, 232, .14);
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: .65rem;
            font-weight: 700;
            color: var(--text-muted);
            transition: all .3s;
        }

        .week-dot-circle.active {
            background: var(--violet);
            border-color: var(--violet);
            color: white;
            box-shadow: 0 2px 8px rgba(91, 80, 232, .3);
        }

        .week-dot-circle.today {
            border-color: var(--violet);
            color: var(--violet);
        }

        .week-dot-label {
            font-size: .62rem;
            color: var(--text-muted);
            font-weight: 600;
        }

        /* ── Dashboard (stats + achievements — nav button & side menu) ── */
        .dash-head {
            display: flex;
            align-items: center;
            justify-content: space-between;
            flex-wrap: wrap;
            gap: 8px;
            margin-bottom: 20px;
        }

        .dash-head h2 {
            margin-bottom: 0;
        }

        /* Plain text, not a pill. A violet chip on the heading's line read
           as something you could press; the date is a caption for the page. */
        .dash-date {
            font-size: .82rem;
            font-weight: 700;
            color: var(--text-muted);
        }

        /* ── Standing ──────────────────────────────────────────────────
           The four measures the dashboard now leads with. Deliberately not
           tiles: a tinted card per number turns a measurement into a
           scoreboard, and this page has to say where the student stands
           before it decorates. One hairline-divided row with clear numbers and
           readable labels. No colour on the numbers, and nothing here is
           ever red — a drop is information, not a telling-off. */
        .dash-standing .ds-row {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            border-top: 1px solid var(--study-line, rgba(14, 18, 32, .09));
            border-bottom: 1px solid var(--study-line, rgba(14, 18, 32, .09));
        }

        .dash-standing .ds-cell {
            min-width: 0;
            padding: 22px 18px;
            border-left: 1px solid var(--study-line, rgba(14, 18, 32, .09));
        }

        .dash-standing .ds-cell:first-child {
            padding-left: 2px;
            border-left: 0;
        }

        .dash-standing .ds-val {
            display: flex;
            align-items: baseline;
            gap: 8px;
            font-family: var(--font-display, var(--font-ui));
            font-size: 2.25rem;
            font-weight: 700;
            line-height: 1;
            color: var(--study-ink, var(--text-primary));
            font-variant-numeric: tabular-nums;
        }

        .dash-standing .ds-delta {
            font-family: var(--font-body, var(--font-ui));
            font-size: .8rem;
            font-weight: 700;
            color: var(--text-muted);
            white-space: nowrap;
        }

        .dash-standing .ds-label {
            margin-top: 8px;
            font-size: .78rem;
            font-weight: 600;
            letter-spacing: 0;
            text-transform: none;
            color: var(--study-muted, var(--text-muted));
        }

        .dash-standing .ds-note {
            margin: 12px 0 0;
            font-size: .84rem;
            color: var(--study-muted, var(--text-muted));
        }

        /* Coverage, one hairline row per subject — part of Standing, not a
           card of its own: it answers the question the four numbers raise
           ("tested on what?") and belongs in the same block. */
        .dash-standing .ds-cov-row {
            display: flex;
            align-items: center;
            gap: 12px;
            width: 100%;
            min-height: 52px;
            padding: 12px 2px;
            border: 0;
            border-bottom: 1px solid var(--study-line, rgba(14, 18, 32, .09));
            background: none;
            font: inherit;
            text-align: left;
            cursor: var(--cur-point, pointer);
        }

        .dash-standing .ds-cov-subject {
            font-weight: 800;
            font-size: .95rem;
            color: var(--study-ink, var(--text-primary));
        }

        .dash-standing .ds-cov-meta {
            margin-left: auto;
            font-size: .84rem;
            font-weight: 700;
            color: var(--study-muted, var(--text-muted));
            font-variant-numeric: tabular-nums;
        }

        .dash-standing .ds-cov-arrow {
            color: var(--study-accent, var(--violet));
            font-weight: 800;
        }

        @media (hover: hover) {
            .dash-standing .ds-cov-row:hover .ds-cov-subject { color: var(--study-accent, var(--violet)); }
        }

        /* #statsPage-qualified: .study-tool-page's own :is(button,...):focus-visible
           in study-tools.css ties this rule's specificity and loads later, so an
           unqualified selector here never wins — the offset silently read 3px
           and dark mode silently read #b9b2ff instead of the values below. */
        #statsPage .dash-standing .ds-cov-row:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
            border-radius: 8px;
        }

        [data-dark] #statsPage .dash-standing .ds-cov-row:focus-visible { outline-color: #9d94ff; }

        /* Four across is a ticker tape on a phone. 2x2 keeps every number at
           full size and every label on one line. */
        @media (max-width: 560px) {
            .dash-standing .ds-row {
                grid-template-columns: repeat(2, 1fr);
            }

            .dash-standing .ds-cell {
                padding: 15px 14px;
            }

            .dash-standing .ds-cell:nth-child(odd) {
                padding-left: 2px;
                border-left: 0;
            }

            .dash-standing .ds-cell:nth-child(n+3) {
                border-top: 1px solid var(--study-line, rgba(14, 18, 32, .09));
            }

            .dash-standing .ds-val {
                font-size: 2rem;
            }
        }

        /* Two quiet doors out of the dashboard: the mark calculator, which
           used to open with a full-width button above the numbers, and
           /insights, a real page nothing linked to. Text, not pills —
           neither of them is what this page is about. */
        .dash-links {
            display: flex;
            flex-wrap: wrap;
            gap: 8px 20px;
            margin: -8px 0 22px;
        }

        .dash-link {
            padding: 0;
            border: 0;
            background: none;
            font-family: inherit;
            font-size: .86rem;
            font-weight: 800;
            color: var(--violet);
            text-decoration: none;
            cursor: var(--cur-point, pointer);
        }

        .dash-link:hover {
            text-decoration: underline;
        }


        /* The Up next card, on the dashboard's own surface. #upNext borrows
           the Today strip's flat-card rule; the study-workspace tokens are
           that rule's equivalent here, so the two read as one component in
           two rooms rather than two components that nearly match. */
        #dashUpNext {
            display: flex;
            flex-direction: column;
            gap: 9px;
            margin-bottom: 24px;
            padding: 16px 18px;
            border: 1px solid var(--study-line, rgba(14, 18, 32, .09));
            border-radius: 20px;
            background: var(--study-surface, #fff);
            box-shadow: var(--study-shadow-small, 0 1px 2px rgba(14, 18, 32, .04));
        }

        #dashUpNext[hidden] { display: none; }

        /* On the dashboard the card is 1080px of ONE column: the primary
           recommendation ran to a 1000px line and the alternatives queued
           underneath it. Two columns give the recommendation a readable
           measure and put the other options beside it rather than after it.
           Scoped to #dashUpNext — the home strip's copy of .up-next is
           narrow and keeps its single column, as does the phone.

           The gate is .un-alts: with nothing for the second column (a brand
           new account's zero state, or a single ranked action) the card
           stays one column and the primary keeps the full width. */
        @media (min-width: 900px) {
            #dashUpNext:has(.un-alts) {
                display: grid;
                grid-template-columns: minmax(0, 56fr) minmax(0, 44fr);
                align-items: start;
                column-gap: 30px;
                row-gap: 9px;
            }

            #dashUpNext:has(.un-alts) > .un-eyebrow {
                grid-column: 1;
                grid-row: 1;
            }

            #dashUpNext:has(.un-alts) > .un-primary {
                grid-column: 1;
                grid-row: 2;
            }

            /* Row 2, so the list starts level with the primary's title
               rather than with the eyebrow above it. */
            #dashUpNext:has(.un-alts) > .un-alts {
                grid-column: 2;
                grid-row: 2;
                margin: 0 -8px;
            }

            /* Stacked, the first row's hairline separates the list from the
               primary. Beside it, it is a line above nothing. */
            #dashUpNext:has(.un-alts) > .un-alts > .un-row:first-child {
                border-top: 0;
            }
        }

        /* The card's own hairline rather than a violet one — the rows are a
           list inside the card, not four tinted things. */
        #dashUpNext .un-row {
            border-top-color: var(--study-line, rgba(14, 18, 32, .09));
        }

        /* 40px between sections. The heads carry it; the two blocks with no
           head of their own carry theirs. */
        /* `auto` on the sides, not 0: .study-tool-page > * centres every
           child in the 1080px column with auto margins, and a shorthand that
           zeroed them dropped the block 35px to the left. That is exactly
           what had happened to #dashLevel. */
        #statsPage .dash-sec-head { margin: 40px auto 16px; }
        #statsPage .dash-standing + .dash-sec-head { margin-top: 32px; }

        /* ── Dashboard upgrade card ──
           Same shell as the Up next card above it — surface, 14px radius, the
           dashboard's own padding — so it reads as another panel of the app
           rather than an ad dropped into it. One accent: the CTA. No gradient,
           no glow, no second call to action. */
        .dash-upsell {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 20px;
            max-width: 1080px;
            margin: 28px auto 0;
            padding: 18px 22px;
            border: 1px solid var(--card-border);
            border-radius: 14px;
            background: var(--card-bg);
        }

        .dash-upsell[hidden] { display: none; }

        .du-text { min-width: 0; }

        .du-title {
            display: flex;
            align-items: center;
            gap: 7px;
            margin: 0;
            font-family: var(--font-ui);
            font-size: 1rem;
            font-weight: 700;
            line-height: 1.3;
            color: var(--text-primary);
        }

        /* The whole premium cue: one small mark, in the brand colour, on the
           title. A kicker above it just said the plan name a second time. */
        .du-spark { width: 15px; height: 15px; flex: none; color: var(--violet); }

        [data-dark] .du-spark { color: #9d94ff; }

        .du-body {
            margin: 4px 0 0;
            font-size: .85rem;
            line-height: 1.45;
            color: var(--text-secondary);
        }

        /* Their own number, not a claim about the plan. */
        .du-usage {
            margin: 7px 0 0;
            font-size: .8rem;
            font-weight: 600;
            color: var(--text-muted);
        }

        .du-usage[hidden] { display: none; }

        .du-cta {
            flex: none;
            padding: 9px 16px;
            border-radius: 10px;
            background: var(--violet);
            color: #fff;
            font-size: .85rem;
            font-weight: 700;
            text-decoration: none;
            white-space: nowrap;
            transition: filter .15s ease;
        }

        .du-cta:hover { filter: brightness(1.08); }
        .du-cta:focus-visible { outline: 3px solid var(--violet); outline-offset: 2px; }
        [data-dark] .du-cta:focus-visible { outline-color: #9d94ff; }

        /* Close to the ceiling: the card earns a little more presence, and the
           usage line stops being the quietest thing on it. Emphasis only — no
           countdown, no colour-coded alarm, no change of message. */
        .dash-upsell.is-tight { border-color: var(--card-border-hover, var(--violet)); }
        .dash-upsell.is-tight .du-usage { color: var(--text-secondary); }

        [data-dark] .dash-upsell { background: #1D1D21; border-color: rgba(255, 255, 255, 0.08); }
        [data-dark] .dash-upsell.is-tight { border-color: rgba(157, 148, 255, .38); }

        /* A phone reads it as a stack: text, then one full-width action. The
           row would otherwise squeeze the title to three words and pin the
           button against the edge. */
        @media (max-width: 620px) {
            .dash-upsell {
                flex-direction: column;
                align-items: stretch;
                gap: 14px;
                padding: 16px 18px;
            }

            .du-cta { text-align: center; }
        }
        #statsPage #dashDaily { margin-top: 40px; }
        #statsPage #dashLevel { margin: 2px auto 14px; }
        #statsPage #accuracyTrendChart .trend-chart-card { margin-bottom: 0; }

        /* Two short cards, each with a column of dead space beside it. Above
           1100 they share a row; below it they stack exactly as before, and
           the children keep their own 40px so the collapsed margin is
           unchanged. */
        @media (min-width: 1100px) {
            #statsPage .dash-pair {
                display: grid;
                grid-template-columns: 1fr 1fr;
                align-items: start;
                gap: 24px;
                margin-top: 40px;
            }

            #statsPage .dash-pair #dashDaily,
            #statsPage .dash-pair .dash-sec-head {
                margin-top: 0;
            }
        }

        /* Section headers — icon, title and optional count. */
        .dash-sec-head {
            display: flex;
            align-items: center;
            gap: 8px;
            margin-bottom: 12px;
        }

        .dash-sec-head svg {
            color: var(--violet);
            flex-shrink: 0;
        }

        .dash-sec-title {
            font-size: 1rem;
            font-weight: 700;
            color: var(--text-secondary);
            text-transform: none;
            letter-spacing: -.015em;
        }

        .dash-count-pill {
            margin-left: auto;
            font-size: .72rem;
            font-weight: 800;
            color: var(--amber);
            background: var(--amber-bg);
            border: 1px solid var(--amber-border);
            border-radius: 999px;
            padding: 3px 11px;
        }

        .dash-ach-progress {
            height: 7px;
            border-radius: 99px;
            background: rgba(91, 80, 232, .1);
            overflow: hidden;
            margin-bottom: 14px;
        }

        .dash-ach-progress span {
            display: block;
            height: 100%;
            border-radius: 99px;
            background: linear-gradient(90deg, var(--amber), #f59e0b);
            transition: width .6s ease;
        }

        /* The gradient banner was the loudest thing on a page about
           accuracy, and the least important thing on it. Same renderer, same
           geometry — a hairline card, one violet ring and one violet fill.
           (#accountPage restyles the same card its own way, one screen
           over.) */
        #dashLevel .level-card {
            background: var(--study-surface, var(--card-bg, #fff));
            border: 1px solid var(--study-line, rgba(14, 18, 32, .09));
            box-shadow: var(--study-shadow-small, 0 1px 2px rgba(14, 18, 32, .04));
            color: var(--study-ink, var(--text-primary));
        }

        #dashLevel .level-ring {
            background: var(--violet);
            border-color: var(--violet);
            color: #fff;
        }

        #dashLevel .level-bar {
            background: rgba(91, 80, 232, .12);
        }

        #dashLevel .level-bar-fill {
            background: var(--violet);
            box-shadow: none;
        }

        #dashLevel .level-title .lt-sub,
        #dashLevel .level-xp {
            color: var(--study-muted, var(--text-muted));
            opacity: 1;
        }

        [data-dark] #dashLevel .level-bar {
            background: rgba(255, 255, 255, 0.08);
        }

        /* Five tiles across left a sixth slot of white at 1440. */
        #dashAchGrid {
            grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
        }

        #dashAchGrid .ach-card {
            gap: 10px;
            padding: 10px 12px;
        }

        /* Accuracy trend card — a light violet-tinted surface sized to host
           an SVG sparkline. */
        .trend-chart-card {
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, .1);
            border-radius: 16px;
            padding: 16px 16px 12px;
            margin-bottom: 22px;
        }

        /* Header row inside the accuracy-trend card: window size + average
           on the left, an honest improving/declining chip on the right */
        .trend-head {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 10px;
            margin-bottom: 10px;
        }

        .trend-title {
            font-size: .82rem;
            font-weight: 800;
            color: var(--text-primary);
        }

        .trend-sub {
            font-size: .7rem;
            font-weight: 600;
            color: var(--text-muted);
            margin-top: 1px;
        }

        .trend-delta {
            font-size: .74rem;
            font-weight: 800;
            padding: 4px 11px;
            border-radius: 99px;
            white-space: nowrap;
        }

        /* One hue. "Improving" in green made the same measurement read as
           a verdict, and put the page's only green on its loudest chip. */
        .trend-delta.up {
            color: var(--violet);
            background: rgba(91, 80, 232, .1);
            border: 1px solid rgba(91, 80, 232, .18);
        }

        .trend-delta.down {
            color: var(--text-muted);
            background: rgba(91, 80, 232, .06);
            border: 1px solid rgba(91, 80, 232, .14);
        }

        .trend-delta.flat {
            color: var(--text-muted);
            background: rgba(91, 80, 232, .06);
            border: 1px solid rgba(91, 80, 232, .14);
        }

        /* 480x190 of viewBox stretched across a 1046px card drew a 414px
           chart with 22px axis labels — a poster of a sparkline. Capping the
           height leaves buildAccuracyTrendChart's viewBox arithmetic alone:
           preserveAspectRatio fits the plot inside the shorter box (543x215,
           centred) and its type comes back to ~11px. It has to be the HEIGHT
           — the svg carries style="max-width:100%" inline, and an inline
           declaration outranks any selector. 215 rather than the 260 the
           spec allows: 260 would put the card at 335px, over its own 300
           ceiling. */
        #accuracyTrendChart .trend-chart-card > svg {
            max-height: 215px;
            margin: 0 auto;
        }

        @media (max-width: 560px) {
            #accuracyTrendChart .trend-chart-card > svg {
                max-width: 100%;
                max-height: 200px;
            }
        }

        [data-dark] .trend-delta.up,
        [data-dark] .trend-delta.down,
        [data-dark] .trend-delta.flat {
            color: #9d94ff;
            background: rgba(255, 255, 255, 0.055);
            border-color: rgba(255, 255, 255, 0.14);
        }

        /* ── Study Activity heatmap (stats page) ── */
        .heatmap-card {
            background: #f8f9ff;
            border: 1px solid rgba(91, 80, 232, .1);
            border-radius: 12px;
            padding: 16px 14px 14px;
            margin-bottom: 22px;
        }
        .heatmap-scroll {
            display: flex;
            align-items: stretch;
            gap: 6px;
            overflow-x: auto;
            padding-bottom: 2px;
        }
        .heatmap-daylabels {
            display: grid;
            grid-template-rows: repeat(7, 13px);
            gap: 3px;
            flex-shrink: 0;
        }
        .heatmap-daylabels span {
            font-size: .6rem;
            line-height: 13px;
            color: var(--text-muted);
        }
        .heatmap-grid {
            display: grid;
            grid-template-rows: repeat(7, 13px);
            grid-auto-flow: column;
            grid-auto-columns: 13px;
            gap: 3px;
        }
        .heatmap-cell {
            width: 13px;
            height: 13px;
            border-radius: 3px;
            background: rgba(91, 80, 232, .07);
        }
        .heatmap-cell[data-level="-1"] { background: transparent; }
        .heatmap-cell[data-level="1"] { background: rgba(91, 80, 232, .28); }
        .heatmap-cell[data-level="2"] { background: rgba(91, 80, 232, .5); }
        .heatmap-cell[data-level="3"] { background: rgba(91, 80, 232, .74); }
        .heatmap-cell[data-level="4"] { background: var(--violet); }
        .heatmap-cell[data-today="1"] { box-shadow: 0 0 0 1.5px var(--violet-dim); }
        .heatmap-footer {
            display: flex;
            align-items: center;
            justify-content: space-between;
            flex-wrap: wrap;
            gap: 8px;
            margin-top: 12px;
            font-size: .72rem;
            color: var(--text-muted);
        }
        .heatmap-legend {
            display: inline-flex;
            align-items: center;
            gap: 3px;
        }
        .heatmap-legend span {
            display: inline-block;
            width: 11px;
            height: 11px;
            border-radius: 3px;
            vertical-align: -2px;
            background: rgba(91, 80, 232, .07);
        }
        .heatmap-legend span[data-level="1"] { background: rgba(91, 80, 232, .28); }
        .heatmap-legend span[data-level="2"] { background: rgba(91, 80, 232, .5); }
        .heatmap-legend span[data-level="3"] { background: rgba(91, 80, 232, .74); }
        .heatmap-legend span[data-level="4"] { background: var(--violet); }

        .written-answer-wrap {
            margin-top: 4px;
        }

        .written-textarea {
            width: 100%;
            min-height: 100px;
            padding: 12px 14px;
            background: #f8f9ff;
            border: 1.5px solid rgba(91, 80, 232, .14);
            border-radius: 12px;
            font-family: var(--font-ui);
            font-size: .9rem;
            color: var(--text-primary);
            resize: vertical;
            line-height: 1.6;
            transition: border-color .2s, box-shadow .2s;
        }

        .written-textarea:focus-visible {
            border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, .08);
        }

        .btn-grade {
            width: 100%;
            margin-top: 10px;
            padding: 12px;
            background: linear-gradient(135deg, var(--violet), var(--violet-dim));
            border: none;
            border-radius: 999px;
            color: white;
            font-family: var(--font-ui);
            font-size: .9rem;
            font-weight: 700;
            cursor: var(--cur-point, pointer);
            transition: all .18s;
        }

        .btn-grade:hover {
            transform: translateY(-1px);
            box-shadow: 0 6px 20px rgba(91, 80, 232, .35);
        }

        .btn-grade:disabled {
            opacity: .55;
            cursor: not-allowed;
            transform: none;
        }

        .grade-result {
            margin-top: 14px;
            padding: 14px 16px;
            border-radius: 12px;
            font-size: .875rem;
            line-height: 1.65;
            border-left: 3px solid;
            animation: fadeIn .35s ease;
        }

        .grade-result.correct-exp {
            background: rgba(5, 150, 105, .06);
            border-color: var(--emerald);
            color: #065f46;
        }

        .grade-result.partial-exp {
            background: rgba(217, 119, 6, .06);
            border-color: var(--amber);
            color: #92400e;
        }

        .grade-result.wrong-exp {
            background: rgba(225, 29, 72, .05);
            border-color: var(--rose);
            color: #9f1239;
        }

        .grade-badge {
            display: inline-flex;
            align-items: center;
            gap: 5px;
            font-size: .72rem;
            font-weight: 700;
            padding: 2px 9px;
            border-radius: 99px;
            margin-bottom: 8px;
        }

        .grade-badge.correct {
            background: rgba(5, 150, 105, .12);
            color: var(--emerald);
        }

        .grade-badge.partial {
            background: rgba(217, 119, 6, .12);
            color: var(--amber);
        }

        .grade-badge.wrong {
            background: rgba(225, 29, 72, .1);
            color: var(--rose);
        }

        /* The written verdict box had no dark rules at all, so its light ink
           (#065f46 / #92400e / #9f1239) was being painted on the dark card.
           Mirrors the explanation box's own dark palette. */
        [data-dark] .grade-result.correct-exp {
            background: rgba(5, 150, 105, .12);
            color: #6ee7b7;
        }

        [data-dark] .grade-result.partial-exp {
            background: rgba(217, 119, 6, .1);
            color: #fcd34d;
        }

        [data-dark] .grade-result.wrong-exp {
            background: rgba(225, 29, 72, .1);
            color: #fca5a5;
        }

        /* ── Self-marking a written answer ──
           The chip row is the builder's segmented control at the same 44px, so
           marking your own answer feels like the same product as setting up the
           quiz. Violet is the mark you chose; red stays reserved for a miss. */
        .self-mark {
            background: rgba(91, 80, 232, .04);
            border-left-color: rgba(91, 80, 232, .35);
        }

        [data-dark] .self-mark {
            background: rgba(255, 255, 255, 0.03);
            border-left-color: rgba(255, 255, 255, 0.22);
        }

        .sm-label {
            margin-bottom: 6px;
            color: var(--text-muted);
            font-size: .72rem;
            font-weight: 800;
            letter-spacing: .1em;
            text-transform: uppercase;
        }

        .sm-model {
            color: var(--text-primary);
            font-size: .9rem;
            line-height: 1.6;
            /* A model answer can be a single unbroken token (a formula, a
               URL) — same guard as .acct-email / .dbr-slug, so it wraps
               instead of being clipped by the card's overflow. */
            overflow-wrap: anywhere;
        }

        .sm-ask {
            margin: 16px 0 8px;
            color: var(--text-primary);
            font-size: .9rem;
            font-weight: 800;
        }

        /* One chip per mark: 0…max, however many marks that is. The class has
           to beat .preset-switch's own four-column track, which is declared
           later in the sheet, so it is qualified rather than bare. Capped so a
           five-chip row stays a control the eye reads at once instead of
           stretching the width of a desktop card. */
        .preset-switch.sm-chips {
            grid-template-columns: repeat(auto-fit, minmax(44px, 1fr));
            max-width: 360px;
            /* .preset-switch's 999px radius auto-clamps to a pill on its usual
               single row (~56px tall). A 10-mark question wraps this to three
               rows, and 999px then clamps to that taller box's own half-height
               instead — an oval, not a pill. 28px is that single-row clamp
               written out, so one row looks identical and three don't balloon. */
            border-radius: 28px;
        }

        .sm-chips .preset-opt[aria-checked="true"],
        [data-dark] .sm-chips .preset-opt[aria-checked="true"] {
            background: var(--violet);
            box-shadow: none;
            color: #fff;
        }

        .sm-verdict,
        .sm-compare {
            font-size: .95rem;
            font-weight: 800;
        }

        .sm-compare {
            margin-bottom: 8px;
        }

        .sm-link {
            display: inline-block;
            /* Vertical padding rather than a bigger font: it makes the tap
               target 44px on a phone while the link stays a link. */
            padding: 12px 0;
            border: 0;
            background: none;
            color: var(--violet);
            font-family: var(--font-ui);
            font-size: .86rem;
            font-weight: 800;
            line-height: 20px;
            text-align: left;
            cursor: var(--cur-point, pointer);
        }

        [data-dark] .sm-link {
            color: #9d94ff;
        }

        .sm-link:disabled {
            opacity: .55;
            cursor: not-allowed;
        }

        .sm-link:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 3px;
            border-radius: 6px;
        }

        [data-dark] .sm-link:focus-visible {
            outline-color: #9d94ff;
        }

        /* On the debrief, #writtenMarksCheck is a .sm-link too, but
           `#scoreCard :focus-visible` (ID specificity) otherwise beats the
           rule above and rings it 2px in the tier colour instead of the
           standard 3px violet — the same class of defeat .preset-switch.sm-chips
           already had to be qualified against. */
        #scoreCard .sm-link:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 3px;
            border-radius: 6px;
        }

        [data-dark] #scoreCard .sm-link:focus-visible {
            outline-color: #9d94ff;
        }

        @media (hover: hover) {
            .sm-link:hover:not(:disabled) {
                text-decoration: underline;
            }
        }

        /* ── The same marks, listed on the debrief ── */
        .written-marks {
            margin: 18px 0 4px;
            text-align: left;
        }

        .wm-title {
            margin-bottom: 4px;
            color: var(--text-muted);
            font-size: .72rem;
            font-weight: 800;
            letter-spacing: .1em;
            text-transform: uppercase;
        }

        .wm-row {
            padding: 8px 0;
            border-top: 1px solid rgba(91, 80, 232, .16);
        }

        .wm-head {
            display: flex;
            align-items: center;
            gap: 10px;
            min-height: 44px;
        }

        .wm-question, .wm-response {
            margin: 4px 0 10px;
            color: var(--text-primary);
            white-space: pre-wrap;
            overflow-wrap: anywhere;
        }

        .wm-answer-label {
            color: var(--text-muted);
            font-size: .8rem;
            font-weight: 800;
        }

        .wm-model summary {
            min-height: 44px;
            padding: 12px 0;
            color: var(--text-primary);
            font-weight: 800;
            cursor: pointer;
        }

        .wm-model summary:focus-visible {
            outline: 2px solid var(--violet);
            outline-offset: 3px;
        }

        [data-dark] .wm-row {
            border-top-color: rgba(255, 255, 255, 0.08);
        }

        .wm-q {
            flex: 1 1 auto;
            min-width: 0;
            color: var(--text-primary);
            font-size: .95rem;
            font-weight: 800;
        }

        .wm-mark {
            color: var(--text-primary);
            font-size: .95rem;
            font-weight: 800;
        }

        .wm-tag {
            color: var(--text-muted);
            font-size: .7rem;
            font-weight: 800;
            letter-spacing: .06em;
            text-transform: uppercase;
        }

        .wm-tag[data-by="examiner"] {
            color: var(--violet);
        }

        [data-dark] .wm-tag[data-by="examiner"] {
            color: #9d94ff;
        }

        .written-mode-indicator {
            display: inline-flex;
            align-items: center;
            gap: 5px;
            font-size: .7rem;
            font-weight: 700;
            color: var(--violet);
            background: rgba(91, 80, 232, .07);
            border: 1px solid rgba(91, 80, 232, .16);
            border-radius: 99px;
            padding: 3px 10px;
        }

        /* ── Question type badges ──────────────────────────────────────── */
        .qtype-badge {
            display: inline-flex; align-items: center; gap: 5px;
            font-size: .7rem; font-weight: 700; border-radius: 99px;
            padding: 3px 10px; border: 1px solid transparent;
        }
        .qtype-written  { color: var(--violet); background: rgba(91,80,232,.07); border-color: rgba(91,80,232,.16); }
        .qtype-tf       { color: #0ea5e9; background: rgba(14,165,233,.07); border-color: rgba(14,165,233,.18); }
        .qtype-ms       { color: #8b5cf6; background: rgba(139,92,246,.07); border-color: rgba(139,92,246,.18); }
        .qtype-fill     { color: #10b981; background: rgba(16,185,129,.07); border-color: rgba(16,185,129,.18); }
        .qtype-match    { color: #f59e0b; background: rgba(245,158,11,.07); border-color: rgba(245,158,11,.18); }
        .qtype-short    { color: #6366f1; background: rgba(99,102,241,.07); border-color: rgba(99,102,241,.18); }
        .qtype-hotspot  { color: #ef4444; background: rgba(239,68,68,.07); border-color: rgba(239,68,68,.18); }

        /* ── True / False ───────────────────────────────────────────── */
        .tf-options { display: flex; gap: 12px; margin-top: 6px; }
        .tf-btn {
            flex: 1; padding: 18px 12px; border: 2px solid rgba(91,80,232,.18);
            border-radius: 12px; background: #f8f9ff; font-family: var(--font-ui);
            font-size: 1.05rem; font-weight: 800; color: var(--text-primary);
            cursor: var(--cur-point, pointer); transition: all .17s; letter-spacing: .03em;
        }
        .tf-btn:hover { border-color: var(--violet); background: rgba(91,80,232,.06); transform: translateY(-1px); }
        .tf-btn.correct {
            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
            border-color: #059669;
            color: #ffffff;
            box-shadow: 0 6px 20px rgba(16, 185, 129, .35), inset 0 1px 0 rgba(255, 255, 255, .18);
        }
        .tf-btn.wrong {
            background: linear-gradient(135deg, #f43f5e 0%, #e11d48 100%);
            border-color: #e11d48;
            color: #ffffff;
            box-shadow: 0 6px 20px rgba(225, 29, 72, .32), inset 0 1px 0 rgba(255, 255, 255, .18);
        }
        .tf-btn.dimmed  { opacity: .35; cursor: default; }
        .tf-btn.disabled { cursor: default; }
        .tf-btn.timeout-correct {
            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
            border-color: #059669;
            color: #ffffff;
        }
        [data-dark] .tf-btn { background: rgba(255,255,255,.04); color: var(--text-primary); border-color: rgba(255,255,255,.1); }
        [data-dark] .tf-btn:hover { background: rgba(255, 255, 255, 0.08); }
        /* Answered states keep their solid fills in dark mode too */
        [data-dark] .tf-btn.correct,
        [data-dark] .tf-btn.correct:hover,
        [data-dark] .tf-btn.timeout-correct,
        [data-dark] .tf-btn.timeout-correct:hover {
            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
            border-color: #059669;
            color: #ffffff;
        }
        [data-dark] .tf-btn.wrong,
        [data-dark] .tf-btn.wrong:hover {
            background: linear-gradient(135deg, #f43f5e 0%, #e11d48 100%);
            border-color: #e11d48;
            color: #ffffff;
        }

        /* ── Multi-select ───────────────────────────────────────────── */
        .ms-hint { font-size: .8rem; font-weight: 700; color: var(--text-secondary); margin: 0 0 8px; opacity: .75; }
        .ms-option { display: flex; align-items: center; gap: 12px; padding-left: 14px !important; }
        .ms-checkbox {
            width: 20px; height: 20px; min-width: 20px; border-radius: 8px;
            border: 2px solid rgba(91,80,232,.3); background: transparent; transition: all .15s;
        }
        .ms-checkbox.checked { background: var(--violet); border-color: var(--violet); }
        .ms-checkbox.checked::after { content: '✓'; display: block; text-align: center; color: white; font-size: .8rem; line-height: 16px; font-weight: 900; }
        .ms-option.selected { border-color: var(--violet) !important; background: rgba(91,80,232,.06) !important; }

        /* ── Fill in the blank ──────────────────────────────────────── */
        .fill-wrap { margin-top: 6px; }
        .fill-input {
            width: 100%; padding: 12px 14px; background: #f8f9ff;
            border: 1.5px solid rgba(91,80,232,.14); border-radius: 12px;
            font-family: var(--font-ui); font-size: .95rem;
            color: var(--text-primary); transition: border-color .2s, box-shadow .2s;
        }
        .fill-input:focus-visible { outline: 3px solid var(--violet); outline-offset: 2px; border-color: var(--violet); box-shadow: 0 0 0 3px rgba(91,80,232,.08); }
        .fill-input:disabled { opacity: .6; }
        [data-dark] .fill-input { background: rgba(255,255,255,.05); border-color: rgba(255,255,255,.1); }
        .fill-label {
            display: flex; align-items: center; gap: 8px;
            font-size: .8rem; font-weight: 800; color: var(--violet);
            margin-bottom: 8px;
        }
        /* the highlighted blank — both in the question text and the label */
        .fill-blank {
            display: inline-flex; align-items: center; justify-content: center;
            min-width: 34px; height: 1.35em; padding: 0 8px;
            background: rgba(91,80,232,.12); border: 2px dashed var(--violet);
            border-radius: 8px; color: var(--violet); font-weight: 900;
            vertical-align: middle; line-height: 1;
            animation: fillBlankPulse 1.8s ease-in-out infinite;
        }
        @keyframes fillBlankPulse {
            0%, 100% { background: rgba(91,80,232,.10); }
            50% { background: rgba(91,80,232,.22); }
        }

        /* ── Matching ───────────────────────────────────────────────── */
        .matching-table { width: 100%; border-collapse: collapse; margin-top: 6px; }
        .matching-row { transition: background .15s; }
        .matching-row + .matching-row td { border-top: 1px solid rgba(91,80,232,.07); }
        .match-left { padding: 10px 12px; font-weight: 700; font-size: .9rem; width: 38%; }
        .match-arrow { padding: 10px 4px; color: var(--text-secondary); opacity: .5; text-align: center; }
        .match-right { padding: 10px 6px; width: 56%; }
        .matching-select {
            width: 100%; padding: 8px 10px; border-radius: 8px;
            border: 1.5px solid rgba(91,80,232,.18); background: #f8f9ff;
            font-family: var(--font-ui); font-size: .88rem; color: var(--text-primary);
            cursor: var(--cur-point, pointer); transition: border-color .18s;
        }
        .matching-select:focus-visible { outline: 3px solid var(--violet); outline-offset: 2px; border-color: var(--violet); }
        .matching-select:disabled { opacity: .7; }
        .matching-row.match-correct .match-left { color: #059669; }
        .matching-row.match-correct .matching-select { border-color: #10b981; background: rgba(16,185,129,.06); }
        .matching-row.match-wrong .match-left { color: #e11d48; }
        .matching-row.match-wrong .matching-select { border-color: #f43f5e; background: rgba(225,29,72,.06); }
        .match-hint { font-size: .78rem; color: #059669; font-weight: 700; margin-left: 6px; }
        [data-dark] .matching-select { background: rgba(255,255,255,.05); border-color: rgba(255,255,255,.1); }
        [data-dark] .matching-row + .matching-row td { border-color: rgba(255,255,255,.07); }

        /* ── Short textarea (smaller than written) ──────────────────── */
        .short-textarea { min-height: 60px !important; }

        /* ── Shared submit button (multi-select, fill, matching) ────── */
        .btn-submit-type {
            width: 100%; margin-top: 10px; padding: 11px;
            background: linear-gradient(135deg, var(--violet), var(--violet-dim));
            border: none; border-radius: 999px; color: white;
            font-family: var(--font-ui); font-size: .9rem; font-weight: 700;
            cursor: var(--cur-point, pointer); transition: all .18s;
        }
        .btn-submit-type:hover { transform: translateY(-1px); box-shadow: 0 6px 20px rgba(91,80,232,.35); }

        /* ── Hotspot ────────────────────────────────────────────────── */
        .hotspot-chart-wrap { cursor: crosshair; user-select: none; position: relative; }
        .hotspot-chart-wrap:hover { opacity: .95; }
        .hotspot-hint { font-size: .82rem; font-weight: 700; color: var(--text-secondary); margin: 0 0 6px; opacity: .8; }

        .hotspot-coordinates { display: flex; flex-wrap: wrap; gap: 12px; margin: 12px 0; }
        .hotspot-coordinate-field { flex: 1 1 140px; min-width: 0; }
        .hotspot-coordinates .fill-input { width: 100%; min-height: 44px; }
        .hotspot-coordinates .btn-submit-type { min-height: 44px; margin-top: 0; }
        .hotspot-coordinate-error { display: block; color: var(--text-primary); font-size: .8rem; margin-top: 4px; }
        .hotspot-coordinates [aria-invalid="true"] { border-color: var(--rose); }

        /* ── Exam mode: single overall countdown bar (replaces per-question timers) ── */
        .exam-timer-bar {
            display: flex;
            align-items: center;
            gap: 14px;
            background: rgba(91, 80, 232, .05);
            border: 1px solid rgba(91, 80, 232, .16);
            border-radius: 16px;
            padding: 14px 18px;
            margin-bottom: 18px;
        }

        .exam-timer-icon {
            font-size: 1.25rem;
            line-height: 1;
            flex-shrink: 0;
        }

        .exam-timer-info {
            flex: 1;
            min-width: 0;
        }

        .exam-timer-label {
            font-size: .7rem;
            font-weight: 700;
            color: var(--text-muted);
            text-transform: uppercase;
            letter-spacing: .05em;
        }

        .exam-timer-value {
            font-size: 1.05rem;
            font-weight: 800;
            color: var(--violet);
            font-variant-numeric: tabular-nums;
            margin-top: 1px;
        }

        .exam-timer-bar.exam-timer-low .exam-timer-value {
            color: var(--rose);
        }

        .exam-timer-track {
            width: 92px;
            flex-shrink: 0;
            height: 6px;
            background: #e8ecf5;
            border-radius: 99px;
            overflow: hidden;
        }

        .exam-timer-fill {
            height: 100%;
            background: linear-gradient(90deg, var(--violet), #818cf8);
            border-radius: 99px;
            transition: width 1s linear, background .3s;
        }

        .exam-timer-bar.exam-timer-low .exam-timer-fill {
            background: linear-gradient(90deg, var(--rose), rgba(225, 29, 72, .55));
        }

        /* ── Exam mode: section divider above the first question of each section ── */
        .exam-section-divider {
            display: flex;
            align-items: baseline;
            justify-content: space-between;
            gap: 10px;
            flex-wrap: wrap;
            padding: 10px 16px;
            margin-bottom: 18px;
            background: linear-gradient(135deg, rgba(91, 80, 232, .08), rgba(91, 80, 232, .03));
            border: 1px solid rgba(91, 80, 232, .14);
            border-left: 3px solid var(--violet);
            border-radius: 12px;
        }

        .exam-section-name {
            font-size: .85rem;
            font-weight: 800;
            color: var(--violet);
        }

        .exam-section-marks {
            font-size: .72rem;
            font-weight: 600;
            color: var(--text-muted);
            white-space: nowrap;
        }

        /* ── Exam mode: per-question marks badge (mirrors .diff-badge) ── */
        .marks-badge {
            display: inline-flex;
            align-items: center;
            gap: 5px;
            border-radius: 99px;
            padding: 3px 10px;
            font-size: .7rem;
            font-weight: 700;
            letter-spacing: .02em;
            background: rgba(217, 119, 6, .08);
            border: 1px solid rgba(217, 119, 6, .2);
            color: var(--amber);
            white-space: nowrap;
        }

        /* ── Exam mode: marks-by-section breakdown on the results screen ── */
        .exam-marks-breakdown {
            margin: 4px 0 18px;
            padding: 16px 18px;
            background: rgba(91, 80, 232, .04);
            border: 1px solid rgba(91, 80, 232, .14);
            border-radius: 16px;
            text-align: left;
        }

        .exam-marks-breakdown-title {
            font-size: .7rem;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: .06em;
            color: var(--text-muted);
            margin-bottom: 10px;
        }

        .exam-marks-section {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            padding: 7px 0;
        }

        .exam-marks-section+.exam-marks-section {
            border-top: 1px solid rgba(91, 80, 232, .08);
        }

        .exam-marks-section-name {
            font-size: .82rem;
            font-weight: 700;
            color: var(--text-primary);
        }

        .exam-marks-section-score {
            font-size: .85rem;
            font-weight: 800;
            color: var(--violet);
            white-space: nowrap;
        }

        .exam-marks-total {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            padding-top: 10px;
            margin-top: 4px;
            border-top: 1px solid rgba(91, 80, 232, .16);
            font-size: .9rem;
            font-weight: 800;
            color: var(--text-primary);
        }

        .exam-marks-total span:last-child {
            color: var(--violet);
        }

        .btn-review-toggle {
            width: 100%;
            margin-top: 14px;
            padding: 11px;
            background: rgba(225, 29, 72, .06);
            border: 1px solid rgba(225, 29, 72, .18);
            border-radius: 999px;
            color: var(--rose);
            font-family: var(--font-ui);
            font-size: .88rem;
            font-weight: 700;
            cursor: var(--cur-point, pointer);
            transition: background .18s;
        }

        .btn-review-toggle:hover {
            background: rgba(225, 29, 72, .1);
        }

        /* ── AI TUTOR RECAP ── */
        .btn-recap {
            width: 100%;
            padding: 12px;
            background: linear-gradient(135deg, var(--violet) 0%, var(--violet-dim) 100%);
            border: none;
            border-radius: 999px;
            color: #fff;
            font-family: var(--font-ui);
            font-size: .9rem;
            font-weight: 700;
            cursor: var(--cur-point, pointer);
            box-shadow: 0 4px 16px rgba(91, 80, 232, .3);
            transition: transform .15s, box-shadow .15s, opacity .15s;
        }

        .btn-recap:hover:not(:disabled) {
            transform: translateY(-1px);
            box-shadow: 0 6px 22px rgba(91, 80, 232, .4);
        }

        .btn-recap:disabled {
            opacity: .75;
            cursor: default;
        }

        .recap-panel {
            margin-top: 14px;
            background: #ffffff;
            border: 1px solid rgba(91, 80, 232, .14);
            border-radius: 20px;
            padding: 22px;
            box-shadow: 0 4px 24px rgba(91, 80, 232, .07);
            animation: slideUp .35s ease both;
            text-align: left;
        }

        .recap-head {
            display: flex;
            align-items: flex-start;
            gap: 12px;
            margin-bottom: 16px;
        }

        .recap-head-icon {
            width: 38px;
            height: 38px;
            border-radius: 12px;
            background: rgba(91, 80, 232, .1);
            color: var(--violet);
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
        }

        .recap-title {
            font-size: .72rem;
            font-weight: 800;
            text-transform: uppercase;
            letter-spacing: .06em;
            color: var(--violet);
        }

        .recap-headline {
            font-size: .95rem;
            font-weight: 700;
            color: var(--text-primary);
            line-height: 1.45;
            margin-top: 2px;
        }

        .recap-section {
            border: 1px solid rgba(91, 80, 232, .1);
            border-left: 3px solid var(--violet);
            border-radius: 12px;
            padding: 14px 14px 12px;
            margin-bottom: 12px;
            background: #fafbff;
        }

        .recap-concept {
            font-size: .92rem;
            font-weight: 800;
            color: var(--text-primary);
            margin-bottom: 9px;
        }

        .recap-row {
            display: flex;
            gap: 9px;
            font-size: .86rem;
            line-height: 1.55;
            color: var(--text-secondary);
            margin-bottom: 8px;
        }

        .recap-row strong {
            color: var(--text-primary);
        }

        .recap-row-icon {
            flex-shrink: 0;
            margin-top: 3px;
        }

        .recap-wrong .recap-row-icon {
            color: var(--rose);
        }

        .recap-fix .recap-row-icon {
            color: var(--emerald);
        }

        .recap-hook {
            display: flex;
            gap: 7px;
            align-items: baseline;
            font-size: .84rem;
            font-weight: 600;
            color: var(--amber);
            background: var(--amber-bg);
            border: 1px solid var(--amber-border);
            border-radius: 8px;
            padding: 8px 11px;
            margin-top: 4px;
            line-height: 1.5;
        }

        .recap-next {
            font-size: .87rem;
            line-height: 1.55;
            color: var(--text-secondary);
            background: rgba(91, 80, 232, .06);
            border: 1px solid rgba(91, 80, 232, .14);
            border-radius: 12px;
            padding: 11px 13px;
        }

        .recap-next strong {
            color: var(--violet);
        }

        [data-dark] .recap-panel {
            background: #1D1D21;
        }

        [data-dark] .recap-section {
            background: #1D1D21;
        }

        /* ── AUTH MODAL ── */
        /* ── Keyboard shortcuts help overlay (additive, self-contained) ── */
        .kbd-help-overlay {
            position: fixed;
            inset: 0;
            background: rgba(10, 8, 40, 0.45);
            backdrop-filter: blur(4px);
            z-index: 2100;   /* above nav (1005) and auth modal (2000) */
            display: none;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }
        .kbd-help-overlay.open { display: flex; }
        .kbd-help-modal {
            background: var(--card-bg);
            color: var(--text-primary);
            border-radius: 20px;
            padding: 28px 28px 24px;
            width: 100%;
            max-width: 440px;
            max-height: 85vh;
            overflow-y: auto;
            box-shadow: 0 20px 60px rgba(91, 80, 232, 0.18), 0 4px 12px rgba(0, 0, 0, 0.08);
            animation: slideUp 0.28s cubic-bezier(0.4, 0, 0.2, 1) both;
            position: relative;
        }
        .kbd-help-close {
            position: absolute;
            top: 14px;
            right: 16px;
            background: none;
            border: none;
            font-size: 1.2rem;
            cursor: var(--cur-point, pointer);
            color: var(--text-muted);
            padding: 4px;
            line-height: 1;
            transition: color 0.15s;
        }
        .kbd-help-close:hover { color: var(--text-primary); }
        .kbd-help-title {
            font-family: var(--font-ui);
            font-size: 1.25rem;
            font-weight: 800;
            color: var(--text-primary);
            margin-bottom: 2px;
        }
        .kbd-help-sub {
            font-size: 0.82rem;
            color: var(--text-muted);
            margin-bottom: 18px;
        }
        .kbd-help-group { margin-bottom: 16px; }
        .kbd-help-group:last-child { margin-bottom: 0; }
        .kbd-help-group-title {
            font-size: 0.7rem;
            font-weight: 800;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            color: var(--violet);
            margin-bottom: 6px;
        }
        .kbd-row {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            padding: 7px 0;
            border-bottom: 1px solid rgba(91, 80, 232, 0.08);
        }
        .kbd-row:last-child { border-bottom: none; }
        .kbd-row-label { font-size: 0.88rem; color: var(--text-primary); }
        .kbd-row-keys { display: flex; gap: 5px; flex-shrink: 0; }
        kbd.kbd-key {
            font-family: var(--font-ui);
            font-size: 0.74rem;
            font-weight: 700;
            min-width: 22px;
            text-align: center;
            padding: 3px 7px;
            border-radius: 7px;
            background: rgba(91, 80, 232, 0.10);
            color: var(--violet);
            border: 1px solid rgba(91, 80, 232, 0.22);
            box-shadow: 0 1px 0 rgba(91, 80, 232, 0.18);
            line-height: 1.2;
        }
        @media (prefers-reduced-motion: reduce) { .kbd-help-modal { animation: none; } }

        .auth-aside { display: none; }

        @media (min-width: 900px) {
            /* The form column keeps 400px exactly; the panel is extra, so the
               sign-up experience a phone gets is not re-flowed on desktop. */
            .auth-modal:has(.auth-aside) {
                max-width: 736px;
                display: grid;
                grid-template-columns: 296px 1fr;
                gap: 32px;
                padding: 0;
                overflow: hidden;
            }

            .auth-modal:has(.auth-aside) > #authLoginForm,
            .auth-modal:has(.auth-aside) > .auth-success,
            .auth-modal:has(.auth-aside) > .welcome {
                padding: 32px 32px 32px 0;
                min-width: 0;
            }

            /* Resetting a password is recovery, not acquisition: the aside is a
               pitch aimed at someone deciding whether to sign up, and the short
               reset form leaves it standing alone in a half-empty column. Fold
               the modal back to the single column the phone already gets. */
            .auth-modal.is-resetting:has(.auth-aside) {
                max-width: 400px;
                display: block;
                padding: 32px;
            }

            .auth-modal.is-resetting .auth-aside {
                display: none;
            }

            .auth-modal.is-resetting:has(.auth-aside) > #authLoginForm {
                padding: 0;
            }

            .auth-aside {
                display: flex;
                flex-direction: column;
                justify-content: center;
                background: linear-gradient(160deg, #6d5cff 0%, #5b50e8 55%, #4b41c4 100%);
                color: #fff;
                padding: 32px 26px;
                min-width: 0;
            }

            .auth-aside-avi {
                width: 54px;
                height: 54px;
                border-radius: 16px;
                display: block;
                margin-bottom: 16px;
                box-shadow: 0 8px 22px rgba(20, 12, 60, .32);
            }

            .auth-aside-title {
                font-family: var(--font-display, 'Plus Jakarta Sans'), sans-serif;
                font-size: 1.32rem;
                font-weight: 800;
                line-height: 1.2;
                letter-spacing: -.01em;
                margin: 0 0 16px;
            }

            .auth-aside-list {
                display: flex;
                flex-direction: column;
                gap: 12px;
                margin: 0;
                padding: 0;
                list-style: none;
            }

            .auth-aside-list li {
                display: flex;
                align-items: flex-start;
                gap: 9px;
                font-size: .855rem;
                line-height: 1.45;
                color: rgba(255, 255, 255, .93);
            }

            .auth-aside-list b { font-weight: 800; color: #fff; }

            .auth-aside-tick {
                flex: none;
                width: 17px;
                height: 17px;
                margin-top: 1px;
                border-radius: 50%;
                background: rgba(255, 255, 255, .22);
                color: #fff;
                font-size: .62rem;
                font-weight: 800;
                display: flex;
                align-items: center;
                justify-content: center;
            }

            /* Once the account exists the panel has made its case — the
               welcome gets the whole modal back. */
            .auth-modal.is-welcome { max-width: 400px; display: block; padding: 32px; }
            .auth-modal.is-welcome .auth-aside { display: none; }
            .auth-modal.is-welcome > .welcome { padding: 0; }
        }

        .auth-modal-overlay {
            position: fixed;
            inset: 0;
            background: rgba(10, 8, 40, 0.45);
            backdrop-filter: blur(4px);
            z-index: 2000;   /* above nav (1005) */
            display: none;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }

        .auth-modal-overlay.open {
            display: flex;
        }

        /* ══════════════════════════════════════════════════════════════
           SIGN-UP — the front door

           On a phone the 400px card fills the screen and is right as it is.
           On a desktop it was a 400px box floating in 1440px of blurred app,
           and nothing on it said why an account is worth making: the reasons
           only appeared AFTER signing up, on the welcome screen, which is the
           wrong side of the decision.

           So from 900px up the modal grows a second panel carrying the same
           honest reasons, and the form keeps its exact width beside it. Below
           900px the panel is not rendered at all and the card is unchanged —
           the phone layout is not a casualty of fixing the desktop one.
           ══════════════════════════════════════════════════════════════ */
        .auth-modal {
            background: white;
            border-radius: 20px;
            padding: 32px;
            width: 100%;
            max-width: 400px;
            /* Cap height to the (keyboard-adjusted) viewport and scroll inside, so
               the signup step-2 form can't clip off-screen on short phones. */
            max-height: calc(100dvh - 32px);
            overflow-y: auto;
            box-shadow: 0 20px 60px rgba(91, 80, 232, 0.18), 0 4px 12px rgba(0, 0, 0, 0.08);
            animation: slideUp 0.28s cubic-bezier(0.4, 0, 0.2, 1) both;
            position: relative;
        }

        .auth-modal-close {
            position: absolute;
            font-family: var(--font-ui);
            top: 14px;
            right: 16px;
            background: none;
            border: none;
            font-size: 1.2rem;
            cursor: var(--cur-point, pointer);
            color: var(--text-muted);
            padding: 4px;
            transition: color 0.15s;
            line-height: 1;
        }

        .auth-modal-close:hover {
            color: var(--text-primary);
        }

        .auth-modal-title {
            font-size: 1.2rem;
            font-weight: 800;
            color: var(--text-primary);
            margin-bottom: 4px;
        }

        .auth-modal-sub {
            font-size: 0.82rem;
            color: var(--text-muted);
            margin-bottom: 20px;
        }

        .auth-tabs {
            display: flex;
            background: #f3f4f8;
            border-radius: 999px;
            padding: 3px;
            gap: 3px;
            margin-bottom: 20px;
        }

        .auth-tab {
            flex: 1;
            padding: 8px;
            border-radius: 999px;
            border: none;
            background: none;
            font-family: var(--font-ui);
            font-size: 0.85rem;
            font-weight: 600;
            cursor: var(--cur-point, pointer);
            color: var(--text-muted);
            transition: all 0.18s;
        }

        .auth-tab.active {
            background: white;
            color: var(--violet);
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
        }

        .auth-field {
            margin-bottom: 13px;
        }

        .auth-field label {
            display: block;
            font-size: 0.72rem;
            font-weight: 700;
            color: var(--text-muted);
            text-transform: uppercase;
            letter-spacing: 0.05em;
            margin-bottom: 5px;
        }

        .auth-field input {
            width: 100%;
            padding: 11px 13px;
            border: 1.5px solid rgba(91, 80, 232, 0.15);
            border-radius: 12px;
            font-family: var(--font-ui);
            font-size: 0.9rem;
            color: var(--text-primary);
            background: #fafbff;
            transition: border-color 0.18s, box-shadow 0.18s;
        }

        .auth-field input:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
            border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, 0.1);
            background: white;
        }

        .auth-agree {
            display: flex;
            align-items: flex-start;
            gap: 9px;
            margin-bottom: 16px;
            font-size: 0.8rem;
            color: var(--text-secondary);
            line-height: 1.5;
        }

        .auth-agree input[type=checkbox] {
            width: 15px;
            height: 15px;
            margin-top: 2px;
            flex-shrink: 0;
            accent-color: var(--violet);
        }

        .auth-agree a {
            color: var(--violet);
            text-decoration: none;
        }

        .auth-agree a:hover {
            text-decoration: underline;
        }

        .auth-legal {
            margin: 12px 4px 0;
            color: #475569;
            font-size: 0.72rem;
            line-height: 1.45;
            text-align: center;
        }

        .auth-legal a {
            color: #4f46e5;
            text-decoration: underline;
            text-underline-offset: 2px;
        }

        [data-dark] .auth-legal {
            color: #B4B4BD;
        }

        [data-dark] .auth-legal a {
            color: #c7bfff;
        }

        .auth-submit {
            width: 100%;
            padding: 14px;
            background: var(--grad-cta);
            color: white;
            border: none;
            border-radius: 999px;
            font-family: var(--font-ui);
            font-size: 1rem;
            font-weight: 800;
            cursor: var(--cur-point, pointer);
            box-shadow: 0 7px 16px rgba(91, 80, 232, .24);
            transition: transform 0.12s ease, box-shadow 0.12s ease, filter 0.12s;
        }

        .auth-submit:hover {
            filter: brightness(1.05);
            transform: translateY(-1px);
            box-shadow: 0 10px 20px rgba(91, 80, 232, .3);
        }

        .auth-submit:active {
            transform: translateY(4px);
            box-shadow: 0 0 0 var(--violet-shade), 0 2px 6px rgba(91, 80, 232, .3);
        }

        .auth-submit:disabled {
            opacity: 0.6;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }

        .auth-error {
            background: rgba(225, 29, 72, 0.06);
            border: 1px solid rgba(225, 29, 72, 0.2);
            color: #c1203e;
            border-radius: 8px;
            padding: 9px 12px;
            font-size: 0.82rem;
            margin-bottom: 13px;
            display: none;
        }

        .auth-error.show {
            display: block;
        }

        .auth-success {
            text-align: center;
            padding: 16px 0 4px;
        }

        .auth-success-icon {
            font-size: 2.2rem;
            margin-bottom: 8px;
        }

        .auth-success-title {
            font-size: 1.05rem;
            font-weight: 700;
            color: var(--text-primary);
            margin-bottom: 4px;
        }

        .auth-success-sub {
            font-size: 0.83rem;
            color: var(--text-muted);
        }

        /* ══════════════════════════════════════════════════════════════
           WELCOME — the moment an account exists

           What was here before: a 2.2rem tick, "You're in!", and a
           setTimeout that closed the modal 1.8s later. A student who had
           just typed an email, waited for a code, typed the code and chosen
           a password got one and a half seconds of acknowledgement and then
           the same screen they started on. The report was "nothing happens
           when you sign up", which is exactly right.

           Three rules for this screen:
           1. It does not close itself. The old auto-close is most of why the
              moment did not register — it was gone before it was read.
           2. Every line is TRUE and specific to them. No invented numbers:
              the guest-progress row only appears when there is guest
              progress, and it states the real count.
           3. One obvious next thing to do. The point of the celebration is
              the first quiz, not the celebration.
           ══════════════════════════════════════════════════════════════ */
        .welcome {
            text-align: center;
            padding: 6px 0 2px;
        }

        .welcome-avi {
            position: relative;
            width: 76px;
            height: 76px;
            margin: 0 auto 16px;
        }

        .welcome-avi img {
            width: 76px;
            height: 76px;
            display: block;
            border-radius: 21px;
            box-shadow: 0 10px 26px rgba(91, 80, 232, .28);
            position: relative;
            z-index: 2;
        }

        /* One ring travelling outward, once. The generation screen uses the
           same violet band to mean "working"; here it fires a single time to
           mean "done", so the two read as one language. */
        .welcome-avi::after {
            content: '';
            position: absolute;
            inset: -6px;
            border-radius: 27px;
            border: 2px solid var(--violet);
            opacity: 0;
            z-index: 1;
            animation: welcomeRing 900ms cubic-bezier(.22, 1, .36, 1) 120ms 2;
        }

        .welcome-title {
            font-family: var(--font-display, 'Plus Jakarta Sans'), sans-serif;
            font-size: 1.5rem;
            font-weight: 800;
            line-height: 1.15;
            color: var(--text-primary);
            margin-bottom: 6px;
            letter-spacing: -.01em;
        }

        .welcome-sub {
            font-size: .88rem;
            color: var(--text-secondary, var(--text-muted));
            margin-bottom: 18px;
        }

        .welcome-list {
            display: flex;
            flex-direction: column;
            gap: 8px;
            text-align: left;
            margin-bottom: 20px;
        }

        .welcome-item {
            display: flex;
            align-items: flex-start;
            gap: 10px;
            padding: 11px 13px;
            border-radius: 13px;
            background: rgba(91, 80, 232, .05);
            border: 1px solid rgba(91, 80, 232, .1);
            font-size: .86rem;
            line-height: 1.45;
            color: var(--text-primary);
            /* Visible by DEFAULT and animated from a class, so a headless
               render or a paused tab can never leave this screen blank. */
            opacity: 1;
        }

        [data-dark] .welcome-item {
            background: rgba(255, 255, 255, 0.055);
            border-color: rgba(255, 255, 255, 0.14);
        }

        .welcome-item b { font-weight: 800; }

        .welcome-tick {
            flex: none;
            width: 19px;
            height: 19px;
            margin-top: 1px;
            border-radius: 50%;
            background: var(--violet);
            color: #fff;
            font-size: .7rem;
            font-weight: 800;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .welcome.is-animating .welcome-item {
            opacity: 0;
            animation: welcomeStamp 420ms cubic-bezier(.22, 1, .36, 1) forwards;
        }

        .welcome.is-animating .welcome-item:nth-child(1) { animation-delay: 160ms; }
        .welcome.is-animating .welcome-item:nth-child(2) { animation-delay: 300ms; }
        .welcome.is-animating .welcome-item:nth-child(3) { animation-delay: 440ms; }

        .welcome-actions {
            display: flex;
            flex-direction: column;
            gap: 9px;
        }

        .welcome-go {
            width: 100%;
            padding: 15px;
            border: none;
            border-radius: 999px;
            background: var(--grad-cta);
            color: #fff;
            font-family: var(--font-display, 'Plus Jakarta Sans'), sans-serif;
            font-size: 1.02rem;
            font-weight: 800;
            cursor: var(--cur-point, pointer);
            /* Flat pill, not a 3D block: the hard `0 4px 0` underside is the
               old Duolingo-style treatment being retired everywhere. Depth
               comes from one soft grounded shadow. */
            box-shadow: 0 6px 18px rgba(91, 80, 232, .32);
            transition: transform .12s ease, box-shadow .12s ease;
        }

        .welcome-go:hover {
            transform: translateY(-1px);
            box-shadow: 0 9px 24px rgba(91, 80, 232, .38);
        }

        .welcome-go:active {
            transform: translateY(0);
            box-shadow: 0 3px 10px rgba(91, 80, 232, .3);
        }

        .welcome-later {
            background: none;
            border: none;
            color: var(--text-muted);
            font-family: var(--font-ui, 'Plus Jakarta Sans'), sans-serif;
            font-size: .84rem;
            font-weight: 700;
            padding: 6px;
            cursor: var(--cur-point, pointer);
        }

        .welcome-later:hover { color: var(--accent-text, var(--violet)); }

        @keyframes welcomeRing {
            0%   { opacity: .75; transform: scale(.82); }
            100% { opacity: 0;   transform: scale(1.5); }
        }

        @keyframes welcomeStamp {
            0%   { opacity: 0; transform: translateY(7px) scale(.98); }
            100% { opacity: 1; transform: none; }
        }

        /* The screen keeps every word; only the movement goes. */
        @media (prefers-reduced-motion: reduce) {
            .welcome-avi::after { animation: none; }
            .welcome.is-animating .welcome-item {
                opacity: 1;
                animation: none;
            }
        }

        /* ── Signup 2-step flow ── */
        .auth-code-hint {
            display: flex;
            align-items: center;
            gap: 7px;
            background: rgba(91, 80, 232, 0.07);
            border-radius: 8px;
            padding: 9px 12px;
            margin-bottom: 14px;
            font-size: 0.83rem;
            color: var(--text-secondary);
        }

        .auth-code-hint svg {
            flex-shrink: 0;
            color: var(--violet);
        }

        /* A long address must break rather than push the hint wider than the
           modal. Pairs with the <span> that keeps the sentence one flex item. */
        .auth-code-hint strong {
            overflow-wrap: anywhere;
        }

        .auth-step2-links {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 8px;
            margin-top: 12px;
        }

        .auth-link-btn {
            background: none;
            border: none;
            cursor: var(--cur-point, pointer);
            font-size: 0.8rem;
            color: var(--text-muted);
            padding: 0;
            font-family: inherit;
        }

        .auth-link-btn:hover {
            text-decoration: underline;
        }

        .auth-link-sep {
            color: var(--text-muted);
            font-size: 0.8rem;
        }

        /* Student / Teacher account-type picker (signup step 1) */
        .role-choice { display: flex; gap: 10px; }
        .role-opt {
            flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 13px 8px;
            border: 2px solid rgba(91, 80, 232, .18); border-radius: 14px; background: #fafbff; cursor: var(--cur-point, pointer);
            font-family: var(--font-ui); text-align: center; transition: border-color .15s, background .15s, box-shadow .15s;
        }
        .role-opt:hover { border-color: rgba(91, 80, 232, .4); }
        .role-opt.selected { border-color: var(--violet); background: rgba(91, 80, 232, .08); box-shadow: 0 0 0 3px rgba(91, 80, 232, .12); }
        .role-opt .role-icon { line-height: 0; color: var(--text-primary); margin-bottom: 1px; }
        .role-opt .role-icon svg { width: 26px; height: 26px; }
        .role-opt .role-name { font-weight: 800; font-size: .98rem; color: var(--text-primary); }
        .role-opt .role-desc { font-size: .72rem; color: var(--text-muted); }
        [data-dark] .role-opt { background: #232327; }

        /* ── Community Quizzes: publish modal + structured editor ──────────────
           Reuses the .auth-modal-overlay shell + design tokens (Plus Jakarta Sans,
           violet #5b50e8, dark via [data-dark]). The editor card is wider than the
           auth modal and scrolls internally for long quizzes. */
        .cq-modal { max-width: 460px; text-align: left; }
        .cq-modal-wide { max-width: 640px; }
        .cq-modal-body { max-height: min(70vh, 560px); overflow-y: auto; margin: 2px -4px 0; padding: 0 4px; }
        .cq-field { margin-bottom: 13px; }
        .cq-field label {
            display: block; font-size: 0.72rem; font-weight: 700; color: var(--text-muted);
            text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 5px;
        }
        .cq-field input[type=text], .cq-field textarea, .cq-field select {
            width: 100%; padding: 11px 13px; border: 1.5px solid rgba(91, 80, 232, 0.15);
            border-radius: 12px; font-family: var(--font-ui); font-size: 0.9rem;
            color: var(--text-primary); background: #fafbff;
            transition: border-color 0.18s, box-shadow 0.18s; box-sizing: border-box;
        }
        .cq-field textarea { resize: vertical; min-height: 64px; line-height: 1.45; }
        .cq-field input[type=text]:focus-visible, .cq-field textarea:focus-visible, .cq-field select:focus-visible {
            outline: 3px solid var(--violet); outline-offset: 2px; border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, 0.1); background: white;
        }
        .cq-row { display: flex; gap: 10px; }
        .cq-row > .cq-field { flex: 1; min-width: 0; }
        /* public/unlisted toggle — pill switch, no side-tab border */
        .cq-toggle {
            display: flex; align-items: center; gap: 11px; margin-bottom: 16px;
            padding: 11px 13px; background: rgba(91, 80, 232, .05);
            border: 1px solid rgba(91, 80, 232, .12); border-radius: 12px;
        }
        .cq-toggle .cq-toggle-txt { flex: 1; min-width: 0; }
        .cq-toggle .cq-toggle-title { font-weight: 800; font-size: .86rem; color: var(--text-primary); }
        .cq-toggle .cq-toggle-sub { font-size: .74rem; color: var(--text-muted); }
        .cq-switch { position: relative; width: 44px; height: 26px; flex-shrink: 0; }
        .cq-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: var(--cur-point, pointer); }
        .cq-switch .cq-slider {
            position: absolute; inset: 0; background: #cbd2e0; border-radius: 999px;
            transition: background .18s; pointer-events: none;
        }
        .cq-switch .cq-slider::before {
            content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px;
            background: #fff; border-radius: 50%; box-shadow: 0 1px 3px rgba(0,0,0,.2);
            transition: transform .18s;
        }
        .cq-switch input:checked + .cq-slider { background: var(--violet); }
        .cq-switch input:checked + .cq-slider::before { transform: translateX(18px); }
        .cq-switch input:focus-visible + .cq-slider { outline: 3px solid var(--violet); outline-offset: 2px; }
        .cq-error {
            background: rgba(225, 29, 72, 0.06); border: 1px solid rgba(225, 29, 72, 0.2);
            color: #c1203e; border-radius: 8px; padding: 9px 12px; font-size: 0.82rem;
            margin-bottom: 13px; display: none;
        }
        .cq-error.show { display: block; }
        /* Shareable-link success card */
        .cq-share-row { display: flex; gap: 8px; margin-top: 6px; }
        .cq-share-row input {
            flex: 1; min-width: 0; padding: 11px 13px; border: 1.5px solid rgba(91, 80, 232, 0.15);
            border-radius: 12px; font-family: var(--font-ui); font-size: 0.85rem;
            color: var(--text-primary); background: #fafbff; box-sizing: border-box;
        }
        .cq-btn-secondary {
            padding: 11px 16px; background: rgba(91, 80, 232, .08); color: var(--violet);
            border: 1.5px solid rgba(91, 80, 232, .2); border-radius: 999px;
            font-family: var(--font-ui); font-size: .88rem; font-weight: 800;
            cursor: var(--cur-point, pointer); transition: background .15s; white-space: nowrap;
        }
        .cq-btn-secondary:hover { background: rgba(91, 80, 232, .14); }
        /* Per-question editor card — flat surface, no left accent bar */
        .cq-q-card {
            background: #fafbff; border: 1px solid rgba(91, 80, 232, .14);
            border-radius: 14px; padding: 14px; margin-bottom: 12px;
        }
        .cq-q-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 9px; }
        .cq-q-num { font-weight: 800; font-size: .82rem; color: var(--violet); }
        .cq-q-del {
            background: none; border: none; color: var(--text-muted); cursor: var(--cur-point, pointer);
            font-size: .98rem; padding: 2px 6px; border-radius: 999px; line-height: 1;
        }
        .cq-q-del:hover { color: #c1203e; background: rgba(225, 29, 72, .08); }
        .cq-opt-row { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
        .cq-opt-row .cq-opt-letter { font-weight: 800; font-size: .82rem; color: var(--text-muted); width: 16px; flex-shrink: 0; }
        .cq-opt-row input[type=text] { flex: 1; min-width: 0; }
        .cq-opt-row input[type=radio] { width: 17px; height: 17px; flex-shrink: 0; accent-color: var(--violet); cursor: var(--cur-point, pointer); }
        .cq-add-q {
            width: 100%; padding: 11px; background: none; color: var(--violet);
            border: 1.5px dashed rgba(91, 80, 232, .35); border-radius: 999px;
            font-family: var(--font-ui); font-size: .88rem; font-weight: 800;
            cursor: var(--cur-point, pointer); transition: background .15s, border-color .15s; margin-bottom: 4px;
        }
        .cq-add-q:hover { background: rgba(91, 80, 232, .06); border-color: var(--violet); }
        .cq-modal-actions { display: flex; gap: 10px; margin-top: 16px; }
        .cq-modal-actions .auth-submit { margin: 0; }
        .cq-success-link { text-align: left; }
        /* dark theme */
        [data-dark] .cq-field input[type=text], [data-dark] .cq-field textarea,
        [data-dark] .cq-field select, [data-dark] .cq-share-row input,
        [data-dark] .cq-opt-row input[type=text] { background: #232327; border-color: rgba(255, 255, 255, 0.14); color: #F5F5F7; }
        [data-dark] .cq-toggle { background: rgba(255, 255, 255, 0.055); border-color: rgba(255, 255, 255, 0.14); }
        [data-dark] .cq-q-card { background: #1D1D21; border-color: rgba(255, 255, 255, 0.14); }
        [data-dark] .cq-switch .cq-slider { background: #34343A; }

        /* ── Nav auth button / user pill ── */
        .nav-auth-btn {
            background: var(--violet);
            color: white;
            border: none;
            border-radius: 999px;
            padding: 6px 13px;
            font-family: var(--font-ui);
            font-size: 0.8rem;
            font-weight: 700;
            cursor: var(--cur-point, pointer);
            transition: all 0.18s;
        }

        .nav-auth-btn:hover {
            background: #4c43d4;
        }

        /* Just a circular profile picture (Quizlet-style) — no username text */
        .nav-user-pill {
            display: none;
            align-items: center;
            padding: 0;
            background: none;
            border: none;
            border-radius: 50%;
            cursor: var(--cur-point, pointer);
            transition: box-shadow 0.15s, transform 0.1s;
        }

        .nav-user-pill:hover {
            transform: translateY(-1px);
        }

        .nav-user-avatar {
            width: 32px;
            height: 32px;
            background: var(--violet);
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 0.8rem;
            font-weight: 800;
            color: white;
            flex-shrink: 0;
            overflow: hidden;
            box-shadow: 0 0 0 2px var(--card, #fff), 0 0 0 3px rgba(91, 80, 232, 0.25);
            transition: box-shadow 0.15s;
        }

        .nav-user-pill:hover .nav-user-avatar {
            box-shadow: 0 0 0 2px var(--card, #fff), 0 0 0 4px rgba(91, 80, 232, 0.55);
        }

        .nav-user-avatar svg {
            width: 100%;
            height: 100%;
            display: block;
        }

        .nav-user-email { display: none; }   /* show only the avatar circle */

        /* ═══════════════════════════════════════════════════
           POLISH LAYER — refinement pass. Purely additive:
           micro-interactions, branded details and motion
           preferences on top of the existing design language.
        ═══════════════════════════════════════════════════ */

        /* Crisper glyph rendering on macOS/iOS */
        body {
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
        }

        /* Branded text selection */
        ::selection {
            background: rgba(91, 80, 232, .22);
        }

        [data-dark] ::selection {
            background: rgba(255, 255, 255, 0.18);
        }

        /* Slim, violet-tinted scrollbars */
        html {
            scrollbar-width: thin;
            scrollbar-color: rgba(91, 80, 232, .35) transparent;
        }

        ::-webkit-scrollbar {
            width: 9px;
            height: 9px;
        }

        ::-webkit-scrollbar-track {
            background: transparent;
        }

        ::-webkit-scrollbar-thumb {
            background: rgba(91, 80, 232, .28);
            border-radius: 99px;
            border: 2px solid transparent;
            background-clip: padding-box;
        }

        ::-webkit-scrollbar-thumb:hover {
            background: rgba(91, 80, 232, .5);
            border: 2px solid transparent;
            background-clip: padding-box;
        }

        /* Visible keyboard-navigation focus ring (mouse clicks unaffected) */
        button:focus-visible,
        a:focus-visible,
        input:focus-visible,
        textarea:focus-visible,
        select:focus-visible,
        [role="button"]:focus-visible,
        .menu-item:focus-visible,
        .option:focus-visible {
            outline: 2px solid var(--violet);
            outline-offset: 2px;
        }

        /* dark mode: violet #5b50e8 is ~3.0:1 on #111113 — periwinkle clears WCAG-AA */
        [data-dark] :focus-visible { outline-color: #9d94ff; }

        /* No grey tap-flash on mobile — the elements' own hover/active
           states provide the feedback instead */
        button,
        a,
        .option,
        .menu-item,
        .hamburger,
        .tab-btn,
        .upload-area,
        .essay-type-chip {
            -webkit-tap-highlight-color: transparent;
        }

        /* Native widgets (date pickers, checkboxes) match the brand */
        input,
        select,
        progress {
            accent-color: var(--violet);
        }

        /* Answered options keep their solid fill on hover — the generic
           .option.disabled:hover reset (both themes) must not wash out the
           full-colour correct/wrong states */
        .option.disabled.correct,
        .option.disabled.correct:hover,
        .option.disabled.timeout-correct,
        .option.disabled.timeout-correct:hover {
            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
            border-color: #059669;
        }

        .option.disabled.wrong,
        .option.disabled.wrong:hover {
            background: linear-gradient(135deg, #f43f5e 0%, #e11d48 100%);
            border-color: #e11d48;
        }

        /* Tactile press feedback on answer options and chips */
        .option:active {
            transform: translateX(3px) scale(.985);
        }

        .essay-type-chip:active,
        .tab-btn:active {
            transform: scale(.96);
        }

        .nav-dash-btn:active,
        .nav-auth-btn:active {
            transform: translateY(0) scale(.97);
        }

        /* Gentle cross-fade when switching light/dark theme.
           nav keeps its existing box-shadow transition. */
        body,
        .input-card,
        .section-page,
        .section-card,
        .tabs {
            transition: background-color .35s ease, border-color .35s ease;
        }

        nav {
            transition: box-shadow .3s, background-color .35s ease, border-color .35s ease;
        }

        /* Smooth in-page scrolling (planner/settings jump links) */
        html {
            scroll-behavior: smooth;
        }

        /* mini mascot head used on section pages */
        .bot-head-svg {
            display: inline-block;
            vertical-align: -8px;
            margin-right: 10px;
            animation: botHeadBob 4.8s ease-in-out infinite;
        }

        @keyframes botHeadBob {

            0%,
            100% {
                transform: translateY(0);
            }

            50% {
                transform: translateY(-3px);
            }
        }


        /* mobile touch targets: keep every tappable control comfortably large */
        @media(max-width:600px) {
            .nav-dash-btn {
                padding: 9px 12px;
            }

            .hint-btn {
                padding: 11px 16px;
            }

            .fc-btn {
                padding: 11px 16px;
            }
        }

        /* ── CONCEPT MAP ── */
        .cmap-wrap {
            overflow-x: auto;
            border: 1.5px solid rgba(91, 80, 232, .15);
            border-radius: 16px;
            background: var(--card-bg, #fff);
            padding: 10px;
        }

        .cmap-wrap svg {
            min-width: 700px;
            width: 100%;
            height: auto;
            display: block;
        }

        .cmap-node {
            cursor: var(--cur-point, pointer);
        }

        .cmap-node rect {
            fill: var(--card-bg, #fff);
            stroke: rgba(91, 80, 232, .45);
            stroke-width: 1.5;
        }

        .cmap-node:hover rect {
            stroke: var(--violet);
            stroke-width: 2.5;
        }

        .cmap-node text {
            font-family: var(--font-ui);
            font-size: 11.5px;
            font-weight: 800;
            fill: var(--text-primary);
            pointer-events: none;
        }

        .cmap-node.center rect {
            fill: var(--violet);
            stroke: none;
        }

        .cmap-node.center text {
            fill: #ffffff;
            font-size: 12.5px;
        }

        .cmap-node.child rect {
            stroke: rgba(91, 80, 232, .25);
        }

        .cmap-node.child text {
            font-weight: 700;
            font-size: 10.5px;
        }

        .cmap-edge {
            stroke: rgba(91, 80, 232, .3);
            stroke-width: 1.5;
            fill: none;
        }

        .cmap-rel {
            font-family: var(--font-ui);
            font-size: 8.5px;
            font-style: italic;
            font-weight: 700;
            fill: var(--text-muted);
        }

        .cmap-hint {
            font-size: .82rem;
            font-weight: 700;
            color: var(--violet);
            margin-bottom: 10px;
        }

        [data-dark] .cmap-wrap,
        [data-dark] .cmap-node rect {
            background: #1D1D21;
        }

        [data-dark] .cmap-node rect {
            fill: #1D1D21;
        }

        .cmap-node:focus-visible { outline: none; }
        .cmap-node:focus-visible rect { stroke: var(--text-primary); stroke-width: 3; }

        /* ── ESSAY RUBRIC CRITERIA + REWRITE ── */
        .ec-row {
            margin-bottom: 12px;
        }

        .ec-head {
            display: flex;
            justify-content: space-between;
            align-items: baseline;
            margin-bottom: 4px;
        }

        .ec-name {
            font-weight: 800;
            font-size: .84rem;
            color: var(--text-primary);
        }

        .ec-score {
            font-weight: 900;
            font-size: .8rem;
        }

        .ec-score.good { color: #16a34a; }
        .ec-score.mid { color: #d97706; }
        .ec-score.low { color: #dc2626; }

        .ec-bar {
            height: 7px;
            border-radius: 99px;
            background: rgba(91, 80, 232, .1);
            overflow: hidden;
        }

        .ec-fill {
            height: 100%;
            border-radius: 99px;
        }

        .ec-fill.good { background: #22c55e; }
        .ec-fill.mid { background: #f59e0b; }
        .ec-fill.low { background: #ef4444; }

        .ec-comment {
            font-size: .78rem;
            color: var(--text-muted);
            margin-top: 4px;
            line-height: 1.45;
        }

        .ec-rw {
            position: relative;
            border-radius: 12px;
            padding: 12px 14px 12px 14px;
            font-size: .86rem;
            line-height: 1.55;
            margin-top: 10px;
        }

        .ec-rw-label {
            display: inline-block;
            font-size: .64rem;
            font-weight: 900;
            text-transform: uppercase;
            letter-spacing: .07em;
            border-radius: 99px;
            padding: 2px 9px;
            margin-bottom: 6px;
            margin-right: 8px;
        }

        .ec-rw-before {
            background: rgba(245, 158, 11, .07);
            border: 1.5px solid rgba(245, 158, 11, .25);
        }

        .ec-rw-before .ec-rw-label {
            background: rgba(245, 158, 11, .15);
            color: #d97706;
        }

        .ec-rw-after {
            background: rgba(34, 197, 94, .07);
            border: 1.5px solid rgba(34, 197, 94, .25);
        }

        .ec-rw-after .ec-rw-label {
            background: rgba(34, 197, 94, .15);
            color: #16a34a;
        }

        /* ── SYLLABUS DOT POINTS ── */
        .syl-toggle {
            display: inline-flex;
            align-items: center;
            gap: 7px;
            background: rgba(91, 80, 232, .06);
            border: 1.5px solid rgba(91, 80, 232, .2);
            color: var(--violet);
            font-family: var(--font-ui);
            font-weight: 800;
            font-size: .82rem;
            border-radius: 999px;
            padding: 8px 14px;
            cursor: var(--cur-point, pointer);
        }

        .syl-count {
            background: var(--violet);
            color: #fff;
            font-size: .68rem;
            border-radius: 99px;
            padding: 1px 8px;
        }

        .syl-chev {
            opacity: .6;
            transition: transform .2s ease;
        }

        .syl-toggle.open .syl-chev {
            transform: rotate(180deg);
        }

        .syl-body {
            margin-top: 10px;
            border: 1.5px solid rgba(91, 80, 232, .15);
            border-radius: 16px;
            padding: 14px;
            background: var(--card-bg, #fff);
        }

        .syl-all-toggle {
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: .75rem;
            font-weight: 700;
            color: var(--text-muted);
            margin-bottom: 10px;
            cursor: var(--cur-point, pointer);
        }

        .syl-list {
            max-height: 260px;
            overflow-y: auto;
        }

        .syl-group {
            font-size: .7rem;
            font-weight: 800;
            text-transform: uppercase;
            letter-spacing: .07em;
            color: var(--violet);
            margin: 10px 0 4px;
        }

        .syl-row {
            display: flex;
            align-items: flex-start;
            gap: 9px;
            padding: 6px 4px;
            border-radius: 8px;
            cursor: var(--cur-point, pointer);
            font-size: .84rem;
            line-height: 1.45;
            color: var(--text-primary);
        }

        .syl-row:hover {
            background: rgba(91, 80, 232, .05);
        }

        .syl-row input {
            margin-top: 3px;
            accent-color: var(--violet);
            flex-shrink: 0;
        }

        .syl-actions {
            display: flex;
            align-items: center;
            gap: 12px;
            margin-top: 10px;
            flex-wrap: wrap;
        }

        .syl-hint {
            font-size: .72rem;
            color: var(--text-muted);
        }

        .syl-empty {
            font-size: .82rem;
            color: var(--text-muted);
            padding: 8px 4px;
        }

        [data-dark] .syl-body {
            background: #1D1D21;
        }

        /* ── TOPICS ── */
        /* The name column used to be the 1fr one, so at 1080px the topic
           sat on the far left and its bar started 640px away with nothing in
           between. The measurement belongs next to the thing it measures:
           the name is capped, the bar takes the space it needs (to 420), and
           the numbers and the action close the row. */
        .tm-row {
            display: grid;
            grid-template-columns: minmax(180px, 260px) minmax(0, 420px) 92px auto;
            align-items: center;
            gap: 8px 16px;
            padding: 11px 2px;
            border-bottom: 1px solid var(--study-line, rgba(14, 18, 32, .09));
        }

        @media (hover: hover) {
            #topicMasteryList .tm-row:hover {
                background: rgba(91, 80, 232, .04);
            }
        }

        /* One line, under the head, for the mark on every track. A div,
           not a p: `.study-tool-page > p` caps paragraphs at a 720px measure
           and the auto margins then centre them, which put the legend 180px
           right of the head it belongs to. */
        #statsPage .tm-legend {
            margin-bottom: 14px;
            font-size: .78rem;
            color: var(--study-muted, var(--text-muted));
        }

        /* Nothing to explain while the list is empty. */
        #statsPage:has(#topicMasteryList:empty) .tm-legend {
            display: none;
        }

        #topicMasteryList .tm-row:last-child {
            border-bottom: 0;
        }

        .tm-info {
            min-width: 0;
            display: flex;
            flex-direction: column;
        }

        .tm-topic {
            font-family: var(--font-display, var(--font-ui));
            font-weight: 800;
            font-size: .92rem;
            line-height: 1.25;
            color: var(--study-ink, var(--text-primary));
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .tm-sub {
            font-size: .72rem;
            color: var(--study-muted, var(--text-muted));
        }

        /* The bar IS the measurement, so it is the one violet on the list.
           The old traffic-light fill said "you are failing" in red on the
           page a struggling student opens most. */
        .tm-bar {
            position: relative;
            width: 100%;
            height: 6px;
            border-radius: 99px;
            background: rgba(91, 80, 232, .12);
        }

        /* The 70% target, marked on the track itself — the debrief's "the bar
           carries its own reference" rather than a second colour saying pass
           and fail. A pseudo-element, so the row is still the two nodes the
           renderer writes. (`overflow: hidden` had to go with it; .tm-fill
           rounds its own ends.) */
        .tm-bar::after {
            content: '';
            position: absolute;
            left: 70%;
            top: 50%;
            width: 1px;
            height: 10px;
            transform: translateY(-50%);
            background: var(--study-muted, var(--text-muted));
        }

        .tm-fill {
            height: 100%;
            border-radius: 99px;
            background: var(--violet);
        }

        .tm-pct {
            font-variant-numeric: tabular-nums;
            font-weight: 800;
            font-size: .8rem;
            text-align: right;
            color: var(--study-ink, var(--text-primary));
            white-space: nowrap;
        }

        .tm-action {
            justify-self: start;
            padding: 0;
            border: 0;
            background: none;
            font-family: inherit;
            font-size: .8rem;
            font-weight: 800;
            color: var(--violet);
            white-space: nowrap;
            cursor: var(--cur-point, pointer);
        }

        .tm-action:hover {
            text-decoration: underline;
        }

        .tm-action:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 3px;
            border-radius: 6px;
        }

        [data-dark] .tm-action:focus-visible {
            outline-color: #9d94ff;
        }

        /* On a phone the name takes its own line above the bar, and the
           bar, the numbers and the action share the one under it — 130px of
           bar next to a truncated name was neither a label nor a
           measurement. */
        @media (max-width: 560px) {
            .tm-row {
                grid-template-columns: minmax(0, 1fr) 92px minmax(72px, auto);
                gap: 7px 12px;
            }

            .tm-info {
                grid-column: 1 / -1;
            }

            .tm-action {
                justify-self: end;
            }
        }

        [data-dark] .tm-bar {
            background: rgba(255, 255, 255, 0.08);
        }

        /* ── INSTALL PROMPT ── */
        .install-banner {
            display: flex;
            align-items: center;
            gap: 12px;
            margin: 20px 0;
            padding: 13px 16px;
            border-radius: 16px;
            background: var(--card-bg, #fff);
            border: 1.5px dashed rgba(91, 80, 232, .35);
        }

        .install-avi {
            flex-shrink: 0;
            line-height: 0;
            animation: aviBob 3.4s ease-in-out infinite;
        }

        .install-text { flex: 1; min-width: 0; }

        .install-title { font-weight: 800; font-size: .92rem; color: var(--text-primary); }

        .install-sub { font-size: .8rem; color: var(--text-muted); line-height: 1.45; }

        .install-btn {
            background: var(--violet);
            color: #fff;
            border: none;
            border-radius: 999px;
            padding: 9px 18px;
            font-family: var(--font-ui);
            font-weight: 800;
            font-size: .85rem;
            cursor: var(--cur-point, pointer);
            white-space: nowrap;
        }

        .install-x {
            background: none;
            border: none;
            color: var(--text-muted);
            cursor: var(--cur-point, pointer);
            font-size: 1rem;
            flex-shrink: 0;
        }

        [data-dark] .install-banner { background: #1D1D21; }

        /* ── DAILY CHALLENGE ── */
        .daily-challenge-banner {
            display: flex;
            align-items: center;
            gap: 14px;
            margin: 20px 0;
            padding: 15px 18px;
            border-radius: 16px;
            cursor: var(--cur-point, pointer);
            color: #fff;
            background: linear-gradient(120deg, #5b50e8, #7a5af5 55%, #18c0dd 135%);
            box-shadow: 0 8px 26px rgba(91, 80, 232, .32);
            transition: transform .15s ease, box-shadow .15s ease;
        }

        .daily-challenge-banner:hover {
            transform: translateY(-2px);
            box-shadow: 0 12px 32px rgba(91, 80, 232, .42);
        }

        .daily-challenge-banner:focus-visible {
            outline: 3px solid rgba(255, 255, 255, .9);
            outline-offset: 2px;
            border-radius: 16px;
        }

        @media (hover: none) {
            .daily-challenge-banner:hover { transform: none; box-shadow: 0 8px 26px rgba(91, 80, 232, .32); }
        }

        .daily-challenge-banner.done {
            background: linear-gradient(120deg, #16a34a, #22c55e);
            box-shadow: 0 8px 26px rgba(34, 197, 94, .3);
        }

        .daily-challenge-banner.in-progress {
            background: linear-gradient(120deg, #d97706, #f59e0b);
            box-shadow: 0 8px 26px rgba(245, 158, 11, .3);
        }

        .dc-icon {
            width: 40px;
            height: 40px;
            border-radius: 12px;
            background: rgba(255, 255, 255, .18);
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
        }

        .dc-text { flex: 1; min-width: 0; }

        .dc-title { font-weight: 900; font-size: 1rem; }

        .dc-sub { font-size: .82rem; opacity: .9; }

        .dc-cta {
            font-weight: 800;
            font-size: .85rem;
            background: rgba(255, 255, 255, .2);
            padding: 8px 14px;
            border-radius: 999px;
            white-space: nowrap;
        }

        /* ── ONBOARDING ── */
        #onboard {
            position: fixed;
            inset: 0;
            z-index: 2030;   /* above nav so the spotlight dims everything */
            /* The container spans the viewport only so the spotlight can be
               positioned against it — it draws nothing itself. Left hit-testable
               it swallowed every click on the page underneath, including the
               whole nav, and including the control each step points at: step one
               says "pick a subject right here" over a picker the overlay would
               not let you reach. The dim is a box-shadow on #onboardSpot, which
               is already pointer-events:none, so passing clicks through costs
               nothing visually. Only the coach card takes input. */
            pointer-events: none;
        }

        #onboardSpot {
            position: fixed;
            border-radius: 16px;
            box-shadow: 0 0 0 9999px rgba(15, 12, 40, .68);
            outline: 3px solid var(--violet);
            outline-offset: 3px;
            pointer-events: none;
            transition: all .4s cubic-bezier(.4, 0, .2, 1);
            opacity: 0;
        }

        #onboardSpot.on { opacity: 1; }

        #onboardCard {
            position: fixed;
            pointer-events: auto;   /* Skip / Next, on a pass-through overlay */
            display: flex;
            gap: 12px;
            align-items: flex-start;
            max-width: 340px;
            background: var(--card-bg, #fff);
            border: 1.5px solid rgba(91, 80, 232, .25);
            border-radius: 20px;
            padding: 16px;
            box-shadow: 0 18px 50px rgba(15, 12, 40, .35);
            transition: top .4s cubic-bezier(.4, 0, .2, 1), left .4s cubic-bezier(.4, 0, .2, 1);
        }

        #onboardAvi {
            width: 50px;
            height: 84px;
            flex-shrink: 0;
            margin: -6px 0 0 -2px;
            transform-origin: 50% 70%;
            animation: aviBob 2.8s ease-in-out infinite;
        }

        #onboardAvi.pop { animation: aviFlyIn .9s cubic-bezier(.34, 1.7, .5, 1), aviBob 2.8s ease-in-out .9s infinite; }

        .onboard-body { flex: 1; min-width: 0; }

        .onboard-text {
            font-size: .92rem;
            font-weight: 700;
            line-height: 1.5;
            color: var(--text-primary);
            margin-bottom: 12px;
        }

        .onboard-row {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .onboard-skip {
            background: none;
            border: none;
            color: var(--text-muted);
            font-family: var(--font-ui);
            font-weight: 700;
            font-size: .8rem;
            cursor: var(--cur-point, pointer);
        }

        .onboard-dots {
            display: flex;
            gap: 5px;
            flex: 1;
            justify-content: center;
        }

        .onboard-dots span {
            width: 7px;
            height: 7px;
            border-radius: 50%;
            background: rgba(91, 80, 232, .25);
        }

        .onboard-dots span.on { background: var(--violet); }

        .onboard-next {
            background: var(--violet);
            color: #fff;
            border: none;
            border-radius: 999px;
            padding: 8px 16px;
            font-family: var(--font-ui);
            font-weight: 800;
            font-size: .82rem;
            cursor: var(--cur-point, pointer);
        }

        [data-dark] #onboardCard { background: #1D1D21; }

        /* Phones: the float-near-the-target layout had nowhere safe to land — the
           card was positioned from a target that was often still below the fold,
           so it clipped past the viewport edge (and sat under the analytics
           banner). Dock it to the bottom instead: always fully on screen, always
           the same place, and the spotlight above it still does the pointing.
           JS reads this class to skip its own positioning — keep them in sync. */
        @media (max-width: 600px) {
            #onboardCard {
                max-width: none;
                left: 12px !important;
                right: 12px;
                top: auto !important;
                bottom: calc(12px + env(safe-area-inset-bottom, 0px));
            }
        }

        /* ── AVATARS ── */
        .nav-user-avatar svg {
            border-radius: 50%;
        }

        .avatar-grid {
            display: flex;
            gap: 12px;
            flex-wrap: wrap;
            margin-top: 14px;
        }

        .avatar-tile {
            position: relative;
            width: 60px;
            height: 60px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: rgba(91, 80, 232, .05);
            border: 2px solid transparent;
            border-radius: 16px;
            padding: 0;
            cursor: var(--cur-point, pointer);
            line-height: 0;
            transition: transform .15s ease, box-shadow .15s ease, background .15s ease, border-color .15s ease;
        }

        .avatar-tile svg {
            width: 44px;
            height: 44px;
            border-radius: 50%;
        }

        .avatar-tile:hover {
            background: rgba(91, 80, 232, .1);
        }

        .avatar-tile:focus-visible {
            outline: 2px solid var(--violet);
            outline-offset: 3px;
        }

        .avatar-tile.selected {
            border-color: var(--violet);
            background: rgba(91, 80, 232, .12);
        }

        /* check badge on the chosen avatar */
        .avatar-tile.selected::after {
            content: '';
            position: absolute;
            top: -6px;
            right: -6px;
            width: 21px;
            height: 21px;
            border-radius: 50%;
            background: var(--violet) url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2012%2012'%20fill='none'%20stroke='white'%20stroke-width='2.2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpolyline%20points='2,6.4%205,9%2010,3'/%3E%3C/svg%3E") no-repeat center/12px;
            border: 2px solid var(--card-bg, #fff);
        }

        [data-dark] .avatar-tile { background: rgba(255, 255, 255, 0.055); }
        [data-dark] .avatar-tile:hover { background: rgba(255, 255, 255, 0.08); }
        [data-dark] .avatar-tile.selected { background: rgba(157, 148, 255, 0.16); }
        [data-dark] .avatar-tile.selected::after { border-color: #1D1D21; }

        /* Rarity stays in picker metadata so the portrait itself remains clear. */
        .avatar-tile .av-tier {
            position: absolute; bottom: -3px; left: 50%; transform: translateX(-50%);
            width: 14px; height: 5px; border-radius: 999px; box-shadow: 0 1px 2px rgba(0,0,0,.2);
        }
        .avatar-tile.locked:hover { transform: none; box-shadow: none; background: rgba(91,80,232,.05); }
        .avatar-tile .av-lock {
            position: absolute; right: -3px; bottom: -3px;
            width: 21px; height: 21px; display: grid; place-items: center;
            border: 2px solid var(--card-bg, #fff); border-radius: 50%;
            background: #242338; color: #fff;
        }
        .avatar-tile .av-lock svg { width: 11px; height: 11px; border-radius: 0; }
        .avatar-tile.locked.selected { border-color: transparent; box-shadow: none; }
        .avatar-tile.locked.selected::after { display: none; }
        @keyframes avShake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-5px)} 75%{transform:translateX(5px)} }
        .avatar-tile.shake { animation: avShake .32s ease; }
        .avatar-hint {
            display: none; margin-top: 10px; font-weight: 800; font-size: .85rem;
            color: var(--violet); background: rgba(91,80,232,.1);
            padding: 8px 12px; border-radius: 12px; text-align: center;
        }
        [data-dark] .avatar-hint { background: rgba(255, 255, 255, 0.08); color: #c7bfff; }

        /* ── ACCOUNT PAGE ──
           The screen itself is designed under "B · ACCOUNT" further down,
           scoped to #accountPage. Only the two shared identity lines live
           here, at the same level as the avatar + auth-form hooks above. */
        .acct-email {
            font-family: var(--font-display);
            font-weight: 800;
            font-size: 1.16rem;
            line-height: 1.25;
            color: var(--text-primary);
            overflow-wrap: anywhere;
        }

        .acct-sub {
            font-size: .85rem;
            color: var(--text-muted);
            margin-top: 2px;
            overflow-wrap: anywhere;
        }
        /* An account with no username has no second line to show, and an empty
           div would still take its margin under the name. */
        .acct-sub:empty { display: none; }

        /* ── Plan & billing card ──
           Cancelling and switching plans happen here rather than on a hosted
           page somewhere else. The moment you send someone away to cancel you
           have made cancelling feel like something you are resisting. */
        /* ?account=plan lands ON this card, and the app's top bar is fixed —
           without this the heading it scrolls to sits underneath it. */
        #acctPlanCard { scroll-margin-top: 68px; }
        /* The band up top answers "what am I on, and what happens next" before
           anything below asks for a decision. */
        .plan-status {
            background: linear-gradient(135deg, rgba(91, 80, 232, .09), rgba(139, 92, 246, .045));
            border: 1.5px solid rgba(91, 80, 232, .15);
            border-radius: 14px; padding: 13px 15px; margin: 14px 0 0;
        }
        .plan-now { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
        .plan-now-name {
            font-family: var(--font-display); font-weight: 800;
            font-size: 1.35rem; line-height: 1.15; color: var(--text-primary);
        }
        .plan-now-term {
            font-size: .68rem; font-weight: 900; letter-spacing: .05em;
            text-transform: uppercase; color: var(--violet, #5b50e8);
            background: rgba(91, 80, 232, .13); border-radius: 999px; padding: 4px 9px;
        }
        .plan-when { color: var(--text-muted, #6b6890); font-size: .85rem; font-weight: 600; margin-top: 3px; }
        .plan-when strong { color: inherit; }
        .plan-ending {
            background: rgba(234, 88, 12, .1); color: #c2410c;
            border-left: 3px solid #ea580c;
            border-radius: 4px 12px 12px 4px; padding: 10px 13px;
            font-size: .85rem; font-weight: 700; line-height: 1.45; margin-top: 10px;
        }
        [data-dark] .plan-status {
            background: linear-gradient(135deg, rgba(255, 255, 255, 0.055), rgba(139, 92, 246, .06));
            border-color: rgba(255, 255, 255, 0.14);
        }
        [data-dark] .plan-now-term { color: #c7bfff; background: rgba(255, 255, 255, 0.08); }
        [data-dark] .plan-ending { background: rgba(251, 146, 60, .14); color: #fdba74; }

        /* Monthly and annual used to share one list, so every plan appeared
           twice under the same name and the list was read as eight products
           instead of four. One term at a time; the other is a click away. */
        .plan-switch {
            display: flex; gap: 4px; margin: 16px 0 12px; padding: 4px;
            background: rgba(91, 80, 232, .07); border-radius: 13px;
        }
        .plan-switch[hidden] { display: none; }
        .plan-switch-opt {
            flex: 1; display: flex; align-items: center; justify-content: center; gap: 7px;
            font: inherit; font-size: .85rem; font-weight: 800; color: var(--text-muted, #6b6890);
            background: transparent; border: 0; border-radius: 10px; padding: 9px 10px;
            cursor: var(--cur-point, pointer); transition: background .15s ease, color .15s ease;
        }
        .plan-switch-opt[aria-pressed="true"] {
            background: var(--card-bg, #fff); color: var(--text-primary);
            box-shadow: 0 1px 3px rgba(17, 24, 39, .1);
        }
        .plan-switch-opt:focus-visible { outline: 3px solid rgba(91, 80, 232, .4); outline-offset: 1px; }
        .plan-save, .plan-offer-tag.save {
            font-size: .64rem; font-weight: 900; letter-spacing: .03em; text-transform: uppercase;
            color: var(--emerald, #059669); background: var(--emerald-bg, rgba(5, 150, 105, .07));
            border: 1px solid var(--emerald-border, rgba(5, 150, 105, .25));
            border-radius: 999px; padding: 2px 7px; white-space: nowrap;
        }
        .plan-save[hidden] { display: none; }
        [data-dark] .plan-switch { background: rgba(255, 255, 255, 0.055); }
        [data-dark] .plan-switch-opt[aria-pressed="true"] { background: #34343A; }
        [data-dark] .plan-save, [data-dark] .plan-offer-tag.save { color: #6ee7b7; }

        .plan-offers { display: flex; flex-direction: column; gap: 9px; margin-bottom: 16px; }
        .plan-group-label {
            font-size: .68rem; font-weight: 900; letter-spacing: .08em;
            text-transform: uppercase; color: var(--text-muted, #6b6890);
            margin: 7px 2px 0;
        }
        .plan-offers > .plan-group-label:first-child { margin-top: 0; }
        .plan-offer {
            position: relative; display: flex; align-items: center; gap: 14px; width: 100%;
            text-align: left; font: inherit; cursor: var(--cur-point, pointer);
            border: 1.5px solid rgba(91, 80, 232, .16); background: var(--card-bg, #fff);
            border-radius: 15px; padding: 13px 15px;
            transition: border-color .15s ease, background .15s ease,
                        transform .15s ease, box-shadow .15s ease;
        }
        .plan-offer:hover:not([disabled]) {
            border-color: var(--violet, #5b50e8); background: rgba(91, 80, 232, .04);
            transform: translateY(-1px); box-shadow: 0 6px 16px rgba(91, 80, 232, .13);
        }
        .plan-offer:focus-visible { outline: 3px solid rgba(91, 80, 232, .45); outline-offset: 2px; }
        .plan-offer[disabled] { cursor: default; }
        /* The row you are already on is a fact, not a dimmed-out option: the
           dashed, faded treatment it had read as "unavailable". */
        .plan-offer.is-current {
            border-color: var(--violet, #5b50e8);
            background: rgba(91, 80, 232, .07);
            box-shadow: inset 3px 0 0 var(--violet, #5b50e8);
        }
        .plan-offer-main { flex: 1; min-width: 0; }
        .plan-offer-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
        .plan-offer-name { font-weight: 800; font-size: 1rem; color: var(--text-primary); }
        .plan-offer-sub {
            font-size: .79rem; color: var(--text-muted, #6b6890);
            font-weight: 600; line-height: 1.45; margin-top: 2px;
        }
        .plan-offer-cost { text-align: right; flex-shrink: 0; }
        .plan-offer-price {
            font-family: var(--font-display); font-weight: 800; font-size: 1.15rem;
            white-space: nowrap; color: var(--text-primary);
        }
        .plan-offer-price small { font-size: .72rem; font-weight: 800; color: var(--text-muted, #6b6890); }
        .plan-offer-per {
            font-size: .71rem; font-weight: 700; white-space: nowrap;
            color: var(--text-muted, #6b6890); margin-top: 1px;
        }
        .plan-offer-tag {
            font-size: .64rem; font-weight: 900; letter-spacing: .04em;
            text-transform: uppercase; color: var(--violet, #5b50e8);
            background: rgba(91, 80, 232, .12); border-radius: 999px; padding: 3px 8px;
        }
        [data-dark] .plan-offer { border-color: rgba(255, 255, 255, 0.14); background: rgba(255, 255, 255, 0.03); }
        [data-dark] .plan-offer.is-current { background: rgba(157, 148, 255, 0.13); }
        [data-dark] .plan-offer-tag { color: #b9b2ff; background: rgba(255, 255, 255, 0.08); }

        .plan-actions {
            display: flex; flex-wrap: wrap; align-items: center; gap: 4px 18px;
            border-top: 1px solid rgba(91, 80, 232, .1); padding-top: 10px;
        }
        .plan-actions[hidden] { display: none; }
        .plan-link, .plan-compare {
            font: inherit; font-size: .85rem; font-weight: 800;
            background: transparent; border: 0; padding: 8px 2px;
            color: var(--text-muted, #6b6890); cursor: var(--cur-point, pointer);
            text-decoration: underline; text-underline-offset: 3px;
        }
        .plan-link:hover, .plan-compare:hover { color: var(--violet, #5b50e8); }
        .plan-link.danger:hover { color: #dc2626; }
        [data-dark] .plan-link.danger:hover { color: #f87171; }
        /* Last, and away from the buttons: leaving for the pricing page is the
           least likely thing anybody opens this card to do. */
        .plan-compare { margin-left: auto; }
        .plan-actions.no-buttons .plan-compare { margin-left: 0; }
        .plan-msg { font-size: .88rem; font-weight: 700; margin-top: 10px; min-height: 18px; }
        .plan-msg:empty { min-height: 0; margin-top: 0; }

        /* Receipts, in the card. "What have I paid?" is not a question worth
           a trip to a hosted portal either — and the portal was the only place
           the answer lived. */
        .plan-invoices {
            margin-top: 14px; border-top: 1px solid rgba(91, 80, 232, .12); padding-top: 12px;
        }
        .plan-invoices[hidden] { display: none; }
        .plan-invoices-head {
            font-size: .68rem; font-weight: 900; letter-spacing: .08em;
            text-transform: uppercase; color: var(--text-muted, #6b6890);
            margin: 0 2px 4px;
        }
        /* Two cells, always: what the invoice was for on the left, what it cost
           and where to read it on the right. Both halves wrap inside their own
           cell rather than pushing the other off a narrow screen. */
        .plan-inv-row {
            display: grid; grid-template-columns: 1fr auto; gap: 2px 12px;
            align-items: start; padding: 8px 0;
            border-bottom: 1px solid rgba(91, 80, 232, .08); font-size: .86rem;
        }
        .plan-inv-row:last-child { border-bottom: 0; }
        /* Deliberately no min-width:0 and no overflow on this cell — either
           one zeroes its automatic minimum, and a wide right-hand cell then
           squeezes the track narrower than the non-wrapping date and clips it.
           The description's overflow-wrap keeps that minimum to the date. */
        /* The date never wraps: letting it break to three lines is how the
           right-hand column takes width it has somewhere else to go. */
        .plan-inv-date { font-weight: 800; white-space: nowrap; color: var(--text-primary); }
        .plan-inv-desc {
            color: var(--text-muted, #6b6890); font-weight: 600;
            line-height: 1.4; overflow-wrap: anywhere;
        }
        .plan-inv-side {
            display: flex; flex-wrap: wrap; align-items: center;
            justify-content: flex-end; gap: 4px 8px; text-align: right;
        }
        .plan-inv-amount { font-weight: 800; white-space: nowrap; color: var(--text-primary); }
        .plan-inv-status {
            font-size: .62rem; font-weight: 900; letter-spacing: .04em;
            border-radius: 999px; padding: 2px 7px; white-space: nowrap;
            color: var(--text-muted, #6b6890); background: rgba(107, 104, 144, .12);
        }
        .plan-inv-status.paid {
            color: var(--emerald, #059669); background: var(--emerald-bg, rgba(5, 150, 105, .09));
        }
        .plan-inv-status.open { color: #b45309; background: rgba(234, 179, 8, .15); }
        .plan-inv-links { display: flex; gap: 10px; flex-shrink: 0; }
        .plan-inv-links a {
            font-weight: 800; color: var(--text-muted, #6b6890);
            text-decoration: underline; text-underline-offset: 3px;
        }
        .plan-inv-links a:hover { color: var(--violet, #5b50e8); }
        .plan-inv-note {
            color: var(--text-muted, #6b6890); font-weight: 600;
            font-size: .86rem; padding: 8px 0;
        }
        .plan-inv-more, .plan-inv-retry {
            font: inherit; font-size: .82rem; font-weight: 800;
            background: transparent; border: 0; padding: 8px 2px;
            color: var(--violet, #5b50e8); cursor: var(--cur-point, pointer);
            text-decoration: underline; text-underline-offset: 3px;
        }
        [data-dark] .plan-invoices { border-top-color: rgba(255, 255, 255, 0.14); }
        [data-dark] .plan-inv-row { border-bottom-color: rgba(255, 255, 255, 0.08); }
        [data-dark] .plan-inv-status { color: #c7bfff; background: rgba(255, 255, 255, 0.08); }
        [data-dark] .plan-inv-status.paid { color: #6ee7b7; background: rgba(5, 150, 105, .2); }
        [data-dark] .plan-inv-status.open { color: #fcd34d; background: rgba(234, 179, 8, .18); }
        [data-dark] .plan-inv-links a:hover { color: #b9b2ff; }
        [data-dark] .plan-inv-more, [data-dark] .plan-inv-retry { color: #b9b2ff; }

        @media (max-width: 420px) {
            .plan-offer { padding: 12px 13px; gap: 10px; }
            .plan-offer-price { font-size: 1.05rem; }
            .plan-offer-tag, .plan-save { font-size: .6rem; padding: 2px 6px; }
            .plan-switch-opt { font-size: .8rem; gap: 5px; padding: 9px 6px; }
            .plan-compare { margin-left: 0; }
            .plan-inv-row { font-size: .82rem; gap: 2px 9px; }
            .plan-inv-links { gap: 8px; }
        }

        @media (prefers-reduced-motion: reduce) {
            .plan-offer, .plan-switch-opt { transition: none; }
            .plan-offer:hover:not([disabled]) { transform: none; }
        }

        /* ── SOCIAL SIGN-IN ── */
        .btn-google,
        .btn-microsoft {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
            width: 100%;
            min-height: 48px;
            background: #ffffff;
            border: 1.5px solid rgba(91, 80, 232, .25);
            border-radius: 999px;
            font-family: var(--font-ui);
            font-weight: 800;
            font-size: .92rem;
            color: var(--text-primary);
            text-decoration: none;
            margin-bottom: 14px;
            transition: transform .15s ease, box-shadow .15s ease;
        }

        .btn-google:hover,
        .btn-microsoft:hover {
            transform: translateY(-1px);
            box-shadow: 0 6px 16px rgba(91, 80, 232, .15);
        }

        .auth-or {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 14px;
            color: var(--text-muted);
            font-size: .72rem;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: .06em;
        }

        .auth-or::before,
        .auth-or::after {
            content: '';
            flex: 1;
            height: 1px;
            background: rgba(91, 80, 232, .15);
        }

        [data-dark] .btn-google,
        [data-dark] .btn-microsoft {
            background: #232327;
        }

        /* ── HINTS ── */
        .hint-btn {
            background: rgba(245, 158, 11, .08);
            border: 1.5px solid rgba(245, 158, 11, .3);
            color: #d97706;
            font-family: var(--font-ui);
            font-weight: 800;
            font-size: .78rem;
            border-radius: 999px;
            padding: 7px 13px;
            cursor: var(--cur-point, pointer);
            margin-top: 12px;
            transition: transform .15s ease;
        }

        .hint-btn:hover {
            transform: translateY(-1px);
        }

        .hint-btn:disabled {
            opacity: .55;
            cursor: default;
            transform: none;
        }

        .hint-box {
            margin-top: 12px;
            background: rgba(245, 158, 11, .07);
            border: 1.5px solid rgba(245, 158, 11, .25);
            border-radius: 12px;
            padding: 10px 14px;
            font-size: .85rem;
            line-height: 1.5;
            color: var(--text-primary);
        }

        .hint-box b {
            color: #d97706;
        }

        [data-dark] .hint-btn {
            color: #fbbf24;
        }

        [data-dark] .hint-box b {
            color: #fbbf24;
        }

        /* ── FLASHCARDS ── */
        .fc-deck-head {
            display: flex;
            align-items: baseline;
            justify-content: space-between;
            gap: 12px;
            flex-wrap: wrap;
            margin-bottom: 10px;
        }

        .fc-deck-title {
            font-weight: 800;
            font-size: 1.05rem;
            color: var(--text-primary);
        }

        .fc-deck-progress {
            font-size: .8rem;
            font-weight: 700;
            color: var(--text-muted);
        }

        .fc-progress-bar {
            height: 6px;
            border-radius: 99px;
            background: rgba(91, 80, 232, .12);
            overflow: hidden;
            margin-bottom: 18px;
        }

        .fc-progress-fill {
            height: 100%;
            width: 0;
            border-radius: 99px;
            background: linear-gradient(90deg, #5b50e8, #8b7cf8);
            transition: width .4s ease;
        }

        .fc-card-wrap {
            perspective: 1400px;
            max-width: 620px;
            margin: 0 auto;
            position: relative;   /* anchor the corner star/audio buttons */
        }

        .fc-card {
            position: relative;
            width: 100%;
            height: clamp(300px, 44vh, 430px);
            cursor: var(--cur-point, pointer);
            transform-style: preserve-3d;
            transition: transform .55s cubic-bezier(.4, .1, .2, 1);
        }

        .fc-card.flipped {
            transform: rotateY(180deg);
        }

        .fc-face {
            position: absolute;
            inset: 0;
            backface-visibility: hidden;
            -webkit-backface-visibility: hidden;
            border-radius: 16px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            gap: 12px;
            padding: 40px 30px;
            text-align: center;
            overflow-y: auto;
        }

        /* Quizlet-style: both faces are clean white cards */
        .fc-front,
        .fc-back {
            background: var(--card-bg, #fff);
            border: 1.5px solid rgba(91, 80, 232, .16);
            box-shadow: 0 8px 28px rgba(17, 24, 39, .07), 0 2px 6px rgba(17, 24, 39, .04);
        }

        .fc-card.known .fc-front {
            border-color: rgba(34, 197, 94, .45);
        }

        .fc-back {
            color: var(--text-primary);
            transform: rotateY(180deg);
        }

        .fc-back .fc-face-label {
            color: var(--violet);
            opacity: .85;
        }

        .fc-face-label {
            font-size: .7rem;
            font-weight: 800;
            letter-spacing: .1em;
            text-transform: uppercase;
            opacity: .5;
        }

        .fc-face-text {
            font-size: clamp(1.15rem, 2.6vw, 1.65rem);
            font-weight: 700;
            line-height: 1.45;
        }

        /* corner star / audio buttons that overlay the card without flipping with it */
        .fc-corner {
            position: absolute;
            top: 14px;
            width: 38px;
            height: 38px;
            border: none;
            border-radius: 10px;
            background: transparent;
            color: var(--text-muted);
            cursor: var(--cur-point, pointer);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 3;
            transition: background .15s ease, color .15s ease;
        }

        .fc-corner-left { left: 12px; }
        .fc-corner-right { right: 12px; }
        .fc-corner:hover { background: rgba(91, 80, 232, .1); color: var(--violet); }
        .fc-corner.starred { color: #f59e0b; }
        .fc-corner.starred svg { fill: #f59e0b; }

        /* Quizlet-style nav bar: round prev/next flanking a counter */
        .fc-nav {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 24px;
            margin: 18px auto 0;
        }

        .fc-round {
            width: 48px;
            height: 48px;
            border-radius: 50%;
            border: 1.5px solid rgba(91, 80, 232, .25);
            background: var(--card-bg, #fff);
            color: var(--violet);
            cursor: var(--cur-point, pointer);
            display: flex;
            align-items: center;
            justify-content: center;
            transition: transform .15s ease, box-shadow .15s ease, background .15s ease;
        }

        .fc-round:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(91, 80, 232, .2); }
        .fc-round:active { transform: scale(.93); }

        .fc-count {
            font-family: var(--font-display);
            font-weight: 800;
            font-size: 1.05rem;
            color: var(--text-primary);
            min-width: 70px;
            text-align: center;
        }

        .fc-controls-sub { margin-top: 14px; }
        .fc-controls-sub .fc-btn { font-size: .8rem; }

        .fc-hint {
            font-size: .72rem;
            color: var(--text-muted);
            margin-top: 2px;
        }

        .fc-controls {
            display: flex;
            gap: 10px;
            justify-content: center;
            margin-top: 16px;
            flex-wrap: wrap;
        }

        .fc-btn {
            font-family: var(--font-ui);
            font-size: .85rem;
            font-weight: 800;
            padding: 9px 16px;
            border-radius: 999px;
            cursor: var(--cur-point, pointer);
            border: 1.5px solid transparent;
            transition: transform .15s ease, box-shadow .15s ease;
        }

        .fc-btn:hover {
            transform: translateY(-1px);
        }

        .fc-btn:active {
            transform: scale(.97);
        }

        .fc-btn-know {
            background: rgba(34, 197, 94, .12);
            color: #16a34a;
            border-color: rgba(34, 197, 94, .35);
        }

        .fc-btn-again {
            background: rgba(245, 158, 11, .1);
            color: #d97706;
            border-color: rgba(245, 158, 11, .35);
        }

        .fc-btn-ghost {
            background: transparent;
            color: var(--text-muted);
            border-color: rgba(91, 80, 232, .2);
        }

        .fc-done {
            text-align: center;
            padding: 30px 0 10px;
        }

        .fc-done-emoji {
            font-size: 2.2rem;
            margin-bottom: 8px;
        }

        .fc-done-title {
            font-weight: 900;
            font-size: 1.3rem;
            color: var(--text-primary);
        }

        .fc-done-sub {
            color: var(--text-muted);
            font-size: .88rem;
            max-width: 420px;
            margin: 8px auto 4px;
        }

        .fc-deck-row {
            display: flex;
            align-items: center;
            gap: 12px;
            padding: 12px 14px;
            border: 1.5px solid rgba(91, 80, 232, .15);
            border-radius: 16px;
            margin-bottom: 10px;
            background: var(--card-bg, #fff);
        }

        .fc-deck-row-info {
            flex: 1;
            min-width: 0;
        }

        .fc-deck-row-title {
            font-weight: 800;
            font-size: .92rem;
            color: var(--text-primary);
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .fc-deck-row-sub {
            font-size: .75rem;
            color: var(--text-muted);
            /* No nowrap here is how "Physics · 12 cards" became four lines with
               an orphaned "·" on one of them the moment the column narrowed.
               It is one line or it is elided; it is never a paragraph. */
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .fc-deck-row-desc {
            font-size: .78rem;
            color: var(--text-secondary, var(--text-muted));
            margin: 1px 0 2px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .fc-deck-row .fc-btn {
            padding: 7px 11px;
            font-size: .78rem;
        }

        .fc-deck-row-actions {
            display: flex;
            align-items: center;
            gap: 8px;
        }

        /* On a phone the deck NAME was losing the row outright. Six fixed-size
           controls (chip 73px, Study 66, Publish 68, and three 34-39px icons,
           plus 12px gaps) came to 386px of a 402px row, so .fc-deck-row-info
           computed to a width of exactly 0 and the title shredded one word per
           line, straight through the "Due today" pill beside it.

           So below 700px the row becomes two: what the deck IS on top, what you
           can DO with it underneath. The name gets the full width it needs and
           the actions get a line where six of them fit honestly. */
        @media (max-width: 700px) {
            .fc-deck-row {
                flex-wrap: wrap;
                column-gap: 8px;
                row-gap: 10px;
                align-items: center;
            }

            .fc-deck-row-info {
                flex: 1 1 auto;
                min-width: 0;
            }

            /* flex-basis:100% is what forces the break, so the split cannot
               depend on how wide any particular label happens to render. */
            .fc-deck-row-actions {
                flex: 1 0 100%;
                gap: 8px;
            }

            /* Study is the one thing most people came to press. */
            .fc-deck-row-actions .fc-btn-know {
                flex: 1 1 auto;
                min-width: 84px;
            }

            .fc-deck-row-actions .fc-btn-icon {
                flex: none;
                min-width: 40px;
                padding: 7px 0;
                text-align: center;
            }
        }


        [data-dark] .fc-deck-row {
            background: #1D1D21;
        }

        [data-dark] .fc-front,
        [data-dark] .fc-back {
            background: #1D1D21;
            border-color: rgba(255, 255, 255, 0.22);
        }

        [data-dark] .fc-round { background: #1D1D21; }

        [data-dark] .fc-progress-bar {
            background: rgba(91, 80, 232, .25);
        }

        @media(max-width:600px) {
            .fc-card {
                height: clamp(260px, 52vh, 360px);
            }

            .fc-face { padding: 30px 22px; }
            .fc-nav { gap: 16px; }
        }

        /* ── QUIZ BUDDY — floating robot mascot ── */
        #quizBuddy {
            position: fixed;
            left: 0;
            top: 0;
            width: 72px;
            height: 86px;
            z-index: 90;
            pointer-events: auto;
            cursor: var(--cur-point, pointer);
            opacity: 0;
            visibility: hidden;
            transform: translate(calc(100vw - 80px), calc(100vh - 190px));
            transition: transform 2.3s cubic-bezier(.5, .06, .22, 1), opacity .5s ease, visibility .5s;
            will-change: transform;
            filter: drop-shadow(0 6px 14px rgba(91, 80, 232, .35));
        }

        body.quiz-active #quizBuddy,
        body.fc-buddy #quizBuddy {
            opacity: 1;
            visibility: visible;
        }

        /* flashcards is a fixed overlay (z 1003) — lift the buddy above it */
        body.fc-buddy #quizBuddy { z-index: 1100; }

        .qb-flip {
            width: 100%;
            height: 100%;
            transition: transform .5s ease;
            animation: qbBob 3.4s ease-in-out infinite;
        }

        /* perks up when you reach for him */
        #quizBuddy svg {
            transition: scale .35s ease;
        }

        #quizBuddy:hover svg {
            scale: 1.09;
        }

        #quizBuddy.flip .qb-flip {
            transform: scaleX(-1);
        }

        @keyframes qbBob {

            0%,
            100% {
                translate: 0 0;
            }

            50% {
                translate: 0 -9px;
            }
        }

        .qb-flame {
            animation: qbFlame .5s ease-in-out infinite alternate;
            transform-origin: 256px 452px;
        }

        @keyframes qbFlame {
            from {
                transform: scaleY(.82);
                opacity: .8;
            }

            to {
                transform: scaleY(1.1);
                opacity: 1;
            }
        }

        #quizBuddy.flying .qb-flame {
            animation-duration: .22s;
        }

        .qb-antenna {
            animation: qbPing 2.4s ease-in-out infinite;
        }

        @keyframes qbPing {

            0%,
            100% {
                opacity: 1;
            }

            50% {
                opacity: .35;
            }
        }

        .qb-arm-l {
            transform-origin: 94px 348px;
            animation: qbSwayL 4.8s ease-in-out infinite;
        }

        .qb-arm-r {
            transform-origin: 420px 264px;
            animation: qbSwayR 4.8s ease-in-out infinite;
        }

        @keyframes qbSwayL {

            0%,
            100% {
                rotate: 0deg;
            }

            50% {
                rotate: 4deg;
            }
        }

        @keyframes qbSwayR {

            0%,
            100% {
                rotate: 0deg;
            }

            50% {
                rotate: -4deg;
            }
        }

        /* big friendly wave (right arm) */
        #quizBuddy.wave .qb-arm-r {
            animation: qbWave .85s ease-in-out 2;
        }

        @keyframes qbWave {

            0%,
            100% {
                rotate: 0deg;
            }

            35% {
                rotate: -60deg;
            }

            55% {
                rotate: -32deg;
            }

            80% {
                rotate: -60deg;
            }
        }

        /* mid-flight barrel roll */
        #quizBuddy.trick .qb-flip {
            animation: qbTrick 1.15s cubic-bezier(.5, .08, .45, .95);
        }

        @keyframes qbTrick {
            0% {
                rotate: 0deg;
                translate: 0 0;
            }

            50% {
                rotate: 180deg;
                translate: 0 -14px;
            }

            100% {
                rotate: 360deg;
                translate: 0 0;
            }
        }

        /* lean into the direction of travel */
        #quizBuddy.flying:not(.trick) .qb-flip {
            rotate: 8deg;
        }

        .qb-flip {
            transition: rotate .6s ease, transform .5s ease;
        }

        /* chest core pulses softly */
        .qb-light {
            animation: qbLight 2.4s ease-in-out infinite;
        }

        @keyframes qbLight {

            0%,
            100% {
                opacity: 1;
            }

            50% {
                opacity: .45;
            }
        }

        /* head bobs and tilts slightly out of phase with the body */
        .qb-head {
            transform-origin: 256px 140px;
            animation: qbHeadTilt 9.6s ease-in-out infinite;
        }

        @keyframes qbHeadTilt {

            0%,
            38%,
            82%,
            100% {
                transform: rotate(0deg) translateY(0);
            }

            18% {
                transform: rotate(-1.6deg) translateY(-.4px);
            }

            62% {
                transform: rotate(1.3deg) translateY(-.35px);
            }
        }

        /* springy antenna */
        .qb-antenna-g {
            transform-origin: 256px 60px;
            animation: qbAntennaSway 4.8s ease-in-out infinite;
        }

        @keyframes qbAntennaSway {

            0%,
            100% {
                transform: rotate(0deg);
            }

            30% {
                transform: rotate(-3deg);
            }

            65% {
                transform: rotate(2.5deg);
            }
        }

        /* antenna droops when he's sad */
        #quizBuddy.sad .qb-antenna-g {
            animation: qbAntennaDroop 1.25s ease;
        }

        @keyframes qbAntennaDroop {

            0%,
            100% {
                transform: rotate(0deg);
            }

            35%,
            75% {
                transform: rotate(-24deg);
            }
        }

        /* hover ring projected under the thruster */
        .qb-ring {
            transform-origin: 256px 466px;
            animation: qbRing 2.4s ease-in-out infinite;
        }

        @keyframes qbRing {

            0%,
            100% {
                transform: scaleX(.9);
                opacity: .15;
            }

            50% {
                transform: scaleX(1.03);
                opacity: .32;
            }
        }

        #quizBuddy.flying .qb-ring {
            opacity: 0;
            animation: none;
        }

        /* specular sheen sweeping across the chrome */
        .qb-sheen {
            animation: qbSheen 7.5s ease-in-out infinite;
        }

        @keyframes qbSheen {
            0% {
                transform: translateX(0) skewX(-18deg);
            }

            32%,
            100% {
                transform: translateX(720px) skewX(-18deg);
            }
        }

        /* sparkles pop in the visor when he celebrates */
        .qb-spark {
            opacity: 0;
            transform-box: fill-box;
            transform-origin: center;
        }

        #quizBuddy.happy .qb-spark {
            animation: qbSpark 1.25s ease;
        }

        #quizBuddy.happy .qb-spark-2 {
            animation-delay: .12s;
        }

        @keyframes qbSpark {

            0%,
            100% {
                opacity: 0;
                transform: scale(.2) rotate(0deg);
            }

            30%,
            70% {
                opacity: 1;
                transform: scale(1.15) rotate(90deg);
            }
        }

        /* ── speech bubble ── */
        .qb-bubble {
            position: absolute;
            bottom: calc(100% + 9px);
            left: 50%;
            transform: translateX(-50%) translateY(7px) scale(.8);
            background: #ffffff;
            border: 1.5px solid rgba(91, 80, 232, .32);
            color: var(--violet);
            font-family: var(--font-ui);
            font-size: .8rem;
            font-weight: 800;
            padding: 6px 12px;
            border-radius: 12px;
            white-space: nowrap;
            opacity: 0;
            pointer-events: none;
            transition: opacity .22s ease, transform .25s cubic-bezier(.34, 1.56, .64, 1);
            box-shadow: 0 5px 16px rgba(91, 80, 232, .22);
        }

        .qb-bubble::after {
            content: '';
            position: absolute;
            top: 100%;
            left: 50%;
            margin-left: -5px;
            border: 5px solid transparent;
            border-top-color: #ffffff;
        }

        .qb-bubble.show {
            opacity: 1;
            transform: translateX(-50%) translateY(0) scale(1);
        }

        /* edge-aware alignment so the bubble never leaves the viewport */
        #quizBuddy.bubble-left .qb-bubble {
            left: 0;
            transform: translateX(0) translateY(7px) scale(.8);
        }

        #quizBuddy.bubble-left .qb-bubble.show {
            transform: translateX(0) translateY(0) scale(1);
        }

        #quizBuddy.bubble-left .qb-bubble::after {
            left: 26px;
        }

        #quizBuddy.bubble-right .qb-bubble {
            left: auto;
            right: 0;
            transform: translateX(0) translateY(7px) scale(.8);
        }

        #quizBuddy.bubble-right .qb-bubble.show {
            transform: translateX(0) translateY(0) scale(1);
        }

        #quizBuddy.bubble-right .qb-bubble::after {
            left: auto;
            right: 21px;
        }

        [data-dark] .qb-bubble {
            background: #1D1D21;
            color: #a89ffb;
            border-color: rgba(255, 255, 255, 0.22);
            box-shadow: 0 5px 16px rgba(0, 0, 0, .4);
        }

        [data-dark] .qb-bubble::after {
            border-top-color: #1D1D21;
        }

        #quizBuddy.happy .qb-arm-l {
            animation: qbArmsUpL 1.25s ease;
        }

        #quizBuddy.happy .qb-arm-r {
            animation: qbArmsUpR 1.25s ease;
        }

        @keyframes qbArmsUpL {

            0%,
            100% {
                rotate: 0deg;
            }

            22%,
            78% {
                rotate: 42deg;
            }
        }

        @keyframes qbArmsUpR {

            0%,
            100% {
                rotate: 0deg;
            }

            22%,
            78% {
                rotate: -42deg;
            }
        }

        /* living eyes: periodic blinks + glancing around */
        .qb-eyes-normal {
            transform-origin: 256px 140px;
            animation: qbEyesLife 8.5s ease-in-out infinite;
        }

        @keyframes qbEyesLife {

            0%,
            28% {
                transform: translateX(0) scaleY(1);
            }

            30% {
                transform: translateX(0) scaleY(.08);
            }

            32%,
            46% {
                transform: translateX(0) scaleY(1);
            }

            50%,
            60% {
                transform: translateX(20px) scaleY(1);
            }

            64%,
            74% {
                transform: translateX(-20px) scaleY(1);
            }

            78%,
            88% {
                transform: translateX(0) scaleY(1);
            }

            90% {
                transform: translateX(0) scaleY(.08);
            }

            92%,
            100% {
                transform: translateX(0) scaleY(1);
            }
        }

        /* eye states */
        .qb-eyes-happy,
        .qb-eyes-sad {
            opacity: 0;
        }

        #quizBuddy.happy .qb-eyes-normal,
        #quizBuddy.sad .qb-eyes-normal {
            opacity: 0;
        }

        #quizBuddy.happy .qb-eyes-happy {
            opacity: 1;
        }

        #quizBuddy.sad .qb-eyes-sad {
            opacity: 1;
        }

        /* reactions */
        #quizBuddy.happy .qb-flip {
            animation: qbHappy 1.25s cubic-bezier(.34, 1.4, .5, 1);
        }

        @keyframes qbHappy {
            0% {
                translate: 0 0;
                rotate: 0deg;
            }

            28% {
                translate: 0 -30px;
                rotate: -14deg;
            }

            55% {
                translate: 0 2px;
                rotate: 10deg;
            }

            75% {
                translate: 0 -12px;
                rotate: -5deg;
            }

            100% {
                translate: 0 0;
                rotate: 0deg;
            }
        }

        #quizBuddy.sad .qb-flip {
            animation: qbSad 1.25s ease;
        }

        @keyframes qbSad {

            0%,
            100% {
                translate: 0 0;
                rotate: 0deg;
            }

            20% {
                translate: -7px 3px;
                rotate: -8deg;
            }

            45% {
                translate: 7px 5px;
                rotate: 8deg;
            }

            70% {
                translate: -4px 6px;
                rotate: -4deg;
            }
        }

        @media(max-width:600px) {
            #quizBuddy {
                width: 54px;
                height: 64px;
            }
        }

        /* Respect users who turn off animation at the OS level —
           instantly completes every entrance/celebration animation */
        @media (prefers-reduced-motion: reduce) {

            *,
            *::before,
            *::after {
                animation-duration: .01ms !important;
                animation-iteration-count: 1 !important;
                transition-duration: .01ms !important;
            }

            html {
                scroll-behavior: auto;
            }

            /* the flying mascot is pure motion — hide it entirely */
            #quizBuddy {
                display: none;
            }

            /* tilt is pure delight — neutralise it */
            .tilt { transition: none !important; transform: none !important; }
        }

        /* 3D tilt on clickable cards (JS sets the transform; this smooths it) */
        .tilt { transition: transform .18s cubic-bezier(.2, .8, .2, 1); transform-style: preserve-3d; }

        /* ════════ Splash — paints first, hides the load flash ════════ */
        #splash {
            position: fixed; inset: 0; z-index: 100000;
            display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px;
            background: linear-gradient(135deg, #6d5cff 0%, #5b50e8 50%, #4338ca 100%);
            transition: opacity .45s ease, visibility .45s ease;
        }
        #splash.hide { opacity: 0; visibility: hidden; pointer-events: none; }
        .splash-logo {
            width: 88px; height: 88px; border-radius: 24px; display: block;
            box-shadow: 0 16px 44px rgba(0, 0, 0, .32); animation: splashBob 1.6s ease-in-out infinite;
        }
        .splash-word { font-family: var(--font-ui); font-weight: 800; font-size: 1.5rem; color: #fff; }
        .splash-ring {
            width: 32px; height: 32px; border-radius: 50%;
            border: 3px solid rgba(255, 255, 255, .28); border-top-color: #fff;
            animation: splashSpin .8s linear infinite;
        }
        @keyframes splashSpin { to { transform: rotate(360deg); } }
        @keyframes splashBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
        @media (prefers-reduced-motion: reduce) {
            #splash { transition: opacity .2s ease; }
            .splash-logo, .splash-ring { animation: none; }
        }

        /* ── Home view entrance: gentle top-to-bottom stagger. Plays once on
           load (and again if a .pre-tool deep-link later restores the home
           view — a nice re-entrance, not a bug). Explicit reduce override
           because the global clamp shortens durations but not delays. ── */
        /* `backwards`, not `both`. A filling animation never stops applying its
           effect, and an effect that mentions `transform` computes to a matrix
           even when the final keyframe says `none` — so `both` left all four of
           these permanently transformed, and a transformed element is the
           containing block for its `position: fixed` descendants.

           Three of them hold fixed children, so `bottom: 20px` on those quietly
           stopped meaning "from the viewport". On phones that put "Build my
           quiz" 22px BELOW the fold, painting it over the preset buttons and
           the question count on the way past; the docking only applies under
           600px, which is why desktop never showed it.

           `backwards` still holds the start frame through the stagger delay,
           then lets go entirely, so these settle to their own untransformed
           styles. That is also why .input-card no longer needs opacity: 0. */
        #todayStrip { animation: fadeUp .5s .06s cubic-bezier(.22, .61, .21, 1) backwards; }
        #inputSection { animation: fadeUp .5s .12s cubic-bezier(.22, .61, .21, 1) backwards; }
        #usageMeter { animation: fadeUp .5s .18s cubic-bezier(.22, .61, .21, 1) backwards; }
        #achievementsPanel { animation: fadeUp .5s .24s cubic-bezier(.22, .61, .21, 1) backwards; }

        @media (prefers-reduced-motion: reduce) {
            /* The global clamp shortens durations but not delays, so without
               this the stagger's delay would still hold the start frame.
               Reveal only these entrances; display/hidden and disabled-button
               rules still control state. */
            #todayStrip, #inputSection, #usageMeter, #achievementsPanel, #generateBtn {
                animation: none;
                opacity: 1;
            }
        }

        /* ═══════════════════════════════════════════════════
           STUDY HOME — a clear intro followed by a compact plan.
           Solid surfaces keep the notebook doodles decorative instead of
           letting them compete with headings and progress information.
        ═══════════════════════════════════════════════════ */
        #todayStrip {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 10px;
            margin: 0 0 22px;
        }

        #todayStrip > * {
            min-width: 0;
        }

        #todayStrip .streak-nudge {
            grid-column: 1 / -1;
        }

        #todayStrip .today-daily,
        #todayStrip .daily-challenge-banner,
        #todayStrip .review-due-banner {
            min-height: 82px;
            padding: 13px 14px;
            border-radius: 18px;
        }

        #todayStrip .today-daily,
        #todayStrip .review-due-banner {
            background-color: rgba(255, 255, 255, .95);
            box-shadow: 0 8px 22px rgba(43, 35, 115, .06);
        }

        #todayStrip .today-daily {
            border-color: rgba(91, 80, 232, .16);
        }

        #todayStrip .daily-challenge-banner {
            box-shadow: 0 9px 22px rgba(91, 80, 232, .22);
        }

        #todayStrip .review-due-banner {
            border-color: rgba(5, 150, 105, .2);
        }

        #todayStrip .exam-countdown-banner {
            border-color: var(--amber-border);
        }

        #todayStrip .review-due-icon {
            width: 38px;
            height: 38px;
        }

        #todayStrip .review-due-title,
        #todayStrip .td-title {
            font-size: .88rem;
            line-height: 1.25;
        }

        #todayStrip .review-due-sub,
        #todayStrip .td-sub,
        #todayStrip .dc-sub {
            display: -webkit-box;
            overflow: hidden;
            -webkit-box-orient: vertical;
            -webkit-line-clamp: 2;
            line-clamp: 2;
            line-height: 1.35;
        }

        #todayStrip .dc-cta {
            padding: 7px 11px;
        }

        /* ── Up next ──────────────────────────────────────────────────────
           Deliberately carries no surface of its own: the flat-card rule in
           #generatorRefresh lists #upNext alongside .today-daily, so the
           background, hairline border, radius and shadow are literally the
           Daily goal card's, not a second card language pretending to match.
           What lives here is the card's own layout. Violet plus the streak
           flame's amber are the only colours on it. */
        #todayStrip #upNext {
            display: flex;
            flex-direction: column;
            gap: 9px;
            padding: 14px 16px;
        }

        /* The display above out-ranks [hidden]'s UA rule, so restate it. */
        #todayStrip #upNext[hidden] { display: none; }

        /* Up next uses the same quiet section label as the builder. */
        .up-next .generator-kicker {
            gap: 9px;
            font-size: .875rem;
            font-weight: 600;
            letter-spacing: 0;
        }

        .up-next .generator-kicker::before {
            content: none;
            width: 20px;
            height: 2px;
            border-radius: 2px;
            background: var(--violet);
        }

        .up-next .un-primary,
        .up-next .un-row {
            display: flex;
            width: 100%;
            margin: 0;
            padding: 0;
            border: 0;
            background: none;
            color: inherit;
            font-family: inherit;
            text-align: left;
            cursor: var(--cur-point, pointer);
        }

        /* The primary stacks: title, reason, the streak line, then the CTA on
           its own row. As icon | text | button it split a ~350px column three
           ways and every part lost — the reason broke mid-phrase, the streak
           line wrapped, the pill was pinned against the right edge, and the
           icon sat alone in the gap doing no work. Vertical gives each line
           the full width and costs one row of height. */
        .up-next .un-primary {
            flex-direction: column;
            gap: 2px;
        }

        .up-next .un-body {
            flex: 1;
            min-width: 0;
        }

        .up-next .un-title {
            display: block;
            font-family: var(--font-ui);
            font-size: .98rem;
            font-weight: 600;
            line-height: 1.25;
            color: var(--text-primary);
        }

        .up-next .un-reason,
        .up-next .un-row-reason {
            display: -webkit-box;
            overflow: hidden;
            -webkit-box-orient: vertical;
            -webkit-line-clamp: 2;
            line-clamp: 2;
            font-size: .8rem;
            line-height: 1.35;
            color: var(--text-muted);
        }

        .up-next .un-streak {
            display: flex;
            align-items: center;
            gap: 5px;
            margin-top: 3px;
            font-size: .78rem;
            font-weight: 700;
            color: var(--amber);
        }

        .up-next .un-streak svg { flex-shrink: 0; }

        /* Its own row, sized to its text rather than stretched across the
           column. Still never wraps: it is the shortest thing on the card and
           the first thing to break if it is allowed to. */
        .up-next .un-cta {
            align-self: flex-start;
            flex-shrink: 0;
            /* 10px clear of the line above, once the column's 2px gap lands. */
            margin-top: 8px;
            padding: 7px 12px;
            border-radius: 8px;
            background: none;
            color: var(--text-primary);
            font-size: .8rem;
            font-weight: 600;
            white-space: nowrap;
            border: 1px solid #8791a3;
        }

        .up-next .un-alts {
            display: flex;
            flex-direction: column;
            margin: -2px -8px -6px;
        }

        .up-next .un-row {
            align-items: center;
            gap: 10px;
            padding: 9px 8px;
            border-top: 1px solid rgba(91, 80, 232, .1);
            border-radius: 8px;
        }

        .up-next .un-row-title {
            display: block;
            font-size: .86rem;
            font-weight: 700;
            line-height: 1.3;
            color: var(--text-primary);
        }

        .up-next .un-row-arrow {
            flex-shrink: 0;
            color: var(--violet);
        }

        .up-next .un-row:hover { background: rgba(91, 80, 232, .05); }

        .up-next .un-primary:focus-visible,
        .up-next .un-row:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
            border-radius: 10px;
        }

        [data-dark] .up-next .generator-kicker { color: var(--text-secondary); }
        [data-dark] .up-next .generator-kicker::before { background: #9d94ff; }
        [data-dark] .up-next .un-row-arrow { color: #9d94ff; }
        [data-dark] .up-next .un-streak { color: #f59e0b; }
        [data-dark] .up-next .un-row { border-top-color: rgba(255, 255, 255, 0.08); }
        [data-dark] .up-next .un-row:hover { background: rgba(255, 255, 255, 0.055); }

        [data-dark] .up-next .un-primary:focus-visible,
        [data-dark] .up-next .un-row:focus-visible { outline-color: #9d94ff; }

        /* ── Absorbed, not deleted ──
           With a recommendation on screen the card already speaks for the
           streak nudge, the daily challenge and both review prompts, so
           leaving them underneath states the same decision four more times.
           CSS only: every function that fills them still runs, and the moment
           the card has nothing to say they are back. !important because their
           JS writes `display` inline — the same reason the phone rule needs
           it. The Daily goal card and the exam countdown are NOT absorbed:
           one is a target, the other a dated deadline, neither a suggestion. */
        #todayStrip.has-next #streakNudge,
        #todayStrip.has-next #dailyChallengeBanner,
        #todayStrip.has-next #dailyReviewBanner,
        #todayStrip.has-next #fcDueBanner { display: none !important; }

        [data-dark] #todayStrip .today-daily,
        [data-dark] #todayStrip .review-due-banner {
            background-color: rgba(24, 24, 27, 0.96);
        }

        @media (max-width: 620px) {
            #todayStrip {
                grid-template-columns: 1fr;
            }

            #todayStrip .streak-nudge {
                grid-column: auto;
            }

            #todayStrip .today-daily,
            #todayStrip .daily-challenge-banner,
            #todayStrip .review-due-banner {
                min-height: 74px;
            }
        }

        /* ═══════════════════════════════════════════════════
           QUIZ BUILDER — one form, one primary action.

           The whole builder lives here. It used to be this block plus three
           appended override layers (#builderRefresh, #builderLayout, and the
           builder halves of #generatorRefresh and #workspaceLayout), which is
           how the card ended up as a gradient console under a flat white card
           under a de-carded form. Anything that paints the builder is in this
           one place now; nothing later in the sheet overrides it.

           Order, top to bottom: eyebrow → heading → quick start → source tabs
           → fields → settings → primary → caption → links.

           House rules for this card: violet is var(--violet) and nothing
           else, surfaces are --card-bg with a hairline, no gradients, no icon
           on the primary, every colour through a token so dark comes for
           free, and every hover behind @media (hover: hover) so a finger
           never leaves one stuck on.
        ═══════════════════════════════════════════════════ */

        /* ── Open form surface ── */
        #inputSection {
            position: relative;
            padding: 0;
            border: 0;
            border-radius: 0;
            background: transparent;
            box-shadow: none;
        }

        [data-dark] #inputSection {
            border-color: transparent;
            box-shadow: none;
        }

        /* An open dropdown must paint over the rest of the form, and the card
           has to be lifted with it — a panel's z-index is resolved inside
           whichever stacking context its card opens. */
        #inputSection:has(.csel.open) {
            z-index: 120;
        }

        #inputSection .csel.open {
            z-index: 130;
        }

        /* ── Head: eyebrow, heading, nothing else ──
           There were seven pieces of framing above the first control (a
           quick-start card, a dotted kicker, this heading, a sub sentence, an
           "Under 1 min" chip, a links row and a 1-2-3 rail). Four survive,
           and only one of them is decoration. */
        .generator-card-head {
            margin-bottom: 18px;
        }

        .generator-kicker {
            display: flex;
            align-items: center;
            gap: 9px;
            color: var(--text-secondary);
            font-size: .875rem;
            font-weight: 600;
            letter-spacing: 0;
            text-transform: none;
        }

        /* The section name carries the hierarchy without a decorative dash. */
        #inputSection .generator-kicker::before {
            content: none;
            width: 20px;
            height: 2px;
            border-radius: 2px;
            background: var(--violet);
        }

        [data-dark] #inputSection .generator-kicker {
            color: var(--text-secondary);
        }

        [data-dark] #inputSection .generator-kicker::before {
            background: #9d94ff;
        }

        .generator-card-head h1 {
            margin: 9px 0 0;
            font-family: var(--font-display);
            font-size: clamp(1.625rem, 2.6vw, 2rem);
            font-weight: 700;
            line-height: 1.2;
            letter-spacing: -.025em;
            color: var(--text-primary);
        }

        /* ── Quick start: a hairline row, not a second card ──
           It sat OUTSIDE the builder as a violet console, so the page opened
           with two competing primaries. Here it reads as what it is: a
           shortcut past the form directly below it. renderQuickStart() only
           toggles display, and 'flex' is still this row's layout. */
        .quick-start-btn {
            width: 100%;
            display: flex;
            align-items: center;
            gap: 12px;
            margin: 16px 0 4px;
            padding: 11px 6px;
            border: 0;
            border-top: 1px solid #dfe3eb;
            border-bottom: 1px solid #dfe3eb;
            border-radius: 0;
            background: none;
            color: var(--text-primary);
            text-align: left;
            font-family: var(--font-ui);
            cursor: var(--cur-point, pointer);
            transition: background .16s ease;
        }

        [data-dark] .quick-start-btn {
            border-top-color: rgba(255, 255, 255, 0.08);
            border-bottom-color: rgba(255, 255, 255, 0.08);
        }

        .qs-bolt {
            flex: 0 0 20px;
            display: flex;
            align-items: center;
            justify-content: center;
            width: 20px;
            height: 20px;
            color: var(--violet);
        }

        [data-dark] .qs-bolt {
            color: #9d94ff;
        }

        .qs-text {
            display: flex;
            flex: 1;
            min-width: 0;
            flex-direction: column;
        }

        .qs-title {
            font-size: .92rem;
            font-weight: 600;
            letter-spacing: -.01em;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .qs-sub {
            color: var(--text-muted);
            font-size: .8rem;
            font-weight: 600;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .qs-arrow {
            flex-shrink: 0;
            color: var(--violet);
            font-size: 1.1rem;
            font-weight: 600;
        }

        [data-dark] .qs-arrow {
            color: #9d94ff;
        }

        /* Title and sub are one line once there is room for one. */
        @media (min-width: 600px) {
            .qs-text {
                flex-direction: row;
                align-items: baseline;
                gap: 10px;
            }

            .qs-title {
                flex: 0 0 auto;
                font-weight: 600;
            }
        }

        @media (hover: hover) {
            .quick-start-btn:hover {
                background: rgba(91, 80, 232, .05);
            }
        }

        .quick-start-btn:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
        }

        /* ── Recently studied: chips above the subject select ── */
        .recent-subs-row {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
            gap: 6px;
            margin-bottom: 14px;
        }

        .rsc-label {
            flex-shrink: 0;
            margin-right: 2px;
            color: var(--text-muted);
            font-size: .7rem;
            font-weight: 600;
            letter-spacing: 0;
            text-transform: none;
        }

        .rsc-chip {
            display: inline-flex;
            align-items: center;
            min-height: 32px;
            padding: 5px 12px;
            border: 1px solid #8791a3;
            border-radius: 12px;
            background: none;
            color: var(--text-secondary);
            font-family: var(--font-ui);
            font-size: .78rem;
            font-weight: 600;
            line-height: 1;
            white-space: nowrap;
            cursor: var(--cur-point, pointer);
            transition: border-color .15s, color .15s;
        }

        [data-dark] .rsc-chip {
            border-color: #85858F;
        }

        @media (hover: hover) {
            .rsc-chip:hover {
                border-color: var(--violet);
                color: var(--violet);
            }

            [data-dark] .rsc-chip:hover {
                border-color: #9d94ff;
                color: #c7bfff;
            }
        }

        .rsc-chip:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
        }

        /* ── Source switcher: neutral track, violet selected tab ──
           switchTab() writes the slider's `left` as 5px / 33.33% / 66.67%, so
           the track's padding is 5px and stays 5px. */
        #inputSection .tabs {
            padding: 5px;
            margin-bottom: 22px;
            border: 1px solid transparent;
            border-radius: 12px;
            background: #f7f8fc;
            box-shadow: none;
        }

        [data-dark] #inputSection .tabs {
            border-color: transparent;
            background: #18181B;
        }

        #inputSection .tab-slider {
            top: 5px;
            left: 5px;
            width: calc(33.33% - 3px);
            height: calc(100% - 10px);
            border: 1px solid var(--violet);
            border-radius: 12px;
            background: #eeecff;
            box-shadow: 0 2px 5px rgba(43, 35, 113, .06);
        }

        [data-dark] #inputSection .tab-slider {
            border-color: #9d94ff;
            background: rgba(157, 148, 255, .12);
            box-shadow: none;
        }

        #inputSection .tab-btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            min-height: 44px;
            padding: 9px 10px;
            color: var(--text-muted);
            font-size: .85rem;
            font-weight: 600;
        }

        /* Restate the selected ink to beat the shared .tab-btn.active rule. */
        #inputSection .tab-btn.active {
            color: var(--violet) !important;
        }

        [data-dark] #inputSection .tab-btn.active { color: #b9b2ff !important; }

        /* ── Fields ── */
        #inputSection .field-label {
            margin-bottom: 6px;
            color: var(--text-secondary);
            font-size: .875rem;
            font-weight: 600;
            letter-spacing: 0;
            text-transform: none;
        }

        [data-dark] #inputSection .field-label {
            color: #B4B4BD;
        }

        .subject-control,
        .topic-control,
        .unit-control {
            position: relative;
        }

        .topic-control,
        .unit-control {
            margin-top: 18px;
        }

        #inputSection .input-text,
        #inputSection .textarea-notes {
            border: 1px solid #8791a3;
            border-radius: 12px;
            background: var(--card-bg, #fff);
            box-shadow: none;
            font-weight: 600;
        }

        #inputSection .input-text {
            min-height: 48px;
            padding: 12px 14px;
        }

        #inputSection .input-text:focus-visible,
        #inputSection .textarea-notes:focus-visible {
            border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, .14);
            outline: none;
        }

        #inputSection .csel {
            --csel-accent: #5b50e8;
        }

        #inputSection .csel-trigger {
            min-height: 48px;
            padding: 8px 12px;
            gap: 10px;
            border: 1px solid #8791a3;
            border-radius: 12px;
            background: var(--card-bg, #fff);
            box-shadow: none;
            font-weight: 600;
            transition: border-color .18s, box-shadow .18s;
        }

        #inputSection .csel.open .csel-trigger,
        #inputSection .csel-trigger:focus-visible {
            border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, .14);
        }

        @media (hover: hover) {
            #inputSection .input-text:hover,
            #inputSection .textarea-notes:hover,
            #inputSection .csel-trigger:hover {
                border-color: rgba(91, 80, 232, .34);
            }
            [data-dark] #inputSection .input-text:hover,
            [data-dark] #inputSection .textarea-notes:hover,
            [data-dark] #inputSection .csel-trigger:hover {
                border-color: rgba(157, 148, 255, .42);
            }
        }

        /* The subject is the one choice that has to be made — it leads. */
        #inputSection .subject-control .csel-trigger {
            min-height: 48px;
            font-size: 1rem;
        }

        .csel-leading {
            display: grid;
            place-items: center;
            width: 24px;
            height: 24px;
            flex: 0 0 24px;
            border: 0;
            border-radius: 6px;
            background: none;
            color: var(--text-secondary);
        }

        .csel-leading svg {
            width: 17px;
            height: 17px;
            fill: none;
            stroke: currentColor;
            stroke-width: 1.9;
            stroke-linecap: round;
            stroke-linejoin: round;
        }

        .csel-value {
            flex: 1;
            min-width: 0;
        }

        #inputSection .csel-chev {
            width: 16px;
            height: 16px;
            padding: 3px;
            border-radius: 50%;
            background: none;
            color: var(--text-muted);
            box-sizing: content-box;
        }

        #inputSection .csel-panel {
            top: calc(100% + 8px);
            max-width: min(360px, 90vw);
            max-height: 330px;
            padding: 7px;
            border: 1px solid #8791a3;
            border-radius: 12px;
            background: #fff;
            box-shadow: 0 8px 24px rgba(14, 18, 32, .14);
            backdrop-filter: none;
            -webkit-backdrop-filter: none;
        }

        /* The flip-up variant has to win in here too, or the panel is crushed flat.
         *
         * .csel.up .csel-panel sets `top: auto; bottom: ...` so an upward panel
         * is anchored by its BOTTOM edge and sizes to its content. But that
         * rule scores (0,3,0), and the two #inputSection rules below score
         * (1,1,0) and (1,2,0) — an id beats any number of classes, so their
         * `top` won and the panel ended up with BOTH top and bottom resolved.
         * An absolutely positioned box pinned on both edges takes its height
         * from the gap between them: measured on production, top:53px with
         * bottom:50px gave a 16px-tall panel holding a 177px list. Every
         * builder dropdown that opened upward — which on a phone is most of
         * them, since the controls sit low on the card — showed as a sliver
         * with its options clipped away.
         *
         * Scoped to match each offender's specificity rather than reaching for
         * !important, so the offsets stay readable and overridable.
         */
        #inputSection .csel.up .csel-panel,
        #inputSection .csel.up[data-select-id="subjectSelect"] .csel-panel {
            top: auto;
            bottom: calc(100% + 8px);
        }

        #inputSection .csel[data-select-id="subjectSelect"] .csel-panel {
            width: 100%;
            max-width: 100%;
            max-height: none;
            overflow: visible;
        }

        .csel-search-wrap {
            position: absolute;
            z-index: 3;
            top: -62px;
            right: -1px;
            left: -1px;
            padding: 0;
        }

        .csel-search {
            width: 100%;
            min-height: 56px;
            padding: 10px 12px 10px 38px;
            border: 1px solid #8791a3;
            border-radius: 12px;
            background:
                rgba(255, 255, 255, .99)
                url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235b50e8' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-4-4'/%3E%3C/svg%3E")
                no-repeat 12px center;
            color: var(--text-primary);
            font: 600 .95rem var(--font-ui);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, .14);
        }

        .csel-search::placeholder {
            color: var(--text-muted);
        }

        .csel-search:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 1px;
            border-color: var(--violet);
        }

        .csel-list {
            display: grid;
            gap: 3px;
        }

        #inputSection .csel[data-select-id="subjectSelect"] .csel-list {
            max-height: min(410px, 55vh);
            overflow-y: auto;
            overscroll-behavior: contain;
        }

        #inputSection .csel[data-select-id="subjectSelect"].up .csel-search-wrap {
            top: auto;
            bottom: -62px;
        }

        .csel-group-block {
            display: grid;
            gap: 2px;
        }

        .csel-opt[hidden],
        .csel-group-block[hidden] {
            display: none !important;
        }

        #inputSection .csel-group {
            padding: 11px 10px 5px;
            color: var(--text-muted);
            font-size: .64rem;
            font-weight: 800;
            letter-spacing: .1em;
        }

        #inputSection .csel-opt {
            width: 100%;
            min-height: 42px;
            padding: 9px 10px;
            border: 0;
            border-radius: 10px;
            background: transparent;
            font-family: var(--font-ui);
            text-align: left;
        }

        #inputSection .csel-opt:hover,
        #inputSection .csel-opt:focus-visible,
        #inputSection .csel-opt.active {
            background: rgba(91, 80, 232, .075);
            color: #2f2a68;
        }

        #inputSection .csel-opt:focus-visible,
        #inputSection .csel-opt.active {
            outline: 2px solid var(--violet);
            outline-offset: -2px;
        }

        #inputSection .csel-opt.selected {
            background: rgba(91, 80, 232, .1);
            color: var(--violet);
        }

        .csel-empty {
            display: none;
            padding: 22px 12px;
            color: var(--text-muted);
            font-size: .82rem;
            text-align: center;
        }

        /* ── Syllabus dot points: a hairline list, no per-row cards ── */
        #inputSection .syl-toggle {
            min-height: 40px;
            border: 1px solid #8791a3;
            background: none;
            font-weight: 600;
            border-radius: 12px;
        }

        [data-dark] #inputSection .syl-toggle {
            border-color: rgba(255, 255, 255, 0.14);
        }

        #inputSection .syl-body {
            border: 1px solid rgba(91, 80, 232, .16);
            border-radius: 12px;
            background: none;
        }

        [data-dark] #inputSection .syl-body {
            border-color: rgba(255, 255, 255, 0.08);
            background: none;
        }

        #inputSection .syl-row {
            padding: 9px 2px;
            border-bottom: 1px solid rgba(91, 80, 232, .1);
            border-radius: 0;
        }

        [data-dark] #inputSection .syl-row {
            border-bottom-color: rgba(255, 255, 255, 0.08);
        }

        #inputSection .syl-list .syl-row:last-child {
            border-bottom: 0;
        }

        /* ── The upload panel keeps its accepted-type chips ── */
        #inputSection .upload-area {
            border: 1.5px dashed #8791a3;
            border-radius: 12px;
            background: none;
        }

        [data-dark] #inputSection .upload-area {
            border-color: #85858F;
        }

        #inputSection .upload-kinds {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 8px;
            margin-top: 14px;
            /* decorative — clicks and drags fall through to the file input */
            pointer-events: none;
        }

        #inputSection .uk-chip {
            display: inline-flex;
            align-items: center;
            gap: 7px;
            padding: 5px 10px 5px 6px;
            border: 1px solid rgba(91, 80, 232, .14);
            border-radius: 6px;
            color: var(--text-secondary);
            font-size: .78rem;
            font-weight: 600;
        }

        #inputSection .uk-chip svg {
            display: block;
            border-radius: 6px;
        }

        [data-dark] #inputSection .uk-chip {
            border-color: rgba(255, 255, 255, 0.14);
        }

        /* ── Settings ──
           The five selects were boxed cards, then unlabelled pills whose only
           cue was an icon. They are labelled fields in a responsive grid now:
           the caption names the setting, so the icon tile is redundant here
           and goes. Two of the five are the course and sit behind a chip; the
           other three are one preset and only unfold on request. */
        .builder-group-label {
            display: flex;
            align-items: center;
            gap: 12px;
            margin: 24px 0 12px;
            color: var(--text-secondary);
            font-size: .875rem;
            font-weight: 600;
            letter-spacing: 0;
            text-transform: none;
        }

        .builder-group-label::after {
            content: '';
            flex: 1;
            height: 1px;
            background: #dfe3eb;
        }

        [data-dark] .builder-group-label::after {
            background: rgba(255, 255, 255, 0.08);
        }

        #inputSection .row-4 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 14px;
            margin-top: 0;
        }

        #inputSection .setting-field {
            position: relative;
            z-index: 0;
            min-width: 0;
        }

        /* Keeps an open dropdown above its siblings. */
        #inputSection .setting-field:focus-within,
        #inputSection .setting-field.csel-open {
            z-index: 80;
        }

        #inputSection .setting-field .csel-leading {
            display: none;
        }

        /* ── Course, set once ──
           A caption plus one bordered toggle, in place of two dropdowns a
           student answers once in their life. The toggle is sized and framed
           like a real field control (not a text link) so it reads as
           something to notice, not something to miss. */
        .course-row {
            margin-bottom: 16px;
        }

        /* An author `display` beats the UA sheet's [hidden], so every element
           toggled by that attribute here needs its own rule or `hidden` is a
           no-op on it. */
        .course-row[hidden] {
            display: none;
        }

        .course-toggle {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            width: 100%;
            min-height: 48px;
            padding: 0 16px;
            border: 1px solid #8791a3;
            border-radius: 12px;
            background: var(--card-bg, #fff);
            font-family: var(--font-ui);
            cursor: var(--cur-point, pointer);
        }

        [data-dark] .course-toggle {
            border-color: #85858F;
            background: #18181B;
        }

        @media (hover: hover) {
            .course-toggle:hover {
                border-color: var(--violet);
            }
        }

        .course-toggle:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
        }

        [data-dark] .course-toggle:focus-visible {
            outline-color: #9d94ff;
        }

        .course-chip {
            color: var(--text-primary);
            font-size: .95rem;
            font-weight: 600;
        }

        .course-toggle-cta {
            display: inline-flex;
            align-items: center;
            gap: 4px;
            flex-shrink: 0;
            color: var(--text-secondary);
            font-size: .86rem;
            font-weight: 600;
        }

        [data-dark] .course-toggle-cta {
            color: var(--text-secondary);
        }

        .course-edit {
            padding: 0;
            border: 0;
            background: none;
            color: var(--violet);
            font-family: var(--font-ui);
            font-size: .82rem;
            font-weight: 600;
            cursor: var(--cur-point, pointer);
        }

        [data-dark] .course-edit {
            color: #9d94ff;
        }

        @media (hover: hover) {
            .course-edit:hover {
                text-decoration: underline;
            }
        }

        #courseFields {
            margin-bottom: 20px;
        }

        /* First thing in the panel: no rule to sit under and nothing above it. */
        #courseFields .builder-group-label {
            margin-top: 0;
        }

        /* Flashcards' own mirror of the two rules above — same reasons, same
           position (first thing in #fcSubjectPanel). */
        #fcCourseFields {
            margin-bottom: 20px;
        }

        #fcCourseFields .builder-group-label {
            margin-top: 0;
        }

        .course-note {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
            gap: 14px;
            margin-top: 12px;
            color: var(--text-muted);
            font-size: .82rem;
            font-weight: 600;
        }

        /* ── One preset, four choices ──
           Each choice keeps a visible boundary; the checked choice supplies
           its own violet state without a moving slider. */
        .preset-switch {
            display: grid;
            grid-template-columns: repeat(4, minmax(0, 1fr));
            gap: 8px;
            padding: 0;
            border: 0;
            border-radius: 12px;
            background: none;
        }

        [data-dark] .preset-switch {
            border-color: transparent;
            background: none;
        }

        .preset-opt {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            min-height: 44px;
            padding: 9px 6px;
            border: 1px solid #8791a3;
            border-radius: 12px;
            background: none;
            color: var(--text-muted);
            font-family: var(--font-ui);
            font-size: .85rem;
            font-weight: 600;
            white-space: nowrap;
            cursor: var(--cur-point, pointer);
            transition: background .16s ease, color .16s ease;
        }

        #inputSection .preset-opt,
        #flashcardsPage .preset-opt,
        #testPage .preset-opt { min-height: 48px; }

        .preset-opt[aria-checked="true"] {
            background: #f0efff;
            box-shadow: none;
            color: var(--violet);
            border-color: var(--violet);
        }

        [data-dark] .preset-opt[aria-checked="true"] {
            background: rgba(157, 148, 255, .12);
            box-shadow: none;
            color: #b9b2ff;
            border-color: #9d94ff;
        }

        .preset-opt:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
        }

        [data-dark] .preset-opt:focus-visible {
            outline-color: #9d94ff;
        }

        @media (hover: hover) {
            .preset-opt:hover:not([aria-checked="true"]) {
                color: var(--text-primary);
            }
        }

        /* One of the two label spans is always display:none, which also keeps
           it out of the accessibility tree — so the radio is named by whichever
           words are actually on screen. */
        .preset-opt .preset-short {
            display: none;
        }

        #customFields {
            margin-top: 16px;
        }

        /* ── Primary: solid violet, one line, no icon, no gradient, no lip ──
           No max-width of its own now that it lives inside #inputSection as
           the card's last child: full width means the card's content width,
           the same edges #quizPreset already sits at. */
        #generateBtn {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
            width: 100%;
            max-width: none;
            min-height: 48px;
            margin-top: 22px;
            padding: 12px 24px;
            border: 0;
            border-radius: 12px;
            background: var(--violet);
            background-image: none;
            color: #fff;
            font-family: var(--font-ui);
            font-size: .95rem;
            font-weight: 700;
            letter-spacing: 0;
            box-shadow: 0 3px 8px rgba(67, 56, 202, .16);
            transition: background .16s ease, box-shadow .16s ease;
        }

        /* The shared .btn-generate carries a sweep highlight; this card does not. */
        #generateBtn::before {
            display: none;
        }

        #generateBtn:hover:not(:disabled),
        #generateBtn:active:not(:disabled) {
            transform: none;
            filter: none;
            background: var(--violet-shade);
            box-shadow: none;
        }

        @media (hover: none) {
            #generateBtn:hover:not(:disabled) {
                background: var(--violet);
            }
        }

        .generate-button-arrow {
            font-size: 1.1rem;
            font-weight: 800;
            line-height: 1;
        }

        /* ── What the tap buys, then the two ways out of the builder ── */
        .builder-footer {
            margin-top: 10px;
        }

        .builder-caption {
            margin: 0;
            color: var(--text-muted);
            font-size: .82rem;
            font-weight: 600;
        }

        /* The way out of a blocked caption — same treatment as
           .usage-upgrade (the popover's own upgrade link), because it is the
           same offer shown on a second surface. Only ever shown alongside a
           blocked caption, so no min-height tap-target rule is needed here;
           it sits on its own line under running text, not in a button row. */
        .builder-caption-upgrade {
            display: block;
            margin-top: 4px;
            color: var(--violet);
            font-size: .82rem;
            font-weight: 800;
            text-decoration: none;
        }
        .builder-caption-upgrade:hover { text-decoration: underline; }
        [data-dark] .builder-caption-upgrade { color: #b9b2ff; }
        .builder-caption-upgrade[hidden] { display: none; }

        .builder-links {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
            gap: 18px;
            margin: 14px 0 0;
        }

        .builder-links button,
        .builder-links a {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            background: none;
            border: 0;
            padding: 0;
            font-family: var(--font-ui);
            font-size: .86rem;
            font-weight: 600;
            color: var(--text-secondary);
            text-decoration: none;
            cursor: var(--cur-point, pointer);
        }

        [data-dark] .builder-links button,
        [data-dark] .builder-links a {
            color: var(--text-secondary);
        }

        @media (hover: hover) {
            .builder-links button:hover,
            .builder-links a:hover {
                text-decoration: underline;
            }
        }

        /* ── Dark ── */
        [data-dark] #inputSection .csel-trigger {
            border-color: #85858F;
            background: #232327;
        }

        [data-dark] .csel-leading {
            border-color: transparent;
            background: none;
        }

        /* .textarea-notes must be listed alongside .input-text in every rule
           here. The light rule above targets both via `#inputSection`, so a
           dark override naming only .input-text loses on specificity and the
           notes box renders white on the dark theme. */
        [data-dark] #inputSection .input-text,
        [data-dark] #inputSection .textarea-notes {
            border-color: #85858F;
            background: #232327;
            color: #ece9ff;
        }

        [data-dark] #inputSection .input-text::placeholder,
        [data-dark] #inputSection .textarea-notes::placeholder {
            color: #B4B4BD;
        }

        [data-dark] #inputSection .input-text:focus-visible,
        [data-dark] #inputSection .textarea-notes:focus-visible {
            border-color: #9d94ff;
            box-shadow: 0 0 0 3px rgba(157, 148, 255, .22);
        }

        [data-dark] #inputSection .csel.open .csel-trigger,
        [data-dark] #inputSection .csel-trigger:focus-visible {
            border-color: #9d94ff;
            box-shadow: 0 0 0 3px rgba(157, 148, 255, .22);
        }

        [data-dark] #inputSection .csel-panel {
            border-color: #85858F;
            background: #1D1D21;
        }

        [data-dark] .csel-search {
            border-color: #85858F;
            background-color: #1D1D21;
            color: #ece9ff;
        }

        [data-dark] .csel-search:focus-visible {
            outline-color: #9d94ff;
        }

        [data-dark] #inputSection .csel-opt:hover,
        [data-dark] #inputSection .csel-opt:focus-visible,
        [data-dark] #inputSection .csel-opt.active {
            background: rgba(157, 148, 255, 0.12);
            color: #ece9ff;
        }

        [data-dark] #inputSection .csel-opt:focus-visible,
        [data-dark] #inputSection .csel-opt.active {
            outline-color: #9d94ff;
        }

        [data-dark] #inputSection .csel-opt.selected {
            background: rgba(157, 148, 255, 0.16);
            color: #c7bfff;
        }

        /* ── Wide: the form sits in an ~800px column beside the day's rail,
              so the measures are capped rather than let run. ── */
        @media (min-width: 900px) {
            .generator-card-head h1 {
                font-size: 2rem;
            }
        }

        /* "WACE (Western Australia)" is 181px of text and the one value a
           student cannot reconstruct from its first word, so the course pair
           runs on six tracks with the exam system taking four of them. The
           three custom selects ("10 questions", "Standard", "Mixed") all read
           fine truncated, so they get even thirds. Both rules carry an id, or
           the bare `.row-4` above them wins on nothing but source order. */
        @media (min-width: 701px) {
            #courseFields .row-4 {
                grid-template-columns: repeat(6, minmax(0, 1fr));
            }

            #courseFields .setting-field {
                grid-column: span 2;
            }

            #courseFields .setting-field:nth-child(2) {
                grid-column: span 4;
            }

            #customFields .row-4 {
                grid-template-columns: repeat(3, minmax(0, 1fr));
            }
        }

        @media (min-width: 1100px) {
            body:not(.quiz-active) #inputSection .tabs { max-width: none; }
            body:not(.quiz-active) #inputSection .subject-control,
            body:not(.quiz-active) #quickPanel .topic-control,
            body:not(.quiz-active) #quickPanel .unit-control { max-width: none; }
            body:not(.quiz-active) #notesPanel .textarea-notes { min-height: 220px; }
        }

        /* ── Phone ──
           `#inputSection .row-4` (0,1,1) outranks the bare `.row-4`, so the
           phone rules have to carry the id or they never apply — the 2-column
           layout was written four times without it and was inert every time.
           A grid item also defaults to min-width:auto and refuses to shrink
           below its label, which is what blew the column out in the first
           place. Both are restated here so the row cannot go inert again. */
        @media (max-width: 700px) {
            #inputSection .row-4 {
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 10px;
                align-items: stretch;
            }

            #inputSection .row-4 .setting-field { min-width: 0; }

            #inputSection .row-4 .csel,
            #inputSection .row-4 .csel-trigger {
                min-width: 0;
                max-width: 100%;
                width: 100%;
            }

            #inputSection .tab-btn {
                padding-inline: 5px;
                font-size: .8rem;
            }
        }

        /* The docked bar spans the phone's width less its 16px insets. That
           width is set by the shared `.btn-generate` docking rule, which this
           id-scoped rule would otherwise outrank — measured at 390px it made
           the pill run edge to edge. Same breakpoint as the dock. */
        @media (max-width: 600px) {
            #generateBtn {
                max-width: none;
                width: calc(100% - 32px);
                min-height: 48px;
                border-radius: 12px;
                font-family: var(--font-ui);
                font-size: .95rem;
                font-weight: 600;
            }
        }

        /* Two 167px tracks cannot hold "WACE (Western Australia)" — 181px of
           text — and that is the one field whose value you cannot infer from a
           truncation. Single column below this width. */
        @media (max-width: 420px) {
            #inputSection .row-4 { grid-template-columns: 1fr; }
        }

        /* Four segments have to stay on one row. "Quick check" is the widest
           label at 89px including padding, and a quarter of the control only
           reaches that from a 460px viewport up (86px at 440, 76px at 400), so
           below this width the segments use one-word forms rather than
           overflowing their track — an overflow a flex centre spills BOTH ways,
           which is why scrollWidth does not report it. Swapping the spans
           rather than truncating them keeps the visible label inside the
           accessible name, and display:none keeps the unused one out of the
           accessibility tree entirely. */
        @media (max-width: 479px) {
            .preset-opt {
                padding-inline: 4px;
                font-size: .82rem;
            }

            .preset-opt .preset-long { display: none; }
            .preset-opt .preset-short { display: inline; }
        }

        /* ═══════════════════════════════════════════════════
           FLASHCARDS — the same one clear form as the quiz builder.

           Everything that paints /flashcards is here, scoped to
           #flashcardsPage, and every value is lifted from the builder block
           above so the two screens are one system rather than two dialects.
           Scoped because .tabs, .tab-btn, .btn-generate, .input-text,
           .textarea-notes, .upload-area, .select-styled and .field-label are
           shared with the cheat sheet, the concept map, write/test and the
           auth modal; .set-mode and the .fc-* families are this page's own.

           Order, top to bottom: eyebrow → heading → sub → source tabs →
           fields → settings → primary → caption → saved decks → the deck.

           House rules, same as the builder: violet is var(--violet) and
           nothing else, no gradients, no icon on a primary, every colour
           through a token so dark comes for free, every hover behind
           @media (hover: hover) so a finger never leaves one stuck on.
        ═══════════════════════════════════════════════════ */

        /* ── Head ──
           The shared tool hero paints its eyebrow as an h2::before whose rule
           is a violet→cyan gradient. This page carries one hue, so the eyebrow
           is the builder's own .generator-kicker element instead and the
           ::before stands down. */
        #flashcardsPage .tool-hero {
            margin-bottom: 20px;
        }

        #flashcardsPage .tool-hero h2::before {
            display: none;
        }

        #flashcardsPage .generator-kicker::before {
            content: none;
            width: 20px;
            height: 2px;
            border-radius: 2px;
            background: var(--violet);
        }

        [data-dark] #flashcardsPage .generator-kicker {
            color: var(--text-secondary);
        }

        [data-dark] #flashcardsPage .generator-kicker::before {
            background: #9d94ff;
        }

        #flashcardsPage .tool-hero h2 {
            margin: 9px 0 0;
            font-family: var(--font-display);
            font-size: clamp(1.625rem, 2.6vw, 2rem);
            font-weight: 700;
            line-height: 1.2;
            letter-spacing: -.025em;
            color: var(--text-primary);
        }

        #flashcardsPage .tool-hero p {
            max-width: 620px;
            margin: 8px 0 0;
            color: var(--text-secondary);
            font-size: .95rem;
            font-weight: 400;
            line-height: 1.65;
        }

        /* ── Source switcher ──
           switchFcTab() writes the slider's `left` as 3px / 25% / 50% / 75%
           over four tabs, so the track's padding is 3px and stays 3px. */
        #flashcardsPage .tabs {
            padding: 3px;
            margin-bottom: 22px;
            border: 1px solid transparent;
            border-radius: 12px;
            background: #f7f8fc;
            box-shadow: none;
        }

        [data-dark] #flashcardsPage .tabs {
            border-color: transparent;
            background: #18181B;
        }

        #flashcardsPage .tab-slider {
            top: 3px;
            left: 3px;
            width: calc(25% - 2px);
            height: calc(100% - 6px);
            border: 1px solid var(--violet);
            border-radius: 12px;
            background: #eeecff;
            box-shadow: 0 2px 5px rgba(43, 35, 113, .06);
        }

        [data-dark] #flashcardsPage .tab-slider {
            border-color: #9d94ff;
            background: rgba(157, 148, 255, .12);
            box-shadow: none;
        }

        #flashcardsPage .tab-btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            min-height: 44px;
            padding: 9px 8px;
            color: var(--text-muted);
            font-size: .85rem;
            font-weight: 600;
        }

        /* `.tab-btn.active` carries an !important ink colour further up the
           sheet; this id-scoped rule has to restate it to win. */
        #flashcardsPage .tab-btn.active {
            color: var(--violet) !important;
        }

        #flashcardsPage .tab-btn .preset-short {
            display: none;
        }

        [data-dark] #flashcardsPage .tab-btn.active { color: #b9b2ff !important; }

        /* ── Fields ── */
        #flashcardsPage .field-label {
            margin-bottom: 6px;
            color: var(--text-muted);
            font-size: .875rem;
            font-weight: 600;
            letter-spacing: 0;
            text-transform: none;
        }

        [data-dark] #flashcardsPage .field-label {
            color: #B4B4BD;
        }

        #flashcardsPage .input-text,
        #flashcardsPage .textarea-notes {
            border: 1px solid #8791a3;
            border-radius: 12px;
            background: var(--card-bg, #fff);
            box-shadow: none;
            font-weight: 600;
        }

        #flashcardsPage .input-text {
            min-height: 48px;
            padding: 12px 14px;
        }

        #flashcardsPage .input-text:focus-visible,
        #flashcardsPage .textarea-notes:focus-visible {
            border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, .14);
            outline: none;
        }

        #flashcardsPage .csel-trigger {
            min-height: 48px;
            padding: 8px 12px;
            gap: 10px;
            border: 1px solid #8791a3;
            border-radius: 12px;
            background: var(--card-bg, #fff);
            box-shadow: none;
            font-weight: 600;
            transition: border-color .18s, box-shadow .18s;
        }

        #flashcardsPage .csel.open .csel-trigger,
        #flashcardsPage .csel-trigger:focus-visible {
            border-color: var(--violet);
            box-shadow: 0 0 0 3px rgba(91, 80, 232, .14);
        }

        @media (hover: hover) {
            #flashcardsPage .input-text:hover,
            #flashcardsPage .textarea-notes:hover,
            #flashcardsPage .csel-trigger:hover {
                border-color: rgba(91, 80, 232, .34);
            }
        }

        #flashcardsPage .upload-area {
            border: 1.5px dashed #8791a3;
            border-radius: 12px;
            background: none;
        }

        [data-dark] #flashcardsPage .upload-area {
            border-color: #85858F;
        }

        [data-dark] #flashcardsPage .csel-trigger,
        [data-dark] #flashcardsPage .input-text,
        [data-dark] #flashcardsPage .textarea-notes {
            border-color: #85858F;
            background: #232327;
            color: var(--text-primary);
        }

        [data-dark] #flashcardsPage .csel.open .csel-trigger,
        [data-dark] #flashcardsPage .csel-trigger:focus-visible,
        [data-dark] #flashcardsPage .input-text:focus-visible,
        [data-dark] #flashcardsPage .textarea-notes:focus-visible {
            border-color: #9d94ff;
            box-shadow: 0 0 0 3px rgba(157, 148, 255, .22);
        }

        /* ── Settings ──
           One setting, in the builder's grid under the builder's group label.
           auto-fit collapses the empty tracks, so a lone select would run the
           card's full 920px: capped to one settings-field width above the
           phone breakpoint, full width below it. */
        #flashcardsPage #fcAiControls .row-4 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 14px;
            margin-top: 0;
            max-width: 300px;
        }

        #flashcardsPage .setting-field {
            position: relative;
            z-index: 0;
            min-width: 0;
        }

        /* Keeps an open dropdown above whatever follows it. */
        #flashcardsPage .setting-field:focus-within,
        #flashcardsPage .setting-field.csel-open {
            z-index: 80;
        }

        /* ── Primary: solid violet, one line, no icon, no gradient, no lip ──
           #fcGenerateBtn is the AI path's action and #fcMakeBtn is the manual
           tab's own; only one of the two is ever on screen, and they are the
           same button. */
        #flashcardsPage #fcGenerateBtn,
        #flashcardsPage #fcMakeBtn {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
            width: 100%;
            max-width: none;
            height: auto;
            min-height: 48px;
            margin-top: 22px;
            padding: 12px 24px;
            border: 0;
            border-radius: 12px;
            background: var(--violet);
            background-image: none;
            color: #fff;
            font-family: var(--font-ui);
            font-size: .95rem;
            font-weight: 700;
            letter-spacing: 0;
            box-shadow: none;
            transition: background .16s ease;
        }

        /* The shared .btn-generate carries a sweep highlight; this page does not. */
        #flashcardsPage #fcGenerateBtn::before {
            display: none;
        }

        #flashcardsPage #fcGenerateBtn:hover:not(:disabled),
        #flashcardsPage #fcGenerateBtn:active:not(:disabled),
        #flashcardsPage #fcMakeBtn:hover,
        #flashcardsPage #fcMakeBtn:active {
            transform: none;
            filter: none;
            background: var(--violet-shade);
            box-shadow: none;
        }

        @media (hover: none) {
            #flashcardsPage #fcGenerateBtn:hover:not(:disabled),
            #flashcardsPage #fcMakeBtn:hover {
                background: var(--violet);
            }
        }

        /* study-tools.css shrinks every tool's .btn-generate to
           `width: auto !important` below 720px, and a <button> sizes `auto` to
           its content — which left this one a 210px stub (its min-width) in the
           601-720 band while it was 420px above and docked below. An
           !important is the only thing that reaches past another file's. */
        #flashcardsPage #fcGenerateBtn {
            width: 100% !important;
        }

        #flashcardsPage #fcGenerateCaption {
            margin-top: 10px;
        }

        /* ── Saved decks: hairline rows, no per-row cards ── */
        #flashcardsPage #fcSavedWrap .builder-group-label {
            margin-top: 0;
        }

        #flashcardsPage .fc-deck-row {
            padding: 12px 2px;
            border: 0;
            border-bottom: 1px solid rgba(91, 80, 232, .16);
            border-radius: 0;
            margin-bottom: 0;
            background: none;
            /* study-tools.css gives every deck row a card's drop shadow. The
               background and the radius are overridden above; without this the
               shadow alone still drew the card that is no longer there. */
            box-shadow: none;
        }

        [data-dark] #flashcardsPage .fc-deck-row {
            border-bottom-color: rgba(255, 255, 255, 0.08);
            background: none;
        }

        #flashcardsPage #fcSavedList .fc-deck-row:last-child {
            border-bottom: 0;
        }

        #flashcardsPage .fc-deck-row-title {
            font-size: .95rem;
            font-weight: 800;
        }

        #flashcardsPage .fc-deck-row-desc,
        #flashcardsPage .fc-deck-row-sub {
            font-size: .8rem;
        }

        #flashcardsPage .fc-deck-row-actions {
            gap: 18px;
        }

        /* Actions are text links, the same ones the builder puts under its
           primary — not five little buttons in a row. */
        #flashcardsPage .fc-deck-row .fc-btn {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            padding: 0;
            border: 0;
            background: none;
            color: var(--violet);
            font-family: var(--font-ui);
            font-size: .86rem;
            font-weight: 800;
            text-decoration: none;
            box-shadow: none;
            transform: none;
        }

        [data-dark] #flashcardsPage .fc-deck-row .fc-btn {
            color: #9d94ff;
        }

        @media (hover: hover) {
            #flashcardsPage .fc-deck-row .fc-btn:hover {
                background: none;
                text-decoration: underline;
            }
        }

        /* ── The deck: five modes, one segmented control ──
           The same hairline track as the source switcher above, at five
           tracks instead of four. No slider element: the current mode paints
           itself, which is all this row needs — it never moves. */
        #flashcardsPage .set-modes {
            display: grid;
            grid-template-columns: repeat(5, minmax(0, 1fr));
            gap: 4px;
            margin: 6px 0 18px;
            padding: 4px;
            border: 1px solid rgba(91, 80, 232, .12);
            border-radius: 999px;
            background: rgba(91, 80, 232, .08);
        }

        [data-dark] #flashcardsPage .set-modes {
            border-color: rgba(255, 255, 255, 0.08);
            background: rgba(255, 255, 255, 0.03);
        }

        #flashcardsPage .set-mode {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            min-height: 44px;
            padding: 9px 6px;
            border: 0;
            border-radius: 999px;
            background: none;
            color: var(--text-muted);
            font-family: var(--font-ui);
            font-size: .85rem;
            font-weight: 800;
            white-space: nowrap;
            cursor: var(--cur-point, pointer);
            box-shadow: none;
            transform: none;
            transition: background .16s ease, color .16s ease;
        }

        #flashcardsPage .set-mode-current {
            background: #fff;
            box-shadow: 0 1px 2px rgba(14, 18, 32, .08);
            color: var(--text-primary);
        }

        [data-dark] #flashcardsPage .set-mode-current {
            background: #232327;
            box-shadow: 0 1px 2px rgba(0, 0, 0, .4);
            color: #ece9ff;
        }

        #flashcardsPage .set-mode:focus-visible {
            outline: 3px solid var(--violet);
            outline-offset: 2px;
        }

        [data-dark] #flashcardsPage .set-mode:focus-visible {
            outline-color: #9d94ff;
        }

        @media (hover: hover) {
            #flashcardsPage .set-mode:hover {
                border-color: transparent;
                box-shadow: none;
                color: var(--text-primary);
            }
        }

        #flashcardsPage .set-mode .preset-short {
            display: none;
        }

        /* ── The deck head and its progress ── */
        #flashcardsPage .fc-deck-title {
            font-family: var(--font-display);
            font-size: 1.2rem;
            letter-spacing: -.01em;
        }

        #flashcardsPage .fc-progress-bar {
            background: rgba(91, 80, 232, .16);
        }

        [data-dark] #flashcardsPage .fc-progress-bar {
            background: rgba(157, 148, 255, 0.14);
        }

        #flashcardsPage .fc-progress-fill {
            background: var(--violet);
        }

        [data-dark] #flashcardsPage .fc-progress-fill {
            background: #9d94ff;
        }

        /* ── Wide ── */
        @media (min-width: 900px) {
            #flashcardsPage .tool-hero h2 {
                font-size: 2rem;
            }
        }

        /* ── Phone ──
           #fcGenerateBtn docks at 600px through the shared .btn-generate rule,
           whose `width: calc(100% - 32px)` an id-scoped max-width would
           otherwise outrank; and the docked bar (54px + a 20px inset) must
           never cover the last control, so the page carries that height plus
           16px of bottom padding. */
        @media (max-width: 600px) {
            #flashcardsPage {
                padding-bottom: 90px;
            }

            #flashcardsPage #fcGenerateBtn {
                max-width: none;
                width: calc(100% - 32px) !important;
            }
        }

        /* Four tabs have to stay on one row. Measured: "Type or paste" needs
           104px of track including its padding, and a quarter of the control
           only reaches that from a 456px viewport up (96px at 420, 89 at 390,
           81 at 360) — below which every label wrapped to two lines and the
           track grew from 44px to 56px. Swapping the spans rather than
           truncating them keeps the visible label inside the accessible name,
           and display:none keeps the unused one out of the accessibility tree
           entirely. */
        @media (max-width: 459px) {
            #flashcardsPage .tab-btn {
                padding-inline: 5px;
                font-size: .82rem;
            }

            #flashcardsPage .tab-btn .preset-long { display: none; }
            #flashcardsPage .tab-btn .preset-short { display: inline; }
        }

        /* One setting is the whole width of a phone. */
        @media (max-width: 560px) {
            #flashcardsPage #fcAiControls .row-4 {
                grid-template-columns: 1fr;
                max-width: none;
            }
        }

        /* Five segments have to stay on one row, and a fifth of a 358px track
           is 71px — less than "Flashcards" needs at any weight. Swapping the
           spans rather than truncating them keeps the visible label inside the
           accessible name, and display:none keeps the unused one out of the
           accessibility tree entirely. */
        @media (max-width: 620px) {
            #flashcardsPage .set-mode {
                padding-inline: 4px;
                font-size: .82rem;
            }

            #flashcardsPage .set-mode .preset-long { display: none; }
            #flashcardsPage .set-mode .preset-short { display: inline; }
        }


        /* ══ PAST PAPERS ══════════════════════════════════════════════════
           Built from the quiz builder's primitives: the same eyebrow, field
           labels, upload area, 54px solid-violet primary and hairline rows the
           builder and the flashcards page already use, so the three read as one
           product. Nothing here is a new component. */
        #paperPage .tool-hero {
            margin-bottom: 20px;
        }

        #paperPage .tool-hero h2::before {
            display: none;
        }

        #paperPage .generator-kicker::before {
            content: '';
            width: 20px;
            height: 2px;
            border-radius: 2px;
            background: var(--violet);
        }

        [data-dark] #paperPage .generator-kicker { color: #9d94ff; }

        [data-dark] #paperPage .generator-kicker::before { background: #9d94ff; }

        #paperPage .tool-hero h2 {
            margin: 9px 0 0;
            font-family: var(--font-display);
            font-size: 1.35rem;
            font-weight: 800;
            line-height: 1.14;
            letter-spacing: -.01em;
            color: var(--text-primary);
        }

        @media (min-width: 900px) {
            #paperPage .tool-hero h2 { font-size: 1.55rem; }
        }

        #paperPage .tool-hero p {
            max-width: 620px;
            margin: 8px 0 0;
            color: var(--text-secondary);
            font-size: .95rem;
            font-weight: 600;
            line-height: 1.5;
        }

        .pp-card {
            background: transparent;
            border: 0;
            padding: 4px 0 0;
        }

        #paperPage .field-label {
            margin-bottom: 6px;
            color: var(--text-muted);
            font-size: .72rem;
            font-weight: 800;
            letter-spacing: .1em;
        }

        [data-dark] #paperPage .field-label { color: #B4B4BD; }

        #paperPage .pp-label-gap { margin-top: 22px; }

        /* Lower-case inside a small-caps label: "optional" is the word the
           student reads, not part of the field's name. */
        #paperPage .pp-optional {
            margin-left: 6px;
            font-weight: 600;
            letter-spacing: .04em;
            text-transform: none;
            opacity: .75;
        }

        #paperPage .upload-area {
            padding: 20px 18px;
            border: 1.5px dashed rgba(91, 80, 232, .22);
            border-radius: 14px;
            background: none;
        }

        /* This screen has TWO of these where every other has one, so the icon
           sits beside the words rather than above them. */
        #paperPage .upload-icon {
            width: 36px;
            height: 36px;
            margin: 0 auto 9px;
        }

        [data-dark] #paperPage .upload-area { border-color: rgba(255, 255, 255, 0.14); }

        /* The shared rule tints and re-borders on :hover; on a touch screen
           that state sticks after the tap that opened the file picker. */
        @media (hover: none) {
            #paperPage .upload-area:hover {
                border-color: rgba(91, 80, 232, .22);
                background: none;
            }

            [data-dark] #paperPage .upload-area:hover { border-color: rgba(255, 255, 255, 0.14); }
        }

        /* No thumbnail on this page — a page of an exam paper is unreadable at
           preview size, so the name bar carries it alone. */
        #paperPage .upload-preview {
            margin-top: 10px;
            background: none;
            border: 1px solid rgba(91, 80, 232, .16);
        }

        [data-dark] #paperPage .upload-preview { border-color: rgba(255, 255, 255, 0.08); }

        /* What the upload actually yielded — the character count when we can
           read the text, the file's own size when the model reads it for us. */
        #paperPage .pp-file-caption {
            margin: 8px 0 0;
            color: var(--text-muted);
            font-size: .82rem;
            font-weight: 600;
            min-height: 1.2em;
        }

        #paperPage #paperSitBtn {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
            width: 100% !important;
            max-width: 420px;
            height: auto;
            min-height: 54px;
            margin-top: 24px;
            padding: 12px 24px;
            border: 0;
            border-radius: 999px;
            background: var(--violet);
            background-image: none;
            color: #fff;
            font-family: var(--font-display);
            font-size: 1.05rem;
            font-weight: 800;
            letter-spacing: 0;
            box-shadow: none;
            transition: background .16s ease;
        }

        #paperPage #paperSitBtn::before { display: none; }

        #paperPage #paperSitBtn:hover:not(:disabled),
        #paperPage #paperSitBtn:active:not(:disabled) {
            transform: none;
            filter: none;
            background: var(--violet-shade);
            box-shadow: none;
        }

        @media (hover: none) {
            #paperPage #paperSitBtn:hover:not(:disabled) { background: var(--violet); }
        }

        #paperPage #paperSitBtn:disabled {
            /* !important for the same reason .btn-generate:disabled needs it:
               the entrance animation's opacity fill outranks a plain
               declaration, so without it this computed .55 (the base rule),
               not .45, and the button read enabled while unclickable. */
            opacity: .45 !important;
            cursor: var(--cur-default, default);
        }

        #paperPage #paperSitCaption { margin-top: 10px; }

        #paperPage #paperFound,
        #paperPage #paperSavedWrap { margin-top: 26px; }

        #paperPage #paperFound .builder-group-label,
        #paperPage #paperSavedWrap .builder-group-label { margin-top: 0; }

        /* Hairline-divided rows, no per-row cards — the same list primitive the
           saved decks use. */
        #paperPage .pp-row {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 14px;
            padding: 12px 2px;
            border-bottom: 1px solid rgba(91, 80, 232, .16);
        }

        [data-dark] #paperPage .pp-row { border-bottom-color: rgba(255, 255, 255, 0.08); }

        #paperPage .pp-row:last-child { border-bottom: 0; }

        #paperPage .pp-row-title {
            color: var(--text-primary);
            font-size: .95rem;
            font-weight: 800;
        }

        #paperPage .pp-row-sub {
            margin-top: 2px;
            color: var(--text-muted);
            font-size: .8rem;
            font-weight: 600;
        }

        #paperPage .pp-row-actions {
            display: flex;
            flex-shrink: 0;
            gap: 18px;
        }

        #paperPage .pp-link {
            padding: 0;
            border: 0;
            background: none;
            color: var(--violet);
            font-family: var(--font-ui);
            font-size: .86rem;
            font-weight: 800;
            cursor: var(--cur-point, pointer);
        }

        [data-dark] #paperPage .pp-link { color: #9d94ff; }

        @media (hover: hover) {
            #paperPage .pp-link:hover { text-decoration: underline; }
        }

        #paperPage .pp-link:focus-visible {
            outline: 3px solid rgba(91, 80, 232, .45);
            outline-offset: 3px;
            border-radius: 6px;
        }

        [data-dark] #paperPage .pp-link:focus-visible { outline-color: rgba(157, 148, 255, .55); }

        @media (pointer: coarse) {
            #paperPage .pp-link { min-height: 44px; display: inline-flex; align-items: center; }

            /* The upload zones' own Remove was never added to the shared
               TOUCH TARGETS block at the end of this stylesheet (it only
               covers .course-edit, .mode-bar a and the like), so it sat at
               18px on a finger like every other .upload-clear on the site. */
            #paperPage .upload-clear { min-height: 44px; display: inline-flex; align-items: center; }
        }

        /* ── The paper's own results, under the marks-by-section slip ── */
        .paper-misses {
            margin: 18px 0 4px;
            padding: 16px 18px;
            border: 1px solid rgba(91, 80, 232, .16);
            border-radius: 16px;
            text-align: left;
        }

        [data-dark] .paper-misses { border-color: rgba(255, 255, 255, 0.08); }

        .paper-misses-title {
            margin-bottom: 12px;
            color: var(--text-muted);
            font-size: .72rem;
            font-weight: 800;
            letter-spacing: .1em;
            text-transform: uppercase;
        }

        .paper-miss {
            padding: 11px 0;
            border-top: 1px solid rgba(91, 80, 232, .12);
        }

        [data-dark] .paper-miss { border-top-color: rgba(255, 255, 255, 0.08); }

        .paper-miss:first-of-type { border-top: 0; padding-top: 0; }

        .paper-miss-head {
            display: flex;
            align-items: baseline;
            justify-content: space-between;
            gap: 12px;
        }

        .paper-miss-q {
            color: var(--text-primary);
            font-size: .9rem;
            font-weight: 800;
        }

        /* The mark, not a verdict: amber for dropped marks and the app's red
           reserved for a question that scored nothing. */
        .paper-miss-mark {
            flex-shrink: 0;
            color: var(--amber);
            font-size: .88rem;
            font-weight: 800;
            font-variant-numeric: tabular-nums;
        }

        /* The app's dark amber, as the streak pill uses: --amber has no dark
           override and #d97706 is too dim on the navy. */
        [data-dark] .paper-miss-mark { color: #fbbf24; }

        .paper-miss-mark.is-zero { color: var(--rose); }

        [data-dark] .paper-miss-mark.is-zero { color: #fb7185; }

        .paper-miss-text {
            margin-top: 3px;
            color: var(--text-muted);
            font-size: .84rem;
            font-weight: 600;
            line-height: 1.45;
        }

        .paper-miss-crit {
            margin: 8px 0 0;
            padding-left: 18px;
            color: var(--text-secondary, var(--text-muted));
            font-size: .84rem;
            font-weight: 600;
            line-height: 1.5;
        }

        .paper-miss-crit li { margin-bottom: 3px; }

        /* Below 600px the shared .btn-generate docks itself (position: fixed,
           left/right 16px), and a fixed element measures `width: 100%` against
           the VIEWPORT — so the 100% above made it 390px wide starting at 16px
           and it ran 16px off the screen. Give way to the dock's own calc, and
           carry the docked bar's height plus 16px as bottom padding so it never
           covers the last control. */
        @media (max-width: 600px) {
            #paperPage {
                padding-bottom: 90px;
            }

            #paperPage #paperSitBtn {
                max-width: none;
                width: calc(100% - 32px) !important;
            }
        }

        /* The one control in this block. It is inside #scoreCard, not
           #paperPage, so it cannot inherit .pp-link's scoped rules. */
        .paper-miss-retest {
            margin-top: 14px;
            padding: 0;
            border: 0;
            background: none;
            color: var(--violet);
            font-family: var(--font-ui);
            font-size: .86rem;
            font-weight: 800;
            cursor: var(--cur-point, pointer);
        }

        [data-dark] .paper-miss-retest { color: #9d94ff; }

        @media (hover: hover) {
            .paper-miss-retest:hover { text-decoration: underline; }
        }

        .paper-miss-retest:focus-visible {
            outline: 3px solid rgba(91, 80, 232, .45);
            outline-offset: 3px;
            border-radius: 6px;
        }

        [data-dark] .paper-miss-retest:focus-visible { outline-color: rgba(157, 148, 255, .55); }

        /* #scoreCard :focus-visible (ID specificity) otherwise beats the rule
           above and rings this 2px in --dbr-accent with a 4px radius instead —
           the same class of defeat .sm-link already had to be qualified
           against on this same card. */
        #scoreCard .paper-miss-retest:focus-visible {
            outline: 3px solid rgba(91, 80, 232, .45);
            outline-offset: 3px;
            border-radius: 6px;
        }

        [data-dark] #scoreCard .paper-miss-retest:focus-visible { outline-color: rgba(157, 148, 255, .55); }

        @media (pointer: coarse) {
            .paper-miss-retest { min-height: 44px; display: inline-flex; align-items: center; }
        }

        @media (max-width: 560px) {
            .paper-misses { padding: 14px; }

            #paperPage .pp-row {
                flex-direction: column;
                align-items: flex-start;
                gap: 6px;
            }
        }

        /* ── TOUCH TARGETS ──
           Touch-only sizing bump; desktop keeps the compact look. On a finger
           these controls were 27–38px tall. Deliberately the LAST rules in this
           stylesheet: the #inputSection variants above pin their own min-height
           (34px on the presets, 38px on the nested field triggers), so anything
           earlier — or of lower specificity — silently loses and the bump never
           lands. Selectors are matched rather than reaching for !important. */
        @media (pointer: coarse) {
            .csel-trigger { min-height: 44px; }
            #inputSection .csel-trigger,
            #inputSection .setting-field .csel-trigger { min-height: 48px; }

            /* The course chip's Change / Done are text links; give a finger
               the full 44px without changing how they read. */
            .course-edit { min-height: 44px; display: inline-flex; align-items: center; }

            /* The switch keeps its 50×27 look — the knob transition is tuned to
               that track — and grows an invisible hit area instead. */
            .toggle-switch::after {
                content: '';
                position: absolute;
                inset: -8px -4px;
            }

            /* The study tools were never added to this block, so their primary
               controls sat at 34-36px on a finger: the row that switches
               between Flashcards / Learn / Test / Match / Write, the library's
               filter chips, the essay-type picker, and the back button that is
               the only way out of a full-screen tool. Measured across all 24
               .section-page panes at 375px — these four were the entire
               shortfall; everything else already clears 44px. Padding grows the
               hit area, the drawn size is unchanged. */
            .mode-bar a,
            .lib-chip,
            .essay-type-chip,
            .section-page > button[onclick^="closeSection"] {
                min-height: 44px;
                display: inline-flex;
                align-items: center;
                justify-content: center;
            }
        }

        .auth-modal-close,
        .menu-close {
            min-width: 44px;
            min-height: 44px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
        }
