@import './scroll-fade.css';

/* Inter, self-hosted.
 *
 * Bruno used to ship no font at all, so it rendered in whatever the host had —
 * and with no fallback stack that meant the browser's own default, a serif. The
 * stack below is the safety net; these two faces are the actual fix.
 *
 * Self-hosted rather than pulled from the Google Fonts CDN, on purpose. A CDN
 * @import would send every visitor's IP to Google, which a German court ruled a
 * GDPR breach in 2022 — not a risk worth carrying in a regulated betting
 * product. It would also make first paint depend on a third party and break
 * offline entirely. These files are 134KB together, load from the same origin as
 * the rest of the package, and work with no network.
 *
 * One variable face per subset covers every weight the DS uses (500, 600, 700)
 * and every weight it could, in one request each. latin-ext is included for
 * European team names: Beşiktaş and Crvena zvezda are content this DS shows.
 *
 * Licensed under SIL OFL 1.1, which explicitly permits bundling and
 * redistribution. The licence ships beside the fonts in `fonts/LICENSE.txt`, as
 * OFL requires. Font files are copied to `dist/fonts/` on build, so the URLs
 * below resolve relative to `dist/tokens.css` in a consumer.
 */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  /* swap, not block: a fallback face for a moment beats invisible text, and the
     stack below is chosen so the swap is not a jarring one. */
  font-display: swap;
  src: url('./fonts/inter-variable-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('./fonts/inter-variable-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
    U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}

