/*
 * Halvard Plow & Ice — design tokens. Every colour, font, size, weight, leading,
 * space, duration, easing, scale, filter and breakpoint on the concept site lives
 * here; site.css and site.js only reference them (JS reads with getComputedStyle,
 * never with a literal fallback). Prefix: --s-. One definition per property.
 *
 * Palette "wet blacktop + plow orange + salt white" (art director, pass 1, 2026-10-02).
 * The page is a NIGHT SHIFT that turns to DAY at 05:00: the night half uses the
 * --s-night-* roles, the day half the --s-day-* roles. The theme change is a class
 * toggle in site.css that picks one set or the other, transitioned with
 * --s-dur-theme. Never a tween of a custom property.
 *
 * Distinctness, CIEDE2000 (art/halvard-plow/tools/delta_e.py: every --s-* colour of
 * the 14 finished sites; re-run 2026-10-02 against all 17 sites incl. this round):
 *   blacktop #0c2227 vs Nightweave #07080f 11.2 · Vantrell #13110f 11.4 · Ashgrove night #0c0d0f 10.3
 *                    nearest: Solenne night-deep #072a36 4.4 · Saltmere deep #1c2427 5.1 · Morrow ink #13201a 7.2
 *   plow orange #ff8400 (municipal safety orange; moved from #ff5414, which was 6.9 from Ashgrove pen-night #ff5a40)
 *                    vs Halberd amber #f2a900 14.9 · nearest Morrow ember #e0743a 10.3 · Morrow ember-hot 13.7
 *   salt white #f6f7f4 vs Ashgrove paper-light #eef2f5 3.3 · nearest Saltmere mineral #eef0ee 1.6
 *   No neutral near-black or near-white can reach 10 against all 14 sites (searched; see PAIR-NOTES).
 *
 * Contrast (WCAG 2.x, measured 2026-10-02, tools/contrast.py):
 *   salt on blacktop 15.33 · blacktop on salt 15.33 · brine on blacktop 7.14 · brine on raised 6.04
 *   blacktop ink on plow orange 6.71 (button label) · ink on pressed orange 7.78 · ink on sodium 9.25
 *   plow orange on blacktop 6.71 (focus ring, needle) · plow orange on salt 2.28: NEVER a
 *   ring or text on day grounds; the day focus ring is blacktop (15.33).
 *   brine FAILS on photographs (2.8–4.0): text on a photo is always salt white.
 *   ORANGE NEVER CARRIES BODY TEXT ON SALT WHITE.
 */

/* Sofia Sans Extra Condensed (wght 1–1000), Public Sans (wght 100–900), Martian Mono (wght 100–800).
 * SIL OFL 1.1, latin subset, woff2. Source + hashes in BRIEF.md; licence texts beside the files. */
