/* Hallmark · design-system: design.md · designed-as-app · studied: yes
 * DNA-source: image (Placify, 4 screens)
 *
 * The system's source of truth. build.mjs concatenates this ahead of
 * styles.css into one hashed stylesheet, so there is exactly one definition of
 * every colour and one HTTP request.
 *
 * The governing rule, from design.md: THE CHROME CARRIES NO COLOUR; THE CONTENT
 * DOES. The map supplies every hue on screen. Everything around it is paper,
 * ink, and a few small semantic marks. A tinted panel is a bug in this system.
 */

:root {
  /* ── Paper · neutral-cool, three steps. Elevation is lightness, never an
        outline: a hairline on near-black is either invisible or a grey box. */
  --color-paper:      oklch(97.2% 0.006 250);
  --color-paper-2:    oklch(99.2% 0.005 250);
  --color-paper-3:    oklch(94.0% 0.008 250);
  --color-ink:        oklch(21.0% 0.012 250);
  --color-ink-2:      oklch(50.0% 0.008 250);
  --color-rule:       oklch(89.0% 0.008 250);

  /* Reserved. Under 5% of any screen — the cheapest price and nothing else. */
  --color-accent:     oklch(62.0% 0.13 85);
  --color-accent-ink: oklch(99.0% 0.006 85);
  --color-focus:      oklch(55.0% 0.15 250);

  /* ── The studied move: category colour is a SET that means something, not one
        brand accent. Mapped onto the price terciles. app.js reads these at
        runtime through getComputedStyle, so the map and the list cannot
        disagree about what "cheap" looks like. */
  /* VIVID FILLS IN BOTH THEMES. They were dark-and-muted in light, raised chroma
     as far as white text allowed, and still read washed out — because the
     constraint was the problem: at 4.5:1 against white the amber tops out around
     #9b6f0c, which is brown. There is no vivid amber on that side of the line,
     so the fills were freed from carrying legible white text at all.

     THE TEXT ON THEM IS NEVERTHELESS WHITE IN LIGHT MODE, by the owner's
     decision and below AA — see --color-on-tier. Keep that trade in view before
     touching these values: they are light BECAUSE the constraint was dropped, so
     darkening them to rescue the white text walks straight back into the muted
     scheme that was reverted.

     Separation from a light basemap comes from the cut-out ring and --shadow-pin,
     not from the fill being dark. */
  --color-tier-cheap: oklch(74.0% 0.18 150);
  --color-tier-mid:   oklch(80.0% 0.16 80);
  --color-tier-dear:  oklch(66.0% 0.20 25);
  --color-tier-none:  oklch(60.0% 0.010 250);

  /* THE SAME SEMANTIC SET, AS TEXT ON PAPER. A fill and a letterform are not the
     same contrast problem, and in light mode they pull in opposite directions:
     a fill wants to be light so dark text can sit on it, text wants to be dark
     so it can sit on light paper. One value cannot do both.

     Inverting the fills to vivid-with-dark-text solved the marker and silently
     broke every place a tier is INK — "1.60 with AVIA" under the pump price fell
     to 2.10:1 and the stale age to 3.34:1, against a 4.5 requirement, on 54 and
     132 rows of a single screen. The fills above are untouched; these are what
     the -text aliases resolve to.

     Solved against --color-paper-3, the darkest light surface any of them runs
     on, so the card (paper-2) and the sheet get more than they need: 5.01 / 5.02
     / 5.00 on the chip, 5.84 / 5.84 / 5.83 on a card. All in sRGB gamut.

     Dark needs no second value — measured, its fills already clear 8.57 / 7.42 /
     4.86 as text on the darkest dark surface, so they alias straight through.
     That asymmetry is the whole point: only one theme has the conflict. */
  --color-tier-cheap-text: oklch(48.7% 0.130 150);  /* #0b7334 */
  --color-tier-mid-text:   oklch(50.4% 0.100 80);   /* #825d0c */
  --color-tier-dear-text:  oklch(52.6% 0.200 25);   /* #c41a27 */
  --color-gps:        oklch(55.0% 0.15 250);
  /* WHITE, BY THE OWNER'S DECISION, AND IT DOES NOT MEET AA. Recorded so nobody
     "fixes" it back as a bug.

     The fills above are light, so white on them measures 2.15 / 1.90 / 3.42
     against the 4.5 that 13px text wants. Dark text on the same fills measures
     8.41 / 9.52 / 5.29. The alternatives were both shown and both rejected:
     white on these fills IS this, and white at 4.5:1 needs the fills dropped to
     roughly 55% lightness, which turns the amber brown (#9b6f0c) and is the
     muted scheme that was reverted earlier for reading washed out.

     So this is a deliberate trade of measured contrast for the colour the owner
     wants on the map, made with the numbers on the table. If it is ever revisited,
     the lever is the FILL, not this value — there is no white that passes on a
     74-80% lightness fill.

     Dark keeps dark text: its fills are light too, and white there is 1.76-2.03,
     worse than here.

     Anything that sits on INK rather than on a tier must use --color-paper
     instead; three rules used to read this token and only worked because it
     happened to equal paper. */
  --color-on-tier:    oklch(100% 0 0);

  /* The tile colour the page background must equal in map view. Measured, not
     chosen: standard OSM land is #f2efe8; CARTO dark_all is #090909 across 66%
     of its pixels. Named so the ground and the tiles cannot drift apart. */
  --color-map-land:   #f2efe8;

  /* ── Type. Display is for titles and moments only — the wordmark, an empty
        state. EVERY figure is body, tabular: the source sets its large data
        numerals in the grotesque, not the serif. */
  --font-display: "Instrument Serif", Georgia, serif;
  --font-body:    Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono:    ui-monospace, SFMono-Regular, Menlo, monospace;

  /* No --space-* scale, and that is the decision rather than an omission.
     Nine tokens were defined here and referenced ZERO times in the whole
     project, so the file claimed a system it did not run — the tokens were the
     lie, not the literals. Spacing is literal on purpose: the values in use are
     already on the 4-pt grid, and the ones that are not are 1-3px optical
     nudges that must survive. An automated snapper once rounded thirteen of
     them to zero, which is the regression this note exists to prevent.
     See design.md § Geometry. */

  /* ── Type scale, 1.25 major third */
  --text-2xs: 0.625rem; --text-xs: 0.75rem;  --text-sm: 0.8125rem;
  --text-md:  0.9375rem; --text-lg: 1.125rem; --text-xl: 1.375rem;
  --text-2xl: 1.75rem;  --text-3xl: 2.25rem;
  /* The price is sized to the ROW, not to the viewport. A row's left column is
     the station name over a two-line address — three lines, 52px — and the right
     column has to match it: the "CHF" eyebrow, the number, and the age. Solved
     against that, the number lands on --text-xl. The old clamp scaled on vw and
     so overshot by 10px at 390px and more on desktop, where 6.5vw pinned it to
     the 34px ceiling and the right column ran well past the left.

     Change this and re-measure both columns; it is not a free knob. */
  --text-price: var(--text-xl);

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 180ms; --dur-base: 240ms; --dur-slow: 320ms;

  --radius-card: 16px; --radius-pill: 999px; --radius-input: 14px;
  --radius-sheet: 28px; --radius-tile: 12px;

  /* Shadows carry the paper's hue. A neutral black shadow on a tinted surface
     is the tell that a palette was picked but never looked at. */
  --shadow-card: 0 1px 2px oklch(21% 0.008 250 / .05),
                 0 2px 8px oklch(21% 0.008 250 / .06);
  --shadow-float: 0 2px 6px oklch(21% 0.008 250 / .10),
                  0 10px 28px oklch(21% 0.008 250 / .12);
  /* Markers and the small buttons that sit directly on the map. --shadow-float
     is 28px of blur, which on a 32px pin is a smudge, not an elevation. */
  --shadow-pin:   0 1px 4px oklch(21% 0.008 250 / .22);
}

