/* =========================================================================
   Hectre Design System — Tokens
   Drop into the head of any Hectre product or marketing surface.

   Version:    2.514.0      (@version 2.514.0)
   Released:   2026-10-02
   Status:     stable
   Owner:      Design

   Single-sourced versioning — the whole system ships under ONE version.
   This file mirrors DS_VERSION in "Hectre Design System.html"; keep the two
   in lockstep on every release. See CLAUDE.md.

   THREE LAYERS:
     1. PRIMITIVES — raw values. Don't reference these in components.
     2. SEMANTIC   — named for purpose. Reference these from components.
     3. COMPONENT  — concrete values for specific UI parts. Reference for
                     bespoke component CSS.

   Why three layers?
   - Primitives let you swap a single hex once without rippling through code.
   - Semantic tokens decouple "what it looks like" from "what it means."
   - Component tokens stop you from re-deriving padding/height in every file.

   Surfaces vocabulary:
     "on-light" = paper or white surfaces
     "on-dark"  = petrol surfaces
   ========================================================================= */

:root {
  /* =========================================================================
     1. PRIMITIVES
     ========================================================================= */

  /* ---------- Color · Primary (orange) — 3 tokens, locked ---------- */
  --primary: #ea5d2e; /* Primary on light */
  --lifted-orange: #ff8a4d; /* Primary on dark   */
  --primary-press: #c8431b; /* Hover/active depth */
  /* Accent LABEL on an accent tint. --primary-press is tuned for depth on white
     (4.91:1) but is carried by the tint underneath it: 4.27:1 on --tint-accent-medium
     and 4.07:1 on --tint-accent-strong, both under the 4.5:1 floor for 13px text.
     This darker step clears it — 5.5:1 on the 0.12 tint, 4.96:1 on the 0.16. */
  --accent-text-on-tint: #b23a16; /* Accent text on an accent-tinted fill (light) */

  /* ---------- Color · Petrol (anchor) ---------- */
  --petrol: #173a4c;
  --petrol-deep: #0e2935;
  --petrol-mid: #20485e;
  --petrol-soft: #edf2f5;

  /* ---------- Color · Ink & Paper (neutrals) ---------- */
  --ink: #0e1411;
  --ink-2: #3a3a35;
  --ink-3: #6a6a65;
  --paper: #fafaf7;
  --line: rgba(0, 0, 0, 0.12);
  --line-2: rgba(0, 0, 0, 0.05);
  --ink-line: rgba(255, 255, 255, 0.1);

  /* ---------- Color · Semantic (status, alerts, validation) ---------- */
  --success: #10b981;
  --success-text: #047352;
  --warning: #f59e0b;
  --warning-text: #8a5200;
  --error: #ef4444;
  --error-text: #dc2626;
  --success-press: #036045; /* Darker green — solid success-button / icon hover + press (white passes AA) */
  --error-press: #b91c1c;
  --warning-press: #d97706; /* Filled warning button hover — ink label 6.6:1 (v2.473) */ /* Darker red — solid danger-button hover + press (white passes AA) */
  --error-active: #991b1b; /* Filled danger pressed — white 7.9:1 (v2.477) */
  --warning-active: #c96a04; /* Filled warning pressed — ink 4.8:1 (v2.477) */
  --success-active: #024d37; /* Filled success pressed (v2.477) */
  --shadow-button-pressed: inset 0 2px 4px rgba(0, 0, 0, 0.28); /* Filled button pressed on petrol (v2.477) */
  /* The info press step, added v2.275. --info-text (#2563EB) is tuned for paper;
     on --tint-info-medium it measures 4.32 — a badge grounds its label on its own
     tint, which is a lower surface than paper, so the -text steps are not enough
     there. Same finding as --level-component in v2.273. */
  --info-press: #1d4fd8;
  --info: #3b82f6;
  --info-text: #2563eb;

  /* ---------- Color · Accessory palette ----------
     Six accents for illustration, secondary highlights, category tagging,
     and data viz. Never combine with primary in a CTA — accessories support,
     they don't lead. */
  /* DEPRECATED v2.490 — replaced for charts by --chart-series-1…4 (orange,
     petrol, steel, mist). Kept one version for illustration only; removed in
     the next release. Do not use in new work. */
  --acc-amber-gold: #ffcc1a;
  --acc-coral-pink: #ff6b6b;
  --acc-magenta: #ec4899;
  --acc-teal: #14b8a6;
  --acc-cyan: #06b6d4;
  --acc-lime: #a8e10c;

  /* ---------- Typography · Families ----------
     Load via type.css (self-hosted fonts/ variable files); Mono + Material Symbols
     are served by the host app’s base.css (v2.389/2.390 decision).
  */
  --font-display: 'Noto Sans Display', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-body: 'Noto Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: 'Noto Sans Mono', 'SF Mono', Menlo, monospace;
  --font-icon: 'Material Symbols Outlined'; /* icon atom — see components.css .mdi */

  /* ---------- Typography · Sizes ---------- */
  --text-display-xl: 92px; /* Cover h1 only */
  --text-display-l: 52px; /* Page hero h1 */
  --text-display-m: 48px; /* Chapter h2 */
  --text-display-s: 32px; /* Stat-md, h3 */
  --text-h-l: 26px;
  --text-h-m: 22px;
  --text-h-s: 18px;
  --text-body-l: 17px;
  --text-body-m: 15px;
  --text-body-s: 13px;
  --text-meta: 11px; /* Mono uppercase */
  --text-micro: 10px; /* Mono uppercase */
  --text-stat-xl: 68px;
  --text-stat-l: 46px;
  --text-stat-m: 32px;
  --text-stat-s: 28px;

  --text-page-title: 38px; /* Dashboard page title (Arc). Responsive — see breakpoints below */

  /* ---------- Typography · Tracking ---------- */
  --tr-display-xl: -0.042em;
  --tr-display-l: -0.036em;
  --tr-display-m: -0.032em;
  --tr-display-s: -0.03em;
  --tr-h-l: -0.024em;
  --tr-h-m: -0.02em;
  --tr-page-title: -0.028em;
  --tr-meta: 0.12em;
  --tr-micro: 0.14em;

  /* ---------- Spacing · 4px scale ---------- */
  --space-1: 4px;
  --space-2: 6px;
  --space-3: 8px;
  --space-4: 10px;
  --space-5: 12px;
  --space-6: 14px;
  --space-7: 16px;
  --space-8: 20px;
  --space-9: 24px;
  --space-10: 28px;
  --space-11: 32px;
  --space-12: 40px;
  --space-14: 48px;
  --space-16: 56px;
  --space-18: 72px;
  --space-20: 96px;

  /* ---------- Radius ---------- */
  --radius-xs: 3px;
  --radius-sm: 4px;
  --radius: 6px;
  --radius-md: 8px;
  --radius-lg: 10px;
  --radius-xl: 12px;
  --radius-2xl: 14px;
  --radius-3xl: 16px;
  --radius-pill: 999px;

  /* ---------- Chart gradients ---------- */
  /* Area-chart fills. Aliases so a gradient never hard-codes the accent. */
  --chart-grad-a: var(--primary); /* Gradient start — accent on light */
  --chart-grad-b: var(--lifted-orange); /* Gradient end */

  /* ---------- Touch · App (the 44px minimum, expressed once) ---------- */
  --touch-min: 44px; /* Every interactive target on the app (WCAG 2.5.5 / platform minimum) */
  --touch-comfortable: 48px; /* App form controls — a typed field is a larger target than a tap */
  --touch-row: 52px; /* App list / option rows */
  --touch-row-tall: 56px; /* App header row, action-sheet items */
  --text-input-min: 16px; /* Typed text on the app. Below this iOS zooms the viewport on focus */

  /* ---------- Form control heights (v2.441) ---------- */
  /* The shared size scale of the Control box — Text input, Select, Chip input. */
  --control-height-xs: 28px; /* Button xs (v2.474) */
  --control-height-sm: 32px; /* Dense toolbars, table settings, More filters */
  --control-height-md: 40px; /* Default dashboard form control */
  --control-height-lg: 48px;
  --control-height-xl: 56px; /* Retired with .btn-xl (v2.481), kept one version */ /* Large / touch-first forms (= --touch-comfortable) */

  /* ---------- Range slider (v2.455) ----------
     Default fill position for .range-slider (0–100, unitless). The host overrides it
     per slider: style="--range-slider-fill: 72", updated on input. */
  --range-slider-fill: 0;

  /* ---------- Checkbox (v2.454) ----------
     One box for every checkbox: Checkbox control, table row select, menu check row,
     multiple FormSelect option. 14px outer (border-box), 1px border, 1px tick. */
  --checkbox-size: 14px;
  --checkbox-radius: var(--radius-xs);

  /* ---------- Icon masks (v2.448) ----------
     Glyphs that CSS draws itself (pseudo-elements), as SVG. Masks take currentColor;
     *-on-fill are white marks for the filled checkbox. No icon font required. */
  --icon-mask-check: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/></svg>"); /* @kind other */
  --icon-mask-lock: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1s3.1 1.39 3.1 3.1v2z'/></svg>"); /* @kind other */
  --icon-check-on-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%23fff' d='M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/></svg>"); /* @kind other */
  --icon-dash-on-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%23fff' d='M19 13H5v-2h14v2z'/></svg>"); /* @kind other */
  /* 1px checkbox marks (v2.454), drawn in a 12px square: masks take currentColor; on-fill
     is white on --primary, on-lifted is --petrol-deep on --lifted-orange. */
  --icon-mask-check-thin: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M2.5 6.2 4.8 8.5 9.5 3.5' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'/></svg>"); /* @kind other */
  --icon-mask-dash-thin: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M3 6.5h6' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'/></svg>"); /* @kind other */
  --icon-check-thin-on-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M2.5 6.2 4.8 8.5 9.5 3.5' fill='none' stroke='%23fff' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'/></svg>"); /* @kind other */
  --icon-dash-thin-on-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M3 6.5h6' fill='none' stroke='%23fff' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'/></svg>"); /* @kind other */
  --icon-check-thin-on-lifted: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M2.5 6.2 4.8 8.5 9.5 3.5' fill='none' stroke='%230E2935' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'/></svg>"); /* @kind other */
  --icon-dash-thin-on-lifted: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M3 6.5h6' fill='none' stroke='%230E2935' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'/></svg>"); /* @kind other */

  /* ---------- Breakpoints ---------- */
  /* One ladder for both surfaces. App owns the first two, dashboard the last two;
     the middle is where a dashboard layout must already have collapsed. */
  --bp-phone: 480px; /* Phone portrait — single column, bottom nav */
  --bp-phone-large: 640px; /* Large phone / small tablet — grids collapse to one column */
  --bp-tablet: 900px; /* Tablet — dashboard nav becomes the icon rail */
  --bp-desktop: 1200px; /* Desktop — docked sidebar, multi-column dashboards */

  /* ---------- Safe area (notch, home indicator, keyboard) ---------- */
  /* env() resolves to 0 off-device, so these are safe to apply unconditionally. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --radius-circle: 50%;

  /* ---------- Shadows ---------- */
  /* Small elevations — for resting UI (buttons, inputs, dropdowns, popovers, tiles). */
  /* Large elevations — for floating mockups and framed surfaces only. */
  --shadow-card: 0 24px 48px -16px rgba(0, 0, 0, 0.12), 0 0 0 0.5px rgba(0, 0, 0, 0.06);
  --shadow-frame: 0 24px 48px -16px rgba(0, 0, 0, 0.14), 0 0 0 0.5px var(--line);
  --shadow-cta-glow: 0 12px 32px -8px rgba(234, 93, 46, 0.55);
  --shadow-cta-lifted: 0 12px 32px -8px rgba(255, 138, 76, 0.5);
  /* Soft calm elevation — the borderless card / tile lift (v2.25). */
  --dp-shadow: 0 1px 2px rgba(20, 30, 25, 0.05), 0 12px 28px -18px rgba(20, 30, 25, 0.24);
  --dp-shadow-hi: 0 2px 6px rgba(20, 30, 25, 0.05), 0 18px 40px -22px rgba(20, 30, 25, 0.26);
  --shadow-slide-over: -12px 0 48px rgba(14, 41, 53, 0.28); /* Left-cast lift for the right-anchored slide-over */
  --shadow-segmented-on:
    0 1px 2px rgba(20, 30, 25, 0.05), 0 6px 14px -8px rgba(20, 30, 25, 0.22); /* Raised segmented pill on light — Unit input (v2.514); same lift as the segmented control on-state */
  --shadow-segmented-on-dark: 0 2px 8px -2px rgba(0, 0, 0, 0.4); /* Raised segmented pill on petrol (v2.514) */

  /* ---------- Motion ---------- */
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1); /* @kind other */
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); /* @kind other */ /* Symmetric ease — loops that breathe (pulse, shimmer) */
  --dur-fast: 150ms; /* @kind other */
  --dur-base: 200ms; /* @kind other */
  --dur-slow: 320ms; /* @kind other */ /* Data-viz growth — a bar or column animating to its
                                             value. Longer than --dur-base on purpose: the eye is
                                             reading a magnitude change, not acknowledging a click. */

  /* ---------- Layout · Page padding ---------- */
  /* The gap between a page's content and the edge of its surface. Exactly two
     margins, one token each (rule 11k, v2.463). Never a literal, never a third. */
  --page-padding: var(--space-11); /* 32px. Dashboard content top + sides, header left/right; bottom is 1.5× (48px). 16px below 900px */
  --app-screen-padding-inline: 16px; /* App screen content, left + right. Add --safe-left / --safe-right on top */

  /* =========================================================================
     2. SEMANTIC TOKENS
     These name primitives by purpose. Components should reference these.
     ========================================================================= */

  /* ---------- Surfaces ---------- */
  --surface-page: var(--paper); /* Default page background */
  --surface-elevated: #ffffff; /* Cards, inputs, popovers */
  --surface-sunken: var(--paper); /* Disabled fields, code blocks */
  --scrim: rgba(0, 0, 0, 0.5); /* Modal/overlay backdrop */
  --scrim-petrol: rgba(14, 41, 53, 0.42); /* Petrol-tinted overlay — dialogs, slide-over */

  /* ---------- Text · on light ---------- */

  /* ---------- Text · on dark ---------- */
  --text-on-dark: #ffffff;
  --text-on-dark-secondary: rgba(255, 255, 255, 0.78);
  /* RAISED 0.55 -> 0.68 in v2.356, and the reason matters more than the number.
     At 0.55 this token could not clear 4.5:1 on ANY translucent fill over petrol —
     3.83:1 on the sidebar's rgb(50,81,97), 3.86 on the feedback card, 4.29 on a
     standard card. v2.354 and v2.355 each fixed a hand-built list of rules and each
     claimed completeness; both claims were false, because a list of RULES cannot
     cover a failure that belongs to the TOKEN. One of the failures was an unclassed
     <span> with no selector to grep for, which is the proof: enumeration could never
     have finished — and note that the chip itself was an INLINE literal, so this raise
     did not fix it either (v2.358 did). 0.68 is the lowest step that clears 4.5:1 on the lightest fill
     measured (4.93:1) while staying visibly below --text-on-dark-secondary (0.78).
     Now safe for: icons, graphics, large text, and normal text on petrol or any
     translucent fill over it. Disabled text stays --text-on-dark-disabled (0.45),
     which 1.4.3 exempts. */
  --text-on-dark-muted: rgba(255, 255, 255, 0.68);
  --text-on-dark-disabled: rgba(255, 255, 255, 0.45); /* Disabled label on petrol */

  /* ---------- Borders ---------- */
  --border-default: var(--line); /* Card outlines */
  --border-strong: rgba(0, 0, 0, 0.2); /* Input default */
  --border-stronger: rgba(0, 0, 0, 0.32); /* Input hover */
  --border-whisper: var(--line-2); /* Row dividers */
  --border-on-dark: var(--ink-line);
  --border-on-dark-strong: rgba(255, 255, 255, 0.3);
  --border-on-dark-medium: rgba(255, 255, 255, 0.25); /* translucent control border on petrol */
  /* translucent control border · hover on petrol.
     ALSO the minimum RESTING boundary for a control
     on petrol: measured against a petrol bar it is
     3.41:1, the lowest step that clears WCAG 1.4.11.
     --border-on-dark-medium (0.25) is only 2.05:1 —
     decorative grouping edges only, never a control. */
  --border-on-dark-hover: rgba(255, 255, 255, 0.45);
  /* Hover edge where 0.45 is already the resting
     boundary, so hover still reads as a step up. */
  --border-on-dark-emphasis: rgba(255, 255, 255, 0.62);

  /* ---------- Composition level ----------
     The atom / component / module / feature badges in the living reference. Four
     hues so a level is identifiable at 9.5px without reading it, each darkened to
     clear 4.5:1 on its OWN tint — which is a lower ground than paper, so the
     obvious mid-tone of each hue is not enough. --level-component was #177a4e
     and measured 4.30 on rgb(219,234,225); #146742 measures 5.53.
     Module reuses the accent, so it takes --accent-text-on-tint rather than a
     fifth hue. */
  --level-atom: #215fbf;
  --level-atom-dot: #2a6fdb;
  --level-atom-tint: rgba(42, 111, 219, 0.12);
  --level-atom-on-dark: #9dc0ff;
  --level-atom-tint-on-dark: rgba(96, 150, 240, 0.22);
  --level-component: #146742;
  --level-component-dot: #1f8a5b;
  --level-component-tint: rgba(31, 138, 91, 0.14);
  --level-component-on-dark: #7fe0ab;
  --level-component-tint-on-dark: rgba(52, 180, 120, 0.22);
  --level-feature: #6d4bd6;
  --level-feature-dot: #7c5cef;
  --level-feature-tint: rgba(124, 92, 239, 0.14);
  --level-feature-on-dark: #c3b1fb;
  --level-feature-tint-on-dark: rgba(150, 120, 245, 0.24);

  /* ---------- Photo scrim ----------
     The bottom gradient laid over a photograph so a white chip or caption
     survives a bright image. NOT --scrim (a dialog backdrop) or --scrim-petrol
     (the slide-over backdrop): those dim a whole surface at a flat alpha, this
     one is the dark end of a gradient over content that is already there. */
  --scrim-photo: rgba(14, 41, 53, 0.78);

  /* ---------- CTA depth (button press fills + glow ladder) ----------
     The pressed fills and the glow steps the button system was already using as
     raw literals. Tokenising them changes nothing visually. --primary-active is
     one step below --primary-press; --primary-active-deep only ever appears as
     the dark end of the pressed .standalone gradient. */
  --primary-active: #a8380f;
  --primary-active-deep: #8b2e0c;
  --shadow-cta-glow-hover: 0 16px 36px -8px rgba(234, 93, 46, 0.7);
  --shadow-cta-glow-press: 0 4px 10px -4px rgba(234, 93, 46, 0.5);
  --shadow-cta-lifted-hover: 0 18px 42px -8px rgba(255, 138, 76, 0.7);
  --shadow-cta-lifted-press: 0 4px 10px -4px rgba(255, 138, 76, 0.5);
  --cta-ring-on-dark: rgba(255, 255, 255, 0.15);
  /* Button loading ring track — 40% of the button's own label colour, resolved
     where it is used, so one token serves every variant on light and petrol. */
  --button-loading-track: color-mix(in srgb, currentColor 40%, transparent);

  /* ---------- Status borders ----------
     The status sibling of --accent-border-soft: the hairline around a tinted
     status surface — badge, chip, inline flag, alert banner. These are the
     values the system was ALREADY using as raw literals; tokenising them changes
     nothing visually. Warning sits one step higher (0.28 / 0.38) because amber
     reads weaker than the other three at the same alpha.
     DECORATIVE: the tinted fill and the label carry the meaning, so this hairline
     is not held to the 3:1 of WCAG 1.4.11. A control whose ONLY boundary is a
     status edge takes the solid --success / --warning / --error / --info instead.
     On petrol the tinted fills lift (0.20–0.22), so the hairline lifts with them. */
  --success-border: rgba(16, 185, 129, 0.25);
  --warning-border: rgba(245, 158, 11, 0.28);
  --error-border: rgba(239, 68, 68, 0.25);
  --info-border: rgba(59, 130, 246, 0.25);
  --success-border-on-dark: rgba(16, 185, 129, 0.35);
  --warning-border-on-dark: rgba(245, 158, 11, 0.38);
  --error-border-on-dark: rgba(239, 68, 68, 0.35);
  --info-border-on-dark: rgba(59, 130, 246, 0.35);

  /* ---------- Accent ---------- */
  --accent: var(--primary); /* Primary brand on light */
  --lifted-orange-press: #e5722e; /* Lifted-orange hover/press depth (solid primary buttons on petrol) */
  --accent-border-soft: rgba(234, 93, 46, 0.3); /* Soft accent border (active pills, date field, selection bar) */

  /* ---------- State tints (for hover/pressed backgrounds) ---------- */
  --tint-accent-faint: rgba(234, 93, 46, 0.04); /* Warm whisper — data-table row hover */
  --tint-accent-soft: rgba(234, 93, 46, 0.08); /* Hover bg, secondary btn */
  --tint-accent-medium: rgba(234, 93, 46, 0.12); /* Pill bg */
  --tint-accent-strong: rgba(234, 93, 46, 0.16); /* Pressed bg */

  /* ---------- Data-viz (charts) ---------- */
  --chart-main: var(--primary); /* the single default data hue (light) */
  --chart-track: rgba(0, 0, 0, 0.05); /* bar / bullet track + gridlines */
  /* Chart series — the categorical palette (v2.490, reordered v2.492). Fixed
     order: orange, mist, steel, petrol. Orange is the result that matters; the
     others are one calm blue ramp, light to deep, so nothing outshouts orange.
     At most four series; petrol only past three. Mist is light (1.9:1 on white),
     so it relies on the 2px segment gap and a label. On petrol each token swaps
     to its -on-dark value via .dark-surface. */
  --chart-series-1: var(--primary);
  --chart-series-2: #a9c0cd;
  --chart-series-3: #5f8aa3;
  --chart-series-4: var(--petrol);
  --chart-series-1-on-dark: var(--lifted-orange);
  --chart-series-2-on-dark: #4f7a92;
  --chart-series-3-on-dark: #8fb4c9;
  --chart-series-4-on-dark: #e8eef1;
  /* Series 5–6 (v2.491) — earth tones for the rare chart that needs more than
     four named series. Past six, group the remainder into "Other" (--ink-300). */
  --chart-series-5: #7d8f69;
  --chart-series-6: #b09b72;
  --chart-series-5-on-dark: #a9b996;
  --chart-series-6-on-dark: #d8c7a2;

  /* Produce colour — cherry (v2.491). The one family that is NOT brand: the
     fruit's real skin colour IS the data, so a grader reads the bar literally.
     Seven named grades, lightest to darkest. Adapted from the product chart:
     Blush lifted lighter and pinker so it reads as a grade, not the --error red;
     lightness falls at every step. Never use these for anything but cherry
     colour grades. On petrol the ramp is lifted, keeping its order; the dark end
     is low-contrast there, so cherry charts always carry labels. */
  --chart-cherry-blush: #db5462;
  --chart-cherry-rose: #b8243a;
  --chart-cherry-ruby: #962438;
  --chart-cherry-crimson: #7c2136;
  --chart-cherry-currant: #5e2035;
  --chart-cherry-merlot: #432039;
  --chart-cherry-mahogany: #262027;
  --chart-cherry-blush-on-dark: #ffb3ba;
  --chart-cherry-rose-on-dark: #f5838f;
  --chart-cherry-ruby-on-dark: #e0607a;
  --chart-cherry-crimson-on-dark: #c84d69;
  --chart-cherry-currant-on-dark: #ac4562;
  --chart-cherry-merlot-on-dark: #8e3f61;
  --chart-cherry-mahogany-on-dark: #6e3a5c;
  /* Colour-grade ramp — ONE hue at rising strength, never a rainbow, so a grade
     bar reads as an ordered scale. Light = primary; on petrol = lifted orange.
     Segments are separated by a 1px gap, so the step boundaries are structural
     and do not depend on telling two neighbouring tints apart. */
  /* Chart sheen (v2.495): a near-invisible top light laid over every chart
     fill (::after overlay). Not a colour — never use it as a fill on its own. */
  --chart-sheen: linear-gradient(180deg, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0) 52%, rgba(14, 20, 17, 0.05) 100%); /* @kind other */
  --chart-sheen-on-dark: linear-gradient(180deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 52%, rgba(0, 0, 0, 0.1) 100%); /* @kind other */
  --chart-grade-1: rgba(234, 93, 46, 0.22);
  --chart-grade-2: rgba(234, 93, 46, 0.45);
  --chart-grade-3: rgba(234, 93, 46, 0.7);
  --chart-grade-4: var(--primary);
  --chart-grade-1-on-dark: rgba(255, 138, 77, 0.28);
  --chart-grade-2-on-dark: rgba(255, 138, 77, 0.5);
  --chart-grade-3-on-dark: rgba(255, 138, 77, 0.74);
  --chart-grade-4-on-dark: var(--lifted-orange);
  --ink-300: #c9c9c2; /* "Unknown" / unattributed buckets — muted, never a hue */
  --tint-on-dark-soft: rgba(255, 255, 255, 0.1); /* Hover on dark */
  --tint-on-dark-strong: rgba(255, 255, 255, 0.18); /* Pressed on dark */
  --tint-on-dark-faint: rgba(255, 255, 255, 0.06); /* Faint fill on dark (quiet control rest) */
  --tint-on-dark-medium: rgba(255, 255, 255, 0.12); /* Translucent control fill on petrol */
  --tint-lifted-faint: rgba(255, 138, 77, 0.07); /* Warm whisper on petrol — data-table row hover */
  --tint-lifted-soft: rgba(255, 138, 77, 0.12); /* Lifted-orange hover / active row on petrol (nav rail, quiet accents) */
  --tint-lifted-medium: rgba(255, 138, 77, 0.16); /* Lifted-orange active pills / accent tiles on petrol */
  --tint-lifted-selected: rgba(255, 138, 77, 0.14); /* Selected / current row on petrol — table rows AND the nav active row */
  --tint-lifted-strong: rgba(255, 138, 77, 0.2);
  /* A BORDER step, not a fill. v2.237 collapsed three literals (0.18 / 0.20 / 0.30)
     onto --tint-lifted-strong; 0.18 → 0.20 is 0.02 of alpha behind a fill and is
     absorbed deliberately, but 0.30 → 0.20 visibly weakened the divider inside
     .filter-tag.accent, where the border is the only thing separating key from
     value. Restored as its own token rather than a sixth fill step. */
  --border-lifted-strong: rgba(255, 138, 77, 0.3); /* Lifted-orange pressed on petrol */
  --tint-success-bg: rgba(16, 185, 129, 0.08);
  --tint-warning-bg: rgba(245, 158, 11, 0.08);
  --tint-error-bg: rgba(239, 68, 68, 0.07);
  --tint-info-bg: rgba(59, 130, 246, 0.07);

  /* ---------- Focus rings ---------- */
  --focus-ring-accent: 0 0 0 3px rgba(234, 93, 46, 0.18);
  --focus-ring-error: 0 0 0 3px rgba(239, 68, 68, 0.15);
  --focus-ring-success: 0 0 0 3px rgba(16, 185, 129, 0.15);

  /* ---------- Status tints · medium (badges, inline flags) ---------- */
  --tint-success-medium: rgba(16, 185, 129, 0.12);
  --tint-warning-medium: rgba(245, 158, 11, 0.14);
  --tint-error-medium: rgba(239, 68, 68, 0.12);
  --tint-info-medium: rgba(59, 130, 246, 0.12);
  /* Category icon tints — the KPI-tile icon disc when a tile needs to read as a
     different category, not a different status. Fill + a darkened text/glyph
     colour that clears 3:1 on paper as a graphic. Follows the
     --tint-<name>-medium / --<name>-text pairing used by the status tints. */
  --tint-amber-medium: rgba(232, 163, 23, 0.14);
  --amber-text: #9a6a00;
  --tint-violet-medium: rgba(124, 92, 239, 0.14);
  --violet-text: #6d4bd6;
  --tint-teal-medium: rgba(20, 184, 166, 0.14);
  --teal-text: #0e8c7f;
  /* Accessory hues · on petrol. The light pair (0.14 tint + dark ink) is far too
     dull on a dark surface, so the disc fill lifts and the glyph lightens. Same
     --tint-<name>-on-dark / --<name>-on-dark pairing as the status tints. */
  --tint-amber-on-dark: rgba(232, 163, 23, 0.24);
  --amber-on-dark: #f2c14e; /* 6.5:1 on petrol */
  --tint-violet-on-dark: rgba(124, 92, 239, 0.3);
  --violet-on-dark: #c4b5fd; /* 5.8:1 on petrol */
  --tint-teal-on-dark: rgba(20, 184, 166, 0.26);
  --teal-on-dark: #5eead4; /* 7.4:1 on petrol */
  --tint-neutral-soft: rgba(0, 0, 0, 0.04); /* Ghost / icon-button hover fill on light */
  --tint-neutral: rgba(0, 0, 0, 0.06); /* Neutral / draft badge + tag bg; neutral chip + sealed-state pill */
  /* On petrol the status tints lighten for contrast */
  --tint-success-on-dark: rgba(16, 185, 129, 0.2);
  --tint-warning-on-dark: rgba(245, 158, 11, 0.22);
  --tint-error-on-dark: rgba(239, 68, 68, 0.22);
  --tint-info-on-dark: rgba(59, 130, 246, 0.22);

  /* ---------- Status text · on dark (lightened for petrol contrast) ---------- */
  --success-on-dark: #86efac;
  --warning-on-dark: #fcd34d;
  --error-on-dark: #fca5a5;
  --error-on-dark-press: #f87171; /* Filled danger button hover on petrol (v2.473) */
  --info-on-dark: #93c5fd;
  /* Neutral completes the family (v2.349). No solid neutral existed on dark, so a
     neutral-toned GRAPHIC on petrol — a capacity bar in the Closed or Empty state —
     had nothing to reference and silently inherited the accent. Text keeps
     --text-on-dark-muted; this is for fills and strokes. */
  --neutral-on-dark: rgba(255, 255, 255, 0.55);

  /* ---------- Focus ring · strong (the 3px field ring the inputs actually use) ---------- */
  --focus-ring-accent-strong: 0 0 0 3px rgba(234, 93, 46, 0.35);
  --focus-ring-accent-strong-on-dark: 0 0 0 3px rgba(255, 138, 77, 0.35);
  --focus-ring-error-strong-on-dark: 0 0 0 3px rgba(239, 68, 68, 0.25);

  /* =========================================================================
     3. COMPONENT TOKENS
     Concrete values per component. Reference these so component sizes stay
     consistent across the system and engineering doesn't re-derive them.
     ========================================================================= */

  /* ---------- Button ---------- */

  /* ---------- Input / Select ---------- */
  --input-border: 1px solid var(--border-strong);
  --input-bg-disabled: var(--surface-sunken);

  /* ---------- Column group ----------
     The bar area a .chart-column's percentage height is measured against. It was
     only ever a local custom property on .chart-column-group, so a consumer
     reading the token layer could not find the value the component asks them to
     override — and the two size tiers lived as literals inside a component rule
     rather than in the scale they belong to. */
  --chart-column-h: 30px;
  --chart-column-h-short: 20px;
  --chart-column-h-tall: 120px;
  --chart-column-h-cell: 24px; /* Data-table cell tier (v2.468) */
  /* Column chart (the DETAILED bar chart, v2.432): minimum plot height. The
     compact Column group tiers above stay in-cell; this is the detail-tile
     chart with axis, gridlines and printed values. */
  --column-chart-h: 188px;
  --column-chart-grouped-h: 240px; /* bar area of a grouped column chart (v2.497); + 22px label lane = 262px */
  /* The petrol twin --input-bg-disabled never had. The petrol tint ladder starts
     at --tint-on-dark-faint (0.06), which IS the enabled field fill, so a
     disabled field styled from that ladder is pixel-identical to an editable one;
     a recessed field has to sit BELOW the ladder. v2.217 briefly coined
     --surface-disabled for the light side before noticing --surface-sunken
     already owned that value — one concept, one name. */
  --input-bg-disabled-on-dark: rgba(255, 255, 255, 0.03);

  /* ---------- Card ---------- */

  /* ---------- Field stack (form group) ---------- */

  /* ---------- Toggle switch ---------- */

  /* ---------- Choice (radio / checkbox) ---------- */

  /* ---------- Tag · pill · stamp ---------- */

  /* ---------- Tenant mark (v2.467) ----------
     The customer's brand tile. A host overrides these per tenant (on the mark
     or any ancestor); both fall back to petrol so an unbranded tenant still
     reads as a mark. The on-dark pair inverts so the tile lifts off petrol. */
  --tenant-mark-bg: var(--petrol);
  --tenant-mark-text: var(--surface-elevated);
  --tenant-mark-bg-on-dark: var(--surface-elevated);
  --tenant-mark-text-on-dark: var(--petrol);

  /* ---------- Slide-over · wide (v2.467) ---------- */
  --slide-over-width-wide: 640px;

  /* ---------- Info tooltip ---------- */
  --z-tooltip: 5000; /* @kind other */
  --tooltip-bg: var(--petrol); /* Bubble on light — 12.1:1 with white */
  --tooltip-text: var(--text-on-dark);
  --tooltip-bg-on-dark: var(--surface-elevated); /* Inverts on petrol so it still lifts */
  --tooltip-text-on-dark: var(--ink);
  --tooltip-radius: var(--radius-md);
  --tooltip-shadow: var(--dp-shadow-hi);
  --tooltip-pad-y: 8px;
  --tooltip-pad-x: 11px;
  --tooltip-offset: 10px; /* Gap between trigger and bubble */
  --tooltip-max-width: 240px;
  --tooltip-max-width-wide: 320px;

  /* ---------- Table ---------- */
  --table-radius: var(--radius-lg); /* Card corner — the table frame (v2.468) */
  --table-shadow: var(--shadow-frame); /* Frame shadow + 0.5px ring (v2.468) */
  --table-row-height: 78px; /* Default row — a chart cell with 12px+ air (v2.468) */
  --table-row-height-compact: 36px;
  --table-header-offset: 0px; /* Long list: height of the sticky toolbar dock (set from a ResizeObserver) */
  --table-scroll-max-height: 70vh; /* .data-table-scroll; set to the space below the chrome */
  --table-sticky-shadow: -12px 0 14px -12px rgba(0, 0, 0, 0.12);
  --row-check-size: 16px;
  --report-page-width: 794px; /* A4 at 96dpi — the width a report renders at before scaling */
  --preview-scale: 1; /* @kind other */
  /* --preview-scale: Preview well scale factor, set per page from its measured width (v2.478) */
  /* Row states. Hover is a WARM accent whisper, not neutral grey: a data-table row
     is a target (it opens a record), so the wash previews the accent the selected
     state commits to. Ladder: hover 4% -> selected 8% -> selected+hover 12%. */
  /* Only .data-table rows use these. Documentation / non-interactive tables keep a
     neutral hover (--tint-neutral-soft) — a row that is not a click target should
     not be washed in accent. */
  --table-row-hover: var(--tint-accent-faint);
  --table-row-selected: var(--tint-accent-soft);
  --table-row-selected-hover: var(--tint-accent-medium);
  --table-row-hover-dark: var(--tint-lifted-faint);
  --table-row-selected-dark: var(--tint-lifted-selected); /* Selected row on petrol */
  --table-row-selected-hover-dark: var(--tint-lifted-medium);

  /* ---------- Eyebrow ---------- */

  /* ---------- Dashboard navigation (sidebar widths) ----------
     unfolded = full labels; rail = collapsed icon-only; drawer = mobile overlay.
     The width tweens between unfolded and rail on --dur-base / --ease-out. */
  --nav-width-expanded: 240px; /* Unfolded, docked with labels */
  --nav-width-rail: 72px; /* Collapsed icon rail */
  --nav-width-drawer: 300px; /* Mobile slide-in overlay */

  /* ---------- Dashboard navigation · row colour ----------
     Sidebar icons and labels are WHITE on petrol — never --ink-*. Idle rows sit
     at --text-on-dark-secondary (0.78 white, 8:1 on --petrol-deep); the current
     row lifts icon + label to solid white and is additionally marked by the 3px
     --lifted-orange left marker, the accent tint, a filled icon and 600 weight
     (never colour alone). The light-rail variant resolves the same roles to ink
     / primary orange. Consumers: reference these, not raw white percentages. */
  --nav-icon: var(--text-on-dark-secondary);
  --nav-icon-active: var(--text-on-dark);
  --nav-label: var(--text-on-dark-secondary);
  --nav-label-active: var(--text-on-dark);
  --nav-section-caption: var(--text-on-dark-muted);
  --nav-row-hover-fill: var(--tint-on-dark-faint);
  --nav-row-press-fill: var(--tint-on-dark-soft); /* Pressed / :active row on petrol — one step up from hover */
  --nav-row-active-fill: var(--tint-lifted-selected);
  --nav-icon-on-light: var(--ink-2);
  --nav-icon-active-on-light: var(--primary);
  --nav-label-on-light: var(--ink-2);
  --nav-label-active-on-light: var(--ink);
  --nav-row-hover-fill-on-light: var(--tint-neutral-soft); /* Hover row on the light rail */
  --nav-row-press-fill-on-light: var(--tint-neutral); /* Pressed / :active row on the light rail */
  --nav-row-active-fill-on-light: var(--tint-accent-soft); /* Current row on the light rail */
}

