/* Option D design tokens (D10 round 2, D24), from Glass Water's. Colour values restate tokens.json, which is the
   one authority for colour and is checked by design/tools/contrast.py in both themes. If a colour here and in
   tokens.json disagree, tokens.json wins and this file is wrong. design/prototypes/option-d/css/tokens.css is an
   exact copy of this file.
   Theme (D23): :root holds light and [data-theme="dark"] holds dark. js/boot.js runs in <head> and always sets
   data-theme to the resolved theme (a stored Light / Dark / Match device choice wins; with no choice the device's
   prefers-color-scheme decides, Light when it states nothing), so no prefers-color-scheme block is needed here and
   the first frame is already in the right theme. */

/* ---------------------------------------------------------------- Archivo (D40: figures and the wordmark on desktop)
   Omnibus-Type, SIL Open Font License 1.1 (fonts/OFL-archivo.txt, checked: "Copyright 2020 The Archivo Project
   Authors", OFL 1.1). Variable: wdth 62 to 125, wght 100 to 900. Self-hosted: the latin woff2 from
   @fontsource-variable/archivo 5.3.0, the same 90,104-byte file Field Day carries. Never a font CDN (D35). */
@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/archivo-e3a28ead.woff2") format("woff2-variations"), url("/assets/fonts/archivo-e3a28ead.woff2") format("woff2");
  font-weight: 100 900; font-stretch: 62% 125%; font-style: normal; font-display: swap;
}

/* ---------------------------------------------------------------- type
   Family: Manrope (Mikhail Sharanda), SIL Open Font License 1.1, variable weight 200 to 800.
   A modern geometric grotesk: open apertures for small stamps, tall clean numerals for the big answers.
   Self-hosted: the prototype carries the latin variable woff2 from @fontsource-variable/manrope 5.3.0
   (fetched from cdn.jsdelivr.net 2026-10-01) with its OFL text in fonts/. Never fonts.googleapis.com,
   which is not on the check_pack allowlist.
   `tnum` verified in the served file (PHASE 2, Chrome, 2026-10-01): at 600 40px "1111" and "0000" both
   measure 99 px with tabular-nums, against 68 px for proportional "1111".
   Map labels are NOT this face: symbol layers can only use the local Noto Sans glyph PBFs
   (Regular, Medium, Italic; see map-style.md). */
