/* ═══════════════════════════════════════════════════════════════════════════
   SageX - design tokens
   ═══════════════════════════════════════════════════════════════════════════

   VALUES extracted 2026-08-03 from:
     sageX-website-build/capital-markets-page/production-view/01-hero.html
   NAMES renamed the same day so each one reads as what it is. Every VALUE is
   unchanged and was verified by diff after renaming - only labels moved.

   WHY THIS FILE EXISTS
   Seven page-hero files each carried their own token set - 84 distinct names,
   ZERO shared across all seven. The design SSOT (sagex-design-system.md) is
   prose, so every page author re-derived it by eye. This file ends that.

   HOW TO USE

     <link rel="stylesheet" href="/assets/css/tokens.css">
     <html data-palette="indigo" data-material="solid">

   TWO INDEPENDENT AXES - they compose, they do not duplicate.

     data-palette   indigo | ember     37 colour tokens, identical names in both
     data-material  solid  | glass      5 surface tokens that var() into the palette

   2 palettes x 2 materials = 4 looks. A third palette is a copy of the block
   with new values; the 37 names must stay identical or things break silently.
   (Was 32 until 2026-08-07; +--signal-ok-bright, +--ambient-* x4, and --shadow
   became --shadow-color. Parity verified by diff after the change.)

   ───────────────────────────────────────────────────────────────────────────
   FIVE VALUES IN THE PALETTE BLOCKS ARE SILENT DERIVATIONS
   ───────────────────────────────────────────────────────────────────────────
   They are hand-typed rgba(), but each is another token at an alpha. Nothing
   recorded the relationship, so a third palette copied by eye would break them.
   Recorded here; do not "fix" them into color-mix() without re-measuring the
   AA gate, because the composited values are what the contrast sweep cleared.

     --glint          = --brand-text     @ 28% (indigo) / 25% (ember)
     --glass-display  = --surface-section @ 55%
     --glass-reading  = --surface-page    @ 85%
     --bloom-from     = --brand-fill      @ 30% (indigo) / 26% (ember)
     --bloom-to       = --accent          @ 16% (indigo) / 14% (ember)

   ───────────────────────────────────────────────────────────────────────────
   NAMING - read the label, know the job
   ───────────────────────────────────────────────────────────────────────────
     --surface-*   backgrounds, darkest to most-tinted:
                   deep · page · section · card · raised · highlight
     --ink-*       text colour, strongest to weakest:
                   heading · high · body · subtle · faint
     --brand-*     fill (backgrounds) · text (links) · deep (pressed, gradients)
     --accent      the per-palette accent; --accent-bright is its glow
     --signal-*    ok · warm · pain
     --cta-*       gradient-from · gradient-to · text
     --panel-*     bg · blur · edge - these follow data-material automatically
     --font-*      display (Plus Jakarta) · body (DM Sans) · mono (Inconsolata)
     --text-*      TYPE SIZES (h1, lead, body, small, caption, eyebrow, mono, button)
     --space-*     sm · md · lg · xl        --pad-x / --pad-y   section padding
     --radius-*    card · pill              --max-width         content column

   Colour is --ink-*, size is --text-*. That split is deliberate - the old
   --t-body / --fs-body pair was one character apart and easy to confuse.

   ───────────────────────────────────────────────────────────────────────────
   DARK ONLY
   ───────────────────────────────────────────────────────────────────────────
   Light mode was removed 2026-08-03 on Ram's instruction. A partial 13-token
   light override existed in the source; it covered surfaces, text and brand
   but no glass, bloom or shadow token, so light + glass rendered a dark
   translucent panel on a light surface. Rather than ship it half-done it is
   gone. The SSOT still carries every light value if it is ever wanted back.

   NOT IN HERE: component styles. Buttons, pills and cards live in
   primitives.css, built against the SGX-* showcase contract.

   ONE ADDITION, FLAGGED
   The source drives breakpoints with data-bp="tablet|mobile" - preview-harness
   mechanics, not live-site mechanics. Media queries were ADDED at the bottom
   carrying the identical values, so tokens respond to real viewport width.
   The data-bp rules are kept and still win on specificity, so the preview
   harness is unaffected. No new numbers were invented.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ─────────────────────────── EXTRACTED ─────────────────────────── */
