/* ================================================================
   THEME - the single source of truth for light and dark surfaces
   ================================================================

   How this works, and why it is built this way.

   Before this file there were four switches (top nav, sidebar, enterprise nav,
   Settings) that all added a `dark-mode` class to <body>, and NOT ONE rule in
   the entire codebase responded to it. Dark mode did not exist; it was a class
   nobody read.

   The theme is now an attribute on <html>: data-theme="light" | "dark". It goes
   on the root element - not <body> - so an inline script in index.html can set
   it before the first paint and before Blazor boots, which is what keeps a dark
   user from being flashbanged by a white app-shell on every reload.

   Two layers do all the work:

     1. THE SCALE FLIPS. The existing --gray-N ramp is used across the app for
        both page surfaces (gray-50/100) and text (gray-700/900). Inverting the
        ramp in dark therefore fixes both at once, and every component already
        written against those tokens comes along for free - roughly 1,800 var()
        call sites.

     2. SEMANTIC TOKENS carry intent that a bare grey ramp cannot: is this a
        page, a card, a popover, a sunken row? Components converted away from
        hardcoded #fff use these, so their meaning survives the theme flip.

   Loaded LAST in index.html. Variable definitions do not care about order, but
   the compatibility block at the bottom - which reclaims third-party and
   Bootstrap surfaces we do not own - has to win on source order.

   The light values below are byte-identical to what custom.css already
   defined. Turning the theme on must not shift a single pixel in light mode. */

/* ================================================================
   1. LIGHT (the default, and the fallback for any unknown theme)
   ================================================================ */
:root {
    /* Page and surface intent */
    --surface-page: #f9fafb;      /* the app background behind everything */
    --surface: #ffffff;           /* cards, panels, the nav bar */
    --surface-raised: #ffffff;    /* things that float: dropdowns, modals */
    --surface-sunken: #f8fafc;    /* inset rows, search fields, wells */
    --surface-hover: rgba(15, 23, 42, 0.04);
    --surface-accent: rgba(42, 158, 166, 0.08);

    --border-subtle: rgba(15, 23, 42, 0.07);
    --border-color: rgba(15, 23, 42, 0.10);
    --border-strong: #e2e8f0;

    --text-strong: #0f172a;
    --text-body: #1f2937;
    --text-muted: #64748b;
    --text-subtle: #94a3b8;

    --overlay: rgba(15, 23, 42, 0.55);

    /* Brand ink that has to stay legible ON a surface (not on a fill). */
    --brand-ink: #1F7F86;
    --brand-text: #2A9EA6;

    /* The app bar is its own material: translucent, blurred, sitting over
       scrolling content. It needs alpha values a flat surface token can't
       carry, so it gets named tokens rather than being approximated. */
    --nav-surface: rgba(255, 255, 255, 0.85);
    --nav-surface-scrolled: rgba(255, 255, 255, 0.94);
    --nav-border: rgba(15, 23, 42, 0.07);
    --nav-divider: rgba(15, 23, 42, 0.1);
    --nav-link: #4A5568;
    --nav-button-surface: rgba(255, 255, 255, 0.9);
    --nav-shadow: rgba(15, 23, 42, 0.28);

    /* Destructive ink. Kept as tokens because #B91C1C is deliberately dark for
       contrast on white and becomes unreadable on a dark ground. */
    --danger-ink: #B91C1C;
    --danger-ink-strong: #991B1B;
    --danger-icon: #DC2626;

    /* ── Tinted families ──────────────────────────────────────────────
       The app codes meaning by colour: blue for information, green for
       correct, amber for flagged, red for wrong, teal for the brand's own
       extras, indigo for the AI coach. Each family is a pale wash, a slightly
       stronger wash for hover/fills, a pale border and a dark ink.

       They need tokens because a wash CANNOT simply be darkened: #d1fae5 at
       dark-mode lightness reads as black, not as green. In dark each becomes
       translucent colour over the page, so the code survives (amber still
       means flagged) while the ground shows through, and the ink lifts to
       stay readable. Light values are the exact hexes already in use. */
    --info-soft: #eff6ff;
    --info-soft-2: #dbeafe;
    --info-border: #bfdbfe;
    --info-ink: #1e40af;

    --success-soft: #ecfdf5;
    --success-soft-2: #d1fae5;
    --success-border: #a7f3d0;
    --success-ink: #059669;
    --success-ink-strong: #065f46;

    --warning-soft: #fffbeb;
    --warning-soft-2: #fef3c7;
    --warning-soft-3: #fde68a;
    --warning-border: #fcd34d;
    --warning-ink: #b45309;
    --warning-ink-strong: #92400e;

    --error-soft: #fef2f2;
    --error-soft-2: #fee2e2;
    --error-soft-3: #fecaca;
    --error-border: #fca5a5;
    --error-ink: #dc2626;
    --error-ink-strong: #991b1b;

    --accent-soft: #ecfeff;
    --accent-soft-2: #cffafe;
    --accent-border: #a5f3fc;
    --accent-ink: #0e7490;

    --indigo-soft: #eef2ff;
    --indigo-soft-2: #e0e7ff;
    --indigo-border: #c7d2fe;
    --indigo-ink: #4338ca;

    color-scheme: light;
}

