/* Maverick Wx — design tokens. The single source of truth for colour, type, spacing,
   borders, focus and layout metrics across every section.

   This file carries **The Advisory** (`DESIGN.md`): the site set as the WMO bulletin its
   graphics are derived from. One ink, one paper, three greys between them, and the entire
   colour budget spent on the Saffir-Simpson and formation-risk ramps in styles.css — so a
   reader can rely on the inverse, that every chromatic pixel on this site means
   meteorological severity and nothing else.

   Four passes brought it here: the typefaces, the removal of the interface accent, the
   `LABEL...VALUE` field line, and the status pass. This is the fifth and last of them — the
   grounds — and it is the one that makes the file stop describing two systems at once.

   ## What the ground swap deleted, and why the names could not simply be re-pointed

   Every earlier pass re-pointed tokens rather than renaming them, because a name that
   describes a *role* survives a change of value and renaming it is a thousand-line diff
   that moves no pixels. That argument runs out here, because these names describe a
   **structure** rather than a role, and the structure is what went:

     --bg + --card  ->  --paper      Clear Sky had a canvas and a surface that floated on
                                     it, 1.08:1 apart. The Advisory has one plane. Two names
                                     for one ground is not a naming choice, it is an
                                     invitation to draw a card, and the next person to write
                                     `background: var(--card)` would have drawn one.
     --card-2/-3    ->  --wash/-strong   A recessed surface and a lifted surface become ink
                                     applied to the paper: a stripe, a hover, a highlighted
                                     line on a printout. Marks on the one plane, not planes.
     --radius*      ->  (gone)       Square, without exception. There is no ramp to pick
                                     from because there is nothing to pick.
     --shadow*      ->  (gone)       Nothing floats, so nothing casts. Separation is a rule
                                     or it is whitespace.
     --navy/-2      ->  (gone)       A second dark brand ground alongside the ink was the
                                     last place two systems disagreed about what "dark"
                                     means. The image viewer, the endpoints band and the
                                     radar canvas all reverse to --ink now.
     --neutral-*    ->  (gone)       Nine tokens serving two rules, both of them a tag.

   The five that remain are the five DESIGN.md publishes. --muted, --line and --ink-2 keep
   their names: those are roles (metadata, divider, secondary ink) and they are what four
   stylesheets and two rendering systems already ask for.

   Themes are declared twice, and both are load-bearing:
     :root                                    light — the default, everywhere
     :root[data-theme=dark] / [data-dark]     the reader's stated choice, and Radar's
   There is no `prefers-color-scheme` rule. Light is the product's face — a printed record
   is a light thing — and reading the OS meant most visitors never saw it. Dark is one click
   away in the masthead and persists; Radar still opens dark on its own.

   Every colour pair a reader actually sees is measured, not eyeballed;
   `tests/web/test_contrast.py` is the instrument. */

