/* ============================================================================
   ALLOCATION POINT — INSTRUMENT GRADE (WARMED) · tokens.css
   ============================================================================
   The single source of truth for the family's visual tokens. Plain CSS custom
   properties: consumable by Tailwind v4 (see IMPLEMENTATION.md for the @theme
   wiring), by Astro/Jinja templates via a plain <link>, and — as hardcoded
   hex fallbacks — by the HTML-email subset (the email column of every value
   is documented in IMPLEMENTATION.md; email clients get resolved hexes, never
   var()).

   Structure:
     1. Core semantic tokens (light mode is the default — light-first system)
     2. Per-product accent scopes  [data-accent="…"]
     3. Dark treatment            [data-theme="dark"]
     4. Texture (permission-gated — see rules below)

   Accent mechanics: each accent scope sets a light/dark PAIR; --accent itself
   is an indirection that the dark theme re-points. Components only ever use
   --accent / --accent-wash / --accent-contrast and get the correct value in
   either theme automatically.

   Every ink/accent pair here was computationally verified against WCAG 2.1 AA
   (≥ 4.5:1 text, ≥ 3:1 UI) on its permitted surfaces — ratios are tabulated
   in DESIGN-SYSTEM.md. Do not tweak these hexes ad hoc; re-run the checks.
   ========================================================================== */

:root {
  color-scheme: light;

  /* ---- 1a. Surfaces — the two-layer elevation model -----------------------
     The page sits on warm canvas; data sits on pure white "instrument"
     surfaces one layer up. Elevation is expressed by surface color + hairline,
     never by drop shadow (single exception: --shadow-float, maps only).
     --canvas-deep is the tonal band for long-page section rhythm. */
  --canvas:       #F7F5F0;   /* page background — warm off-white           */
  --canvas-deep:  #F0EDE5;   /* tonal section band on marketing pages      */
  --surface:      #FFFFFF;   /* elevated data surfaces: tables, cards, map panels */
  --well:         #F6F4EF;   /* sunken wells INSIDE a white surface (toolbars, zebra) */

  /* ---- 1b. Lines ---------------------------------------------------------- */
  --hairline:        #E4E0D5; /* default border on canvas and surface        */
  --hairline-strong: #C9C3B4; /* emphasized rules: table header underline    */

  /* ---- 1c. Ink ------------------------------------------------------------
     Warm near-neutral charcoals. ink-3 is the FLOOR for text (4.61:1 on the
     deepest band) — anything lighter is decoration, not text. */
  --ink:   #1D1B17;
  --ink-2: #4C4943;
  --ink-3: #6E6A60;

  /* ---- 1d. Global masthead ribbon (32px app-switcher) ---------------------
     The ribbon is ink-colored in BOTH themes — it is the family's constant. */
  --ribbon-bg:     #1D1B17;
  --ribbon-text:   #F0EDE5;
  --ribbon-muted:  #A9A296;
  --ribbon-h:      32px;

  /* ---- 1e. Accent indirection --------------------------------------------
     Set by the [data-accent] scopes below; defaults to the hub. Components
     use only these three. --accent is text-safe on canvas, canvas-deep,
     surface, and well; --accent-contrast is the text color ON accent fills. */
  --accent-l:      #A84A2A;
  --accent-d:      #E8916C;
  --accent-wash-l: #F6EDEA;
  --accent-wash-d: #422F25;
  --accent:          var(--accent-l);
  --accent-wash:     var(--accent-wash-l);
  --accent-contrast: #FFFFFF;

  /* ---- 1f. Status (forms, notices). Never used as data-series colors. ---- */
  --danger:  #B42318;
  --success: #1E7A44;

  /* ---- 1g. Typography -----------------------------------------------------
     Instrument Sans = display voice: headlines and section heads only, at
       weights 600–650 with tight tracking — angular panel-lettering
       character, distinct from the Inter body without costume.
     Inter    = everything else: UI, body, data. tabular-nums globally.
     Plex Mono = technical marginalia: coordinates, band edges, annotations. */
  --font-display: "Instrument Sans", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-sans:    "Inter", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-mono:    "IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  /* type scale (size / paired line-height) */
  --text-xs:   12px;   --leading-xs:   1.5;   /* marginalia, table footnotes  */
  --text-sm:   13.5px; --leading-sm:   1.5;   /* dense tables, captions      */
  --text-base: 16px;   --leading-base: 1.6;   /* body                        */
  --text-lede: 18px;   --leading-lede: 1.6;   /* hero ledes                  */
  --text-h4:   17px;   --leading-h4:   1.4;
  --text-h3:   21px;   --leading-h3:   1.35;
  --text-h2:   27px;   --leading-h2:   1.25;
  --text-h1:   34px;   --leading-h1:   1.15;
  --text-display:    44px; --leading-display:    1.08; /* display face from here up */
  --text-display-xl: 56px; --leading-display-xl: 1.04;

  /* ---- 1h. Spacing (4px base) --------------------------------------------- */
  --space-1: 4px;  --space-2: 8px;   --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px;  --space-7: 48px; --space-8: 64px;
  --space-9: 96px;

  /* ---- 1i. Shape & elevation ---------------------------------------------- */
  --radius:    4px;   /* buttons, inputs, chips        */
  --radius-lg: 6px;   /* cards, tables, panels         */
  --border-w:  1px;   /* the hairline                  */
  --rule-w:    2px;   /* emphasized rules              */
  /* THE ONE SHADOW. Permitted only on panels floating over map canvases,
     where a hairline alone disappears against imagery. Nowhere else. */
  --shadow-float: 0 2px 10px rgba(29, 27, 23, 0.14), 0 0 0 1px var(--hairline);

  /* ---- 1j. Layout ---------------------------------------------------------- */
  --wrap-max: 1180px;
  --measure:  66ch;    /* max reading width for body copy */
}

