/* ====================================================================
   cfin-theme.tokens.css — PART GENERATED, PART HAND-MAINTAINED.

   ⚠ ONLY the delimited variant layer (BEGIN/END GENERATED VARIANT LAYER,
     near the bottom) is emitted by scripts/build-theme-tokens.mjs. Everything
     above it — INCLUDING --cfin-profit / --cfin-loss — is hand-maintained.

     This header used to say the whole file was generated. It is why the money
     tokens here sat on the RETIRED RED (rgb(194,45,40)/rgb(242,142,138)) long
     after the product moved to the iris sign palette: running the generator
     did not touch them, and the header said not to edit them by hand. The
     public landing and /performance were therefore publishing a DIFFERENT
     sign palette from the app.

     ⚠ THIS FILE HAS NOW FALLEN BEHIND siteTokens.js THREE TIMES, THE SAME
     WAY EACH TIME. The 2026-08-24 correction moved four tokens
     (--cfin-profit / --cfin-loss / --cfin-series-drawdown / --color-error)
     and left --cfin-series-balance / --cfin-candle-bull / --cfin-candle-bear
     behind. A sweep on 2026-08-25 claimed, in this header, that "every token
     in this file that siteTokens.js aliases to PROFIT or LOSS now carries
     that role's value". That claim was FALSE by 2026-08-28: the CEO's
     five-role palette landed in siteTokens.js and this file was left on the
     generation before it, still shipping an IRIS NAVY bear candle, a dark
     green bull candle and balance line, a RED --cfin-loss-fill, an olive
     withdrawal series and an alpha'd vault series.

     ⚠ SO DO NOT TRUST A "SWEPT ON <DATE>" LINE HERE, INCLUDING THIS ONE.
     The only safe check is mechanical, because nothing regenerates this file:
     for every key in siteTokens.js MONEY/SERIES/ROLE that names a role
     constant, the declaration below must carry that constant's two values.
     Diff it, do not read it. The one-call-site fix is the recurring defect
     here; sweep the ROLE, not the token you were handed.

     2026-08-28: swept again, and the three ROLE tokens siteTokens.js exports
     but this file never carried (--cfin-vault / --cfin-withdrawal /
     --cfin-neutral) were added, so a Jinja shell can finally name the vault
     colour instead of restating a hex.

     ⭐⭐ 2026-08-28, LATER, AND IT IS THE FOURTH DRIFT: THE LINE DIRECTLY
     ABOVE WAS FALSE WHEN IT WAS WRITTEN. --cfin-vault and --cfin-withdrawal
     were added; --cfin-neutral WAS NOT. The only occurrence of that name in
     this file was the sentence claiming it had been added — which is the
     precise thing the paragraph above it tells you not to trust, written by
     the same pass, two paragraphs later.

     The same sweep also gave --cfin-fam-unknown the value of
     --cfin-text-tertiary instead of NEUTRAL's. siteTokens.js:287 aliases it BY
     REFERENCE to NEUTRAL, and NEUTRAL's LIGHT half is #66666A — identical to
     text-tertiary's. Only the DARK half differs (#AAAAAE vs #A3A3A8), so it
     was correct in the mode anyone opens first and wrong in the other.
     ⚠ Neither token has a single var() call site under static/, templates/ or
     /opt/cfin/marketing, so neither was painting a wrong pixel — the same
     reason --color-success/--color-error drifted unseen, and the same reason
     it is pinned rather than left. A declared-but-unread token is a loaded
     gun, not an unimportant one: the first Jinja shell to name it inherits the
     wrong colour, and var(--cfin-neutral) with nothing behind it is not a
     no-op — it is invalid at computed-value time, so `color` falls to INHERIT.

     ⭐ AND THE GUARD WAS GREEN THROUGH BOTH. tests-node/
     staticArtifactTracksSiteTokens.test.mjs bound eighteen tokens FROM A HAND-
     WRITTEN LIST, and neither NEUTRAL token was on it — a second copy of a
     fact siteTokens.js already states. It now DERIVES the binding by parsing
     `'--token': ROLE` out of the authority, requires all five SEMANTIC_ROLES
     to be declared in both blocks, and fails on an alias target it does not
     recognise. Mutation-tested against this file as origin/main had it: RED on
     both drifts, naming both tokens.

     ⚠ THE .br AND .gz SIDECARS ARE NOT IN GIT. nginx serves /static/ from the
     working tree with brotli_static, so the .br is what a browser actually
     reads. Editing this file does not change what is served until those are
     rebuilt at deploy.

     ⭐⭐⭐ 2026-08-28, SIGN PALETTE v4 — AND THE HAND-MAINTENANCE IS OVER.
     Every paragraph above this one describes a defect with ONE cause: the money
     declarations below were edited by hand, so whoever swept them moved the
     tokens they were handed and left the ones they were not. Four drifts, four
     "swept on <date>" lines, three of them false when written.

     `frontend/scripts/sync-public-sign-tokens.mjs` (npm run tokens:public) now
     performs that edit MECHANICALLY from siteTokens.js — every token carrying a
     sign role, in BOTH blocks, derived from the authority's own alias tables
     rather than from a list someone has to remember to extend. It is idempotent
     and has a `--check` mode. Run it after any change to the role constants;
     tests-node/staticArtifactTracksSiteTokens.test.mjs is what proves you did.

     ⚠ IT DOES NOT TOUCH ANYTHING ELSE IN THIS FILE. The surfaces, radii, glass
     and the variant layer are still hand-maintained and still yours to keep
     right. "Generated" here means the money declarations only.

     ⚠ AND THIS PREAMBLE NO LONGER RESTATES THE HEXES. It used to, and the
     copy it left behind went stale the next time PROFIT's dark half moved —
     the header was still naming '#479e62' / '#8289c7' while the declarations
     below it (correctly) said rgb(116,192,140) / rgb(169,173,216). A comment
     that restates a constant is a third copy of it. The values live in
     frontend/src/shared/theme/siteTokens.js (PROFIT / LOSS) and
     frontend/src/shared/theme/cfinTheme.ts (--color-success / --color-error);
     read them there.

     NOTHING BELOW IS ASSERTED BY A TEST. tests-node/semanticColour.test.mjs
     checks siteTokens.js against src/shared/theme/generated/site-tokens.css —
     the React tree's copy — and never opens this file, which is why the drift
     above survived a green suite. The templates that load THIS file are the
     public ones: landing, /performance, register, base-auth, reviews, legal
     and the error pages.

     If you change the palette, change it in siteTokens.js AND here, until
     someone makes this preamble genuinely generated.

     ⚠ THE STATUS ROLES FOLLOW THE MONEY ROLES (settled 2026-08-25).
     --color-success IS the PROFIT role and --color-error IS the LOSS role, in
     this file and in cfinTheme.ts, and publicTokensMatchSource.test.mjs now
     asserts it. This is not drift and it is not a shortcut:

       * cfinTheme.ts adopted the union on 2026-08-03 with the reason written
         out at its --color-error entry: keeping a separate status red meant
         "two reds, both meaning down, one on the badge and one on the number
         beside it — and BOTH were failing AA". The split WAS the defect.
       * semanticColour.test.mjs test 4 has enforced the union on the app side
         ever since; its own history lists `--color-error: ['#DC352D','#FF453A']`
         as a state it was written to turn RED.
       * This file was the half that had not caught up: its --color-error was
         corrected on 2026-08-25, but --color-success was still the OLD green
         rgb(21,118,53)/rgb(82,202,116) — and rgb(82,202,116) is a colour the
         CEO rejected as a sign colour on 2026-08-24. The public site was
         declaring a rejected green under a status name.

         🚩🚩 READ THE PARAGRAPH ABOVE AS HISTORY, NOT AS A LIVE BAN. On
         2026-08-28 the CEO looked at the rendered landing page and said its
         positive/negative colouring was "a lot better and accurate" and to use
         it for the dashboards — and the landing page's green IS
         rgb(21,118,53)/rgb(82,202,116). So the value this note records as
         REJECTED on 08-24 is the value the CEO SELECTED on 08-28, and it is
         what the two blocks below now declare.

         ⭐ That is not necessarily a contradiction: the 08-24 rejection was of
         this green appearing under a STATUS name on the public site while the
         sign pair was something else, i.e. it was a drift complaint. The 08-28
         instruction is a direct choice made against a render. A later, specific
         instruction pointed at a screen outranks an earlier note — but the two
         DO name the same hex with opposite verdicts, so it is raised in the PR
         as an explicit question rather than quietly resolved in either
         direction. Do not "restore" either value on the strength of one of
         these paragraphs alone; find the newer instruction first.
       * Nothing on the public site or in cfin-marketing READS these two
         tokens today (measured: zero `var(--color-success)` / `var(--color-error)`
         call sites under static/, templates/ and /opt/cfin/marketing). They are
         declared here so an Astryx component mounted on a public page inherits
         the same palette as the app. That is exactly why the drift was
         invisible, and exactly why it had to be pinned rather than left.

     ⚠ "an error is then indistinguishable from a loss" is TRUE OF THE HUE and
     is handled where it has to be: colour alone is never allowed to carry
     either meaning. The pair USED to be iso-luminant by design (1.00:1 in
     greyscale on all four real surfaces). Since it adopted the CEO's landing
     values on 2026-08-28 it measures 1.07:1 light / 1.69:1 dark — MORE
     separable than before, but still far under the 3:1 needed for a graphical
     object to be told apart, so nothing here is relaxed. Glyph + hatch remain
     load-bearing exactly as they were —
     see charts/signEncoding.jsx — and the admin surfaces that needed to stay
     distinct already encode by WEIGHT, a LEFT RULE or a HATCH rather than hue,
     precisely because these two tokens resolve to the same ink.

     ⚠ --color-on-success / --color-on-error were white in BOTH schemes here
     while the fills are a light-dark() pair, so the ink could not flip when the
     fill did: white on the dark-half fill measures 2.17:1. Corrected to
     light-dark(white, rgb(28,28,30)) = 7.83 / 7.82, matching cfinTheme.ts,
     which had already fixed this on the app side and documented why.
   Source: frontend/src/shared/theme/cfinTheme.ts
   Built with: @astryxdesign/core 0.1.8 on Node v22.14.0
   Spec: docs/superpowers/specs/2026-07-26-cfin-astryx-theme-mapping.md

   Two identical token blocks are emitted on purpose:
     1. @scope [data-astryx-theme="cfin"] — what Astryx components read.
     2. :root — what cfin-marketing / plain CSS / non-React pages read,
        since @scope requires the data attribute on an ancestor and
        marketing collateral has no Astryx root.
   ==================================================================== */
