/**
 * Design Tokens - hodlon-webcore
 *
 * Architecture (Radix-inspired, perceptually calibrated):
 *   1. Primitive scales (OKLCH) — 12-step ramps per hue
 *   2. Semantic tokens — the API modules/components consume
 *   3. Component tokens — kept minimal, only when genuinely needed
 *
 * Color space: OKLCH for perceptually uniform ramps (supports hover/dark
 * derivation without hue shifts). Hex fallback provided via @supports.
 *
 * Theme support: CSS light-dark() native function. `data-theme="dark"`
 * and `data-theme="light"` force the theme regardless of OS preference.
 *
 * Brand palette sourced from Cobudge logo:
 *   navy    #173954  → --navy-9    (primary action, brand signature)
 *   emerald #10b981  → --emerald-9 (accent, success, charts positifs)
 */

:root {
    color-scheme: light dark;

    /* ======================================================================
       SPACING — 4px base unit
       ====================================================================== */
    --space-xs:  0.25rem;   /*  4px */
    --space-sm:  0.5rem;    /*  8px */
    --space-md:  1rem;      /* 16px */
    --space-lg:  1.5rem;    /* 24px */
    --space-xl:  2rem;      /* 32px */
    --space-2xl: 3rem;      /* 48px */
    --space-3xl: 4rem;      /* 64px */

    /* ======================================================================
       RADIUS
       ====================================================================== */
    --radius-xs:   2px;
    --radius-sm:   6px;
    --radius-md:   8px;
    --radius-lg:   12px;
    --radius-xl:   16px;
    --radius-full: 9999px;

    /* ======================================================================
       TYPOGRAPHY
       ====================================================================== */
    --font-sans:    'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --font-mono:    'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
    --font-display: var(--font-sans);

    /* Inter OpenType features globally enabled on body:
     *   cv11 — alternate single-storey 'a' (more legible at small sizes)
     *   ss01 — alternate open digits
     *   cv05 — lowercase 'l' with tail (distinct from I, 1)
     */
    --font-features: 'cv11', 'ss01', 'cv05';

    /* Modular scale — ratio 1.2 (minor third). Body = 15px (pro density). */
    --text-xs:      0.75rem;    /* 12px — caption, legal */
    --text-sm:      0.8125rem;  /* 13px — labels, secondary */
    --text-base:    0.9375rem;  /* 15px — body */
    --text-md:      1rem;       /* 16px — body lead */
    --text-lg:      1.125rem;   /* 18px — card-title */
    --text-xl:      1.375rem;   /* 22px — h2, page-title */
    --text-2xl:     1.75rem;    /* 28px — h1 */
    --text-3xl:     2.25rem;    /* 36px — landing section */
    --text-display: clamp(2.5rem, 3.5vw + 1.5rem, 4.5rem);

    --leading-none:    1;
    --leading-tight:   1.2;
    --leading-snug:    1.4;
    --leading-normal:  1.55;
    --leading-relaxed: 1.75;

    --tracking-tighter: -0.04em;
    --tracking-tight:   -0.02em;
    --tracking-normal:  0;
    --tracking-wide:    0.025em;
    --tracking-widest:  0.1em;

    /* ======================================================================
       MOTION
       ====================================================================== */
    --duration-instant: 80ms;
    --duration-fast:    150ms;
    --duration-normal:  200ms;
    --duration-slow:    300ms;
    --duration-slower:  500ms;

    /* Material 3 easing vocabulary */
    --ease-standard:   cubic-bezier(0.2, 0, 0, 1);
    --ease-emphasized: cubic-bezier(0.3, 0, 0, 1);
    --ease-decelerate: cubic-bezier(0, 0, 0, 1);
    --ease-accelerate: cubic-bezier(0.3, 0, 1, 1);
    --ease-spring:     cubic-bezier(0.34, 1.56, 0.64, 1);

    /* Typed transitions — never use `transition: all` */
    --motion-hover:  background-color var(--duration-fast) var(--ease-standard),
                     color var(--duration-fast) var(--ease-standard),
                     border-color var(--duration-fast) var(--ease-standard),
                     box-shadow var(--duration-fast) var(--ease-standard);
    --motion-enter:  opacity var(--duration-normal) var(--ease-decelerate),
                     transform var(--duration-normal) var(--ease-decelerate);
    --motion-spring: transform var(--duration-slow) var(--ease-spring);

    /* ======================================================================
       LAYOUT
       ====================================================================== */
    --sidebar-width-mini: 64px;
    --sidebar-width-full: 240px;
    --header-height:      44px;
    --touch-target:       44px;

    /* ======================================================================
       BREAKPOINTS
       ----------------------------------------------------------------------
       Media queries cannot consume CSS custom properties, so these tokens
       exist as a single source of truth for documentation and scripts.
       The canonical set aligns with Tailwind/Bootstrap for dev familiarity:

         sm  640px   phone landscape / small tablet
         md  768px   tablet
         lg  1024px  desktop
         xl  1280px  large desktop

       Authoring rules:
         - Prefer mobile-first:  @media (min-width: 640px) { ... }
         - When using max-width, subtract 0.02 to avoid pixel overlap:
             @media (max-width: 767.98px) { ... }
         - Legacy 480px / 767px breakpoints in existing files are kept
           to avoid regressions; new code should use the values above.
       ====================================================================== */
    --bp-sm: 640px;
    --bp-md: 768px;
    --bp-lg: 1024px;
    --bp-xl: 1280px;

    /* ======================================================================
       Z-INDEX SCALE
       ====================================================================== */
    --z-base:            1;
    --z-dropdown:        100;
    --z-sticky:          100;
    --z-sidebar-overlay: 199;
    --z-sidebar:         200;
    --z-select:          1000;
    --z-tour:            1050;
    --z-drawer:          1100;
    --z-toast:           1200;
    --z-widget:          1300;
    --z-capture:         1400;
    --z-loading:         1500;
    --z-skip-link:       1600;

    /* ======================================================================
       PRIMITIVE COLOR SCALES (OKLCH, Radix-style 12-step semantics)
       ----------------------------------------------------------------------
       Step roles:
         1-2:  app/surface backgrounds
         3-5:  UI element backgrounds (normal/hover/active)
         6-8:  borders (subtle/normal/hover)
         9:    solid action color
         10:   solid action hover
         11:   low-contrast text (≥4.5:1 on step-1)
         12:   high-contrast text (≥15:1 on step-1)
       ====================================================================== */

    /* Slate — cool-tinted neutrals (body surfaces, borders, text) */
    --slate-1:  oklch(0.990 0.003 247);
    --slate-2:  oklch(0.985 0.004 247);
    --slate-3:  oklch(0.965 0.008 247);
    --slate-4:  oklch(0.945 0.011 247);
    --slate-5:  oklch(0.920 0.013 247);
    --slate-6:  oklch(0.885 0.016 247);
    --slate-7:  oklch(0.835 0.019 247);
    --slate-8:  oklch(0.745 0.025 247);
    --slate-9:  oklch(0.565 0.028 247);
    --slate-10: oklch(0.520 0.026 247);
    --slate-11: oklch(0.430 0.024 247);
    --slate-12: oklch(0.240 0.020 247);

    /* Navy — brand primary (derived from logo #173954) */
    --navy-1:   oklch(0.990 0.005 235);
    --navy-2:   oklch(0.975 0.010 235);
    --navy-3:   oklch(0.950 0.020 235);
    --navy-4:   oklch(0.915 0.030 235);
    --navy-5:   oklch(0.870 0.040 235);
    --navy-6:   oklch(0.805 0.050 235);
    --navy-7:   oklch(0.710 0.060 235);
    --navy-8:   oklch(0.580 0.070 235);
    --navy-9:   oklch(0.320 0.060 235);
    --navy-10:  oklch(0.270 0.060 235);
    --navy-11:  oklch(0.400 0.070 235);
    --navy-12:  oklch(0.200 0.045 235);

    /* Emerald — accent (derived from logo #10b981) */
    --emerald-1:  oklch(0.990 0.010 162);
    --emerald-2:  oklch(0.975 0.020 162);
    --emerald-3:  oklch(0.945 0.045 162);
    --emerald-4:  oklch(0.905 0.070 162);
    --emerald-5:  oklch(0.855 0.095 162);
    --emerald-6:  oklch(0.790 0.115 162);
    --emerald-7:  oklch(0.720 0.130 162);
    --emerald-8:  oklch(0.635 0.145 162);
    --emerald-9:  oklch(0.680 0.145 162);
    --emerald-10: oklch(0.625 0.140 162);
    --emerald-11: oklch(0.495 0.120 162);
    --emerald-12: oklch(0.280 0.070 162);

    /* Red — danger */
    --red-1:   oklch(0.990 0.008 27);
    --red-2:   oklch(0.975 0.015 27);
    --red-3:   oklch(0.945 0.035 27);
    --red-4:   oklch(0.905 0.060 27);
    --red-5:   oklch(0.860 0.090 27);
    --red-6:   oklch(0.800 0.115 27);
    --red-7:   oklch(0.725 0.140 27);
    --red-8:   oklch(0.655 0.175 27);
    --red-9:   oklch(0.575 0.205 27);
    --red-10:  oklch(0.520 0.200 27);
    --red-11:  oklch(0.490 0.185 27);
    --red-12:  oklch(0.270 0.080 27);

    /* Amber — warning */
    --amber-1:   oklch(0.990 0.010 75);
    --amber-2:   oklch(0.980 0.020 75);
    --amber-3:   oklch(0.960 0.040 75);
    --amber-4:   oklch(0.935 0.070 75);
    --amber-5:   oklch(0.895 0.100 75);
    --amber-6:   oklch(0.845 0.130 75);
    --amber-7:   oklch(0.800 0.155 75);
    --amber-8:   oklch(0.760 0.170 75);
    --amber-9:   oklch(0.720 0.175 75);
    --amber-10:  oklch(0.670 0.170 75);
    --amber-11:  oklch(0.495 0.135 75);
    --amber-12:  oklch(0.290 0.085 75);

    /* Blue — info (neutral signal, not brand) */
    --blue-1:   oklch(0.990 0.008 247);
    --blue-2:   oklch(0.975 0.015 247);
    --blue-3:   oklch(0.945 0.035 247);
    --blue-4:   oklch(0.905 0.060 247);
    --blue-5:   oklch(0.860 0.085 247);
    --blue-6:   oklch(0.800 0.110 247);
    --blue-7:   oklch(0.720 0.140 247);
    --blue-8:   oklch(0.625 0.170 247);
    --blue-9:   oklch(0.525 0.200 247);
    --blue-10:  oklch(0.475 0.200 247);
    --blue-11:  oklch(0.450 0.190 247);
    --blue-12:  oklch(0.260 0.090 247);

    /* ======================================================================
       SEMANTIC COLOR TOKENS (theme-aware via light-dark())
       These are the tokens components should prefer.
       ====================================================================== */

    /* Backgrounds — light mode follows the Stripe/GitHub/Plaid pattern:
       canvas (bg) is a tinted neutral around oklch 0.965 (#f1f1f4),
       elevated surfaces are pure white. This produces a ~3-4% luminance
       delta between canvas and elevated surfaces — the minimum needed
       for sidebars, cards and modals to feel "lifted" without shadows
       doing the heavy lifting. Dark mode already had the right hierarchy
       and is left untouched. */
    --color-bg:          light-dark(var(--slate-3), oklch(0.135 0.015 240));
    --color-bg-subtle:   light-dark(var(--slate-4), oklch(0.175 0.018 240));
    --color-bg-elevated: light-dark(#ffffff,        oklch(0.205 0.020 240));
    --color-surface:     light-dark(var(--slate-4), oklch(0.235 0.020 240));
    --color-bg-hover:    light-dark(var(--slate-5), oklch(0.255 0.020 240));
    --color-bg-active:   light-dark(var(--slate-6), oklch(0.285 0.022 240));

    /* A matrix crossing that holds no datum — see components/group-table.css.
       Deliberately a translucent BLACK rather than a grey step: it darkens the
       surface it sits on in either theme, so "nothing here" stays a recess. A
       fixed grey would be a recess in light mode and a raised tile in dark,
       where the eye then reads the empty cells as the filled ones. */
    --color-cell-empty:  light-dark(rgba(15, 23, 42, 0.055), rgba(0, 0, 0, 0.28));

    /* Text — every step bumped up one rank so the hierarchy stays clear
       without any muted/subtle copy becoming hard to read in light mode. */
    --color-text:           light-dark(var(--slate-12), oklch(0.960 0.005 240));
    --color-text-secondary: light-dark(var(--slate-12), oklch(0.880 0.008 240));
    --color-text-muted:     light-dark(var(--slate-11), oklch(0.760 0.012 240));
    --color-text-subtle:    light-dark(var(--slate-10), oklch(0.620 0.015 240));
    --color-text-inverted:  light-dark(#ffffff, var(--slate-12));

    /* Borders (WCAG 2.2 non-text contrast requirements) */
    --color-border-subtle: light-dark(var(--slate-5), oklch(0.275 0.020 240));
    --color-border:        light-dark(var(--slate-6), oklch(0.330 0.022 240));
    --color-border-strong: light-dark(var(--slate-8), oklch(0.450 0.022 240));

    /* Primary (navy from logo — for actions, links, focus)

       DARK MODE INVERTS THE PAIR, and the reason is that one token serves two
       opposite jobs: 31 rules use --color-primary as a BACKGROUND (it must be
       far enough from the text laid on it) and 51 use it as a TEXT colour (it
       must be far enough from the dark canvas). Darkening it to rescue the
       first breaks the second — measured: white on a darkened primary reaches
       5.41:1, but the same token used as text falls to 3.70:1 on --color-bg and
       3.32:1 on --color-bg-elevated, trading one AA failure for two.

       So dark mode goes the other way, as Material 3 / Primer / Radix do:
       primary gets LIGHTER and the contrast colour flips to ink.

       THE LIGHTNESS IS SET BY THE WORST OF THE SEVEN PAIRINGS, not by the two
       that started this. --color-bg-active — the pressed/selected row — is the
       tightest: a `color: var(--color-primary)` link inside one reached 4.31:1
       at oklch(0.640), still under AA, which is why the lightness is 0.660.

       THE CHROMA IS SET BY THE EYE, and it took looking at the page to see it.
       Lightening a colour without raising its chroma desaturates it: at 0.080
       the dark-mode primary rendered a pale steel blue, and on a near-black
       canvas the PRIMARY button read as quieter than the secondary beside it —
       the action hierarchy inverted, every contrast ratio green. 0.120 restores
       it. Chroma barely moves relative luminance, so every figure below holds
       or improves; the ceiling is 0.160, where the toggle knob (white on this
       surface) drops under the 3:1 of WCAG 1.4.11.

       Measured on the rendered page, dark:

           text on primary          5.89 : 1   (was 4.19 — AA failure)
           text on primary:hover    7.39 : 1   (was 3.31 — AA failure)
           white toggle knob on it  3.04 : 1   (1.4.11 asks 3)
           primary AS TEXT on
             --color-bg             6.57 : 1   (was 4.77)
             --color-bg-subtle      6.21 : 1
             --color-bg-elevated    5.89 : 1   (was 4.28 — AA failure)
             --color-surface        5.49 : 1
             --color-bg-hover       5.18 : 1
             --color-bg-active      4.69 : 1   (was 3.39 — AA failure)

       --color-primary-contrast is therefore NOT a constant. Anything painting
       --color-primary as a background must read the token, never spell #fff:
       that hardcode is what hid the failure for as long as it lasted.
       e2e/contrast.spec.ts holds every line above to a test, looping the six
       surfaces — the two-surface version of that spec is what let 4.31 pass. */
    --color-primary:          light-dark(var(--navy-9),  oklch(0.660 0.120 235));
    --color-primary-hover:    light-dark(var(--navy-10), oklch(0.720 0.120 235));
    --color-primary-subtle:   light-dark(var(--navy-3),  oklch(0.265 0.055 235));
    --color-primary-border:   light-dark(var(--navy-7),  oklch(0.400 0.065 235));
    --color-primary-text:     light-dark(var(--navy-11), oklch(0.750 0.075 235));
    --color-primary-contrast: light-dark(#ffffff,        oklch(0.205 0.020 240));

    /* Accent (emerald from logo — for highlights, success, charts) */
    --color-accent:         light-dark(var(--emerald-9),  oklch(0.700 0.145 162));
    --color-accent-hover:   light-dark(var(--emerald-10), oklch(0.745 0.140 162));
    --color-accent-subtle:  light-dark(var(--emerald-3),  oklch(0.265 0.055 162));
    --color-accent-text:    light-dark(var(--emerald-11), oklch(0.720 0.130 162));
    /* Ink in BOTH themes, and not by symmetry with primary: the accent is a
       light emerald in either theme, so white on it measures 2.49:1 — the
       filter-facet count badge and check glyph were painting exactly that.
       Ink gives 7.16 light / 7.19 dark. Without this token those components
       had to borrow --color-primary-contrast, which coupled two accent
       surfaces to a navy value and would have repainted them on any future
       move of the primary. */
    --color-accent-contrast: oklch(0.205 0.020 240);

    /* Brand (navy — used on logos, sidebar, display headings) */
    --color-brand:         light-dark(var(--navy-9), oklch(0.620 0.080 235));
    --color-brand-on-dark: #ffffff;

    /* Semantic fills — step-11 used for light-mode solids so white text
       passes WCAG AA. Dark mode flips to a brighter fill with dark text. */

    /* Success */
    --color-success:          light-dark(var(--emerald-11), oklch(0.700 0.145 162));
    --color-success-hover:    light-dark(var(--emerald-12), oklch(0.745 0.140 162));
    --color-success-subtle:   light-dark(var(--emerald-3),  oklch(0.260 0.055 162));
    --color-success-text:     light-dark(var(--emerald-11), oklch(0.720 0.130 162));
    --color-success-border:   light-dark(var(--emerald-7),  oklch(0.400 0.100 162));
    --color-success-contrast: light-dark(#ffffff, oklch(0.135 0.015 240));

    /* Danger */
    --color-danger:          light-dark(var(--red-10), oklch(0.655 0.195 27));
    --color-danger-hover:    light-dark(var(--red-11), oklch(0.705 0.190 27));
    --color-danger-subtle:   light-dark(var(--red-3),  oklch(0.270 0.070 27));
    --color-danger-text:     light-dark(var(--red-11), oklch(0.745 0.160 27));
    --color-danger-border:   light-dark(var(--red-7),  oklch(0.400 0.140 27));
    --color-danger-contrast: light-dark(#ffffff, oklch(0.135 0.015 240));

    /* Warning */
    --color-warning:          light-dark(var(--amber-11), oklch(0.800 0.160 75));
    --color-warning-hover:    light-dark(var(--amber-12), oklch(0.840 0.155 75));
    --color-warning-subtle:   light-dark(var(--amber-3),  oklch(0.270 0.060 75));
    --color-warning-text:     light-dark(var(--amber-11), oklch(0.780 0.130 75));
    --color-warning-border:   light-dark(var(--amber-7),  oklch(0.400 0.120 75));
    --color-warning-contrast: light-dark(#ffffff, oklch(0.135 0.015 240));

    /* Info */
    --color-info:          light-dark(var(--blue-9),  oklch(0.680 0.180 247));
    --color-info-hover:    light-dark(var(--blue-10), oklch(0.720 0.175 247));
    --color-info-subtle:   light-dark(var(--blue-3),  oklch(0.265 0.070 247));
    --color-info-text:     light-dark(var(--blue-11), oklch(0.760 0.145 247));
    --color-info-border:   light-dark(var(--blue-7),  oklch(0.400 0.130 247));
    --color-info-contrast: #ffffff;

    /* ======================================================================
       INVERSE SURFACE — Material 3 pattern
       ----------------------------------------------------------------------
       Surfaces that must always contrast maximally with the page background,
       regardless of theme. Used by contextual action bars (selection-bar),
       snackbars, tooltips, any "commanding" floating element.

       The polarity is always the *opposite* of the page bg:
         - Light mode: dark pill on light page
         - Dark mode:  light pill on dark page

       Both combinations guarantee ~17:1 (light) and ~11:1 (dark) ratios,
       well above WCAG AAA for normal and large text.

       Semantic helpers (`*-on-inverse`) carry the flipped polarity of the
       page-facing semantic tokens so red/green remain legible on whichever
       surface the component happens to land on.
       ====================================================================== */
    --color-inverse-surface:    light-dark(var(--slate-12), var(--slate-6));
    --color-inverse-on-surface: light-dark(var(--slate-1),  var(--slate-12));

    --color-danger-on-inverse:  light-dark(var(--red-7),     var(--red-11));
    --color-success-on-inverse: light-dark(var(--emerald-7), var(--emerald-11));

    /* ======================================================================
       SHADOWS — restrained by default. Prefer borders over drop shadows.

       light-dark() wraps the COLOR and nothing else. It is a <color> function:
       given a whole shadow value it does not merely misbehave, it makes the
       declaration invalid, so `box-shadow: var(--shadow-xs)` computes to
       `none`. These five tokens carried the whole value for a while and every
       shadow in the framework — 63 declarations, cards, dropdowns, modals,
       popovers — silently painted nothing.

       Two things hid it. Nothing errors: an invalid custom-property
       substitution is dropped at used-value time, so the page renders, just
       flat. And the hex fallback below, which IS valid, lives behind
       `@supports not (color: oklch(0 0 0))` — a modern browser supports oklch,
       skips the fallback, and inherits the broken values. The behaviour was
       inverted: only old browsers saw the shadows.

       build/scripts/check-css-light-dark.sh fails the build if the wrapping
       comes back, and its own test suite pins the multi-line form that the
       first version of that guard did not see.
       ====================================================================== */
    --shadow-xs: 0 1px 1px 0 light-dark(rgb(0 0 0 / 0.03), rgb(0 0 0 / 0.25));
    --shadow-sm: 0 1px 3px 0 light-dark(rgb(0 0 0 / 0.06), rgb(0 0 0 / 0.35));
    --shadow-md: 0 4px 10px -2px light-dark(rgb(0 0 0 / 0.08), rgb(0 0 0 / 0.40));
    --shadow-lg: 0 12px 24px -6px light-dark(rgb(0 0 0 / 0.10), rgb(0 0 0 / 0.50));
    --shadow-xl: 0 24px 48px -12px light-dark(rgb(0 0 0 / 0.12), rgb(0 0 0 / 0.55));

    /* ======================================================================
       OPACITY — de-emphasis scale for non-color visual hierarchy
       ----------------------------------------------------------------------
       Use these tokens whenever opacity < 1 is needed outside animation
       keyframes. Color and contrast are the primary tools for hierarchy;
       opacity is reserved for cases where the same element must remain
       recognisable but visually subdued (disabled state, hover affordance).

       Animation keyframes (skeleton, htmx, capture pulses) may keep
       literal opacity values for performance reasons.
       ====================================================================== */
    --opacity-disabled: 0.25;   /* Non-interactive elements (disabled buttons, inactive markers) */
    --opacity-hint:     0.5;    /* Subtle affordances revealed on hover (drag handles, decorative carets) */

    /* ======================================================================
       FOCUS RING — double-layer, readable on any background (Shadcn pattern)
       ====================================================================== */
    --focus-ring-width:  2px;
    --focus-ring-offset: 2px;
    --focus-ring-color:  var(--color-accent);
    --focus-ring:
        0 0 0 var(--focus-ring-offset) var(--color-bg-elevated),
        0 0 0 calc(var(--focus-ring-offset) + var(--focus-ring-width)) var(--focus-ring-color);

    /* ======================================================================
       TOUR / GUIDED EXPERIENCE — backdrop, spotlight halo, popover
       Sits between --z-select (1000) and --z-drawer (1100): drawers, modals,
       toasts, capture and loading overlays all stay above an open tour.
       ====================================================================== */
    --tour-backdrop:           light-dark(rgb(15 23 42 / 0.42), rgb(0 0 0 / 0.62));
    --tour-spotlight-padding:  6px;
    --tour-spotlight-radius:   calc(var(--radius-md) + 2px);
    --tour-halo-color:         var(--color-accent);
    --tour-popover-width:      clamp(280px, 30ch, 360px);

    /* ======================================================================
       SIDEBAR — theme-aware, accent bar on active item (signature element)
       ====================================================================== */
    --sidebar-width:       0px;                         /* mobile: hidden */
    --sidebar-bg:          var(--color-bg-elevated);
    --sidebar-border:      var(--color-border-subtle);
    /* Inactive items use the muted rank — the active item then visibly
       outranks them via colour + weight + accent bar, instead of relying
       on the accent bar alone. */
    --sidebar-text:        var(--color-text-muted);
    --sidebar-text-hover:  var(--color-text);
    --sidebar-text-active: var(--color-text);
    --sidebar-hover:       var(--color-bg-subtle);
    --sidebar-active:      var(--color-accent-subtle);
    --sidebar-accent:      var(--color-accent);

    /* ======================================================================
       DATA VISUALISATION — categorical series palette
       ======================================================================

       Eight slots for charts that encode IDENTITY (one colour per series).
       See DESIGN_SYSTEM.md § Data visualisation for the rules; the short
       version, because getting these wrong is invisible until someone
       cannot read the chart:

         - assign slots in order, 1..N, consecutively. The palette is
           validated on ADJACENT pairs (1↔2, 2↔3, …); with arbitrary
           adjacency it fails hard — worst pair ΔE 3.2 light / 1.6 dark for
           protanopia, and 7.1 in both modes for normal vision;
         - colour follows the entity, never its rank;
         - a 9th series is never a 9th hue: fold into "other", which takes
           --chart-series-other (a neutral, deliberately outside the eight);
         - status colours are reserved and never double as a series.

       Both modes are SELECTED, not flipped: the dark column is the same
       eight hues re-stepped for the dark surface. Measured against this
       framework's own chart surface (--color-bg-elevated: #ffffff light,
       #1a2436 dark). Dark passes every gate; light passes all but a contrast
       WARN on slots 3, 4 and 5 (2.82 / 2.17 / 2.69 against white), which is
       why a categorical chart in light mode must carry a non-colour channel
       — a legend with direct labels, or a table view. Re-stepping those
       three was tried and is strictly worse (it breaks CVD separation).

       Re-run the validator on any change; do not hand-pick a hex. */
    --chart-series-1: light-dark(#2a78d6, #3987e5); /* blue    */
    --chart-series-2: light-dark(#eb6834, #d95926); /* orange  */
    --chart-series-3: light-dark(#1baf7a, #199e70); /* aqua    */
    --chart-series-4: light-dark(#eda100, #c98500); /* yellow  */
    --chart-series-5: light-dark(#e87ba4, #d55181); /* magenta */
    --chart-series-6: light-dark(#008300, #008300); /* green   */
    --chart-series-7: light-dark(#4a3aa7, #9085e9); /* violet  */
    --chart-series-8: light-dark(#e34948, #e66767); /* red     */

    /* "Other" / remainder. Neutral by design, and stacked at the END that
       neighbours slot 1 — measured: next to slot 8 it collapses to ΔE 5.9
       (protan, dark), and a mid grey next to slot 1 to 14.2 (normal vision,
       dark). These two values clear both. */
    --chart-series-other: light-dark(#8a8f98, #a8b0bb);

    /* ======================================================================
       BACKWARDS COMPATIBILITY — keep legacy token names used across modules.
       Prefer the new names; these aliases remain until migration completes.
       ====================================================================== */
    --transition-fast:     var(--duration-fast) var(--ease-standard);
    --transition-normal:   var(--duration-normal) var(--ease-standard);
    --ease-out:            var(--ease-decelerate);
    --ease-in-out:         var(--ease-standard);
    --font-size-base:      16px;
    --font-family:         var(--font-sans);
    --color-primary-rgb:   23 57 84;
    --color-primary-light: var(--color-primary-subtle);
    --color-danger-light:  var(--color-danger-subtle);
    --color-danger-dark:   var(--color-danger-text);
    --color-success-light: var(--color-success-subtle);
    --color-success-dark:  var(--color-success-text);
    --color-warning-light: var(--color-warning-subtle);
    --color-warning-dark:  var(--color-warning-text);
    --color-bg-muted:      var(--color-bg-active);
    --color-border-light:  var(--color-border-subtle);
}

/* ==========================================================================
   Theme forcing
   ========================================================================== */
[data-theme="dark"]  { color-scheme: dark; }
[data-theme="light"] { color-scheme: light; }

/* ==========================================================================
   Fallback for browsers without OKLCH + light-dark() support
   (~5% of traffic in 2026 — mostly old WebViews).
   ========================================================================== */
@supports not (color: oklch(0 0 0)) {
    :root {
        /* Slate */
        --slate-1:  #fcfcfd;
        --slate-2:  #f9f9fb;
        --slate-3:  #f1f1f4;
        --slate-4:  #e8e8ec;
        --slate-5:  #dfe0e5;
        --slate-6:  #d3d4dc;
        --slate-7:  #c2c4cd;
        --slate-8:  #a4a6b3;
        --slate-9:  #6b6e7d;
        --slate-10: #616473;
        --slate-11: #4d505d;
        --slate-12: #1e1f24;

        /* Navy (logo-derived) */
        --navy-1:   #fbfcfe;
        --navy-2:   #f5f8fc;
        --navy-3:   #e6edf6;
        --navy-4:   #d0dcee;
        --navy-5:   #b5c7e1;
        --navy-6:   #92afd2;
        --navy-7:   #6791bf;
        --navy-8:   #3f73a8;
        --navy-9:   #173954;
        --navy-10:  #102a40;
        --navy-11:  #2f5b80;
        --navy-12:  #0a1c2b;

        /* Emerald (logo-derived) */
        --emerald-1:  #fafefc;
        --emerald-2:  #f1fbf6;
        --emerald-3:  #d7f5e6;
        --emerald-4:  #b3ecd0;
        --emerald-5:  #86dcb3;
        --emerald-6:  #56c896;
        --emerald-7:  #2cb278;
        --emerald-8:  #159862;
        --emerald-9:  #10b981;
        --emerald-10: #059669;
        --emerald-11: #047857;
        --emerald-12: #064e3b;

        /* Red */
        --red-3:  #fee2e2;
        --red-7:  #fca5a5;
        --red-9:  #dc2626;
        --red-10: #b91c1c;
        --red-11: #991b1b;

        /* Amber */
        --amber-3:  #fef3c7;
        --amber-7:  #fcd34d;
        --amber-9:  #d97706;
        --amber-10: #b45309;
        --amber-11: #92400e;
        --amber-12: #451a03;

        /* Blue */
        --blue-3:  #dbeafe;
        --blue-7:  #93c5fd;
        --blue-9:  #2563eb;
        --blue-10: #1d4ed8;
        --blue-11: #1e40af;

        /* Light semantic defaults — tinted canvas, white elevated surfaces */
        --color-bg:          #f1f1f4;
        --color-bg-subtle:   #e8e8ec;
        --color-bg-elevated: #ffffff;
        --color-surface:     #e8e8ec;
        --color-bg-hover:    #dfe0e5;
        --color-bg-active:   #d3d4dc;

        --color-text:           #0f172a;
        --color-text-secondary: #1e293b;
        --color-text-muted:     #475569;
        --color-text-subtle:    #64748b;
        --color-text-inverted:  #ffffff;

        --color-border-subtle: #e2e8f0;
        --color-border:        #cbd5e1;
        --color-border-strong: #94a3b8;

        --color-primary:          #173954;
        --color-primary-hover:    #0f2940;
        --color-primary-subtle:   #e7edf4;
        --color-primary-border:   #6791bf;
        --color-primary-text:     #2f5b80;
        --color-primary-contrast: #ffffff;

        --color-accent:        #10b981;
        --color-accent-hover:  #059669;
        --color-accent-subtle: #d1fae5;
        --color-accent-text:   #047857;
        /* Ink in both themes — see the modern block. The dark override below
           inherits this rather than restating it. */
        --color-accent-contrast: #0f172a;

        --color-brand:         #173954;
        --color-brand-on-dark: #ffffff;

        /* Solid success uses step-11 (#047857) for WCAG AA with white text */
        --color-success:          #047857;
        --color-success-hover:    #064e3b;
        --color-success-subtle:   #d1fae5;
        --color-success-text:     #047857;
        --color-success-border:   #6ee7b7;
        --color-success-contrast: #ffffff;

        /* Solid danger uses step-10 for safer AA margin than step-9 */
        --color-danger:          #b91c1c;
        --color-danger-hover:    #991b1b;
        --color-danger-subtle:   #fee2e2;
        --color-danger-text:     #991b1b;
        --color-danger-border:   #fca5a5;
        --color-danger-contrast: #ffffff;

        /* Solid warning uses step-11 (#92400e) for WCAG AA with white text */
        --color-warning:          #92400e;
        --color-warning-hover:    #451a03;
        --color-warning-subtle:   #fef3c7;
        --color-warning-text:     #92400e;
        --color-warning-border:   #fcd34d;
        --color-warning-contrast: #ffffff;

        --color-info:          #2563eb;
        --color-info-hover:    #1d4ed8;
        --color-info-subtle:   #dbeafe;
        --color-info-text:     #1e40af;
        --color-info-border:   #93c5fd;
        --color-info-contrast: #ffffff;

        /* Inverse surface — light-mode fallback (dark pill). */
        --color-inverse-surface:    #1e1f24;
        --color-inverse-on-surface: #fcfcfd;
        --color-danger-on-inverse:  #fca5a5;
        --color-success-on-inverse: #6ee7b7;

        --shadow-xs: 0 1px 1px 0 rgb(0 0 0 / 0.03);
        --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.06);
        --shadow-md: 0 4px 10px -2px rgb(0 0 0 / 0.08);
        --shadow-lg: 0 12px 24px -6px rgb(0 0 0 / 0.10);
        --shadow-xl: 0 24px 48px -12px rgb(0 0 0 / 0.12);

        /* Categorical series — light steps (see :root for the rules). */
        --chart-series-1: #2a78d6;
        --chart-series-2: #eb6834;
        --chart-series-3: #1baf7a;
        --chart-series-4: #eda100;
        --chart-series-5: #e87ba4;
        --chart-series-6: #008300;
        --chart-series-7: #4a3aa7;
        --chart-series-8: #e34948;
        --chart-series-other: #8a8f98;
    }

    [data-theme="dark"] {
        --color-bg:          #0b1220;
        --color-bg-subtle:   #131c2b;
        --color-bg-elevated: #1a2436;
        --color-surface:     #1e293b;
        --color-bg-hover:    #1e293b;
        --color-bg-active:   #253349;

        --color-text:           #f1f5f9;
        --color-text-secondary: #cbd5e1;
        --color-text-muted:     #94a3b8;
        --color-text-subtle:    #64748b;
        --color-text-inverted:  #0f172a;

        --color-border-subtle: #253349;
        --color-border:        #334155;
        --color-border-strong: #64748b;

        /* Mirrors the modern path above — lighter primary, ink on top. The old
           pair failed the same way the oklch one did: white on #5a8bbe was
           3.58:1. A fallback nobody measures is where a fixed defect comes
           back — and "mirrors" has to mean the NUMBERS, not the intent: the
           first attempt at this block used #5994b6, which reads 4.41:1 as text
           on --color-surface (#1e293b) and 3.84 on #253349, both under AA,
           while the modern path cleared them. #66a3c6 restores the mirror
           (5.31 and 4.62, against 5.44 and 4.65).

           IT MIRRORS THE RATIOS, NOT THE HUE. The modern primary went to
           chroma 0.120 for the reason written above; the same move here drops
           the white toggle knob to 2.73:1 against this block's older, lighter
           surface ramp, under the 3:1 that knob needs. So the fallback stays a
           muted steel blue: on a browser without oklch(), correctness is the
           job and identity is not.

           NO PLAYWRIGHT TEST REACHES HERE — contrast.spec.ts runs in a Chromium
           that supports light-dark(), so this block never applies to it. The
           Go test web/static/tokens_fallback_contrast_test.go does reach it,
           arithmetically, and holds both the AA floors and the distance to the
           modern ratios. */
        --color-primary:          #66a3c6;
        --color-primary-hover:    #7ab3d2;
        --color-primary-subtle:   #1a2d45;
        --color-primary-border:   #3f73a8;
        --color-primary-text:     #92afd2;
        /* #0f172a, the ink every other -contrast token in this block uses —
           not a one-off near-black. 6.48:1 on the primary above. */
        --color-primary-contrast: #0f172a;
        --color-accent-contrast:  #0f172a;

        --color-accent:        #10b981;
        --color-accent-hover:  #34d399;
        --color-accent-subtle: #0a3d2b;
        --color-accent-text:   #6ee7b7;

        --color-brand:         #3f73a8;

        /* In dark mode semantic fills are lighter; contrast flips to dark text */
        --color-success:          #10b981;
        --color-success-hover:    #34d399;
        --color-success-subtle:   #0a3d2b;
        --color-success-text:     #6ee7b7;
        --color-success-border:   #065f46;
        --color-success-contrast: #0f172a;

        --color-danger:          #f87171;
        --color-danger-hover:    #fca5a5;
        --color-danger-subtle:   #3f1212;
        --color-danger-text:     #fca5a5;
        --color-danger-border:   #7f1d1d;
        --color-danger-contrast: #0f172a;

        --color-warning:          #fbbf24;
        --color-warning-hover:    #fcd34d;
        --color-warning-subtle:   #3b2605;
        --color-warning-text:     #fcd34d;
        --color-warning-border:   #78350f;
        --color-warning-contrast: #0f172a;

        --color-info:        #60a5fa;
        --color-info-hover:  #93c5fd;
        --color-info-subtle: #0f1e3d;
        --color-info-text:   #93c5fd;
        --color-info-border: #1e40af;

        /* Inverse surface — dark-mode fallback (light pill on dark page). */
        --color-inverse-surface:    #d3d4dc;
        --color-inverse-on-surface: #1e1f24;
        --color-danger-on-inverse:  #991b1b;
        --color-success-on-inverse: #047857;

        --shadow-xs: 0 1px 1px 0 rgb(0 0 0 / 0.25);
        --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.35);
        --shadow-md: 0 4px 10px -2px rgb(0 0 0 / 0.40);
        --shadow-lg: 0 12px 24px -6px rgb(0 0 0 / 0.50);
        --shadow-xl: 0 24px 48px -12px rgb(0 0 0 / 0.55);

        /* Categorical series — dark steps. Same eight hues re-stepped for
           the dark surface, NOT an automatic flip of the light column. */
        --chart-series-1: #3987e5;
        --chart-series-2: #d95926;
        --chart-series-3: #199e70;
        --chart-series-4: #c98500;
        --chart-series-5: #d55181;
        --chart-series-6: #008300;
        --chart-series-7: #9085e9;
        --chart-series-8: #e66767;
        --chart-series-other: #a8b0bb;
    }
}