:root {
  /* ---- Type: one superfamily, two registers -------------------------------------
     IBM Plex, set as two registers of one family. `--font-body` (IBM Plex Sans) is the
     voice: the page title, section headings, system names, navigation, controls and all
     prose — everything a reader reads as language or operates as an interface. `--font-mono`
     (IBM Plex Mono) is the data: winds, pressures, coordinates, timestamps, IDs, ATCF codes,
     endpoint paths and code — everything a reader compares down a column. The split is
     functional before it is aesthetic: tabular figures keep digits in columns so two
     readings can be compared down a list, and a `LABEL...VALUE` line only aligns if the
     value advances at a fixed rate.

     The two are one family drawn as a system, which is why they no longer clash where they
     meet: Plex Sans and Plex Mono share a skeleton and proportions, so a heading over a data
     column reads as one voice at two widths. The pairing before it — Public Sans over
     Inconsolata — set a signage sans against a code-listing mono, two unrelated worlds that
     read as two eras on one page. The mono is now demoted to values; a heading is the sans's
     own voice, larger, not a teletype.

     `--font-display` stood beside these until the short-scale pass and is gone: a heading is
     `--font-body` at a heading step, not a third face. */
  --font-mono: "IBM Plex Mono", "IBM Plex Mono Fallback", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --font-body: "IBM Plex Sans", "IBM Plex Sans Fallback", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* ---- The short scale: four steps --------------------------------------------------
     There were twenty. Nine `--fs-*` tokens and eleven hard-coded sizes that never reached
     a token at all — 13.5px in fourteen rules, 12.5px in thirteen, six each of 14px and
     13px. A scale with twenty steps is not a scale; it is the absence of one, and every
     new element got whatever size its neighbour happened to have.

       --fs-title      the page title, one per page
       --fs-lead       section headings and state sentences — the ...HEADLINE... form
       --fs-bulletin   values, tables, IDs, coordinates, timestamps, endpoint paths
       --fs-remarks    prose: sentences rather than readings
       --fs-micro      the WMO id line, chip text, units, registration marks

     That is **four steps**, not five. Bulletin and Remarks are one step in two registers:
     IBM Plex Mono at 15px and IBM Plex Sans at 16px set to nearly the same x-height, so a
     value and the sentence explaining it sit on one optical line. Setting them to the
     identical number is what would look wrong.

     Hierarchy comes from case, weight and the `----` and `...` devices. A fifth size is how
     a system stops having an opinion. */
  --fs-title: clamp(26px, 3.2vw, 34px);
  --fs-lead: 19px;
  --fs-bulletin: 15px;
  --fs-remarks: 16px;
  --fs-micro: 11px;

  /* The rest of each role, so a rule asks for a role rather than re-deriving one. */
  --lh-title: 1.15;
  --lh-lead: 1.3;
  --lh-bulletin: 1.55;
  --lh-remarks: 1.65;
  --lh-micro: 1.4;
  --track-title: -0.01em;
  --track-micro: 0.04em;

  /* ---- Spacing: a 4px base ---- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-7: 32px;
  --sp-8: 44px;

  /* ---- The committed colour: enamel ------------------------------------------------
     The Transit Board replaces The Advisory, and its one interface colour is the midnight
     enamel a metropolitan transit diagram is fired on. It carries whole regions — the
     masthead station-header, the section headers, the primary action — rather than tinting
     an accent, and it is emphatically NOT a member of the Saffir-Simpson ramp: a deep cobalt
     is not the bright sky-blue of a tropical depression, and the ramp never appears as text,
     a rule or a link, so the two languages cannot be confused.

     Colour still means one thing at a time. Storm severity is the ramp and nothing else — on
     this world each storm reads as a transit *route* in its own category colour. The enamel
     means structure and affordance and nothing else. And **state is still carried by reversal
     and a rank marker, never by a hue** — the ramp already spans the spectrum, so no status
     colour could avoid colliding with a category. That discipline is inherited intact.

       --enamel        #14275e  the field: masthead, section headers, primary ground
       --enamel-strong #0e1c45  its darker edge, for a hairline or a hover
       --enamel-wash   #e7ecf7  a pale enamel field behind an inset (light)
       --enamel-link   #1c3f8f  interactive text on paper — 9.24:1, plainly not tier-td
       --on-enamel     #ffffff  text on the enamel field — 14.17:1
       --on-enamel-muted #aebede  the secondary half of a line on enamel — 7.57:1, tinted
                                  from the enamel per the craft floor, never grey
     Every pair a reader sees is measured; `tests/web/test_contrast.py` is the instrument. */
  --enamel: #14275e;
  --enamel-strong: #0e1c45;
  --enamel-wash: #e7ecf7;
  --enamel-link: #1c3f8f;
  --on-enamel: #ffffff;
  --on-enamel-muted: #aebede;
  --network: color-mix(in srgb, var(--enamel) 26%, transparent);
  /* Route bullets and interchange nodes are the one round thing on the board — a transit
     line badge and a station tick are circular, and that reads at a glance. Everything
     structural stays ruled and square. */
  --radius-node: 999px;

  /* ---- The one plane -----------------------------------------------------------------
     Paper is barely warm and deliberately not white: bulletin stock, so that a reversed
     block reads as printed rather than as a screen inverting. It is the *only* ground.
     Nothing is a surface on top of it.

     The two washes are ink laid on that paper, in alpha so they compose correctly wherever
     they land — including inside a reversed block, where a wash lightens the ink rather
     than punching a pale rectangle through it. That is the difference between a mark and a
     plane, and it is why they are not opaque colours.

       --wash          4%   table stripes, code grounds, recessed rows, `<pre>`
       --wash-strong   8%   hover and selection, :target, skeletons

     Measured on paper: ink 17.18:1, --muted 6.10:1, --edge 3.67:1. Ink holds 15.87:1 on
     --wash and 14.63:1 on --wash-strong; --muted holds 5.64:1 and 5.20:1. */
  --paper: #f9f9f7;
  --wash: color-mix(in srgb, var(--ink) 4%, transparent);
  --wash-strong: color-mix(in srgb, var(--ink) 8%, transparent);

  --ink: #14161a;
  --ink-2: #383d44;       /* secondary headings, de-emphasised body — 10.38:1 */
  --muted: #5a5f66;       /* metadata, captions, the label half of a field line — 6.10:1 */

  /* Two boundary tokens, because they answer different criteria and one token for both
     means either an invisible input or a shouting divider. A divider owes nothing — 1.55:1
     is *correct* for a separator, which should not compete with what it separates. A
     control boundary owes 3:1 under WCAG 1.4.11, and since the accent went it is the whole
     affordance, so it has to clear on its own. */
  --line: #c9cbc7;        /* the `----` rule and table hairlines — 1.55:1 */
  --line-strong: #a5a8a2; /* a rule that has to be seen against a wash — 2.28:1 */
  --edge: #7e837d;        /* anything a reader can operate — 3.67:1 */

  /* A link carries the committed enamel colour and keeps its underline in prose (WCAG
     1.4.1): colour is the affordance where the ground makes it unambiguous, the underline
     where running prose would otherwise swallow it. The token names the role and four
     stylesheets ask for it. */
  --link: var(--enamel-link);
  --code-bg: var(--wash);
  --skeleton: var(--wash-strong);

  /* The masthead is the network's station header: the enamel field the whole diagram hangs
     from, printed across the top and separated from the paper by its own edge. */
  --header: var(--enamel);
  --header-ink: var(--on-enamel);
  --header-nav: var(--on-enamel-muted);

  /* ---- No status colour --------------------------------------------------------------
     Twelve tokens stood here — --ok/--warn/--critical, each with a -mark, a -bg and an
     on- sibling — and they are gone for the same reason the accent ramp went: on this site
     colour means meteorological severity and nothing else.

     Deleting them repaired something rather than merely tidying. `--warn-mark` (#b86a12)
     was rendered as a dot twelve pixels below `.chip.tier-c2` (#ff9f1c) in every rail row,
     meaning "this advisory is late" and "Category 2" in the same hue.

     The ladder that replaced them is rank, not hue, and it is the same in all three places
     the site reports a state — the freshness component, the masthead pill, and the NWS
     section's severity chips:

       ordinary     a "·" marker, muted, no emphasis        (current, held)
       caution      a "!" marker, ink, weight 700, ruled    (aging, warn)
       escalation   a "!!" marker, reversed — paper on ink  (stale, unavailable, degraded)

     Reversal survives greyscale, a colour-vision difference and a forced-colours mode
     identically, and unlike a red it can never be mistaken for a Saffir-Simpson tier.
     `held` never escalates: showing the last good state on purpose is invariant 5 working,
     and marking it as a fault is how a reader learns to ignore faults.
     ------------------------------------------------------------------------------------ */

  /* ---- Dividers, in alpha form so hairlines hold over any ground ---- */
  --divider: color-mix(in srgb, var(--ink) 12%, transparent);
  --divider-strong: color-mix(in srgb, var(--ink) 24%, transparent);

  /* ---- Borders, focus, motion --------------------------------------------------------
     There is no --radius ramp and no --shadow ramp. Both are deleted rather than set to
     zero: a --radius that reads 0 is still a knob, and the first rule to turn it back up
     re-opens the question this system has already answered. Square, one plane, no
     exceptions — the drawer included, which is genuinely above the page and says so with a
     full-height rule instead of a shadow. */
  --hairline: 1px solid var(--line);
  --focus-ring: 2px solid var(--ink);
  --focus-offset: 2px;
  --dur: 0.16s;
  --ease: ease;

  /* ---- Layout metrics ----
     --wrap is the reading measure, used by prose pages. --wrap-wide is the dashboard
     measure: Storms is a monitoring surface, not an article. Workspace sections ignore
     both and go full-bleed. --wrap-prose is narrower still and exists for the editorial
     pages — 68ch resolves to ~640px on IBM Plex Sans, and the `ch` unit is face-relative so
     this token follows a face change on its own. */
  --wrap-prose: 68ch;
  --wrap: 1120px;
  --wrap-wide: 1440px;
  --gutter: var(--sp-5);

  /* Measured at runtime by shell.js; the values here are the pre-JS estimate so the
     first paint is not wrong before the measurement lands. */
  --masthead-h: 62px;
  --pagehead-h: 0px;
  --banner-h: 0px;
  /* An in-page section navigator, where a page has one. Zero everywhere else, so the
     offsets that compose from it are correct on every page that does not. */
  --subnav-h: 0px;

  /* ONE primary rail width. There were three — 300px on the dashboard, 340px for the
     radar controls, 252px for the section nav — chosen independently, which is exactly
     the tell that the sections were designed as separate products. A rail is the same
     furniture doing the same job in all of them, so it is the same width; a section that
     needs different *content* density varies its rows, not the column. */
  --panel-w: 300px;
  --subrail-w: 236px;     /* the secondary, in-content category rail */
  --drawer-w: 340px;      /* the drawer is wider than the rail: it is the whole surface */
  --drawer-bp: 900px;     /* documentation only; media queries cannot read a var */
  /* Form controls, scrollbars and the canvas the browser paints behind the page. It
     follows the tokens rather than the OS for the same reason they do. */
  color-scheme: light;
}