/* ═══════════════════════════════════════════════════════════════
   PALETTE AXIS - hue only. Material and motion live below.
   ═══════════════════════════════════════════════════════════════ */

/* ── INDIGO (default · what ships today) ─────────────────────── */
:root,:root[data-palette="indigo"]{
  --surface-deep:#08080C; --surface-page:#0C0C0F; --surface-section:#17181F; --surface-card:#232431; --surface-raised:#303046; --surface-highlight:#414162;
  --ink-heading:#FFFFFF; --ink-high:#E4E4E7; --ink-body:#9AA0A6; --ink-subtle:#6B6F76; --ink-faint:#3F4147;
  --brand-fill:#4C4CFF; --brand-text:#8AA6FF; --brand-deep:#1A1A8A;
  --accent:#06B6D4;            /* traced / verified - reserved */
  --accent-bright:#5AFFFF;
  --signal-warm:#F97316;              /* Accent/Warm - ONE warm moment per view */
  --signal-ok:#22C55E; --signal-pain:#FF8A4C;
  /* ADDED 2026-08-07. The success DISPLAY pair's bright stop (--signal-ok mixed
     55/45 toward --ink-heading, frozen). Success ramp = 135deg ok-bright -> ok,
     for positive-outcome numerals and strips. --signal-ok alone stays the
     small-signal token. Neither is a body-text colour. */
  --signal-ok-bright:#7DE8A6;
  /* CTA gradient must not end on cyan. Two reasons, both sourced:
     (1) design system - cyan #06B6D4 "takes dark text on it", light fills never take white;
         white-on-cyan measured 2.43:1, and 2.88:1 at the worst point under the label.
     (2) cyan is the RESERVED traced/verified status hue - a status hue never doubles as a
         brand fill. Brand/Deep #1A1A8A is the documented "deep gradient stop".
     No single ink clears 4.5:1 across #4C4CFF -> #06B6D4, so a stop had to move, not the ink. */
  --cta-gradient-from:#4C4CFF; --cta-gradient-to:#1A1A8A; --cta-text:#FFFFFF;
  --hairline:rgba(253,253,255,.14);
  --glint:rgba(138,166,255,.28);
  --glass-display:rgba(23,24,31,.55);
  --glass-reading:rgba(12,12,15,.85);
  --bloom-from:rgba(76,76,255,.30); --bloom-to:rgba(6,182,212,.16);
  --bloom-peak:#2A2A6B;        /* worst-case blend point the AA gate measures against */
  /* --shadow is now GEOMETRY (shared :root) x COLOUR (here), so a breakpoint can
     change the blur without re-typing the hue per palette. Composed value is
     byte-identical to the previous `0 40px 90px -50px rgba(8,10,40,.95)`. */
  --shadow-color:rgba(8,10,40,.95);               /* cool-tinted, never grey-black */
  --diagram-from:#4C4CFF; --diagram-to:#06B6D4;
  /* AMBIENT BACKDROP stops (GradientFlow + Convergence). Named by ROLE, not hue -
     the Framer originals were --amb-indigo / --amb-cyan / --amb-violet, which
     would hold amber values on ember. */
  --ambient-primary:rgba(76,76,255,.20); --ambient-secondary:rgba(6,182,212,.15);
  --ambient-tertiary:rgba(139,92,246,.18); --ambient-deep:rgba(42,42,107,.45);
}

