/*
 * @bsuite/theme — Braden Corporate brand baseline
 * Version 0.4.0
 *
 * Usage (braden.com.au only):
 *   @import '@bsuite/theme/braden-css';
 *
 * EXCLUSIVELY for the braden.com.au Corporate brand. Never import this into a
 * D2C app (crm7, conduit, BSU, R80.3, throughput), and never put Neon Electric
 * colours on a Corporate surface.
 *
 * GENERATED FROM THE CONTRACT, NOT HAND-TUNED.
 * Every value below is copied from
 *   packages/theme/docs/braden-corporate-theme-source-of-truth.html
 * which is authoritative. Operator ruling 2026-08-03: only colours present in
 * the two source-of-truth documents are permitted in packages/. Verify with
 *   scripts/audit-palette-whitelist.py
 *
 * WHAT CHANGED IN 0.4.0 AND WHY IT MATTERED
 * 0.3.0 carried its own hand-built red/gold/navy ramps. 52 of its values
 * appeared nowhere in the Corporate contract — close to the brand, but not the
 * brand, and drifting further with every edit. This file also shipped a header
 * asserting "purple error is a cross-brand system requirement", which was
 * already false twice over: the 0.7.0 separation-first contract retired purple
 * for semantics, and the Corporate contract binds error to --braden-indigo.
 *
 * ERROR IS RED HERE — OPERATOR RULING 2026-08-10, superseding the indigo rule.
 * Braden: "use standard error red not braden corporate red."
 *
 * What this overturns. 0.4.0 bound error to --braden-indigo on a
 * separation-first argument: D2C's primary is blue so error must be red;
 * Corporate's primary IS red so error must not be. That reasoning was sound
 * and it is no longer the rule. Error now uses --error-red, the SAME standard
 * error red the D2C brand uses (oklch(0.580 0.230 25)) — one error colour
 * across the estate. Recognition beats palette separation: a person reads red
 * as "danger" before they read it as "Braden".
 *
 * --error-red is NOT a Braden brand colour and must never be used as one. It
 * is permitted here for the error/destructive roles only. It stays inside the
 * palette whitelist because it is a value the D2C source-of-truth document
 * already ships; the whitelist pools both contracts.
 *
 * THE COST, MEASURED, SO NOBODY REDISCOVERS IT AS A BUG:
 *   ΔE_oklch(error red, --braden-red) = 0.113   ← now the palette's tightest pair
 *   ΔE_oklch(old indigo, --braden-red) = 0.312
 * The Corporate contract's previously-worst pair was 0.143. A destructive
 * button and a primary button are now both red, separated by lightness (0.092)
 * and chroma rather than hue, and under deuteranopia lightness is nearly all
 * that survives. THEREFORE: destructive actions on Corporate must carry an
 * icon or an explicit verb ("Delete"), never colour alone. The contract
 * already said shape and label do more work on this brand than on D2C; after
 * this ruling that is load-bearing rather than advisory.
 */
@import './scrollbars.css';