:root {
  --font-ui: "Manrope Variable", "Manrope", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-num: var(--font-ui);
  --num-features: "tnum" 1, "lnum" 1;   /* every figure: tabular, lining */

  /* size / line-height / weight / tracking. Display steps are for the one big answer per job. */
  --t-display-xl: 600 56px/1.0 var(--font-num);  /* desktop hero numeral: wind speed, wave bin */
  --t-display-l:  600 44px/1.02 var(--font-num); /* phone hero numeral in the peek */
  --t-display-m:  600 32px/1.08 var(--font-num); /* card figure: depth band, Secchi ft, inHg */
  --t-headline:   650 22px/1.2 var(--font-ui);   /* the J1 sentence; lake name */
  --t-title:      650 17px/1.3 var(--font-ui);   /* card title */
  --t-body:       500 15px/1.45 var(--font-ui);
  --t-body-s:     500 14px/1.45 var(--font-ui);
  --t-label:      600 13px/1.3 var(--font-ui);   /* chips, buttons, legend entries */
  --t-stamp:      500 12.5px/1.35 var(--font-ui);/* Kind · Agency · dataset · date. Never below 12px. */
  --track-display: -0.02em;
  --track-label: 0.01em;
  --track-kind: 0.06em;                           /* the stamp's kind word, set in small caps-like uppercase */

  /* ---------------------------------------------------------------- spacing (4 px base) */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px; --s-5: 20px;
  --s-6: 24px; --s-8: 32px; --s-10: 40px; --s-12: 48px;
  --gutter: 16px;            /* phone side gutter */
  --gutter-desk: 24px;       /* gap between desktop floating cards and the viewport edge */
  --target: 44px;            /* every control (spec 3.0.1) */
  --target-gap: 8px;

  /* ---------------------------------------------------------------- radii (generous, the direction's signature) */
  --r-xs: 8px;     /* chart bars' data end is 4px (dataviz spec), legend swatches 4px */
  --r-s: 12px;     /* chips are full pills, see --r-pill */
  --r-m: 18px;     /* buttons, search field */
  --r-l: 24px;     /* floating cards */
  --r-xl: 32px;    /* the phone sheet's top corners */
  --r-pill: 999px;

  /* ---------------------------------------------------------------- glass (per theme below)
     A glass surface = background colour with alpha + backdrop blur and saturation + a 1px inner
     highlight border + a soft shadow. The alpha values are the ones contrast.py checked; blur only
     makes the real result safer than the check. */
  --glass-blur: 22px;
  --glass-saturate: 165%;
  --glass-blur-strong: 30px;

  /* ---------------------------------------------------------------- D40 desktop system (1024 px and up; the phone keeps
     the radii, glass and heights above). One elevation scale, one radius scale, one height scale:
     e0 the map; e1 docked surfaces (surface-1, a hairline, no shadow); e2 floating controls; e3 popovers.
     Translucency on e1 and e2 only. Radii: 6 tags, 10 inputs / buttons / segments, 14 tiles, 20 the phone sheet,
     0 at docked edges; no 999 px pills on desktop except tags. Heights: 56 bar, 40 inputs, 36 controls and segments
     (a 44 px target around each, D34), 32 compact, 24 tags. */
  --e2: 0 1px 2px rgba(16, 24, 32, 0.08), 0 4px 16px rgba(16, 24, 32, 0.10);
  --e3: 0 8px 32px rgba(16, 24, 32, 0.16);
  --e-blur: 24px; --e-saturate: 140%;
  --rd-tag: 6px; --rd-ctl: 10px; --rd-tile: 14px; --rd-sheet: 20px;
  --h-bar: 56px; --h-input: 40px; --h-ctl: 36px; --h-compact: 32px; --h-tag: 24px;
  --panel-w: 400px;
  /* D40 type: Manrope for text, Archivo (variable width) for figures and the wordmark */
  --font-display: "Archivo", "Manrope Variable", system-ui, sans-serif;
  --td-name: 700 28px/1.1 var(--font-display);       /* the lake's name */
  --td-section: 650 20px/1.25 var(--font-ui);
  --td-headline: 600 17px/1.32 var(--font-ui);
  --td-body: 500 15px/1.45 var(--font-ui);
  --td-label: 500 13px/1.35 var(--font-ui);
  --td-meta: 600 11px/1.3 var(--font-ui);            /* caps meta, letter-spacing .04em */
  --tf-xl: 700 44px/1 var(--font-display);           /* the wind tile's speed */
  --tf-l: 650 32px/1.05 var(--font-display);         /* the other tiles' figures */
  --tf-m: 650 20px/1.15 var(--font-display);         /* inline figures and the tiles' words */

  /* ---------------------------------------------------------------- elevation */
  --z-map: 0; --z-map-ui: 10; --z-card: 20; --z-sheet: 30; --z-popover: 40; --z-alert: 50; --z-toast: 60;

  /* ---------------------------------------------------------------- motion
     Springs drive the sheet, cards and markers through a small JS spring (PHASE 2). Each has a CSS
     fallback curve and duration that approximates it, for transitions the spring does not drive.
     Spring params are for a unit mass: stiffness k, damping c. */
  --spring-sheet: "k=380 c=36";          /* ~ critically damped + 2% overshoot; settles in ~320 ms */
  --spring-card: "k=520 c=34";           /* a lighter pop, ~4% overshoot; settles in ~260 ms */
  --spring-marker: "k=700 c=28";         /* marker drop, ~8% overshoot; settles in ~220 ms */
  --ease-spring-css: cubic-bezier(0.2, 1.1, 0.3, 1);   /* fallback for the springs, 2 to 4% overshoot */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);           /* fades, cross-fades */
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);        /* camera flies (MapLibre easing fn equivalent) */
  --d-instant: 0ms;
  --d-fast: 150ms;       /* chips, layer fades, popover open (spec 3.0.1) */
  --d-medium: 200ms;     /* dial needle, wave-bin cross-fade per scrub step (spec 3.4) */
  --d-sheet: 280ms;      /* sheet snap fallback, the spec's 200 to 280 ms upper bound */
  --d-ray: 250ms;        /* upwind ray draws in (spec 3.6) */
  --d-camera: 750ms;     /* fly to a lake (spec 3.13: 600 to 900 ms) */
  --d-theme: 180ms;      /* chrome cross-fade on theme switch; the map style swaps instantly */
  --d-play-step: 700ms;  /* one forecast hour per step while playing (spec 3.4) */
}