/* --------------------------------------------------------------------------------
   The same bulletin at night, not a second vocabulary.

   Every value below is the sibling of its light counterpart in the same role, and the
   reversed pair is the same two colours swapped — so a reversed block cannot pass contrast
   in one appearance and fail in the other. Radar opts in regardless of preference (see
   data-dark on <html> in radar.html) because reflectivity and satellite imagery need a
   low-glare ground to read against.

   Everywhere else it is a *stated* choice. There is no `prefers-color-scheme` rule here —
   dark arrives through the masthead toggle (which persists in localStorage and is
   re-applied before first paint by the guard in every page head) or through Radar's own
   opt-in. A reader who wants dark everywhere gets it in one click, and keeps it.

   Measured on the dark paper: ink 15.77:1, --muted 7.31:1, --edge 3.59:1. The washes hold
   ink at 14.59:1 and 13.32:1.
   -------------------------------------------------------------------------------- */

/* `[data-dark]` is the second entry point: Radar sets it on <html> so the workspace opens
   dark for a reader who has expressed no preference, without writing a choice into their
   localStorage on their behalf. `:not([data-theme="light"])` is what lets that reader say
   no. */
/* `.viewer` is the third entry point and it is not a theme: the full-screen image stage
   takes the night palette in *either* appearance, because a graphic is read against a dark
   surround and a light one glares. Declaring it here rather than re-typing five hexes on
   the viewer's own rules is what keeps the two from drifting apart. */
:root[data-theme="dark"],
:root[data-dark]:not([data-theme="light"]),
.viewer {
  color-scheme: dark;

  /* The diagram at night: the enamel mural itself. A deep indigo ground rather than a
     neutral black, so the cobalt that is the interface colour by day is the very air after
     dark. */
  --paper: #0f1f47;

  --ink: #eef1f8;
  --ink-2: #c6cee0;
  --muted: #9fb0d6;

  --line: #26335c;
  --line-strong: #3c4a76;
  --edge: #6b789e;

  /* The enamel family at night. The field lifts off the mural; the interactive cobalt is
     the sibling of the light enamel-link, brighter because the ground is dark, and still
     never a member of the ramp. `--header`, `--link` and `--network` reference these, so
     they follow this redefinition without being re-declared. */
  --enamel: #1c3570;
  --enamel-strong: #0b1738;
  --enamel-wash: #16294f;
  --enamel-link: #9fc0ff;
  --on-enamel: #eef1f8;
  --on-enamel-muted: #9fb0d6;

  --divider: color-mix(in srgb, var(--ink) 16%, transparent);
  --divider-strong: color-mix(in srgb, var(--ink) 28%, transparent);
}