:root {

/* ============================================================
   LAYER 1 — BRAND PALETTE
   Raw brand colours. Consumers must never bind to these directly.
   ============================================================ */
  --braden-red:        oklch(0.488 0.170 17.6);
  --braden-red-light:  oklch(0.572 0.201 17.9);
  --braden-red-dark:   oklch(0.400 0.137 16.8);
  --braden-gold:       oklch(0.758 0.092 89.9);
  --braden-gold-light: oklch(0.818 0.070 90.0);
  --braden-bronze:     oklch(0.698 0.110 89.2);
  --braden-navy:       oklch(0.356 0.039 249.0);
  --braden-slate:      oklch(0.710 0.018 201.3);
  --braden-sky:        oklch(0.653 0.135 242.7);
  --braden-forest:     oklch(0.663 0.160 152.4);
  --braden-lavender:   oklch(0.577 0.152 315.3);
  --braden-indigo:     oklch(0.400 0.200 270);
  --braden-teal-deep:  oklch(0.500 0.140 220);
  --braden-aqua:       oklch(0.800 0.130 198);

  /* NOT A BRAND COLOUR. The estate's single standard error red, identical to
     D2C's, bound to error/destructive only — operator ruling 2026-08-10.
     Never bind this to primary, accent, a gradient stop or any decorative
     surface: doing so puts a non-Braden red on a Braden page. */
  --error-red:         oklch(0.580 0.230  25);

/* ============================================================
   LAYER 2 — SURFACES AND BORDERS
   ============================================================ */
  /* THE WHOLE LIGHT RAMP SITS 0.012 LOWER THAN IT USED TO, and the reason is
     the top of it. --role-bg-panel was oklch(0.994 …) — brighter than the
     value this design system calls white, oklch(0.982 0.002 248) / #f8f9fa.
     The agent visual gate fails any surface at L >= 0.990 as a pure endpoint
     (visual-probe C1), and braden/ is exempt from the D2C PALETTE only: the
     pure white/black ban is platform-wide by operator ruling 2026-08-02.
     visual-probe's own comment names this exact case — three live declarations
     carried the comment "pure white banned" while declaring oklch(0.994 …).

     Capping the panel alone would have left it 0.002 above the body, which is
     no separation at all: every card on the marketing pages would read as flat
     against the page. So the ramp SLID rather than clamped. Every interval is
     preserved to three decimals — panel-over-body is still 0.014, body-over-
     surface still 0.012, surface-over-sunken still 0.016 — and the ceiling now
     lands exactly on the sanctioned white instead of past it.

     Contrast re-measured through OKLab -> linear sRGB -> WCAG relative
     luminance for all three text roles against all five surfaces. Fifteen
     pairs, every one still AA, worst case --role-h6 on --role-bg-sunken at
     6.40:1 against a 4.5:1 requirement. The largest single loss is 0.61 on a
     ratio of 17.78, which is the arithmetic of moving a near-white 1.2% and
     not a legibility change. Hue and chroma are untouched: the warm 50/55
     greys stay warm, which is the Braden identity and is not what was wrong. */
  /* THE TWO NAMED ENDPOINTS, which this baseline did not have and vars.css
     did. braden/ imports braden-css and preset-v4.css and NOT vars.css, so
     `var(--white)` resolved to nothing here — and the consequence is visible
     in braden's own src/index.css, where eight hairline and gradient rules
     spell oklch(0.99 0.004 250 / 0.08) by hand because there was no token to
     bind to. A missing token does not stop anyone needing the colour; it just
     moves the value into eight places where nothing can find it again.

     Same values as the D2C baseline, deliberately: white and black are estate
     constants, not brand choices. Braden's identity is the warm 50/55 greys
     and the red/gold/navy above, not its idea of white. Keeping these two in
     sync across both baselines is the point — a Corporate-specific white would
     reintroduce exactly the drift this removes. */
  --white:              oklch(0.982 0.002 247.8); /* #f8f9fa */
  --black:              oklch(0.166 0.026 269);   /* #0a0e1a */

  --role-bg-body:       oklch(0.968 0.002 50);
  --role-bg-surface:    oklch(0.956 0.004 55);
  --role-bg-panel:      oklch(0.982 0.001 50);
  --role-bg-input:      oklch(0.960 0.003 250);
  --role-bg-sunken:     oklch(0.940 0.005 250);
  --role-border:        oklch(0.900 0.008 248);
  --role-border-strong: oklch(0.840 0.012 248);

/* ============================================================
   LAYER 3 — HEADING RAMP (six levels, per the contract)
   ============================================================ */
  --role-h1: oklch(0.20 0.028 252);
  --role-h2: oklch(0.25 0.034 250);
  --role-h3: oklch(0.30 0.040 246);
  --role-h4: oklch(0.35 0.046 240);
  --role-h5: oklch(0.40 0.052 232);
  --role-h6: oklch(0.44 0.058 224);

/* ============================================================
   LAYER 3 — TEXT AND LINKS
   ============================================================ */
  --role-text-heading:   var(--role-h1);
  --role-text-body:      oklch(0.22 0.020 250);
  /* -base is what a LIGHT panel nested inside a dark section resets to. A
     dark brand fill re-scopes the surface tokens for everything inside it,
     which is right until the section contains a white card — then the card
     inherits on-dark type and renders light-on-white. The reset cannot
     hardcode a value because the correct one differs per theme, so it reads
     this alias instead. */
  --role-text-secondary-base: oklch(0.38 0.018 250);
  --role-text-secondary: var(--role-text-secondary-base);
  --role-text-muted:     oklch(0.44 0.018 250);  /* 7.06:1 on bg-body · 4.71:1 worst, on primary/20 over sunken ✓ AA */
  --role-text-subtle:    oklch(0.60 0.012 250);
  --role-text-disabled:  oklch(0.72 0.010 250);
  --role-text-strong:    oklch(0.16 0.024 252);
  --role-text-emphasis:  oklch(0.42 0.070 240);
  --role-link:           oklch(0.480 0.140 245);
  --role-link-hover:     oklch(0.400 0.150 250);
  --role-link-visited:   oklch(0.450 0.120 300);

/* ============================================================
   LAYER 3 — EDITORIAL (code, quote, mark, kbd)
   ============================================================ */
  --role-code-text:  oklch(0.400 0.090 230);
  --role-code-bg:    oklch(0.950 0.010 235);
  --role-quote-text: oklch(0.400 0.060 25);
  --role-quote-rule: var(--braden-gold);
  --role-mark-bg:    oklch(0.930 0.060 90);
  --role-mark-text:  oklch(0.24 0.040 60);
  --role-kbd-bg:     oklch(0.962 0.004 250);
  --role-kbd-border: oklch(0.870 0.010 250);

/* ============================================================
   LAYER 3 — SEMANTIC ROLES
   error = --error-red, the estate's standard error red — operator ruling
   2026-08-10. It is deliberately NOT --braden-red: the brand primary and the
   destructive colour must still be two different values, even now that both
   are red. See the header for the measured separation and what it obliges.
   ============================================================ */
  --role-primary:     var(--braden-red);
  --role-secondary:   var(--braden-navy);
  --role-accent:      var(--braden-gold);
  --role-error:       var(--error-red);
  --role-destructive: var(--error-red);
  --role-warning:     var(--braden-gold);
  --role-success:     var(--braden-aqua);
  --role-info:        var(--braden-teal-deep);

  /* ═══ INFORMATIONAL SCALE — categorical, NOT semantic ═══
     Added 2026-08-03 by operator ruling: "informational hues might be handy
     to stand out against the style colour palette."

     Role tokens describe STATE. They cannot describe CATEGORY — which
     pipeline stage, which user role, which product tile. Apps that needed a
     category reached for raw Tailwind instead, which is how one role-badge
     table came to use purple, indigo, blue, violet and sky as its only
     distinguishing signal.

     NUMBERED, NOT NAMED, deliberately. Call one of these "moss green" and
     it will be used for success within a week. A number says what these
     are: interchangeable slots carrying no meaning of their own.
     NEVER use an --info-* for state. State has role tokens.

     Derived, not picked by eye: Vienot-Brettel-Mollon dichromat simulation,
     DeltaE in OKLab, scored as the WORST case across normal, deuteranope and
     protanope vision. Two constraints — perceptual distance keeps them
     DISTINGUISHABLE, a >=28 degree hue gap keeps them looking CATEGORICAL
     rather than like a light/dark pair of one colour. Every one is also
     held away from the brand roles, which is what "stand out against the
     style palette" requires: an informational badge must not read as a
     primary action or an error.
     Reproduce with scripts/design-informational-hues.py

     LIMIT: worst-case separation is ~0.06-0.07, against >=0.156 for the
     semantic pairs. That is 10x better than the purple-vs-blue pairing this
     system rejected (0.006), but it is NOT the semantic standard and cannot
     be — 8 mutually-distinct categories that also avoid 6 reserved brand
     colours is a harder problem than 6 roles. So: colour is never the sole
     signifier for a category. Always pair with a label or an icon. Past 8
     categories, stop adding hues and add a second dimension. */
  --info-1: oklch(0.660 0.120   0.0);
  --info-2: oklch(0.660 0.120  30.0);
  --info-3: oklch(0.620 0.120  72.0);
  --info-4: oklch(0.460 0.120 132.0);
  --info-5: oklch(0.780 0.120 162.0);
  --info-6: oklch(0.740 0.120 222.0);
  --info-7: oklch(0.660 0.120 252.0);
  --info-8: oklch(0.620 0.120 324.0);

  /* ═══ STAGE RAMP — progression, one hue, ascending lightness ═══
     For an ORDERED sequence (pipeline stages), not a category set. A ramp
     encodes direction: "further along" is visible at a glance, and it
     survives greyscale and both dichromacies because lightness carries it.
     Arbitrary per-stage hues cannot do that — a reader has to LEARN that
     sky comes after amber.

     Progression only. OUTCOMES are state, not stage: a hired candidate is
     --role-success, a rejected one --role-error, a withdrawn one muted.
     Do not extend this ramp to cover them. */
  --stage-1: oklch(0.860 0.090 249.0);
  --stage-2: oklch(0.780 0.090 249.0);
  --stage-3: oklch(0.700 0.090 249.0);
  --stage-4: oklch(0.620 0.090 249.0);
  --stage-5: oklch(0.540 0.090 249.0);
  --stage-6: oklch(0.460 0.090 249.0);

/* ============================================================
   LAYER 3 — AA-SAFE TEXT RENDERINGS OF THE SATURATED ROLES
   A saturated fill colour is not a legible text colour.
   ============================================================ */
  --role-primary-text: oklch(0.467 0.170 17.6);
  --role-accent-text-base: oklch(0.495 0.092 89.9);
  --role-accent-text:  var(--role-accent-text-base);
  /* Red, per the 2026-08-10 ruling. Measured on Corporate's own light
     surfaces, not inherited from D2C's: 6.18:1 on --role-bg-body,
     6.44:1 on --role-bg-panel. Both ✓ AA. */
  --role-error-text:   oklch(0.432 0.230  25);
  --role-warning-text: oklch(0.495 0.092 89.9);
  --role-success-text: oklch(0.466 0.130 198);
  --role-info-text:    oklch(0.430 0.140 220);

/* ============================================================
   LAYER 3 — INVERSE TEXT ON COLOURED FILLS
   ============================================================ */
  --text-on-light-fill: oklch(0.980 0.006 50);
  --text-on-dark-fill:  oklch(0.190 0.020 250);
  --text-on-primary:    var(--text-on-light-fill);
  /* On the new error red (L 0.58) this measures 4.54:1 — ✓ AA, but with no
     headroom. It was 9.35:1 on the old indigo fill (L 0.40). If the error
     fill is ever lightened, re-measure before shipping: a tenth of a point of
     lightness drops it below AA. */
  --text-on-error:      var(--text-on-light-fill);
  --text-on-accent:     var(--text-on-dark-fill);
  --text-on-warning:    var(--text-on-dark-fill);
  --text-on-success:    var(--text-on-dark-fill);
  --text-on-info:       var(--text-on-light-fill);
  /* Was MISSING and preset-v4.css references it, so --color-overlay-foreground
     resolved to nothing and any text on a scrim fell back to whatever it
     inherited. Measured undefined in the browser on 2026-08-03. The scrim is
     dark in both modes, so this is light in both. */
  --text-on-overlay:    var(--text-on-light-fill);

/* ============================================================
   DECORATION — shadow, glow, dot and grid
   ============================================================ */
  --gradient-accent: linear-gradient(135deg, var(--braden-red), var(--braden-gold));
  /* Same gradient, re-stopped for a DARK backdrop. --gradient-accent is built
     for fills on a light surface: against the hero scrim (L~0.36) its red stop
     measures ~1.7:1 and the text half-disappears. This keeps the red hue and
     chroma exactly (17.6 / 0.17) and lifts only lightness to a value the
     contract already ships, so both stops clear the scrim and G2 still passes. */
  --braden-red-on-dark: oklch(0.704 0.170 17.6);
  --gradient-accent-on-dark: linear-gradient(135deg, var(--braden-red-on-dark), var(--braden-gold));
  --shadow-xs:       0 1px 2px oklch(0.30 0.03 250 / 0.06);
  --shadow-sm:       0 1px 3px oklch(0.30 0.03 250 / 0.08), 0 1px 2px oklch(0.30 0.03 250 / 0.04);
  --shadow-md:       0 4px 10px -3px oklch(0.30 0.03 250 / 0.10), 0 2px 4px -2px oklch(0.30 0.03 250 / 0.06);
  --shadow-lg:       0 14px 26px -8px oklch(0.28 0.04 250 / 0.14), 0 5px 10px -5px oklch(0.28 0.04 250 / 0.07);

  /* ============================================================
     SHADOW INK — Corporate. Added 2026-08-12 alongside the elevation ramp.
     ============================================================
     braden imports BOTH braden-css and preset-v4.css, so it receives the
     `shadow-elev-0..4` utilities and the rebound `--shadow-*` namespace.
     Those resolve through --shadow-ink-*, which lived only in the D2C
     vars.css — without these four lines every one of them would resolve to
     an undefined colour, the browser would drop the layer, and the utility
     would render nothing. That is the exact phantom-utility bug the ramp
     was added to fix, so shipping it for D2C only would have re-created it
     here. braden/CLAUDE.md already instructs `shadow-elev-*`.

     The four --shadow-xs/sm/md/lg above are UNTOUCHED. They are corporate's
     own bespoke soft geometry and remain correct for direct
     `box-shadow: var(--shadow-md)` call sites; they never fed a Tailwind
     utility, because a `:root` custom property registers no v4 utility.

     Tint is corporate's own shadow colour, not the D2C navy. Base opacity
     0.10 keeps the light ramp inside the 0.06-0.14 band the values above
     already use — "subtle professional shadows, no neon glow". */
  --shadow-strength:  1;
  --shadow-color:     oklch(0.30 0.03 250 / 0.10);
  --shadow-ink-faint: oklch(from var(--shadow-color) l c h / calc(alpha * 0.4 * var(--shadow-strength)));
  --shadow-ink-soft:  oklch(from var(--shadow-color) l c h / calc(alpha * 0.6 * var(--shadow-strength)));
  --shadow-ink:       oklch(from var(--shadow-color) l c h / calc(alpha * 1.0 * var(--shadow-strength)));
  --shadow-ink-deep:  oklch(from var(--shadow-color) l c h / calc(alpha * 1.6 * var(--shadow-strength)));
  --glow-card:       none;
  --glow-card-hover: none;
  --panel-hairline:  transparent;
  --dot-color:       oklch(0.42 0.030 250 / 0.14);
  --dot-size:        16px;
  --dot-radius:      1px;
  --grid-color:      oklch(0.40 0.030 250 / 0.07);
  --grid-size:       32px;

/* ============================================================
   TYPOGRAPHY AND GEOMETRY
   ============================================================ */
  --font-display:  'Open Sans', system-ui, sans-serif;
  --font-heading:  Lato, 'Open Sans', system-ui, sans-serif;
  --font-body:     'Open Sans', system-ui, sans-serif;
  --font-mono:     'JetBrains Mono', ui-monospace, monospace;
  --track-display: -0.018em;
  --track-heading: -0.008em;
  --track-body:    0em;
  --track-eyebrow: 0.10em;
  /* Corporate radius language: tight, 4/6/10. Defined since the brand landed and
     read by NOTHING — measured 2026-08-30, zero consumers estate-wide, so every
     `rounded-sm`/`rounded-lg` in the braden app rendered Tailwind's 2px/8px instead
     of the brand's 4px/10px. Moved into the --role-* namespace the contract already
     uses for bindable tokens, and mapped onto the utilities in preset-v4.css. The
     old names are kept as aliases: unconsumed today, but removing a public custom
     property is a breaking change we have no reason to make in the same commit. */
  --role-radius-sm:  4px;
  --role-radius-md:  6px;
  --role-radius-lg:  10px;
  --radius-sm:     var(--role-radius-sm);
  --radius:        var(--role-radius-md);
  --radius-lg:     var(--role-radius-lg);
  --row-pad:       11px;
}