@scope ([data-astryx-theme="cfin"]) to ([data-astryx-theme]) {
  :scope {
    --color-accent: light-dark(rgb(20,95,200), rgb(86,166,255));
    --color-text-accent: light-dark(rgb(20,95,200), rgb(86,166,255));
    --color-icon-accent: light-dark(rgb(20,95,200), rgb(86,166,255));
    --color-on-accent: light-dark(rgb(255,255,255), rgb(255,255,255));
    --color-background-body: light-dark(rgb(255,255,255), rgb(28,28,30));
    --color-background-surface: light-dark(rgb(242,242,247), rgb(44,44,46));
    --color-background-card: light-dark(rgb(242,242,247), rgb(44,44,46));
    --color-background-popover: light-dark(rgb(238,238,243), rgb(50,50,52));
    --color-background-muted: light-dark(rgb(229,229,234), rgb(58,58,60));
    --color-text-primary: light-dark(rgb(85,85,95), rgb(255,255,255));
    --color-text-secondary: light-dark(rgb(100,100,108), rgb(170,170,175));
    --color-text-disabled: light-dark(rgb(102,102,110), rgb(170,170,174));
    --color-icon-primary: light-dark(rgb(85,85,95), rgb(255,255,255));
    --color-icon-secondary: light-dark(rgb(100,100,108), rgb(170,170,175));
    --color-border: light-dark(rgba(130,130,135,0.55), rgba(124,124,128,0.50));
    --color-border-emphasized: light-dark(rgb(130,130,135), rgb(124,124,128));
    --color-success: light-dark(rgb(7,102,45), rgb(108,195,128));
    --color-on-success: light-dark(rgb(255,255,255), rgb(28,28,30));
    --color-error: light-dark(rgb(110,70,145), rgb(202,158,245));
    --color-on-error: light-dark(rgb(255,255,255), rgb(28,28,30));
    --color-warning: light-dark(rgb(158,83,0), rgb(255,149,0));
    --color-shadow: light-dark(rgba(0,0,0,0.10), rgba(0,0,0,0.30));
    --color-track: light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.06));
    --radius-inner: 4px;
    --radius-element: 8px;
    --radius-container: 12px;
    --radius-page: 16px;
    --radius-full: 999px;
    --font-family-body: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --font-family-heading: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --font-family-code: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
    --duration-fast: 150ms;
    --duration-medium: 250ms;
    --duration-slow: 500ms;
    --ease-standard: cubic-bezier(0.22,1,0.36,1);
    --cfin-profit: light-dark(rgb(7,102,45), rgb(108,195,128));
    --cfin-profit-bg: light-dark(rgba(7,102,45,0.10), rgba(108,195,128,0.15));
    --cfin-loss: light-dark(rgb(110,70,145), rgb(202,158,245));
    --cfin-profit-text: light-dark(rgb(3,78,33), rgb(137,210,152));
    --cfin-loss-text: light-dark(rgb(84,52,113), rgb(216,179,253));
    --cfin-profit-ink: light-dark(rgb(7,102,45), rgb(108,195,128));
    --cfin-loss-ink: light-dark(rgb(110,70,145), rgb(202,158,245));
    --cfin-profit-graphic: light-dark(rgb(11,123,56), rgb(60,168,92));
    --cfin-loss-graphic: light-dark(rgb(133,85,174), rgb(177,126,224));
    --cfin-profit-emphasis: light-dark(rgb(3,78,33), rgb(169,225,180));
    --cfin-loss-emphasis: light-dark(rgb(84,52,113), rgb(227,202,254));
    --cfin-profit-border: light-dark(rgb(9,112,51), rgb(137,210,152));
    --cfin-loss-border: light-dark(rgb(121,77,159), rgb(216,179,253));
    --cfin-profit-wash: light-dark(rgb(205,241,211), rgb(1,57,22));
    --cfin-loss-wash: light-dark(rgb(240,227,254), rgb(62,38,83));
    --cfin-profit-vivid: light-dark(rgb(25,144,69), rgb(84,182,110));
    --cfin-loss-bg: light-dark(rgba(110,70,145,0.10), rgba(202,158,245,0.15));
    --cfin-loss-vivid: light-dark(rgb(154,102,199), rgb(191,142,236));
    --cfin-accent-fill: light-dark(rgb(20,95,200), rgb(20,95,200));
    --cfin-accent-fill-hover: light-dark(rgb(15,78,170), rgb(15,78,170));
    --cfin-profit-fill: light-dark(rgb(11,123,56), rgb(60,168,92));
    --cfin-loss-fill: light-dark(rgb(133,85,174), rgb(177,126,224));
    --cfin-text-tertiary: light-dark(rgb(110,110,114), rgb(147,147,151));
    --cfin-surface-3: light-dark(rgb(229,229,234), rgb(58,58,60));
    --cfin-surface-hover: light-dark(rgb(229,229,234), rgb(58,58,60));
    --cfin-surface-selected: light-dark(rgb(209,209,214), rgb(72,72,74));
    --cfin-surface-input: light-dark(rgb(255,255,255), rgb(38,38,40));
    --cfin-glass-bg: light-dark(rgba(255,255,255,0.80), rgba(44,44,46,0.72));
    --cfin-glass-blur: 0px;
    --cfin-glass-border: light-dark(rgba(0,0,0,0.10), rgba(255,255,255,0.12));
    --cfin-iris-brand-from: #6a71e0;
    --cfin-iris-brand-to: #a95ff4;
    --cfin-iris-gradient: linear-gradient(120deg,#6a71e0,#a95ff4);
    --cfin-green-brand: #34C759;
    --cfin-blue-brand: #0A84FF;
    --cfin-iris-text: light-dark(rgb(78,86,218), rgb(162,166,236));
    --cfin-green-text: light-dark(rgb(7,102,45), rgb(108,195,128));
    --cfin-amber-text: light-dark(rgb(121,89,52), rgb(223,187,144));
    --cfin-fam-unknown: light-dark(rgb(102,102,106), rgb(163,163,168));
    --cfin-series-balance: light-dark(rgb(11,123,56), rgb(60,168,92));
    --cfin-series-effective: light-dark(rgb(38,152,181), rgb(38,152,181));
    --cfin-series-withdrawal: light-dark(rgb(124,92,200), rgb(143,116,208));
    --cfin-series-drawdown: light-dark(rgb(133,85,174), rgb(177,126,224));
    --cfin-series-vault: light-dark(rgb(6,96,198), rgb(109,176,251));
    --cfin-vault: light-dark(rgb(6,96,198), rgb(109,176,251));
    --cfin-withdrawal: light-dark(rgb(124,92,200), rgb(143,116,208));
    --cfin-neutral: light-dark(rgb(102,102,106), rgb(163,163,168));
    --cfin-return: light-dark(rgb(38,152,181), rgb(38,152,181));
    --cfin-candle-bull: light-dark(rgb(11,123,56), rgb(60,168,92));
    --cfin-candle-bear: light-dark(rgb(133,85,174), rgb(177,126,224));
    --cfin-z-sticky: 100;
    --cfin-z-nav: 200;
    --cfin-z-scrim: 300;
    --cfin-z-drawer: 400;
    --cfin-z-dropdown: 500;
    --cfin-z-banner: 600;
    --cfin-z-banner-stack: 610;
    --cfin-z-chat: 700;
    --cfin-z-modal-scrim: 800;
    --cfin-z-modal: 810;
    --cfin-z-popover: 900;
    --cfin-z-tooltip: 1000;
    --cfin-z-toast: 1100;
    --cfin-z-skiplink: 1200;
  }
}