/* ================================================================
   2. DARK
   ================================================================
   Not "grey with the lights off": a slightly blue-cool ink family, so the
   teal brand keeps its identity instead of turning muddy. Surfaces step up
   in lightness as they come forward (page < card < popover), which is how
   depth reads without shadows on a dark ground. */
[data-theme="dark"] {
    --surface-page: #0b1220;
    --surface: #131c2b;
    --surface-raised: #1b2536;
    --surface-sunken: #0f1826;
    --surface-hover: rgba(255, 255, 255, 0.06);
    --surface-accent: rgba(42, 158, 166, 0.16);

    --border-subtle: rgba(255, 255, 255, 0.07);
    --border-color: rgba(255, 255, 255, 0.11);
    --border-strong: rgba(255, 255, 255, 0.15);

    --text-strong: #e9eef6;
    --text-body: #dbe3ee;
    --text-muted: #9aa8bd;
    --text-subtle: #7b8aa0;

    --overlay: rgba(2, 6, 15, 0.7);

    /* #2A9EA6 on a dark ground sits at roughly 3:1 - fine for a large fill,
       not for body text. Text-weight brand ink is lifted; the fill token
       stays put so buttons keep the brand colour. */
    --brand-ink: #4FC3CB;
    --brand-text: #4FC3CB;

    --nav-surface: rgba(13, 20, 32, 0.82);
    --nav-surface-scrolled: rgba(13, 20, 32, 0.94);
    --nav-border: rgba(255, 255, 255, 0.08);
    --nav-divider: rgba(255, 255, 255, 0.12);
    --nav-link: #a8b6ca;
    --nav-button-surface: rgba(255, 255, 255, 0.05);
    --nav-shadow: rgba(0, 0, 0, 0.6);

    --danger-ink: #FCA5A5;
    --danger-ink-strong: #FECACA;
    --danger-icon: #F87171;

    --info-soft: rgba(96, 165, 250, 0.12);
    --info-soft-2: rgba(96, 165, 250, 0.2);
    --info-border: rgba(96, 165, 250, 0.35);
    --info-ink: #93c5fd;

    --success-soft: rgba(52, 211, 153, 0.12);
    --success-soft-2: rgba(52, 211, 153, 0.2);
    --success-border: rgba(52, 211, 153, 0.35);
    --success-ink: #34d399;
    --success-ink-strong: #6ee7b7;

    --warning-soft: rgba(251, 191, 36, 0.12);
    --warning-soft-2: rgba(251, 191, 36, 0.18);
    --warning-soft-3: rgba(251, 191, 36, 0.26);
    --warning-border: rgba(251, 191, 36, 0.38);
    --warning-ink: #fbbf24;
    --warning-ink-strong: #fcd34d;

    --error-soft: rgba(248, 113, 113, 0.12);
    --error-soft-2: rgba(248, 113, 113, 0.18);
    --error-soft-3: rgba(248, 113, 113, 0.26);
    --error-border: rgba(248, 113, 113, 0.4);
    --error-ink: #f87171;
    --error-ink-strong: #fca5a5;

    --accent-soft: rgba(42, 158, 166, 0.16);
    --accent-soft-2: rgba(42, 158, 166, 0.24);
    --accent-border: rgba(42, 158, 166, 0.4);
    --accent-ink: #4FC3CB;

    --indigo-soft: rgba(129, 140, 248, 0.14);
    --indigo-soft-2: rgba(129, 140, 248, 0.22);
    --indigo-border: rgba(129, 140, 248, 0.35);
    --indigo-ink: #c7d2fe;

    /* The grey ramp inverts. Backgrounds written as gray-50/100/200 go dark,
       text written as gray-700/800/900 goes light, in one move. */
    --gray-50: #0f1724;
    --gray-100: #16202f;
    --gray-200: #1e2a3b;
    --gray-300: #2a3749;
    --gray-400: #55637a;
    --gray-500: #8290a6;
    --gray-600: #a7b3c6;
    --gray-700: #c4cddc;
    --gray-800: #dde4ee;
    --gray-900: #eef2f8;

    --navy-800: #101a29;
    --navy-900: #0a121e;

    /* Brand + status colours lifted for contrast against the dark ground. */
    --primary-600: #35b3bb;
    --primary-700: #2A9EA6;
    --primary-800: #26808C;
    --accent-purple: #A9B0D6;

    --success-500: #34d399;
    --success-600: #10b981;
    --warning-500: #fbbf24;
    --warning-600: #f59e0b;
    --error-500: #f87171;
    --error-600: #ef4444;
    --info-500: #60a5fa;

    /* Shadows carry almost no weight on a dark ground - deepen them so
       elevation is still readable. */
    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.4);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -1px rgba(0, 0, 0, 0.4);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.55), 0 4px 6px -2px rgba(0, 0, 0, 0.4);
    --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.6), 0 10px 10px -5px rgba(0, 0, 0, 0.4);
    --shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.75);

    color-scheme: dark;
}