/* ── EMBER (parked exploration · Terminal Ember) ─────────────── */
:root[data-palette="ember"]{
  --surface-deep:#0E0A05; --surface-page:#141009; --surface-section:#1D1710; --surface-card:#241D14; --surface-raised:#2F261A; --surface-highlight:#3A2E20;
  --ink-heading:#F7F1E6; --ink-high:#E8E0D2; --ink-body:#C4B9A9; --ink-subtle:#8A8072; --ink-faint:#574F41;
  --brand-fill:#FFAD52; --brand-text:#FFC989; --brand-deep:#8A3D14;
  --accent:#17B8A0;
  --accent-bright:#5CE8CE;
  --signal-warm:#E06B2D;
  --signal-ok:#43D97C; --signal-pain:#F5D90A;
  --signal-ok-bright:#8CE4AB;
  --cta-gradient-from:#FFAD52; --cta-gradient-to:#E06B2D; --cta-text:#2B1304;   /* dark ink on amber = 9.5:1 */
  --hairline:rgba(247,241,230,.14);
  --glint:rgba(255,173,82,.25);
  --glass-display:rgba(36,29,20,.55);
  --glass-reading:rgba(20,16,9,.85);
  --bloom-from:rgba(255,173,82,.26); --bloom-to:rgba(23,184,160,.14);
  --bloom-peak:#5A4321;
  --shadow-color:rgba(43,19,4,.95);               /* warm-tinted */
  --diagram-from:#FFAD52; --diagram-to:#17B8A0;
  --ambient-primary:rgba(255,173,82,.20); --ambient-secondary:rgba(23,184,160,.15);
  --ambient-tertiary:rgba(224,107,45,.18); --ambient-deep:rgba(90,67,33,.45);
}

/* ═══ METRIC-ADJUSTED FALLBACK FACES - added 2026-08-07 ══════════════════════
   THE PROBLEM THESE SOLVE
   The three webfonts load with display=swap, so the first paint uses a fallback
   and then every line re-measures when the real font arrives. The whole page
   re-wraps in the opening moment - which is also when text-wrap:balance
   recomputes. Until the swap stops moving text, any wrapping or spacing decision
   is being tuned against a moving target.

   These faces are the same local font (Arial / Courier New) scaled so its
   advance widths and its ascent/descent match the webfont it stands in for.
   Same line count, same line-box height, so the swap changes the letterforms
   and nothing else.

   MEASURED, NOT REMEMBERED. Every number below was fitted in a real browser
   against the ACTUAL capital-markets page copy, not a pangram - the ratio is
   the one that matters for the text that really has to wrap. Method and
   residuals are recorded in the 2026-08-07 typography handoff. Validation, same
   paragraph at the real breakpoint measures:
       worst height error with these faces   1.89%  (h1 at 340px, one line)
       exact match in 6 of the 7 cases       0.00%
       worst height error WITHOUT them       8.33%
   Regenerate with scratchpad/fit-fallbacks.js if a family or weight changes.

   WHY size-adjust IS DIVIDED OUT OF THE OVERRIDES
   css-fonts-5: "All metrics associated with this font - including glyph
   advances, baseline tables, and overrides provided by @font-face descriptors -
   are scaled by the given percentage." So ascent-override is itself scaled by
   size-adjust, and the declared value has to be pre-divided by it to land on the
   intended ascent. These values already are.

   WHY ARIAL AND NOT system-ui
   system-ui is a different font on every OS - SF on macOS, Segoe UI on Windows -
   so one set of numbers cannot fit it. Arial is metric-identical on macOS and
   Windows, which is where the enterprise buyers this page is built for actually
   are. Where Arial is absent (most Linux, and Android maps it to Roboto) the
   local() lookup simply fails, the face never loads, and the stack falls through
   to system-ui exactly as it does today. Strictly additive - it cannot regress.

   WEIGHT-BY-WEIGHT because advance width changes with weight: Plus Jakarta at
   700 is 3.6% wider than at 400. One face for all weights would leave that error
   in place, which is the error we are here to remove. The local file is Arial
   regular in every case (style-suffixed names like "Arial Bold" do not resolve
   as family names - verified, they silently fall through to a default), so a
   heading looks lighter than usual during the swap window. That is the trade:
   correct geometry, approximate colour, for a few hundred milliseconds.

   unicode-range IS LOAD-BEARING - DO NOT DROP IT
   Font fallback is per-GLYPH, not per-element. Google's latin subset does not
   contain U+2192 "→", and this page uses that arrow in .arr, .interlink and
   .sgx-flow__arrow. Without the range below, Arial - which does have it - would
   step in and serve every arrow on the page, permanently, not just while the
   webfont is in flight. Caught by the visual gate on the first run of this
   change: 1571 px moved on desktop and 21 px of page height on mobile, all of
   it arrows. The range is Google's own latin range for these three families,
   copied verbatim, so the fallback covers exactly what the webfont covers and
   any glyph outside it falls through to system-ui exactly as it does today.
   ════════════════════════════════════════════════════════════════════════════ */
