/* ===== Brand Refresh: Codex Token Tier =====
   Two tiers below:

   1. Primitive palette (--color-<palette>-<step>) -- the full raw color scale,
      generated from Codex's own Figma variable export (docs/brand-refresh/
      root.tokens.json, 232 tokens across 12 palettes: deep-teal, vapor, black,
      aubergine, vermillion, indigo, lime, cherry, ruby, ember, gold, alpha).
      Step names (0-15, half-steps like "1-5", and "-brand"-flagged steps e.g.
      "8-brand") are Codex's own Figma step naming, not invented here. Generated
      via a script, not hand-typed, so it's a faithful 1:1 port -- see git history
      for the generator if it needs to be re-run after a token update upstream.

   2. Semantic tier, light/default mode only -- Codex ships a .dark variant we
      haven't ported yet (see TODO below now that dark mode is planned). Named to
      match Codex's own role/leaf convention directly (`--<role>-<leaf>`, e.g.
      `--neutral-bg`, `--chart-accent-teal-regular`) rather than an invented
      `--brand-*` prefix on everything, since nothing here is article-facing --
      renaming custom properties is a purely internal, safe refactor. The one
      exception is the role Codex itself calls `brand` (--brand-bg, --brand-text,
      --brand-icon, --brand-border(-strong), --brand-gradient-*, --brand-logo --
      the actual brand-red color role), which keeps the `brand-` prefix because
      that IS its real name, plus a couple of non-color utility tokens
      (--brand-font-family-sans/-mono, --brand-font-weight-medium/-semibold)
      that stay prefixed since we don't have a confirmed Codex name for them
      (they weren't in either Figma export). --radius-* and the font
      family/size/weight/tracking primitives below ARE confirmed Codex names
      now (--radius-* via Joy reading Codex's Figma Dev Mode output directly;
      font.* via root.tokens.json), so those are unprefixed too. No name here
      collides with the existing --clr-* tier in
      css-root.css (different leaf-naming scheme entirely), so no renaming or
      overwriting happens there either. Originally extracted by hand from
      @knowbe4/codex v68.65.0 (dist/theme.css +
      dist/style.css); cross-checked and filled out against a second, more
      complete Figma semantic export (docs/brand-refresh/Semantic/Light.tokens.json
      + Dark.tokens.json -- 242 tokens each, role/leaf keys like `neutral.bg`,
      `chart.accent.teal.regular`, mapping straight to `--neutral-bg`,
      `--chart-accent-teal-regular` etc.) once that became available. That
      audit fixed 4 small drifts (e.g. --critical-bg-soft was the CSS
      keyword `snow` instead of its actual hex) and added everything that first
      hand-extraction pass had missed: neutral.heading/border-inverse, all the
      *.glow tokens, fixed.bg-black-alpha/overlay, and five whole sections that
      didn't exist in the original pass at all -- Page, Shadow, Glow, Scroll, and
      Chart (categorical/accent/sequential -- Codex's actual designed tag and
      data-viz color system, 100+ tokens).

   DONE(dark mode) -- this paragraph used to read "DEFERRED", and the stale part
   was not the status but the INSTRUCTION. It said to port dark mode from
   Semantic/Dark.tokens.json, the Figma export. That block now exists further
   down (`:root[data-theme='dark']`) and it is a manual toggle, not
   prefers-color-scheme, as planned. But on 2026-10-25 nine of its ink values
   were corrected against Codex's SHIPPED stylesheet, which disagrees with the
   Figma export: the export documents #ffffff for six text roles and the live
   site never puts pure white on text. So the sentence "this is the source to
   port" would now send someone back to the wrong source and quietly undo that
   fix. The source of truth for token VALUES is the live dump
   (`.dark-mode, [data-theme=dark]` in entry.*.css, read from DevTools); Figma is
   reference. The long note on the dark block itself has the full diff.

   Deferred, not included here:
   - Full type scale / spacing scale: Codex only customizes 3 font sizes (xs/sm/4xl)
     on top of Tailwind's stock scale -- not a distinct enough system to port over
     KB4's existing step-0..step-8 type scale. Only font family/weight are ported.
   - --hyperlink-link-soft-visited: still undefined in both Codex's compiled
     source AND the newer Semantic export (hyperlink role only has link/
     link-visited/link-soft/link-inverse/link-inverse-visited, no soft-visited
     variant). The unused indigo/13-brand (#3a2a68) primitive remains a strong,
     unconfirmed candidate -- not wired in, flagging rather than guessing.
*/
:root {
  /* ===== Primitive palette (Codex Figma export) ===== */
  /* deep-teal */
  --color-deep-teal-0: #f0fbff;
  --color-deep-teal-0-5: #e0f7fe;
  --color-deep-teal-1: #cff2fc;
  --color-deep-teal-1-5: #bfecfa;
  --color-deep-teal-2: #afe7f8;
  --color-deep-teal-3: #90dbf3;
  --color-deep-teal-4: #73ceec;
  --color-deep-teal-5: #5ac0e4;
  --color-deep-teal-6: #44b1d9;
  --color-deep-teal-7: #32a1cc;
  --color-deep-teal-8: #2390bc;
  --color-deep-teal-9: #177da9;
  --color-deep-teal-10: #0f6a94;
  --color-deep-teal-11: #08577c;
  --color-deep-teal-12: #044463;
  --color-deep-teal-13: #023249;
  --color-deep-teal-13-5-brand: #01293d;
  --color-deep-teal-14: #002131;
  --color-deep-teal-14-5: #001925;
  --color-deep-teal-15: #001119;

  /* vapor */
  --color-vapor-0: #faffff;
  --color-vapor-0-5: #f5fefe;
  --color-vapor-1: #f2fdfd;
  --color-vapor-1-5: #effbfb;
  --color-vapor-2: #ebf8f8;
  --color-vapor-3: #e5f2f3;
  --color-vapor-4: #deebec;
  --color-vapor-5: #d4e2e4;
  --color-vapor-6: #c9d7d9;
  --color-vapor-7-brand: #bbcbce;
  --color-vapor-8: #aab9bc;
  --color-vapor-9: #96a6a9;
  --color-vapor-10: #809094;
  --color-vapor-11: #68787c;
  --color-vapor-12: #4f5f63;
  --color-vapor-13: #384649;
  --color-vapor-13-5: #2e3a3d;
  --color-vapor-14: #232e31;
  --color-vapor-14-5: #1a2325;
  --color-vapor-15: #111819;

  /* black */
  --color-black-0: #ffffff;
  --color-black-0-5: #fefefe;
  --color-black-1: #fdfdfe;
  --color-black-1-5: #f9fbfc;
  --color-black-2: #f6f8fa;
  --color-black-3: #ebf0f4;
  --color-black-4: #dce4eb;
  --color-black-5: #c8d5e0;
  --color-black-6: #b2c3d2;
  --color-black-7: #99aec1;
  --color-black-8: #8198ad;
  --color-black-9: #698198;
  --color-black-10: #536a80;
  --color-black-11: #3f5467;
  --color-black-12: #2e3e4e;
  --color-black-13: #1e2a35;
  --color-black-13-5: #172029;
  --color-black-14-brand: #10171e;
  --color-black-14-5: #0b0f13;
  --color-black-15: #050709;

  /* aubergine */
  --color-aubergine-0: #fff0f5;
  --color-aubergine-0-5: #fee5ed;
  --color-aubergine-1: #fcdae6;
  --color-aubergine-1-5: #fad0de;
  --color-aubergine-2: #f8c5d6;
  --color-aubergine-3: #f3afc6;
  --color-aubergine-4: #ec9bb6;
  --color-aubergine-5: #e488a6;
  --color-aubergine-6: #d97797;
  --color-aubergine-7: #cc6788;
  --color-aubergine-8: #bc5878;
  --color-aubergine-9: #a94a69;
  --color-aubergine-10: #943d59;
  --color-aubergine-11: #7c3149;
  --color-aubergine-12: #632539;
  --color-aubergine-13: #491b2a;
  --color-aubergine-13-5-brand: #391621;
  --color-aubergine-14: #31111b;
  --color-aubergine-14-5: #250d15;
  --color-aubergine-15: #19090e;

  /* vermillion */
  --color-vermillion-0: #fef7f6;
  --color-vermillion-0-5: #ffece8;
  --color-vermillion-1: #fed8d1;
  --color-vermillion-1-5: #fec6bb;
  --color-vermillion-2: #fdb5a6;
  --color-vermillion-3: #fc9681;
  --color-vermillion-4: #fb7d64;
  --color-vermillion-5: #f8694c;
  --color-vermillion-6: #f6593a;
  --color-vermillion-7: #f24d2c;
  --color-vermillion-8-brand: #ef4523;
  --color-vermillion-9: #e43b19;
  --color-vermillion-10: #d73312;
  --color-vermillion-11: #c12b0d;
  --color-vermillion-12: #992008;
  --color-vermillion-13: #611404;
  --color-vermillion-13-5: #470e03;
  --color-vermillion-14: #2d0902;
  --color-vermillion-14-5: #170501;
  --color-vermillion-15: #0a0200;

  /* indigo */
  --color-indigo-0: #f3f0ff;
  --color-indigo-0-5: #ece8fe;
  --color-indigo-1: #dfd8fb;
  --color-indigo-1-5: #cbc0f6;
  --color-indigo-2: #bdb0f2;
  --color-indigo-3: #b0a1ec;
  --color-indigo-4: #a492e6;
  --color-indigo-5: #9884de;
  --color-indigo-6: #8c77d5;
  --color-indigo-7: #806bca;
  --color-indigo-8: #755fbe;
  --color-indigo-9: #6a54b0;
  --color-indigo-10: #5e499f;
  --color-indigo-11: #523f8e;
  --color-indigo-12: #47357b;
  --color-indigo-13-brand: #3a2a68;
  --color-indigo-13-5: #2f2253;
  --color-indigo-14: #24193f;
  --color-indigo-14-5: #19112c;
  --color-indigo-15: #0f0a19;

  /* lime */
  --color-lime-0: #fafff7;
  --color-lime-0-5: #f3ffed;
  --color-lime-1: #edfee3;
  --color-lime-1-5: #e6fed9;
  --color-lime-2: #e0fdcf;
  --color-lime-3: #d5fcbc;
  --color-lime-4: #cafbaa;
  --color-lime-5: #c1f999;
  --color-lime-6: #b9f68b;
  --color-lime-7: #b2f27e;
  --color-lime-8: #abed72;
  --color-lime-9: #a3e567;
  --color-lime-10: #98d95c;
  --color-lime-11: #88c34f;
  --color-lime-12: #6c9d3d;
  --color-lime-13: #476827;
  --color-lime-13-5: #364f1d;
  --color-lime-14: #253614;
  --color-lime-14-5: #16200c;
  --color-lime-15: #070a04;

  /* cherry */
  --color-cherry-0: #fffafa;
  --color-cherry-0-5: #ffeaea;
  --color-cherry-1: #fedadb;
  --color-cherry-1-5: #fecacb;
  --color-cherry-2: #fdbabb;
  --color-cherry-3: #fc9c9e;
  --color-cherry-4: #fb8082;
  --color-cherry-5: #f96769;
  --color-cherry-6: #f65154;
  --color-cherry-7: #f23e41;
  --color-cherry-8: #ed2e31;
  --color-cherry-9: #e52124;
  --color-cherry-10: #d91619;
  --color-cherry-11: #c30e11;
  --color-cherry-12: #9d070a;
  --color-cherry-13: #680204;
  --color-cherry-13-5: #4f0102;
  --color-cherry-14: #360102;
  --color-cherry-14-5: #200001;
  --color-cherry-15: #0a0000;

  /* ruby */
  --color-ruby-0: #fffafb;
  --color-ruby-0-5: #ffeaef;
  --color-ruby-1: #fedae3;
  --color-ruby-1-5: #fecad8;
  --color-ruby-2: #fdbacc;
  --color-ruby-3: #fc9cb7;
  --color-ruby-4: #fb80a4;
  --color-ruby-5: #f96794;
  --color-ruby-6: #f65186;
  --color-ruby-7: #f23e7a;
  --color-ruby-8: #ed2e6f;
  --color-ruby-9: #e52165;
  --color-ruby-10: #d9165b;
  --color-ruby-11: #c30e4e;
  --color-ruby-12: #9d073d;
  --color-ruby-13: #680227;
  --color-ruby-13-5: #4f011d;
  --color-ruby-14: #360114;
  --color-ruby-14-5: #20000c;
  --color-ruby-15: #0a0004;

  /* ember */
  --color-ember-0: #fffcfa;
  --color-ember-0-5: #fff1ea;
  --color-ember-1: #ffe6d9;
  --color-ember-1-5: #ffdbc9;
  --color-ember-2: #ffd0b8;
  --color-ember-3: #ffbb99;
  --color-ember-4: #ffa87c;
  --color-ember-5: #ff9661;
  --color-ember-6: #ff8548;
  --color-ember-7: #ff7631;
  --color-ember-8: #fd681e;
  --color-ember-9: #fd5a09;
  --color-ember-10: #ed5002;
  --color-ember-11: #d14600;
  --color-ember-12: #a43700;
  --color-ember-13: #6a2300;
  --color-ember-13-5: #501b00;
  --color-ember-14: #371200;
  --color-ember-14-5: #200b00;
  --color-ember-15: #0a0300;

  /* gold */
  --color-gold-0: #fffef7;
  --color-gold-0-5: #fff7d5;
  --color-gold-1: #feefb3;
  --color-gold-1-5: #fee696;
  --color-gold-2: #fddc79;
  --color-gold-3: #fcca4e;
  --color-gold-4: #fbb930;
  --color-gold-5: #f8aa1e;
  --color-gold-6: #f69d12;
  --color-gold-7: #f2920a;
  --color-gold-8: #ec8806;
  --color-gold-9: #e47f03;
  --color-gold-10: #d77402;
  --color-gold-11: #c16501;
  --color-gold-12: #994f00;
  --color-gold-13: #613100;
  --color-gold-13-5: #472400;
  --color-gold-14: #2d1700;
  --color-gold-14-5: #170b00;
  --color-gold-15: #000000;

  /* alpha */
  --color-alpha-white-10: #ffffff1a;
  --color-alpha-black-10: #10171e1a;
  --color-alpha-white-20: #ffffff33;
  --color-alpha-black-20: #10171e33;
  --color-alpha-black-30: #10171e4d;
  --color-alpha-black-40: #10171e66;
  --color-alpha-black-50: #10171e80;
  --color-alpha-black-60: #10171e99;
  --color-alpha-white-70: #ffffffb2;
  --color-alpha-black-70: #10171eb2;
  --color-alpha-white-85: #ffffffd9;
  --color-alpha-black-85: #10171ed9;

  /* ===== Primitive typography (Codex Figma export) ===== */
  /* family */
  --font-family-primary: 'Sora';
  --font-family-secondary: 'Inter';
  --font-family-icon: 'Font Awesome 7 pro';
  --font-family-brand-icon: 'Font Awesome 7 Brands';

  /* size (Codex FONT_SIZE Figma variables, px) */
  --font-size-3xs: 8px;
  --font-size-2xs: 10px;
  --font-size-xs: 12px;
  --font-size-sm: 14px;
  --font-size-base: 16px;
  --font-size-lg: 19px;
  --font-size-xl: 20px;
  --font-size-2xl: 24px;
  --font-size-3xl: 30px;
  --font-size-4xl: 36px;
  --font-size-5xl: 48px;
  --font-size-6xl: 60px;
  --font-size-7xl: 72px;
  --font-size-8xl: 96px;
  --font-size-9xl: 128px;

  /* weight */
  --font-weight-regular: 400;
  --font-weight-strong: 600;
  --font-weight-icon-regular: 'Regular';
  --font-weight-icon-solid: 'Solid';

  /* tracking (letter-spacing, px) */
  --font-tracking-tighter: -0.8px;
  --font-tracking-tight: -0.4px;
  --font-tracking-normal: 0px;
  --font-tracking-wide: 0.4px;
  --font-tracking-wider: 0.8px;
  --font-tracking-widest: 1.6px;

  /* ===== Semantic tier (light/default mode) ===== */
  /* Brand */
  --brand-bg: #d73312;
  --brand-border: #ef4523;
  --brand-border-strong: #992008;
  --brand-gradient-l-active: #992008;
  --brand-gradient-l-hover: #992008;
  --brand-gradient-r-active: #992008;
  --brand-gradient-r-hover: #d73312;
  --brand-icon: #ef4523;
  /* vermillion-12, was vermillion-11 (#c12b0d). RAISED FOR CONTRAST, 2026-10-28,
     Joy's call. This token is the sitewide link hover (css-reset.css:466) as well
     as the breadcrumb trail's, so it is read as body-sized text everywhere it
     appears -- and the floor on this project is AAA (7:1), which vermillion-11
     missed on every surface in both tiers: 5.75:1 on --neutral-bg, 4.75:1 on
     --neutral-bg-component.

       surface                     was (11)   now (12)
       --neutral-bg      #faffff    5.75       8.12  AAA
       --neutral-bg-comp #deebec    4.75       6.71  AA

     ONE STEP, NOT TWO, AND THE REASON IS THE HOVER'S DIRECTION. vermillion-13
     (#611404) clears AAA on both surfaces at 12.93:1 and 10.68:1, and was
     declined: the article body copy is --neutral-icon at 9.72:1, so 13 would
     render a hovered link DARKER than the paragraph around it. The note on
     `a:not([class])` picks this token over --hyperlink-link-soft precisely
     because a hover has to move away from body text "in the direction that reads
     as interactive"; 12 sits just lighter than body copy and still reads red,
     13 reads as emphasis-black. Do not "finish the job" by stepping to 13.

     --neutral-bg-component stays AA at 6.71:1 and that is the documented
     exception, not an oversight. Two places land a hover on that mid-tone: the
     article sidebar rail (css-page-article.css:1335) and the requests table,
     which is the worse case because `tbody tr:hover td` tints the row underneath
     the hovered link. The rest state is untouched and unaffected on both --
     --hyperlink-link is 20.00:1 light and 12.73:1 dark -- and the underline is
     permanent, so no link anywhere depends on this colour to be recognisable as
     a link.

     CALLOUT LINKS WERE LISTED HERE AS A THIRD CASE, 2026-10-28, AND THAT WAS
     WRONG. They never touch --neutral-bg-component; they sit on the severity's
     own fill -- regular --*-bg in light, saturated --*-bg-strong in dark. Light
     is better than the figure above rather than worse: all four severities clear
     AAA on hover at 7.37 / 7.46 / 7.42 / 7.10:1. Dark is worse and is an open
     defect rather than an accepted exception -- #fdb5a6 is 4.63:1 on info,
     3.64:1 on critical, 2.69:1 on high and 1.01:1 on success. Nothing on this
     ramp fixes it: strong emphasis puts the rest ink at --fixed-white /
     --fixed-black, already at the ceiling, so a hover has nowhere to go.

     AND THOSE AAA FIGURES ANSWERED THE WRONG QUESTION, which is the correction
     that matters most here. "Readable on the fill" is not "visibly changed":
     scored rest-ink-against-HOVER-ink, `.callout-warn` is dE00 3.2, because
     --critical-text is cherry-12 and this token is vermillion-12 -- the same
     step index on adjacent red hues. Joy saw it as no hover at all.

     SO CALLOUT LINKS NO LONGER READ THIS TOKEN IN EITHER TIER, and they do not
     read a severity hover ink either -- the colour axis inside a callout turned
     out to be exhausted at both floors in both directions, so the hover there is
     Codex's underline weight and the ink holds still. The full measurement is on
     `[class*='callout-'] a:hover` in css-components.css and in plan.md's Phase 1
     log; the short version is that AAA on those pale fills caps the ink at
     L* 34.8 while the rest inks already sit at L* 26.0-40.2, and in dark
     --high-bg-strong and --critical-bg-strong cap out at 4.59:1 and 6.19:1 for
     ANY ink at all. Do not spend a --brand-text step on any of it, and do not
     reintroduce a colour hover on a callout without re-reading that note.

     Shares its value with --brand-border-strong in this tier, which is fine:
     that collision is text-against-border, not the fill-against-border kind that
     made the table header lose its column lines (see --neutral-border-soft). */
  --brand-text: #992008;
  --brand-logo: #10171e;

  /* Critical */
  --critical-bg: #ffeaea;
  --critical-bg-soft: #fffafa;
  --critical-bg-strong: #c30e11;
  --critical-bg-strong-active: #680204;
  --critical-bg-strong-hover: #9d070a;
  --critical-border: #f65154;
  --critical-border-strong: #9d070a;
  --critical-heading: #c30e11;
  --critical-icon: #e52124;
  --critical-text: #9d070a;
  --critical-glow: #fb808266;

  /* Success */
  --success-bg: #e0fdcf;
  --success-bg-soft: #fafff7;
  --success-bg-strong: #a3e567;
  --success-bg-strong-active: #88c34f;
  --success-bg-strong-hover: #88c34f;
  --success-heading: #6c9d3d;
  --success-text: #476827;
  --success-icon: #6c9d3d;
  --success-border: #88c34f;
  --success-border-strong: #88c34f;
  --success-glow: #cafbaa66;

  /* Warning */
  --warning-bg: #fff7d5;
  --warning-bg-soft: #fffef7;
  --warning-bg-strong: #fcca4e;
  --warning-bg-strong-active: #f8aa1e;
  --warning-bg-strong-hover: #f8aa1e;
  --warning-border: #f8aa1e;
  --warning-border-strong: #f69d12;
  --warning-heading: #d77402;
  --warning-icon: #f2920a;
  --warning-text: #613100;
  --warning-glow: #fbb93066;

  /* High */
  --high-bg: #fff1ea;
  --high-bg-soft: #fffcfa;
  --high-bg-strong: #d14600;
  --high-bg-strong-active: #6a2300;
  --high-bg-strong-hover: #a43700;
  --high-border: #ff8548;
  --high-border-strong: #a43700;
  --high-heading: #d14600;
  --high-icon: #fd681e;
  --high-text: #a43700;
  --high-glow: #fba98066;

  /* Info */
  --info-bg: #e0f7fe;
  --info-bg-soft: #f0fbff;
  --info-bg-strong: #0f6a94;
  --info-bg-strong-active: #023249;
  --info-bg-strong-hover: #044463;
  --info-border: #44b1d9;
  --info-border-strong: #044463;
  --info-heading: #08577c;
  --info-icon: #177da9;
  --info-text: #044463;

  /* Neutral */
  --neutral-bg: #faffff;
  --neutral-bg-alpha: #10171e1a;
  --neutral-bg-component: #deebec;
  --neutral-bg-component-active: #c9d7d9;
  --neutral-bg-component-hover: #d4e2e4;
  --neutral-bg-component-soft: #f2fdfd;
  --neutral-bg-component-soft-active: #deebec;
  --neutral-bg-component-soft-hover: #e5f2f3;
  --neutral-bg-highlight: #e5f2f3;
  --neutral-bg-soft: #ebf8f8;
  --neutral-bg-strong: #4f5f63;
  --neutral-bg-strong-active: #1a2325;
  --neutral-bg-strong-hover: #2e3a3d;
  --neutral-border: #aab9bc;
  --neutral-border-alpha: #10171e1a;
  --neutral-border-alpha-strong: #10171e33;
  --neutral-border-soft: #c9d7d9;
  --neutral-border-strong: #384649;
  --neutral-icon: #384649;
  --neutral-icon-soft: #96a6a9;
  --neutral-icon-strong: #10171e;
  --neutral-icon-inverse: #faffff;
  --neutral-text: #10171e;
  --neutral-text-inverse: #faffff;
  --neutral-text-soft: #4f5f63;
  --neutral-heading: #10171e;
  --neutral-border-inverse: #faffff;

  /* Form */
  --form-bg: #faffff;
  --form-bg-active: #effbfb;
  --form-bg-error: #fffafb;
  --form-bg-hover: #f2fdfd;
  --form-bg-highlight: #90dbf3;
  --form-bg-readonly: #ebf8f8;
  --form-border: #809094;
  --form-border-active: #4f5f63;
  --form-border-error: #f65154;
  --form-border-readonly: #bbcbce;
  --form-focus-ring: #177da9;

  /* Fixed */
  /* The two -active values were `b2` until 2026-10-25, where the shipped
     stylesheet has `b3`. Both spellings mean "70% alpha" -- b2 is 178/255
     (69.8%) and b3 is 179/255 (70.2%) -- so this is a rounding difference with
     no visible effect, taken only so a future diff against the live dump comes
     back clean. The -hover pair at `d9` (85%) already matched. */
  --fixed-black: #10171e;
  --fixed-black-active: #10171eb3;
  --fixed-black-hover: #10171ed9;
  --fixed-white: #ffffff;
  --fixed-white-active: #ffffffb3;
  --fixed-white-hover: #ffffffd9;
  --fixed-bg-black-alpha: #10171e33;
  --fixed-overlay: #10171e80;

  /* Hyperlink.
     --hyperlink-link-visited IS CARRIED BUT NOT USED, which is a decision and
     not an omission. It is a purple (#755fbe), and the plum it would replace
     (--clr-secondary-140, #56215d) is the exact thing Joy asked to get rid of
     on 2026-10-24: "we're going to keep coming across the purple links
     everywhere we go". Honouring the role would have swapped one purple for
     another on every link anybody has already clicked, which is most of the
     links on a help centre. css-reset.css:357 therefore states only
     --hyperlink-link and leaves :visited to inherit it. Adding the state back
     is one rule if we decide the distinction is worth the colour. */
  --hyperlink-link: #050709;
  --hyperlink-link-visited: #755fbe;
  --hyperlink-link-soft: #384649;
  --hyperlink-link-inverse: #faffff;
  --hyperlink-link-inverse-visited: #dfd8fb;

  /* Page */
  --page-bg-middle: #faffff;
  --page-bg-corner: #e5f2f3;
  --page-bg-corner-transparent: #e5f2f300;

  /* Shadow -- color tokens ported earlier; the numeric offset/blur ones below
     were missed the first time (flattening only picked up $type "color", not
     "number") and filled in now against the same Light.tokens.json source.

     How Codex composes these, read off its own stylesheet on 2026-10-03:
       --shadow-regular: 0 var(--shadow-y-offset) var(--shadow-blur) 0 <color>
       --shadow-hover:   0 var(--shadow-y-offset-hover) var(--shadow-blur-hover) 0 <color>
     i.e. no x-offset and no spread. Worth having written down, because consumers
     have to assemble the box-shadow by hand -- including css-page-header.css's
     .navbar-btn, which matches this shape.

     Both of those two appear struck through in DevTools, and they are genuinely
     dead in Codex: each is declared in terms of a var() of *its own name*
     (--shadow-regular resolving --shadow-regular), which is a dependency cycle,
     so the declaration is invalid at computed-value time. It is a naming
     collision between Codex's alias layer and the primitive underneath --
     --shadow-floating-* escapes it only by suffixing its colour token -color,
     which is why --shadow-floating is the one composite that survives.
     The names below are the primitives, the tier that works. Do not "fix" this by
     redefining --shadow-regular as a composite here: that would reintroduce the
     same cycle in our file. */
  --shadow-regular: #10171e1a;
  --shadow-hover: #10171e1a;
  --shadow-y-offset: 2px;
  --shadow-y-offset-hover: 6px;
  --shadow-blur: 6px;
  --shadow-blur-hover: 16px;
  --shadow-floating-y-offset: 2px;
  --shadow-floating-blur: 20px;
  --shadow-floating-spread: 2px;
  --shadow-floating-color: #10171e33;

  /* Glow -- same numeric gap as Shadow above. color-wide/color-tight are
     transparent white in light mode (a light-mode no-op; presumably a real
     glow in dark mode -- worth re-checking against Dark.tokens.json once
     dark-mode work starts). */
  --glow-wide-pos-y: 0px;
  --glow-wide-blur: 0px;
  --glow-color-wide: #ffffff00;
  --glow-tight-blur: 0px;
  --glow-color-tight: #ffffff00;
  --glow-error-blur: 12px;

  /* Border-width -- not in either Figma export (root.tokens.json is color+font
     only; Light/Dark.tokens.json have no top-level border-width role), so this
     is sourced directly from Joy reading Codex's Figma component in Dev Mode
     rather than from our JSON exports.

     Both values confirmed 2026-10-26 against the Codex Component Library file
     itself (get_variable_defs on the side-navigation documentation frame
     returns `border-width/regular: 1` and `border-width/heavy: 2`), which is a
     firmer source than the Dev Mode read above. `heavy` was added in that pass
     for the article page's table-of-contents rail; nothing else uses it yet. */
  --border-width-regular: 1px;
  --border-width-heavy: 2px;

  /* Scroll */
  --scroll-thumb: #96a6a9;
  --scroll-thumb-hover: #68787c;
  --scroll-thumb-active: #384649;

  /* Chart -- border + 10 categorical colors */
  --chart-border: #faffff;
  --chart-categorical-1: #4f5f63;
  --chart-categorical-2: #32a1cc;
  --chart-categorical-3: #d97797;
  --chart-categorical-4: #806bca;
  --chart-categorical-5: #c0cb6f;
  --chart-categorical-6: #42447d;
  --chart-categorical-7: #4fafa9;
  --chart-categorical-8: #9c90ab;
  --chart-categorical-9: #c47b7e;
  --chart-categorical-10: #ca8cba;

  /* Chart -- accent hues (regular/soft/strong per hue). "Indigo" is
     lowercased here for consistency; Codex's own Figma source capitalizes
     it inconsistently (accent.Indigo vs sequential.indigo). */
  --chart-accent-neutral-regular: #809094;
  --chart-accent-neutral-soft: #bbcbce;
  --chart-accent-neutral-strong: #232e31;
  --chart-accent-teal-regular: #32a1cc;
  --chart-accent-teal-soft: #afe7f8;
  --chart-accent-teal-strong: #044463;
  --chart-accent-aubergine-regular: #d97797;
  --chart-accent-aubergine-soft: #f8c5d6;
  --chart-accent-aubergine-strong: #7c3149;
  --chart-accent-indigo-regular: #806bca;
  --chart-accent-indigo-soft: #cbc0f6;
  --chart-accent-indigo-strong: #3a2a68;
  --chart-accent-positive-regular: #88c34f;
  --chart-accent-positive-soft: #c1f999;
  --chart-accent-positive-strong: #476827;
  --chart-accent-negative-regular: #e52124;
  --chart-accent-negative-soft: #fdbabb;
  --chart-accent-negative-strong: #9d070a;
  --chart-accent-warning-regular: #f69d12;
  --chart-accent-warning-soft: #fddc79;
  --chart-accent-warning-strong: #994f00;
  --chart-accent-risk-score-high-regular: #fd5a09;
  --chart-accent-risk-score-high-soft: #ffd0b8;
  --chart-accent-risk-score-high-strong: #a43700;

  /* Chart -- 9-step sequential ramps per hue, plus a matching border step */
  --chart-sequential-neutral-1: #1a2325;
  --chart-sequential-neutral-2: #2e3a3d;
  --chart-sequential-neutral-3: #4f5f63;
  --chart-sequential-neutral-4: #68787c;
  --chart-sequential-neutral-5: #809094;
  --chart-sequential-neutral-6: #96a6a9;
  --chart-sequential-neutral-7: #bbcbce;
  --chart-sequential-neutral-8: #deebec;
  --chart-sequential-neutral-9: #f5fefe;
  --chart-sequential-neutral-border: #809094;
  --chart-sequential-teal-1: #001925;
  --chart-sequential-teal-2: #01293d;
  --chart-sequential-teal-3: #044463;
  --chart-sequential-teal-4: #08577c;
  --chart-sequential-teal-5: #0f6a94;
  --chart-sequential-teal-6: #177da9;
  --chart-sequential-teal-7: #32a1cc;
  --chart-sequential-teal-8: #73ceec;
  --chart-sequential-teal-9: #e0f7fe;
  --chart-sequential-teal-border: #2390bc;
  --chart-sequential-aubergine-1: #250d15;
  --chart-sequential-aubergine-2: #491b2a;
  --chart-sequential-aubergine-3: #632539;
  --chart-sequential-aubergine-4: #7c3149;
  --chart-sequential-aubergine-5: #943d59;
  --chart-sequential-aubergine-6: #a94a69;
  --chart-sequential-aubergine-7: #cc6788;
  --chart-sequential-aubergine-8: #ec9bb6;
  --chart-sequential-aubergine-9: #fad0de;
  --chart-sequential-aubergine-border: #bc5878;
  --chart-sequential-indigo-1: #24193f;
  --chart-sequential-indigo-2: #2f2253;
  --chart-sequential-indigo-3: #47357b;
  --chart-sequential-indigo-4: #523f8e;
  --chart-sequential-indigo-5: #6a54b0;
  --chart-sequential-indigo-6: #806bca;
  --chart-sequential-indigo-7: #a492e6;
  --chart-sequential-indigo-8: #b0a1ec;
  --chart-sequential-indigo-9: #cbc0f6;
  --chart-sequential-indigo-border: #755fbe;
  --chart-sequential-positive-1: #253614;
  --chart-sequential-positive-2: #476827;
  --chart-sequential-positive-3: #6c9d3d;
  --chart-sequential-positive-4: #88c34f;
  --chart-sequential-positive-5: #a3e567;
  --chart-sequential-positive-6: #b2f27e;
  --chart-sequential-positive-7: #cafbaa;
  --chart-sequential-positive-8: #e6fed9;
  --chart-sequential-positive-9: #f3ffed;
  --chart-sequential-positive-border: #abed72;
  --chart-sequential-negative-1: #360102;
  --chart-sequential-negative-2: #680204;
  --chart-sequential-negative-3: #9d070a;
  --chart-sequential-negative-4: #c30e11;
  --chart-sequential-negative-5: #e52124;
  --chart-sequential-negative-6: #f23e41;
  --chart-sequential-negative-7: #fb8082;
  --chart-sequential-negative-8: #fdbabb;
  --chart-sequential-negative-9: #fedadb;
  --chart-sequential-negative-border: #ed2e31;
  --chart-sequential-warning-1: #2d1700;
  --chart-sequential-warning-2: #613100;
  --chart-sequential-warning-3: #994f00;
  --chart-sequential-warning-4: #d77402;
  --chart-sequential-warning-5: #ec8806;
  --chart-sequential-warning-6: #f8aa1e;
  --chart-sequential-warning-7: #fbb930;
  --chart-sequential-warning-8: #fddc79;
  --chart-sequential-warning-9: #feefb3;
  --chart-sequential-warning-border: #ec8806;

  /* Radius -- unprefixed now that Joy's Figma Dev Mode copy confirmed Codex's
     own name is exactly --radius-md (rem, not px like our first hand-extracted
     guess); --radius-sm follows the same confirmed pattern. --radius-round
     is KB4's own pill-shape addition (not a Codex token), kept large/unitless
     rather than converted to rem since "as round as possible" isn't a
     font-size-relative concept. */
  --radius-sm: 0.375rem;
  --radius-md: 0.75rem;
  --radius-round: 9999px;

  /* Typography -- practical CSS stacks/weights KB4 added on top of the Codex
     primitives above; not Codex tokens themselves, so still --brand-prefixed.
     --font-weight-regular/-strong (400/600) are now covered by the confirmed
     Codex primitives above -- medium (500) and semibold (600) below have no
     Codex counterpart in either Figma export, they're KB4-specific additions. */
  --brand-font-family-sans: 'Inter', Verdana, sans-serif;
  --brand-font-family-mono:
    'Space Mono', 'Hiragino Sans', 'Yu Gothic UI', 'Apple SD Gothic Neo',
    'Malgun Gothic', 'PingFang SC', 'Microsoft YaHei', 'PingFang TC',
    'Microsoft JhengHei', ui-monospace, 'SF Mono', 'Menlo', 'Consolas',
    monospace;
  --brand-font-weight-medium: 500;
  --brand-font-weight-semibold: 600;

  /* Stacking order, verbatim from the same Codex `:host, :root` block Joy pulled
     from DevTools on 2026-10-03. Recorded in full rather than only the three the
     header uses, matching how the colour tiers above are mirrored: the value of
     a scale like this is that the next layer added can find its slot without
     inventing a number, and the gaps between steps are the useful part.
     The header's existing hardcoded 10 and 20 turned out to be exactly
     --z-index-nav and --z-index-nav-flyout, so adopting these changes no
     computed value anywhere -- see css-page-header.css. */
  --z-index-behind: -1;
  --z-index-base: 0;
  --z-index-raised: 1;
  --z-index-nav: 10;
  --z-index-nav-flyout: 20;
  --z-index-sticky: 30;
  --z-index-drag: 40;
  --z-index-overlay: 100;
  --z-index-modal: 200;
  --z-index-floating: 300;
  --z-index-tooltip: 400;
  --z-index-toast: 500;

  /* Not Codex's, and deliberately not pretending to be. Codex's scale stops at
     --z-index-toast, and nothing in it anticipates a third-party widget that
     inline-styles itself past the top of it. Forethought's does:
     solve-widget.forethought.ai/embed.js sets `zIndex: "999999"` on the one
     iframe that is both launcher and panel, and `"1199"` on the sidepanel
     variant. Algolia's autocomplete sets its own wrapper to `1e4` -- so the
     header search dropdown was painting *under* the home page's floating_bar
     hero. Joy caught it on 2026-10-22: the second and third suggestions sliced
     in half by the "Ask a question..." pill.

     One more than Forethought's, and that is the whole specification. This is a
     ceiling to clear rather than a layer to design with, and the only
     relationship it has that means anything is "above that". Anything of ours
     that needs to stack against our own UI belongs in the scale above; if a
     second thing ever needs to clear the same ceiling, the two are peers at this
     value and should be ordered by source, not by inventing 1000001. */
  --z-index-above-vendor-widget: 1000000;

  /* Motion. Mostly real Codex tokens after all -- Joy found them in DevTools on
     2026-10-03, in Codex's own `:host, :root` block (entry.uEn_emt_.css). They
     are absent from both Figma exports and from the published component
     library, which is why the first pass through this section concluded Codex
     documented no timing and invented a scale instead.

     The invented curves turned out to be character-for-character identical to
     Codex's, and the invented 150ms step turned out to be Codex's documented
     default. That is reassuring rather than lucky: these are the Material
     standard-easing values, which is where both ended up independently.

     Provenance is readable from the names, and that is the point of the split
     below: a token with a Codex name is Codex's, verbatim from that block;
     anything still named --motion-* is ours, filling a gap Codex genuinely does
     not address. Only two of those are left.

     Codex's, verbatim:
     - --default-transition-duration and --default-transition-timing-function
       are its documented defaults. 0.15s is kept in Codex's own `s` unit rather
       than normalised to 150ms so this block diffs cleanly against the source.
     - --motion-duration-control is 0.2s, Codex's value for interactive controls,
       which is **not** the 0.15s global default. Its `.kb-button` rule sets
       `--tw-duration: .2s` and resolves `transition-duration` through it, so the
       default is only ever the fallback for things that do not set --tw-duration.
       The name is ours because --tw-* is Tailwind plumbing rather than a design
       token, but the value is Codex's and it is the one to reach for on anything
       the user clicks. Paired with --ease-in-out, Codex's --tw-ease for the same
       rule -- which, unlike on .kb-button-strong, does survive the cascade there.
     - all three curves. ease-out for anything entering or responding to the
       pointer (fast start, settles); ease-in-out for anything that both starts
       and stops in view; ease-in for anything leaving. Note Codex's own default
       timing function is ease-in-out, not ease-out.

     Ours, and why Codex has no equivalent:
     - --motion-duration-instant, for :active. Codex draws pressed states but
       says nothing about how fast to reach them, and a press has to feel like
       it already happened -- any perceptible ramp reads as lag, not animation.
     - --motion-duration-moderate, for changes that move layout: the hamburger
       panel's reveal, the mobile search row's 64px push. Codex's single 0.15s
       is tuned for colour and shadow on controls; larger travel needs longer to
       stay legible. This is the one value here with no external backing, so it
       is the one to second-guess in preview. It replaced a hardcoded 300ms on
       the hamburger bars and 350ms on the panel, so it is already a step toward
       Codex rather than away.
     - --motion-spin-duration, for the loading state's spinner. Codex draws a
       rotating arc and gives no period for the rotation.

     --motion-duration-slow is a hybrid: the **value is Codex's**, verbatim from
     `.kb-button-strong`'s `transition: background-position .6s, transform .6s`,
     but Codex inlines it with no token, so the name is ours. It is 4x the default
     and deliberately so -- a gradient sweeping the width of a button is a much
     longer visual journey than a colour crossfade, and at 0.15s it read as abrupt
     (Joy spotted this in preview before the dump confirmed the figure). Use it for
     travel across an element's own width, not for state acknowledgement: the
     shadow on that same button stays on the 0.15s default so the control still
     responds to the pointer instantly.

     Hover-in and hover-out deliberately share one duration throughout.
     Asymmetric timing is a common flourish and it reads as lag on a nav bar,
     where the pointer crosses several targets in a row. */
  --default-transition-duration: 0.15s;
  --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
  --motion-duration-control: 0.2s;
  --motion-duration-instant: 75ms;
  --motion-duration-moderate: 250ms;
  --motion-duration-slow: 0.6s;
  --motion-spin-duration: 800ms;
}