/* =========================================================================
   Responsive type scale
   The display/heading/stat/page-title sizes step down at two breakpoints so
   large type stays in proportion on tablet and phone. Body, meta and micro
   stay fixed — shrinking running text hurts legibility. Breakpoints match the
   dashboard navigation (900 / 540). Tokens only; every type style that reads a
   --text-* var scales automatically.
   ========================================================================= */
@media (max-width: 900px) {
  :root {
    --page-padding: var(--space-7);
    --text-page-title: 32px;
    --text-display-xl: 64px;
    --text-display-l: 40px;
    --text-display-m: 36px;
    --text-display-s: 28px;
    --text-h-l: 23px;
    --text-h-m: 20px;
    --text-h-s: 17px;
    --text-stat-xl: 52px;
    --text-stat-l: 38px;
    --text-stat-m: 28px;
    --text-stat-s: 24px;
  }
}
@media (max-width: 540px) {
  :root {
    --text-page-title: 26px;
    --text-display-xl: 44px;
    --text-display-l: 32px;
    --text-display-m: 28px;
    --text-display-s: 23px;
    --text-h-l: 20px;
    --text-h-m: 18px;
    --text-h-s: 16px;
    --text-stat-xl: 40px;
    --text-stat-l: 30px;
    --text-stat-m: 24px;
    --text-stat-s: 22px;
  }
}

/* =========================================================================
   Reduced motion
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* =========================================================================
   EXPORT HINTS

   Tailwind 3+ (tailwind.config.js):
     theme.extend.colors = {
       primary:       'rgb(234 93 46 / <alpha-value>)',
       'lifted-orange':'rgb(255 138 77 / <alpha-value>)',
       'primary-press':'rgb(200 67 27 / <alpha-value>)',
       petrol:        'rgb(23 58 76 / <alpha-value>)',
       paper:         'rgb(250 250 247 / <alpha-value>)',
       ink:           'rgb(14 20 17 / <alpha-value>)',
       ...
     }

   Style Dictionary / DTCG (design-tokens.json):
     {
       "color": {
         "primary":       { "$value": "#EA5D2E" },
         "lifted-orange": { "$value": "#FF8A4D" },
         ...
       }
     }

   iOS / Android: hex values are stable; consume primitives only. Do not
   port `var()` references — flatten to absolute values per platform.

   Figma: each primitive maps 1:1 to a Color Style. Each semantic and
   component token maps to a Token Studio variable referencing its
   primitive. Never set a Figma fill to a raw hex if a token exists.
   ========================================================================= */