:root,
:host {
  /* primitives */
  --colour-black: #000000;
  --colour-amber-1: #fffbeb;
  --colour-amber-2: #fef3c7;
  --colour-amber-3: #fde68a;
  --colour-amber-4: #fcd34d;
  --colour-amber-5: #fbbf24;
  --colour-amber-6: #f59e0b;
  --colour-amber-7: #d97706;
  --colour-amber-8: #b45309;
  --colour-amber-9: #92400e;
  --colour-amber-10: #78350f;
  --colour-amber-11: #451a03;
  --colour-amber-12: #361402;
  --colour-green-1: #f7fdf6;
  --colour-green-2: #e6fae5;
  --colour-green-3: #c2f2c3;
  --colour-green-4: #91e794;
  --colour-green-5: #5edc62;
  --colour-green-6: #2dd232;
  --colour-green-7: #00c807;
  --colour-green-8: #05aa06;
  --colour-green-9: #008e02;
  --colour-green-10: #007203;
  --colour-green-11: #015a02;
  --colour-green-12: #014702;
  --colour-grey-dark-1: #111111;
  --colour-grey-dark-2: #191919;
  --colour-grey-dark-3: #222222;
  --colour-grey-dark-4: #2a2a2a;
  --colour-grey-dark-5: #313131;
  --colour-grey-dark-6: #3a3a3a;
  --colour-grey-dark-7: #484848;
  --colour-grey-dark-8: #606060;
  --colour-grey-dark-9: #6e6e6e;
  --colour-grey-dark-10: #7b7b7b;
  --colour-grey-dark-11: #b4b4b4;
  --colour-grey-dark-12: #eeeeee;
  --colour-grey-light-1: #fcfcfc;
  --colour-grey-light-2: #f9f9f9;
  --colour-grey-light-3: #f0f0f0;
  --colour-grey-light-4: #e8e8e8;
  --colour-grey-light-5: #e0e0e0;
  --colour-grey-light-6: #d9d9d9;
  --colour-grey-light-7: #cecece;
  --colour-grey-light-8: #bbbbbb;
  --colour-grey-light-9: #8d8d8d;
  --colour-grey-light-10: #838383;
  --colour-grey-light-11: #646464;
  --colour-grey-light-12: #202020;
  --colour-red-1: #fef2f2;
  --colour-red-2: #fee2e2;
  --colour-red-3: #fecaca;
  --colour-red-4: #fca5a5;
  --colour-red-5: #f87171;
  --colour-red-6: #ef4444;
  --colour-red-7: #dc2626;
  --colour-red-8: #b91c1c;
  --colour-red-9: #991b1b;
  --colour-red-10: #7f1d1d;
  --colour-red-11: #450a0a;
  --colour-red-12: #350808;
  --colour-white: #ffffff;
  --colour-dark-alpha-0: rgba(0, 0, 0, 0);
  --colour-dark-alpha-1: rgba(0, 0, 0, 0.1);
  --colour-dark-alpha-2: rgba(0, 0, 0, 0.2);
  --colour-dark-alpha-3: rgba(0, 0, 0, 0.3);
  --colour-dark-alpha-4: rgba(0, 0, 0, 0.4);
  --colour-dark-alpha-5: rgba(0, 0, 0, 0.5);
  --colour-dark-alpha-6: rgba(0, 0, 0, 0.6);
  --colour-dark-alpha-7: rgba(0, 0, 0, 0.7);
  --colour-dark-alpha-8: rgba(0, 0, 0, 0.8);
  --colour-dark-alpha-9: rgba(0, 0, 0, 0.9);
  --colour-light-alpha-0: rgba(232, 232, 232, 0);
  --colour-light-alpha-1: rgba(232, 232, 232, 0.1);
  --colour-light-alpha-2: rgba(232, 232, 232, 0.2);
  --colour-light-alpha-3: rgba(232, 232, 232, 0.3);
  --colour-light-alpha-4: rgba(232, 232, 232, 0.4);
  --colour-light-alpha-5: rgba(232, 232, 232, 0.5);
  --colour-light-alpha-6: rgba(232, 232, 232, 0.6);
  --colour-light-alpha-7: rgba(232, 232, 232, 0.7);
  --colour-light-alpha-8: rgba(232, 232, 232, 0.8);
  --colour-light-alpha-9: rgba(232, 232, 232, 0.9);
  --border-width-0: 0;
  --border-width-1: 1px;
  --border-width-2: 2px;
  --border-width-4: 4px;
  --border-width-8: 8px;
  /* Each family carries a fallback stack. Figma's variables hold the bare family
     name, and a bare name is a trap in CSS: if the face is not installed and the
     host app has not loaded it, the browser drops to its OWN default, which is a
     serif on every major engine. Bruno ships as a library and does not bundle a
     webfont, so that is the normal case in a consumer that forgot the @font-face,
     and it was showing up as serif headings across the iOS components. The first
     entry is still exactly what Figma specifies; everything after it only ever
     applies when the first is unavailable. */
  --typography-font-family-sans: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
    Helvetica, Arial, sans-serif;
  --typography-font-family-serif: Georgia, 'Times New Roman', Times, serif;
  --typography-font-family-mono: 'Fira Code', ui-monospace, SFMono-Regular, Menlo, Consolas,
    monospace;
  --typography-font-size-xxs: 10px;
  --typography-font-size-xs: 12px;
  --typography-font-size-sm: 14px;
  --typography-font-size-base: 16px;
  --typography-font-size-lg: 18px;
  --typography-font-size-xl: 20px;
  --typography-font-size-2xl: 24px;
  --typography-font-size-3xl: 30px;
  --typography-font-size-4xl: 36px;
  --typography-font-size-5xl: 40px;
  --typography-font-size-6xl: 48px;
  --typography-font-size-7xl: 60px;
  --typography-font-size-8xl: 72px;
  --typography-font-size-9xl: 96px;
  --typography-font-weight-thin: 100;
  --typography-font-weight-extralight: 200;
  --typography-font-weight-light: 300;
  --typography-font-weight-normal: 400;
  --typography-font-weight-medium: 500;
  --typography-font-weight-semibold: 600;
  --typography-font-weight-bold: 700;
  --typography-font-weight-extrabold: 800;
  --typography-font-weight-black: 900;
  --typography-line-height-3: 12px;
  --typography-line-height-4: 16px;
  --typography-line-height-5: 20px;
  --typography-line-height-6: 24px;
  --typography-line-height-7: 28px;
  --typography-line-height-8: 32px;
  --typography-line-height-9: 36px;
  --typography-line-height-10: 40px;
  --typography-line-height-11: 48px;
  --typography-line-height-none: 1;
  --typography-line-height-tight: 1.25;
  --typography-line-height-snug: 1.375;
  --typography-line-height-normal: 1.5;
  --typography-line-height-relaxed: 1.625;
  --typography-line-height-loose: 2;
  --opacity-0: 0%;
  --opacity-5: 5%;
  --opacity-10: 10%;
  --opacity-15: 15%;
  --opacity-20: 20%;
  --opacity-25: 25%;
  --opacity-30: 30%;
  --opacity-35: 35%;
  --opacity-40: 40%;
  --opacity-45: 45%;
  --opacity-50: 50%;
  --opacity-55: 55%;
  --opacity-60: 60%;
  --opacity-65: 65%;
  --opacity-70: 70%;
  --opacity-75: 75%;
  --opacity-80: 80%;
  --opacity-85: 85%;
  --opacity-90: 90%;
  --opacity-95: 95%;
  --opacity-100: 100%;
  --radius-none: 0;
  --radius-xs: 2px;
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 8px;
  --radius-xl: 10px;
  --radius-2xl: 12px;
  --radius-3xl: 16px;
  --radius-4xl: 24px;
  --radius-5xl: 32px;
  --radius-full: 9999px;
  --spacing-0: 0;
  --spacing-px: 1px;
  --spacing-0-5: 2px;
  --spacing-1: 4px;
  --spacing-1-5: 6px;
  --spacing-2: 8px;
  --spacing-2-5: 10px;
  --spacing-3: 12px;
  --spacing-3-5: 14px;
  --spacing-4: 16px;
  --spacing-5: 20px;
  --spacing-6: 24px;
  --spacing-7: 28px;
  --spacing-8: 32px;
  --spacing-9: 36px;
  --spacing-10: 40px;
  --spacing-11: 44px;
  --spacing-12: 48px;
  --spacing-13: 52px;
  --spacing-14: 56px;
  --spacing-15: 60px;
  --spacing-16: 64px;
  --spacing-18: 72px;
  --spacing-19-5: 78px;
  --spacing-20: 80px;
  --spacing-24: 96px;
  --spacing-27: 108px;
  --spacing-27-5: 110px;
  --spacing-28: 112px;
  --spacing-32: 128px;
  --spacing-36: 144px;
  --spacing-40: 160px;
  --spacing-43: 172px;
  --spacing-44: 176px;
  --spacing-48: 192px;
  --spacing-52: 208px;
  --spacing-56: 224px;
  --spacing-57: 228px;
  --spacing-60: 240px;
  --spacing-64: 256px;
  --spacing-70: 280px;
  --spacing-72: 288px;
  --spacing-76: 304px;
  --spacing-80: 320px;
  --spacing-85: 340px;
  --spacing-92-5: 370px;
  --spacing-96: 384px;
  --spacing-97-5: 390px;
  /* breakpoints — the shared screen-size ladder (640px up mirrors Tailwind;
     --breakpoint-2xs/-xs below it are Bruno's own addition, for finer control
     on small/older phones — ds/conventions.md#responsive).
     SOURCE OF TRUTH for designers + screen specs. NOTE: CSS forbids using a
     custom property inside a @container/@media *condition*, so query code must
     repeat the literal px below. Keep the two in sync (src/tokens.breakpoints.test.ts). */
  --breakpoint-2xs: 380px;
  --breakpoint-xs: 420px;
  --breakpoint-sm: 640px;
  --breakpoint-md: 768px;
  --breakpoint-lg: 1024px;
  --breakpoint-xl: 1280px;
  --breakpoint-2xl: 1536px;
  /* Page-layout tokens. PageLayout/GridRow both read --gutter-base only, but not the same
     way: GridRow's own row gap is flat at every width, while PageLayout's own gutter
     (padding-inline, on :host itself, alongside its cap and centring) steps
     once — zero below lg, --gutter-base from lg up (owner decision, 2026-09-12).
     --gutter-md/-lg/-xl remain defined below —
     reserved for a future page wrapper that genuinely needs a growing gutter, not
     currently consumed by any shipped component. --page-max-inline-size may also cap
     a component-owned text measure when ds/conventions.md records the exception
     (currently FeedbackState and AvatarText) — kept deliberately separate from
     --page-layout-max-inline-size below (owner-approved 2026-09-12) so raising PageLayout's
     own page-shell cap never blows out those components' reading width. The canonical
     PageLayout/GridRow/GridItem model lives in ds/conventions.md#responsive, adapted from
     bbc/gel-grid. */
  --page-max-inline-size: 904px;         /* text-measure cap: AvatarText/EmptyState/FeedbackState only */
  --page-layout-max-inline-size: 1536px;   /* PageLayout's own page-shell cap */
  /* Stacking: the four front-to-back levels for things that float over a page, lowest
     first. Named so a component asks for a level instead of guessing a number; the values
     are the ones already in use, so nothing moves (owner decision, 2026-10-19, closing
     2026-09-26 I4 after Table tied with the page header). Layering inside one component
     (Table's pinned column, Sheet's own fades) stays local: those components isolate
     their stacking. Web Modal uses the browser's top layer and needs no level. */
  --layer-page-chrome: 1;    /* web site header, mobile footer: content scrolls under them */
  --layer-docked: 19;        /* floating bet slip, iOS bottom dock */
  --layer-ios-chrome: 20;    /* iOS status bar, tab bar, chat composer */
  --layer-sheet: 100;        /* iOS bottom sheet, over everything including chrome */
  /* The page recipes' fixed header and footer (2026-09-26 audit C5, owner decision 2). */
  --page-layout-chrome-layer: var(--layer-page-chrome);
  /* The shared iOS frame every iOS chrome surface caps itself at (AGENTS.md, iOS).
     Declared once here rather than as each call site's own fallback (09-26 W8); a
     bounded surface such as Sheet overrides it for its subtree. */
  --bruno-ios-frame-inline-size: 402px;
  --gutter-base: var(--spacing-4);  /* 16px — GridRow's gap at every width; PageLayout's own padding-inline from lg up (0 below it) */
  --gutter-md: var(--spacing-6);    /* 24px — reserved, currently unconsumed */
  --gutter-lg: var(--spacing-8);    /* 32px — reserved, currently unconsumed */
  --gutter-xl: var(--spacing-12);   /* 48px — reserved, currently unconsumed */
  --grid-columns: 12;                /* default column count a GridRow divides into; GridItem's span is a fraction of this */
  --icon-size-xs: 12px;
  --icon-size-sm: 14px;
  --icon-size-md: 16px;
  --icon-size-lg: 20px;
  --icon-size-xl: 24px;
  --icon-size-2xl: 28px;
  --icon-size-3xl: 32px;
  --icon-size-4xl: 40px;
  --icon-size-5xl: 64px;
  --icon-size-6xl: 80px;
  --focus-ring-width: 2px;
  --focus-ring-offset: 2px;
  --motion-duration-fast: 150ms;
  --motion-duration-moderate: 300ms;
  --motion-duration-slow: 400ms;

  /* The motion library (2026-11-03): 28 cubic curves, then 10 springs. Every
     Bruno animation uses one of these; the six easings that came before
     (standard, accelerate, decelerate, smooth, snappy, bouncy) were retired the
     same day.

     A cubic curve has no length of its own: pair it with --motion-duration-* or
     a component duration. A spring is the opposite. Its linear() holds a whole
     run of that spring, start to rest, so it only looks right at the -duration
     beside it: played at 300ms, Float (1228ms) runs four times too fast. Always
     use a spring and its duration together.

     Repeats, kept so every name resolves: snappy-out and out-expo are one
     curve, and in-out-base is CSS `ease`. The springs are the damped step
     response x(t) = 1 - e^-zwt (cos wd·t + (zw/wd) sin wd·t), rounded to four
     decimals, sampled over a 1000ms run at 10ms a stop. Every spring ends on an
     explicit `1`: a spring that reaches rest inside that run carries it at the
     stop where it got there (Slow at 50%, so the back half is still), and the
     rest carry it at 100%. Without it, linear() keeps extrapolating past its
     last stop, which drifted LineupAdvertRow's panels 1.3px past rest and
     snapped them back at the end.

     Bouyant, Elegant and Float are the three that were still moving at 1000ms,
     so they are sampled over their own run to rest instead (2308 / 1066 /
     2321ms, same 101 stops) and land on `1` at 100%. Before that they were cut
     off mid-flight — Bouyant finished a 300px travel 1.86px past the target and
     Float 0.96px short, then snapped (2026-11-03 review). Their -durations are
     unchanged, so Bouyant and Float now fit 2.3x as much travel into the same
     length and read that much brisker; Elegant barely overran and is within 7%
     of where it was. Nothing on screen consumed any of the three. */
  --motion-easing-anticipate: cubic-bezier(1, -0.4, 0.35, 0.95);
  --motion-easing-quick-out: cubic-bezier(0, 0, 0.2, 1);
  --motion-easing-overshoot-out: cubic-bezier(0.175, 0.885, 0.32, 1.275);
  --motion-easing-swift-out: cubic-bezier(0.175, 0.885, 0.32, 1.1);
  --motion-easing-snappy-out: cubic-bezier(0.19, 1, 0.22, 1);
  --motion-easing-in-out: cubic-bezier(0.42, 0, 0.58, 1);
  --motion-easing-in-quad: cubic-bezier(0.55, 0.085, 0.68, 0.53);
  --motion-easing-in-cubic: cubic-bezier(0.55, 0.055, 0.675, 0.19);
  --motion-easing-in-quart: cubic-bezier(0.895, 0.03, 0.685, 0.22);
  --motion-easing-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06);
  --motion-easing-in-expo: cubic-bezier(0.95, 0.05, 0.795, 0.035);
  --motion-easing-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.335);
  --motion-easing-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --motion-easing-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
  --motion-easing-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
  --motion-easing-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
  --motion-easing-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
  --motion-easing-out-circ: cubic-bezier(0.075, 0.82, 0.165, 1);
  --motion-easing-in-out-quad: cubic-bezier(0.455, 0.03, 0.515, 0.955);
  --motion-easing-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1);
  --motion-easing-in-out-quart: cubic-bezier(0.77, 0, 0.175, 1);
  --motion-easing-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);
  --motion-easing-in-out-expo: cubic-bezier(1, 0, 0, 1);
  --motion-easing-in-out-circ: cubic-bezier(0.785, 0.135, 0.15, 0.86);
  --motion-easing-in-out-base: cubic-bezier(0.25, 0.1, 0.25, 1);
  --motion-easing-in: cubic-bezier(0.42, 0, 1, 1);
  --motion-easing-out: cubic-bezier(0, 0, 0.58, 1);
  --motion-easing-linear: cubic-bezier(0, 0, 1, 1);

  /* Bouyant: stiffness 900, damping 80, mass 10 */
  --motion-spring-bouyant: linear(
    0, 0.0225, 0.0838, 0.1747, 0.2863, 0.4102, 0.5389, 0.666, 0.7862,
    0.8955, 0.991, 1.0707, 1.1339, 1.1806, 1.2116, 1.2281, 1.2319, 1.2249,
    1.2093, 1.1872, 1.1607, 1.1316, 1.1017, 1.0724, 1.0449, 1.0201, 0.9986,
    0.9807, 0.9667, 0.9566, 0.95, 0.9467, 0.9463, 0.9483, 0.9522, 0.9576,
    0.9639, 0.9707, 0.9776, 0.9844, 0.9906, 0.9963, 1.0011, 1.0051, 1.0082,
    1.0104, 1.0118, 1.0124, 1.0124, 1.0119, 1.0109, 1.0096, 1.0081, 1.0065,
    1.0049, 1.0034, 1.0019, 1.0007, 0.9996, 0.9987, 0.998, 0.9975, 0.9972,
    0.9971, 0.9971, 0.9973, 0.9975, 0.9978, 0.9982, 0.9986, 0.9989, 0.9993,
    0.9996, 0.9999, 1.0001, 1.0003, 1.0005, 1.0006, 1.0007, 1.0007, 1.0007,
    1.0006, 1.0006, 1.0005, 1.0004, 1.0003, 1.0002, 1.0002, 1.0001, 1,
    1, 0.9999, 0.9999, 0.9999, 0.9998, 0.9998, 0.9998, 0.9999, 0.9999,
    0.9999, 1
  );
  --motion-spring-bouyant-duration: 1151ms;
  /* Elegant: stiffness 150, damping 19, mass 1.2 */
  --motion-spring-elegant: linear(
    0, 0.0067, 0.0253, 0.0538, 0.0902, 0.1328, 0.1802, 0.2308, 0.2837,
    0.3377, 0.3919, 0.4457, 0.4983, 0.5494, 0.5983, 0.645, 0.689, 0.7302,
    0.7686, 0.804, 0.8365, 0.866, 0.8928, 0.9167, 0.9381, 0.9569, 0.9734,
    0.9876, 0.9998, 1.0102, 1.0187, 1.0257, 1.0313, 1.0356, 1.0388, 1.041,
    1.0423, 1.0428, 1.0427, 1.0421, 1.041, 1.0395, 1.0378, 1.0358, 1.0337,
    1.0314, 1.0291, 1.0268, 1.0245, 1.0222, 1.02, 1.0179, 1.0159, 1.0139,
    1.0121, 1.0104, 1.0089, 1.0075, 1.0061, 1.005, 1.0039, 1.0029, 1.0021,
    1.0014, 1.0007, 1.0002, 0.9997, 0.9993, 0.999, 0.9987, 0.9985, 0.9984,
    0.9983, 0.9982, 0.9982, 0.9982, 0.9982, 0.9982, 0.9983, 0.9984, 0.9984,
    0.9985, 0.9986, 0.9987, 0.9988, 0.9989, 0.999, 0.9991, 0.9992, 0.9993,
    0.9994, 0.9995, 0.9995, 0.9996, 0.9997, 0.9997, 0.9998, 0.9998, 0.9999,
    0.9999, 1
  );
  --motion-spring-elegant-duration: 582ms;
  /* Bob: stiffness 131.1, damping 2.3, mass 0.1 */
  --motion-spring-bob: linear(
    0, 0.0602, 0.2168, 0.432, 0.6688, 0.8953, 1.0874, 1.2299, 1.3165,
    1.3486, 1.3338, 1.2833, 1.2104, 1.1281, 1.0479, 0.9786, 0.926, 0.8928,
    0.8788, 0.8818, 0.8978, 0.9224, 0.9509, 0.9793, 1.0042, 1.0235, 1.0361,
    1.042, 1.0418, 1.0367, 1.0285, 1.0187, 1.0087, 0.9997, 0.9927, 0.9879,
    0.9855, 0.9853, 0.9868, 0.9896, 0.993, 0.9965, 0.9997, 1.0022, 1.004,
    1.005, 1.0052, 1.0047, 1.0038, 1.0026, 1.0014, 1.0003, 0.9993, 0.9987,
    0.9983, 0.9982, 0.9983, 0.9986, 0.999, 0.9994, 0.9998, 1.0002, 1.0004,
    1.0006, 1.0006, 1.0006, 1.0005, 1.0004, 1.0002, 1.0001 69%,
    1
  );
  --motion-spring-bob-duration: 400ms;
  /* Fling: stiffness 800, damping 80, mass 4 */
  --motion-spring-fling: linear(
    0, 0.0094, 0.0349, 0.0733, 0.1216, 0.1769, 0.2372, 0.3003, 0.3646,
    0.4288, 0.4917, 0.5524, 0.6101, 0.6645, 0.7151, 0.7616, 0.8041, 0.8424,
    0.8766, 0.9068, 0.9333, 0.9561, 0.9756, 0.992, 1.0056, 1.0166, 1.0254,
    1.032, 1.0369, 1.0403, 1.0423, 1.0431, 1.0431, 1.0422, 1.0408, 1.0389,
    1.0366, 1.0341, 1.0314, 1.0286, 1.0258, 1.0231, 1.0204, 1.0179, 1.0155,
    1.0132, 1.0111, 1.0092, 1.0075, 1.0059, 1.0046, 1.0033, 1.0023, 1.0014,
    1.0006, 1 55%,
    1
  );
  --motion-spring-fling-duration: 461ms;
  /* Swift: stiffness 280, damping 18, mass 0.3 */
  --motion-spring-swift: linear(
    0, 0.0383, 0.1263, 0.2354, 0.3486, 0.456, 0.5529, 0.6372, 0.7087,
    0.7683, 0.8171, 0.8566, 0.8883, 0.9135, 0.9333, 0.9488, 0.9609, 0.9703,
    0.9775, 0.983, 0.9872, 0.9904, 0.9928, 0.9947, 0.996, 0.9971, 0.9978,
    0.9984, 0.9988, 0.9992, 0.9994, 0.9996, 0.9997, 0.9998, 0.9998, 0.9999,
    0.9999 36%,
    1
  );
  --motion-spring-swift-duration: 154ms;
  /* Float: stiffness 290, damping 15, mass 2 */
  --motion-spring-float: linear(
    0, 0.0366, 0.1361, 0.2811, 0.4542, 0.6385, 0.8191, 0.9838, 1.1233,
    1.2317, 1.3063, 1.3472, 1.3568, 1.3394, 1.3007, 1.2467, 1.1838, 1.1178,
    1.054, 0.9966, 0.9485, 0.9118, 0.8873, 0.8747, 0.873, 0.8807, 0.8956,
    0.9156, 0.9384, 0.9619, 0.9844, 1.0044, 1.0209, 1.0333, 1.0413, 1.0451,
    1.0451, 1.0419, 1.0362, 1.0288, 1.0206, 1.0122, 1.0043, 0.9973, 0.9917,
    0.9875, 0.9849, 0.9838, 0.984, 0.9853, 0.9875, 0.9902, 0.9932, 0.9961,
    0.9989, 1.0013, 1.0033, 1.0047, 1.0055, 1.0058, 1.0057, 1.0051, 1.0043,
    1.0033, 1.0023, 1.0012, 1.0002, 0.9994, 0.9987, 0.9983, 0.998, 0.9979,
    0.998, 0.9982, 0.9985, 0.9989, 0.9993, 0.9996, 1, 1.0003, 1.0005,
    1.0006, 1.0007, 1.0007, 1.0007, 1.0006, 1.0005, 1.0004, 1.0002, 1.0001,
    1, 0.9999, 0.9998, 0.9998, 0.9997, 0.9997, 0.9998, 0.9998, 0.9998,
    0.9999, 1
  );
  --motion-spring-float-duration: 1228ms;
  /* Slow: stiffness 26.7, damping 4.1, mass 0.2 */
  --motion-spring-slow: linear(
    0, 0.0062, 0.0233, 0.049, 0.0814, 0.1188, 0.1599, 0.2036, 0.2487,
    0.2946, 0.3404, 0.3857, 0.4301, 0.473, 0.5144, 0.5539, 0.5915, 0.6271,
    0.6606, 0.6919, 0.7212, 0.7484, 0.7735, 0.7968, 0.8182, 0.8378, 0.8557,
    0.8721, 0.8869, 0.9004, 0.9126, 0.9236, 0.9334, 0.9423, 0.9502, 0.9572,
    0.9634, 0.969, 0.9738, 0.9781, 0.9819, 0.9852, 0.988, 0.9905, 0.9926,
    0.9944, 0.996, 0.9973, 0.9984, 0.9993, 1.0001 50%,
    1
  );
  --motion-spring-slow-duration: 449ms;
  /* Snap: stiffness 320, damping 20, mass 0.4 */
  --motion-spring-snap: linear(
    0, 0.0339, 0.1148, 0.2193, 0.3315, 0.4413, 0.5429, 0.6331, 0.7107,
    0.7759, 0.8295, 0.8726, 0.9068, 0.9333, 0.9536, 0.9688, 0.9799, 0.988,
    0.9936, 0.9974, 0.9999, 1.0014, 1.0022, 1.0026, 1.0026, 1.0025, 1.0023,
    1.002, 1.0017, 1.0014, 1.0011, 1.0009, 1.0007, 1.0006, 1.0004, 1.0003,
    1.0002, 1.0002, 1.0001, 1.0001 39%,
    1
  );
  --motion-spring-snap-duration: 184ms;
  /* Stern: stiffness 550, damping 30, mass 1.2 */
  --motion-spring-stern: linear(
    0, 0.021, 0.077, 0.1578, 0.2548, 0.3605, 0.4686, 0.5742, 0.6737,
    0.7644, 0.8445, 0.9132, 0.9702, 1.0158, 1.0507, 1.0758, 1.0923, 1.1014,
    1.1044, 1.1025, 1.0969, 1.0886, 1.0786, 1.0676, 1.0563, 1.0453, 1.0348,
    1.0253, 1.0168, 1.0096, 1.0035, 0.9987, 0.9949, 0.9923, 0.9905, 0.9895,
    0.9891, 0.9893, 0.9898, 0.9907, 0.9917, 0.9929, 0.994, 0.9952, 0.9963,
    0.9973, 0.9982, 0.9989, 0.9996, 1.0001, 1.0005, 1.0008, 1.001, 1.0011,
    1.0011, 1.0011, 1.0011, 1.001, 1.0009, 1.0008, 1.0006, 1.0005, 1.0004,
    1.0003, 1.0002, 1.0001, 1 66%,
    1
  );
  --motion-spring-stern-duration: 368ms;
  /* Boingoingoing: stiffness 1000, damping 1.5, mass 0.1 */
  --motion-spring-boingoingoing: linear(
    0, 0.4379, 1.2948, 1.7806, 1.5323, 0.8641, 0.405, 0.5179, 1.0266,
    1.4418, 1.4219, 1.0446, 0.6818, 0.6412, 0.9126, 1.2208, 1.2976, 1.1096,
    0.8542, 0.7589, 0.8827, 1.0894, 1.191, 1.1154, 0.9517, 0.8521, 0.8926,
    1.0192, 1.1117, 1.096, 1.0005, 0.9179, 0.9169, 0.987, 1.0584, 1.07,
    1.0202, 0.9601, 0.9424, 0.9764, 1.0258, 1.0463, 1.0244, 0.9848, 0.9636,
    0.9765, 1.0076, 1.0279, 1.0215, 0.9977, 0.9791, 0.981, 0.9988, 1.0152,
    1.0163, 1.0033, 0.9893, 0.9864, 0.9955, 1.0072, 1.0111, 1.005, 0.9955,
    0.9911, 0.995, 1.0025, 1.0069, 1.0048, 0.9989, 0.9947, 0.9957, 1.0002,
    1.0039, 1.0038, 1.0004, 0.9972, 0.9968, 0.9992, 1.0019, 1.0026, 1.001,
    0.9987, 0.9979, 0.9989, 1.0008, 1.0017, 1.001, 0.9996, 0.9987, 0.999,
    1.0002, 1.001, 1.0009, 1 93%,
    1
  );
  --motion-spring-boingoingoing-duration: 614ms;

  /* shadows (theme-invariant; from Figma effect styles shadow/*) */
  --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.05), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
  --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
  --shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  --shadow-none: 0 0 #0000;
  /* blur: backdrop blur radii, from the Figma effect styles (BACKGROUND_BLUR), kept like
     the shadow scale above. Started 2026-09-23 with SiteHeader's frost (owner-approved).
     Figma's blur value is twice the CSS blur() radius that renders the same: blur/sm is
     8 in Figma and 4px here, the value Figma's own code export gives. */
  --blur-sm: 4px;

  /*
   * theme: Light — semantic colour usage contract
   *
   * The structured comments in this block are the canonical source of truth
   * for semantic colour meaning. Read them before choosing colour for a new
   * component, then create a component-owned alias to the matching semantic
   * token. Dark theme declarations inherit this intent and only change values.
   */
  /**
   * @meaning Default neutral surface for cards, rows, and resting controls.
   * @use Component containers placed on the page canvas.
   * @avoid Page backgrounds, selected states, and destructive actions.
   * @pair --fg-primary, --border-primary.
   * @theme Changes between Light and Dark themes.
   */
  --bg-primary: var(--colour-grey-light-2);
  /**
   * @meaning Subordinate neutral surface one step stronger than the default component surface.
   * @use Nested regions, secondary controls, and grouped content within a primary surface.
   * @avoid Page canvases and regions that need stronger tertiary or brand emphasis.
   * @pair --fg-primary, --border-secondary.
   * @theme Changes between Light and Dark themes.
   */
  --bg-secondary: var(--colour-grey-light-3);
  /**
   * @meaning Highest-emphasis brand surface used to make a primary action or state dominant.
   * @use Primary actions, selected controls, and compact brand-emphasis regions.
   * @avoid General card backgrounds and low-priority content.
   * @pair --fg-accent-brand, --border-accent.
   * @theme Inverts between black in Light and white in Dark.
   */
  --bg-accent-brand: var(--colour-black);
  /**
   * @meaning Strong positive surface communicating success, a win, or a confirmed positive outcome.
   * @use Positive badges, chart fills, and high-emphasis success regions.
   * @avoid Neutral selection, decoration, and warning or destructive states.
   * @pair --fg-on-dark, --border-positive.
   * @theme Changes between Light and Dark themes.
   * @constraint White small text may not reach WCAG AA on every resolved green; validate text contrast for the rendered context.
   */
  --bg-positive-primary: var(--colour-green-8);
  /**
   * @meaning Subtle default boundary between a component surface and adjacent content.
   * @use Card outlines, row dividers, and separators on primary or page surfaces.
   * @avoid Boundaries that need selected, positive, negative, or stronger neutral emphasis.
   * @pair --bg-primary, --bg-page.
   * @theme Changes between Light and Dark themes.
   */
  --border-primary: var(--colour-grey-light-3);
  /**
   * @meaning Medium neutral boundary stronger than the default separator.
   * @use Dividers or outlines that must remain visible between neighbouring neutral surfaces.
   * @avoid Focus indicators and semantic positive or negative boundaries.
   * @pair --bg-primary, --bg-secondary.
   * @theme Changes between Light and Dark themes.
   */
  --border-secondary: var(--colour-grey-light-4);
  /**
   * @meaning Application page canvas behind all component surfaces.
   * @use View and screen backgrounds.
   * @avoid Cards, rows, resting controls, and nested component containers.
   * @pair --fg-primary, --bg-primary.
   * @theme Changes between Light and Dark themes.
   */
  --bg-page: var(--colour-white);
  /**
   * @meaning Positive foreground for success text, icons, and outcome indicators.
   * @use Concise positive labels, icons, and data marks on neutral surfaces.
   * @avoid Large filled regions, neutral emphasis, and negative messaging.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   * @constraint Do not assume this colour passes WCAG AA for small text; use it for text only after checking contrast in context.
   */
  --fg-positive: var(--colour-green-8);
  /**
   * @meaning Highest-emphasis foreground for primary content.
   * @use Titles, body copy, key values, and primary icons on neutral surfaces.
   * @avoid Disabled content and deliberately subordinate metadata.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   */
  --fg-primary: var(--colour-grey-light-12);
  /**
   * @meaning Secondary foreground for supporting content with reduced emphasis.
   * @use Metadata, secondary labels, helper copy, and supporting icons.
   * @avoid Primary instructions, disabled content, and text on fixed dark or light contexts.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   */
  --fg-secondary: var(--colour-grey-light-11);
  /**
   * @meaning Positive boundary signalling success or a confirmed positive state.
   * @use Outlines, dividers, and indicator edges that accompany positive content.
   * @avoid Using a border as the only signal of success.
   * @pair --bg-positive-primary, --fg-positive.
   * @theme Changes between Light and Dark themes.
   */
  --border-positive: var(--colour-green-8);
  /**
   * @meaning Brand-emphasis boundary for selected or accent regions.
   * @use Outlines paired with the brand accent surface or strong brand selection.
   * @avoid Keyboard focus indication and general card separation.
   * @pair --bg-accent-brand, --fg-accent-brand.
   * @theme Inverts between black in Light and white in Dark.
   */
  --border-accent: var(--colour-black);
  /**
   * @meaning Strong negative surface communicating error, loss, or a destructive action.
   * @use Destructive controls, error badges, and high-emphasis negative states.
   * @avoid Neutral selection, warnings, and decorative red accents.
   * @pair --fg-on-dark, --border-negative.
   * @theme Fixed to the same red across Light and Dark themes.
   */
  --bg-negative: var(--colour-red-7);
  /**
   * @meaning Negative boundary for an error, loss, or destructive state.
   * @use Error outlines and dividers that accompany explicit negative text or icons.
   * @avoid Using a border as the only signal of an error.
   * @pair --bg-negative, --fg-negative.
   * @theme Fixed to the same red across Light and Dark themes.
   */
  --border-negative: var(--colour-red-7);
  /**
   * @meaning Negative foreground for error, loss, and destructive messaging.
   * @use Error labels, destructive icons, and concise negative status indicators on neutral surfaces.
   * @avoid Filled negative regions and decorative red details without semantic meaning.
   * @pair --bg-page, --bg-primary.
   * @theme Fixed to the same red across Light and Dark themes.
   */
  --fg-negative: var(--colour-red-7);
  /**
   * @meaning Inactive surface showing that a control or region is unavailable.
   * @use Disabled control backgrounds and unavailable placeholders.
   * @avoid Resting neutral surfaces and read-only content that remains perceivable.
   * @pair --fg-disabled, --border-secondary.
   * @theme Changes between Light and Dark themes.
   */
  --bg-disabled: var(--colour-grey-light-4);
  /**
   * @meaning Deliberately low-emphasis foreground for unavailable content.
   * @use Labels and icons inside disabled controls when another cue also communicates the state.
   * @avoid Essential information, helper text, and any interactive enabled state.
   * @pair --bg-disabled, --bg-page.
   * @theme Changes between Light and Dark themes.
   * @constraint Disabled contrast is intentionally reduced and is not a substitute for disabled semantics or another non-colour cue.
   */
  --fg-disabled: var(--colour-grey-light-8);
  /**
   * @meaning Strong neutral surface for elevated hierarchy, prominent headers, and tertiary controls.
   * @use Header bands, tertiary controls, and regions needing more separation than secondary surfaces.
   * @avoid Page canvases and high-emphasis brand or status states.
   * @pair --fg-primary, --border-tertiary.
   * @theme Changes between Light and Dark themes.
   */
  --bg-tertiary: var(--colour-grey-light-4);
  /**
   * @meaning Strongest neutral surface in the progressive surface ladder.
   * @use Compact selected-neutral states and deeply nested regions needing maximum neutral separation.
   * @avoid Brand selection, destructive actions, and broad page areas.
   * @pair --fg-primary, --border-tertiary.
   * @theme Changes between Light and Dark themes.
   */
  --bg-quaternary: var(--colour-grey-light-5);
  /**
   * @meaning Strong neutral boundary at the top of the neutral border hierarchy.
   * @use Outlines and dividers that must stand apart from primary and secondary borders.
   * @avoid Focus rings and positive, negative, or brand state boundaries.
   * @pair --bg-tertiary, --bg-quaternary.
   * @theme Changes between Light and Dark themes.
   */
  --border-tertiary: var(--colour-grey-light-5);
  /**
   * @meaning Foreground designed specifically for the current brand accent surface.
   * @use Labels and icons placed directly on --bg-accent-brand.
   * @avoid Neutral surfaces and fixed light or dark media contexts.
   * @pair --bg-accent-brand, --border-accent.
   * @theme Inverts between white in Light and black in Dark.
   */
  --fg-accent-brand: var(--colour-white);
  /**
   * @meaning Fixed white foreground for content known to sit on a dark backdrop.
   * @use Text and icons on dark media, black surfaces, or dark outcome fills.
   * @avoid Theme-responsive neutral surfaces and backdrops whose luminance is unknown.
   * @pair --bg-on-light, --bg-negative.
   * @theme Fixed across Light and Dark themes.
   */
  --fg-on-dark: var(--colour-white);
  /**
   * @meaning Foreground for the inverse brand accent surface and inverse active states.
   * @use Labels and icons placed directly on --bg-accent-brand-inverted.
   * @avoid The standard brand accent surface and general neutral content.
   * @pair --bg-accent-brand-inverted, --border-accent-inverted.
   * @theme Inverts between black in Light and white in Dark.
   */
  --fg-accent-brand-inverted: var(--colour-black);
  /**
   * @meaning Inverse of the current brand accent surface for pressed or reversed brand contexts.
   * @use Inverse active states and regions intentionally reversing the normal brand polarity.
   * @avoid Default brand actions and ordinary neutral cards.
   * @pair --fg-accent-brand-inverted, --border-accent-inverted.
   * @theme Inverts between white in Light and black in Dark.
   */
  --bg-accent-brand-inverted: var(--colour-white);
  /**
   * @meaning Boundary designed for the inverse brand accent surface.
   * @use Outlines paired with --bg-accent-brand-inverted.
   * @avoid Standard accent regions, neutral separation, and focus indication.
   * @pair --bg-accent-brand-inverted, --fg-accent-brand-inverted.
   * @theme Inverts between white in Light and black in Dark.
   */
  --border-accent-inverted: var(--colour-white);
  /**
   * @meaning Tertiary foreground for low-priority but still available content.
   * @use De-emphasised icons, tertiary labels, and subtle metadata.
   * @avoid Primary instructions, disabled states, and text that must meet stronger contrast.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   */
  --fg-tertiary: var(--colour-grey-light-10);
  /**
   * @meaning Fixed black foreground for content known to sit on a light backdrop.
   * @use Text and icons on white media, pale artwork, or fixed light status surfaces.
   * @avoid Theme-responsive neutral surfaces and backdrops whose luminance is unknown.
   * @pair --bg-on-dark, --bg-accent-light-green.
   * @theme Fixed across Light and Dark themes.
   */
  --fg-on-light: var(--colour-black);
  /**
   * @meaning Fixed light surface for elements deliberately placed within a dark context.
   * @use White chips, cut-outs, or inverse blocks on known dark backdrops.
   * @avoid Theme-responsive component cards and the page canvas.
   * @pair --fg-on-light, --border-accent-inverted.
   * @theme Fixed across Light and Dark themes.
   */
  --bg-on-dark: var(--colour-white);
  /**
   * @meaning Deeper positive surface for layered success graphics and secondary positive emphasis.
   * @use Secondary bands or details within a positive composition.
   * @avoid Default success surfaces, neutral cards, and standalone text backgrounds without contrast review.
   * @pair --fg-on-dark, --bg-positive-primary.
   * @theme Changes between Light and Dark themes.
   */
  --bg-positive-secondary: var(--colour-green-10);
  /**
   * @meaning Yellow status foreground for warnings, favourites, and card indicators.
   * @use Small icons and marks whose surrounding text also explains the state.
   * @avoid Body text, large surfaces, and decoration with no status meaning.
   * @pair --bg-page, --bg-primary.
   * @theme Fixed across Light and Dark themes.
   * @constraint Contrast varies by surface and is not guaranteed for text; pair with a textual or structural status cue.
   */
  --fg-accent-yellow: var(--colour-amber-6);
  /**
   * @meaning Red status foreground for card events or specialised negative indicators.
   * @use Small semantic marks and icons on neutral surfaces.
   * @avoid General destructive copy when --fg-negative expresses the intent more clearly.
   * @pair --bg-page, --bg-primary.
   * @theme Fixed across Light and Dark themes.
   * @constraint Colour must not be the only status cue.
   */
  --fg-accent-red: var(--colour-red-7);
  /**
   * @meaning Yellow status surface for warning or card-event cells.
   * @use Compact status fills with an explicit label or icon.
   * @avoid General highlights and text-only warnings without contrast validation.
   * @pair --fg-on-dark, --fg-on-light.
   * @theme Fixed across Light and Dark themes.
   * @constraint Choose the fixed foreground that contrasts with the resolved surface and verify it in context.
   */
  --bg-accent-yellow: var(--colour-amber-6);
  /**
   * @meaning Red status surface for specialised negative events distinct from generic error UI.
   * @use Compact card-event cells and domain-specific negative marks.
   * @avoid Destructive controls when --bg-negative is the clearer semantic role.
   * @pair --fg-on-dark, --border-negative.
   * @theme Fixed across Light and Dark themes.
   */
  --bg-accent-red: var(--colour-red-7);
  /**
   * @meaning Positive chart fill for won, successful, or above-target data.
   * @use Filled bars, cells, and chart regions that encode a positive outcome.
   * @avoid Success messages outside data visualisation and foreground strokes.
   * @pair --fg-chart-positive, --fg-on-dark.
   * @theme Changes between Light and Dark themes.
   * @constraint Charts must also expose the outcome through labels, position, or another non-colour cue.
   */
  --bg-chart-positive: var(--colour-green-8);
  /**
   * @meaning Opaque end of the primary neutral fade used to soften a content edge.
   * @use As the start stop of a gradient paired with --gradient-primary-end.
   * @avoid Standalone fills and gradients with unrelated end tokens.
   * @pair --gradient-primary-end, --bg-primary.
   * @theme Changes polarity between Light and Dark themes.
   */
  --gradient-primary-start: var(--colour-light-alpha-8);
  /**
   * @meaning Transparent end of the primary neutral content-edge fade.
   * @use As the end stop of a gradient paired with --gradient-primary-start.
   * @avoid Standalone fills and gradients with unrelated start tokens.
   * @pair --gradient-primary-start, --bg-primary.
   * @theme Changes polarity between Light and Dark themes.
   */
  --gradient-primary-end: var(--colour-light-alpha-0);
  /**
   * @meaning First stop of the positive statistics gradient.
   * @use As the start stop of a positive data or insight gradient.
   * @avoid Neutral fades and gradients with unrelated end tokens.
   * @pair --gradient-stat-end, --fg-on-dark.
   * @theme Fixed across Light and Dark themes.
   */
  --gradient-stat-start: var(--colour-green-8);
  /**
   * @meaning Second stop of the positive statistics gradient.
   * @use As the end stop paired with --gradient-stat-start.
   * @avoid Neutral fades and gradients with unrelated start tokens.
   * @pair --gradient-stat-start, --fg-on-dark.
   * @theme Fixed across Light and Dark themes.
   */
  --gradient-stat-end: var(--colour-green-6);
  /**
   * @meaning Opaque end of the secondary surface-to-transparent fade.
   * @use As the start stop of an insight or overlay gradient paired with --gradient-secondary-end.
   * @avoid Primary content-edge fades and gradients with unrelated end tokens.
   * @pair --gradient-secondary-end, --fg-primary.
   * @theme Changes between white in Light and black in Dark.
   */
  --gradient-secondary-start: var(--colour-white);
  /**
   * @meaning Transparent end of the secondary surface fade.
   * @use As the end stop paired with --gradient-secondary-start.
   * @avoid Primary content-edge fades and gradients with unrelated start tokens.
   * @pair --gradient-secondary-start, --fg-primary.
   * @theme Changes polarity between Light and Dark themes.
   */
  --gradient-secondary-end: var(--colour-light-alpha-0);
  /**
   * @meaning Fixed pale-green decorative surface for positive artwork and patterns.
   * @use Non-textual branded artwork layers and positive decorative shapes.
   * @avoid Success messaging, interactive states, and general component surfaces.
   * @pair --fg-on-light, --bg-page.
   * @theme Fixed across Light and Dark themes.
   * @constraint This specialised art colour is not a general-purpose accessible background.
   */
  --bg-accent-light-green: var(--colour-green-5);
  /**
   * @meaning Fixed dark surface for elements deliberately placed within a light context.
   * @use Black chips, cut-outs, or inverse blocks on known light backdrops.
   * @avoid Theme-responsive component cards and the page canvas.
   * @pair --fg-on-dark, --border-accent.
   * @theme Fixed across Light and Dark themes.
   */
  --bg-on-light: var(--colour-black);
  /**
   * @meaning Neutral chart fill for lost, unsuccessful, or comparison data.
   * @use Filled bars and cells encoding a non-positive chart outcome.
   * @avoid Generic disabled UI and negative error states.
   * @pair --fg-chart-negative, --fg-secondary.
   * @theme Changes between Light and Dark themes.
   * @constraint Charts must expose the outcome through labels, position, or another non-colour cue.
   */
  --bg-chart-negative: var(--colour-grey-light-4);
  /**
   * @meaning Positive chart foreground for axes, strokes, and data marks.
   * @use Chart lines, axes, labels, and marks that encode a positive outcome.
   * @avoid General success copy and filled chart regions.
   * @pair --bg-chart-positive, --bg-page.
   * @theme Changes between Light and Dark themes.
   * @constraint Validate thin strokes and small labels against their actual chart background.
   */
  --fg-chart-positive: var(--colour-green-8);
  /**
   * @meaning Neutral chart foreground for axes and marks representing a lost outcome.
   * @use Non-positive chart strokes and axes where a neutral, not destructive, meaning is intended.
   * @avoid Body text, error messaging, and fills outside data visualisation.
   * @pair --bg-chart-negative, --fg-secondary.
   * @theme Changes between Light and Dark themes.
   * @constraint This low-emphasis token may not meet text contrast requirements; do not use it for essential labels.
   */
  --fg-chart-negative: var(--colour-grey-light-4);
  /**
   * @meaning Lowest-emphasis available foreground in the neutral emphasis ladder.
   * @use Resting utility icons and non-essential details that remain enabled.
   * @avoid Body copy, instructions, disabled content, and essential controls.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   * @constraint Use only where low contrast is intentional and the information is available elsewhere.
   */
  --fg-quaternary: var(--colour-grey-light-9);
  /**
   * @meaning Hovered state of a primary-foreground text control.
   * @use Pointer hover on text links and text buttons whose resting colour is --fg-primary.
   * @avoid Resting copy, and hover on filled or outlined buttons, which have their own state tokens.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   */
  --fg-primary-hover: var(--colour-grey-light-11);
  /**
   * @meaning Hovered state of a secondary-foreground text control.
   * @use Pointer hover on text links and text buttons whose resting colour is --fg-secondary.
   * @avoid Resting copy, and hover on filled or outlined buttons.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   * @constraint Light mode is a governed contrast residual on --bg-page; never the only cue that a control is interactive.
   */
  --fg-secondary-hover: var(--colour-grey-light-10);
  /**
   * @meaning Hovered state of a tertiary-foreground text control.
   * @use Pointer hover on text links and text buttons whose resting colour is --fg-tertiary.
   * @avoid Resting copy, and hover on filled or outlined buttons.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   * @constraint Light mode is a governed contrast residual on --bg-page; never the only cue that a control is interactive.
   */
  --fg-tertiary-hover: var(--colour-grey-light-9);
  /**
   * @meaning Hovered state of an accent-inverted text control.
   * @use Pointer hover on text links and text buttons whose resting colour is --fg-accent-brand-inverted.
   * @avoid Resting copy, and accent fills, which keep --bg-accent-brand-inverted.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   */
  --fg-accent-brand-inverted-hover: var(--colour-grey-dark-4);
  /**
   * @meaning Hovered state of a destructive text control.
   * @use Pointer hover on text links and text buttons whose resting colour is --fg-negative.
   * @avoid Error copy and status icons, which stay on --fg-negative.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   * @constraint Red must not be the only cue that an action is destructive.
   */
  --fg-negative-hover: var(--colour-red-6);
  /**
   * @meaning Green accent foreground for positive trends and domain-specific positive emphasis.
   * @use Trend labels, positive icons, and concise accent marks on neutral surfaces.
   * @avoid Generic success copy when --fg-positive is the clearer role.
   * @pair --bg-page, --bg-primary.
   * @theme Changes between Light and Dark themes.
   * @constraint Colour must not be the only cue for trend direction.
   */
  --fg-accent-green: var(--colour-green-8);
  /**
   * @meaning Green accent surface for positive trend icons and specialised branded status marks.
   * @use Compact positive-trend icon containers and domain-specific accent fills.
   * @avoid General success regions and neutral selected states.
   * @pair --fg-on-dark, --fg-accent-green.
   * @theme Changes between Light and Dark themes.
   */
  --bg-accent-green: var(--colour-green-8);
  /**
   * @meaning High-visibility keyboard focus indication for the current theme.
   * @use Focus rings around interactive elements using the shared ring width and offset tokens.
   * @avoid Borders, selected states, and non-keyboard decorative outlines.
   * @pair --bg-page, --bg-primary.
   * @theme Inverts between black in Light and white in Dark.
   * @constraint Preserve a visible offset and verify the ring against both the control and its surrounding surface.
   */
  --focus-ring-colour: var(--colour-black);
  /**
   * @meaning Translucent hover overlay calibrated for the default neutral surface.
   * @use Layered over --bg-primary for pointer hover feedback.
   * @avoid Standalone backgrounds and hover states on other base surfaces.
   * @pair --bg-primary, --fg-primary.
   * @theme Changes polarity between Light and Dark themes.
   * @constraint Composite this token over its named base; its resolved alpha colour is not meaningful alone.
   */
  --bg-primary-hover: var(--colour-dark-alpha-1);
  /**
   * @meaning Translucent hover overlay calibrated for the secondary neutral surface.
   * @use Layered over --bg-secondary for pointer hover feedback.
   * @avoid Standalone backgrounds and hover states on other base surfaces.
   * @pair --bg-secondary, --fg-primary.
   * @theme Changes polarity between Light and Dark themes.
   * @constraint Composite this token over its named base; its resolved alpha colour is not meaningful alone.
   */
  --bg-secondary-hover: var(--colour-dark-alpha-1);
  /**
   * @meaning Translucent hover overlay calibrated for the tertiary neutral surface.
   * @use Layered over --bg-tertiary for pointer hover feedback.
   * @avoid Standalone backgrounds and hover states on other base surfaces.
   * @pair --bg-tertiary, --fg-primary.
   * @theme Changes polarity between Light and Dark themes.
   * @constraint Composite this token over its named base; its resolved alpha colour is not meaningful alone.
   */
  --bg-tertiary-hover: var(--colour-dark-alpha-1);
  /**
   * @meaning Translucent hover overlay calibrated for the brand accent surface.
   * @use Layered over --bg-accent-brand for pointer hover feedback.
   * @avoid Standalone backgrounds and hover states on neutral or negative bases.
   * @pair --bg-accent-brand, --fg-accent-brand.
   * @theme Changes polarity between Light and Dark themes.
   * @constraint Composite this token over its named base; its resolved alpha colour is not meaningful alone.
   */
  --bg-accent-brand-hover: var(--colour-light-alpha-2);
  /**
   * @meaning Translucent hover overlay calibrated for the negative surface.
   * @use Layered over --bg-negative for destructive-control hover feedback.
   * @avoid Standalone backgrounds and hover states on brand or neutral bases.
   * @pair --bg-negative, --fg-on-dark.
   * @theme Declared in both themes and currently resolves to the same light overlay.
   * @constraint Composite this token over its named base; its resolved alpha colour is not meaningful alone.
   */
  --bg-negative-hover: var(--colour-light-alpha-2);
  /**
   * @meaning Translucent neutral overlay tint composited over arbitrary, independently scrolling content.
   * @use As a decorative fill for a control that floats above content it does not own, such as an overlay scrollbar thumb.
   * @avoid Standalone backgrounds on a known, fixed surface — use a --bg-* surface token instead.
   * @pair --bg-page, --bg-primary.
   * @theme Lighter in Light than in Dark, so it stays legible against either page background.
   * @constraint Composite this token over the content behind it; its resolved alpha colour is not meaningful alone.
   */
  --bg-overlay: var(--colour-light-alpha-6);

  /* components */
  --bruno-logo-icon: var(--fg-accent-brand-inverted);
  /* Badge. Figma calls these component variables tag/* and carries stale
     status-message code syntax; the verified alias targets are translated into
     Badge-owned names here (badge-spec D4/D5). */
  --badge-background-neutral: var(--bg-tertiary);
  --badge-background-positive: var(--bg-positive-primary);
  --badge-background-warning: var(--bg-accent-yellow);
  --badge-background-negative: var(--bg-negative);
  --badge-label-primary: var(--fg-primary);
  --badge-label-on-dark: var(--fg-on-dark);
  --button-accent-background: var(--bg-accent-brand);
  --button-accent-label: var(--fg-accent-brand);
  --button-negative-background: var(--bg-negative);
  --button-negative-label: var(--fg-on-dark);
  --button-primary-background: var(--bg-primary);
  --button-primary-label: var(--fg-primary);
  --button-ghost-label: var(--fg-primary);
  --button-secondary-background: var(--bg-secondary);
  --button-secondary-label: var(--fg-primary);
  --button-tertiary-background: var(--bg-tertiary);
  --button-tertiary-label: var(--fg-primary);
  --button-label-disabled: var(--fg-disabled);
  --button-background-disabled: var(--bg-disabled);
  --button-primary-background-active: var(--bg-accent-brand);
  --button-primary-label-active: var(--fg-accent-brand);
  --button-secondary-background-active: var(--bg-accent-brand);
  --button-secondary-label-active: var(--fg-accent-brand);
  --button-tertiary-background-active: var(--bg-accent-brand);
  --button-tertiary-label-active: var(--fg-accent-brand);
  --button-accent-background-active: var(--bg-accent-brand-inverted);
  --button-accent-label-active: var(--fg-accent-brand-inverted);
  --button-negative-background-active: var(--bg-negative);
  --button-negative-label-active: var(--fg-on-dark);
  --button-ghost-label-active: var(--fg-primary);
  --button-ghost-background-active: var(--bg-secondary);
  --button-primary-background-hover: var(--bg-primary-hover);
  --button-secondary-background-hover: var(--bg-secondary-hover);
  --button-tertiary-background-hover: var(--bg-tertiary-hover);
  --button-ghost-background-hover: var(--bg-primary-hover);
  --button-accent-background-hover: var(--bg-accent-brand-hover);
  --button-negative-background-hover: var(--bg-negative-hover);
  --odds-button-background: var(--bg-tertiary);
  --odds-button-label-primary: var(--fg-primary);
  --odds-button-background-disabled: var(--bg-disabled);
  --odds-button-label-disabled: var(--fg-disabled);
  --odds-button-background-active: var(--bg-accent-brand);
  --odds-button-label-active: var(--fg-accent-brand);
  --odds-button-label-secondary: var(--fg-secondary);
  --odds-button-background-hover: var(--bg-tertiary-hover);
  /* Figma: the `bookmaker-button` variable collection. Each name and each alias below is the
     collection's own; the card's palette coincides with OddsButton today but is not borrowed
     from it, so a future restyle of one cannot silently move the other. There is deliberately
     no -active-hover alias: the chosen card does not react to hover (bookmaker-button-spec D11). */
  --bookmaker-button-background: var(--bg-tertiary);
  --bookmaker-button-background-hover: var(--bg-tertiary-hover);
  --bookmaker-button-background-active: var(--bg-accent-brand);
  --bookmaker-button-background-disabled: var(--bg-disabled);
  --bookmaker-button-label-primary: var(--fg-primary);
  --bookmaker-button-label-secondary: var(--fg-secondary);
  --bookmaker-button-label-active: var(--fg-accent-brand);
  --bookmaker-button-label-disabled: var(--fg-disabled);
  --player-button-background: var(--bg-tertiary);
  --player-button-background-hover: var(--bg-tertiary-hover);
  --player-button-background-active: var(--bg-accent-brand);
  --player-button-background-disabled: var(--bg-disabled);
  --player-button-label: var(--fg-secondary);
  --player-button-label-active: var(--fg-primary);
  --player-button-label-disabled: var(--fg-disabled);
  --pill-button-primary-background: var(--bg-primary);
  --pill-button-primary-label: var(--fg-primary);
  --pill-button-secondary-background: var(--bg-secondary);
  --pill-button-secondary-label: var(--fg-primary);
  --pill-button-tertiary-background: var(--bg-tertiary);
  --pill-button-tertiary-label: var(--fg-primary);
  --pill-button-accent-background: var(--bg-accent-brand);
  --pill-button-accent-label: var(--fg-accent-brand);
  --pill-button-negative-background: var(--bg-negative);
  --pill-button-negative-label: var(--fg-on-dark);
  --pill-button-ghost-label: var(--fg-primary);
  --pill-button-background-disabled: var(--bg-disabled);
  --pill-button-label-disabled: var(--fg-disabled);
  --pill-button-primary-background-active: var(--bg-accent-brand);
  --pill-button-secondary-background-active: var(--bg-accent-brand);
  --pill-button-tertiary-background-active: var(--bg-accent-brand);
  --pill-button-primary-label-active: var(--fg-accent-brand);
  --pill-button-secondary-label-active: var(--fg-accent-brand);
  --pill-button-tertiary-label-active: var(--fg-accent-brand);
  --pill-button-accent-background-active: var(--bg-accent-brand-inverted);
  --pill-button-accent-label-active: var(--fg-accent-brand-inverted);
  --pill-button-negative-background-active: var(--bg-negative);
  --pill-button-negative-label-active: var(--fg-on-dark);
  --pill-button-ghost-label-active: var(--fg-primary);
  --pill-button-ghost-background-active: var(--bg-secondary);
  --pill-button-primary-background-hover: var(--bg-primary-hover);
  --pill-button-secondary-background-hover: var(--bg-secondary-hover);
  --pill-button-tertiary-background-hover: var(--bg-tertiary-hover);
  --pill-button-ghost-background-hover: var(--bg-primary-hover);
  --pill-button-accent-background-hover: var(--bg-accent-brand-hover);
  --pill-button-negative-background-hover: var(--bg-negative-hover);
  /* RESERVED — no consumer yet. Kept deliberately (owner-approved 2026-08-11):
     this names a surface still to be built, and tokens.audit.test.ts fails if it
     is dropped, so an audit reporting it as an orphan is not licence to delete. */
  --event-header-background: var(--bg-tertiary);
  --event-header-label: var(--fg-primary);
  --card-background: var(--bg-primary);
  /* SiteHeader: Figma "components-web" collection (site-header/background,
     site-header/divider). The background is bg/page at opacity/75, as in Figma. */
  --site-header-background: color-mix(in srgb, var(--bg-page) var(--opacity-75), transparent);
  --site-header-divider: var(--border-primary);
  /* SiteHeader's rendered height: its band plus the divider under it. Screens clear it
     with --page-header-height: var(--site-header-block-size); declared once so a change
     to the header cannot leave content sliding under it (09-26 W9). */
  --site-header-block-size: calc(var(--spacing-18) + var(--border-width-1));
  /* Modal: Figma PageHeader (18580:180941) inside the Lineups frame. Its divider is
     bound to the colour/dark-alpha-1 primitive in Figma; component styling never reads
     a primitive, so it takes the semantic SiteHeader's divider uses. */
  --modal-background: var(--bg-page);
  --modal-header-background: var(--bg-accent-brand-inverted);
  --modal-header-label: var(--fg-accent-brand-inverted);
  --modal-header-divider: var(--border-primary);
  /* Modal's motion: Sheet's 350ms in, 250ms out and Out Expo (modal-spec; owner,
     2026-10-18; Out Expo since 2026-11-03). */
  --modal-duration: 350ms;
  --modal-dismiss-duration: 250ms;
  --modal-easing: var(--motion-easing-out-expo);
  /* PageLayout recipe shell's text colour (09-26 W3). */
  --page-layout-label-primary: var(--fg-primary);
  --card-header-background: var(--bg-tertiary);
  --card-header-label: var(--fg-primary);
  --card-footer-background: var(--bg-primary);
  --card-footer-label: var(--fg-primary);
  --card-subheader-background: var(--bg-secondary);
  --card-subheader-label-primary: var(--fg-primary);
  --card-subheader-label-secondary: var(--fg-secondary);
  --card-subheader-gradient-start: var(--gradient-primary-start);
  --card-subheader-gradient-end: var(--gradient-primary-end);
  --circle-button-primary-background: var(--bg-primary);
  --circle-button-primary-icon: var(--fg-primary);
  --circle-button-background-disabled: var(--bg-disabled);
  --circle-button-icon-disabled: var(--fg-disabled);
  --circle-button-secondary-background: var(--bg-secondary);
  --circle-button-secondary-icon: var(--fg-primary);
  --circle-button-tertiary-background: var(--bg-tertiary);
  --circle-button-tertiary-icon: var(--fg-primary);
  --circle-button-accent-background: var(--bg-accent-brand);
  --circle-button-accent-icon: var(--fg-accent-brand);
  --circle-button-negative-background: var(--bg-negative);
  --circle-button-negative-icon: var(--fg-on-dark);
  --circle-button-ghost-icon: var(--fg-primary);
  --circle-button-primary-background-hover: var(--bg-primary-hover);
  --circle-button-secondary-background-hover: var(--bg-secondary-hover);
  --circle-button-tertiary-background-hover: var(--bg-tertiary-hover);
  --circle-button-ghost-background-hover: var(--bg-primary-hover);
  --circle-button-accent-background-hover: var(--bg-accent-brand-hover);
  --circle-button-negative-background-hover: var(--bg-negative-hover);
  --circle-button-primary-background-active: var(--bg-accent-brand);
  --circle-button-primary-icon-active: var(--fg-accent-brand);
  --circle-button-secondary-background-active: var(--bg-accent-brand);
  --circle-button-secondary-icon-active: var(--fg-accent-brand);
  --circle-button-tertiary-background-active: var(--bg-accent-brand);
  --circle-button-tertiary-icon-active: var(--fg-accent-brand);
  --circle-button-accent-background-active: var(--bg-accent-brand-inverted);
  --circle-button-accent-icon-active: var(--fg-accent-brand-inverted);
  --circle-button-negative-background-active: var(--bg-negative);
  --circle-button-negative-icon-active: var(--fg-on-dark);
  --circle-button-ghost-icon-active: var(--fg-primary);
  --circle-button-ghost-background-active: var(--bg-secondary);
  --link-button-primary-label: var(--fg-primary);
  --link-button-secondary-label: var(--fg-secondary);
  --link-button-tertiary-label: var(--fg-tertiary);
  --link-button-accent-label: var(--fg-accent-brand-inverted);
  --link-button-negative-label: var(--fg-negative);
  --link-button-label-disabled: var(--fg-disabled);
  /* Hover: each variant takes its fg/*-hover semantic, mirroring the Figma
     `components` collection verbatim. These used to step down the neutral ladder
     and alias two primitives, which left the accent hover near-black on a dark
     page (2026-09-26 audit, W1). */
  --link-button-primary-label-hover: var(--fg-primary-hover);
  --link-button-secondary-label-hover: var(--fg-secondary-hover);
  --link-button-tertiary-label-hover: var(--fg-tertiary-hover);
  --link-button-accent-label-hover: var(--fg-accent-brand-inverted-hover);
  --link-button-negative-label-hover: var(--fg-negative-hover);
  /* Reserved on 2026-08-11 for a surface still to be built; EventRow arrived on
     2026-09-01 and consumes all three, so they left the roadmap list in
     tokens.audit.test.ts for the stronger alias-pinning guard — same move
     --feedback-state-* made. `--event-row-label` was renamed
     `--event-row-label-primary` at the same time, matching --team-row-* and
     --match-card-*, and renamed in Figma on the owner's call. The row's quieter
     second line takes --link-button-secondary-label directly: it IS the
     secondary LinkButton treatment (event-row-spec D2/D7), drawn without a
     nested button so the whole row stays one control. */
  --event-row-background: var(--bg-primary);
  --event-row-label-primary: var(--fg-primary);
  --event-row-divider: var(--border-primary);
  --match-card-background: var(--bg-primary);
  --match-card-label-primary: var(--fg-primary);
  --match-card-label-secondary: var(--fg-secondary);
  --trend-card-label-primary: var(--fg-primary);
  --trend-card-label-positive: var(--fg-accent-green);
  --trend-card-label-secondary: var(--fg-secondary);
  --trend-card-background: var(--bg-primary);
  --trend-card-divider: var(--border-secondary);
  --stat-card-background: var(--bg-primary);
  --stat-card-label-primary: var(--fg-primary);
  --stat-card-label-secondary: var(--fg-secondary);
  --stake-card-background: var(--bg-primary);
  --stake-card-label-primary: var(--fg-primary);
  --stake-card-label-secondary: var(--fg-secondary);
  --trend-icon-background: var(--bg-accent-green);
  --trend-icon-icon: var(--fg-on-dark);
  --trend-category-label-secondary: var(--fg-primary);
  --trend-category-label-primary: var(--fg-accent-green);
  --event-hero-label-primary: var(--fg-primary);
  --event-hero-label-secondary: var(--fg-secondary);
  --feedback-state-label-primary: var(--fg-primary);
  --feedback-state-label-secondary: var(--fg-secondary);
  --feedback-state-icon-negative: var(--fg-negative);
  --feedback-state-icon-positive: var(--fg-positive);
  /* Offline is the third FeedbackState variant (added alongside the component's
     rename from StatusMessage). It aliases the existing warning semantic rather
     than a raw hex — component-token rule 3 (conventions.md): not another
     component's private state, so it takes its own alias. */
  --feedback-state-icon-warning: var(--fg-accent-yellow);
  /* StatusMessage's inline card, distinct from FeedbackState's page-level glyph
     tokens above even though the background/label values happen to coincide with
     other primary/secondary surfaces — component-token rule 3 (conventions.md):
     never borrow another component's token, always take an own alias. */
  --status-message-background: var(--bg-primary);
  --status-message-border: var(--border-primary);
  /* ScrollArea's overlay thumb aliases the shared overlay tint. */
  --scroll-area-thumb-background: var(--bg-overlay);
  --status-message-label-primary: var(--fg-primary);
  --status-message-label-secondary: var(--fg-secondary);
  --status-message-icon-negative: var(--fg-negative);
  --status-message-icon-warning: var(--fg-accent-yellow);
  --status-message-icon-positive: var(--fg-positive);
  /* ComplianceNotice's fixed logo mark and disclaimer copy. Both alias
     --fg-secondary independently rather than sharing one token or referencing
     --fg-secondary directly — component-token rule 3 (conventions.md), same as
     --team-row-icon / --team-row-label-primary. Colour confirmed with the
     design owner as the Figma component's own tokens, not an inference from
     the exported asset (compliance-notice-spec D4). */
  --compliance-notice-icon: var(--fg-secondary);
  --compliance-notice-label-primary: var(--fg-secondary);
  /* LineupAdvertRow's two board blues: BoyleSports' own brand colours, drawn as raw
     fills in Figma (node 18277:128257, no variable bound). Partner artwork, so the
     same in light and dark, and literal by the partner-colour exception in
     ds/conventions.md (owner-approved 2026-10-06). Panels alternate primary, secondary. */
  --lineup-advert-row-background-primary: #2400f6;
  --lineup-advert-row-background-secondary: #1d00c2;
  /* The cascade. Figma has no motion data; owner-approved pacing (2026-10-06): a board
     holds for 3s, then each panel slides the next board down from above, panel N
     starting N cascades after the first, so the change ripples left to right. Under
     reduced motion the boards cross-fade instead, all panels at once. */
  --lineup-advert-row-hold-duration: 3000ms;
  --lineup-advert-row-slide-duration: var(--motion-spring-slow-duration);
  --lineup-advert-row-slide-easing: var(--motion-spring-slow);
  --lineup-advert-row-cascade-duration: 100ms;
  --lineup-advert-row-fade-duration: var(--motion-duration-moderate);
  /* EmptyState's icon/label read StatusMessage-shaped variable names in Figma, but
     the rendered colours don't match that component's tokens (near-black label,
     red icon) — a copy/paste leftover, not an intentional borrow. Own alias per
     ds/conventions.md component-token rule 3, matching the actual greys on screen. */
  --empty-state-label-primary: var(--fg-secondary);
  --empty-state-icon-primary: var(--fg-disabled);
  --flag-icon-background-placeholder: var(--bg-secondary);
  /* Avatar's glyph sits on fixed gradient artwork that does not change between
     themes, so the glyph must not either. Figma's `avatar/icon` was rebound on
     2026-08-27 from `bg/primary` (which flipped near-black in Dark) to
     `fg/on-dark`, which is --colour-white in both modes — so this mirrors the
     Figma component token exactly, with no divergence to maintain (D1). */
  --avatar-icon: var(--fg-on-dark);
  /* AvatarText's two copy ramps. Figma names them avatar/primary and
     avatar/secondary — one `avatar/*` family covering both components (D2). */
  /* The bed painted under the artwork so a near-white glyph is never on nothing
     while the image loads, or forever if it 404s. An independent colour choice that
     happens to equal --bg-secondary, not an impersonation of another component's
     surface, so it takes its own alias (conventions.md, component-token rule 3). */
  --avatar-background-placeholder: var(--bg-secondary);
  --avatar-primary: var(--fg-primary);
  --avatar-secondary: var(--fg-secondary);
  /* RESERVED — no consumer yet, and a different case from the others: MarketCard
     IS built, but paints no surface of its own and inherits Card's. These name the
     surface it would own if it ever needs to diverge. Kept deliberately
     (owner-approved 2026-08-11); tokens.audit.test.ts fails if either is dropped,
     so an audit reporting them as orphans is not licence to delete. */
  --market-card-background: var(--bg-primary);
  --market-card-border: var(--border-primary);
  --team-row-label-primary: var(--fg-primary);
  --team-row-label-secondary: var(--fg-secondary);
  --team-row-icon: var(--fg-secondary);
  --team-row-background: var(--bg-primary);
  --team-row-divider: var(--border-primary);
  /* Table (table-spec). Figma components collection: table/*. */
  --table-label-primary: var(--fg-primary);
  --table-label-secondary: var(--fg-secondary);
  --table-border: var(--border-primary);
  --table-gradient-start: var(--gradient-primary-start);
  --table-gradient-end: var(--gradient-primary-end);
  --market-row-label-primary: var(--fg-primary);
  --market-row-label-secondary: var(--fg-secondary);
  --market-row-icon: var(--fg-secondary);
  --market-row-background: var(--bg-primary);
  --market-row-border: var(--border-primary);
  --market-row-gradient-start: var(--gradient-primary-start);
  --market-row-gradient-end: var(--gradient-primary-end);
  --bet-selection-row-background: var(--bg-primary);
  --bet-selection-row-divider: var(--border-primary);
  --bet-selection-row-label-primary: var(--fg-primary);
  --bet-selection-row-label-secondary: var(--fg-secondary);
  --bet-selection-row-label-unavailable: var(--fg-secondary);
  --fav-button-icon-primary: var(--fg-quaternary);
  --fav-button-icon-hover: var(--fg-tertiary);
  --fav-button-icon-active: var(--fg-accent-yellow);
  --fav-button-icon-disabled: var(--fg-disabled);
  --stats-button-icon-primary: var(--fg-quaternary);
  --stats-button-icon-hover: var(--fg-tertiary);
  --stats-button-icon-active: var(--fg-accent-green);
  --stats-button-icon-disabled: var(--fg-disabled);
  /* RESERVED — no consumer yet. Kept deliberately (owner-approved 2026-08-11):
     this names a surface still to be built, and tokens.audit.test.ts fails if it
     is dropped, so an audit reporting it as an orphan is not licence to delete. */
  --scanner-card-background: var(--bg-primary);
  /* FeatureCard. Supersedes the reserved --feature-row-label / --feature-row-icon
     pair, retired 2026-09-01: Figma renamed that family to feature-card/* when the
     component was drawn, so no feature-row/* variable exists in the file any more
     and keeping both left two near-identical names for one surface. */
  --feature-card-background: var(--bg-primary);
  --feature-card-primary: var(--fg-primary);
  --feature-card-secondary: var(--fg-secondary);
  --bar-chart-chart-won-axis: var(--fg-chart-positive);
  --bar-chart-chart-won-label: var(--fg-chart-positive);
  --bar-chart-chart-lost-axis: var(--fg-chart-negative);
  --bar-chart-chart-lost-label: var(--fg-secondary);
  --dial-chart-dial-primary: var(--fg-chart-positive);
  --dial-chart-label-primary: var(--fg-primary);
  --dial-chart-dial-on-light: var(--fg-on-light);
  --dial-chart-label-on-light: var(--fg-on-light);
  --grid-chart-cell-won: var(--bg-chart-positive);
  --grid-chart-cell-lost: var(--bg-chart-negative);
  --grid-chart-cell-yellow-card: var(--bg-accent-yellow);
  --grid-chart-cell-red-card: var(--bg-accent-red);
  --grid-chart-label-on-won: var(--fg-on-dark);
  --grid-chart-label-on-lost: var(--fg-secondary);
  --grid-chart-icon-on-won: var(--fg-on-dark);
  --grid-chart-icon-on-lost: var(--fg-secondary);
  --stepper-button-icon-primary: var(--fg-primary);
  --stepper-button-icon-hover: var(--fg-secondary);
  --stepper-button-icon-disabled: var(--fg-disabled);
  --number-stepper-background: var(--bg-primary);
  --number-stepper-value: var(--fg-primary);
  --quick-picks-nav-background: var(--bg-primary);
  --quick-picks-nav-border: var(--border-primary);
  --quick-picks-card-background: var(--bg-primary);
  --quick-picks-card-border: var(--border-secondary);
  --quick-picks-card-background-pattern-primary: var(--bg-accent-light-green);
  --quick-picks-card-background-pattern-secondary: var(--bg-page);
  --quick-picks-card-stat-gradient-start: var(--gradient-stat-start);
  --quick-picks-card-stat-gradient-end: var(--gradient-stat-end);
  --quick-picks-card-stat-label: var(--fg-on-light);
  --quick-picks-card-stat-icon: var(--fg-on-light);
  --quick-picks-card-insight-gradient-start: var(--gradient-secondary-start);
  --quick-picks-card-insight-gradient-end: var(--gradient-secondary-end);
  --quick-picks-card-insight-label: var(--fg-primary);
  --quick-picks-card-team-label: var(--fg-primary);
  --quick-picks-card-market-label: var(--fg-primary);
  --quick-picks-card-selection-label: var(--fg-primary);
  --quick-picks-card-odds-label: var(--fg-primary);
  /* QuickPicksInstruction. Transcribed from `quick-picks-instruction/border` and
     `quick-picks-instruction/label-primary` in Figma's `components` collection,
     which alias `theme/border/secondary` and `theme/fg/primary` there. The dashed
     outline is therefore the same neutral boundary that outlines a QuickPicksCard.
     `-label-primary` has no `-secondary` sibling; the name is Figma's, not half a
     pair someone forgot to finish.

     Note that get_design_context reports this border as
     `status-message/label-secondary`; that is codegen flattening the alias chain
     onto the wrong name (quick-picks-instruction-spec.md B1). Slash form
     deliberately: tokens.audit.test.ts matches token names with an unanchored
     regex, and the CSS-variable spelling in a comment is a trap for it. */
  --quick-picks-instruction-border: var(--border-secondary);
  --quick-picks-instruction-label-primary: var(--fg-primary);
  --team-lineup-background: var(--bg-primary);
  --team-lineup-outline: var(--border-secondary);
  /* Chat, Bruno family. Figma's `components` collection aliases both of these
     straight through `theme`, so a Bruno theme change restyles the bubble. NOT
     the `components-ios` collection ChatComposer reads, even though the two
     share a screen and now share a Storybook section — see
     ds/specs/shipped/message-bubble-thinking-indicator-spec.md D1. */
  --message-bubble-background: var(--bg-secondary);
  --message-bubble-primary: var(--fg-primary);
  /* MessageReply's heading and body are bound in Figma to
     message-pair/label-primary on node 17159:34333. Bruno keeps the public
     token dashed and component-scoped, but this alias is grounded in that Figma
     token rather than guessed from a screenshot. */
  --message-reply-primary: var(--fg-primary);
  --message-reply-accent: var(--fg-accent-brand-inverted);
  --message-reply-word-enter-duration: 500ms;
  --message-reply-word-enter-easing: var(--motion-easing-in-out-base);
  /* Heading words, and any body words entering in that same pass, cascade in
     one after another: word N's delay is exactly N times this duration, so
     each word fully finishes fading before the next one starts — no two
     words are ever mid-fade at once, and the title flows straight into the
     body as one unbroken sequence with no pause and no overlap at the seam.
     150ms, then 112.5ms, now 25% faster again on Krishan's call. */
  --message-reply-word-cascade-duration: 84.375ms;
  --message-reply-word-settle-duration: 700ms;
  --message-reply-word-settle-easing: var(--motion-easing-in-out-base);
  --message-pair-enter-duration: 500ms;
  --message-pair-enter-easing: var(--motion-easing-out-cubic);
  /* QuickPicksStack's two curves, on the motion library since 2026-11-03: the
     restack settles quickly as the next card rises into place; the fly-out eases
     off a swipe's momentum rather than starting from rest. Both within 3.3% of
     the hand-tuned curves they replaced. */
  --quick-picks-stack-restack-easing: var(--motion-easing-out-quint);
  --quick-picks-stack-fly-easing: var(--motion-easing-out-quad);
  /* Carousel's edge fade ramps in on this curve as the track moves, so the fade builds
     quickly at the start of a swipe (2026-09-29 audit C1; CSS `ease-out`, which is
     --motion-easing-out). */
  --carousel-scroll-fade-easing: var(--motion-easing-out);
  /* Reversed from full-strength --fg-primary to --fg-secondary, design owner,
     2026-09-10 — supersedes the 2026-09-05 call recorded in
     ThinkingIndicator.ts, which argued for full-strength text. */
  --thinking-indicator-primary: var(--fg-secondary);
  /* Pure black in Light, pure white in Dark: deliberately stronger than
     ThinkingIndicator's label beside them. Figma's own call for the chat dots
     (thinking-indicator/icon → fg/accent-brand-inverted); ThinkingIndicator
     draws its dots with ThinkingDots, so this is the one dot colour. */
  --thinking-dots-icon: var(--fg-accent-brand-inverted);

  /* text styles */
  --text-style-heading-2xl-font-family: var(--typography-font-family-sans);
  --text-style-heading-2xl-font-weight: 700;
  --text-style-heading-2xl-font-size: 48px;
  --text-style-heading-2xl-line-height: 48px;
  --text-style-heading-2xl-letter-spacing: 0;
  --text-style-heading-xl-font-family: var(--typography-font-family-sans);
  --text-style-heading-xl-font-weight: 700;
  --text-style-heading-xl-font-size: 30px;
  --text-style-heading-xl-line-height: 48px;
  --text-style-heading-xl-letter-spacing: 0;
  --text-style-heading-lg-font-family: var(--typography-font-family-sans);
  --text-style-heading-lg-font-weight: 700;
  --text-style-heading-lg-font-size: 24px;
  --text-style-heading-lg-line-height: 40px;
  --text-style-heading-lg-letter-spacing: 0;
  --text-style-heading-md-font-family: var(--typography-font-family-sans);
  --text-style-heading-md-font-weight: 700;
  --text-style-heading-md-font-size: 20px;
  --text-style-heading-md-line-height: 32px;
  --text-style-heading-md-letter-spacing: 0;
  --text-style-heading-sm-font-family: var(--typography-font-family-sans);
  --text-style-heading-sm-font-weight: 700;
  --text-style-heading-sm-font-size: 18px;
  --text-style-heading-sm-line-height: 28px;
  --text-style-heading-sm-letter-spacing: 0;
  --text-style-title-lg-font-family: var(--typography-font-family-sans);
  --text-style-title-lg-font-weight: 700;
  --text-style-title-lg-font-size: 16px;
  --text-style-title-lg-line-height: 24px;
  --text-style-title-lg-letter-spacing: 0;
  --text-style-title-md-font-family: var(--typography-font-family-sans);
  --text-style-title-md-font-weight: 700;
  --text-style-title-md-font-size: 14px;
  --text-style-title-md-line-height: 20px;
  --text-style-title-md-letter-spacing: 0;
  --text-style-title-sm-font-family: var(--typography-font-family-sans);
  --text-style-title-sm-font-weight: 700;
  --text-style-title-sm-font-size: 12px;
  --text-style-title-sm-line-height: 16px;
  --text-style-title-sm-letter-spacing: 0;
  --text-style-title-xs-font-family: var(--typography-font-family-sans);
  --text-style-title-xs-font-weight: 700;
  --text-style-title-xs-font-size: 10px;
  --text-style-title-xs-line-height: 12px;
  --text-style-title-xs-letter-spacing: 0;
  --text-style-body-xl-font-family: var(--typography-font-family-sans);
  --text-style-body-xl-font-weight: 500;
  --text-style-body-xl-font-size: 18px;
  --text-style-body-xl-line-height: 28px;
  --text-style-body-xl-letter-spacing: 0;
  --text-style-body-lg-font-family: var(--typography-font-family-sans);
  --text-style-body-lg-font-weight: 500;
  --text-style-body-lg-font-size: 16px;
  --text-style-body-lg-line-height: 24px;
  --text-style-body-lg-letter-spacing: 0;
  --text-style-body-md-font-family: var(--typography-font-family-sans);
  --text-style-body-md-font-weight: 500;
  --text-style-body-md-font-size: 14px;
  --text-style-body-md-line-height: 20px;
  --text-style-body-md-letter-spacing: 0;
  --text-style-body-sm-font-family: var(--typography-font-family-sans);
  --text-style-body-sm-font-weight: 500;
  --text-style-body-sm-font-size: 12px;
  --text-style-body-sm-line-height: 16px;
  --text-style-body-sm-letter-spacing: 0;
  --text-style-body-xs-font-family: var(--typography-font-family-sans);
  --text-style-body-xs-font-weight: 500;
  --text-style-body-xs-font-size: 10px;
  --text-style-body-xs-line-height: 12px;
  --text-style-body-xs-letter-spacing: 0;
}