/* ================================================================
   3. BASE
   ================================================================ */
html[data-theme="dark"],
html[data-theme="dark"] body {
    background-color: var(--surface-page);
    color: var(--text-body);
}

/* The theme flip itself is animated on the two properties that actually
   change, so switching reads as one deliberate move rather than a flicker.
   Not applied to everything - a global transition would drag every hover. */
html[data-theme="dark"] body,
html[data-theme="light"] body {
    transition: background-color 0.25s ease, color 0.25s ease;
}

@media (prefers-reduced-motion: reduce) {
    html[data-theme="dark"] body,
    html[data-theme="light"] body {
        transition: none;
    }
}

/* ================================================================
   4. COMPATIBILITY - surfaces we do not own
   ================================================================
   Bootstrap ships hardcoded white/near-white here, and the app leans on these
   classes all over. Each one is a real surface in the layout, so it is claimed
   explicitly rather than hoping a variable reaches it. */
html[data-theme="dark"] .card,
html[data-theme="dark"] .modal-content,
html[data-theme="dark"] .list-group-item,
html[data-theme="dark"] .accordion-item,
html[data-theme="dark"] .accordion-button,
html[data-theme="dark"] .dropdown-menu,
html[data-theme="dark"] .popover,
html[data-theme="dark"] .offcanvas {
    background-color: var(--surface-raised);
    color: var(--text-body);
    border-color: var(--border-color);
}

html[data-theme="dark"] .modal-header,
html[data-theme="dark"] .modal-footer,
html[data-theme="dark"] .card-header,
html[data-theme="dark"] .card-footer {
    border-color: var(--border-color);
}

html[data-theme="dark"] .dropdown-item {
    color: var(--text-body);
}

html[data-theme="dark"] .dropdown-item:hover,
html[data-theme="dark"] .dropdown-item:focus,
html[data-theme="dark"] .list-group-item-action:hover {
    background-color: var(--surface-hover);
    color: var(--text-strong);
}

html[data-theme="dark"] .form-control,
html[data-theme="dark"] .form-select,
html[data-theme="dark"] .input-group-text {
    background-color: var(--surface-sunken);
    border-color: var(--border-color);
    color: var(--text-body);
}

html[data-theme="dark"] .form-control::placeholder {
    color: var(--text-subtle);
}

html[data-theme="dark"] .form-control:focus,
html[data-theme="dark"] .form-select:focus {
    background-color: var(--surface-sunken);
    border-color: var(--primary-600);
    color: var(--text-strong);
}

html[data-theme="dark"] .table {
    --bs-table-color: var(--text-body);
    --bs-table-bg: transparent;
    --bs-table-border-color: var(--border-color);
    --bs-table-striped-color: var(--text-body);
    --bs-table-striped-bg: var(--surface-hover);
    --bs-table-hover-color: var(--text-strong);
    --bs-table-hover-bg: var(--surface-hover);
}

/* Bootstrap's utility surfaces mean "the page's own paper", which is exactly
   what has to move in dark - not literal white. */
html[data-theme="dark"] .bg-white,
html[data-theme="dark"] .bg-light {
    background-color: var(--surface) !important;
}

html[data-theme="dark"] .text-dark {
    color: var(--text-strong) !important;
}

html[data-theme="dark"] .text-muted,
html[data-theme="dark"] .text-secondary {
    color: var(--text-muted) !important;
}