@font-face{font-family:'Plus Jakarta Sans fallback';src:local('Arial');font-weight:400;size-adjust:103.98%;ascent-override:99.83%;descent-override:21.35%;line-gap-override:0%;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:'Plus Jakarta Sans fallback';src:local('Arial');font-weight:500;size-adjust:105.24%;ascent-override:98.63%;descent-override:21.09%;line-gap-override:0%;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:'Plus Jakarta Sans fallback';src:local('Arial');font-weight:600;size-adjust:106.50%;ascent-override:97.46%;descent-override:20.84%;line-gap-override:0%;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:'Plus Jakarta Sans fallback';src:local('Arial');font-weight:700;size-adjust:107.76%;ascent-override:96.32%;descent-override:20.60%;line-gap-override:0%;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:'DM Sans fallback';src:local('Arial');font-weight:400;size-adjust:103.69%;ascent-override:95.67%;descent-override:29.90%;line-gap-override:0%;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:'DM Sans fallback';src:local('Arial');font-weight:500;size-adjust:105.48%;ascent-override:94.04%;descent-override:29.39%;line-gap-override:0%;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:'DM Sans fallback';src:local('Arial');font-weight:600;size-adjust:107.72%;ascent-override:92.09%;descent-override:28.78%;line-gap-override:0%;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:'Inconsolata fallback';src:local('Courier New');font-weight:400;size-adjust:83.32%;ascent-override:103.10%;descent-override:22.80%;line-gap-override:0%;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:'Inconsolata fallback';src:local('Courier New');font-weight:600;size-adjust:83.32%;ascent-override:103.10%;descent-override:22.80%;line-gap-override:0%;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}

:root{
  /* The 'X fallback' entry is the metric-adjusted face defined above. It sits
     between the webfont and system-ui: used only while the webfont is in
     flight, skipped entirely once it lands, skipped where Arial is absent. */
  --font-display:'Plus Jakarta Sans','Plus Jakarta Sans fallback',system-ui,-apple-system,sans-serif;
  --font-body:'DM Sans','DM Sans fallback',system-ui,-apple-system,sans-serif;
  --font-mono:'Inconsolata','Inconsolata fallback',ui-monospace,monospace;

  /* Shadow GEOMETRY. Colour is per-palette (--shadow-color). */
  --shadow:0 40px 90px -50px var(--shadow-color);

  /* ═══ ADDED 2026-08-07 - palette-INDEPENDENT tokens, promoted from the
     capital-markets base after the five-layer hardening pass. No hue, so they
     live here and are exempt from the identical-names parity rule. None need a
     breakpoint value: em tracking scales with the font ladder, weight is
     size-independent, leading is a ratio. ═══ */
  --tracking-display: -.03em;   /* h1 and large numerals */
  --tracking-tight:   -.01em;   /* buttons, emphasis paragraphs */
  --tracking-micro:    .02em;   /* small labels - doc names, fund names, chips */
  --tracking-caps-sm:  .08em;   /* small uppercase */
  --tracking-caps:     .14em;   /* uppercase eyebrows and tags */

  --leading-heading: 1.2;
  --leading-body:    1.65;

  /* ADDED 2026-08-08. The sub-heading size. It lives HERE, not in the responsive
     ladder, because it is genuinely constant - the capital-markets page has held
     it at 19px across all three tiers since it was written, and the ladder blocks
     never overrode it. Do NOT reach for --text-lead instead: that is 19px at
     desktop but steps to 18/17, so borrowing it would silently shrink every
     sub-heading at tablet and mobile. Same number today, different job. */
  --text-h3: 20.25px;

  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;

  /* Loop periods and choreography delays stay literal at the call site - they are
     sequence positions, not durations. These three are transition tiers only. */
  --dur-micro: .2s;    /* hover and chip state */
  --dur-base:  .45s;   /* the workhorse panel transition */
  --dur-slow:  .7s;    /* the scroll reveal */

  /* Motion curves. --ease-out is the [LIFTED] showcase value, moved here from
     primitives.css (which now has no local copy) - that closes its GAP 1.
     The capital-markets base carried a second, different curve under the same
     name; it was reconciled TO this one, because the showcase is the contract
     for traits and easing is a trait. */
  --ease-out:    cubic-bezier(0.2, 0, 0, 1);
  --ease-in-out: cubic-bezier(.2, .7, .3, 1);
}