/* ===== Semantic tier (dark mode) =====

   Ported 2026-10-20 from docs/brand-refresh/Semantic/Dark.tokens.json, the
   Figma semantic export that is the same source the light tier above came from.
   This is the block DEFERRED(dark mode) at the top of this file asked for, and
   the one footer.hbs's theme-toggle comment says the button is waiting on.

   Verified rather than assumed, because the note at line 46 warned against a
   blind port. Flattening both exports to our own naming (`neutral.bg` ->
   --neutral-bg, nested `chart.accent.teal.regular` -> --chart-accent-teal-regular,
   with Figma's separate alpha channel folded back into 8-digit hex) gives 230
   colour tokens each. All 230 resolve to names :root already defines, and every
   one of the 230 light values matches what :root holds **exactly** -- zero
   drift. So the mapping is proven on the light side before being trusted on the
   dark side, and the 205 declarations below are the full set of tokens whose
   value actually changes, a figure that independently reproduces the "205 of
   which differ" in the header comment.

   Only the 205 that differ are here. The other 25 are deliberately absent
   rather than restated: all eight --fixed-* (fixed across themes is what the
   role means), --brand-bg/-icon/-border and three --brand-gradient-* (the coral
   is the brand in both modes), --critical-bg-strong, --high-bg-strong and
   --high-icon. Restating them would mean a future palette change had two places
   to edit and one of them silently wrong.

   No [data-theme="light"] block, by design: document_head.hbs's pre-paint script
   treats light as the *absence* of the attribute, so :root above is the light
   theme and this is the only override needed.

   The primitive ramps (--color-deep-teal-*, etc.) are deliberately NOT
   re-pointed. Primitives are the fixed palette and semantics are what re-map
   onto them; the export contains no primitives at all, which confirms that is
   the intended model rather than our own convention.

   Two things this tier cannot fix on its own, both real and both outside the
   token layer:
   - --brand-logo flips to #ffffff here, but the header logo is an <img> to
     knowbe4-logo.svg (header.hbs), and a CSS variable cannot recolour an
     external image. Dark mode needs either a second asset or an inline SVG.
   - --form-bg and --form-bg-active are the same value (#172029) in dark, where
     in light they differ. The search field's focus fill therefore does nothing
     in dark mode by design -- focus is carried by --form-border-active
     (#99aec1, a clear lighten) and the ring, which moves to a periwinkle
     #9884de rather than light mode's teal. Not a porting mistake; noted so the
     missing fill change does not get "fixed" later.

   NINE INK VALUES IN HERE WERE CORRECTED AGAINST THE LIVE SITE ON 2026-10-25,
   and the reason is worth keeping, because the obvious instinct is to "restore"
   them from Figma. Joy noticed the dark theme on Codex's own site reads better
   than the one documented in Figma and pulled the shipped dark block out of
   DevTools (`.dark-mode, [data-theme=dark]` in entry.*.css). Resolving all 136
   roles in it through the primitive ramps and diffing against this tier gave 98
   identical values, 22 more correctly left theme-invariant, nothing missing, and
   sixteen differences. Nine of those sixteen are ink and are fixed below.

   THE RULE WE HAD MISSED: Codex's shipped dark theme never sets text to pure
   white. In 136 roles, --color-black-0 (#ffffff) appears exactly twice --- on
   --neutral-bg-strong-active and --neutral-icon-strong --- and on no text role
   at all. Neutral ink tops out at black-3 (#ebf0f4), and each semantic text is
   a light step of its OWN hue. We had six text roles at #ffffff.

   This tier already contained both conventions, which is the tell. --brand-text
   was vermillion-3 and --warning-text gold-3 --- correct, hue-tinted, matching
   the live values exactly. The other six semantic texts were flat white. Two of
   eight followed the rule.

   The steps are tuned per hue and are NOT derivable, so do not re-derive them:
   critical uses cherry-3, success lime-7, high ember-4, info deep-teal-4,
   warning gold-3, brand vermillion-3. A uniform "step 3" guess would have put
   success four steps off.

   Figma is not wrong so much as stale: the Semantic Scales frame really does
   document #ffffff for these. It was checked, and it is why this was cleared as
   "not an oversight" when Joy first reported the symptom on 2026-10-23. The
   lesson is the one already recorded for the token dump generally --- the
   shipped stylesheet is the source of truth and Figma is reference. Where the
   two disagree about a token VALUE, the live site wins.

   ALL NINE STILL STAND. Two of them, --info-text and --info-icon, were white
   for part of 2026-10-25 before being put back; the note at the Info block
   below records that detour so it does not read as an accidental revert.

   Contrast was computed for all nine before applying. Every ink value drops
   (they were all at or near maximum, which is the glare Joy was reacting to)
   and none falls below AA; the worst in the set is #ebf0f4 on
   --neutral-bg-component-active at 4.89:1. The two heading corrections go the
   other way and RAISE contrast, and --critical-heading was a genuine defect:
   cherry-7 on --critical-bg is 4.14:1, which fails AA for normal text. cherry-6
   clears it at 4.65:1.

   SEVEN DIFFERENCES ARE DELIBERATELY NOT APPLIED, so a future diff against the
   same dump will not look half-finished:
   - Five shadow/glow GEOMETRY values, which are not colours. The live dark tier
     enlarges shadows (--shadow-blur 12px vs our 6px, --shadow-floating-blur
     32px vs our 20px) and switches glows on (--glow-wide-blur 20px, -pos-y 4px,
     --glow-tight-blur 10px, all 0px here). We have no dark override for any of
     them, so dark mode uses the light geometry. Left alone because the dark
     block alone cannot say whether our 0px is a correct light value missing a
     dark override or wrong in both tiers --- that needs the live :root block.
   - Two alpha roundings, --fixed-black-active and --fixed-white-active, which
     were b2 (69.8%) against the live b3 (70.2%). Those two ARE aligned, in the
     light tier where they live; they are listed here only so the count adds up.

   Written `:root[data-theme='dark']` rather than the bare attribute selector,
   which would be enough today: every one of these 205 names is defined in
   exactly one place (this file), so nothing later in the cascade currently ties
   with it. The qualifier is there for css-page-custom.css, which loads last and
   exists to win -- a `:root { --neutral-bg: ... }` added there would otherwise
   out-order this block and take dark mode's value with it, silently and in one
   token only. (0,2,0) keeps the theme scope ahead of any plain :root. */
