/* Cyber Academy — design tokens.
 *
 * The values are the visual contract's (`notes/design-rulebook.md`, surfaces, shape, colour semantics and
 * typography); this file transcribes them and decides none. Every contrast ratio in a comment was computed (WCAG 2.x
 * relative luminance over the exact hex pair), not estimated.
 *
 * TWO MODES OF ONE SYSTEM. The mode is chosen by `data-mode` on a shell root: `operator` (dark, the superadmin
 * outside a customer), `customer` (light, branded, the customer area for every role) and `neutral` (light, unbranded:
 * pre-authentication and the unassigned-administrator landing). Everything that does not differ between modes —
 * type, spacing, radius, controls, motion, layers, focus — is declared once on `:root`.
 *
 * A MODE TOKEN IS RESOLVED WHERE `data-mode` IS DECLARED. `--accent: var(--brand-primary, …)` is computed on the
 * element carrying `data-mode="customer"`, so the brand properties (`client.ui.branding/branding-style`) must be set
 * on that same element or above it — set on a descendant, they would change nothing.
 */

:root {
/* boit-palette:begin — generated by bb ops/brand-palette.clj */
--boit-primary: #14171C; --boit-secondary: #51610D; --boit-lime: #D3FD22;
/* boit-palette:end */

  /* Type families */
  --font-sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;

  /* Type scale: size / line-height (the roles below compose them with a weight and a family) */
  --text-12: 12px;  --lh-12: 16px;   /* caption: table headers, tags, legends, axes */
  --text-13: 13px;  --lh-13: 18px;   /* label + small: field labels, meta, help, secondary cell line */
  --text-14: 14px;  --lh-14: 20px;   /* body, body strong, name: default UI text, cells, inputs (fine pointer) */
  --text-16: 16px;  --lh-16: 24px;   /* body-lg + title-3 */
  --text-18: 18px;  --lh-18: 26px;   /* title-2 */
  --text-20: 20px;  --lh-20: 28px;   /* title-1 on a phone; the reading subhead */
  --text-24: 24px;  --lh-24: 32px;   /* title-1 (page title); figure on a phone */
  --text-28: 28px;  --lh-28: 36px;   /* figure (stat tile) */

  /* Weights */
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;

  /* Type roles: one `font` shorthand per UI role of `notes/design-rulebook.md` §7, so a site names its role instead of
   * restating it. A shorthand resets `font-variant-*` and `font-feature-settings`, so a site that needs tabular
   * figures declares `font-variant-numeric: tabular-nums` after it; letter-spacing lies outside `font`, so a caption
   * also sets `letter-spacing: var(--track-caption)`. These resolve on `:root`: a step (the phone, below) redefines
   * the role token itself, because redefining `--text-*` alone would not reach an already-resolved shorthand. */
  --type-figure:      var(--weight-semibold) var(--text-28) / var(--lh-28) var(--font-sans);
  --type-title-1:     var(--weight-semibold) var(--text-24) / var(--lh-24) var(--font-sans);
  --type-title-2:     var(--weight-semibold) var(--text-18) / var(--lh-18) var(--font-sans);
  --type-title-3:     var(--weight-semibold) var(--text-16) / var(--lh-16) var(--font-sans);
  --type-body-lg:     var(--weight-regular) var(--text-16) / var(--lh-16) var(--font-sans);
  --type-body:        var(--weight-regular) var(--text-14) / var(--lh-14) var(--font-sans);
  --type-body-strong: var(--weight-medium) var(--text-14) / var(--lh-14) var(--font-sans);
  --type-name:        var(--weight-semibold) var(--text-14) / var(--lh-14) var(--font-sans);
  --type-label:       var(--weight-medium) var(--text-13) / var(--lh-13) var(--font-sans);
  --type-small:       var(--weight-regular) var(--text-13) / var(--lh-13) var(--font-sans);
  --type-caption:     var(--weight-medium) var(--text-12) / var(--lh-12) var(--font-sans);
  --type-mono:        var(--weight-regular) var(--text-14) / var(--lh-14) var(--font-mono);
  --track-caption: 0.01em;

  /* Spacing (4 px base) */
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px; --space-5: 20px;
  --space-6: 24px; --space-8: 32px; --space-10: 40px; --space-12: 48px; --space-16: 64px;

  /* Page gutters and widths */
  --gutter: 16px;                 /* phone; overridden at 640 / 1024 */
  --content-max: 1280px;          /* dashboards, tables */
  --form-max: 720px;              /* forms, Settings, Profile */
  --reading-max: 680px;           /* long text */
  --field-max: 400px;             /* single text field width inside a form */

  /* Page rhythm (rulebook §3, spacing): one gap between the cards and blocks of a page, and between the cards of a
   * grid; one padding for a content card. Both step down with the gutter on a phone. A control card (the filter
   * card, the Reports control card) keeps its own compact padding; tiles keep theirs (rulebook §9). */
  --card-gap: var(--space-6);
  --card-pad: var(--space-6);

  /* Surface-category radii, shared directly by administration and learner documents. */
  --radius-xs: 4px;    /* tags, checkbox, progress bars, chart bar tops */
  --radius-sm: 6px;    /* buttons, inputs, selects, segmented thumb, course label, icon button */
  --radius-md: 8px;    /* logo/monogram tiles, segmented track, notices, drop zone, menu items */
  --radius-lg: 12px;   /* cards, stat tiles, menus, popovers, dialogs, pre-auth card */
  --radius-xl: 16px;   /* the shell's content card floating over the sidebar's chrome */
  --radius-full: 9999px; /* named round exceptions: pace badge, radio, switch */

  /* Level-neutral editorial tints; strengths describe meaning, never height. */
  --tint-neutral: 4%; --tint-soft: 8%; --tint-strong: 14%;

  /* Controls */
  --control-h: 36px;
  --control-h-sm: 32px;
  --control-h-lg: 40px;           /* pre-auth forms on fine pointers */
  --row-h: 44px;
  --row-h-2line: 52px;
  --icon-button: 32px;

  /* Motion — durations. Only `transform`, `opacity`, `background-color`, `color` and `box-shadow` animate, plus the
   * two sanctioned geometry changes (the sidebar width and the inline-create rows), so no state shifts layout. */
  --dur-instant: 60ms;            /* press in */
  --dur-fast: 120ms;              /* hover, focus, colour, press release */
  --dur-base: 200ms;              /* overlay enter, fades, label fades, segmented thumb */
  --dur-exit: 150ms;              /* overlay and notice exit: leaving is quicker than arriving */
  --dur-slow: 300ms;              /* sidebar width and logo↔icon morph, drawer, inline-create height */
  --dur-feedback: 2000ms;         /* the just-created highlight fading out */
  --dur-pulse: 1200ms;            /* one skeleton pulse */
  --dur-spin: 800ms;              /* one busy-spinner turn */
  /* Motion — delays */
  --delay-tooltip: 500ms;         /* a hover pause before a tooltip; keyboard focus shows it at once */
  --delay-skeleton: 300ms;        /* a load shorter than this never flashes a skeleton */
  --delay-label-in: 100ms;        /* expanded labels fade in once the width has made room */
  /* Motion — easings */
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);   /* in-place changes */
  --ease-out: cubic-bezier(0, 0, 0.2, 1);        /* enter and expand; the reference sidebar's ease-out, one-to-one */
  --ease-in: cubic-bezier(0.4, 0, 1, 1);         /* exit */
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);   /* a cross-fade between two states, even enough to be seen */
  --ease-linear: linear;                          /* spin and pulse */
  /* Motion — distance, scale, sequencing */
  --move-xs: 2px;
  --move-sm: 4px;                 /* an overlay travels this far toward its anchor as it enters */
  --move-md: 8px;                 /* content rising in on load */
  --scale-enter: 0.98;            /* an overlay or dialog grows from this to 1 */
  --scale-icon: 0.6;              /* the logo↔icon morph */
  --stagger: 30ms;                /* tiles and cards on content load only, at most 4 steps; never rows or menu items */

  /* Z-index */
  --z-sticky: 10;        /* sticky table header, sticky toolbar */
  --z-sidebar: 20;
  --z-topbar: 30;
  --z-backdrop: 40;      /* phone drawer backdrop */
  --z-drawer: 50;
  --z-overlay: 60;       /* everything portaled into the overlay root, stacked by open order */
  --z-tooltip: 100;

  /* Focus — the keyboard focus treatment is a lift, a surface shift, a restrained glow and the focus dash; never a
   * ring, an outline or a border (`notes/design-rulebook.md`, components). The dash is the measured 3:1 cue: a
   * detached 2 px pill, never as long as a side of the control. */
  --focus-dash-h: 2px;
  --focus-dash-w: 16px;
  --focus-dash-w-sm: 12px;          /* icon-only controls and checkboxes */
  --focus-dash-gap: 3px;            /* between a checkbox and the dash under it */

  /* Console scrollbar: an 8 px gutter; the thumb is 4 px at rest and 6 px on hover. Colours are per mode. */
  --scrollbar-size: 8px;
  --header-axis: 36px;  /* the sidebar header's centre line (8 px inset + half its 56 px row); every floating header control centres on it */

  /* Count badge */
  --badge-h: 20px;

  /* The operator console's own colours, named once. The operator mode reads them as its surface, pressed fill, ink
   * and accent; the console action on a customer's light sidebar reads them directly, because a nested
   * `data-mode="operator"` would repaint the document's ground (`notes/design-rulebook.md` §4). */
  --console-surface: #171B22;
  --console-surface-hover: #272D37;  /* the console's pressed and selected fill */
  --console-ink: #E8EBF0;            /* 14.45:1 on the console surface */
  --console-accent: var(--boit-lime);         /* BOIT lime: 14.67:1 on the console surface */

  /* The light ground a logo, a QR code and print stand on in every mode: near-white, never pure white (backlog item
   * 5). A logo is drawn for a light ground, so the dark mode keeps it too. */
  --logo-ground: #FEFEFE;

  /* Chart (mode-independent parts) */
  --chart-series-2: #D55181;      /* validated with series-1 in both modes */
}

