/* Global brand tokens — colors, type, spacing, radii, shadows, motion.
   See docs/superpowers/plans/2026-04-30-form-editor-redesign-pr1.md Task 1.
   Note: app/assets/stylesheets/move_out_landing.css declares the same tokens
   under .mo-page for legacy reasons. Same values; can be removed in a
   follow-up sweep. */
/* ---- Webfonts ------------------------------------------------------------------
   Both families are served from our own origin. See app/assets/fonts/README.md
   for what is vendored and how to refresh it.

   This used to be an `@import` of a remote Google Fonts stylesheet, which is the
   slowest way to load a font: the browser cannot see it until this stylesheet has
   arrived and parsed, so the chain ran HTML -> brand_tokens.css -> Google's CSS ->
   the woff2. Three serial round trips, while the <link> in the layout head fetched
   Poppins on the first hop. Petrona always lost that race, and because the hero
   headline is centred, the swap from the fallback serif moved every line 44px
   sideways after the page had already painted.
   Pinned by test/system/webfont_stability_test.rb.

   Poppins is gone. It was --zw-font-display and Tailwind's --font-display, but the
   homepage never painted a single glyph of it; the surfaces that did use it (/work,
   the admin page header, the event partials) now take the system sans stack below.

   Both families are VARIABLE fonts, so one file per subset covers the whole weight
   range and `font-weight: 400 700` on the @font-face is what tells the browser so.
   Only latin and latin-ext are vendored; a glyph outside them falls back per
   character to the next family in the stack. */