:root[data-theme='dark'] {
  /* Brand */
  --brand-border-strong: #f8694c;
  /* vermillion-2, was vermillion-3 (#fc9681). 6.83:1 -> 8.58:1 on --neutral-bg;
     6.44:1 on --neutral-bg-component, still AA. The light tier carries the
     reasoning, including why this is one step and not two (2026-10-28) */
  --brand-text: #fdb5a6;
  --brand-logo: #ffffff;

  /* Critical */
  --critical-bg: #4f0102;
  --critical-bg-soft: #360102;
  --critical-bg-strong-active: #e52124;
  --critical-bg-strong-hover: #e52124;
  --critical-border: #c30e11;
  --critical-border-strong: #ed2e31;
  /* cherry-6, was cherry-7. 4.14:1 on --critical-bg failed AA for normal text; this is 4.65:1 (2026-10-25, see above) */
  --critical-heading: #f65154;
  --critical-icon: #f23e41;
  /* cherry-3 (2026-10-25, see above) */
  --critical-text: #fc9c9e;
  --critical-glow: #9d070a8c;

  /* Success */
  --success-bg: #364f1d;
  --success-bg-soft: #253614;
  --success-bg-strong: #98d95c;
  --success-bg-strong-active: #d5fcbc;
  --success-bg-strong-hover: #b9f68b;
  --success-heading: #a3e567;
  /* lime-7 -- the furthest from a uniform step, see the note above (2026-10-25, see above) */
  --success-text: #b2f27e;
  --success-icon: #a3e567;
  --success-border: #6c9d3d;
  --success-border-strong: #b9f68b;
  --success-glow: #6c9d3d8c;

  /* Warning */
  --warning-bg: #472400;
  --warning-bg-soft: #170b00;
  --warning-bg-strong: #fbb930;
  --warning-bg-strong-active: #feefb3;
  --warning-bg-strong-hover: #fddc79;
  --warning-border: #994f00;
  --warning-border-strong: #fddc79;
  --warning-heading: #fbb930;
  --warning-icon: #fbb930;
  --warning-text: #fcca4e;
  --warning-glow: #994f008c;

  /* High */
  --high-bg: #501b00;
  --high-bg-soft: #371200;
  --high-bg-strong-active: #fd5a09;
  --high-bg-strong-hover: #ed5002;
  --high-border: #d14600;
  --high-border-strong: #fd681e;
  --high-heading: #ff7631;
  /* ember-4 (2026-10-25, see above) */
  --high-text: #ffa87c;
  --high-glow: #9d39078c;

  /* Info */
  --info-bg: #023249;
  --info-bg-soft: #002131;
  --info-bg-strong: #08577c;
  --info-bg-strong-active: #177da9;
  --info-bg-strong-hover: #0f6a94;
  --info-border: #08577c;
  --info-border-strong: #2390bc;
  /* deep-teal-6, was deep-teal-7. 4.57:1 -> 5.49:1 (2026-10-25, see above) */
  --info-heading: #44b1d9;
  /* Both of these were briefly #ffffff earlier on 2026-10-25 and are back where
     the correction above put them, so info is an unexceptional severity again
     and the nine ink fixes all stand. Worth knowing why, because the white
     version is in this session's history and looks like something that got
     reverted by accident: the front-page banner read badly in dark mode, and
     whitening info's ink and icon was the first fix. Then dark mode moved to
     Codex's STRONG emphasis for messages instead (see the Callouts section of
     css-components.css), which solved it properly -- and took both reasons for
     the white away. The white the banner needed now comes from the component,
     where strong emphasis sets `--fg` and `--icon` to --fixed-white on the
     saturated panel, and not from the severity's own ink. Which is the right
     place for it: a message on a `-bg-strong` fill is one context, and bending
     a role token was making every other info context pay for it.

     That paragraph described a state that ended on 2026-10-29, and it is kept
     because it explains why these two values are what they are. Callouts no
     longer use strong emphasis in dark: Joy's team asked for regular emphasis
     sitewide, so the callout variants now read --info-text and --info-icon in
     BOTH tiers and these values are live rather than unused. The Callouts
     section of css-components.css has the measurements. The front-page banner
     the white patch was originally for is the one thing still on strong -- it is
     .kb-banner, not a callout-* class, and it keeps its own override in
     css-page-home.css. Whichever way that lands, the right place for a fill's
     ink is still the component and not the severity's own role, which is the
     part of this note that was never about emphasis. */
  --info-icon: #44b1d9;
  --info-text: #73ceec;

  /* Neutral */
  --neutral-bg: #1e2a35;
  --neutral-bg-alpha: #ffffff1a;
  --neutral-bg-component: #2e3e4e;
  --neutral-bg-component-active: #536a80;
  --neutral-bg-component-hover: #3f5467;
  --neutral-bg-component-soft: #172029;
  --neutral-bg-component-soft-active: #3f5467;
  --neutral-bg-component-soft-hover: #2e3e4e;
  --neutral-bg-highlight: #1e2a35;
  --neutral-bg-soft: #172029;
  --neutral-bg-strong: #dce4eb;
  --neutral-bg-strong-active: #ffffff;
  --neutral-bg-strong-hover: #fdfdfe;
  --neutral-border: #3f5467;
  --neutral-border-alpha: #ffffff1a;
  --neutral-border-alpha-strong: #ffffff33;
  --neutral-border-soft: #2e3e4e;
  --neutral-border-strong: #99aec1;
  --neutral-icon: #b2c3d2;
  --neutral-icon-soft: #698198;
  --neutral-icon-strong: #ffffff;
  --neutral-icon-inverse: #10171e;
  /* black-3. The document ink, inherited by everything via style.css:40 -- 73 references (2026-10-25, see above) */
  --neutral-text: #ebf0f4;
  --neutral-text-inverse: #10171e;
  --neutral-text-soft: #b2c3d2;
  /* black-3 (2026-10-25, see above) */
  --neutral-heading: #ebf0f4;
  --neutral-border-inverse: #10171e;

  /* Form */
  --form-bg: #172029;
  --form-bg-active: #172029;
  --form-bg-error: #200001;
  --form-bg-hover: #10171e;
  --form-bg-highlight: #0f6a94;
  --form-bg-readonly: #1e2a35;
  --form-border: #698198;
  --form-border-active: #99aec1;
  --form-border-error: #c30e11;
  --form-border-readonly: #3f5467;
  --form-focus-ring: #9884de;

  /* Hyperlink */
  /* black-3. Every link in dark mode was pure white (2026-10-25, see above) */
  --hyperlink-link: #ebf0f4;
  --hyperlink-link-visited: #bdb0f2;
  --hyperlink-link-soft: #c8d5e0;
  --hyperlink-link-inverse: #050709;
  --hyperlink-link-inverse-visited: #5e499f;

  /* Page */
  --page-bg-middle: #10171e;
  --page-bg-corner: #1e2a35;
  --page-bg-corner-transparent: #1e2a3500;
  --shadow-regular: #10171e4d;
  --shadow-hover: #10171e66;
  --shadow-floating-color: #10171e99;
  --glow-color-wide: #232e31;
  --glow-color-tight: #4f5f63;

  /* Scroll */
  --scroll-thumb: #536a80;
  --scroll-thumb-hover: #8198ad;
  --scroll-thumb-active: #b2c3d2;

  /* Chart -- border + 10 categorical colors */
  --chart-border: #1e2a35;
  --chart-categorical-1: #b2c3d2;
  --chart-categorical-3: #cc6788;
  --chart-categorical-4: #8c77d5;
  --chart-categorical-5: #aab551;
  --chart-categorical-6: #c3bbeb;
  --chart-categorical-7: #579b97;
  --chart-categorical-8: #a091b5;
  --chart-categorical-9: #cc8686;
  --chart-categorical-10: #dfbed7;
  --chart-accent-neutral-regular: #8198ad;
  --chart-accent-neutral-soft: #3f5467;
  --chart-accent-neutral-strong: #c8d5e0;
  --chart-accent-teal-soft: #0f6a94;
  --chart-accent-teal-strong: #90dbf3;
  --chart-accent-aubergine-regular: #cc6788;
  --chart-accent-aubergine-soft: #943d59;
  --chart-accent-aubergine-strong: #f3afc6;
  --chart-accent-indigo-regular: #9884de;
  --chart-accent-indigo-soft: #5e499f;
  --chart-accent-indigo-strong: #cbc0f6;
  --chart-accent-positive-soft: #476827;
  --chart-accent-positive-strong: #d5fcbc;
  --chart-accent-negative-regular: #d91619;
  --chart-accent-negative-soft: #9d070a;
  --chart-accent-negative-strong: #fc9c9e;
  --chart-accent-warning-regular: #e47f03;
  --chart-accent-warning-soft: #994f00;
  --chart-accent-warning-strong: #fcca4e;
  --chart-accent-risk-score-high-regular: #ed5002;
  --chart-accent-risk-score-high-soft: #a43700;
  --chart-accent-risk-score-high-strong: #ffbb99;

  /* Chart -- 9-step sequential ramps per hue, plus a matching border step */
  --chart-sequential-neutral-1: #fdfdfe;
  --chart-sequential-neutral-2: #c8d5e0;
  --chart-sequential-neutral-3: #99aec1;
  --chart-sequential-neutral-4: #8198ad;
  --chart-sequential-neutral-5: #698198;
  --chart-sequential-neutral-6: #536a80;
  --chart-sequential-neutral-7: #3f5467;
  --chart-sequential-neutral-8: #1e2a35;
  --chart-sequential-neutral-9: #10171e;
  --chart-sequential-neutral-border: #698198;
  --chart-sequential-teal-1: #e0f7fe;
  --chart-sequential-teal-2: #afe7f8;
  --chart-sequential-teal-3: #5ac0e4;
  --chart-sequential-teal-4: #32a1cc;
  --chart-sequential-teal-5: #2390bc;
  --chart-sequential-teal-6: #0f6a94;
  --chart-sequential-teal-7: #08577c;
  --chart-sequential-teal-8: #023249;
  --chart-sequential-teal-9: #002131;
  --chart-sequential-teal-border: #08577c;
  --chart-sequential-aubergine-1: #fad0de;
  --chart-sequential-aubergine-2: #ec9bb6;
  --chart-sequential-aubergine-3: #cc6788;
  --chart-sequential-aubergine-4: #a94a69;
  --chart-sequential-aubergine-6: #7c3149;
  --chart-sequential-aubergine-7: #632539;
  --chart-sequential-aubergine-8: #491b2a;
  --chart-sequential-aubergine-9: #250d15;
  --chart-sequential-aubergine-border: #a94a69;
  --chart-sequential-indigo-1: #cbc0f6;
  --chart-sequential-indigo-2: #b0a1ec;
  --chart-sequential-indigo-3: #a492e6;
  --chart-sequential-indigo-4: #806bca;
  --chart-sequential-indigo-6: #523f8e;
  --chart-sequential-indigo-7: #47357b;
  --chart-sequential-indigo-8: #2f2253;
  --chart-sequential-indigo-9: #24193f;
  --chart-sequential-indigo-border: #6a54b0;
  --chart-sequential-positive-1: #f3ffed;
  --chart-sequential-positive-2: #e6fed9;
  --chart-sequential-positive-3: #cafbaa;
  --chart-sequential-positive-4: #b2f27e;
  --chart-sequential-positive-6: #88c34f;
  --chart-sequential-positive-7: #6c9d3d;
  --chart-sequential-positive-8: #476827;
  --chart-sequential-positive-9: #253614;
  --chart-sequential-positive-border: #a3e567;
  --chart-sequential-negative-1: #fedadb;
  --chart-sequential-negative-2: #fdbabb;
  --chart-sequential-negative-3: #fb8082;
  --chart-sequential-negative-4: #f23e41;
  --chart-sequential-negative-6: #c30e11;
  --chart-sequential-negative-7: #9d070a;
  --chart-sequential-negative-8: #680204;
  --chart-sequential-negative-9: #360102;
  --chart-sequential-negative-border: #e52124;
  --chart-sequential-warning-1: #feefb3;
  --chart-sequential-warning-2: #fddc79;
  --chart-sequential-warning-3: #fbb930;
  --chart-sequential-warning-4: #f8aa1e;
  --chart-sequential-warning-6: #d77402;
  --chart-sequential-warning-7: #994f00;
  --chart-sequential-warning-8: #613100;
  --chart-sequential-warning-9: #2d1700;
  --chart-sequential-warning-border: #e47f03;
}