/* ============================================================
   DARK MODE — the contract's .dark block, verbatim.
   Only tokens the contract actually flips appear here; anything
   absent is mode-independent by design, not by omission.
   ============================================================ */
.dark {
  --role-bg-body:        oklch(0.140 0.012 252);
  --role-bg-surface:     oklch(0.180 0.016 251);
  --role-bg-panel:       oklch(0.205 0.018 250);
  --role-bg-input:       oklch(0.245 0.020 250);
  --role-bg-sunken:      oklch(0.120 0.010 252);
  --role-border:         oklch(0.320 0.020 250);
  --role-border-strong:  oklch(0.420 0.024 250);
  --role-h1:             oklch(0.95 0.014 250);
  --role-h2:             oklch(0.92 0.018 250);
  --role-h3:             oklch(0.88 0.024 244);
  --role-h4:             oklch(0.84 0.032 236);
  --role-h5:             oklch(0.80 0.040 228);
  --role-h6:             oklch(0.75 0.048 220);
  --role-text-body:      oklch(0.93 0.014 250);
  --role-text-secondary-base: oklch(0.80 0.016 250);
  --role-text-secondary: var(--role-text-secondary-base);
  --role-text-muted:     oklch(0.66 0.018 250);
  --role-text-subtle:    oklch(0.55 0.015 250);
  --role-text-disabled:  oklch(0.43 0.010 250);
  --role-text-strong:    oklch(0.97 0.010 250);
  --role-text-emphasis:  oklch(0.85 0.050 235);
  --role-link:           oklch(0.780 0.110 240);
  --role-link-hover:     oklch(0.860 0.095 225);
  --role-link-visited:   oklch(0.770 0.080 300);
  --role-code-text:      oklch(0.850 0.070 215);
  --role-code-bg:        oklch(0.250 0.026 230);
  --role-quote-text:     oklch(0.840 0.045 40);
  --role-quote-rule:     var(--braden-gold);
  --role-mark-bg:        oklch(0.360 0.060 85);
  --role-mark-text:      oklch(0.94 0.030 85);
  --role-kbd-bg:         oklch(0.250 0.020 250);
  --role-kbd-border:     oklch(0.400 0.022 250);
  --role-primary-text:   oklch(0.704 0.170 17.6);
  --role-accent-text-base: oklch(0.733 0.092 89.9);
  --role-accent-text:    var(--role-accent-text-base);
  /* Red, per the 2026-08-10 ruling. 7.24:1 on --role-bg-body,
     6.51:1 on --role-bg-panel. Both ✓ AA. */
  --role-error-text:     oklch(0.786 0.230  25);
  --role-warning-text:   oklch(0.733 0.092 89.9);
  --role-success-text:   oklch(0.730 0.130 198);
  --role-info-text:      oklch(0.667 0.140 220);
  --shadow-xs:           0 1px 2px oklch(0.07 0.01 252 / 0.5);
  --shadow-sm:           0 1px 3px oklch(0.07 0.01 252 / 0.55);
  --shadow-md:           0 6px 16px -6px oklch(0.07 0.01 252 / 0.6);
  --shadow-lg:           0 18px 34px -12px oklch(0.07 0.01 252 / 0.68);

  /* Corporate dark ink. Re-declared here, not inherited: a var() inside a
     custom property resolves at the element where it is DECLARED, so the
     :root ladder would freeze to its light value and every dark shadow
     would silently be a light-mode shadow. Measured, both a plain alias and
     a computed form freeze this way. Base 0.70 lands the main layer at 0.56
     after --shadow-strength, inside the 0.5-0.68 band above. */
  --shadow-strength:  0.8;
  --shadow-color:     oklch(0.07 0.01 252 / 0.70);
  --shadow-ink-faint: oklch(from var(--shadow-color) l c h / calc(alpha * 0.4 * var(--shadow-strength)));
  --shadow-ink-soft:  oklch(from var(--shadow-color) l c h / calc(alpha * 0.6 * var(--shadow-strength)));
  --shadow-ink:       oklch(from var(--shadow-color) l c h / calc(alpha * 1.0 * var(--shadow-strength)));
  --shadow-ink-deep:  oklch(from var(--shadow-color) l c h / calc(alpha * 1.6 * var(--shadow-strength)));
  --glow-card:           0 0 0 1px color-mix(in oklch, var(--braden-gold) 18%, transparent), 0 0 10px -4px color-mix(in oklch, var(--braden-gold) 20%, transparent);
  --glow-card-hover:     0 0 0 1px color-mix(in oklch, var(--braden-gold) 30%, transparent), 0 0 16px -4px color-mix(in oklch, var(--braden-gold) 32%, transparent);
  --panel-hairline:      color-mix(in oklch, var(--braden-gold) 26%, transparent);
  --dot-color:           oklch(0.72 0.060 90 / 0.16);
  --grid-color:          oklch(0.82 0.020 250 / 0.055);
}