/* ---------------------------------------------------------------- colour: light (default) */
:root {
  color-scheme: light;
  /* map grounds (Protomaps "light" flavor overrides, see map-style.md) */
  --earth: #EFF2EE; --map-highway: #FFFFFF; --map-road: #E2E7E4; --basemap-water: #CFE9F0;
  --park: #DDEBDF; --map-plain: #E8EEF1; --map-label-ink: #2B3A44; --map-label-halo: #F7FAF9;
  /* the lake */
  --shore-line: #1E7F95; --shore-halo: #8FE6F073; --island-fill: #EFF2EE;
  --depth-1: #E2F7F6; --depth-2: #BDEDEF; --depth-3: #91DEE6; --depth-4: #5FC8DA; --depth-5: #34AECB;
  --depth-6: #1F8FB7; --depth-7: #17709E; --depth-8: #135684; --depth-9: #103F69;
  --contour-ink-shallow: #0B2A40; --contour-ink-deep: #EEFAFF;
  --contour-halo-shallow: #F4FBFC; --contour-halo-deep: #0D3150;
  /* shore waves (estimate), bins under 1/4, 1/4 to 1/2, 1/2 to 1, 1 to 1 1/2, 1 1/2 ft or more */
  --wave-0: #F4EEDC; --wave-1: #F7D774; --wave-2: #F5A83E; --wave-3: #EB7134; --wave-4: #8E5BB5; --wave-5: #5E2D8C;
  --wave-edge: #10283A; --wave-bed-land: #10283A; --wave-bed-water: #10283A;
  --sheltered-ink: #0B2A40; --sheltered-halo: #F7FAF9;
  /* wind, access, markers, location */
  --particle-core: #0D3B52; --particle-edge: #FFFFFF;
  --wind-pale-core: #0D3B52; --wind-pale-edge: #0D3B52; --wind-deep-core: #DCEBF1; --wind-deep-edge: #D0E4EC;   /* wind streaks by the surface under them (app.js WIND_LOOK) */
  --access-fill: #0B3A55; --access-glyph: #FFFFFF;
  --marker-edge-a: #0B2A40; --marker-edge-b: #FFFFFF; --marker-fill: #007E8E;
  --loc-dot: #2D5BFF; --loc-ring: #FFFFFF; --loc-accuracy: #2D5BFF26;
  /* chrome */
  --surface: #F6F9FA; --glass: #FFFFFFCC; --glass-strong: #FFFFFFE6; --glass-solid: #F8FBFC;
  --glass-border: #FFFFFFB3; --glass-shade: #0B1A2414;
  --ink: #0B1A24; --ink-2: #2F4555; --ink-3: #435868;
  --accent: #007E8E; --accent-ink: #00606C; --on-accent: #FFFFFF;
  --accent-glow: #2ED8E659; --accent-soft: #00B3C226;
  --control-border: #5A6B78; --track: #5A6B78; --focus: #08476B; --focus-halo: #FFFFFF;
  /* states */
  --now-bg: #D9EEF1; --now-ink: #0B2A33; --stale-ink: #7A4300; --stale-bg: #F7C46C33; --error-ink: #A8231B; --error-bg: #FF8A801F;
  --missing-ink: #435868; --missing-hatch: #43586826; --estimate-ink: #4E3FA0; --estimate-bg: #7C6CF21F;
  --radar-empty-ink: #2F4555; --radar-empty-border: #5E7180; --select-bg: #00B3C22E;
  /* charts */
  --chart-catch: #0B1A24; --chart-normal-band: #00B3C22E; --chart-normal-edge: #0B6E80;
  --chart-secchi: #1F75A8; --chart-secchi-median: #0B1A24; --chart-level: #3D5F8C;
  --chart-pressure: #5B4FA3; --chart-precip: #2F6FB8; --chart-wind: #0A6E80; --chart-gust: #5E7180;
  --chart-grid: #0B1A241A; --chart-cursor: #007E8E; --chart-sky: #5E7180;
  /* radar (MRMS observed, HRRR model forecast): bins at 5, 20, 35, 50, 60 dBZ */
  --radar-1: #5F8A70; --radar-2: #1F9A43; --radar-3: #E9AE00; --radar-4: #E5301B; --radar-5: #C2119F;
  --radar-keyline: #0B2A40; --model-ink: #2F4555; --model-edge: #5E7180; --radar-now: #0B1A24;
  /* Option D additions */
  --sky-track: #0B1A241F; --model-hatch: #0B1A24; --scrim: #0B1A2466;
  /* Option D additions */
  --img-casing: #F7FAF9;
  /* Option D additions */
  --img-dark: #36393C; --img-forest: #4B5646; --img-water: #5E6662; --img-field: #7D8A68; --img-sand: #A7AB8D; --img-light: #B3B59C; --img-shore: #0B2A40; --img-ring: #FFFFFF;
  /* Option D additions */
  --r-depth-1: #C9DDE4; --r-depth-2: #B9D0DA; --r-depth-3: #A9C4D0; --r-depth-4: #99B7C6; --r-depth-5: #8AAABC; --r-depth-6: #7A9EB1; --r-depth-7: #6A91A7; --r-depth-8: #5A859D; --r-depth-9: #4A7893; --r-water: #C9DDE4; --r-shore: #4D6B78; --r-contour: #132833; --r-contour-halo: #E6EEF0; --r-relief-shadow: #2C4652; --r-relief-light: #FFFFFF;
  /* Option D additions */
  --ns-fill: #DCDFDD; --ns-hatch: #5F6A70;
  /* Option D additions */
  --r-contour-deep: #132833; --r-label: #132833;
  /* Option D additions */
  --img-contour: #C4D3DACC; --img-tint-lo: #C9DDE40B; --img-tint-hi: #4A789357;
  /* Option D additions */
  --img-contour-casing: #0E1A208C; --img-dark-tlo: #3C4043; --img-dark-thi: #3D4E5A; --img-water-tlo: #636B68; --img-water-thi: #576C73; --img-light-tlo: #B4B79F; --img-light-thi: #8FA099;
  /* Option D additions */
  --wind-arrow-core: #0D3B52; --wind-arrow-casing: #FFFFFF;
  /* Option D additions */
  --img-road: #D8D1C4; --img-road-label: #2E2B26; --img-road-halo: #F2EEE6CC;
  /* Option D additions */
  --dial-needle: #007E8E; --dial-ring: #5A6B78; --tile-edge: #5A6B7833;
  /* Option D additions */
  --surface-1: #FFFFFFDB; --surface-2: #F2F5F7; --hairline: #0F1E2814; --earth-desk: #F0F0EB; --park-desk: #DFE7DB; --chart-wave: #A35A00; --desk-shade: #0A192314; --vignette-edge: #0B1A2414;
  /* Option D additions */
  /* QA M7 imagery grade */
  --img-saturation: -0.15; --img-contrast: -0.05; --img-brightness-max: 1; --img-radar-saturation: -1; --img-radar-contrast: 0; --img-radar-brightness-max: 0.8;
  --spot: #FFFFFF; --spot-ink: #0B3A55; --shell-surface: #F8FBFC; --shell-line: #0F1E2824;
  /* Option D additions */
  --plus-ink: #0B3A55; --plus-bg: #0B3A5514;

  /* glass recipe, light: bright frost, a white inner highlight, a cool soft shadow */
  --glass-highlight: inset 0 1px 0 0 #FFFFFFE6, inset 0 0 0 1px var(--glass-border);
  --shadow-card: 0 1px 2px #0B1A2414, 0 8px 28px -6px #0B3A5529;
  --shadow-sheet: 0 -6px 30px -8px #0B3A5533;
  --shadow-chip: 0 1px 2px #0B1A241F;
  --map-glow-shore: 0 0 0 transparent; /* the shoreline halo is a map layer, not a CSS shadow */
}

