/*
 * ============================================================================
 *  Criterium design tokens
 * ============================================================================
 *
 *  All shared visual values live here as CSS custom properties. Component CSS
 *  (site.css, components.css) should reach for these tokens rather than literal
 *  values, so a change happens in one place and every theme inherits it. New
 *  CSS that hardcodes a colour / spacing / radius / shadow / duration is a
 *  defect — use (or add) a token. Full guidance:
 *  _documents/criterium_ui_design_tokens.md
 *
 *  Each [data-theme="…"] block below overrides the colour tokens; the
 *  non-colour scales (spacing, elevation, motion, radius) are defined once on
 *  :root and inherited by every theme.
 *
 *  ── Spacing (4px base; for margins, gap, vertical rhythm) ──────────────────
 *    --space-0  0       --space-3  0.75rem 12px   --space-6  2rem  32px
 *    --space-1  0.25rem --space-4  1rem    16px   --space-7  3rem  48px
 *    --space-2  0.5rem  --space-5  1.5rem  24px
 *
 *  ── Typography (the only sizes allowed at or below body size) ─────────────
 *    --font-size-xs  0.85rem 13.6px (floor)  --font-size-md   0.95rem 15.2px
 *    --font-size-sm  0.9rem  14.4px          --font-size-base 1rem    16px
 *    Heading/display sizes above base stay literal. No font-size below the
 *    floor anywhere — TypographyScaleGuardTest fails the suite on new ones.
 *
 *  ── Elevation (drop shadows; NOT for focus rings) ─────────────────────────
 *    --elevation-1  resting cards / subtle lift
 *    --elevation-2  raised panels, popovers
 *    --elevation-3  mastheads, prominent surfaces
 *    --elevation-4  modals / highest overlays
 *    --panel-boundary-shadow / -hover  visible collection-panel boundaries
 *
 *  ── Motion (transitions & animations) ─────────────────────────────────────
 *    --duration-fast 120ms   --duration-base 200ms   --duration-slow 320ms
 *    --ease-standard  decelerate to rest (UI affordances)
 *    --ease-emphasis  slight overshoot (becoming-active moments)
 *
 *  ── Radius ────────────────────────────────────────────────────────────────
 *    --border-radius-sm / -md / -lg / -pill  (theme-tuned; pill = fully round,
 *    or 0 on the sharp-corner themes — never hardcode 999px)
 *
 *  ── Colour / surface / status ─────────────────────────────────────────────
 *    Per-theme below: --bg-…, --text-…, --accent…, --border-…, --btn-…,
 *    --panel-action-…, --success…, --warning…, the error and status
 *    (ready/open/closed/…) families, and --role-… identifiers. Use
 *    --accent-text (not --accent) for link and status TEXT — --accent fails
 *    WCAG 1.4.3 as text on some themes.
 * ============================================================================
 */