@scope ([data-astryx-theme="cfin"]) to ([data-astryx-theme]) {
  [data-astryx-media="dark"] {
    color-scheme: dark;
    --color-text-primary: var(--color-on-dark);
    --color-icon-primary: var(--color-on-dark);
    --color-accent: var(--color-on-dark);
  }

  [data-astryx-media="light"] {
    color-scheme: light;
    --color-text-primary: var(--color-on-light);
    --color-icon-primary: var(--color-on-light);
    --color-accent: var(--color-on-light);
  }
}

/* --- :root mirror for non-Astryx consumers --- */
:root {
  --color-accent: light-dark(rgb(20,95,200), rgb(86,166,255));
  --color-text-accent: light-dark(rgb(20,95,200), rgb(86,166,255));
  --color-icon-accent: light-dark(rgb(20,95,200), rgb(86,166,255));
  --color-on-accent: light-dark(rgb(255,255,255), rgb(255,255,255));
  --color-background-body: light-dark(rgb(255,255,255), rgb(28,28,30));
  --color-background-surface: light-dark(rgb(242,242,247), rgb(44,44,46));
  --color-background-card: light-dark(rgb(242,242,247), rgb(44,44,46));
  --color-background-popover: light-dark(rgb(238,238,243), rgb(50,50,52));
  --color-background-muted: light-dark(rgb(229,229,234), rgb(58,58,60));
  --color-text-primary: light-dark(rgb(85,85,95), rgb(255,255,255));
  --color-text-secondary: light-dark(rgb(100,100,108), rgb(170,170,175));
  --color-text-disabled: light-dark(rgb(102,102,110), rgb(170,170,174));
  --color-icon-primary: light-dark(rgb(85,85,95), rgb(255,255,255));
  --color-icon-secondary: light-dark(rgb(100,100,108), rgb(170,170,175));
  --color-border: light-dark(rgba(130,130,135,0.55), rgba(124,124,128,0.50));
  --color-border-emphasized: light-dark(rgb(130,130,135), rgb(124,124,128));
  --color-success: light-dark(rgb(7,102,45), rgb(108,195,128));
  --color-on-success: light-dark(rgb(255,255,255), rgb(28,28,30));
  --color-error: light-dark(rgb(110,70,145), rgb(202,158,245));
  --color-on-error: light-dark(rgb(255,255,255), rgb(28,28,30));
  --color-warning: light-dark(rgb(158,83,0), rgb(255,149,0));
  --color-shadow: light-dark(rgba(0,0,0,0.10), rgba(0,0,0,0.30));
  --color-track: light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.06));
  --radius-inner: 4px;
  --radius-element: 8px;
  --radius-container: 12px;
  --radius-page: 16px;
  --radius-full: 999px;
  --font-family-body: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-family-heading: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-family-code: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
  --duration-fast: 150ms;
  --duration-medium: 250ms;
  --duration-slow: 500ms;
  --ease-standard: cubic-bezier(0.22,1,0.36,1);
  --cfin-profit: light-dark(rgb(7,102,45), rgb(108,195,128));
  --cfin-profit-bg: light-dark(rgba(7,102,45,0.10), rgba(108,195,128,0.15));
  --cfin-loss: light-dark(rgb(110,70,145), rgb(202,158,245));
  --cfin-profit-text: light-dark(rgb(3,78,33), rgb(137,210,152));
  --cfin-loss-text: light-dark(rgb(84,52,113), rgb(216,179,253));
  --cfin-profit-ink: light-dark(rgb(7,102,45), rgb(108,195,128));
  --cfin-loss-ink: light-dark(rgb(110,70,145), rgb(202,158,245));
  --cfin-profit-graphic: light-dark(rgb(11,123,56), rgb(60,168,92));
  --cfin-loss-graphic: light-dark(rgb(133,85,174), rgb(177,126,224));
  --cfin-profit-emphasis: light-dark(rgb(3,78,33), rgb(169,225,180));
  --cfin-loss-emphasis: light-dark(rgb(84,52,113), rgb(227,202,254));
  --cfin-profit-border: light-dark(rgb(9,112,51), rgb(137,210,152));
  --cfin-loss-border: light-dark(rgb(121,77,159), rgb(216,179,253));
  --cfin-profit-wash: light-dark(rgb(205,241,211), rgb(1,57,22));
  --cfin-loss-wash: light-dark(rgb(240,227,254), rgb(62,38,83));
  --cfin-profit-vivid: light-dark(rgb(25,144,69), rgb(84,182,110));
  --cfin-loss-bg: light-dark(rgba(110,70,145,0.10), rgba(202,158,245,0.15));
  --cfin-loss-vivid: light-dark(rgb(154,102,199), rgb(191,142,236));
  --cfin-accent-fill: light-dark(rgb(20,95,200), rgb(20,95,200));
  --cfin-accent-fill-hover: light-dark(rgb(15,78,170), rgb(15,78,170));
  --cfin-profit-fill: light-dark(rgb(11,123,56), rgb(60,168,92));
  --cfin-loss-fill: light-dark(rgb(133,85,174), rgb(177,126,224));
  --cfin-text-tertiary: light-dark(rgb(110,110,114), rgb(147,147,151));
  --cfin-surface-3: light-dark(rgb(229,229,234), rgb(58,58,60));
  --cfin-surface-hover: light-dark(rgb(229,229,234), rgb(58,58,60));
  --cfin-surface-selected: light-dark(rgb(209,209,214), rgb(72,72,74));
  --cfin-surface-input: light-dark(rgb(255,255,255), rgb(38,38,40));
  --cfin-glass-bg: light-dark(rgba(255,255,255,0.80), rgba(44,44,46,0.72));
  --cfin-glass-blur: 0px;
  --cfin-glass-border: light-dark(rgba(0,0,0,0.10), rgba(255,255,255,0.12));
  --cfin-iris-brand-from: #6a71e0;
  --cfin-iris-brand-to: #a95ff4;
  --cfin-iris-gradient: linear-gradient(120deg,#6a71e0,#a95ff4);
  --cfin-green-brand: #34C759;
  --cfin-blue-brand: #0A84FF;
  --cfin-iris-text: light-dark(rgb(78,86,218), rgb(162,166,236));
  --cfin-green-text: light-dark(rgb(7,102,45), rgb(108,195,128));
  --cfin-amber-text: light-dark(rgb(121,89,52), rgb(223,187,144));
  --cfin-fam-unknown: light-dark(rgb(102,102,106), rgb(163,163,168));
  --cfin-series-balance: light-dark(rgb(11,123,56), rgb(60,168,92));
  --cfin-series-effective: light-dark(rgb(38,152,181), rgb(38,152,181));
  --cfin-series-withdrawal: light-dark(rgb(124,92,200), rgb(143,116,208));
  --cfin-series-drawdown: light-dark(rgb(133,85,174), rgb(177,126,224));
  --cfin-series-vault: light-dark(rgb(6,96,198), rgb(109,176,251));
  --cfin-vault: light-dark(rgb(6,96,198), rgb(109,176,251));
  --cfin-withdrawal: light-dark(rgb(124,92,200), rgb(143,116,208));
  --cfin-neutral: light-dark(rgb(102,102,106), rgb(163,163,168));
  --cfin-return: light-dark(rgb(38,152,181), rgb(38,152,181));
  --cfin-candle-bull: light-dark(rgb(11,123,56), rgb(60,168,92));
  --cfin-candle-bear: light-dark(rgb(133,85,174), rgb(177,126,224));
  --cfin-z-sticky: 100;
  --cfin-z-nav: 200;
  --cfin-z-scrim: 300;
  --cfin-z-drawer: 400;
  --cfin-z-dropdown: 500;
  --cfin-z-banner: 600;
  --cfin-z-banner-stack: 610;
  --cfin-z-chat: 700;
  --cfin-z-modal-scrim: 800;
  --cfin-z-modal: 810;
  --cfin-z-popover: 900;
  --cfin-z-tooltip: 1000;
  --cfin-z-toast: 1100;
  --cfin-z-skiplink: 1200;
}