/* ═══════════════════════════════════════════════════════════════
   MATERIAL AXIS - surface treatment only. No hue here.
   Glass = translucency + backdrop blur + hairline + top-edge glint
           + depth-down well. It is a MATERIAL, not a palette.
   Glass has a hard dependency: it only reads as glass with the
   ambient bloom behind it, so the bloom lifts in glass mode.
   ═══════════════════════════════════════════════════════════════ */
:root[data-material="solid"]{
  --panel-bg:var(--surface-card); --panel-blur:none; --panel-edge:0;
  --bloom-opacity:.75; --well-bg:var(--surface-section);
}
:root[data-material="glass"]{
  --panel-bg:var(--glass-display); --panel-blur:blur(14px) saturate(140%); --panel-edge:1;
  --bloom-opacity:1; --well-bg:var(--glass-reading);
}
/* Reduce-transparency fallback: layout identical, frost lost. */
@media (prefers-reduced-transparency:reduce){
  :root[data-material="glass"]{--panel-bg:var(--surface-card);--panel-blur:none;--well-bg:var(--surface-section)}
}

/* ═══════════════════════════════════════════════════════════════
   RESPONSIVE LADDER - padding constant within a breakpoint,
   varying only by form factor. Sizes stay inside design-system ranges.
   ═══════════════════════════════════════════════════════════════ */
/* ═══ THE BOND / COMP SPLIT - added 2026-08-07 ═══════════════════════════════
   --space-md was doing four different jobs at 26 call sites on the CM page, and
   was the wrong size for two of them.

   THE COLLISION LAW. A gap that SEPARATES two blocks of text has to be bigger
   than the leading INSIDE them, or the break between blocks reads tighter than
   the lines within one - and the eye stops seeing where a block ends. Body
   leading here is 16px x 1.65 = 26.4px, and it is 26.4px at EVERY breakpoint,
   because --text-body never changes. --space-md is 20/18/16, under it at all
   three. So one token was simultaneously too big to bind and too small to
   separate. That is why headings read detached AND components read mushy from
   the same cause.

     --space-bond   13/12/11   binds a label or heading to the thing it
                               introduces. DELIBERATELY under 26.4px - that is
                               what makes the pair read as one unit.
     --space-comp   40/34/30   separates two components. Clearly over 26.4px at
                               every tier, so a break always reads as a break.

   --space-md SURVIVES and keeps its value. It is still correct for inset
   padding inside a card, which is not a gap between two things and is not
   governed by the collision law. Those call sites were left alone on purpose.

   Paragraph-to-paragraph is a THIRD case and needs neither new token: 40px on
   16px text is 2.5em and reads airy. Those sites moved to the existing
   --space-lg (32/28/24), the closest correct value already in the scale.
   RESIDUAL, flagged not silently fixed: --space-lg at mobile is 24px, which is
   2.4px UNDER the 26.4px leading - so mobile paragraph separation still fails
   the collision law by a hair. Fixing it means moving --space-lg itself, which
   reaches every other lg call site, so it is a separate decision.
   ════════════════════════════════════════════════════════════════════════════ */