:root,
[data-theme="modern-grade"] {
    /* Semantic presentation choices consumed by theme-agnostic component CSS. */
    --page-color-scheme: light;
    /*
     * Main UI typeface. Defined once here so the application font can be changed
     * in a single place. The default is the accessibility-oriented "Atkinson
     * Hyperlegible" (designed by the Braille Institute for low-vision readers),
     * loaded from Google Fonts in includes/page.php. Users may override it per
     * the [data-font="…"] rules below; see includes/font.php for the allow-list.
     * If you change the default family, update that <link> (and the CSP font
     * sources in src/auth.php if you move off Google Fonts) to match.
     */
    --font-sans: "Atkinson Hyperlegible", "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
    /*
     * Keep font-size-adjust off so text renders at its authored size. A
     * numeric value made the loaded reading font render smaller than its CSS
     * size (for example, 0.875rem appeared around 13.3px instead of 14px).
     */
    --font-size-adjust: none;
    /*
     * Serif and monospace stacks. Defined here so any theme or component that
     * opts into them and monospaced surfaces (e.g. API key fields) resolve to a
     * real font rather than the browser
     * default. System stacks only — no extra web-font load.
     */
    --font-serif: Georgia, Cambria, "Times New Roman", Times, serif;
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
    --page-background:
        radial-gradient(circle at top left, color-mix(in srgb, var(--accent) 16%, transparent), transparent 32%),
        radial-gradient(circle at bottom right, color-mix(in srgb, var(--progress-fill) 12%, transparent), transparent 36%),
        linear-gradient(180deg, var(--bg-page) 0%, color-mix(in srgb, var(--bg-page) 78%, var(--bg-panel) 22%) 100%);
    --site-brand-logo-light-display: block;
    --site-brand-logo-amber-display: none;
    --site-brand-logo-dark-display: none;
    --presence-completed-text: var(--text-primary);
    --hero-box-shadow: 0 18px 40px color-mix(in srgb, var(--shadow-color) 18%, transparent);
    --candidate-home-text: var(--text-on-accent);
    --candidate-home-icon-text: color-mix(in srgb, var(--text-on-accent) 78%, var(--accent-subtle) 22%);
    --candidate-home-helper-text: color-mix(in srgb, var(--text-on-accent) 72%, var(--accent-subtle) 28%);
    --candidate-home-input-text: var(--text-on-accent);
    --candidate-home-placeholder-text: color-mix(in srgb, var(--text-on-accent) 62%, var(--accent-subtle) 38%);
    /* Table-panel controls need to read as interactive, not as another
       information tile. Derived tokens inherit each theme's own palette. */
    --panel-action-secondary-bg: color-mix(in srgb, var(--accent) 12%, var(--bg-panel) 88%);
    --panel-action-secondary-bg-hover: color-mix(in srgb, var(--accent) 22%, var(--bg-panel) 78%);
    --panel-action-secondary-border: color-mix(in srgb, var(--accent) 58%, var(--border-color) 42%);
    --panel-boundary-shadow-color: var(--accent-hover);
    --panel-boundary-shadow:
        0 0 0 1px color-mix(in srgb, var(--panel-boundary-shadow-color) 18%, transparent),
        0 5px 14px color-mix(in srgb, var(--panel-boundary-shadow-color) 20%, transparent),
        0 18px 38px color-mix(in srgb, var(--panel-boundary-shadow-color) 14%, transparent);
    --panel-boundary-shadow-hover:
        0 0 0 1px color-mix(in srgb, var(--panel-boundary-shadow-color) 26%, transparent),
        0 8px 20px color-mix(in srgb, var(--panel-boundary-shadow-color) 22%, transparent),
        0 24px 48px color-mix(in srgb, var(--panel-boundary-shadow-color) 16%, transparent);
    --role-admin: #334155;
    --role-content-author: #0f766e;
    --role-content-reviewer: #2563eb;
    --role-marker: #7c3aed;
    --role-invigilator: #e8a020;
    --role-candidate: #4a7cb5;
    --brand-surface: #ffffff;
    --sidebar-bg: #ffffff;
    --sidebar-text: #1a1a2a;
    --sidebar-muted: #9c9690;
    --heading-font: inherit;
    --bg-page: #f5f3ef;
    --bg-panel: #ffffff;
    --bg-panel-secondary: #f8fbff;
    --bg-table-header: #1b3f72;
    --bg-input: #ffffff;
    --bg-radio-selected: #d6e6f5;
    --bg-status-live: #dcfce7;
    --bg-badge-draft: #d6e6f5;
    --border-color: #e0dbd3;
    --border-color-emphasis: #4a7cb5;
    --border-width: 1px;
    --border-width-emphasis: 1.5px;
    --border-radius-sm: 8px;
    --border-radius-md: 12px;
    --border-radius-lg: 18px;
    --border-radius-pill: 999px;
    --text-primary: #1a1a2a;
    --text-secondary: #4a4a5a;
    /* Darkened from #736e66 (~4.3:1 on the warm --bg-page) so muted text —
       footer, labels, helper copy — reads comfortably rather than faint. */
    --text-muted: #5c574f;
    --text-on-accent: #ffffff;
    --text-status-live: #166534;
    --text-badge-draft: #1b3f72;
    --text-role-label: #d6e6f5;
    --accent: #4a7cb5;
    /* AA-compliant text variant of the accent (WCAG 1.4.3): used for link and
       status text where --accent itself fails 4.5:1. --accent stays for
       borders/fills/backgrounds. */
    --accent-text: #2f5f93;
    --accent-hover: #1b3f72;
    --accent-subtle: #d6e6f5;
    --success: #22c55e;
    --success-bg: #f0fdf4;
    --success-border: #bbf7d0;
    --success-text: #166534;
    --btn-primary-bg: #1b3f72;
    --btn-primary-text: #ffffff;
    --btn-primary-border: none;
    --btn-secondary-bg: #ffffff;
    --btn-secondary-text: #1b3f72;
    --btn-secondary-border: 1px solid #e0dbd3;
    --progress-track: #d6e6f5;
    --progress-fill: #4a7cb5;
    --role-icon-bg: #1b3f72;
    --role-icon-text: #ffffff;
    --question-accent-border: #4a7cb5;
    --question-accent-bg: #f8fbff;
    --bg-notice: #ffffff;
    --bg-error: #fef2f2;
    --border-error: #fecaca;
    --text-error: #b91c1c;
    --warning-bg: #fff7ed;
    --warning-text: #9a3412;
    --bg-status-ready: #f3f7fc;
    --border-status-ready: #a8c4e0;
    --text-status-ready: #1b3f72;
    --bg-status-open: #f0fdf4;
    --border-status-open: #bbf7d0;
    --text-status-open: #166534;
    --bg-status-closed: #fff5df;
    --border-status-closed: #e8a020;
    --text-status-closed: #8c5d10;
    --bg-status-archived: #f8f5f0;
    --border-status-archived: #d9d1c7;
    --text-status-archived: #6b6773;
    /* Warning border companion to --warning-bg / --warning-text. */
    --warning-border: #d6a64a;
    /* Additional status families for badges that are neither ready/open/closed.
       Defined once here as the theme-agnostic default; themes inherit these
       unless a future change tunes them per palette. */
    --bg-status-info: #ede9fe;
    --border-status-info: #8b5cf6;
    --text-status-info: #5b21b6;
    --bg-status-sky: #e0f2fe;
    --border-status-sky: #0ea5e9;
    --text-status-sky: #0c4a6e;
    --bg-status-pink: #fce7f3;
    --border-status-pink: #ec4899;
    --text-status-pink: #831843;
    /* Bespoke gold "attention" highlight used by invigilator help/indicator pills. */
    --highlight-attention: #f4c95d;
    --highlight-attention-text: #3b2b00;
    --shadow-color: #d7d0c7;

    /*
     * Elevation scale. Before this existed, every surface hand-rolled its own
     * box-shadow (~37 sites in site.css) with slightly different blur/spread and
     * --shadow-color opacity, so panels at the "same" height did not actually
     * match. These four steps give a deliberate, consistent ramp; each is a
     * two-layer shadow (a tight contact shadow + a soft ambient one) which reads
     * as more grounded than a single blurred drop. Built on --shadow-color so
     * every theme — including the dark ones, whose --shadow-color is near-black —
     * inherits a tuned elevation for free. Component CSS should prefer these over
     * bespoke values; the existing inline shadows can migrate opportunistically.
     */
    --elevation-1:
        0 1px 2px color-mix(in srgb, var(--shadow-color) 10%, transparent),
        0 2px 6px color-mix(in srgb, var(--shadow-color) 8%, transparent);
    --elevation-2:
        0 2px 4px color-mix(in srgb, var(--shadow-color) 10%, transparent),
        0 8px 22px color-mix(in srgb, var(--shadow-color) 12%, transparent);
    --elevation-3:
        0 4px 8px color-mix(in srgb, var(--shadow-color) 12%, transparent),
        0 18px 40px color-mix(in srgb, var(--shadow-color) 14%, transparent);
    --elevation-4:
        0 8px 16px color-mix(in srgb, var(--shadow-color) 14%, transparent),
        0 28px 60px color-mix(in srgb, var(--shadow-color) 18%, transparent);

    /*
     * Motion tokens. Durations + a shared easing curve so transitions across the
     * app feel like one system rather than each hover/reveal picking its own
     * timing. The easing is a gentle ease-out (decelerate into rest), which suits
     * UI affordances; --ease-emphasis adds a slight overshoot for playful moments
     * like a control becoming active. All motion is suppressed under the existing
     * prefers-reduced-motion handling — see the reduced-motion block in site.css.
     */
    --duration-fast: 120ms;
    --duration-base: 200ms;
    --duration-slow: 320ms;
    --ease-standard: cubic-bezier(0.2, 0, 0, 1);
    --ease-emphasis: cubic-bezier(0.34, 1.56, 0.64, 1);

    /*
     * Vertical-rhythm spacing scale (4px base). Before this existed, margins and
     * gaps were hand-picked rem values: a dominant 0.25/0.5/0.75/1rem rhythm plus
     * a long tail of one-off in-betweens (0.15, 0.3, 0.35, 0.4, 0.45, 0.6, 0.65,
     * 0.7, 0.85, 0.9rem). Those near-misses read as "sometimes too tight /
     * inconsistent" even though no single value was wrong. These steps name the
     * rhythm so the same gap means the same thing on every screen; outlier values
     * across site.css/components.css were snapped to the nearest step. Use these
     * for vertical gaps between elements (margins, flex/grid gap, stack spacing).
     */
    --space-0: 0;
    --space-1: 0.25rem;   /* 4px  — hairline gaps, icon/label pairs */
    --space-2: 0.5rem;    /* 8px  — tight groupings within a control */
    --space-3: 0.75rem;   /* 12px — default gap between related elements */
    --space-4: 1rem;      /* 16px — between distinct elements / rows */
    --space-5: 1.5rem;    /* 24px — between sub-sections */
    --space-6: 2rem;      /* 32px — between major sections */
    --space-7: 3rem;      /* 48px — page-level separation */

    /*
     * Typography scale. Before this existed, every component picked its own
     * literal font-size, and the small end drifted ever downward (9px badges,
     * 11px pills, a long 0.7–0.85rem tail ≈ 11–13.6px) — each new screen copied
     * a nearby small value, so "the text is too small" kept recurring across
     * the platform. These four steps are the only sizes allowed at or below
     * the body size; --font-size-xs is the readability floor and nothing may
     * render smaller. Display/heading sizes above --font-size-base stay
     * literal (they are one-off by nature). TypographyScaleGuardTest enforces
     * this: new sub-body font-size literals in the stylesheets fail the suite.
     */
    --font-size-xs: 0.85rem;   /* 13.6px — the floor: badges, chips, fine print */
    --font-size-sm: 0.9rem;    /* 14.4px — secondary text, meta lines, small labels */
    --font-size-md: 0.95rem;   /* 15.2px — dense/compact body, control labels */
    --font-size-base: 1rem;    /* 16px   — default body and table reading size */
}