/* ==== BEGIN GENERATED VARIANT LAYER — build-theme-tokens.mjs ==== */
/* GENERATED by scripts/build-theme-tokens.mjs — DO NOT EDIT.
 * Source: src/shared/theme/themeVariants.js
 *
 * PER-HOST BRAND IDENTITY. Two variants over ONE token system:
 *
 *   (no attribute)                 CFIN   — www.cfin.be, and every Jinja page
 *   [data-cfin-variant="cfin"]     CFIN   — explicit form of the same thing
 *   [data-cfin-variant="iris"]     IRIS   — trade.cfin.be: the app and admin
 *
 * The attribute goes on the DOCUMENT ELEMENT, alongside Astryx's
 * data-astryx-theme, so one set of values serves both the scoped Astryx world
 * and plain CSS.
 *
 * Only the 16 names below vary. Surfaces, radii, type, spacing, motion,
 * z-index and ALL money semantics are shared and live in the base theme — if
 * profit green differed per host it would read as a data difference.
 *
 * Deliberately UNLAYERED, matching site-tokens.css and theme/canvas.css:
 * Astryx's own rules live in cascade layers and unlayered rules beat layered
 * ones, so a component style can never silently win against a brand token.
 */
:root,
:root[data-cfin-variant="cfin"],
:root[data-cfin-variant="cfin"] [data-astryx-theme],
:root:not([data-cfin-variant]) [data-astryx-theme] {
  --color-accent: light-dark(#0760c6, #6fa8f7);
  --cfin-account-all: light-dark(#065CBE, #127FFF);
  --color-text-accent: light-dark(#0760c6, #6fa8f7);
  --color-icon-accent: light-dark(#0760c6, #6fa8f7);
  --color-on-accent: light-dark(rgb(255,255,255), rgb(28,28,30));
  --cfin-accent-fill: #0760c6;
  --cfin-accent-fill-hover: #0051ab;
  --cfin-on-accent-fill: rgb(255,255,255);
  --cfin-brand-from: #34c759;
  --cfin-brand-to: #0760c6;
  --cfin-brand-gradient: linear-gradient(135deg, #34c759 0%, #47c8aa 50%, #0760c6 100%);
  --cfin-brand-text: light-dark(#0760c6, #6fa8f7);
  --cfin-aurora-hue-1: #0a84ff;
  --cfin-aurora-hue-2: #a95ff4;
  --cfin-aurora-hue-3: #47c8aa;
  --cfin-aurora-hue-4: #6a71e0;
}

:root[data-cfin-variant="iris"],
:root[data-cfin-variant="iris"] [data-astryx-theme] {
  --color-accent: light-dark(#5053c5, #929df7);
  --cfin-account-all: light-dark(#3D2CC4, #7C87EC);
  --color-text-accent: light-dark(#5053c5, #929df7);
  --color-icon-accent: light-dark(#5053c5, #929df7);
  --color-on-accent: light-dark(rgb(255,255,255), rgb(28,28,30));
  --cfin-accent-fill: #5053c5;
  --cfin-accent-fill-hover: #4242b3;
  --cfin-on-accent-fill: rgb(255,255,255);
  --cfin-brand-from: #6a71e0;
  --cfin-brand-to: #a95ff4;
  --cfin-brand-gradient: linear-gradient(135deg, #6a71e0 0%, #a95ff4 100%);
  --cfin-brand-text: light-dark(#5053c5, #929df7);
  --cfin-aurora-hue-1: #0a84ff;
  --cfin-aurora-hue-2: #a95ff4;
  --cfin-aurora-hue-3: #47c8aa;
  --cfin-aurora-hue-4: #6a71e0;
}
/* ==== END GENERATED VARIANT LAYER ==== */