@media (min-width: 640px)  { :root { --gutter: 24px; } }
@media (max-width: 639px)  { :root { --card-gap: var(--space-4); --card-pad: var(--space-4);
                                     /* the phone steps of §7: title 1 20/28, figure 24/32 */
                                     --type-title-1: var(--weight-semibold) var(--text-20) / var(--lh-20) var(--font-sans);
                                     --type-figure: var(--weight-semibold) var(--text-24) / var(--lh-24) var(--font-sans); } }
@media (min-width: 1024px) { :root { --gutter: 32px; } }
@media (pointer: coarse)   { :root { --control-h: 44px; --control-h-sm: 40px; --control-h-lg: 44px;
                                     --icon-button: 44px; } }
/* Under reduced motion every duration and delay is zero; the state changes still happen. The stagger goes too, so no
 * content waits for a sequence nobody will see. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 0ms; --dur-fast: 0ms; --dur-base: 0ms; --dur-exit: 0ms; --dur-slow: 0ms;
    --dur-feedback: 0ms; --dur-pulse: 0ms; --dur-spin: 0ms;
    --delay-tooltip: 0ms; --delay-skeleton: 0ms; --delay-label-in: 0ms;
    --stagger: 0ms; --move-xs: 0px; --move-sm: 0px; --move-md: 0px; --scale-enter: 1; --scale-icon: 1;
  }
}

/* == Operator mode (dark) == */
[data-mode="operator"] {
  color-scheme: dark;
  --bg: #101319;            /* level 1: perceptually separated from the sidebar's ground */
  --surface: var(--console-surface);        /* #171B22: cards, tables, the sidebar */
  --surface-2: #1E232B;     /* hover row, input fill, segmented track, skeleton */
  --surface-3: var(--console-surface-hover); /* #272D37: pressed, selected segmented thumb */
  --chrome: #08090B;        /* the sidebar's ground, one step below the content card's bg */
  --chrome-hover: var(--surface); /* an item's hover fill on the chrome */

  --text-1: var(--console-ink); /* #E8EBF0: 15.56:1 on bg, 14.45:1 on surface */
  --text-hover: #F6F7F9;    /* text-only controls: colour only, never a hover underline; a step beyond text-1,
                             never pure white (backlog item 5): 16.92:1 on surface */
  --text-2: #AEB5C2;        /* 8.38:1 on surface, 7.66:1 on surface-2 */
  --text-3: #969FAE;        /* 6.97:1 on bg, 6.47:1 on surface, 4.55:1 on modal hover */
  --text-disabled: #5E6776; /* 2.76:1 on surface-2 — disabled only (WCAG-exempt) */

  --accent: var(--console-accent); /* #D3FD22, BOIT lime: 15.80:1 on bg, 14.67:1 on surface */
  --accent-ink: #0C0E12;    /* 16.41:1 on lime */
  --accent-hover: #C2EC12;  /* ink 14.07:1 */
  --accent-pressed: color-mix(in srgb, var(--accent) 80%, #000000);
  --accent-tint: color-mix(in srgb, var(--accent) 10%, var(--surface)); /* selected nav bg ≈ #2A3222 */
  --focus-color: var(--accent);
  --focused-label-ink: var(--focus-color);
  --link: var(--text-1);    /* underlined; no cyan */

  /* A destructive act is a clearly red button with light text in both modes (backlog item 6): the light mode's red,
   * brightening on hover as a dark-mode control does. Ink 5.65:1 on the fill, 4.95:1 on hover; the fill stands at
   * 3.03:1 against the card it sits on. */
  --destructive: #C4291D;
  --destructive-ink: #FEFEFE;
  --destructive-hover: #D0342A;
  --destructive-pressed: color-mix(in srgb, var(--destructive) 85%, #000000);
  --destructive-fg: #FF8A82; /* destructive text on surface 7.57:1 */

  /* Elevation ladder (dark): black shadows, dx 0, blur larger than offset, no spread, no ring. On a dark ground the
   * surface also carries height: an overlay and a modal are a step lighter than a card. */
  --elev-1: 0 1px 2px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.25);
  --elev-2: 0 2px 4px rgba(0, 0, 0, 0.50), 0 6px 18px rgba(0, 0, 0, 0.35);
  --elev-3: 0 6px 12px rgba(0, 0, 0, 0.50), 0 16px 40px rgba(0, 0, 0, 0.50);
  --elev-4: 0 10px 20px rgba(0, 0, 0, 0.55), 0 28px 72px rgba(0, 0, 0, 0.60);
  --elev-1-fill: var(--elev-1);   /* a filled button's own shadow; black on a dark ground */
  --elev-2-fill: var(--elev-2);
  --elev-1-destructive: var(--elev-1);
  --elev-2-destructive: var(--elev-2);
  --surface-overlay: #1F242D;       /* menus, popovers, tooltips, the bulk bar */
  --surface-modal: #252B36;         /* dialogs */
  --surface-overlay-hover: #2B313B; /* hover and focus inside an overlay: 1.19:1 on it */
  --surface-modal-hover: #303641;   /* hover and focus inside a dialog: 1.17:1 on it */
  /* The bulk bar: the overlay rung, already apart from a card in the dark ladder. */
  --surface-bar: var(--surface-overlay);
  --surface-bar-hover: var(--surface-overlay-hover);
  --control-on-bar: var(--control-on-overlay);
  --control-pressed-on-bar: var(--control-pressed-on-overlay);

  /* Surface shift (dark): state changes a fill, never a stroke. Rest, hover and pressed are measured apart. */
  --surface-hover: #1E232B;         /* 1.09:1 on surface */
  --surface-pressed: #272D37;       /* 1.25:1 on surface, 1.14:1 on surface-hover */
  --control-fill: var(--surface);   /* a raised control at rest: level 1, as a card is */
  --control-fill-hover: var(--surface); /* hover and focus lift it to level 2; the fill stays */
  --control-fill-pressed: #20252D;  /* 1.12:1 on rest, 1.03:1 on hover */
  --badge-fill: #272D37;            /* count badge; text-2 on it 6.72:1 */
  /* A raised control on a holder above the page ground stands one rung higher than its holder, so it is never the
   * holder's own colour (backlog item 5): a card's on the overlay rung (1.11:1 against the card), an overlay's on the
   * modal rung (1.10:1), a dialog's on the dialog's hover fill (1.17:1). Pressed falls back below its rest. The holders
   * declare which pair they take (components.css, raised controls). */
  --control-on-card: var(--surface-overlay);
  --control-pressed-on-card: var(--surface-hover);
  --control-on-overlay: var(--surface-modal);
  --control-pressed-on-overlay: var(--surface-overlay);
  --control-on-modal: var(--surface-modal-hover);
  --control-pressed-on-modal: var(--surface-modal);

  /* Holders (dark). `--holder` is the fill of the nearest surface and `--holder-below` the surface one elevation
   * beneath it; every surface that holds fields declares both (components.css, layout.css). Beneath the page ground
   * lies the sidebar's ground, the chrome, so a field on the page ground recedes toward it like any other (backlog
   * item 5: a control is never its parent's own colour). Inputs are RECESSED into their holder (components.css, the
   * input rule). */
  --holder: var(--bg);
  --holder-below: var(--chrome);
  --overlay-below: var(--surface);  /* an overlay's fields recede to the card level */
  --modal-below: var(--surface-overlay);
  --hover-region-below: var(--surface);
  /* The recess, lit from above (operator 2026-10-18): an inset shadow only — never an external shadow, a border, a
   * ring or a highlight line. The upper rim shades the floor: a crisp short shadow under the top edge, and a soft
   * falloff that fades down the floor, so the well reads moulded rather than cut. The floor itself sits one full step
   * below its holder (components.css); the inset carries hover and focus. The focus inset is J1 turned inward — the
   * same near layer as `--elev-1` — so a focused field never reads deeper than a card stands high. */
  --inset-rest: inset 0 1px 1px rgba(0, 0, 0, 0.32), inset 0 4px 6px -3px rgba(0, 0, 0, 0.28);
  --inset-hover: inset 0 1px 1px rgba(0, 0, 0, 0.38), inset 0 5px 7px -3px rgba(0, 0, 0, 0.34);
  --inset-focus: inset 0 1px 2px rgba(0, 0, 0, 0.45), inset 0 6px 8px -3px rgba(0, 0, 0, 0.40);
  --inset-disabled: inset 0 1px 1px rgba(0, 0, 0, 0.18);
  /* Check wells: a checkbox or radio keeps the filled well, ≥ 3:1 against its holder (components.css). */
  --well-toward: #FEFEFE;
  --well-mix: 64%;
  --well-mix-hover: 63%;
  --well-mix-disabled: 88%;

  /* Focus (dark) */
  --focus-glow: 0 0 14px color-mix(in srgb, var(--focus-color) 20%, transparent);
  --focus-tint: color-mix(in srgb, var(--focus-color) 14%, transparent);

  --backdrop: rgba(0, 0, 0, 0.56);

  --chart-series-1: #3987E5;
  --chart-neutral: #6B7382;
  --chart-grid: #262B34;            /* data ink, not framing: gridlines stay (`notes/design-rulebook.md`, charts) */
  --chart-baseline: #363D49;
  --chart-axis: var(--text-3);
}

/* == Light defaults and customer mode ==
 * Standalone learner/native documents inherit these defaults on :root. A mode root rebinds the roles on its
 * own element so valid customer properties resolve there. Operator and neutral overrides stay explicit. */
:root, [data-mode="customer"], [data-mode="neutral"] {
  color-scheme: light;
  --bg: #F6F7F9;
  /* Never pure white (backlog item 5, decided 2026-10-17): shared.brand.contrast judges every brand colour on this
   * value, contrast recommendations use this surface; valid configured colours remain authoritative (ADR-0071). */
  --surface: #FEFEFE;
  --surface-2: #F0F2F5;
  --surface-3: #E6E9EE;
  --chrome: var(--surface-2); /* the sidebar's ground, one step below the content card's bg */
  --chrome-hover: var(--surface-3); /* an item's hover fill on the chrome */

  --text-1: #14171C;        /* 17.96:1 on surface, 16.76:1 on bg */
  --text-hover: #0C0E12;    /* a small final step beyond text-1, never pure black (backlog item 5); mirrored in
                             employee.css: 19.15:1 on surface */
  --text-2: #4A5363;        /* 7.75:1 on surface, 6.91:1 on surface-2 */
  --text-3: #626B7A;        /* 5.38:1 on surface, 5.02:1 on bg, 4.80:1 on surface-2 */
  --text-disabled: #9AA1AD; /* 2.32:1 on surface-2 — disabled only */

  /* Brand-driven roles: set from --brand-* (client.ui.branding/branding-style), with the unbranded default. The pure
   * black and white below are mixing endpoints, never painted: the hover, pressed and tint derivations are the shared
   * contrast model's own arithmetic (shared.brand.contrast/derived), which judges every brand colour through them. */
  --accent: var(--brand-primary, var(--boit-primary));          /* Boit charcoal default; shared.brand.palette owns the value */
  --accent-ink: var(--brand-primary-ink, #FEFEFE);
  --accent-hover: color-mix(in srgb, var(--accent) 88%, #000000);
  --accent-pressed: color-mix(in srgb, var(--accent) 80%, #000000);
  --accent-tint: color-mix(in srgb, var(--accent) 10%, #FFFFFF);
  --focus-color: var(--accent);                      /* ≥ 4.5:1 on white by validation ⇒ ≥ 3:1 ring */
  --focused-label-ink: color-mix(in srgb, var(--accent) 85%, #000);
  --link: var(--brand-secondary, var(--boit-secondary));

  --destructive: #C4291D;   /* white ink 5.70:1 */
  --destructive-ink: #FEFEFE;   /* 5.65:1 */
  --destructive-hover: #A8221A; /* 7.16:1 */
  --destructive-pressed: color-mix(in srgb, var(--destructive) 85%, #000000);
  --destructive-fg: #A3201A;    /* destructive text on surface 7.56:1 */

  /* Elevation ladder (light): shadows tinted rgb(16, 24, 40), dx 0, blur larger than offset, no spread, no ring.
   * Administration and learner documents consume this one ladder. */
  --elev-1: 0 1px 2px rgba(16, 24, 40, 0.08), 0 2px 6px rgba(16, 24, 40, 0.05);
  --elev-2: 0 2px 4px rgba(16, 24, 40, 0.08), 0 6px 16px rgba(16, 24, 40, 0.08);
  --elev-3: 0 4px 8px rgba(16, 24, 40, 0.08), 0 12px 32px rgba(16, 24, 40, 0.14);
  --elev-4: 0 8px 16px rgba(16, 24, 40, 0.10), 0 24px 56px rgba(16, 24, 40, 0.20);
  /* A filled button's shadow takes its own fill, so a coloured control does not cast a grey shadow. */
  --elev-1-fill: 0 1px 2px color-mix(in srgb, var(--accent) 30%, transparent),
                 0 2px 8px color-mix(in srgb, var(--accent) 16%, transparent);
  --elev-2-fill: 0 2px 4px color-mix(in srgb, var(--accent) 30%, transparent),
                 0 6px 16px color-mix(in srgb, var(--accent) 22%, transparent);
  --elev-1-destructive: 0 1px 2px color-mix(in srgb, var(--destructive) 30%, transparent),
                        0 2px 8px color-mix(in srgb, var(--destructive) 16%, transparent);
  --elev-2-destructive: 0 2px 4px color-mix(in srgb, var(--destructive) 30%, transparent),
                        0 6px 16px color-mix(in srgb, var(--destructive) 22%, transparent);
  --surface-overlay: #FEFEFE;
  --surface-modal: #FEFEFE;
  --surface-overlay-hover: #F0F2F5;
  --surface-modal-hover: #F0F2F5;
  /* The bulk bar: the overlay rung, as every floating surface (the grey step was tried and withdrawn, operator
   * 2026-10-18); the dock's fade parts it from the content beneath. */
  --surface-bar: var(--surface-overlay);
  --surface-bar-hover: var(--surface-overlay-hover);
  --control-on-bar: var(--control-on-overlay);
  --control-pressed-on-bar: var(--control-pressed-on-overlay);

  /* Surface shift (light) */
  --surface-hover: #F0F2F5;         /* 1.12:1 on surface */
  --surface-pressed: #E6E9EE;       /* 1.22:1 on surface, 1.09:1 on surface-hover */
  --control-fill: var(--surface);   /* a raised control at rest: level 1, as a card is */
  --control-fill-hover: var(--surface); /* hover and focus lift it to level 2; the fill stays */
  --control-fill-pressed: #E6E9EE;  /* below rest: 1.07:1 on rest, 1.13:1 on hover */
  --badge-fill: #E6E9EE;            /* count badge; text-2 on it 6.37:1 */
  /* A raised control on a near-white holder — a card, an overlay, a dialog — would be white on white, and the light
   * ladder has no brighter rung to lift it to, so it takes its grandparent's rung instead: the page ground beneath
   * the holder, 1.06:1 against it, its J1 shadow still lifting it (backlog item 5). Pressed is the pressed fill. */
  --control-on-card: var(--bg);
  --control-pressed-on-card: var(--control-fill-pressed);
  --control-on-overlay: var(--bg);
  --control-pressed-on-overlay: var(--control-fill-pressed);
  --control-on-modal: var(--bg);
  --control-pressed-on-modal: var(--control-fill-pressed);

  /* Holders (light): see the operator mode above. In light mode a lower elevation is darker: a card's fields recede
   * to the page ground, the page ground's to the sidebar's ground beneath it. An overlay and a dialog share the
   * card's near-white, so their fields recede to the page ground as well. */
  --holder: var(--bg);
  --holder-below: var(--chrome);
  --overlay-below: var(--bg);
  --modal-below: var(--bg);
  --hover-region-below: #EAECF0;
  /* The recess lit from above, as in the operator mode; the focus near layer is the light J1's, turned inward. */
  --inset-rest: inset 0 1px 1px rgba(16, 24, 40, 0.06), inset 0 4px 6px -3px rgba(16, 24, 40, 0.05);
  --inset-hover: inset 0 1px 1px rgba(16, 24, 40, 0.07), inset 0 5px 7px -3px rgba(16, 24, 40, 0.065);
  --inset-focus: inset 0 1px 2px rgba(16, 24, 40, 0.08), inset 0 6px 8px -3px rgba(16, 24, 40, 0.08);
  --inset-disabled: inset 0 1px 1px rgba(16, 24, 40, 0.04);
  --well-toward: #14171C;
  --well-mix: 52%;
  --well-mix-hover: 50%;
  --well-mix-disabled: 88%;

  /* Focus (light) */
  --focus-glow: 0 0 16px color-mix(in srgb, var(--focus-color) 24%, transparent);
  --focus-tint: color-mix(in srgb, var(--focus-color) 12%, transparent);

  --backdrop: rgba(12, 14, 18, 0.40);

  --chart-series-1: #2A78D6;  /* 4.42:1 on white */
  --chart-neutral: #8A93A3;   /* 3.10:1 on white */
  --chart-grid: #E3E6EB;      /* data ink, not framing */
  --chart-baseline: #CDD2DA;
  --chart-axis: var(--text-3);
}

/* Pre-authentication and the unassigned-administrator landing: customer tokens, no brand. */
[data-mode="neutral"] {   /* after the shared block: overrides the brand-driven roles only */
  --accent: #14171C;        /* dark ink primary button, white ink 17.96:1 */
  --accent-ink: #FEFEFE;
  --accent-hover: #2A2F37;
  --accent-tint: #F0F2F5;
  --focus-color: #14171C;
  --link: #14171C;
}

/* The document background follows the mode, so overscroll never shows the other mode; so does the document
 * scrollbar, which belongs to the root element and cannot read the tokens a mode root declares below it. */
:root:has([data-mode="operator"]) {
  background: #101319; color-scheme: dark;
  /* the thumb ≥ 3:1 at rest on every surface a scroller sits on: 4.30:1 on bg, 4.00:1 on surface, 3.65:1 on
   * surface-2, 3.60:1 on surface-overlay, 3.29:1 on surface-modal */
  --scrollbar-thumb: #727A89; --scrollbar-thumb-hover: #8A93A3; --scrollbar-thumb-active: #AEB5C2;
}
:root:has([data-mode="customer"]), :root:has([data-mode="neutral"]) {
  background: #F6F7F9; color-scheme: light;
  /* the thumb ≥ 3:1 at rest on every surface a scroller sits on: 3.72:1 on white (surface, overlay, modal),
   * 3.47:1 on bg, 3.32:1 on surface-2 */
  --scrollbar-thumb: #7C8595; --scrollbar-thumb-hover: #6B7382; --scrollbar-thumb-active: #4A5363;
}

/* == Status tokens (fixed; never brand) ==
 * fg = text and icon colour (on surface, tint and fill); tint = label base background; fill = the progress-fill
 * layer of the course label; solid = non-text marks (2 px progress bar, chart segments, dots), ≥ 3:1 on surface
 * and on tint. Notice tones reuse the hue families: success → on-track, warning → behind, error → serious,
 * info → info. */
:root, [data-mode="customer"], [data-mode="neutral"] {
  --status-on-track-fg: #146C36;   /* 6.51 surface · 5.73 tint · 4.74 fill */
  --status-on-track-tint: #E6F4EB;
  --status-on-track-fill: #BFE5CC;
  --status-on-track-solid: #1F8445; /* 4.72 surface · 4.16 tint · 3.44 fill */

  --status-behind-fg: #8F4300;     /* 7.07 surface · 6.25 tint · 5.01 fill */
  --status-behind-tint: #FDEFDD;
  --status-behind-fill: #F9D3A6;
  --status-behind-solid: #B85A00;  /* 4.67 surface · 4.13 tint */

  --status-serious-fg: #A3201A;    /* 7.56 surface · 6.43 tint · 4.79 fill */
  --status-serious-tint: #FDE8E6;
  --status-serious-fill: #F7C1BC;
  --status-serious-solid: #C42A1E; /* 5.68 surface · 4.83 tint */

  --status-paused-fg: #4E5664;     /* 6.48 tint · 5.16 fill */
  --status-paused-tint: #EEF0F3;
  --status-paused-fill: #D3D8DF;
  --status-paused-solid: #737C8B;  /* 4.21 surface · 3.69 tint */

  --status-neutral-fg: var(--text-3);   /* not-completed: 4.80 on surface-2 */
  --status-neutral-tint: var(--surface-2);

  --info-fg: #1F56B8;              /* 6.81 surface · 5.94 tint */
  --info-tint: #E8F0FD;
  --info-solid: #3B7BEA;
}

[data-mode="operator"] {
  --status-on-track-fg: #6FDC98;   /* 10.17 surface · 9.09 tint · 5.97 fill */
  --status-on-track-tint: #13291B;
  --status-on-track-fill: #1D4A2E;
  --status-on-track-solid: #2EB35F; /* 6.35 surface · 5.68 tint */

  --status-behind-fg: #FFB866;     /* 10.11 surface · 9.25 tint · 6.41 fill */
  --status-behind-tint: #2E2010;
  --status-behind-fill: #54361A;
  --status-behind-solid: #F08A1C;  /* 6.87 surface · 6.28 tint */

  --status-serious-fg: #FF8A82;    /* 7.57 surface · 7.28 tint · 5.33 fill */
  --status-serious-tint: #331614;
  --status-serious-fill: #5C2420;
  --status-serious-solid: #EF4B40; /* 4.73 surface · 4.54 tint */

  --status-paused-fg: #B4BBC7;     /* 8.94 surface · 8.16 tint · 5.83 fill */
  --status-paused-tint: #1F232A;
  --status-paused-fill: #353B46;
  --status-paused-solid: #8A93A3;  /* 5.58 surface · 5.09 tint */

  --status-neutral-fg: var(--text-3);   /* 5.91 on surface-2 */
  --status-neutral-tint: var(--surface-2);

  --info-fg: #8DB8FF;              /* 8.58 surface · 7.82 tint */
  --info-tint: #15233A;
  --info-solid: #3B7BEA;
}

/* == Sticky bars: what the document must keep clear when it scrolls a focused control into view ==
 * `--sticky-top` is the height of the sticky bar at the top of the page — the phone's top bar, the only one; from a
 * tablet up the sidebar is at the side, not on top — and `--sticky-bottom` the room the sticky bars docked at the
 * bottom take. base.css turns them into the document's scroll padding, so keyboard focus is never hidden under a
 * sticky bar (WCAG 2.4.11). */
:root { --sticky-top: 0px; --sticky-bottom: 0px; }
@media (max-width: 831px) { :root:has(.mobile-topbar) { --sticky-top: 56px; } }
:root:has(.wizard-actions) { --sticky-bottom: 72px; }   /* a 36 px action row in 12 px of padding, and a gap */
:root:has(.bulk-bar) { --sticky-bottom: 88px; }         /* a 56 px bar floating 16 px up, and a gap */