/* ============================================================
   BASE — Corporate sets the heading FACE only.
   ============================================================
   Not colour, not size, not weight, not transform. Reverted to this after
   operator review ("well that looks worse") and a measurement that showed
   why: on the live site the hero H1 picked up the ramp colour while the 25
   headings below it kept their explicit `text-braden-navy`. One heading
   stopped matching the rest. That is not a hierarchy.

   A base rule only reaches elements that do not style themselves. In a
   dense app UI that is most headings, which is the case the ramp was
   measured against. On a marketing site it is almost none — 59 headings
   here carry an explicit brand colour and their own size utility — so a
   base ramp cannot create hierarchy there, only a mismatch on whichever
   few it happens to reach.

   font-family is the exception: nothing on the page overrides it, so it
   lands uniformly and is exactly what a base rule is for.

   D2C keeps the full ramp (see vars.css) — those apps ARE the dense-UI
   case, and the ramp is verified there in a real browser by G5. */
@layer base {
  h1 { font-family: var(--font-display); }
  h2, h3, h4, h5, h6 { font-family: var(--font-heading); }

  /* The root element's colour was the UA default — measured pure black (L=0)
     in BOTH modes on 2026-08-03, i.e. the one banned value, sitting at the top
     of the inheritance chain. Nothing renders text at <html> so it was
     invisible to review, but every element that does not set a colour and is
     not under a styled ancestor lands on it. */
  html { color: var(--role-text-body); background-color: var(--role-bg-base); }

  /* The contract names a family and the package shipped the token, but NOTHING
     bound it to an element — so every app fell back to whatever it happened
     to set itself, which is how crm7 ran Inter against a Geist contract and
     the estate ran four families at once. Same defect as the heading ramp:
     a token nobody applies is not a font, it is a variable. */
  body { font-family: var(--font-body); }
  code, kbd, samp, pre { font-family: var(--font-mono); }
}