:root{                        /* DESKTOP 1200 */
  --pad-x:64px; --pad-y:104px; --max-width:1320px;
  --space-xl:48px; --space-lg:32px; --space-md:20px; --space-sm:12px;
  --space-bond:13px; --space-comp:40px;
  --text-eyebrow:14.22px; --text-h1:52px; --text-h2:39px; --text-lead:20.25px; --text-caption:14.22px;
  --text-button:16px; --text-mono:14.22px; --text-body:16px; --text-small:14.22px;
  --leading-h1:1.06; --radius-card:18px; --radius-pill:999px;
}
:root[data-bp="tablet"]{      /* TABLET 900 */
  --pad-x:48px; --pad-y:80px;
  --space-xl:40px; --space-lg:28px; --space-md:18px; --space-sm:12px; --space-bond:12px; --space-comp:34px;
  --text-eyebrow:14.22px; --text-h1:42.67px; --text-h2:32px; --text-lead:18px; --text-caption:14.22px;
  --leading-h1:1.10; --radius-card:16px;
}
:root[data-bp="mobile"]{      /* MOBILE 390 */
  --pad-x:20px; --pad-y:56px;
  --space-xl:32px; --space-lg:24px; --space-md:16px; --space-sm:10px; --space-bond:11px; --space-comp:30px;
  --text-eyebrow:12.64px; --text-h1:36px; --text-h2:27px; --text-lead:18px; --text-caption:14.22px;
  --text-mono:12.64px; --leading-h1:1.14; --radius-card:16px;
}

/* ════════════════════════════════════════════════════════════════════════════
   WIDTH BANDS + FLUID GUTTER  -  the breakout-grid ladder.        ADDITIVE ONLY.
   D-2026-0807-09. Nothing above this line is modified: --pad-x / --pad-y /
   --max-width keep their values, so every page that has NOT opted into
   `.sgx-section--grid` renders byte-identically. That is what makes this safe to
   put in a file 12+ pages read.

   THE PROBLEM THESE SOLVE (measured 2026-08-07, 11 viewport widths)
   The page had exactly ONE component-band width: every card row, panel, diagram
   block and Q&A rendered at the section's outer edge. Nothing looked nested
   because nothing was nested, and raising --pad-x could not fix it - padding
   moves the outer edge and every pinned block moves with it.

   THE LADDER. Four bands, each one centred inside the last:
       page    1216   text, how-blocks, CTA rows - the outer bound
       cards   1080   card + stat rows          -  "nested" per Ram
       comp     720   flow diagrams, duos       -  cut again, -20% (Ram)
       narrow   660   the Q&A                   -  the ~50% cut
   The three step values below are the HALF-differences between adjacent bands,
   which is what a centred grid track needs:
       (1216-1080)/2 = 68    (1080-720)/2 = 180   (720-660)/2 = 30
       68 + 180 + 30 = 278   ->  278*2 + 660 = 1216  exact.
   comp went 900 -> 720 (-20%) on Ram's "further reduce the width of the today vs
   sagex boxes by at least 20%". It now sits only 60px outside the Q&A band, which
   is deliberate - the two narrowest bands read as one family.

   WHY page IS 1216 AND NOT 1320. The sticky nav bar caps at max-width:1280px.
   At 1320 the page band was WIDER than the bar, so above ~1450px viewport the
   body copy hung 20px OUTSIDE the nav on each side - measured 1500/1600/1700/1920,
   all -20. Ram: "dont change the width of the nav bad but shrink the width of the
   content space such that it is a bit nested under the top nav." 1216 puts the
   content 32px inside the bar on each side at every width where the bar is capped.
   TIED TO THE NAV: if `.sgx-hdr__bar`'s max-width ever changes, this must follow.
   Change a band and you MUST recompute its step. The LAYOUT rubric in
   verify-page.js fails the build if the resulting ladder inverts or collapses.

   WHY THE GUTTER IS clamp() AND NOT THREE STEPPED VALUES
   Stepped padding was measured running 64/64/64/48/48/48/48/20 - flat for four
   viewport sizes then a 58% fall at 480px. Utopia's argument, confirmed here:
   stepped values look right at the widths you picked and wrong at every width
   between.

   THE THREE NUMBERS ARE FITTED, NOT PICKED. The brief was MORE breathing room at
   every tier Ram reviews on, so each one has to beat the old stepped value:
       390px   old 20  ->  28  (the 1.75rem floor; 6.5vw would give only 25)
       900px   old 48  ->  59
      1200px   old 64  ->  78
      1440px   old 64  ->  88  (the 5.5rem cap; 6.5vw would give 94)
   A first cut at clamp(1rem, 4.5vw, 4rem) passed the rubric but shipped mobile a
   gutter of 18px - NARROWER than the 20px it replaced. The rubric cannot catch
   that: 18px clears both the 16px and the 4% floors. It is a brief failure, not
   a correctness failure, and it took reading the numbers to see it.
   ════════════════════════════════════════════════════════════════════════════ */