/* ---------------------------------------------------------------- colour: dark */
[data-theme="dark"] {
  color-scheme: dark;
  --earth: #0D1319; --map-highway: #2A3038; --map-road: #1A2027; --basemap-water: #13212C;
  --park: #101B17; --map-plain: #0F161C; --map-label-ink: #C9D6DE; --map-label-halo: #0D1319;
  --shore-line: #59C6D8; --shore-halo: #3FE0DA40; --island-fill: #0D1319;
  --depth-1: #0F2027; --depth-2: #10293A; --depth-3: #11324B; --depth-4: #133C5D; --depth-5: #16476F;
  --depth-6: #1A5382; --depth-7: #1F6096; --depth-8: #276FAB; --depth-9: #3480C2;
  --contour-ink-shallow: #A9CCDC; --contour-ink-deep: #D4ECF5;
  --contour-halo-shallow: #0B161D; --contour-halo-deep: #0B1A2A;
  --wave-0: #93897A; --wave-1: #F2D16B; --wave-2: #F9A64A; --wave-3: #FF7E4D; --wave-4: #C79BFF; --wave-5: #9F6BFF;
  --wave-edge: #93897A; --wave-bed-land: #0D1319; --wave-bed-water: #0F2027;
  --sheltered-ink: #DDEFF5; --sheltered-halo: #0D1319;
  --particle-core: #DCEBF1; --particle-edge: #D0E4EC;
  --wind-pale-core: #0D3B52; --wind-pale-edge: #0D3B52; --wind-deep-core: #DCEBF1; --wind-deep-edge: #D0E4EC;
  --access-fill: #EAF6FA; --access-glyph: #0B1620;
  --marker-edge-a: #E8F7FF; --marker-edge-b: #CFEFF7; --marker-fill: #0A6E78;
  --loc-dot: #2F55D4; --loc-ring: #E8F7FF; --loc-accuracy: #7C9BFF2E;
  --surface: #0A1219; --glass: #0B1620D6; --glass-strong: #0B1620EB; --glass-solid: #0E1922;
  --glass-border: #FFFFFF1F; --glass-shade: #00000059;
  --ink: #EAF3F8; --ink-2: #B5C7D3; --ink-3: #9DB1BF;
  --accent: #3FE0DA; --accent-ink: #6FEDE6; --on-accent: #04161A;
  --accent-glow: #3FE0DA59; --accent-soft: #3FE0DA24;
  --control-border: #7F94A3; --track: #7F94A3; --focus: #7FF3EE; --focus-halo: #CFF9F6;
  --now-bg: #12343B; --now-ink: #E6F6F8; --stale-ink: #F7C46C; --stale-bg: #F7C46C24; --error-ink: #FF9A8F; --error-bg: #FF8A8024;
  --missing-ink: #9DB1BF; --missing-hatch: #9DB1BF2E; --estimate-ink: #C3B8FF; --estimate-bg: #7C6CF233;
  --radar-empty-ink: #B5C7D3; --radar-empty-border: #7F94A3; --select-bg: #3FE0DA29;
  --chart-catch: #EAF3F8; --chart-normal-band: #3FE0DA2E; --chart-normal-edge: #6FC9D6;
  --chart-secchi: #58B4E8; --chart-secchi-median: #EAF3F8; --chart-level: #8FA8D8;
  --chart-pressure: #B3A6F0; --chart-precip: #6FA8F0; --chart-wind: #4FD8E8; --chart-gust: #9DB0BE;
  --chart-grid: #EAF3F81A; --chart-cursor: #3FE0DA; --chart-sky: #9DB0BE;
  --radar-1: #7C9A88; --radar-2: #45C764; --radar-3: #FFD84A; --radar-4: #FF553D; --radar-5: #FF5BE6;
  --radar-keyline: #A9CCDC; --model-ink: #B5C7D3; --model-edge: #7F94A3; --radar-now: #EAF3F8;
  /* Option D additions */
  --sky-track: #EAF3F824; --model-hatch: #EAF3F8; --scrim: #00000099;
  /* Option D additions */
  --img-casing: #A9BFC8;
  /* Option D additions */
  --img-dark: #191A1C; --img-forest: #232721; --img-water: #2C2F2D; --img-field: #3A3F32; --img-sand: #4D4E43; --img-light: #53534A; --img-shore: #A9BFC8; --img-ring: #EAF6FA;
  /* Option D additions */
  --r-depth-1: #3F6E83; --r-depth-2: #386275; --r-depth-3: #315667; --r-depth-4: #2A4A59; --r-depth-5: #223E4A; --r-depth-6: #1B313C; --r-depth-7: #14252E; --r-depth-8: #0D1920; --r-depth-9: #060D12; --r-water: #536A73; --r-shore: #5F7B89; --r-contour: #C2D2DA; --r-contour-halo: #14212A; --r-relief-shadow: #05090C; --r-relief-light: #6E8A96;
  /* Option D additions */
  --ns-fill: #1A2025; --ns-hatch: #C4CFD5;
  /* Option D additions */
  --r-contour-deep: #C2D2DA; --r-label: #DCE7EB;
  /* Option D additions */
  --img-contour: #C4D3DACC; --img-tint-lo: #1B2E390B; --img-tint-hi: #4B809957;
  /* Option D additions */
  --img-contour-casing: #0E1A208C; --img-dark-tlo: #191B1D; --img-dark-thi: #2A3D47; --img-water-tlo: #2B2F2E; --img-water-thi: #374B52; --img-light-tlo: #515149; --img-light-thi: #506265;
  /* Option D additions */
  --wind-arrow-core: #DCE7EB; --wind-arrow-casing: #0B1620;
  /* Option D additions */
  --img-road: #8C867A; --img-road-label: #E8E3DA; --img-road-halo: #161512CC;
  /* Option D additions */
  --dial-needle: #3FE0DA; --dial-ring: #7F94A3; --tile-edge: #FFFFFF24;
  /* Option D additions */
  --surface-1: #121A20D6; --surface-2: #1A242C; --hairline: #FFFFFF1A; --earth-desk: #111518; --park-desk: #131B17; --chart-wave: #F2B451; --desk-shade: #0000003D; --vignette-edge: #00000038;
  /* Option D additions */
  /* QA M7 imagery grade */
  --img-saturation: -0.3; --img-contrast: -0.05; --img-brightness-max: 0.465; --img-radar-saturation: -1; --img-radar-contrast: 0; --img-radar-brightness-max: 0.28;
  --spot: #0B1620; --spot-ink: #EAF6FA; --shell-surface: #0E1922; --shell-line: #FFFFFF24;
  /* Option D additions */
  --plus-ink: #EAF6FA; --plus-bg: #EAF6FA1F;

  /* glass recipe, dark: deep blue-black smoke, a faint top highlight, a deeper shadow; data glows */
  --glass-highlight: inset 0 1px 0 0 #FFFFFF14, inset 0 0 0 1px var(--glass-border);
  --shadow-card: 0 1px 2px #00000066, 0 10px 32px -6px #00000080;
  --shadow-sheet: 0 -8px 34px -6px #00000099;
  --shadow-chip: 0 1px 2px #00000066;
}