/* ============================================================
   DARK SURFACES INSIDE LIGHT MODE
   ============================================================
   A navy or red panel on a light page is a dark surface, and the mode-sensitive
   role tokens are still resolving their LIGHT values inside it. That is not a
   theoretical problem — measured on the contact section 2026-08-03:

     --role-accent-text (light) on bg-braden-navy ....... 2.20:1   FAIL
     --braden-gold                on bg-braden-navy ..... 5.07:1   AA

   and the mirror holds on a light background, where the brand gold is 2.05:1
   and the light accent is 4.71:1. No single value passes on both, so this
   cannot be fixed by picking a better gold — the token has to follow the
   SURFACE, not just the mode. Mark a dark panel and its accent text flips. */
[data-surface='dark'] {
  --role-accent-text: var(--braden-gold);
  --role-text-body: var(--text-on-light-fill);
  --role-text-secondary: var(--text-on-light-fill);
  /* D2C's heading ramp reads this; Corporate has no colour ramp, but a shared
     surface contract should behave the same in both brands. */
  --heading-color: currentColor;
}

/* ============================================================
   GRADIENT TEXT — the one place the accent gradient paints glyphs.
   ============================================================
   background-clip:text needs `color: transparent` to show through, which means
   a failed gradient produces INVISIBLE TEXT rather than an ugly one. So both
   stops resolve from tokens defined above in this same file, never from a
   token an app might or might not have. */
@layer components {
  .text-gradient-accent {
    background-image: var(--gradient-accent);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  .text-gradient-accent-on-dark {
    background-image: var(--gradient-accent-on-dark);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  /* Forced-colours mode drops background-image entirely, which would leave
     transparent glyphs on screen. Hand the text back to the system palette. */
  @media (forced-colors: active) {
    .text-gradient-accent,
    .text-gradient-accent-on-dark { background-image: none; color: CanvasText; }
  }
}
