/* ==========================================================================
   FRONTGRADE  ·  DESIGN TOKENS  ·  v2
   Dark theme. Single source of truth for color, type, space, motion.
   --------------------------------------------------------------------------
   CONTRAST NOTATION
   Every pair below carries its computed WCAG 2.1 contrast ratio. Ratios are
   calculated from the sRGB relative-luminance formula
     L = 0.2126R + 0.7152G + 0.0722B  on linearized channels
     ratio = (Llighter + 0.05) / (Ldarker + 0.05)
   Alpha values are composited against the surface first, then measured.
   Targets: 4.5:1 normal text · 3:1 large text (24px+ regular, 18.66px+ bold)
            3:1 non-text UI (control boundaries, icons, focus, chart strokes).

   SINGLE-ORANGE RULE
   #e35530 is the only orange in the system. There is no second orange, no
   lightened text variant, and no darkened hover variant. Where #e35530 does
   not clear a threshold on a given surface, that combination is forbidden in
   a comment beside the token rather than solved with a new hue.
   ========================================================================== */

:root {

  /* ======================================================================
     1. SURFACE LADDER  ·  four steps, navy-tinted near-black
     Hierarchy is carried by tone, never by drop shadow. The steps sit close
     together on purpose: v2 separates sections with hairline rules and
     small tone shifts, not heavy alternating gradients.
     Step separation (informational; no WCAG minimum applies between two
     decorative surfaces):
       base   vs raised   1.05   base vs panel  1.11   base vs elevated 1.16
       raised vs panel    1.06   raised vs elev 1.11   panel vs elevated 1.04
     ====================================================================== */

  --surface-base:      #090c14;  /* 00 · page ground, hero, default band     */
  --surface-raised:    #0e1220;  /* 01 · cards, dropdown panels, alt band    */
  --surface-panel:     #131928;  /* 02 · raised rows, inputs, tooltips       */
  --surface-elevated:  #161d2e;  /* 03 · muted panel, inert wells            */

  /* Ink. Text ON the orange fill, and the dark half of the focus ring. */
  --surface-ink:       #090c14;

  /* Scrims and washes (decorative, layered over imagery or bands). */
  --scrim-strong:      rgba(9, 12, 20, 0.90);
  --scrim-medium:      rgba(9, 12, 20, 0.62);
  --scrim-soft:        rgba(9, 12, 20, 0.34);
  /* Transparent-header scrim. The header reads as transparent over a hero,
     but the scrim layer is 180px tall and fades BELOW the header rather than
     inside it, so the alpha never drops under 0.80 anywhere the header type
     sits. The 0.80 stop is placed to cover the whole header box, so that
     holds by construction rather than by argument: the box grew from 86px to
     92px when the header took its top padding, so the stop moved 48% to 52%
     (52% of 180px = 93.6px, clear of the 92px box; mobile's 73px box is 41%,
     well inside). Measured at that 0.80 floor, over the lightest point any
     placeholder well can reach (#2f2733), the composited backdrop is #11111a
     and the header type reads
       --text-display  17.15:1 · --text-primary 15.54:1
       --text-nav       6.01:1 · --text-utility  5.14:1 · --accent 5.00:1
     The remaining 86px of the layer fades to nothing under the header, which
     is what makes it read as a hero vignette instead of a bar.             */
  --header-scrim:      linear-gradient(180deg, rgba(9,12,20,0.88) 0%, rgba(9,12,20,0.80) 52%, rgba(9,12,20,0.42) 76%, rgba(9,12,20,0) 100%);
  --header-scrim-h:    180px;
  --header-solid:      rgba(9, 12, 20, 0.97);   /* over any page: #090c14   */

  /* ======================================================================
     2. TEXT
     ====================================================================== */

  /* --text-display  #f3f5f8  Barlow Condensed display headings only.
     Crisp without being pure #fff, which halates on this ground.
       base 17.90:1 · raised 17.08:1 · panel 16.06:1 · elevated 15.39:1   AAA */
  --text-display:      #f3f5f8;

  /* --text-primary  #e8eaed  UI labels, card titles, menu titles, body lead.
       base 16.22:1 · raised 15.47:1 · panel 14.55:1 · elevated 13.95:1   AAA */
  --text-primary:      #e8eaed;

  /* --text-muted  #7d89a3  THE quiet tone. Body copy, deks, descriptors,
     captions, meta. The system runs ONE quiet tone rather than a ladder of
     them, so there is never a question of which grey a given caption takes.
       base 5.57:1 · raised 5.31:1 · panel 4.99:1 · elevated 4.79:1        AA
     Over the card hover tint rgba(227,85,48,0.05):
       base 5.37:1 · raised 5.10:1 · panel 4.78:1 · elevated 4.58:1        AA
     DERIVATION. The nearby value #6b7a94 measures 4.5021:1 on #090c14 and
     4.30 / 4.04 / 3.87 on the three lifted surfaces, so it clears AA on the
     ground surface only, and by 0.002. #7d89a3 is the nearest value that
     clears 4.5:1 on all four surfaces and on the hover tint. It is a grey, so
     the single-orange rule is untouched.                                  */
  --text-muted:        #7d89a3;

  /* Alias. v2 runs one quiet tone, so secondary and muted are the same
     value; the name is kept because page CSS references it.               */
  --text-secondary:    #7d89a3;

  /* --text-nav  #909295  primary nav links. White at 55 percent over the
     surface ramp, flattened to a hex so the value is deterministic over an
     image hero rather than compositing against whatever is behind it.
       base 6.27:1 · raised 5.98:1 · panel 5.62:1 · elevated 5.39:1        AA */
  --text-nav:          #909295;

  /* --text-utility  #84868a  utility-bar links, the quietest text in the
     system. White at 40 percent computes 3.79:1 and does not clear AA;
     white at 50 is the quietest alpha that does.
       base 5.36:1 · raised 5.11:1 · panel 4.81:1 · elevated 4.61:1        AA */
  --text-utility:      #84868a;

  /* Text sitting ON the orange fill.
       --text-on-accent on --accent   5.22:1   AA
     White on --accent computes 3.74:1 and is therefore NEVER used for button
     labels, badge labels, or any other text on an orange fill.            */
  --text-on-accent:    #090c14;
  --text-inverse:      #090c14;   /* reserved for any future light band     */

  /* ---- Text on a LIGHT ground -----------------------------------------
     WHY A SECOND PAIR EXISTS RATHER THAN A DARKER --text-muted. The audit
     measured --text-muted below 4.5:1 wherever a legacy component paints a
     light panel underneath it: 3.51:1 on #ffffff, 3.28:1 on #f7f7f7 and
     2.87:1 on #e8e8e8. Darkening the single token cannot answer that,
     because no one value clears 4.5:1 on both grounds and the bound is
     arithmetic rather than a matter of taste. Against --surface-base
     (#090c14, relative luminance 0.003715) a text colour clears 4.5:1 only
     at luminance 0.191719 or above. Against #e8e8e8 (0.806952) it clears
     4.5:1 only at 0.140434 or below, and against #f7f7f7 (0.930111) only at
     0.167802 or below. The two ranges do not overlap, so one value cannot
     satisfy both and the ladder needs a second rung.

     The two values below are not new colours. They are the light-ground ink
     and quiet tone legacy-skin.css already defines as --fgl-ink and
     --fgl-muted; they are promoted here so a dark page that hosts a legacy
     light panel can reach them, and legacy-skin.css now points its own two
     names at these rather than restating the hexes.

       --text-ink-on-light   #16202b  #ffffff 16.46:1 · #f7f7f7 15.37:1
                                      #f4f6f8 15.19:1 · #e8e8e8 13.44:1  AAA
       --text-muted-on-light #4a5666  #ffffff  7.46:1 · #f7f7f7  6.97:1
                                      #f4f6f8  6.89:1 · #e8e8e8  6.09:1  AAA

     Both are greys, so the single-orange rule is untouched. Neither is ever
     used on a dark surface: #4a5666 measures 2.62:1 on --surface-base.    */
  --text-ink-on-light:   #16202b;
  --text-muted-on-light: #4a5666;

  /* ======================================================================
     3. ACCENT  ·  one orange, #e35530, everywhere
     ====================================================================== */

  /* --accent  #e35530
       base 5.22:1 · raised 4.98:1 · panel 4.68:1 · elevated 4.49:1
     PERMITTED as small text (below 24px regular / 18.66px bold) on:
       --surface-base, --surface-raised, --surface-panel,
       --surface-raised under the white/0.04 menu hover  (4.56:1),
       --surface-base and --surface-raised under the 0.05 accent hover tint
         (5.04:1 and 4.79:1).
     FORBIDDEN as small text on:
       --surface-elevated                                  (4.49:1),
       --surface-panel under the white/0.04 hover          (4.23:1),
       --surface-panel or --surface-elevated under the accent hover tint
         (4.48:1 and 4.29:1).
     In every forbidden case the fix is to move the element down the surface
     ladder, not to lighten the orange.
     PERMITTED without qualification for large display text and for non-text
     UI (icons, rules, borders, stat numerals), where the threshold is 3:1
     and the worst surface still measures 4.49:1.                          */
  --accent:            #e35530;

  /* Interaction fills. The primary button never darkens on hover: the label
     is near-black ink and darkening the fill would collapse its contrast.
     Hover is carried by a light outline and a 1px lift instead.           */
  --accent-hover:      #e35530;
  --accent-active:     #e35530;

  /* Decorative accent washes. No contrast requirement; none carries meaning. */
  --accent-tint:       rgba(227, 85, 48, 0.05);  /* card / row hover bg      */
  --accent-wash-08:    rgba(227, 85, 48, 0.08);
  --accent-wash-16:    rgba(227, 85, 48, 0.16);
  --accent-wash-30:    rgba(227, 85, 48, 0.30);
  --accent-glow:       rgba(227, 85, 48, 0.42);
  --accent-line:       linear-gradient(90deg, transparent 0%, #e35530 50%, transparent 100%);

  /* ======================================================================
     4. BORDERS
     Two decorative hairlines carry the v2 skin. Anything that IDENTIFIES a
     control (secondary button outline, field, toggle, icon-button boundary)
     must use --border-ui or --border-strong, which clear 3:1.
     ====================================================================== */

  /* Decorative only. These separate panels that are already identified by
     their tone and their content, so no 3:1 minimum applies.
       white/0.08  base 1.19 · raised 1.22 · panel 1.25 · elevated 1.26
       white/0.14  base 1.44 · raised 1.49 · panel 1.52 · elevated 1.54     */
  --border-hairline:        rgba(255, 255, 255, 0.08);
  --border-hairline-strong: rgba(255, 255, 255, 0.14);
  --border-hairline-faint:  rgba(255, 255, 255, 0.04);
  --border-hairline-w:      1px;

  /* Name-compatible aliases for the two decorative hairlines. */
  --border-subtle:     rgba(255, 255, 255, 0.08);
  --border-default:    rgba(255, 255, 255, 0.14);

  /* --border-ui  #666f88  functional control boundaries and icon strokes
       base 3.90:1 · raised 3.72:1 · panel 3.50:1 · elevated 3.36:1  >= 3:1
     Holds over the accent tint (3.77 / 3.58 / 3.35 / 3.21) and over the
     white/0.04 hover (3.62 / 3.41 / 3.16 / 3.02).                          */
  --border-ui:         #666f88;

  /* --border-strong  #7d89a3  hover and selected control boundaries
       base 5.57:1 · raised 5.31:1 · panel 4.99:1 · elevated 4.79:1         */
  --border-strong:     #7d89a3;

  /* --border-accent  #e35530  selected / active brand boundary and the card
     hover edge. Solid, not an alpha: rgba(227,85,48,0.5) composites to
     2.07:1 and would fail the 3:1 non-text minimum.
       base 5.22:1 · raised 4.98:1 · panel 4.68:1 · elevated 4.49:1         */
  --border-accent:     #e35530;

  /* Decorative-only accent edge, for glows and washes that identify nothing. */
  --border-accent-soft: rgba(227, 85, 48, 0.50);

  /* --stroke-quiet  #6b7a94  the quiet grey one step below --text-muted, for
     NON-TEXT use only (thin icon strokes, decorative glyphs, chart lines)
     where the threshold is 3:1.
       base 4.50:1 · raised 4.30:1 · panel 4.04:1 · elevated 3.87:1
     NEVER use this as a text color. See the --text-muted derivation note.  */
  --stroke-quiet:      #6b7a94;

  /* ======================================================================
     5. FOCUS RING  ·  two-tone, precise not chunky
     2px white outline at a 2px offset, with the offset gap filled by a dark
     box-shadow so the white ring always has a guaranteed-contrast neighbour
     on both sides, plus a 1px accent edge outside it for brand.
       --focus-ring-inner on --focus-ring-outer  19.55:1
       --focus-ring-inner on --surface-base      19.55:1
       --focus-ring-inner on --surface-raised    18.65:1
       --focus-ring-inner on --surface-panel     17.54:1
       --focus-ring-inner on --surface-elevated  16.81:1
       --focus-ring-inner on --accent             3.74:1  clears 3:1
     `outline` is retained rather than replaced by box-shadow alone, so
     Windows forced-colors mode keeps a visible indicator.
     ====================================================================== */

  --focus-ring-inner:  #ffffff;
  --focus-ring-outer:  #090c14;
  --focus-ring-halo:   rgba(227, 85, 48, 0.38);
  --focus-ring-width:  2px;
  --focus-ring-offset: 2px;

  /* ======================================================================
     6. STATUS TINTS  (form validation and node states, used sparingly)
     Colour never carries meaning alone; each status pairs with a glyph and
     a text label.
       --status-positive #6fd39a  base 10.67 · raised 10.18 · panel 9.57 · elevated 9.17
       --status-caution  #f2c14e  base 11.65 · raised 11.11 · panel 10.45 · elevated 10.02
       --status-critical #ff8f8f  base  8.92 · raised  8.51 · panel  8.00 · elevated  7.67
     ====================================================================== */

  --status-positive:   #6fd39a;
  --status-caution:    #f2c14e;
  --status-critical:   #ff8f8f;

  /* ======================================================================
     7. TYPOGRAPHY
     Display: "Barlow Condensed" bold, uppercase, set tight. Body and UI:
     "Inter", small and quiet. Two families, one link tag, no third face.
     ====================================================================== */

  --font-display: "Barlow Condensed", "Oswald", "Arial Narrow", Arial, sans-serif;
  --font-body:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono:    ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* --- Weights ------------------------------------------------------- */
  --fw-regular:   400;
  --fw-medium:    500;
  --fw-semibold:  600;
  --fw-bold:      700;
  --fw-display:   700;   /* Barlow Condensed bold */
  --fw-display-x: 800;   /* reserved for the largest hero setting */

  /* --- Sizes  (fluid, 390px floor to 1600px ceiling) ------------------
     Floors are set so no single uppercase word can outrun a 390px column:
     Barlow Condensed sets narrow, but MICROELECTRONICS at 64px still does.  */
  --fs-display:  clamp(3.5rem,   2.479rem + 4.19vw, 6.25rem);   /*  56 -> 100  hero H1   */
  --fs-h1:       clamp(2.5rem,   1.757rem + 3.05vw, 4.5rem);    /*  40 ->  72  page H1   */
  --fs-h2:       clamp(2rem,     1.722rem + 1.14vw, 2.75rem);   /*  32 ->  44  section   */
  --fs-h3:       clamp(1.25rem,  1.13rem  + 0.50vw, 1.625rem);  /*  20 ->  26  card title*/
  --fs-h4:       clamp(1rem,     0.95rem  + 0.21vw, 1.1875rem); /*  16 ->  19  sub head  */
  --fs-drawer:   1.375rem;                                      /*  22  drawer title     */
  --fs-stat:     clamp(2rem,     1.81rem  + 0.78vw, 2.5rem);    /*  32 ->  40  stat numeral */
  --fs-prose:    clamp(1rem,     0.96rem  + 0.17vw, 1.0625rem); /*  16 ->  17  article body */
  --fs-lede:     clamp(1rem,     0.954rem + 0.19vw, 1.0625rem); /*  16 ->  17  lede      */
  --fs-body:     1rem;                                          /*  16  body             */
  --fs-small:    0.875rem;                                      /*  14  secondary        */
  --fs-xs:       0.8125rem;                                     /*  13  nav, menu label  */
  --fs-2xs:      0.75rem;                                       /*  12  eyebrow, chip, meta */
  --fs-3xs:      0.6875rem;                                     /*  11  column title, badge */
  --fs-eyebrow:  0.75rem;                                       /*  12  alias            */

  /* --- Line heights --------------------------------------------------- */
  --lh-display:  1;       /* leading-none, the v2 display setting */
  --lh-heading:  1.02;
  --lh-h3:       1.16;
  --lh-lede:     1.60;
  --lh-body:     1.62;
  --lh-prose:    1.75;
  --lh-tight:    1.32;

  /* --- Letterspacing -------------------------------------------------- */
  --ls-display: -0.02em;
  --ls-h1:      -0.01em;
  --ls-h2:       0.015em;
  --ls-h3:       0.01em;
  --ls-body:     0em;
  --ls-eyebrow:  0.22em;
  --ls-label:    0.20em;
  --ls-badge:    0.15em;
  --ls-wordmark: 0.14em;
  --ls-chip:     0.04em;
  --ls-btn:      0.03em;

  /* --- Composite roles (shorthand-safe) ------------------------------- */
  --type-display: var(--fw-display) var(--fs-display)/var(--lh-display) var(--font-display);
  --type-h1:      var(--fw-display) var(--fs-h1)/var(--lh-heading) var(--font-display);
  --type-h2:      var(--fw-display) var(--fs-h2)/var(--lh-heading) var(--font-display);
  --type-h3:      var(--fw-display) var(--fs-h3)/var(--lh-h3) var(--font-display);
  --type-body:    var(--fw-regular) var(--fs-body)/var(--lh-body) var(--font-body);

  /* Measure caps. Display headings are capped in px, not ch: ch resolves
     against the body font and would throttle a condensed face to half. */
  --measure-lede:  460px;
  --measure-body:  620px;
  --measure-tight: 380px;
  --measure-prose: 68ch;

  /* ======================================================================
     8. SPACING  ·  4px base unit
     ====================================================================== */

  --space-0:   0;
  --space-05:  2px;
  --space-1:   4px;
  --space-2:   8px;
  --space-3:   12px;
  --space-4:   16px;
  --space-5:   20px;
  --space-6:   24px;
  --space-7:   32px;
  --space-8:   40px;
  --space-9:   48px;
  --space-10:  64px;
  --space-11:  80px;
  --space-12:  96px;
  --space-13:  120px;
  --space-14:  160px;

  /* Vertical rhythm. v2 sections run py-20 to py-24 (80px to 96px). */
  --section-y:      clamp(56px, 2.60rem + 3.2vw, 96px);
  --section-y-lg:   clamp(72px, 3.20rem + 4.2vw, 120px);
  --section-y-sm:   clamp(40px, 1.90rem + 2.2vw, 64px);
  --stack-gap:      clamp(12px, 0.60rem + 0.6vw, 20px);
  --grid-gap:       clamp(12px, 0.60rem + 0.7vw, 16px);

  /* ======================================================================
     9. LAYOUT  ·  containers, gutters, breakpoints
     BREAKPOINTS (documented; media queries cannot read custom properties,
     so these mirror the literals used in components.css):
        390px   small handset floor       (single column, 20px gutter)
        640px   large handset             (2-up chip rows)
        768px   tablet portrait           (2-up card grids)
       1024px   tablet landscape / small laptop
                <= 1024px  header collapses to the hamburger panel
                >  1024px  desktop megamenu and utility bar are active
       1280px   desktop baseline          (3-up and 4-up grids)
       1600px   large desktop ceiling     (container stops growing)
     ====================================================================== */

  --bp-sm:   390px;
  --bp-md:   768px;
  --bp-nav:  1024px;
  --bp-lg:   1280px;
  --bp-xl:   1600px;

  /* ONE CONTENT WIDTH FOR THE WHOLE KIT, and it is 1440px: narrower margins
     than this read cramped on a 1600px display and up. --container-wide is
     retained as a name and set to the same value, so full-bleed bands line
     their inner copy up with every other section. */
  --container-max:   1440px;
  --container-wide:  1440px;
  --container-text:  760px;   /* article reading measure */
  --gutter:          clamp(20px, 0.90rem + 1.4vw, 24px);

  --header-h:             56px;  /* main row */
  --header-utility-h:     28px;  /* utility bar, desktop only */
  --header-h-mobile:      64px;  /* compact row, 1024px and down */
  /* MEASUREMENTS, not design values: these must equal the header's real box
     or every page's top spacing is wrong. .fg-header now carries a top
     padding so its contents are not flush to the viewport edge (6px desktop,
     8px mobile, set in components.css), and the mobile row went 56 -> 64px,
     so both figures are restated here. Hairlines included:
       desktop  6 + 28 + 1 + 56 + 1 = 92   was 86
       mobile   8 + 64 + 1      = 73       was 57
     Content offsets, the mobile panel top and scroll-margin all read these,
     so every page follows automatically. */
  --header-offset:        92px;
  --header-offset-mobile: 73px;
  --menu-col:          256px; /* dropdown card column width */
  --grid-columns:      12;

  /* ======================================================================
     10. RADII  ·  sharp. v2 has no rounded corners.
     ====================================================================== */

  --radius-0:    0;
  --radius-1:    0;
  --radius-2:    0;
  --radius-3:    0;
  --radius-pill: 999px;   /* reserved; not used by any v2 component */

  /* ======================================================================
     11. MOTION  ·  durations and easing
     Asymmetric, long-tailed easing is what makes the transitions read as
     expensive rather than springy.
     ====================================================================== */

  --dur-instant: 90ms;
  --dur-fast:    140ms;
  --dur-quick:   200ms;
  --dur-base:    280ms;
  --dur-slow:    420ms;
  --dur-slower:  620ms;
  --dur-reveal:  760ms;
  --dur-ambient: 22s;

  --ease-out-expo:  cubic-bezier(0.16, 1, 0.30, 1);
  --ease-out-quart: cubic-bezier(0.25, 1, 0.50, 1);
  --ease-in-out:    cubic-bezier(0.65, 0, 0.35, 1);
  --ease-standard:  cubic-bezier(0.40, 0, 0.20, 1);
  --ease-entrance:  cubic-bezier(0.22, 0.61, 0.36, 1);

  --t-color:  color var(--dur-quick) var(--ease-standard),
              background-color var(--dur-quick) var(--ease-standard),
              border-color var(--dur-quick) var(--ease-standard);
  --t-shift:  transform var(--dur-base) var(--ease-out-expo);
  --t-panel:  opacity var(--dur-base) var(--ease-out-expo),
              transform var(--dur-base) var(--ease-out-expo),
              visibility 0s linear var(--dur-base);

  --reveal-rise: 18px;

  /* ======================================================================
     12. ELEVATION  ·  tone first; shadow only for true floating layers
     ====================================================================== */

  --shadow-none:  none;
  --shadow-menu:  0 24px 48px -20px rgba(0, 0, 0, 0.88);
  --shadow-panel: 0 30px 60px -24px rgba(0, 0, 0, 0.92);
  --shadow-lift:  0 14px 30px -20px rgba(0, 0, 0, 0.9);

  --z-base:    0;
  --z-raised:  10;
  --z-sticky:  100;
  --z-header:  600;
  --z-menu:    700;
  --z-motion:  800;
  --z-skip:    900;

  /* ======================================================================
     13. COMPATIBILITY ALIASES
     Retained names from the previous token set so no page rule resolves to
     an empty value. Both now point at the one orange. There is no separate
     "text-safe" orange in v2: where #e35530 fails, the combination is
     forbidden (see the --accent block), not recoloured.
     ====================================================================== */

  --accent-text-safe:  #e35530;

  /* ======================================================================
     14. SITEWIDE CONTRACT  ·  the role layer

     WHAT THIS SECTION IS. Sections 1 to 13 are primitives: raw colour, raw
     scale, raw spacing. A primitive answers "what values exist". It does not
     answer "which one does a page headline take", and that second question is
     where the site diverged: eleven header treatments, twenty five button
     renderings, five breadcrumb sizes, three lede components, twenty five
     font sizes. Every one of those was assembled from primitives that were
     already correct, chosen differently each time.

     This section names ONE value per role. A template that needs a page
     headline takes --fg-h1. There is no second choice to make, so two
     templates converted by two people land on the same rendering.

     WHERE THE VALUES COME FROM. The interior hero v2 pattern, in interior.css
     and the interior templates, is the newest approved arrangement and its
     scale is canon. Nothing here is a new design. Every value below is either
     lifted from that pattern, lifted from the button kit in components.css,
     or, where the two genuinely disagreed, resolved to the dominant existing
     convention. The source of each value is named beside it.

     ROLE TOKENS SIT ON TOP OF PRIMITIVES, THEY DO NOT REPLACE THEM. --fs-h1
     and the rest of section 7 stay exactly as they are, because page CSS
     already resolves against them and rewriting a primitive would move every
     rule that reads it at once. A role token is a second, stable name that
     converted templates point at. --fg-h1 is deliberately NOT --fs-h1: the
     page headline role is the hero v2 scale, which is a larger setting than
     the --fs-h1 primitive, and both values are live on the site today.
     ====================================================================== */

  /* ---- Type roles -----------------------------------------------------
     One size per role. The h1 role is the hero v2 headline scale and it is
     the same clamp on every page that carries a page title.               */

  /* THE page headline. Lifted from interior.css, the .fg-interior__hero
     block, which declares this clamp as --fg-hero-h1.
       390 wide   52.28px      1280 wide  98.56px      1385 and up  104px
     The 1280 figure is the measured interior family value in the audit, so
     the clamp and the running site agree. Set with --font-display at
     --fw-display, uppercase, --lh-display, --ls-h1, in --text-display.     */
  --fg-h1:        clamp(2rem, 1.25rem + 2.9vw, 3.625rem); /*  32 ->  58  */
  --fg-h1-measure: min(100%, 16ch);   /* the headline's own column          */

  /* Section and sub heads. These take the section 7 primitives unchanged:
     the display scale below h1 was never the part that diverged.          */
  --fg-h2:        var(--fs-h2);       /*  32 ->   44  section heading      */
  --fg-h3:        var(--fs-h3);       /*  20 ->   26  card and block title */
  --fg-h4:        var(--fs-h4);       /*  16 ->   19  Inter sub head       */

  /* Lede. One component, one size. The audit found three renderings of this
     role, at 17px regular, 17px semibold and 24px semibold. The 17px regular
     setting is the dominant one and is what .fg-lede already ships.       */
  --fg-lede:      var(--fs-lede);     /*  16 ->   17                       */

  /* Body. The audit measured five body sizes across the site, 13, 16, 17,
     20 and 24px. 17px is the dominant value by a wide margin: 19 pages and
     26,372 characters against the next largest group's 15 pages. The 17px
     reading size is therefore the role, and --fs-prose is the primitive
     that already lands on it.                                            */
  --fg-body:      var(--fs-prose);    /*  16 ->   17                       */

  /* Eyebrow. ONE size and ONE case treatment for every eyebrow on the site.
     Both existing eyebrow components already agree on 12px uppercase: the
     global .fg-eyebrow and the interior v2 bracket form, which carries both
     classes and so takes its case from the global rule. The divergences the
     audit found were the article date line at 16px sentence case and the
     placeholder eyebrows at 20px, and neither is a treatment to keep.     */
  --fg-eyebrow:      var(--fs-2xs);   /*  12                               */
  --fg-eyebrow-case: uppercase;

  /* Breadcrumb. ONE size. Five were in production: 12, 13, 14, 16 and none.
     14px is the interior hero v2 value, so canon picks it, and it is also
     the middle of the measured spread rather than an end of it.           */
  --fg-crumb:      var(--fs-small);   /*  14                               */
  --fg-crumb-gap:  var(--space-5);    /*  20  gap under the trail          */
  --fg-crumb-line: 22px;              /*      the trail's own line box     */

  /* The marker slot between the trail and the headline. Fixed height by
     construction: a page naming a section prints 12px of type at leading
     none plus a 20px gap, a page directly under Home prints a 2px rule plus
     a 30px gap, and both come to 32px, so the headline starts at the same
     distance below whichever mark the page carries.                       */
  --fg-mark-slot:  32px;

  /* ---- Buttons --------------------------------------------------------
     Three heights, and they are the kit's own boxes rather than new ones.
     The kit sets height through padding and font size, so the heights below
     are what .fg-btn already computes to:
       base   12px padding + 14px text at leading none + 2px border  =  40
       small  10px padding + 13px text at leading none + 2px border  =  35
     Primary and secondary MUST share one height. They differ only in fill
     and border, they sit side by side in .fg-btn-group, and the audit found
     them rendering at 46, 40 and 32px against each other.

     THE 46px --fg-btn--lg BOX IS OUT OF CONTRACT. It is a real kit value and
     it stays in components.css for the rules that already use it, but a
     converted template picks from the three roles below and never from it.   */
  --fg-btn-h:            40px;   /* primary, secondary and ghost, one height */
  --fg-btn-h-sm:         35px;   /* small                                    */
  --fg-btn-pad-y:        12px;
  --fg-btn-pad-x:        26px;
  --fg-btn-pad-y-sm:     10px;
  --fg-btn-pad-x-sm:     20px;
  --fg-btn-fs:           var(--fs-small);   /* 14                            */
  --fg-btn-fs-sm:        var(--fs-xs);      /* 13                            */

  /* Radius. The audit found 0, 3px and 50% in use with no shared token.
     0 is the dominant convention and it is also the stated intent of section
     10, which sets every radius step to 0 and says so. .fg-btn declares
     border-radius: 0 directly. So the kit's convention is square, the two
     3px components are the divergence, and this is the token that settles
     it for controls, fields, cards, chips and panels alike.
     The one permitted exception is a control whose box is a circle by
     construction, the back to top affordance, which takes --radius-pill.   */
  --fg-btn-radius:       var(--radius-0);   /* 0                             */
  --fg-control-radius:   var(--radius-0);   /* 0, every control and surface  */

  /* Minimum hit area on a coarse pointer. The audit found 24 of 49 visible
     interactive elements under 44px at 390 wide. The rule below the token
     block raises the button box to this floor on coarse pointers only, so
     the drawn height stays 40 and 35 under a mouse and grows to 44 under a
     thumb. It grows the real box rather than laying an invisible overlay
     over it, because an overlay on a ghost button, which has no horizontal
     padding and sits inside running text, would take clicks meant for the
     copy beside it.                                                       */
  --fg-tap-min:          44px;

  /* ---- Focus ----------------------------------------------------------
     ONE ring, and it already exists: section 5, applied in components.css
     section 4 to :where(a, button, input, select, textarea, summary,
     [tabindex]):focus-visible. No new token is minted here, because a second
     name for one ring is how a system ends up with two rings.

       colour   --focus-ring-inner   #ffffff, the 2px outline
                --focus-ring-outer   #090c14, fills the offset gap
                --focus-ring-halo    accent at 0.38, the 1px outer edge
       width    --focus-ring-width   2px
       offset   --focus-ring-offset  2px

     THE CONTRACT IS THAT NOTHING RESTATES IT. The audit found two ring
     colours in production, white on 282 stops and orange on 16, plus 29
     stops with no visible ring at all. Both faults come from a component
     writing its own :focus-visible rule. A converted template removes any
     local focus rule and lets the global one apply; where a component must
     opt in explicitly it adds the .fg-focus-ring class, which components.css
     already binds to the same declaration.                                */

  /* ---- Prose links ----------------------------------------------------
     The audit measured body links inside main p and main li computing
     text-decoration-line: none at rgb(125,137,163), which is --text-muted,
     the exact colour of the paragraph around them: a contrast ratio against
     their own surrounding text of 1.0, with no weight difference either. A
     link in running text was invisible until hover.

     THE TREATMENT IS COLOUR PLUS UNDERLINE, and both halves are already in
     the theme. article.css sets prose links to the accent with a 1px
     underline at a 2px offset, which is the one existing approved prose link
     rule, so the resting state is lifted from it unchanged.

     THE HOVER IS THE PART THAT IS FIXED HERE. article.css hovers --accent to
     --accent-hover, and section 3 sets both to #e35530, so those links
     currently change nothing at all on hover. The kit already has an accent
     to display hover, on .fg-btn--ghost in components.css section 5, so the
     link hover takes that same pair rather than inventing a state.

     SURFACE LIMIT. --accent as small text measures 5.22 / 4.98 / 4.68 on
     base, raised and panel, and 4.49 on --surface-elevated, which section 3
     forbids. Prose bands run on the first three. A prose block that must sit
     on --surface-elevated takes --fg-link-hover as its resting colour, where
     the underline still carries the distinction and the ratio is 15.39:1.  */
  --fg-link:            var(--accent);          /* #e35530                  */
  --fg-link-hover:      var(--text-display);    /* #f3f5f8                  */
  --fg-link-decoration: underline;
  --fg-link-offset:     2px;

  /* ---- Alignment ------------------------------------------------------
     Long-form body copy is left aligned. Centring is reserved for a short
     lede and for a call to action band.

     WHAT WENT WRONG. The audit found a 597 character paragraph centred
     across 1216px, roughly eight lines with a ragged left edge on every one,
     and the same prose component computing center on three product pages,
     start on three others and left on a seventh. The cause is an opt-in
     class applied per node, so the alignment was an editorial accident.

     WHAT CSS CAN AND CANNOT ENFORCE. A stylesheet cannot count characters,
     so it cannot refuse to centre a long paragraph. It CAN cap the measure
     of anything centred, which is the half that stops the eight line case:
     .fg-u-center below carries --fg-center-max and centres itself in the
     column. The character ceiling is an authoring rule, stated in the
     contract document and checked per template, not a rule this file can
     hold. Both halves are needed and neither substitutes for the other.    */
  --fg-center-max: var(--measure-lede);   /* 460px                          */
}

/* ==========================================================================
   REDUCED MOTION  ·  the static state is the default, not a fallback.
   motion.js also stamps html[data-motion="reduced"] so JS-driven ambient
   loops never start. See components.css for the paused-state rules.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 1ms;
    --dur-fast:    1ms;
    --dur-quick:   1ms;
    --dur-base:    1ms;
    --dur-slow:    1ms;
    --dur-slower:  1ms;
    --dur-reveal:  1ms;
    --reveal-rise: 0px;
  }
}

/* ==========================================================================
   CONTRACT RULES  ·  the four places a token is not enough

   A token settles a value. It does not settle a behaviour, and four of the
   audit's findings are behaviours: prose links carried no underline, long
   copy was centred, small controls were under a thumb's reach, and 3px
   corners appeared on two components. The rules below are the enforcing half
   of section 14.

   THIS SHEET LOADS FIRST, at weight -10, ahead of components.css and every
   page stylesheet. That is correct for custom properties, which have to be
   defined before anything reads them, and it is the weakest position in the
   cascade for a rule. So the defaults below are written to be overridable by
   a component that has a reason, and the two utilities, which exist
   specifically to override a component, carry !important on the single
   property they are named for and on nothing else.
   ========================================================================== */

/* ---- Prose links --------------------------------------------------------
   Applied to running copy only: the long-form containers, not navigation,
   not cards, not buttons, all of which carry their own affordance and would
   be damaged by an underline. A component that needs a bare link still opts
   out locally, which is why this is not !important.                        */
.fg-prose a:not([class]),
.fg-prose p a,
.fg-prose li a,
.fg-article__body a,
.fg-catalog__prose a,
.fg-interior__lede a {
  color: var(--fg-link);
  text-decoration-line: var(--fg-link-decoration);
  text-underline-offset: var(--fg-link-offset);
  transition: var(--t-color);
}

.fg-prose a:not([class]):hover,
.fg-prose p a:hover,
.fg-prose li a:hover,
.fg-article__body a:hover,
.fg-catalog__prose a:hover,
.fg-interior__lede a:hover,
.fg-prose a:not([class]):focus-visible,
.fg-prose p a:focus-visible,
.fg-prose li a:focus-visible,
.fg-article__body a:focus-visible,
.fg-catalog__prose a:focus-visible,
.fg-interior__lede a:focus-visible {
  color: var(--fg-link-hover);
  text-decoration-line: var(--fg-link-decoration);
}

/* ---- Alignment ----------------------------------------------------------
   The default: long-form containers set their copy from the start edge.
   Written without !important so a component with a genuine reason can still
   differ, and so this does not silently reflow the catalog pages that carry
   the per-node centring class. Retiring that opt-in class is a template
   change, made where the class is applied, not something a token sheet
   should do behind the page's back.                                        */
.fg-prose,
.fg-article__body,
.fg-catalog__prose {
  text-align: start;
}

/* Tables, data and lists are never centred, whatever the block around them
   does. Centred data cannot be read down a column.                         */
.fg-prose table, .fg-prose th, .fg-prose td,
.fg-article__body table, .fg-article__body th, .fg-article__body td,
.fg-catalog__prose table, .fg-catalog__prose th, .fg-catalog__prose td {
  text-align: start;
}

/* THE TWO UTILITIES. These are the only sanctioned way to change alignment
   in a converted template.

   .fg-u-center is the centring permission, and it carries its own ceiling:
   an element that centres also takes --fg-center-max, so a paragraph cannot
   be centred across a 1216px column the way the audit found one. The measure
   is the enforceable half. The other half is an authoring rule, stated in
   the contract document: centre a short lede or a call to action line, not
   running copy, and never more than about two lines of it. CSS cannot count
   characters, so that half is checked per template, not here.

   A call to action band centres its LAYOUT, through the flex alignment of
   its own component, and does not need this class for that. This class is
   for the text inside a short block.                                       */
.fg-u-center {
  text-align: center !important;
  margin-inline: auto;
  max-width: min(100%, var(--fg-center-max));
}

.fg-u-align-start {
  text-align: start !important;
}

/* ---- Controls -----------------------------------------------------------
   Square corners, stated once. Two components ship 3px and the rest ship 0;
   this is the rule that makes 0 the value rather than the accident. Kept off
   !important so the one circular control can still be a circle.            */
.fg-btn,
.fg-input,
.fg-select,
.fg-textarea,
input[type="text"], input[type="email"], input[type="tel"],
input[type="search"], input[type="number"], input[type="url"],
input[type="password"], input[type="date"], select, textarea,
.button, .form-submit, .webform-button--submit {
  border-radius: var(--fg-control-radius);
}

/* The coarse pointer floor. Height only: nothing here touches the drawn
   padding, the type or the corners, so a button looks the same and answers
   a thumb. Scoped to pointer: coarse so a mouse still gets the compact kit. */
@media (pointer: coarse) {
  .fg-btn,
  .button,
  .form-submit,
  .webform-button--submit {
    min-height: var(--fg-tap-min);
  }
}