/* ---------------------------------------------------------------- glass surfaces */
.od-glass {
  background: var(--glass);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
          backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  box-shadow: var(--glass-highlight), var(--shadow-card);
  border-radius: var(--r-l);
  color: var(--ink);
}
.od-glass--strong {
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(var(--glass-blur-strong)) saturate(var(--glass-saturate));
          backdrop-filter: blur(var(--glass-blur-strong)) saturate(var(--glass-saturate));
}
/* No backdrop-filter support: the alpha alone is what contrast.py checked, so it stays legible. */

/* Reduce transparency: the OS setting (where the browser exposes it) or the in-app "Solid panels"
   setting (data-glass="solid") swaps every glass for the opaque token. Never lighter than the check. */
@media (prefers-reduced-transparency: reduce) {
  .od-glass, .od-glass--strong { background: var(--glass-solid); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
[data-glass="solid"] .od-glass, [data-glass="solid"] .od-glass--strong {
  background: var(--glass-solid); -webkit-backdrop-filter: none; backdrop-filter: none;
}
/* Forced colours (Windows high contrast): glass becomes Canvas with a real border. */
@media (forced-colors: active) {
  .od-glass, .od-glass--strong { background: Canvas; border: 1px solid CanvasText; box-shadow: none; backdrop-filter: none; }
}

/* ---------------------------------------------------------------- figures and stamps */
.od-num { font-variant-numeric: tabular-nums lining-nums; font-feature-settings: var(--num-features); letter-spacing: var(--track-display); }
.od-stamp { font: var(--t-stamp); color: var(--ink-3); }
.od-stamp .kind { text-transform: uppercase; letter-spacing: var(--track-kind); font-weight: 700; }
.od-stamp--stale { color: var(--stale-ink); }
.od-estimate { color: var(--estimate-ink); background: var(--estimate-bg); border-radius: var(--r-pill); padding: 1px 8px; font: var(--t-label); }

/* ---------------------------------------------------------------- focus (two-tone so it reads on glass and on any map pixel) */
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; box-shadow: 0 0 0 5px var(--focus-halo); border-radius: inherit; }

/* ---------------------------------------------------------------- motion: what animates, and reduced motion
   Animates (default):
   - sheet snaps: spring-sheet; follows the finger 1:1 while dragging; fling > 0.5 px/ms goes to the next snap
   - desktop cards: enter with spring-card (scale 0.96 -> 1, translateY 8px -> 0, opacity 0 -> 1)
   - spot marker: drops with spring-marker (translateY -14px -> 0) plus a one-shot accent-glow ring pulse (600 ms, once)
   - upwind ray: dash draws in over --d-ray
   - wind particles: continuous, the only looping motion besides radar on request; re-seeded on scrub so the
     field turns with the forecast hour (particles ease to the new direction over --d-medium, never snap)
   - shore-wave bins: cross-fade over --d-medium per scrub step
   - wind dial needle: shortest arc over --d-medium
   - layer on/off: opacity over --d-fast
   - camera: flyTo over --d-camera with --ease-in-out; easeTo for selections
   - theme switch: chrome cross-fade over --d-theme; the map style swaps instantly
   - fishery bars: grow once on first view over 300 ms
   Reduced motion (prefers-reduced-motion: reduce, or the in-app "Reduce motion" setting, data-motion="reduce"):
   - sheet: instant snap, no overshoot, no follow-through (the drag itself still tracks the finger)
   - cards and popovers: appear instantly (opacity only, 0 ms)
   - marker: placed, no drop, no pulse; the ray appears whole
   - wind: NO particles. 8 to 12 fixed-size static arrows per basin pointing where the wind blows;
     size never encodes speed; arrows redraw instantly on each scrub step
   - waves, dial, numbers: instant redraw, no cross-fade, no tween
   - camera: jumpTo, never flyTo
   - play: still offered; each 700 ms step is an instant redraw
   - theme: instant swap
   - fishery bars: drawn at full length */
@media (prefers-reduced-motion: reduce) {
  :root { --d-fast: 0ms; --d-medium: 0ms; --d-sheet: 0ms; --d-ray: 0ms; --d-camera: 0ms; --d-theme: 0ms; --ease-spring-css: linear; }
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
}
[data-motion="reduce"] { --d-fast: 0ms; --d-medium: 0ms; --d-sheet: 0ms; --d-ray: 0ms; --d-camera: 0ms; --d-theme: 0ms; --ease-spring-css: linear; }