:root[data-theme='dark'],
:host([data-theme='dark']) {
  /* theme: Dark */
  /* Native scrollbars, form controls and the UA canvas follow the theme too, so
     a dark page never shows a white scrollbar or a light date picker (2026-10-03). */
  color-scheme: dark;
  --bg-primary: var(--colour-grey-dark-1);
  --bg-secondary: var(--colour-grey-dark-2);
  --bg-accent-brand: var(--colour-white);
  --bg-positive-primary: var(--colour-green-7);
  --border-primary: var(--colour-grey-dark-2);
  --border-secondary: var(--colour-grey-dark-3);
  --bg-page: var(--colour-black);
  --fg-positive: var(--colour-green-7);
  --fg-primary: var(--colour-grey-dark-12);
  --fg-secondary: var(--colour-grey-dark-11);
  --border-positive: var(--colour-green-7);
  --border-accent: var(--colour-white);
  --bg-negative: var(--colour-red-7);
  --border-negative: var(--colour-red-7);
  --fg-negative: var(--colour-red-7);
  --bg-disabled: var(--colour-grey-dark-3);
  --fg-disabled: var(--colour-grey-dark-8);
  --bg-tertiary: var(--colour-grey-dark-3);
  --bg-quaternary: var(--colour-grey-dark-4);
  --border-tertiary: var(--colour-grey-dark-4);
  --fg-accent-brand: var(--colour-black);
  --fg-on-dark: var(--colour-white);
  --fg-accent-brand-inverted: var(--colour-white);
  --bg-accent-brand-inverted: var(--colour-black);
  --border-accent-inverted: var(--colour-black);
  --fg-tertiary: var(--colour-grey-dark-10);
  --fg-on-light: var(--colour-black);
  --bg-on-dark: var(--colour-white);
  --bg-positive-secondary: var(--colour-green-9);
  --fg-accent-yellow: var(--colour-amber-6);
  --fg-accent-red: var(--colour-red-7);
  --bg-accent-yellow: var(--colour-amber-6);
  --bg-accent-red: var(--colour-red-7);
  --bg-chart-positive: var(--colour-green-7);
  --gradient-primary-start: var(--colour-dark-alpha-8);
  --gradient-primary-end: var(--colour-dark-alpha-0);
  --gradient-stat-start: var(--colour-green-8);
  --gradient-stat-end: var(--colour-green-6);
  --gradient-secondary-start: var(--colour-black);
  --gradient-secondary-end: var(--colour-dark-alpha-0);
  --bg-accent-light-green: var(--colour-green-5);
  --bg-on-light: var(--colour-black);
  --bg-chart-negative: var(--colour-grey-dark-3);
  --fg-chart-positive: var(--colour-green-7);
  --fg-chart-negative: var(--colour-grey-dark-3);
  --fg-quaternary: var(--colour-grey-dark-10);
  /* Hover states, from the Figma theme collection (fg/*-hover). In Dark they
     lighten rather than step down the ladder, except primary. */
  --fg-primary-hover: var(--colour-grey-dark-11);
  --fg-secondary-hover: var(--colour-grey-dark-12);
  --fg-tertiary-hover: var(--colour-grey-dark-11);
  --fg-accent-brand-inverted-hover: var(--colour-grey-light-8);
  --fg-negative-hover: var(--colour-red-6);
  --fg-accent-green: var(--colour-green-7);
  --bg-accent-green: var(--colour-green-7);
  --focus-ring-colour: var(--colour-white);
  /* hover overlays flip polarity: light overlay on dark surfaces; accent surface inverts to white, so it darkens */
  --bg-primary-hover: var(--colour-light-alpha-1);
  --bg-secondary-hover: var(--colour-light-alpha-1);
  --bg-tertiary-hover: var(--colour-light-alpha-1);
  --bg-accent-brand-hover: var(--colour-dark-alpha-1);
  /* negative resolves to the same overlay in both themes (red surface stays dark), but set explicitly so a future dark-mode change has a home */
  --bg-negative-hover: var(--colour-light-alpha-2);
  /* overlay fill drops to a dimmer tint on the dark surface, where the lighter Light-mode value would read too bright */
  --bg-overlay: var(--colour-light-alpha-1);

}

/* The Light half of the colour-scheme pair above. On :root alone, never on :host:
   every component's shadow root adopts the :root, :host block, so a light
   color-scheme there would pin each component's native scrollbars and controls
   light on a dark page. Dark mode is a whole-page switch on the root (2026-10-03),
   so the root is the only place the scheme needs setting. */
:root {
  color-scheme: light;
}