html[data-theme="dark"] .border,
html[data-theme="dark"] .border-top,
html[data-theme="dark"] .border-bottom,
html[data-theme="dark"] .border-start,
html[data-theme="dark"] .border-end {
    border-color: var(--border-color) !important;
}

/* Bootstrap's "light" button is literally #f8f9fa with dark text. It is used
   for secondary actions next to a primary one, so in dark it becomes the same
   quiet raised surface the rest of the app uses for that role. */
html[data-theme="dark"] .btn-light {
    background-color: var(--surface-raised);
    border-color: var(--border-color);
    color: var(--text-body);
}

html[data-theme="dark"] .btn-light:hover,
html[data-theme="dark"] .btn-light:focus {
    background-color: var(--surface-hover);
    border-color: var(--border-strong);
    color: var(--text-strong);
}

html[data-theme="dark"] .btn-outline-secondary {
    color: var(--text-body);
    border-color: var(--border-strong);
}

/* The close glyph is a black SVG baked into a background-image. */
html[data-theme="dark"] .btn-close {
    filter: invert(1) grayscale(100%) brightness(200%);
}

html[data-theme="dark"] .modal-backdrop.show {
    opacity: 0.75;
}

/* Blazor's own error bar and the boot screen live outside every component. */
html[data-theme="dark"] #blazor-error-ui {
    background: #2b2410;
    color: #fde68a;
}

/* Scrollbars: a bright system scrollbar on a dark page is the last thing that
   gives away a half-finished theme. */
html[data-theme="dark"] ::-webkit-scrollbar {
    width: 12px;
    height: 12px;
}

html[data-theme="dark"] ::-webkit-scrollbar-track {
    background: var(--surface-page);
}

html[data-theme="dark"] ::-webkit-scrollbar-thumb {
    background: #2a3749;
    border: 3px solid var(--surface-page);
    border-radius: 8px;
}

html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover {
    background: #3a4a60;
}

/* Images and illustrations authored on white keep their own ground; only the
   flat-white logo tile is toned down so it stops glowing. */
html[data-theme="dark"] .logo-icon-img {
    filter: brightness(0.95);
}

/* ================================================================
   5. GRADIENTS - the exam runner
   ================================================================
   Flat fills across the app now ride the tokens above, so they flip on their
   own. What cannot is a GRADIENT: a wash between two near-white stops has no
   darker twin to swap in - interpolating #f8fafc to #eef2f6 at dark lightness
   just yields two blacks. Each one below is rebuilt as translucent colour over
   the dark ground, keeping the colour code (amber flagged, green correct, red
   wrong, teal study-mode) while letting the page show through.

   The light rules live in a <style> block inside Exam.razor, which renders
   after every linked stylesheet - so these are prefixed with html[data-theme]
   to win on specificity rather than on source order. FreeExam shares the same
   class names and is covered by the same rules.
   ================================================================ */
html[data-theme="dark"] .fx-page {
    background: linear-gradient(180deg, var(--surface-page) 0%, #0d1522 100%);
}

html[data-theme="dark"] .fx-save__icon {
    background: linear-gradient(135deg, var(--warning-soft-2) 0%, var(--warning-soft-3) 100%);
    color: var(--warning-ink);
}

html[data-theme="dark"] .fx-study__icon {
    background: linear-gradient(135deg, var(--accent-soft) 0%, var(--accent-soft-2) 100%) !important;
    color: var(--brand-ink) !important;
}

html[data-theme="dark"] .fx-modecard--study {
    background: linear-gradient(180deg, var(--surface-raised) 0%, rgba(42, 158, 166, 0.1) 100%);
    border-color: var(--accent-border);
}

html[data-theme="dark"] .fx-modecard--study.is-locked {
    background: var(--surface-sunken);
    border-color: var(--border-color);
}

html[data-theme="dark"] .fx-shuffle-note {
    background: linear-gradient(135deg, rgba(42, 158, 166, 0.12) 0%, rgba(129, 140, 248, 0.12) 100%);
    border-color: var(--accent-border);
}

html[data-theme="dark"] .fx-ask-pop {
    background: linear-gradient(135deg, var(--surface-raised) 0%, rgba(129, 140, 248, 0.12) 100%);
    border-color: var(--indigo-border);
}

/* Drag-and-drop targets paint their own paper via a radial highlight. */
html[data-theme="dark"] .fx-ddt--over {
    background: var(--surface-accent);
    border-color: var(--primary-600);
}