@font-face {
  font-family: "Petrona";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/petrona-latin-b303f1cd.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Petrona";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/petrona-latin-ext-bac6024b.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/jetbrains-mono-latin-68dbce1c.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/jetbrains-mono-latin-ext-b0c48b7a.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Petrona is now same-origin and preloaded, so it normally paints first time. On a
   slow enough connection it can still lose, and `font-display: swap` means the
   fallback paints and is then replaced -- which only goes unnoticed if the two
   occupy the same width. Georgia scaled to Petrona's width is that fallback.

   `font-weight: 400 700` is doing more work here than it looks. Georgia is a static
   face, and declaring the range tells the browser this face already covers 600, so
   it stops SYNTHESISING the bold. That matters twice over: synthetic emboldening
   widens text by an amount that differs per browser, which no single size-adjust
   could track, and it is also what made the first measurement of this number wrong
   by 15%.

   With synthesis suppressed, Georgia and Petrona are already close, and the gap
   depends on weight -- Petrona is variable and gains width as it gets heavier,
   Georgia cannot. Measured ratios (Petrona / Georgia at size-adjust 100%):

     weight 400   0.972
     weight 600   1.006   <- every consumer of --zw-font-serif sets 600
     weight 700   1.026

   So 100.6%, tuned at 600. Per-string spread at that weight is 0.997-1.024: a
   single scale factor cannot match every letter mix exactly, and the residual is
   about a percent of line width -- against the 15% that caused the reported jump.

   The ascent/descent overrides are not optional, and the reasoning that says
   they are is wrong in a way worth writing down. Every consumer sets an
   explicit unitless line-height, so the line box HEIGHT does come from
   font-size and not from the font. But the BASELINE sits inside that box
   according to the face's own ascent and descent, so a fallback with different
   vertical metrics puts the text at a different height in an identically sized
   box. Georgia is 0.92/0.22 and Times 0.97/0.24 against Petrona's 0.86/0.27,
   which moved the headline 3px vertically on a host with no Georgia -- caught
   only by simulating one, because Georgia's own offset stayed inside the
   tolerance.

   The percentages are NOT 86/27 as you would expect, because size-adjust
   multiplies the overrides as well as the glyphs. Each face divides Petrona's
   metrics by its own scale factor: 86/1.006 and 86/1.092. Change a size-adjust
   here and these have to move with it.

   `local()` only, so this costs no download. Where Georgia is absent (Android,
   most Linux) the face does not match and the stack falls through to the plain
   serif below.

   If you re-cut Petrona, re-measure: test/system/webfont_stability_test.rb
   compares rendered widths and fails if this number drifts. */
@font-face {
  font-family: "Petrona Fallback";
  font-style: normal;
  font-weight: 400 700;
  src: local("Georgia");
  size-adjust: 100.6%;
  ascent-override: 85.5%;
  descent-override: 26.8%;
  line-gap-override: 0%;
}

/* The same trick for the platforms with no Georgia -- Linux, Android, and CI.
   Without this the stack falls straight through to the generic `serif` with no
   scaling at all, which is a 2.4% width difference and moved the hero 6px on a
   Linux runner. Georgia is not the only serif worth matching, it is just the
   only one most of our visitors have.

   Faces listed widest-net-first: Liberation Serif and Tinos are the metric
   clones of Times shipped by most distros and by GitHub's runners, Noto and
   DejaVu Serif cover Android and the rest, and Times New Roman is the last
   stop. They are close enough in width to share one scale factor.

   109.2%, measured against Times New Roman -- Liberation Serif and Tinos are
   metric clones of it, so the number carries. Do NOT derive this from what a
   Linux runner reports for the bare generic `serif`: that measurement includes
   Chrome SYNTHESISING the bold at weight 600, while this face declares
   `font-weight: 400 700` and so suppresses it. Reading 102.5% off an
   unsuppressed measurement left the face 6.5% narrow. Same trap as the Georgia
   face above, in the opposite direction; measure against a face declared the
   way this one is.

   Split from the Georgia face rather than added to its src list because the two
   need DIFFERENT scale factors, and one @font-face carries only one. */
@font-face {
  font-family: "Petrona Fallback Serif";
  font-style: normal;
  font-weight: 400 700;
  src: local("Liberation Serif"), local("Tinos"), local("Noto Serif"),
       local("DejaVu Serif"), local("Times New Roman");
  size-adjust: 109.2%;
  ascent-override: 78.8%;
  descent-override: 24.7%;
  line-gap-override: 0%;
}

:root {
  --zw-blue-900: #1f4063;
  --zw-blue-800: #29527d;
  --zw-blue-700: #336699;
  --zw-blue-600: #4d7cb0;
  --zw-blue-500: #6f98c4;
  --zw-blue-300: #b3c8dd;
  --zw-blue-200: #c2d3e3; /* the outlined quiet CTA's border — too light at 300 */
  --zw-blue-100: #e4ecf4;
  --zw-blue-50:  #f2f6fa;

  /* Green measures: the reduction ladder, progress, impact. Never a button.
     Design System 3.0 replaced the 2.x mint-leaning ramp (#00cc99 at 600) with the
     muted measurement greens, so this ramp now carries the kit's values rather than
     a second, brighter green that happened to share the name.

     The old ramp was also failing WCAG AA everywhere it was used as text: 700 was
     #00a881, which is 3.04:1 on white, across 32 `text-zw-green-700` usages. The
     steps below are ordered light-to-dark so `bg-zw-green-600 hover:bg-zw-green-700`
     still darkens on hover, and 600 is dark enough to carry white text (5.14:1).

     600 is the canonical 3.0 green. Mint (#00cc99) survives as --zw-mint, which is
     the logo and the 2027 goal bar and nothing else.

     test/assets/green_contrast_test.rb pins the legibility of every step. */
  --zw-green-900: #163f34; /* interpolated, darkest ink */
  --zw-green-800: #1f5a49; /* kit --zw-green-deep */
  --zw-green-700: #276754; /* interpolated, the hover for 600 */
  --zw-green-600: #2f7a63; /* kit --zw-green — the canonical 3.0 green */
  --zw-green-500: #4e9a80; /* kit --zw-green-mid */
  --zw-green-300: #a8d3c3; /* kit --zw-green-on-dk */
  --zw-green-100: #cfe6dc; /* kit --zw-green-line */
  --zw-green-50:  #eef6f2; /* kit --zw-green-tint */

  /* Brand palette: Red (Crayola) #ee4266, Jonquil #ffcb05, Safety orange #fa760a.
     The 500 step is the brand value; the rest are tints/shades around it so a
     traffic-light row can pair a 50 background with a 500 dot and a 900 label. */
  --zw-red-900: #8f1633;
  --zw-red-700: #c9284b;
  --zw-red-500: #ee4266;
  --zw-red-300: #f593a9;
  --zw-red-100: #fbd0d9;
  --zw-red-50:  #fdecef;

  --zw-yellow-900: #7a6100;
  --zw-yellow-700: #b38e00;
  --zw-yellow-500: #ffcb05;
  --zw-yellow-300: #ffe066;
  --zw-yellow-100: #fff0b0;
  --zw-yellow-50:  #fff9e0;

  --zw-orange-900: #8a3e04;
  --zw-orange-700: #c25806;
  --zw-orange-500: #fa760a;
  --zw-orange-300: #fdb972;
  --zw-orange-100: #ffdfc2;
  --zw-orange-50:  #fff2e5;

  --zw-ink:     #0f1a26;
  --zw-ink-2:   #2a3947;
  --zw-ink-3:   #566676;
  --zw-line:    #d9e0e8;
  --zw-line-2:  #eceff3;
  --zw-surface: #ffffff;
  --zw-surface-2: #f7f9fb;
  --zw-surface-3: #eef2f6;
  --zw-paper:   #fbfaf6;

  --zw-sun:  #ffb547;
  --zw-clay: #d97757;
  --zw-sky:  #7ac8e0;
  --zw-moss: #557a44;

  /* The kit's petition signature bar (Tools.dc.html:339-340), which is deliberately
     NOT green. A reduction ladder measures something achieved; a signature count
     measures a shortfall against a deadline, and the kit paints that as urgency. Named
     by role rather than hue, like --zw-tool-* and --zw-pin-*, so the pairing stays
     legible at the point of use. */
  --zw-advocacy:       #9e453c;
  --zw-advocacy-track: #f4ece9;

  /* ---- Design System 3.0 additions ----------------------------------------
     Ported from the kit's tokens/colors.css. Declared here so later phase-1 PRs
     (the homepage, the four tool surfaces, the challenge category colours) have a
     palette to draw on rather than inventing hex.

     3.0 gives each colour exactly one job, and breaking that is what makes the
     system stop working:
       blue       acts   — buttons, links, focus. Nothing decorative is blue.
       green      measures — the reduction ladder, progress, impact. Never a button.
       dark green is the ground the page sits on. A substrate, not a section colour.
       warm paper + hairlines do structure. Never colour blocks.
       mint       is the logo, plus the 2027 goal bar. Nowhere else. */

  /* Warm grounds. 3.0's paper is warmer than the 2.x --zw-paper above. */
  --zw-paper-3:      #fdfcfa; /* page background */
  --zw-surface-warm: #fbfaf7; /* row hover, quiet fills */
  --zw-panel:        #f7f5f1; /* the panel the tool cards bouquet out of */

  /* The dark green ground beneath the page. */
  --zw-base:       #1b3b31;
  --zw-base-panel: #16332a;
  --zw-base-line:  #2a5044;
  --zw-base-quiet: #7fa494;
  --zw-base-body:  #b7cfc4;
  --zw-base-link:  #dcebe4;

  /* Warm hairlines — never grey-blue. */
  --zw-border-warm:       #ece9e3; /* section rules, sticky header */
  --zw-border-warm-2:     #e2ded6; /* card borders */
  --zw-border-warm-soft:  #eae6df; /* borders sitting under a shadow */
  --zw-border-warm-inner: #f1eee8; /* dividers inside a card */
  --zw-border-warm-grid:  #f4f2ee; /* calendar cells, faintest rule */
  /* The darkest of the warm borders, and the only one used on an INTERACTIVE outline: the
     kit draws an unchecked tick box at 1.5px of this (Tools.dc.html:2267). The rules above
     are for structure, where a hairline is the point; an outline a person has to find and
     click needs to be visibly darker than the card it sits on. See the note in
     checkbox_contrast_test.rb about this still being under WCAG 1.4.11. */
  --zw-border-warm-strong: #d5d0c7;

  /* Mint. The logo and the 2027 goal bar. Nowhere else. */
  --zw-mint: #00cc99;

  /* 3.0's quiet neutrals, for the greys that are not ink: eyebrow labels, unselected
     segments, disabled numerals. These are warm, while --zw-ink/-2/-3 above are the
     2.x cool navies and are left alone — repointing ink is an app-wide repaint, not a
     component change. So a 3.0 component can read warm-grey beside cool-ink body
     copy until that pass happens. */
  --zw-muted:   #6b6b70;
  --zw-faint:   #8b8880; /* unselected segment, neutral tag */
  --zw-quiet:   #9a978f; /* eyebrows */
  --zw-whisper: #c3bfb6; /* ladder numerals, disabled */

  /* 3.0's ink ramp, for the warm body copy that belongs beside the warm greys above.
     The kit calls these --zw-ink / -2 / -3, which are taken here by the 2.x cool
     navies. DO NOT repoint those to these values as a tidy-up: --zw-ink is reached
     through --fg-1 and is read across the whole app and admin, so collapsing the two
     ramps is an app-wide repaint and belongs in its own change. Until then a 3.0 page
     opts into warm ink explicitly. */
  --zw-ink-warm:   #1c1c1e; /* headlines, the serif */
  --zw-ink-warm-2: #2b2b2f; /* the founders' letter */
  --zw-ink-warm-3: #4a4a50; /* hero subhead, panel body */

  /* The five Rs ladder. Green measures; this is the ramp it measures on. */
  --zw-ladder-1: #2f7a63;  --zw-ladder-1-ink: #ffffff;
  --zw-ladder-2: #4e9a80;  --zw-ladder-2-ink: #ffffff;
  --zw-ladder-3: #a8ccbc;  --zw-ladder-3-ink: #1c1c1e;
  --zw-ladder-4: #e6d3a4;  --zw-ladder-4-ink: #1c1c1e;
  --zw-ladder-5: #fdfcfa;  --zw-ladder-5-ink: #8b8880;

  /* Sand — ladder step 4, the one surviving warm accent. */
  --zw-sand:      #d9cfae;
  --zw-sand-ink:  #4a4230;
  --zw-sand-tint: #faf1e2; /* the sand tag's ground */

  /* The four tools, each a muted stroke on its own soft tint. These recur wherever
     that tool's content appears, so they are identity, not decoration. Never darken a
     stroke to fix a contrast problem — use the -ink companion below.

     STROKES: icons, borders, dots. Decorative or large, so 3:1 is the bar. */
  --zw-tool-actions:  #7d6a9c;  --zw-tool-actions-tint:  #f1eef7;
  --zw-tool-calendar: #a68a3f;  --zw-tool-calendar-tint: #f8f2e3;
  --zw-tool-map:      #5d8a72;  --zw-tool-map-tint:      #eef4f0;
  --zw-tool-wiki:     #5c7d9e;  --zw-tool-wiki-tint:     #eff3f7;

  /* INKS: text sitting on the matching tint, as in a tag. The strokes above do not
     reach 4.5:1 on their own tints at 14px (map 3.54:1, wiki 3.89:1, actions 4.17:1),
     so text uses these instead. The kit already made exactly this distinction for the
     calendar tool via --zw-tool-clay; these three extend the pattern.

     test/assets/component_tone_contrast_test.rb pins every pair. */
  --zw-tool-actions-ink: #74628f;
  /* THE WIKI's topic palette. Topics are admin-CRUD and can be added on the
     fly; the colours they draw from are not, so a topic created in a hurry
     cannot introduce an off-brand hue. tone_key on wiki_topics selects one of
     these by name, which is also why no hex reaches the database.
     The first six are the 3.0 kit's own topic tones (Tools.dc.html:2013). */
  --zw-wiki-topic-kitchen:  #2f7a63; /* = --zw-green-600 */
  --zw-wiki-topic-clothes:  #a68a3f; /* = --zw-tool-calendar */
  --zw-wiki-topic-repair:   #5c7d9e; /* = --zw-tool-wiki */
  --zw-wiki-topic-buying:   #7d6a9c; /* = --zw-tool-actions */
  --zw-wiki-topic-curbside: #5d8a72; /* = --zw-tool-map */
  --zw-wiki-topic-hosting:  #b5544a; /* kit's Hosting clay */
  --zw-wiki-topic-basics:   #4a6b8a; /* = --zw-pin-slate, the map's muted blue */
  --zw-wiki-topic-bigger:   #8a7033; /* = --zw-pin-ochre */

  /* Past its review date. Amber rather than red: an entry that needs checking
     is not an error, and the kit is careful about that distinction. */
  --zw-wiki-warn:        #c99a3f;
  --zw-wiki-warn-ink:    #6b4f1f; /* on the tint at 12-14px, so it must clear AA */
  --zw-wiki-warn-tint:   #fdf6ee;
  --zw-wiki-warn-border: #ecd9c2;

  /* A wikilink pointing at an entry nobody has written yet. Distinct from a
     resolving link on purpose — the kit reads it as an invitation. */
  --zw-wiki-missing:           #9e453c;
  --zw-wiki-missing-underline: #ddc4c0;

  --zw-tool-clay:        #7a6a41; /* text on the ochre tint — the kit's own name */
  --zw-tool-map-ink:     #4d7460;
  --zw-tool-wiki-ink:    #52708d;

  /* Map pin tones, from the 3.0 kit's `kinds` table in Tools.dc.html.
     3.0's map is deliberately quiet: every pin is a muted earth, green, slate or
     purple, and there is no red or orange anywhere on it. The 2.x pin set reached for
     saturated hues to tell categories apart, including the ACTION BLUE for Repair —
     which breaks 3.0's one rule about blue, since a pin is not something you click.

     Each carries a white glyph, so each clears 3:1 against white.
     test/assets/map_pin_colours_test.rb pins that, and that no two collide. */
  --zw-pin-slate:  #4a6b8a; /* kit Repair */
  --zw-pin-ochre:  #8a7033; /* kit Secondhand / Donate */
  --zw-pin-moss:   #4a7a62; /* kit Recycle */
  --zw-pin-violet: #6a5788; /* kit Borrow / Hazardous */

  /* 3.0's display face. Applied only where the kit allows — see the webfont note
     at the top of this file. "Petrona Fallback" is Georgia scaled to Petrona's
     width, so a late swap does not move the text. */
  --zw-font-serif: Petrona, "Petrona Fallback", "Petrona Fallback Serif", Georgia, serif;

  /* ---- Chart series -------------------------------------------------------
     A small categorical palette, declared here rather than inside any one chart,
     because a chart drawn in JS and a legend rendered in ERB describe the same
     series and must not be able to disagree. Both read these.

     Ordered by emphasis, not by hue: series 1 is the subject of the chart, 2 the
     comparison, 3 a reference or projection. Green first honours 3.0's rule that
     green measures — a chart is measurement, which is exactly its job. Blue appears
     here as data rather than decoration; nothing in a chart is clickable. */
  --zw-series-1: var(--zw-green-800);
  --zw-series-2: var(--zw-blue-700);
  --zw-series-3: var(--zw-ink-3);

  /* Area fill under series 1. Stated as an explicit rgba rather than derived from
     --zw-series-1, because Chart.js needs a resolved colour string and colour-mix()
     resolution through getComputedStyle is not dependable across browsers. Keep the
     rgb in step with --zw-green-800 (#1f5a49). */
  --zw-series-1-fill: rgba(31, 90, 73, 0.07);

  /* Chart chrome. Axis labels want to be readable but quiet; gridlines want to be
     nearly invisible — 3.0 does structure with hairlines, not colour blocks. */
  --zw-chart-axis: var(--zw-ink-3);
  --zw-chart-grid: rgba(15, 26, 38, 0.08);

  /* ---- Avatar palette ------------------------------------------------------
     Six hues for identity chips, where the only requirement is that adjacent
     avatars are told apart. Assigned by index, so nothing here carries meaning and
     none of it should be read as status.

     Drawn from the ramps and 3.0's muted tool colours rather than the saturated
     one-offs these replace (#00b386, #3b82c4, #e08a3c, #d1587e, #7c5cbf), which sat
     outside the palette and could not follow a rebrand. Ordered so neighbours in
     the rotation differ in hue rather than only in lightness. */
  --zw-avatar-1: var(--zw-green-700);
  --zw-avatar-2: var(--zw-tool-wiki);
  --zw-avatar-3: var(--zw-tool-calendar);
  --zw-avatar-4: var(--zw-red-500);
  --zw-avatar-5: var(--zw-tool-actions);
  --zw-avatar-6: var(--zw-moss);

  --zw-success: var(--zw-green-700);
  /* Brand Jonquil. This is a FILL, not a text colour: 1.52:1 on white. Anything
     textual — a label sitting on the fill, or warning-coloured copy — uses
     --zw-warning-ink (5.94:1 on white, 3.9:1 on the fill). For small text on the
     fill, go darker still with --zw-ink (11.5:1). */
  --zw-warning: var(--zw-yellow-500);
  --zw-warning-ink: var(--zw-yellow-900);
  --zw-danger:  #d64545;
  --zw-info:    var(--zw-blue-700);

  --fg-1: var(--zw-ink);
  --fg-2: var(--zw-ink-2);
  --fg-3: var(--zw-ink-3);
  --fg-on-brand: #ffffff;

  --bg-1: var(--zw-surface);
  --bg-2: var(--zw-surface-2);
  --bg-3: var(--zw-surface-3);

  --border-1: var(--zw-line);
  --border-2: var(--zw-line-2);
  --border-strong: var(--zw-blue-700);

  --link: var(--zw-blue-700);
  --link-hover: var(--zw-blue-800);

  /* Every token below is --zw-* prefixed, and that is load-bearing rather than
     stylistic. This file is linked unlayered; Tailwind v4 compiles its theme into
     `@layer theme`, and unlayered declarations beat layered ones regardless of
     source order. So a bare --font-*, --shadow-*, --ease-*, --radius-* or --text-*
     here silently rewrites the matching Tailwind utility across the whole app.

     That already happened twice: --radius-* inflated every rounded-* into a pill,
     and --shadow-sm / --shadow-md / --ease-out were quietly redefining 724 utility
     usages. Where we genuinely want to change a Tailwind utility, it is declared in
     app/assets/tailwind/application.css's @theme block instead.

     test/assets/token_namespace_test.rb enforces this. */
  --zw-font-display: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --zw-font-sans:    system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --zw-font-mono:    "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;

  /* Not a Tailwind namespace — Tailwind uses --spacing-*. Left unprefixed. */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 64px;

  /* The kit's structural measures, from tokens/spacing.css. Three column widths,
     not one, because 3.0 sizes a page by what it holds:

       measure       reading and marketing pages
       measure-app   the tool shell's own chrome — nav bar, footer
       measure-tool  a tool's working surface, which is wider than its chrome
       measure-prose an article column

     measure-tool is not in tokens/spacing.css. The 3.0 kit sets it inline on every
     tool screen in Tools.dc.html (`max-width:1440px`) while keeping the nav and
     footer at 1100, so the numeral exists in the kit but never got a name. It gets
     one here rather than being hardcoded in each tool as it is built.

     header-h is what makes the map's full-height shell expressible: the kit writes
     that height as `calc(100vh - 210px)`, a magic number that is really the header
     plus the page's top padding plus the filter row. */
  --zw-measure:        960px;
  --zw-measure-app:   1100px;
  --zw-measure-tool:  1440px;
  --zw-measure-prose:  560px;
  --zw-gutter:          28px;
  --zw-section-y:       80px;
  --zw-header-h:        60px;

  /* Radii, aligned to the 3.0 kit's shape.css so translating a component from the
     kit is a name swap rather than a judgement call. Two steps moved to get there:
     sm 8px -> 10px (the kit's button radius, which ButtonComponent previously
     hardcoded as rounded-[10px]) and lg 18px -> 14px (input shells). */
  --zw-radius-xs:   4px;
  --zw-radius-sm:  10px;  /* buttons */
  --zw-radius-md:  12px;
  --zw-radius-lg:  14px;  /* input shells */
  --zw-radius-xl:  16px;  /* cards */
  --zw-radius-2xl: 24px;  /* the tools panel */
  --zw-radius-page: 26px; /* page bottom corners over the dark base */
  --zw-radius-pill: 999px;

  --zw-shadow-xs: 0 1px 0 rgba(15,26,38,0.04);
  --zw-shadow-sm: 0 1px 2px rgba(15,26,38,0.06), 0 1px 3px rgba(15,26,38,0.04);
  --zw-shadow-md: 0 4px 12px rgba(15,26,38,0.08), 0 2px 4px rgba(15,26,38,0.04);
  --zw-shadow-ring: 0 0 0 3px rgba(51,102,153,0.25);

  /* 3.0's depth ladder, ported from the kit's shape.css. Warmer and shallower than
     the --zw-shadow-xs/sm/md trio above, which stays because ~724 Tailwind utility
     usages resolve through it via the @theme block. */
  --zw-shadow-hairline: 0 1px 2px rgba(28, 28, 30, 0.04);
  --zw-shadow-card:     0 2px 6px rgba(28, 28, 30, 0.05);
  --zw-shadow-float:    0 10px 28px rgba(28, 28, 30, 0.09), 0 2px 6px rgba(28, 28, 30, 0.05);
  --zw-shadow-dock:     0 6px 18px rgba(28, 28, 30, 0.10), 0 1px 3px rgba(28, 28, 30, 0.05);
  --zw-shadow-lift:     0 20px 44px rgba(28, 28, 30, 0.14);
  --zw-shadow-page:     0 14px 28px rgba(28, 28, 30, 0.16);

  --zw-ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --dur-1: 120ms; --dur-2: 200ms; --dur-3: 320ms;

  /* The eyebrow's type, the one place 3.0 fixes a size and tracking together. 13px
     rather than Tailwind's text-xs (12px), so it needs its own token. */
  --zw-text-xs: 13px;
  --zw-tracking-eyebrow: 0.06em;
}