/* The non-token half of dark mode. color-scheme is a UA-rendering switch, not a
   colour value, so it cannot live in the block above as a custom property --
   css-reset.css:107 sets it on <html> and this is what moves it. Without it the
   page repaints dark and then keeps a light scrollbar track down its edge, light
   UA form controls, and Chrome's pale-yellow autofill fill in the search field.
   Kept here rather than in css-reset.css so both halves of the theme switch are
   in one file; the reset's rule carries a pointer to this one. */
:root[data-theme='dark'] {
  color-scheme: dark;
}

/* Honouring prefers-reduced-motion at the token layer rather than per
   component, so a new transition cannot forget to opt in. Zeroing the durations
   leaves every `transition` declaration in place and valid -- it just completes
   in no time -- which is why this is three lines instead of a pile of
   component-level overrides.

   This also composes with forethought-widget.js, which reads <body>'s computed
   transition-duration rather than hardcoding 300ms (see bodyTransitionMs) for
   exactly this reason: with the durations zeroed its rAF anchor-tracking
   collapses to a single measurement on its own, with nothing to change there.

   --motion-spin-duration is deliberately NOT zeroed. A spinner is state
   feedback rather than decoration, and a 0ms spin would be a static arc that
   looks like a rendering bug. Reduced motion asks for less gratuitous movement,
   not for progress indicators to stop reporting progress. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --default-transition-duration: 0s;
    --motion-duration-control: 0s;
    --motion-duration-instant: 0ms;
    --motion-duration-moderate: 0ms;
    --motion-duration-slow: 0s;
  }
}