@font-face {
    font-family: "HP Sofia XC";
    src: url("fonts/sofia-sans-extra-condensed-latin-wght-normal.woff2") format("woff2-variations"), url("fonts/sofia-sans-extra-condensed-latin-wght-normal.woff2") format("woff2");
    font-weight: 1 1000;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "HP Public";
    src: url("fonts/public-sans-latin-wght-normal.woff2") format("woff2-variations"), url("fonts/public-sans-latin-wght-normal.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "HP Martian";
    src: url("fonts/martian-mono-latin-wght-normal.woff2") format("woff2-variations"), url("fonts/martian-mono-latin-wght-normal.woff2") format("woff2");
    font-weight: 100 800;
    font-style: normal;
    font-display: swap;
}

:root {
    /* ---- colour: palette (the source) ---------------------------------- */
    --s-blacktop: #0c2227;          /* wet blacktop — night field, day text */
    --s-blacktop-raised: #133037;   /* console rows, panels on the night field (salt 12.97, brine 6.04) */
    --s-blacktop-deep: #071519;     /* footer, under-photo wells at night */
    --s-salt: #f6f7f4;              /* salt white — day field, night text */
    --s-salt-shade: #e9ece8;        /* zebra / column neighbour on day (blacktop 13.84, day-muted 4.89) */
    --s-plow: #ff8400;              /* plow orange — button fill, recommended band, closing field, ruler needle */
    --s-spec-label-w: 18%;          /* contracts table: row labels */
    --s-spec-rec-w: 38%;            /* contracts table: the focal (recommended) column */
    --s-plow-press: #ff9a2e;        /* :active fill — lighter, so the ink stays legible (7.78) */
    --s-sodium: #ffb25e;            /* night glow + small data labels on blacktop only (ticker label 6.3 measured on the 390 scrim; never on salt) */
    --s-brine: #a3acb1;             /* secondary text on SOLID blacktop only (7.14) */
    --s-ice: #cfd8dc;               /* hairlines on day (decorative, 1.35) */
    --s-day-muted: #5b676d;         /* secondary text on salt (5.42), on white (5.82) */
    --s-error-night: #ffb39a;       /* form errors on blacktop (9.55) */
    --s-error-day: #a32a00;         /* form errors on salt (6.76) and on the ticket (7.27) */

    /* ---- colour: roles, night ------------------------------------------ */
    --s-night-field: #0c2227;
    --s-night-text: #f6f7f4;
    --s-night-muted: #a3acb1;
    --s-night-rule: #f6f7f426;      /* hairlines on blacktop */
    --s-night-rule-strong: #f6f7f45c;
    --s-night-console: #0c2227f0;   /* 94% blacktop: the dispatch console strip */
    --s-night-focus: #ff8400;       /* 6.71 on blacktop */

    /* ---- colour: roles, day -------------------------------------------- */
    --s-day-field: #f6f7f4;
    --s-day-text: #0c2227;
    --s-day-rule: #cfd8dc;
    --s-day-rule-strong: #0c22274d;
    --s-day-focus: #0c2227;         /* 15.33 on salt — orange fails there */

    /* ---- colour: buttons ------------------------------------------------ */
    --s-btn-bg: #ff8400;
    --s-btn-ink: #0c2227;           /* 6.71 on plow */
    --s-btn-ghost-ink-night: #f6f7f4;
    --s-btn-ghost-ink-day: #0c2227;

    /* ---- colour: closing (night field + white ticket + dispatch readout) --
       Engineer pass 5 (r5 review): the page no longer closes on a saturated orange field holding a light
       form (Pellmarsh's move). The work order ends where the page began, on the night field beside a
       dispatch readout; orange is kept to the ticket's tear strip and the submit button. */
    --s-close-field: #0c2227;       /* = night field */
    --s-close-ink: #f6f7f4;         /* salt on blacktop: 15.33 */
    --s-close-muted: #a3acb1;       /* readout labels + pending values on blacktop: 7.14 */
    --s-close-rule: #f6f7f426;
    --s-close-rule-strong: #f6f7f45c;
    --s-ticket-strip: #ff8400;      /* the tear strip: plow orange, decorative only (never carries text) */
    --s-ticket: #ffffff;
    --s-ticket-ink: #0c2227;
    --s-ticket-muted: #5b676d;      /* 5.82 on white */
    --s-ticket-line: #0c22274d;     /* underlined field lines */
    --s-ticket-line-focus: #0c2227;
    --s-chip-on-bg: #0c2227;        /* selected chip: blacktop with salt text */
    --s-chip-on-ink: #f6f7f4;

    /* ---- colour: photography support ------------------------------------ */
    --s-photo-well-night: #0a1c20;  /* behind a night photo while it decodes */
    --s-photo-well-day: #dfe4e2;
    --s-hero-scrim: linear-gradient(to bottom, #0c222700 45%, #0c2227eb 100%);      /* desktop hero: 8.3–8.6 measured under the copy */
    --s-hero-scrim-m: linear-gradient(to bottom, #0c222700 50%, #0c2227d9 72%, #0c2227f5 84%);    /* phone hero: holds the fog spray under the ticker (AD pass 2, re-measured) */
    --s-hero-sky-veil-m: linear-gradient(to bottom, #0c222759 0%, #0c222700 46%);  /* phone: deepens the sky behind the headline (7.15 already without it) */
    --s-panel-scrim: #0c2227e6;     /* solid log/caption panel over a photo */

    /* ---- type ------------------------------------------------------------ */
    --s-font-display: "HP Sofia XC", "Arial Narrow", sans-serif;
    --s-font-body: "HP Public", "Helvetica Neue", Arial, sans-serif;
    --s-font-data: "HP Martian", Menlo, monospace;      /* DATA ONLY: clock, console, ruler, logs, ticket labels */
    --s-weight-display: 900;        /* Black, uppercase: hero, closing */
    --s-weight-display-2: 800;      /* index words, H2 */
    --s-weight-body: 400;
    --s-weight-label: 600;
    --s-weight-data: 400;
    --s-weight-data-strong: 600;
    --s-figures-data: "tnum" 1, "zero" 1;
    --s-figures-body: "tnum" 1, "lnum" 1;

    --s-step-hero: clamp(4.75rem, 1.6rem + 10.2vw, 11rem);        /* 76px @390 → 176px @1440 */
    --s-step-index: clamp(3.25rem, 1.1rem + 6.6vw, 7rem);         /* property index words: 52 → 112px */
    --s-step-h2: clamp(2.5rem, 1.2rem + 4.2vw, 5rem);
    --s-step-h3: clamp(1.375rem, 1.15rem + 0.8vw, 1.875rem);
    --s-step-close: clamp(3rem, 1.4rem + 5.4vw, 6.5rem);          /* GET ON THE ROUTE */
    --s-step-h2-sm: clamp(2rem, 1.4rem + 1.6vw, 2.75rem);   /* the focal plan name in the contracts table */
    --s-step-lede: clamp(1.125rem, 1.02rem + 0.45vw, 1.375rem);
    --s-step-body: clamp(1.0625rem, 1.02rem + 0.18vw, 1.125rem);  /* 17 → 18px */
    --s-step-label: 0.875rem;
    --s-step-small: 0.8125rem;
    --s-step-data: clamp(0.75rem, 0.72rem + 0.12vw, 0.8125rem);   /* mono rows: 12 → 13px */
    --s-step-data-lg: clamp(1rem, 0.9rem + 0.5vw, 1.375rem);      /* clock hours on the rail */
    --s-step-ruler: clamp(2rem, 1.2rem + 1.4vw, 2.75rem);        /* depth readout (steps, never counts); engineer: sized to the 108px ruler column so '3.5' never crosses into the photo */
    --s-step-ticker: 0.75rem;
    --s-step-logo: 1.5rem;

    --s-leading-hero: 0.84;
    --s-leading-display: 0.9;
    --s-leading-body: 1.55;
    --s-leading-tight: 1.25;
    --s-leading-data: 1.5;
    --s-track-hero: -0.012em;
    --s-track-display: -0.006em;
    --s-track-label: 0.04em;
    --s-track-logo: 0.06em;
    --s-measure-body: 34em;
    --s-measure-lede: 30em;
    --s-measure-log: 26em;

    /* ---- button: the BLADE PARALLELOGRAM (both ends slanted ~12°, text upright) */
    --s-btn-h: 56px;
    --s-btn-h-s: 48px;
    --s-btn-pad-x: 34px;
    --s-btn-slant: 12px;            /* each slanted end's horizontal offset: tan(12°) × 56px ≈ 12px */
    --s-btn-clip: polygon(var(--s-btn-slant) 0, 100% 0, calc(100% - var(--s-btn-slant)) 100%, 0 100%);
    /* The focus ring must NOT be clipped: put --s-btn-clip on an inner span, the outline on the <a>/<button>. */
    --s-focus-w: 3px;
    --s-focus-offset: 4px;

    /* ---- space ----------------------------------------------------------- */
    --s-space-1: 4px;
    --s-space-2: 8px;
    --s-space-3: 12px;
    --s-space-4: 16px;
    --s-space-5: 24px;
    --s-space-6: 32px;
    --s-space-7: 48px;
    --s-space-8: 64px;
    --s-space-9: 96px;
    --s-space-10: 144px;
    --s-gutter: clamp(16px, 4vw, 56px);
    --s-section: clamp(72px, 10vw, 160px);
    --s-ticket-tuck: 28px;  /* desktop: the work order ticket's torn top rides this far over the town photo (below the town panel's 64px foot) */
    --s-section-foot: clamp(48px, 5vw, 80px); /* every section's foot: content ends, one step, the next band (r5: 144px feet read as dead bands) */
    --s-max: 1320px;
    --s-console-w: 360px;           /* the hero dispatch strip */
    --s-ticket-w: 760px;            /* the closing work order (phone/tablet: centred, capped) */
    --s-order-split: minmax(0, 2fr) minmax(0, 3fr); /* desktop: ticket pinned left at 40%, readout on the right */
    --s-order-split-mid: minmax(0, 1fr) minmax(0, 1fr); /* 1024–1279: half and half, so the ticket's head and stepper keep their lines */
    --s-order-gap: clamp(48px, 6vw, 112px);
    --s-ticket-perf: 22px;          /* perforation pitch on the ticket's top edge (engineer: 10px left no gap between 12px holes) */
    --s-touch-min: 44px;
    --s-touch-index-m: 56px;        /* property accordion rows on phone */

    /* ---- art direction: desktop stage focal points (AD pass 2) ----------------
       The pinned stage shows each 16:9 frame in a ~1.26:1 region with the log panel
       bottom-left (3–63% of the region). These place the subject clear of the panel. */
    --s-focus-stage: 50% 50%;       /* default */
    --s-focus-stage-flakes: 0% 50%; /* the lamp (47% of the source) moves to ~66% of the region, off the panel */
    --s-rule-w: 1px;

    /* ---- motion: restrained, mechanical, hydraulic (power2 family) ------ */
    --s-ease: cubic-bezier(0.45, 0, 0.55, 1);           /* power2.inOut */
    --s-ease-out: cubic-bezier(0.33, 1, 0.68, 1);       /* power2.out */
    --s-gsap-ease: power2.inOut;                         /* the same curves, named for GSAP */
    --s-gsap-ease-out: power2.out;
    --s-dur-ui: 220ms;              /* hovers, chips, colour changes */
    --s-dur-wipe: 900ms;            /* index photo vertical clip wipe; unscrubbed blade wipes */
    --s-dur-theme: 700ms;           /* night → day class toggle (background + text colours) */
    --s-dur-console-step: 140ms;    /* console rows appear one after another, once */
    --s-dur-hero-scale: 18000ms;    /* hero 1.00 → 1.04, slow */
    --s-dur-tear: 650ms;            /* the ticket's perforated edge tears in once */
    --s-dur-ruler-step: 260ms;      /* the needle MOVES between stepped values; the number swaps instantly */
    --s-scale-hero: 1.04;
    --s-scrub: 0.8;                 /* storm-night scrub smoothing (seconds) */
    --s-station-hold: 0.4;          /* fraction of each station held still before the next blade pass */
    --s-delay-console: 450ms;

    /* ---- breakpoints (read by JS; CSS @media uses the same numbers) ------ */
    --s-bp-tablet: 768px;
    --s-bp-desktop: 1024px;
    --s-mq-phone: (max-width: 767px);
    --s-mq-wide: (min-width: 768px);
    --s-mq-pin: (min-width: 1024px) and (min-height: 640px);

    /* ---- z ---------------------------------------------------------------- */
    --s-z-nav: 50;
    --s-z-sticky: 40;
    --s-z-sheet: 60;
}

/* ---- Front-end engineer additions (pass 1, 2026-10-02). Layout, sizes and JS
 * tuning the templates need; one definition each, read by site.css, site.js and
 * index.php (picture `sizes`). Nothing here repeats a token above. ---------- */
:root {
    /* chrome */
    --s-ribbon-h: 34px;             /* replaced at runtime with the measured ribbon height */
    --s-nav-h: 56px;
    --s-mark-dot: 6px;              /* ticker separators, storm-line marker */

    /* hero */
    --s-hero-pad-b: clamp(24px, 5vh, 56px);
    --s-hero-title-m: 6.25rem;      /* phone headline: two lines in the sky, measured 7.15+ on the pixels */
    /* Phone hero photo is pinned to its TOP edge, so the headlights sit at a fixed distance below the
       headline whatever height Safari's toolbars leave the svh hero (r5 review: the lede slid onto the
       lights on iPhone). The bottom dock is solid, so the lights may pass under it on short screens. */
    --s-hero-focus-m: 50% 0%;
    /* site.js then slides the phone photo up so the top of the glow starts just under the lede at ANY
       hero height. Hero is Krueger's grader since 2026-10-02 (r5 review): the sodium traffic-light glow
       starts 0.548 down the hero-p crop (first row whose lightest 10% passes L 0.2), headlights ~0.67;
       0.53 leaves a margin. Two lamp heads above it (0.21, 0.40) are points: the 5-40% band measures
       p90 L 0.010 (salt 16.3) and 40-50% L 0.017 (salt 14.6). Text never sits on the glow. */
    --s-hero-hot-top: 0.53;
    --s-hero-hot-gap: 16px;
    --s-hero-title-m-short: 4.75rem; /* phone viewports <=700px tall (iPhone Pro in Safari ~677, SE): 76px, so the plow still shows */
    /* desktop: grader sits 608-1056px at 1440, clear of the 360px console strip. x only matters where the
       viewport is narrower than 16:9 (1440x810 and 1920x990 heroes have no horizontal overflow); at 1280 the
       70% the AD set put the right wheel under the console, so x is pushed to 100% (slides the frame left). */
    --s-hero-focus: 100% 50%;
    /* 1024-1279: the console leaves ~660px of photo, so 100% would put the amber beacons behind 'CLEAR'
       (measured at 1024). 40% keeps the beacons right of the headline; the console covers the cab's right half. */
    --s-hero-focus-mid: 40% 50%;
    /* 768-1023 (tablet, no console): portrait box crops ~40% of the frame; 63% centres the grader. */
    --s-hero-focus-tab: 63% 50%;

    /* storm night: the pinned stage */
    --s-rail-w: clamp(380px, 29vw, 440px);
    --s-storm-scroll: 0.9;          /* viewport heights of scroll per blade pass */
    --s-scale-frame: 1.05;          /* an arriving frame settles 1.05 → 1 during its wipe */
    --s-blade-w: 4px;               /* the hard edge riding the wipe */
    --s-blade-glow: 0 0 24px #ff840080;
    --s-ruler-w: 108px;
    --s-ruler-needle-h: 3px;
    --s-ruler-mark: 9px;            /* the 'on pavement' marker */
    --s-rail-dot: 11px;
    --s-log-w: 34em;
    --s-thumb-w: 112px;             /* reduced-motion log thumbnails */
    --s-day-at: 0.55;               /* the 05:00 block flips the theme when its top crosses this fraction of the viewport */
    /* 18:00 has no photograph: a short band of brine stripes in sodium with the log card overlapping it
       (r5 review: the 700px striped panel read as an image that failed to load). */
    --s-brine-band: 120px;
    --s-brine-band-stripes: repeating-linear-gradient(104deg, #ffb25e8c 0 6px, #ffb25e00 6px 22px);
    --s-brine-overlap: 40px;        /* the log card rides up over the band */
    --s-chip-sticky-h: 48px;        /* the phone mini clock is ONE fixed-height line (no jump between stations) */

    /* who we clear */
    --s-index-photo-w: clamp(420px, 37vw, 540px);
    --s-index-rule: 2px;

    /* contracts */
    --s-band-w: 3px;
    --s-table-col: minmax(0, 1fr);

    /* proof filmstrip */
    --s-card-w: clamp(300px, 27vw, 380px);
    --s-card-w-m: 82vw;
    /* The lead card's title is sized to the CARD (container query), not the viewport: r5 review, the stop of
       'TIMESTAMPED.' ran past a 380px card at 1440. The longest word measures ~4.45em in Sofia Sans XC Black,
       so 20cqi of the card's content box keeps it inside with a margin at every card width. */
    --s-proof-title: clamp(2.25rem, 20cqi, 5rem);
    --s-proof-pad-top: var(--s-space-8);   /* the bar sits close under the section edge; the card carries the weight */
    --s-drag-throw: 240ms;          /* release velocity × this = how far a flick carries before it snaps */
    --s-drag-min: 6px;              /* movement before a press becomes a drag */

    /* closing ticket */
    --s-ticket-hole: 6px;           /* perforation hole radius */
    --s-ticket-pad: clamp(20px, 4vw, 48px);
    --s-ticket-strip-h: 28px;       /* height of the orange tear strip along the ticket's top edge */
    --s-order-title: clamp(2.75rem, 3.4vw, 3.5rem); /* desktop: the title sized to the 40% ticket, so step one's choices sit in the first screen */
    --s-readout-value: clamp(1.25rem, 2.4vw, 2.25rem); /* the readout's large mono values */
    --s-chip-h: 48px;

    /* picture sizes (read by index.php) */
    --s-sizes-full: 100vw;
    --s-sizes-stage: (min-width: 1024px) 72vw, 100vw;
    --s-sizes-index: (min-width: 1024px) 540px, 100vw;
    --s-sizes-card: (min-width: 768px) 380px, 82vw;
    --s-sizes-thumb: 112px;
}