[data-theme="dark"] {
  --color-paper:      oklch(15.5% 0.006 250);
  --color-paper-2:    oklch(21.5% 0.006 250);
  --color-paper-3:    oklch(27.0% 0.006 250);
  --color-ink:        oklch(97.0% 0.006 250);
  --color-ink-2:      oklch(68.0% 0.008 250);
  --color-rule:       oklch(30.0% 0.006 250);

  --color-accent:     oklch(82.0% 0.14 85);
  --color-accent-ink: oklch(20.0% 0.02 85);
  --color-focus:      oklch(72.0% 0.14 250);

  --color-tier-cheap: oklch(80.0% 0.15 160);
  --color-tier-mid:   oklch(78.0% 0.11 75);
  --color-tier-dear:  oklch(68.0% 0.16 25);
  --color-tier-none:  oklch(68.0% 0.008 250);

  /* No separate value: on a dark sheet a bright fill is already readable ink.
     Measured against --color-paper-3, the darkest dark surface these run on —
     8.57, 7.42, 4.86. Defined rather than left to fall through to :root, which
     would leak the light theme's dark greens onto a dark card. */
  --color-tier-cheap-text: var(--color-tier-cheap);
  --color-tier-mid-text:   var(--color-tier-mid);
  --color-tier-dear-text:  var(--color-tier-dear);
  --color-gps:        oklch(72.0% 0.14 250);
  --color-on-tier:    oklch(16.0% 0.008 250);

  --color-map-land:   #090909;

  --shadow-card: none;
  --shadow-float: 0 2px 8px oklch(0% 0 0 / .5), 0 14px 34px oklch(0% 0 0 / .55);
  /* None, and not an oversight. A 22%-black shadow on a #090909 map paints
     nothing — it was costing a blur per marker, 150 of them, to render
     invisibly. The ring separates the pin from the tiles here. */
  --shadow-pin:   none;
}