/* ============================================================================
   2. PER-PRODUCT ACCENT SCOPES
   Apply data-accent on <html> or <body> (whole property) or on any subtree
   (cross-property embeds). Values are the validated pairs; the family-strip
   order is the product order 1–6.

   NOTE ON MECHANICS — accent × theme is enumerated EXPLICITLY below rather
   than via var() indirection. A custom property resolves its var() references
   at the element where it is DECLARED, and descendants inherit the resolved
   value; an indirection like `--accent: var(--accent-l)` therefore goes stale
   inside nested scopes (a proof card, an embed, a dark wrapper). Twelve plain
   rules cost nothing and can never resolve wrong. The --accent-l/--accent-d
   pairs remain available for chrome that needs a fixed variant regardless of
   theme (the ribbon's family strip always uses --accent-d on its dark bar).
   ========================================================================== */
[data-accent="consulting"] { --accent:#A84A2A; --accent-wash:#F6EDEA; --accent-l:#A84A2A; --accent-d:#E8916C; --accent-wash-l:#F6EDEA; --accent-wash-d:#422F25; } /* 01 oxidized copper */
[data-accent="chart"]      { --accent:#1C4EAA; --accent-wash:#E8EDF7; --accent-l:#1C4EAA; --accent-d:#8FB0F2; --accent-wash-l:#E8EDF7; --accent-wash-d:#32353D; } /* 02 federal cobalt  */
[data-accent="auctions"]   { --accent:#C73620; --accent-wash:#F9EBE9; --accent-l:#C73620; --accent-d:#F2907C; --accent-wash-l:#F9EBE9; --accent-wash-d:#442F28; } /* 03 vermilion       */
[data-accent="explorer"]   { --accent:#00705E; --accent-wash:#E6F1EF; --accent-l:#00705E; --accent-d:#63C9AE; --accent-wash-l:#E6F1EF; --accent-wash-d:#2A3A31; } /* 04 utility green   */
[data-accent="digest"]     { --accent:#8A6600; --accent-wash:#F3F0E6; --accent-l:#8A6600; --accent-d:#D8B24A; --accent-wash-l:#F3F0E6; --accent-wash-d:#3F351F; } /* 05 brass           */
/* 06 is the RESERVED SPARE accent slot, unassigned and unused — not an "atlas" product.
   Zone Atlas was folded into FCC Explorer as map layers (Spectrum Strategy §3.3, §5.3);
   the selector keeps its historical name only to avoid a breaking rename across every
   consuming repo. Zone layers use the `explorer` accent. Don't wire a property to this. */
[data-accent="atlas"]      { --accent:#006C93; --accent-wash:#E6F0F4; --accent-l:#006C93; --accent-d:#55BAE2; --accent-wash-l:#E6F0F4; --accent-wash-d:#28373A; } /* 06 blueprint cyan  */

/* accent scopes at or below a dark scope get the dark variant (the
   two-selector form covers both nesting orders and same-element use) */
[data-theme="dark"] [data-accent="consulting"], [data-accent="consulting"][data-theme="dark"] { --accent:#E8916C; --accent-wash:#422F25; }
[data-theme="dark"] [data-accent="chart"],      [data-accent="chart"][data-theme="dark"]      { --accent:#8FB0F2; --accent-wash:#32353D; }
[data-theme="dark"] [data-accent="auctions"],   [data-accent="auctions"][data-theme="dark"]   { --accent:#F2907C; --accent-wash:#442F28; }
[data-theme="dark"] [data-accent="explorer"],   [data-accent="explorer"][data-theme="dark"]   { --accent:#63C9AE; --accent-wash:#2A3A31; }
[data-theme="dark"] [data-accent="digest"],     [data-accent="digest"][data-theme="dark"]     { --accent:#D8B24A; --accent-wash:#3F351F; }
[data-theme="dark"] [data-accent="atlas"],      [data-accent="atlas"][data-theme="dark"]      { --accent:#55BAE2; --accent-wash:#28373A; }

/* ============================================================================
   3. DARK TREATMENT — warm near-black, explicit opt-in via data-theme.
   Default for long map sessions; toggleable elsewhere. (If a property wants
   OS-auto dark, mirror this block inside
   @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { … } }.)
   The ribbon tokens intentionally do not change.
   ========================================================================== */
[data-theme="dark"] {
  color-scheme: dark;

  /* SCOPE-BOUNDARY RULE — inherited properties must be RE-DECLARED here,
     not just re-tokened. `color` inherits as a COMPUTED value: if a page
     sets `color: var(--ink)` at body and a nested dark scope only
     redefines --ink, descendants keep inheriting the light-resolved
     color straight through the dark wrapper (light ink on dark surface,
     ~1:1). Declaring color here makes every descendant recompute against
     the locally-cascaded dark ink. Second instance of the resolved-value
     inheritance class (see b751c14 for the custom-property twin); the
     rule lives in DESIGN-SYSTEM.md §9. */
  color: var(--ink);

  --canvas:      #161310;
  --canvas-deep: #12100D;
  --surface:     #1E1A15;   /* elevated data surfaces on dark                */
  --well:        #26211B;

  --hairline:        #322D25;
  --hairline-strong: #4A443A;

  --ink:   #EDE9DF;
  --ink-2: #B5AEA0;
  --ink-3: #B5AEA0;  /* muted collapses into ink-2 on dark: a third gray
                        would fall below 4.5:1, so dark mode has two ink
                        levels, not three */

  /* accents flip to their calibrated dark variants; text ON accent fills
     flips to dark canvas (all pairs ≥ 7.6:1) */
  --accent:          var(--accent-d);
  --accent-wash:     var(--accent-wash-d);
  --accent-contrast: #161310;

  --danger:  #F1917E;
  --success: #7BC89B;

  --shadow-float: 0 2px 12px rgba(0, 0, 0, 0.5), 0 0 0 1px var(--hairline);
}

/* ============================================================================
   4. TEXTURE — the allocation-density trace
   --------------------------------------------------------------------------
   Phase 5: replaces the generated engineering grid outright (retired, not
   kept as an alternative — see CHANGELOG.md). The ground is now a single
   data-derived treatment: allocation density across 30 MHz–6 GHz, computed
   from the real U.S. Table of Frequency Allocations
   (data/ntia-allocations-30mhz-6ghz.json) and rendered as a bottom-anchored
   stepped trace — an analyzer floor, not a decoration. Regenerate the SVGs
   with scripts/gen-texture-candidates.mjs; each carries its own provenance
   comment. Bake-off record: specimens/warm/texture-bakeoff.html.

   PERMITTED:  marketing/chrome surfaces only — hero bands, tonal section
               bands (--canvas-deep areas), footers, empty states, page
               chrome around (never under) a map.
   FORBIDDEN:  behind dense data tables, behind/on map canvases, on elevated
               --surface/--well cards, inside form fields, anywhere in email.
   Alpha is solved, not eyeballed (see the generator script): 2.4% light /
   5% dark, chosen so ink/ink-2/copper stay >= 4.5:1 directly over a stroke
   pixel on every permitted surface.

   HARD RULE — ink-3 never sits on a texture stroke. At the strict reading
   (every text token permitted on a stroke) the safe ceiling collapses to
   ~1% alpha — impractical, and the RETIRED grid already failed AA under it
   (ink-3 over a gridline on the deep tonal band measured 4.30:1; the new
   trace's own ink-3-over-stroke composite measures 4.41 on the deep band —
   still short of 4.5). Any marginalia, label, or other ink-3 text that would
   otherwise render directly on a textured background must step up to ink-2
   (7.33–7.88 over a stroke on either light surface; comfortable margin).
   Text inside an opaque elevated surface (--surface or --well) floating
   within a textured zone is unaffected — the surface sits between it and
   the texture, not the texture itself.
   ========================================================================== */
.texture-trace {
  background-image: url('assets/texture-trace-light.svg');
  background-repeat: no-repeat;
  background-position: bottom;
  background-size: 100% 220px;
}
[data-theme="dark"] .texture-trace {
  background-image: url('assets/texture-trace-dark.svg');
}

/* ============================================================================
   5. MOTION — "Power-On / The Sweep"  (see CONCEPT.md and MOTION.md)
   --------------------------------------------------------------------------
   Organizing rule: GRATICULE vs. SIGNAL. The reference layer — hairlines,
   marginalia, ruler ticks, labels, focus rings — never moves. Only signal
   (content, washes, traces, indicators) animates.

   Durations are Morse-derived: unit = 120ms (10 WPM by the PARIS standard).
   dit = 1 unit, dah = 3 units, word = 7 units. The 60ms stagger is dit/2 —
   a documented deviation from Morse (no half-dit exists) used for
   overlapping reveals.

   Easings:
     --ease-sweep     linear — instruments sweep at constant rate. Used for
                      sweeps, underline draws, loader travel. Deliberate.
     --ease-settle    damped needle: ONE small overshoot, just under critical
                      damping. Never make it bouncier — a wobbling needle is
                      where instrument becomes cartoon.
     --ease-attenuate accelerate-out, for exits/dismissals.

   Reduced motion is a token mechanism, not per-component cleanup:
   TRANSFORM-BEARING transitions/animations must take their duration as
     calc(var(--dur-X) * var(--motion-move))
   so prefers-reduced-motion collapses them to 0ms (instant, settled state)
   while opacity/color state changes (≤150ms, non-vestibular) keep timing.
   JS-driven reveals must additionally check the media query and never hide
   content when it matches.
   ========================================================================== */
:root {
  --dur-dit:  120ms;  /* micro state changes: hovers, washes, underlines, selection */
  --dur-dah:  360ms;  /* reveals, panel settles                             */
  --dur-word: 840ms;  /* the largest gestures: ruler sweep, loader cycle    */
  --dur-el:    60ms;  /* stagger step between sibling reveals (dit/2)       */
  --motion-move: 1;   /* multiplier for transform-bearing motion            */
  --ease-sweep:     linear;
  --ease-settle:    cubic-bezier(0.33, 1.24, 0.44, 1);
  --ease-attenuate: cubic-bezier(0.4, 0, 1, 1);
}
@media (prefers-reduced-motion: reduce) {
  :root { --motion-move: 0; }
}

/* ============================================================================
   Base application — the few global rules the tokens imply.
   ========================================================================== */
.tokens-base,
body.tokens-base {
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-base);
  font-variant-numeric: tabular-nums;  /* global: every numeral aligns */
  -webkit-font-smoothing: antialiased;
}