/*
 * Reading-font preference (accessibility). The default is Atkinson Hyperlegible
 * (set on --font-sans above). Users may opt into an alternative via the font
 * switcher, which sets <html data-font="…">. The allow-list and persistence
 * live in includes/font.php; the toggle is rendered in includes/page.php.
 *
 * BOTH reading fonts are self-hosted from deploy/public/assets/fonts/ (per
 * that directory's README) so no page load contacts a third-party origin and
 * the CSP font-src / style-src stay pure 'self'. Until the files
 * are present a face simply falls through to the sans-serif fallback stack,
 * so a missing font never breaks the page. font-display: swap avoids
 * invisible text while a face loads. Paths are relative to this stylesheet's
 * location. All four faces of each family are declared so bold and italic
 * text use the real designed faces rather than synthesised ones. Atkinson
 * Hyperlegible ships as WOFF2; OpenDyslexic ships as OpenType (.otf).
 */
@font-face {
    font-family: "Atkinson Hyperlegible";
    src: url("../fonts/AtkinsonHyperlegible-Regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Atkinson Hyperlegible";
    src: url("../fonts/AtkinsonHyperlegible-Bold.woff2") format("woff2");
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Atkinson Hyperlegible";
    src: url("../fonts/AtkinsonHyperlegible-Italic.woff2") format("woff2");
    font-weight: 400;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: "Atkinson Hyperlegible";
    src: url("../fonts/AtkinsonHyperlegible-BoldItalic.woff2") format("woff2");
    font-weight: 700;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: "OpenDyslexic";
    src: url("../fonts/OpenDyslexic-Regular.otf") format("opentype");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "OpenDyslexic";
    src: url("../fonts/OpenDyslexic-Bold.otf") format("opentype");
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "OpenDyslexic";
    src: url("../fonts/OpenDyslexic-Italic.otf") format("opentype");
    font-weight: 400;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: "OpenDyslexic";
    src: url("../fonts/OpenDyslexic-BoldItalic.otf") format("opentype");
    font-weight: 700;
    font-style: italic;
    font-display: swap;
}

/* "atkinson" is the default and so needs no override; it is listed so the
   switcher can mark it active and to document the full set in one place. */
[data-font="atkinson"] {
    --font-sans: "Atkinson Hyperlegible", "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}

[data-font="dyslexic"] {
    --font-sans: "OpenDyslexic", "Atkinson Hyperlegible", "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
    --font-size-adjust: none;
}

[data-theme="slate-command"] {
    --page-color-scheme: dark;
    --panel-boundary-shadow-color: var(--shadow-color);
    --page-background:
        radial-gradient(circle at top left, color-mix(in srgb, var(--accent) 20%, transparent), transparent 28%),
        radial-gradient(circle at bottom right, color-mix(in srgb, var(--progress-fill) 18%, transparent), transparent 30%),
        linear-gradient(180deg, var(--bg-page) 0%, color-mix(in srgb, var(--bg-page) 90%, var(--bg-panel) 10%) 100%);
    --site-brand-logo-light-display: none;
    --site-brand-logo-dark-display: block;
    --presence-completed-text: var(--text-on-accent);
    --role-admin: #334155;
    --role-content-author: #0f766e;
    --role-content-reviewer: #2563eb;
    --role-marker: #7c3aed;
    --role-invigilator: #d97706;
    --role-candidate: #0891b2;
    --brand-surface: #1b3f72;
    --sidebar-bg: #0f172a;
    --sidebar-text: #f8fafc;
    --sidebar-muted: #cbd5e1;
    --heading-font: inherit;
    --bg-page: #0f172a;
    --bg-panel: #1e293b;
    --bg-panel-secondary: #0f172a;
    --bg-table-header: #0a0f1a;
    --bg-input: #0f172a;
    --bg-radio-selected: #1e3a5f;
    --bg-status-live: #052e16;
    --bg-badge-draft: #052e16;
    --border-color: #334155;
    --border-color-emphasis: #3b82f6;
    --border-width: 1px;
    --border-width-emphasis: 1px;
    --border-radius-sm: 4px;
    --border-radius-md: 4px;
    --border-radius-lg: 8px;
    --border-radius-pill: 3px;
    --text-primary: #f8fafc;
    --text-secondary: #cbd5e1;
    --text-muted: #94a3b8;
    --text-on-accent: #ffffff;
    --text-status-live: #22c55e;
    --text-badge-draft: #22c55e;
    --text-role-label: #3b82f6;
    --accent: #3b82f6;
    --accent-text: #60a5fa;
    --accent-hover: #2563eb;
    --accent-subtle: #1e3a5f;
    --success: #22c55e;
    --success-bg: #052e16;
    --success-border: #166534;
    --success-text: #ffffff;
    --btn-primary-bg: #3b82f6;
    --btn-primary-text: #ffffff;
    --btn-primary-border: none;
    --btn-secondary-bg: #1e293b;
    --btn-secondary-text: #cbd5e1;
    --btn-secondary-border: 1px solid #475569;
    --progress-track: #334155;
    --progress-fill: #3b82f6;
    --role-icon-bg: #1e3a5f;
    --role-icon-text: #3b82f6;
    --question-accent-border: #3b82f6;
    --question-accent-bg: #1e3a5f;
    --bg-notice: #0f172a;
    --bg-error: #3f1d1d;
    --border-error: #7f1d1d;
    --text-error: #fca5a5;
    --warning-bg: #431407;
    --warning-text: #fdba74;
    --bg-status-ready: #172554;
    --border-status-ready: #1d4ed8;
    --text-status-ready: #93c5fd;
    --bg-status-open: #052e16;
    --border-status-open: #166534;
    --text-status-open: #86efac;
    --bg-status-closed: #431407;
    --border-status-closed: #9a3412;
    --text-status-closed: #fdba74;
    --bg-status-archived: #111827;
    --border-status-archived: #374151;
    --text-status-archived: #cbd5e1;
    --shadow-color: #020617;
}

[data-theme="civic-clear"] {
    --hero-box-shadow: none;
    --role-admin: #334155;
    --role-content-author: #0f766e;
    --role-content-reviewer: #2563eb;
    --role-marker: #7c3aed;
    --role-invigilator: #d97706;
    --role-candidate: #0891b2;
    --brand-surface: #ffffff;
    --sidebar-bg: #003078;
    --sidebar-text: #ffffff;
    --sidebar-muted: #93c5fd;
    --sidebar-card-bg: #1a4080;
    --sidebar-card-border: #2a5298;
    --sidebar-card-label: #93c5fd;
    --sidebar-card-text: #ffffff;
    --heading-font: inherit;
    --bg-page: #ffffff;
    --bg-panel: #f3f2f1;
    --bg-panel-secondary: #ffffff;
    --bg-table-header: #003078;
    --bg-input: #ffffff;
    --bg-radio-selected: #f0f4fa;
    --bg-status-live: #00703c;
    --bg-badge-draft: #f3f2f1;
    --border-color: #b1b4b6;
    --border-color-emphasis: #003078;
    --border-width: 2px;
    --border-width-emphasis: 2px;
    --border-radius-sm: 0px;
    --border-radius-md: 0px;
    --border-radius-lg: 0px;
    --border-radius-pill: 0px;
    --text-primary: #0b0c0e;
    --text-secondary: #505a5f;
    --text-muted: #505a5f;
    --text-on-accent: #ffffff;
    --text-status-live: #ffffff;
    --text-badge-draft: #505a5f;
    --text-role-label: #ffffff;
    --accent: #003078;
    /* --accent already clears 4.5:1 as text on this theme; keep them equal. */
    --accent-text: #003078;
    --accent-hover: #001f53;
    --accent-subtle: #f0f4fa;
    --success: #00703c;
    --success-bg: #f3f2f1;
    --success-border: #b1b4b6;
    --success-text: #0b0c0e;
    --btn-primary-bg: #00703c;
    --btn-primary-text: #ffffff;
    --btn-primary-border: none;
    --btn-secondary-bg: #ffffff;
    --btn-secondary-text: #0b0c0e;
    --btn-secondary-border: 2px solid #0b0c0e;
    --progress-track: #b1b4b6;
    --progress-fill: #003078;
    --role-icon-bg: #003078;
    --role-icon-text: #ffffff;
    --question-accent-border: #ffdd00;
    --question-accent-bg: #faf9f8;
    --bg-notice: #ffffff;
    --bg-error: #ffffff;
    --border-error: #d4351c;
    --text-error: #d4351c;
    --warning-bg: #fff7bf;
    --warning-text: #0b0c0e;
    --bg-status-ready: #f0f4fa;
    --border-status-ready: #003078;
    --text-status-ready: #003078;
    --bg-status-open: #00703c;
    --border-status-open: #00703c;
    --text-status-open: #ffffff;
    --bg-status-closed: #fff7bf;
    --border-status-closed: #ffdd00;
    --text-status-closed: #0b0c0e;
    --bg-status-archived: #f3f2f1;
    --border-status-archived: #b1b4b6;
    --text-status-archived: #505a5f;
    --shadow-color: #b1b4b6;
}

[data-theme="amber-ledger"] {
    /* The marker question card is an attention surface, not a success state:
       use Amber's pale-orange question palette instead of its dark-green
       success palette. */
    --marker-question-bg: var(--question-accent-bg);
    --marker-question-border: var(--question-accent-border);
    --site-brand-logo-light-display: none;
    --site-brand-logo-amber-display: block;
    --presence-completed-text: var(--text-on-accent);
    --role-admin: #334155;
    --role-content-author: #0f766e;
    --role-content-reviewer: #2563eb;
    --role-marker: #7c3aed;
    --role-invigilator: #d97706;
    --role-candidate: #0891b2;
    --brand-surface: #fffdf9;
    --sidebar-bg: #78350f;
    --sidebar-text: #fff7ed;
    --sidebar-muted: #fed7aa;
    --sidebar-card-bg: #92400e;
    --sidebar-card-border: #b45309;
    --sidebar-card-label: #fdba74;
    --sidebar-card-text: #fff7ed;
    --heading-font: var(--font-sans);
    --bg-page: #fdf8f0;
    --bg-panel: #ffffff;
    --bg-panel-secondary: #fef3c7;
    --bg-table-header: #451a03;
    --bg-input: #ffffff;
    --bg-radio-selected: #fff7ed;
    --bg-status-live: #14532d;
    --bg-badge-draft: #451a03;
    --border-color: #e7d5bb;
    --border-color-emphasis: #ea580c;
    --border-width: 1px;
    --border-width-emphasis: 1.5px;
    --border-radius-sm: 4px;
    --border-radius-md: 5px;
    --border-radius-lg: 8px;
    --border-radius-pill: 999px;
    --text-primary: #451a03;
    --text-secondary: #78350f;
    --text-muted: #b45309;
    --text-on-accent: #fff7ed;
    --text-status-live: #86efac;
    --text-badge-draft: #fed7aa;
    --text-role-label: #fed7aa;
    --accent: #ea580c;
    --accent-text: #b8480b;
    --accent-hover: #c2410c;
    --accent-subtle: #fff7ed;
    --success: #4ade80;
    --success-bg: #14532d;
    --success-border: #166534;
    --success-text: #fff7ed;
    --btn-primary-bg: #ea580c;
    --btn-primary-text: #fff7ed;
    --btn-primary-border: none;
    --btn-secondary-bg: #ffffff;
    --btn-secondary-text: #78350f;
    --btn-secondary-border: 1px solid #e7d5bb;
    --progress-track: #e7d5bb;
    --progress-fill: #ea580c;
    --role-icon-bg: #92400e;
    --role-icon-text: #fed7aa;
    --question-accent-border: #ea580c;
    --question-accent-bg: #fff7ed;
    --bg-notice: #fffaf2;
    --bg-error: #fff1f2;
    --border-error: #fdba74;
    --text-error: #9a3412;
    --warning-bg: #fef3c7;
    --warning-text: #92400e;
    --bg-status-ready: #ffedd5;
    --border-status-ready: #fdba74;
    --text-status-ready: #9a3412;
    --bg-status-open: #14532d;
    --border-status-open: #166534;
    --text-status-open: #bbf7d0;
    --bg-status-closed: #fef3c7;
    --border-status-closed: #f59e0b;
    --text-status-closed: #92400e;
    --bg-status-archived: #451a03;
    --border-status-archived: #78350f;
    --text-status-archived: #fed7aa;
    --shadow-color: #b45309;
}

[data-theme="forest-authority"] {
    --presence-completed-text: var(--text-on-accent);
    --role-admin: #334155;
    --role-content-author: #0f766e;
    --role-content-reviewer: #2563eb;
    --role-marker: #7c3aed;
    --role-invigilator: #d97706;
    --role-candidate: #0891b2;
    --brand-surface: #f8fdf9;
    --sidebar-bg: #14532d;
    --sidebar-text: #f0fdf4;
    --sidebar-muted: #86efac;
    --sidebar-card-bg: #166534;
    --sidebar-card-border: #15803d;
    --sidebar-card-label: #4ade80;
    --sidebar-card-text: #f0fdf4;
    --heading-font: inherit;
    --bg-page: #f7fdf9;
    --bg-panel: #ffffff;
    --bg-panel-secondary: #f0fdf4;
    --bg-table-header: #052e16;
    --bg-input: #ffffff;
    --bg-radio-selected: #dcfce7;
    --bg-status-live: #052e16;
    --bg-badge-draft: #052e16;
    --border-color: #bbf7d0;
    --border-color-emphasis: #15803d;
    --border-width: 1px;
    --border-width-emphasis: 1.5px;
    --border-radius-sm: 5px;
    --border-radius-md: 5px;
    --border-radius-lg: 8px;
    --border-radius-pill: 999px;
    --text-primary: #052e16;
    --text-secondary: #166534;
    --text-muted: #15803d;
    --text-on-accent: #f0fdf4;
    --text-status-live: #4ade80;
    --text-badge-draft: #4ade80;
    --text-role-label: #f0fdf4;
    --accent: #15803d;
    /* --accent already clears 4.5:1 as text on this theme; keep them equal. */
    --accent-text: #15803d;
    --accent-hover: #14532d;
    --accent-subtle: #dcfce7;
    --success: #4ade80;
    --success-bg: #052e16;
    --success-border: #166534;
    --success-text: #f0fdf4;
    --btn-primary-bg: #15803d;
    --btn-primary-text: #f0fdf4;
    --btn-primary-border: none;
    --btn-secondary-bg: #ffffff;
    --btn-secondary-text: #166534;
    --btn-secondary-border: 1px solid #bbf7d0;
    --progress-track: #bbf7d0;
    --progress-fill: #15803d;
    --role-icon-bg: #14532d;
    --role-icon-text: #86efac;
    --question-accent-border: #15803d;
    --question-accent-bg: #f0fdf4;
    --bg-notice: #f0fdf4;
    --bg-error: #fef2f2;
    --border-error: #fecaca;
    --text-error: #991b1b;
    --warning-bg: #fef3c7;
    --warning-text: #92400e;
    --bg-status-ready: #dcfce7;
    --border-status-ready: #86efac;
    --text-status-ready: #166534;
    --bg-status-open: #052e16;
    --border-status-open: #166534;
    --text-status-open: #86efac;
    --bg-status-closed: #ecfccb;
    --border-status-closed: #84cc16;
    --text-status-closed: #3f6212;
    --bg-status-archived: #14532d;
    --border-status-archived: #166534;
    --text-status-archived: #bbf7d0;
    --shadow-color: #166534;
}

[data-theme="obsidian-edge"] {
    --page-color-scheme: dark;
    --panel-boundary-shadow-color: var(--shadow-color);
    --page-background:
        radial-gradient(circle at top left, color-mix(in srgb, var(--accent) 20%, transparent), transparent 28%),
        radial-gradient(circle at bottom right, color-mix(in srgb, var(--progress-fill) 18%, transparent), transparent 30%),
        linear-gradient(180deg, var(--bg-page) 0%, color-mix(in srgb, var(--bg-page) 90%, var(--bg-panel) 10%) 100%);
    --site-brand-logo-light-display: none;
    --site-brand-logo-dark-display: block;
    --presence-completed-text: var(--text-on-accent);
    /* This palette's accent text tokens are near-black, so the dark candidate
       tile needs its light text tokens for readable copy and access-code input. */
    --candidate-home-text: var(--text-primary);
    --candidate-home-icon-text: var(--text-secondary);
    --candidate-home-helper-text: var(--text-secondary);
    --candidate-home-input-text: var(--text-primary);
    --candidate-home-placeholder-text: var(--text-secondary);
    --role-admin: #334155;
    --role-content-author: #0f766e;
    --role-content-reviewer: #2563eb;
    --role-marker: #7c3aed;
    --role-invigilator: #d97706;
    --role-candidate: #0891b2;
    --brand-surface: #09090b;
    --sidebar-bg: #09090b;
    --sidebar-text: #fafafa;
    --sidebar-muted: #52525b;
    --heading-font: inherit;
    --bg-page: #09090b;
    --bg-panel: #09090b;
    --bg-panel-secondary: #18181b;
    --bg-table-header: #18181b;
    --bg-input: #09090b;
    --bg-radio-selected: #18181b;
    --bg-status-live: #09090b;
    --bg-badge-draft: #09090b;
    --border-color: #27272a;
    --border-color-emphasis: #a3e635;
    --border-width: 1px;
    --border-width-emphasis: 1px;
    --border-radius-sm: 0px;
    --border-radius-md: 0px;
    --border-radius-lg: 2px;
    --border-radius-pill: 0px;
    --text-primary: #fafafa;
    --text-secondary: #d4d4d8;
    --text-muted: #8a8a93;
    --text-on-accent: #09090b;
    --text-status-live: #a3e635;
    /* WCAG 1.4.3: #71717a was 4.12:1 on the #09090b pill bg; #85858e
       is 5.44:1, keeping the muted-grey intent. Reused by --text-status-archived. */
    --text-badge-draft: #85858e;
    --text-role-label: #a3e635;
    --accent: #a3e635;
    /* Lime on near-black already clears 4.5:1 as text; keep them equal. */
    --accent-text: #a3e635;
    --accent-hover: #84cc16;
    --accent-subtle: #18181b;
    --success: #a3e635;
    --success-bg: #09090b;
    --success-border: #27272a;
    --success-text: #a3e635;
    --btn-primary-bg: #a3e635;
    --btn-primary-text: #09090b;
    --btn-primary-border: none;
    --btn-secondary-bg: #09090b;
    --btn-secondary-text: #71717a;
    --btn-secondary-border: 1px solid #3f3f46;
    --progress-track: #27272a;
    --progress-fill: #a3e635;
    --role-icon-bg: #09090b;
    --role-icon-text: #a3e635;
    --question-accent-border: #a3e635;
    --question-accent-bg: #18181b;
    --bg-notice: #18181b;
    --bg-error: #2b1115;
    --border-error: #7f1d1d;
    --text-error: #fca5a5;
    --warning-bg: #1c1917;
    --warning-text: #fdba74;
    --bg-status-ready: #18181b;
    --border-status-ready: #52525b;
    --text-status-ready: #fafafa;
    --bg-status-open: #09090b;
    --border-status-open: #3f6212;
    --text-status-open: #a3e635;
    --bg-status-closed: #1c1917;
    --border-status-closed: #57534e;
    --text-status-closed: #e7e5e4;
    --bg-status-archived: #09090b;
    --border-status-archived: #27272a;
    /* WCAG 1.4.3: lightened from #71717a (4.12:1) to clear 4.5:1
       on the #09090b archived-pill background. */
    --text-status-archived: #85858e;
    --shadow-color: #000000;
}
[data-theme="learning"] {
    --sidebar-bg: #0b3b63;
    --sidebar-text: #ffffff;
    --sidebar-muted: #b6d8ee;
    --sidebar-card-bg: #f4f9fc;
    --sidebar-card-border: #c9dbe8;
    --sidebar-card-label: #5f84a0;
    --sidebar-card-text: #12324a;

    --bg-page: #f4f9fc;
    --bg-panel: #ffffff;
    --bg-panel-secondary: #eef7fc;
    --bg-table-header: #0b3b63;

    --text-primary: #12324a;
    --text-secondary: #3d5d74;
    /* Darkened from #577084 (~4.5:1 on --bg-page) so muted text — footer,
       labels, helper copy — reads comfortably rather than faint. */
    --text-muted: #45647c;
    --text-on-accent: #ffffff;

    --accent: #7bb342;
    /* AA-compliant text variant: lime #7bb342 is only 2.5:1 as text on white;
       #4a7a28 clears 4.5:1. --accent stays for borders/fills/backgrounds. */
    --accent-text: #4a7a28;
    --accent-hover: #5f8f32;
    --accent-subtle: #eef7e8;

    --btn-primary-bg: #7bb342;
    --btn-primary-text: #ffffff;
    --btn-primary-border: none;

    --btn-secondary-bg: #ffffff;
    --btn-secondary-text: #0b3b63;
    --btn-secondary-border: 1px solid #c9dbe8;

    --progress-track: #d9edf8;
    --progress-fill: #7bb342;

    --border-color: #c9dbe8;
    --border-color-emphasis: #7bb342;

    --question-accent-border: #7bb342;
    --question-accent-bg: #eef7e8;

    --role-icon-bg: #0b3b63;
    --role-icon-text: #ffffff;

    --success: #7bb342;
    --success-bg: #eef7e8;
    --success-border: #b9d99a;
    --success-text: #3f6212;

    --shadow-color: rgba(11, 59, 99, 0.12);
}