/* THE STEPS ARE DERIVED, NOT TYPED  -  changed 2026-08-08.
   Until now the four bands and the three steps were seven independently typed
   numbers that had to agree, and NOTHING enforced the agreement. The bands are
   the design intent; the steps are arithmetic. But only the STEPS are read by
   `.sgx-section--grid` - `--band-page`, `--band-cards` and `--band-comp` were
   never referenced by any var() anywhere (verified: 0 in page CSS, 0 in
   primitives.css, 0 in JS). So editing a band did nothing at all, and left the
   documented number disagreeing with the rendered page - silently, because the
   LAYOUT rubric measures what the page RENDERS, not what the tokens say. It
   catches an inverted ladder; it cannot catch a band that lies.
   Deriving the steps closes that: change a band and its step follows. The
   computed values are unchanged (68 / 180 / 30), which is why this lands
   pixel-identical - and that is the proof it is a refactor, not a redesign. */
:root{
  --gutter:clamp(1.75rem, 6.5vw, 5.5rem);
  --band-page:1216px; --band-cards:1080px; --band-comp:720px; --band-narrow:660px;
  --step-page: calc((var(--band-page)  - var(--band-cards))  / 2);   /*  68px */
  --step-cards:calc((var(--band-cards) - var(--band-comp))   / 2);   /* 180px */
  --step-comp: calc((var(--band-comp)  - var(--band-narrow)) / 2);   /*  30px */
}



/* ═══════════════════════════════════════════════════════════════
   ADDED 2026-08-03 - not in the source file.
   Production breakpoints. The data-bp rules above are the preview
   harness and keep winning on specificity; these drive the live site.
   Values are copied from the data-bp blocks above - no new numbers.

   THE TWO CONTENT LINES (aligned 2026-08-07): 640 and 1200.
   Desktop >=1200 · Tablet 640-1199 · Mobile <640. Chosen because no Apple
   device lands on either boundary - 640 sits in the 440-744 gap, 1200 in the
   1032-1180 gap. Written as max-width 1199 / 639 so the boundaries are exact.

   A COMPONENT MAY SUB-DIVIDE INSIDE A TIER BUT MUST NOT CROSS A LINE.
   chrome.css's nav goes burger at <900 and the footer stacks at <820; both sit
   inside the 640-1199 tablet band, which is legitimate nav/footer density.
   What was NOT legitimate was chrome.css's full-bar line at 1100 - it cut
   across the tablet band - so it moved to 1200 to match the desktop line.
   ═══════════════════════════════════════════════════════════════ */
@media (max-width: 1199px){
  :root{
    --pad-x:48px; --pad-y:80px;
    --space-xl:40px; --space-lg:28px; --space-md:18px; --space-sm:12px; --space-bond:12px; --space-comp:34px;
    --text-eyebrow:14.22px; --text-h1:42.67px; --text-h2:32px; --text-lead:18px; --text-caption:14.22px;
    --leading-h1:1.10; --radius-card:16px;
  }
}
@media (max-width: 639px){
  :root{
    --pad-x:20px; --pad-y:56px;
    --space-xl:32px; --space-lg:24px; --space-md:16px; --space-sm:10px; --space-bond:11px; --space-comp:30px;
    --text-eyebrow:12.64px; --text-h1:36px; --text-h2:27px; --text-lead:18px; --text-caption:14.22px;
    --text-mono:12.64px; --leading-h1:1.14; --radius-card:16px;
  }
}
