/**
 * Wind Window.
 *
 * A meteorological broadsheet, not a dashboard: paper ground, hairline
 * rules, a serif for anything editorial, a mono for anything you are meant
 * to read as a measurement. No gradients, no glass, no shadows doing
 * decorative work.
 *
 * Light by choice - this gets read on a phone in a car park in full sun.
 *
 * MOBILE FIRST. Every rule here is the small-screen rule; wider layouts are
 * additions at the breakpoints, never overrides walked back. The two sizes
 * that drive the design are 390px (a phone) and 884px (a Fold opened), and
 * the awkward one is the Fold cover screen at ~404 x 940 - narrow but very
 * tall, which is why vertical space above the fold is spent so carefully.
 *
 * Scales, so nothing is a one-off:
 *   space  4 8 12 16 20 24 32 40 56
 *   type   12 13 14 16 18 21 26 34
 *   radius 3 (default) 10 (sheets) 999 (pills)
 */

/* ---------------------------------------------------------------- tokens */

:root {
  color-scheme: light;

  --paper:        #F7F6F2;
  --surface:      #FFFFFF;
  --surface-sunk: #FBFAF7;
  --surface-warm: #F2EFE7;

  --ink:          #14171A;
  --ink-2:        #4E545B;
  --ink-3:        #7C838C;
  --ink-invert:   #FFFFFF;

  --rule:         #E4E1D8;
  --rule-strong:  #CFCBBF;

  --accent:       #14557F;
  --accent-ink:   #0E3E5C;
  --accent-wash:  #EAF1F6;
  --accent-rule:  #BDD3E2;

  --ok:           #0F7A46;
  --ok-wash:      #E7F3EC;
  --warn:         #9A6510;
  --warn-wash:    #FAF0DD;
  --bad:          #A82C2C;
  --bad-wash:     #F8E9E7;

  --serif: "Source Serif 4", "Iowan Old Style", Georgia, serif;
  --sans:  "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono:  "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 20px; --s6: 24px; --s7: 32px; --s8: 40px; --s9: 56px;

  --radius: 3px;
  --radius-lg: 10px;

  --shadow-card: 0 1px 2px rgba(20,23,26,.06);
  --shadow-pop:  0 10px 34px rgba(20,23,26,.18), 0 2px 6px rgba(20,23,26,.10);

  --section-gap: var(--s7);
  --gutter: var(--s4);
  --shell: 1440px;

  /* Anything a finger has to hit. */
  --tap: 44px;
}

@media (min-width: 860px) {
  :root { --section-gap: var(--s8); --gutter: var(--s6); }
}

/* ------------------------------------------------------------------ base */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 16px/1.55 var(--sans);
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -0.01em; }
a { color: var(--accent-ink); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--ink); }
button { font: inherit; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

.shell { max-width: var(--shell); margin: 0 auto; padding: 0 var(--gutter); }
main.shell { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }
@media (min-width: 900px) { main.shell { padding-bottom: 0; } }

.skip-link {
  position: absolute; left: -9999px;
  background: var(--ink); color: var(--ink-invert);
  padding: 10px 16px; z-index: 300;
}
.skip-link:focus { left: 12px; top: 12px; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.subtle { color: var(--ink-3); }
.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------- masthead */

/*
 * On a phone this is the one sticky thing: brand with a health dot, the
 * spot as a button, a menu. Five rows became one. From 900px the picker
 * takes over as the sticky element and this scrolls away with the page.
 */
.masthead {
  position: sticky; top: 0; z-index: 60;
  background: var(--surface);
  border-bottom: 1px solid var(--rule-strong);
}
@media (min-width: 900px) { .masthead { position: static; } }

.masthead-top { display: flex; align-items: center; gap: var(--s2); min-height: 56px; }
.wordmark {
  display: inline-flex; align-items: center; gap: 7px;
  font: 600 18px/1 var(--serif); letter-spacing: -0.02em; color: var(--ink);
  text-decoration: none; white-space: nowrap; padding: var(--s2) 0; flex: none;
}
.wordmark .wm span { color: var(--accent); }
/* Run health, as a dot on the brand. Tap the menu for the words. */
.health { width: 8px; height: 8px; border-radius: 50%; background: var(--rule-strong); flex: none; }
.health.is-ok { background: var(--ok); }
.health.is-warn { background: var(--warn); }
.health.is-bad { background: var(--bad); }

/* The spot, as the primary control. Fills the bar between brand and menu. */
.spot-btn {
  flex: 1 1 auto; min-width: 0; min-height: var(--tap);
  display: flex; align-items: center; gap: var(--s2);
  background: var(--surface-warm); border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 5px 10px 5px 12px; cursor: pointer; text-align: left; color: var(--ink);
}
.spot-btn:hover { border-color: var(--rule-strong); }
.spot-btn-text { min-width: 0; display: flex; flex-direction: column; line-height: 1.15; }
.spot-btn-name { font: 600 16px/1.15 var(--serif); letter-spacing: -0.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spot-btn-sub { font: 400 11.5px/1.2 var(--sans); color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spot-btn .chev { margin-left: auto; color: var(--ink-3); font-size: 12px; }
@media (min-width: 900px) { .spot-btn { display: none; } }

.menu-btn {
  flex: none; width: var(--tap); height: var(--tap);
  background: none; border: 1px solid transparent; border-radius: var(--radius);
  cursor: pointer; display: grid; place-items: center; color: var(--ink-2);
}
.menu-btn:hover { background: var(--surface-warm); color: var(--ink); }
.menu-glyph, .menu-glyph::before, .menu-glyph::after {
  display: block; width: 18px; height: 2px; background: currentColor; border-radius: 1px;
}
.menu-glyph { position: relative; }
.menu-glyph::before, .menu-glyph::after { content: ""; position: absolute; left: 0; }
.menu-glyph::before { top: -6px; }
.menu-glyph::after { top: 6px; }

.masthead-nav { display: none; gap: 2px; margin-left: auto; }
@media (min-width: 900px) { .masthead-nav { display: flex; } }
.masthead-nav a {
  font-size: 13px; font-weight: 500; color: var(--ink-2);
  text-decoration: none; padding: 10px var(--s2); border-radius: var(--radius);
  white-space: nowrap;
}
.masthead-nav a:hover { background: var(--surface-warm); color: var(--ink); }
.masthead-nav a[aria-current="page"] { background: var(--accent-wash); color: var(--accent-ink); }

@media (min-width: 560px) {
  .wordmark { font-size: 22px; }
  .masthead-nav a { font-size: 14px; padding: 8px 11px; }
}

/*
 * Data freshness. On a phone this is one tappable line, not three rows of
 * chips - it used to cost about 90px above the fold on a Fold cover screen,
 * which is most of what you see before scrolling.
 */
.status-line {
  display: flex; align-items: center; gap: var(--s2);
  width: 100%; text-align: left;
  background: none; border: 0; border-top: 1px solid var(--rule);
  padding: 9px 0; cursor: pointer;
  font: 500 12.5px/1 var(--sans); color: var(--ink-2);
  min-height: var(--tap);
}
.status-line .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); flex: none; }
.status-line.is-warn .dot { background: var(--warn); }
.status-line.is-bad  .dot { background: var(--bad); }
.status-line .chev { margin-left: auto; color: var(--ink-3); transition: transform .15s; }
.status-line[aria-expanded="true"] .chev { transform: rotate(180deg); }

.status-detail { display: none; border-top: 1px solid var(--rule); padding: var(--s3) 0 var(--s4); }
.status-detail.is-open { display: block; }
.status-grid {
  display: grid; gap: var(--s2) var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  font-family: var(--mono); font-size: 12px;
}
.status-item { display: flex; align-items: center; gap: 7px; color: var(--ink-2); }
.status-item b { font-weight: 500; color: var(--ink); }
.status-item .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); flex: none; }
.status-item.is-down .dot { background: var(--bad); }
.status-item.is-none .dot { background: var(--ink-3); }
.status-detail .note { margin-top: var(--s3); }

/* ------------------------------------------------------ spot + region bar */

/*
 * The primary control, and the thing the old build got most wrong: region
 * lived at the top of the page and the spot picker several hundred pixels
 * below it inside the forecast section. They belong together, and they
 * belong above everything they scope.
 */
.picker { display: none; position: sticky; top: 0; z-index: 55; background: var(--surface); border-bottom: 1px solid var(--rule-strong); }
@media (min-width: 900px) { .picker { display: block; } }

.picker-row { display: flex; align-items: center; gap: var(--s3); padding: var(--s2) 0; }

.segmented { display: inline-flex; background: var(--surface-warm); border-radius: var(--radius); padding: 3px; gap: 2px; flex: none; }
.segmented button {
  font: 500 13px/1 var(--sans); color: var(--ink-2);
  background: none; border: 0; cursor: pointer;
  padding: 9px 12px; border-radius: 2px; white-space: nowrap; min-height: 36px;
}
.segmented button:hover { color: var(--ink); }
.segmented button[aria-selected="true"] { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-card); }

.region-blurb { font: 400 13px/1.4 var(--sans); color: var(--ink-3); display: none; }
@media (min-width: 1000px) { .region-blurb { display: block; } }

/*
 * Spot chips scroll with snap rather than wrapping to four rows. The fade
 * on the right edge is the only affordance saying there is more - a
 * scrollbar is invisible on touch.
 */
.spot-scroll { position: relative; border-top: 1px solid var(--rule); }
.spot-scroll::after {
  content: ""; position: absolute; right: 0; top: 0; bottom: 0; width: 28px;
  background: linear-gradient(to right, rgba(255,255,255,0), var(--surface));
  pointer-events: none;
}
.spot-tabs {
  display: flex; gap: var(--s2); overflow-x: auto; scroll-snap-type: x proximity;
  padding: var(--s2) var(--s5) var(--s2) 0; scrollbar-width: none;
}
.spot-tabs::-webkit-scrollbar { display: none; }
.spot-tab {
  scroll-snap-align: start; flex: none;
  font: 500 14px/1 var(--sans);
  background: var(--surface); color: var(--ink-2);
  border: 1px solid var(--rule); border-radius: 999px;
  padding: 0 14px; height: 38px; cursor: pointer;
}
.spot-tab:hover { border-color: var(--rule-strong); color: var(--ink); }
.spot-tab[aria-selected="true"] { background: var(--ink); border-color: var(--ink); color: var(--ink-invert); }

/* ---------------------------------------------------------- section nav */

.sectionnav-scroll { position: relative; border-top: 1px solid var(--rule); }
.sectionnav-scroll::after {
  content: ""; position: absolute; right: 0; top: 0; bottom: 0; width: 24px;
  background: linear-gradient(to right, rgba(255,255,255,0), var(--surface));
  pointer-events: none;
}
.sectionnav {
  display: flex; gap: var(--s1); overflow-x: auto; scrollbar-width: none;
  padding: 5px var(--s5) 5px 0;
}
.sectionnav::-webkit-scrollbar { display: none; }
.sectionnav a {
  flex: none; text-decoration: none; white-space: nowrap;
  font: 500 13px/1 var(--sans); color: var(--ink-3);
  padding: 9px 10px; border-radius: var(--radius);
  border-bottom: 2px solid transparent;
}
.sectionnav a:hover { color: var(--ink); background: var(--surface-warm); }
/* Scroll-spy: the section you are actually looking at. */
.sectionnav a[aria-current="true"] {
  color: var(--ink); border-bottom-color: var(--accent);
}

/* ------------------------------------------------------------ spot head */

.spot-head { padding-top: var(--s5); }
/* On a phone the sticky bar already carries the spot name in serif, so the
   h1 is for the outline and the screen reader, not for the eye. */
@media (max-width: 899px) {
  .spot-head { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
  .hero { margin-top: var(--s4); }
}
.spot-title {
  font: 600 26px/1.15 var(--serif); letter-spacing: -0.02em;
}
.spot-sub { margin: 3px 0 0; font: 400 13.5px/1.4 var(--sans); color: var(--ink-3); }
@media (min-width: 560px) { .spot-title { font-size: 32px; } }

/* Anchor targets clear the sticky picker rather than hiding under it. */
.section-anchor { scroll-margin-top: 72px; }
@media (min-width: 900px) { .section-anchor { scroll-margin-top: 172px; } }

/* ------------------------------------------------------------------ now */

/*
 * "Should I go?" answered before any scrolling. On a Fold cover screen this
 * is most of the first screen, and deliberately the only thing competing
 * for attention there.
 */
/*
 * Three things, in the order they are the answer: the number, today as a
 * strip, the window. Everything the old card also carried - confidence,
 * spread, model count - is one tap away in the day list.
 */
.hero {
  margin-top: var(--s3);
  background: var(--surface); border: 1px solid var(--rule);
  border-left: 4px solid var(--rule-strong); border-radius: var(--radius);
  padding: var(--s4);
}
.hero-top { display: flex; align-items: center; gap: var(--s4); }
.hero-figure { display: flex; align-items: baseline; gap: 6px; flex: none; }
.hero-value { font: 500 44px/1 var(--mono); font-variant-numeric: tabular-nums; letter-spacing: -0.03em; }
.hero-unit { font: 500 14px/1 var(--sans); color: var(--ink-3); }
.hero-figure .now-arrow { align-self: center; }
.hero-words { min-width: 0; }
.hero-verdict { font: 400 15px/1.3 var(--sans); color: var(--ink-2); }
.hero-verdict b { font-weight: 600; color: var(--ink); }
.hero-facts { display: flex; flex-wrap: wrap; gap: 4px var(--s3); margin-top: 5px; font-size: 13px; color: var(--ink-2); align-items: center; }
.hero-kite { font: inherit; background: none; border: 0; padding: 0; color: var(--accent-ink); cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
.hero-kite b { font-weight: 600; }
.hero-when { color: var(--ink-3); font-size: 12px; flex-basis: 100%; }
.now-empty { color: var(--ink-3); font-size: 14px; }

/* Today, hour by hour. 24 cells in one row; night dimmed; now ringed. */
.strip { display: grid; grid-template-columns: repeat(24, 1fr); gap: 2px; margin-top: var(--s4); height: 22px; }
.strip-cell { display: block; border: 0; padding: 0; border-radius: 2px; background: var(--surface-warm); cursor: pointer; min-width: 0; }
.strip-cell.is-night { opacity: .45; }
.strip-cell.is-past:not(.is-now) { opacity: .5; }
.strip-cell.is-now { box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--ink); position: relative; z-index: 1; }
span.strip-cell { cursor: default; }
.strip-ticks { position: relative; height: 14px; margin-top: 3px; font: 400 10.5px/1 var(--mono); color: var(--ink-3); }
.strip-ticks span { position: absolute; top: 0; transform: translateX(0); }

.hero-window { margin-top: var(--s3); font-size: 14px; color: var(--ink-2); display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; }
.hero-window b { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.hero-go { font: 500 12.5px/1 var(--sans); background: none; border: 1px solid var(--accent-rule); color: var(--accent-ink); border-radius: 999px; padding: 6px 10px; cursor: pointer; margin-left: auto; }
.hero-go:hover { background: var(--accent-wash); }

@media (min-width: 560px) {
  .hero { padding: var(--s5); }
  .hero-value { font-size: 52px; }
  .strip { height: 26px; }
}

/* -------------------------------------------------------------- sections */

.section { margin-top: var(--section-gap); }
.section-head {
  display: flex; align-items: baseline; gap: var(--s3);
  padding-bottom: var(--s2); margin-bottom: var(--s3);
  border-bottom: 1px solid var(--rule-strong); flex-wrap: wrap;
}
.section-title { font: 600 18px/1.2 var(--serif); letter-spacing: -0.015em; }
@media (min-width: 560px) { .section-title { font-size: 21px; } }
.eyebrow { font: 400 12.5px/1.4 var(--sans); color: var(--ink-3); }
.section-head .spacer { margin-left: auto; }

.note { font: 400 12.5px/1.5 var(--sans); color: var(--ink-3); margin: var(--s2) 0 0; }

.empty {
  padding: var(--s5); background: var(--surface);
  border: 1px solid var(--rule); border-left: 3px solid var(--accent-rule);
  border-radius: var(--radius);
}
.empty h3 { font: 600 16px/1.3 var(--sans); margin-bottom: 6px; }
.empty p { margin: 0; color: var(--ink-2); font-size: 14.5px; max-width: 70ch; }

/* ----------------------------------------------------------- live meters */

/*
 * Ten full-width cards with a chart each used to bury the forecast under
 * roughly 1300px of scrolling on a phone. These are small tappable meters;
 * the detail, including the big chart, is one tap away in a sheet.
 */
.meters {
  display: flex; gap: var(--s2); overflow-x: auto;
  padding-bottom: var(--s2); scroll-snap-type: x proximity; scrollbar-width: thin;
}
.meter {
  scroll-snap-align: start; flex: none; width: 148px;
  display: block; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--rule);
  border-left: 3px solid var(--rule-strong);
  border-radius: var(--radius); padding: var(--s3);
  transition: border-color .12s, box-shadow .12s;
}
.meter:hover { border-color: var(--rule-strong); box-shadow: var(--shadow-card); }
.meter:hover .meter-name { color: var(--ink); }
.meter-name {
  font: 500 12.5px/1.25 var(--sans); color: var(--ink-2);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-height: 2.5em;
}
.meter-figure { display: flex; align-items: baseline; gap: 5px; margin-top: 6px; }
.meter-value { font: 500 24px/1 var(--mono); font-variant-numeric: tabular-nums; }
.meter-unit { font: 400 11px/1 var(--sans); color: var(--ink-3); }
.meter-sub { font: 400 11.5px/1.3 var(--sans); color: var(--ink-3); margin-top: 3px; }
.meter.is-stale .meter-value { color: var(--ink-3); }
.meter-spark { margin-top: var(--s2); height: 30px; }
.meter-more { font: 500 11px/1 var(--sans); color: var(--accent); margin-top: var(--s2); }

@media (min-width: 860px) {
  .meters { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); overflow: visible; }
  .meter { width: auto; }
}

/* --------------------------------------------------------- station sheet */

.sheet-backdrop {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(20,23,26,.42);
  display: flex; align-items: flex-end; justify-content: center;
}
@media (min-width: 700px) { .sheet-backdrop { align-items: center; padding: var(--s5); } }

.sheet {
  background: var(--surface); width: 100%; max-height: 92vh; overflow-y: auto;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--shadow-pop); padding: var(--s4) var(--s4) var(--s6);
}
@media (min-width: 700px) {
  .sheet { max-width: 720px; border-radius: var(--radius-lg); padding: var(--s6); max-height: 88vh; }
}

.sheet-head { display: flex; align-items: flex-start; gap: var(--s3); margin-bottom: var(--s3); }
.sheet-title { font: 600 19px/1.25 var(--sans); }
.sheet-kind { font: 400 12.5px/1.4 var(--sans); color: var(--ink-3); margin-top: 2px; }
.sheet-close {
  margin-left: auto; flex: none;
  width: var(--tap); height: var(--tap); border-radius: 50%;
  border: 1px solid var(--rule); background: var(--surface);
  color: var(--ink-2); font-size: 20px; line-height: 1; cursor: pointer;
}
.sheet-close:hover { background: var(--surface-warm); color: var(--ink); }

.sheet-figure { display: flex; align-items: baseline; gap: 7px; }
.sheet-value { font: 500 38px/1 var(--mono); font-variant-numeric: tabular-nums; }
.sheet-unit { font: 500 14px/1 var(--sans); color: var(--ink-3); }
.sheet-meta { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4); font-size: 13px; color: var(--ink-2); margin-top: var(--s2); }

.sheet-facts { display: grid; grid-template-columns: auto 1fr; gap: 4px var(--s4); font-size: 13px; margin: var(--s4) 0 0; }
.sheet-facts dt { color: var(--ink-3); }
.sheet-facts dd { margin: 0; font-family: var(--mono); font-size: 12.5px; }

.sheet-links { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s4); }
.sheet-links a {
  font: 500 12.5px/1 var(--sans); text-decoration: none;
  border: 1px solid var(--accent-rule); color: var(--accent-ink); background: var(--accent-wash);
  padding: 10px 12px; border-radius: var(--radius);
}
.sheet-links a:hover { background: var(--accent); color: #fff; border-color: var(--accent); }

.sheet-table-toggle {
  margin-top: var(--s4); font: 500 13px/1 var(--sans);
  background: none; border: 0; color: var(--accent-ink); cursor: pointer;
  padding: 10px 0; text-decoration: underline; text-underline-offset: 3px;
}
.sheet-table { margin-top: var(--s3); max-height: 260px; overflow-y: auto; border: 1px solid var(--rule); border-radius: var(--radius); }

/* ------------------------------------------------------------------ chart */

.chart { margin-top: var(--s4); }
.chart-readout {
  display: flex; align-items: baseline; gap: var(--s4); flex-wrap: wrap;
  min-height: 22px; margin-bottom: var(--s2);
  font: 400 13px/1 var(--sans); color: var(--ink-2);
}
.chart-readout .when { font-family: var(--mono); color: var(--ink); font-weight: 500; }
.chart-readout .pair { display: inline-flex; align-items: center; gap: 6px; }
.chart-readout .pair i { width: 14px; height: 0; border-top: 2px solid currentColor; }
.chart-readout .pair .v { font-family: var(--mono); font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 500; }
.chart-readout .hint { color: var(--ink-3); margin-left: auto; }

.chart-plot { position: relative; touch-action: pan-y; }
.chart-plot svg { display: block; width: 100%; height: auto; }

.c-grid   { stroke: var(--rule); stroke-width: 1; vector-effect: non-scaling-stroke; }
.c-day    { stroke: var(--rule-strong); stroke-width: 1; vector-effect: non-scaling-stroke; }
.c-good   { stroke: var(--ok); stroke-width: 1; stroke-dasharray: 3 3; opacity: .6; vector-effect: non-scaling-stroke; }
.c-axis   { fill: var(--ink-3); font: 400 10px var(--sans); }
.c-wind   { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.c-gust   { fill: none; stroke: #9CBBD0; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.c-cross  { stroke: var(--ink); stroke-width: 1; vector-effect: non-scaling-stroke; opacity: .45; }
.c-dot    { fill: var(--accent); stroke: var(--surface); stroke-width: 1.5; }
.c-dot-gust { fill: #9CBBD0; stroke: var(--surface); stroke-width: 1.5; }
.c-barb   { stroke: var(--ink-3); stroke-width: 1.2; vector-effect: non-scaling-stroke; }

.chart-key { display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap; font: 400 12px/1 var(--sans); color: var(--ink-2); margin-top: var(--s2); }
.chart-key span { display: inline-flex; align-items: center; gap: 6px; }
.chart-key i { width: 16px; height: 0; border-top-width: 2px; border-top-style: solid; }
.chart-key i.k-wind { border-color: var(--accent); }
.chart-key i.k-gust { border-color: #9CBBD0; }
.chart-key i.k-good { border-color: var(--ok); border-top-style: dotted; }

/* The compact trace inside a meter. Same data, no interaction. */
.spark-svg { display: block; width: 100%; height: 30px; overflow: visible; }
.spark-wind { fill: none; stroke: var(--accent); stroke-width: 1.5; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.spark-gust { fill: none; stroke: #9CBBD0; stroke-width: 1; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.spark-good { stroke: var(--ok); stroke-width: 1; stroke-dasharray: 2 3; opacity: .5; vector-effect: non-scaling-stroke; }
.spark-base { stroke: var(--rule); stroke-width: 1; vector-effect: non-scaling-stroke; }
.spark-day  { stroke: var(--rule-strong); stroke-width: 1; opacity: .7; vector-effect: non-scaling-stroke; }
.spark-now  { fill: var(--accent); }
.spark-empty { font: 400 11px/30px var(--sans); color: var(--ink-3); text-align: center; }

/* -------------------------------------------------------------- day view */

/*
 * The narrow-screen forecast. A 168-column table on a 390px phone is a
 * horizontal-scrolling maze; this is the same data as a vertical list, one
 * day at a time, which is how a phone wants to read it.
 */
.day-scroll { position: relative; }
.day-scroll::after {
  content: ""; position: absolute; right: 0; top: 0; bottom: var(--s2); width: 24px;
  background: linear-gradient(to right, rgba(247,246,242,0), var(--paper));
  pointer-events: none;
}
.day-tabs { display: flex; gap: var(--s2); overflow-x: auto; scrollbar-width: none; padding-bottom: var(--s2); }
.day-tabs::-webkit-scrollbar { display: none; }
.day-tab {
  flex: none; background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: 7px 12px; cursor: pointer;
  font: 500 13px/1.3 var(--sans); color: var(--ink-2);
  min-height: var(--tap); text-align: center;
}
.day-tab[aria-selected="true"] { background: var(--ink); border-color: var(--ink); color: var(--ink-invert); }
.day-tab .dt-day { display: block; font-size: 13px; }
.day-tab .dt-peak { display: inline-block; font: 500 11px/1 var(--mono); margin-top: 4px; padding: 3px 6px; border-radius: 2px; min-width: 26px; }

.hour-list {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); overflow: hidden;
  /* Vertical scrolling stays with the page; horizontal is ours, for the
     swipe-between-days gesture. */
  touch-action: pan-y;
}
.hour-row {
  display: grid; align-items: center; gap: var(--s2);
  grid-template-columns: 44px 56px 1fr;
  padding: 6px var(--s3); border-bottom: 1px solid var(--rule); min-height: 46px;
  cursor: pointer;
}
.hour-row.is-past { opacity: .6; }
.hour-row.is-focus { box-shadow: inset 3px 0 0 var(--accent); }
.hour-row.is-open { background: var(--surface-sunk); }
.hour-row.is-open.is-now { background: var(--accent-wash); }
.h-kite { display: none; }
@media (min-width: 620px) {
  .hour-row { grid-template-columns: 52px 62px minmax(0, 1fr) 62px; }
  .h-kite { display: block; text-align: right; }
}

/* The rest of an hour, on tap. Spans every column. */
.h-more { grid-column: 1 / -1; padding: 4px 0 6px; display: grid; gap: 6px; }
.h-more-facts { display: flex; flex-wrap: wrap; gap: 4px var(--s4); font-size: 12.5px; color: var(--ink-2); }
.h-more-facts small { color: var(--ink-3); font-size: 11.5px; }
.h-more-facts b { font-weight: 500; color: var(--ink); font-family: var(--mono); }
.h-more-models { display: flex; flex-wrap: wrap; gap: 6px; }
.h-model { font: 400 11.5px/1 var(--mono); background: var(--surface-warm); border-radius: 2px; padding: 5px 7px; color: var(--ink-2); }
.h-model b { font-weight: 500; color: var(--ink); }

/* Night hours, folded to one row per stretch. */
.night-fold {
  width: 100%; display: flex; align-items: center; gap: var(--s3);
  background: var(--surface-sunk); border: 0; border-bottom: 1px solid var(--rule);
  padding: 0 var(--s3); min-height: 40px; cursor: pointer; text-align: left;
  font: 400 12.5px/1 var(--sans); color: var(--ink-3);
}
.night-fold .nf-label { font-weight: 500; color: var(--ink-2); }
.night-fold .nf-span { font-family: var(--mono); }
.night-fold .nf-peak { margin-left: auto; font-family: var(--mono); }
.night-fold .nf-chev { transition: transform .15s; }
.night-fold.is-open .nf-chev { transform: rotate(180deg); }
.night-group .hour-row { background: var(--surface-sunk); }
.hour-row:last-child { border-bottom: 0; }
.hour-row.is-now { background: var(--accent-wash); }
.hour-row.is-night { background: var(--surface-sunk); }
.hour-row.is-night .h-time, .hour-row.is-night .h-detail { color: var(--ink-3); }

.h-time { font: 500 13px/1 var(--mono); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.h-wind { font: 500 15px/1 var(--mono); font-variant-numeric: tabular-nums; text-align: center; border-radius: 3px; padding: 7px 0; }
.h-detail { display: flex; align-items: center; gap: var(--s2); font-size: 12.5px; color: var(--ink-2); flex-wrap: wrap; }
.h-detail .h-dir { display: inline-flex; align-items: center; gap: 4px; }
.h-kite { font: 500 12px/1 var(--mono); color: var(--ink-3); }
.h-gust { font-family: var(--mono); font-size: 12px; }
.h-measured { font: 500 12px/1 var(--mono); color: var(--ink); border: 1.5px solid rgba(20,23,26,.5); border-radius: 3px; padding: 4px 5px; }
/*
 * A Fold opened is 884px - wide enough that the phone row leaves a lane of
 * dead space before the kite size. Spend it on confidence and spread rather
 * than stretching the gap.
 */
@media (max-width: 430px) {
  .hour-row { grid-template-columns: 40px 52px minmax(0, 1fr); gap: 6px; padding-inline: 10px; }
  .h-detail { gap: 6px; font-size: 12px; }
  .h-measured { padding: 3px 4px; font-size: 11.5px; }
}

.day-legend { display: flex; gap: var(--s3); flex-wrap: wrap; font-size: 12px; color: var(--ink-3); margin-top: var(--s2); }

.xs-on   { color: var(--ok);   font-weight: 500; }
.xs-off  { color: var(--bad);  font-weight: 500; }
.xs-side { color: var(--ink-2); }

/* ---------------------------------------------------------------- matrix */

.matrix-scroll { overflow-x: auto; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius); }
table.matrix {
  border-collapse: collapse; font-family: var(--mono); font-size: 13px;
  font-variant-numeric: tabular-nums; width: max-content; min-width: 100%;
}
table.matrix th, table.matrix td { padding: 0; text-align: center; white-space: nowrap; }

table.matrix th.row-label {
  position: sticky; left: 0; z-index: 3; background: var(--surface);
  border-right: 1px solid var(--rule-strong);
  box-shadow: 3px 0 5px -3px rgba(20,23,26,.16);
  text-align: left; font: 500 12px/1.2 var(--sans); color: var(--ink-2);
  padding: 0 12px 0 14px; min-width: 178px;
}
table.matrix tr.is-headline th.row-label { color: var(--ink); font-weight: 600; font-size: 13px; }
.row-label-inner { display: flex; align-items: center; gap: 7px; }
.row-label-inner .lbl { overflow: hidden; text-overflow: ellipsis; }

table.matrix th.day {
  font: 600 12px/1 var(--sans); letter-spacing: .04em; color: var(--ink-2);
  text-align: left; padding: 9px 10px; background: var(--surface-sunk);
  border-bottom: 1px solid var(--rule); border-left: 1px solid var(--rule-strong);
}
table.matrix th.hour {
  font: 400 11px/1 var(--mono); color: var(--ink-3);
  padding: 7px 0 8px; min-width: 30px; border-bottom: 1px solid var(--rule);
}
table.matrix th.hour.is-day-start { border-left: 1px solid var(--rule-strong); }
table.matrix th.hour.is-now { color: var(--accent-ink); font-weight: 600; }
table.matrix th.hour.is-night { color: #B3B8BF; }

table.matrix td { height: 26px; min-width: 30px; border-bottom: 1px solid var(--surface); }
table.matrix td.is-day-start { border-left: 1px solid var(--rule-strong); }
table.matrix tr.rule-above td, table.matrix tr.rule-above th { border-top: 1px solid var(--rule); }

td.wind { font-weight: 500; }
td.wind span { display: block; margin: 1px; padding: 4px 0; border-radius: 2px; }
tr.is-headline td.wind span { padding: 6px 0; font-size: 14px; }

td.plain { color: var(--ink-2); font-size: 12px; }
td.muted { color: var(--ink-3); font-size: 11px; }
td.is-now, th.hour.is-now { background: var(--accent-wash); }
td.is-night.plain, td.is-night.muted { color: var(--ink-3); opacity: .55; }
td.is-night.wind span { opacity: .5; }

/* Forecast cells are flat fills; measured cells are ringed. Same palette,
   deliberately different shape, so a column never reads as one kind. */
td.wind.is-measured span { box-shadow: inset 0 0 0 1.5px rgba(20,23,26,.55); margin: 2px 1px; }
td.err-over  { color: var(--bad); }
td.err-under { color: var(--accent-ink); }

.dir-arrow { display: inline-block; line-height: 1; color: var(--ink-2); }
.conf-high { color: var(--ok); }
.conf-med  { color: var(--warn); }
.conf-low  { color: var(--bad); }

.matrix-foot {
  display: flex; gap: var(--s4); align-items: center; flex-wrap: wrap;
  padding: var(--s3) 2px 0; font-size: 12.5px; color: var(--ink-3);
}

/* --------------------------------------------------------- source button */

.src-btn {
  flex: none; position: relative;
  width: 16px; height: 16px; border-radius: 50%;
  border: 1px solid var(--rule-strong); background: var(--surface); color: var(--ink-3);
  font: 600 10px/1 var(--sans); cursor: pointer; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
/* The painted dot is 16px; the thing a finger has to hit is 44. */
.src-btn::after { content: ""; position: absolute; inset: -14px; }
.src-btn:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-wash); }
.src-btn[aria-expanded="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }

/* --------------------------------------------------------------- popover */

.pop {
  position: absolute; z-index: 220;
  width: min(400px, calc(100vw - 24px));
  background: var(--surface); border: 1px solid var(--rule-strong);
  border-radius: var(--radius); box-shadow: var(--shadow-pop);
  font-family: var(--sans); padding: var(--s4) var(--s5);
}
.pop h4 { font: 600 15px/1.3 var(--sans); margin: 0 0 3px; }
.pop .pop-kind { font-size: 12px; color: var(--ink-3); margin-bottom: 11px; text-transform: uppercase; letter-spacing: .05em; }
.pop dl { margin: 0 0 11px; display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 13px; }
.pop dt { color: var(--ink-3); }
.pop dd { margin: 0; color: var(--ink); }
.pop p { margin: 0 0 10px; font-size: 13.5px; line-height: 1.5; color: var(--ink-2); }
.pop p.caveat { background: var(--warn-wash); border-left: 2px solid var(--warn); padding: 8px 11px; color: var(--ink-2); border-radius: 0 2px 2px 0; }
.pop .pop-links { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s3); }
.pop .pop-links a {
  font-size: 12.5px; font-weight: 500; text-decoration: none;
  border: 1px solid var(--accent-rule); color: var(--accent-ink); background: var(--accent-wash);
  padding: 9px 11px; border-radius: var(--radius);
}
.pop .pop-links a:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
.pop .pop-close {
  position: absolute; top: 4px; right: 4px; width: 36px; height: 36px;
  background: none; border: 0; cursor: pointer;
  color: var(--ink-3); font-size: 17px; line-height: 1; border-radius: 2px;
}
.pop .pop-close:hover { background: var(--surface-warm); color: var(--ink); }

.tip {
  position: absolute; z-index: 230; pointer-events: none;
  background: var(--ink); color: var(--ink-invert); border-radius: var(--radius);
  padding: 9px 11px; font: 400 12.5px/1.45 var(--sans);
  max-width: 280px; box-shadow: 0 4px 14px rgba(20,23,26,.22);
}
.tip .tip-head { font-family: var(--mono); font-size: 12px; color: #C9D4DC; margin-bottom: 4px; }
.tip .tip-row { display: flex; justify-content: space-between; gap: 14px; }
.tip .tip-row span:last-child { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------- map */

.map-layout { display: grid; gap: var(--s4); }
@media (min-width: 1000px) { .map-layout { grid-template-columns: minmax(0, 1fr) 260px; align-items: start; } }

.map-frame { background: #DCE9F0; border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden; margin-inline: auto; }
.map-frame svg { display: block; width: 100%; height: auto; }

.map-land   { fill: #F0EDE4; stroke: #C6C0B0; stroke-width: 0.6; }
.map-water  { fill: #DCE9F0; stroke: #C6C0B0; stroke-width: 0.4; }
.map-graticule { stroke: rgba(20,23,26,.07); stroke-width: 0.4; fill: none; }
.field-arrow { stroke: #3E7C9E; stroke-width: 0.7; fill: none; opacity: .55; }
.field-head  { fill: #3E7C9E; opacity: .55; }
.map-pin    { fill: var(--ink); }
.map-leader { stroke: var(--ink-3); stroke-width: 0.5; stroke-dasharray: 1.5 1.5; }
.map-spot { cursor: pointer; }
.map-spot rect.tile { stroke: rgba(20,23,26,.35); stroke-width: 0.5; fill: var(--surface); }
.map-spot:hover rect.tile { stroke: var(--ink); stroke-width: 1.1; }
.map-spot.is-selected rect.tile { stroke: var(--ink); stroke-width: 1.4; }
.map-wind { font: 500 7px/1 var(--mono); font-variant-numeric: tabular-nums; dominant-baseline: middle; }
.map-label { font: 500 5.4px/1 var(--sans); fill: var(--ink-2); paint-order: stroke; stroke: rgba(255,255,255,.85); stroke-width: 1.6px; }
.map-spot.is-selected .map-label { fill: var(--ink); font-weight: 600; }
.map-scale { font: 400 5px/1 var(--sans); fill: var(--ink-3); }
.map-scale-bar { stroke: var(--ink-2); stroke-width: 0.7; }

.map-key { display: grid; gap: var(--s3); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
@media (min-width: 1000px) { .map-key { grid-template-columns: 1fr; } }
.key-block { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius); padding: var(--s3); }
.key-block--explain { display: none; }
@media (min-width: 700px) { .key-block--explain { display: block; } }
.key-block h3 { font: 600 11px/1 var(--sans); text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3); margin-bottom: var(--s2); }
.key-row { display: flex; align-items: center; gap: var(--s2); font-size: 12.5px; padding: 3px 0; }
.key-swatch { width: 24px; height: 13px; border-radius: 2px; flex: none; border: 1px solid rgba(20,23,26,.12); }
.key-row .kn { font-family: var(--mono); font-size: 11.5px; color: var(--ink); font-variant-numeric: tabular-nums; min-width: 42px; }
.key-row .what { color: var(--ink-3); font-size: 11.5px; }

/* --------------------------------------------------------------- tables */

table.data { width: 100%; border-collapse: collapse; background: var(--surface); font-size: 13.5px; }
table.data th, table.data td { text-align: left; padding: 11px 14px; border-bottom: 1px solid var(--rule); }
table.data th {
  font: 500 11.5px/1 var(--sans); text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3); background: var(--surface-sunk);
}
table.data td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
table.data tr:last-child td { border-bottom: 0; }

.pill { display: inline-flex; align-items: center; gap: 6px; font: 500 12px/1 var(--sans); padding: 5px 9px; border-radius: 999px; }
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill.is-ok   { background: var(--ok-wash);   color: var(--ok); }
.pill.is-warn { background: var(--warn-wash); color: var(--warn); }
.pill.is-bad  { background: var(--bad-wash);  color: var(--bad); }
.pill.is-idle { background: var(--surface-warm); color: var(--ink-3); }

/* ----------------------------------------------------------- status page */

.stat-grid { display: grid; gap: var(--s3); grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.stat { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius); padding: var(--s4); }
.stat .stat-label { font: 500 11.5px/1 var(--sans); text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3); }
.stat .stat-value { font: 500 25px/1.15 var(--mono); font-variant-numeric: tabular-nums; margin: 8px 0 3px; }
.stat .stat-sub { font-size: 12.5px; color: var(--ink-3); }
.stat.is-ok { border-left: 3px solid var(--ok); }
.stat.is-warn { border-left: 3px solid var(--warn); }
.stat.is-bad { border-left: 3px solid var(--bad); }

.source-grid { display: grid; gap: var(--s3); grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.source-card { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius); padding: var(--s4); display: flex; flex-direction: column; }
.source-card .sc-top { display: flex; align-items: baseline; gap: var(--s2); margin-bottom: 2px; flex-wrap: wrap; }
.source-card h3 { font: 600 15.5px/1.25 var(--sans); }
.source-card .sc-tag { font: 500 11px/1 var(--mono); padding: 3px 6px; border-radius: 2px; background: var(--surface-warm); color: var(--ink-2); white-space: nowrap; }
.source-card .sc-tag.is-blend { background: var(--accent-wash); color: var(--accent-ink); }
.source-card .sc-agency { font-size: 12.5px; color: var(--ink-3); margin-bottom: var(--s3); }
.source-card dl { display: grid; grid-template-columns: auto 1fr; gap: 3px var(--s3); font-size: 12.5px; margin: 0 0 var(--s3); }
.source-card dt { color: var(--ink-3); }
.source-card dd { margin: 0; font-family: var(--mono); font-size: 12px; }
.source-card p { font-size: 13.5px; line-height: 1.5; color: var(--ink-2); margin: 0 0 var(--s3); }
.source-card .sc-links { margin-top: auto; display: flex; gap: var(--s2); flex-wrap: wrap; }
.source-card .sc-links a {
  font-size: 12.5px; font-weight: 500; text-decoration: none; padding: 9px 11px;
  border-radius: var(--radius); border: 1px solid var(--accent-rule);
  color: var(--accent-ink); background: var(--accent-wash);
}
.source-card .sc-links a:hover { background: var(--accent); color: #fff; border-color: var(--accent); }

.backlink { margin: var(--s4) 0 0; font: 500 13px/1 var(--sans); }
.backlink a { text-decoration: none; color: var(--ink-3); }
.backlink a:hover { color: var(--accent-ink); }

/* ----------------------------------------------------------------- prose */

.prose { max-width: 70ch; }
.prose h2 { font: 600 22px/1.25 var(--serif); margin: var(--s8) 0 var(--s3); letter-spacing: -0.02em; }
.prose h3 { font: 600 16px/1.3 var(--sans); margin: var(--s6) 0 var(--s2); }
.prose p { margin: 0 0 var(--s3); font-size: 16px; line-height: 1.65; color: var(--ink-2); }
.prose p.lead { font-size: 18px; line-height: 1.55; color: var(--ink); }
.prose ul, .prose ol { margin: 0 0 var(--s4); padding-left: 22px; }
.prose li { margin-bottom: 7px; font-size: 15.5px; line-height: 1.6; color: var(--ink-2); }
.prose strong { color: var(--ink); font-weight: 600; }
.prose code { font: 400 13.5px/1 var(--mono); background: var(--surface-warm); padding: 2px 5px; border-radius: 2px; color: var(--ink); }
.prose .callout {
  background: var(--surface); border: 1px solid var(--rule); border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0; padding: var(--s4); margin: 0 0 var(--s4);
}
.prose .callout p:last-child { margin-bottom: 0; }
@media (min-width: 560px) { .prose h2 { font-size: 26px; } .prose p { font-size: 16.5px; } }

.flow { display: grid; gap: var(--s2); margin: 0 0 var(--s5); }
.flow-step {
  display: grid; grid-template-columns: 30px 1fr; gap: var(--s3);
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: var(--s3) var(--s4);
}
.flow-step .n {
  font: 500 12.5px/1 var(--mono); color: var(--accent-ink); background: var(--accent-wash);
  border-radius: 2px; display: flex; align-items: center; justify-content: center; height: 24px;
}
.flow-step h3 { font: 600 15px/1.3 var(--sans); margin: 2px 0 4px; }
.flow-step p { margin: 0; font-size: 14px; line-height: 1.55; color: var(--ink-2); }

.weight-field { display: flex; align-items: center; gap: var(--s2); font-size: 12.5px; color: var(--ink-3); }
.weight-field input {
  font: 500 13px/1 var(--mono); width: 60px; padding: 10px 8px; text-align: right;
  border: 1px solid var(--rule-strong); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
}

/* ---------------------------------------------------------------- footer */

.footer { margin-top: var(--s9); border-top: 1px solid var(--rule-strong); background: var(--surface); }
.footer-inner { display: grid; gap: var(--s5); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); padding: var(--s6) 0 var(--s7); }
.footer h3 { font: 600 11.5px/1 var(--sans); text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3); margin-bottom: var(--s2); }
.footer ul { margin: 0; padding: 0; list-style: none; }
.footer li { font-size: 13px; line-height: 1.6; color: var(--ink-2); margin-bottom: 6px; }
@media (max-width: 899px) { .footer-inner { padding: var(--s5) 0; gap: var(--s4); } .footer li { font-size: 12.5px; } }
.footer .colophon {
  border-top: 1px solid var(--rule); padding: var(--s3) 0 var(--s6);
  font-size: 12.5px; color: var(--ink-3);
  display: flex; justify-content: space-between; gap: var(--s3); flex-wrap: wrap;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ------------------------------------------------------------- loading */

/*
 * Skeletons hold the shape of what is coming so the page does not jump when
 * it lands. Only for a FIRST load - a refresh keeps the previous render,
 * because replacing good data with grey boxes every five minutes would be
 * worse than a number a few seconds old.
 */
.skel-wrap { display: grid; gap: var(--s2); }
.skel {
  background: var(--surface-warm);
  border-radius: var(--radius);
  animation: skel-pulse 1.4s ease-in-out infinite;
}
.skel-now { height: 44px; width: min(280px, 70%); }
.skel-row { height: 34px; }

@keyframes skel-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }

.retry-btn {
  margin-top: var(--s3);
  font: 500 13px/1 var(--sans);
  background: var(--surface); color: var(--accent-ink);
  border: 1px solid var(--accent-rule); border-radius: var(--radius);
  padding: 11px 14px; cursor: pointer; min-height: var(--tap);
}
.retry-btn:hover { background: var(--accent); color: #fff; border-color: var(--accent); }

/* -------------------------------------------------------------- tab bar */

/*
 * Phone navigation. Five sections within a thumb's reach, marking the one
 * on screen. Replaces the section strip that sat under the spot chips,
 * which on a phone was the fifth stacked row before any content.
 */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  display: grid; grid-template-columns: repeat(5, 1fr);
  background: var(--surface); border-top: 1px solid var(--rule-strong);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.tabbar a {
  display: flex; align-items: center; justify-content: center;
  min-height: 52px; text-decoration: none;
  font: 500 12.5px/1 var(--sans); color: var(--ink-3);
  border-top: 2px solid transparent;
}
.tabbar a[aria-current="true"] { color: var(--ink); border-top-color: var(--accent); }
@media (min-width: 900px) { .tabbar { display: none; } }

/* --------------------------------------------------------- spot sheet */

.sheet-body { min-width: 0; }
.spot-group + .spot-group { margin-top: var(--s4); }
.spot-group-title { font: 600 11.5px/1 var(--sans); text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3); margin: 0 0 var(--s2); }
.spot-list { display: grid; gap: 4px; }
.spot-row {
  display: flex; align-items: center; gap: var(--s3); width: 100%;
  background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 8px 10px 8px 12px; min-height: var(--tap); cursor: pointer; text-align: left;
}
.spot-row:hover { border-color: var(--rule-strong); }
.spot-row.is-selected { border-color: var(--ink); box-shadow: inset 3px 0 0 var(--ink); }
.spot-row-name { min-width: 0; flex: 1; display: flex; flex-direction: column; line-height: 1.2; }
.spot-row-name b { font: 500 15px/1.2 var(--sans); color: var(--ink); }
.spot-row-name small { font-size: 11.5px; color: var(--ink-3); }
.spot-row-wind { display: flex; align-items: center; gap: 7px; flex: none; }
.spot-row-kn { font: 500 14px/1 var(--mono); font-variant-numeric: tabular-nums; min-width: 38px; text-align: center; padding: 7px 0; border-radius: 3px; }
.spot-row-kn.is-none { background: var(--surface-warm); color: var(--ink-3); }
.spot-row-xs { font: 500 11px/1 var(--mono); min-width: 38px; }
@media (min-width: 560px) { .spot-list { grid-template-columns: 1fr 1fr; } }

/* --------------------------------------------------------- menu sheet */

.menu-block + .menu-block { margin-top: var(--s5); }
.menu-title { font: 600 11.5px/1 var(--sans); text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3); margin: 0 0 var(--s2); }
.menu-block .weight-field { font-size: 14px; color: var(--ink-2); }
.menu-links { display: grid; gap: 4px; }
.menu-link {
  display: flex; flex-direction: column; gap: 2px; text-decoration: none;
  border: 1px solid var(--rule); border-radius: var(--radius); padding: 10px 12px;
  min-height: var(--tap);
}
.menu-link:hover { border-color: var(--rule-strong); }
.menu-link b { font: 500 14.5px/1.2 var(--sans); color: var(--ink); }
.menu-link span { font-size: 12.5px; color: var(--ink-3); }

/* ------------------------------------------------------- forecast graph */

.segmented--sm { padding: 2px; }
.segmented--sm button { font-size: 12.5px; padding: 6px 10px; min-height: 30px; }
.section-head .segmented--sm { flex: none; }

.fc-head { display: flex; align-items: center; gap: var(--s3); margin-bottom: var(--s2); flex-wrap: wrap; }
.fc-readout { flex-wrap: wrap; row-gap: 4px; }
.fc-readout .pair[hidden] { display: none; }
.fc-readout .fc-models { color: var(--ink-3); font-family: var(--mono); font-size: 12px; flex-basis: 100%; }
.c-night { fill: rgba(20,23,26,.045); }
.c-envelope { fill: rgba(20,85,127,.12); stroke: none; }
.c-measured { fill: none; stroke: var(--ink); stroke-width: 1.6; stroke-dasharray: 4 3; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.c-dot-measured { fill: var(--ink); stroke: var(--surface); stroke-width: 1.5; }
.c-now { stroke: var(--accent-ink); stroke-width: 1; stroke-dasharray: 2 2; vector-effect: non-scaling-stroke; }
.c-now-label { fill: var(--accent-ink); font-weight: 500; }
.c-axis-mid { text-anchor: middle; }
.chart-key i.k-envelope { height: 8px; border: 0; background: rgba(20,85,127,.18); }
.chart-key i.k-measured { border-color: var(--ink); border-top-style: dashed; }

/* --------------------------------------------------------- review 3 */

/* Masthead on the secondary pages: the page name sits where the spot
   button sits on the forecast page. */
.masthead-here { font: 600 15px/1.2 var(--serif); color: var(--ink-2); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (min-width: 900px) { .masthead-here { display: none; } }
.menu-link[aria-current="page"] { border-color: var(--ink); box-shadow: inset 3px 0 0 var(--ink); }

/* Hero: why chips, shoreline glyph, share, legend. */
.hero-top { position: relative; }
.hero-why { display: flex; flex-wrap: wrap; gap: 4px 6px; margin-top: 7px; align-items: center; }
.why-chip { font: 500 11.5px/1 var(--sans); padding: 5px 8px; border-radius: 999px; background: var(--surface-warm); color: var(--ink-2); }
.why-chip.is-good { background: var(--ok-wash); color: var(--ok); }
.why-chip.is-warn { background: var(--warn-wash); color: var(--warn); }
.why-when { font: 400 11.5px/1 var(--sans); color: var(--ink-3); margin-left: 2px; }
.hero-xs { display: inline-flex; align-items: center; gap: 5px; vertical-align: middle; }
.shore { display: inline-block; vertical-align: middle; border-radius: 3px; overflow: hidden; }
.shore-water { fill: #DCE9F0; }
.shore-land { fill: #E6E1D3; }
.hero-share {
  position: absolute; top: -4px; right: -4px;
  width: var(--tap); height: var(--tap); border-radius: 50%;
  background: none; border: 1px solid transparent; color: var(--ink-3);
  font-size: 17px; line-height: 1; cursor: pointer;
}
.hero-share:hover { background: var(--surface-warm); color: var(--ink); border-color: var(--rule); }
.strip-head { display: flex; align-items: baseline; gap: var(--s2); margin-top: var(--s4); font: 400 12.5px/1 var(--sans); color: var(--ink-3); }
.strip-head b { font-weight: 600; color: var(--ink-2); }
.hero .strip { margin-top: 6px; }
.band-legend { display: flex; flex-wrap: wrap; gap: 4px 10px; margin-top: var(--s3); font: 400 11px/1 var(--mono); color: var(--ink-3); }
.band-legend span { display: inline-flex; align-items: center; gap: 4px; }
.band-legend i { width: 12px; height: 8px; border-radius: 2px; border: 1px solid rgba(20,23,26,.1); }
.band-legend-unit { color: var(--ink-3); }

/* Spot sheet: tabs, star, ranked rows. */
.spot-tabs-row { margin-bottom: var(--s3); }
.spot-row { padding: 0; gap: 0; }
.spot-star {
  flex: none; width: 40px; align-self: stretch; border: 0; background: none; cursor: pointer;
  font-size: 16px; color: var(--ink-3); border-right: 1px solid var(--rule);
}
.spot-star.is-on { color: var(--warn); }
.spot-star:hover { background: var(--surface-warm); }
.spot-row-pick { flex: 1; display: flex; align-items: center; gap: var(--s3); min-width: 0; border: 0; background: none; padding: 8px 10px 8px 10px; text-align: left; cursor: pointer; min-height: var(--tap); }
.spot-row-span { font: 500 12px/1 var(--mono); color: var(--ink-2); }

/* Live: the spot's station leads, with the forecast against it. */
.meter.is-nearest { border-color: var(--ink); }
.meter-delta { display: flex; align-items: center; gap: 6px; margin-top: 6px; font: 400 11.5px/1 var(--sans); color: var(--ink-2); }
.meter-delta b { font: 500 12px/1 var(--mono); padding: 3px 6px; border-radius: 2px; }
.meter-delta.is-good b { background: var(--ok-wash); color: var(--ok); }
.meter-delta.is-warn b { background: var(--warn-wash); color: var(--warn); }
.meter-delta.is-bad b { background: var(--bad-wash); color: var(--bad); }
.meter-delta.is-plain { color: var(--ink-3); }

/* Accuracy: this run so far. */
.recent-error { background: var(--surface); border: 1px solid var(--rule); border-left: 3px solid var(--accent); border-radius: var(--radius); padding: var(--s4); margin-bottom: var(--s3); }
.recent-head { display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap; margin-bottom: var(--s3); }
.recent-head h3 { font: 600 15px/1.3 var(--sans); }
.stat-row { display: grid; gap: var(--s2); grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }
.stat-mini { display: flex; flex-direction: column; gap: 3px; background: var(--surface-sunk); border-radius: var(--radius); padding: 10px 12px; }
.stat-mini .stat-label { font: 500 10.5px/1 var(--sans); text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3); }
.stat-mini .stat-value { font: 500 19px/1.1 var(--mono); font-variant-numeric: tabular-nums; }
.stat-mini .stat-sub { font: 400 11.5px/1.2 var(--sans); color: var(--ink-3); }

/* Map: zoom buttons and the time scrubber. */
.map-frame { position: relative; touch-action: none; }
.map-frame svg { cursor: grab; }
.map-zoom { position: absolute; top: 8px; right: 8px; display: flex; flex-direction: column; gap: 4px; }
.map-zoom button {
  width: 34px; height: 34px; border-radius: var(--radius); border: 1px solid var(--rule-strong);
  background: var(--surface); color: var(--ink-2); font: 500 16px/1 var(--sans); cursor: pointer;
  box-shadow: var(--shadow-card);
}
.map-zoom button:hover { color: var(--ink); border-color: var(--ink); }
.map-time { display: flex; align-items: center; gap: var(--s3); margin-top: var(--s2); }
.map-play {
  flex: none; width: var(--tap); height: var(--tap); border-radius: 50%;
  border: 1px solid var(--rule-strong); background: var(--surface); color: var(--ink);
  font-size: 13px; cursor: pointer;
}
.map-play:hover { border-color: var(--ink); }
.map-time input[type=range] { flex: 1; min-width: 0; accent-color: var(--accent); height: var(--tap); }
.map-time-label { flex: none; font: 500 12.5px/1 var(--mono); color: var(--ink-2); min-width: 108px; text-align: right; }

/* Play buttons and the shared playhead. */
.play-btn {
  flex: none; width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid var(--rule-strong); background: var(--surface); color: var(--ink);
  font-size: 12px; cursor: pointer;
}
.play-btn:hover { border-color: var(--ink); }
.play-btn--sm { width: 28px; height: 28px; font-size: 10px; }
.strip-scrub { font: 500 12px/1 var(--mono); color: var(--accent-ink); }
.strip-back { font: 500 11.5px/1 var(--sans); background: none; border: 1px solid var(--accent-rule); color: var(--accent-ink); border-radius: 999px; padding: 4px 8px; cursor: pointer; margin-left: auto; }
.strip-back:hover { background: var(--accent-wash); }
.c-past { fill: none; stroke: var(--accent); stroke-width: 2; stroke-dasharray: 5 4; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; opacity: .75; }
.chart-key i.k-past { border-color: var(--accent); border-top-style: dashed; }
.spot-regions { margin-bottom: var(--s3); width: 100%; }
.spot-regions button { flex: 1; }

/* ---------------------------------------------------------- transport */

/* One control, everywhere the playhead can be driven. */
.transport {
  display: inline-flex; align-items: center; gap: 2px;
  background: var(--surface); border: 1px solid var(--rule-strong); border-radius: 999px;
  padding: 3px; max-width: 100%;
}
.transport.is-playing { border-color: var(--accent); }
.tp-btn {
  width: 36px; height: 36px; border-radius: 50%; border: 0; background: none;
  color: var(--ink-2); cursor: pointer; display: grid; place-items: center; flex: none;
}
.tp-btn:hover { background: var(--surface-warm); color: var(--ink); }
.tp-play { background: var(--ink); color: var(--ink-invert); }
.tp-play:hover { background: var(--accent-ink); color: var(--ink-invert); }
.transport.is-playing .tp-play { background: var(--accent); }
.tp-time { font: 500 12.5px/1 var(--mono); color: var(--ink-2); padding: 0 8px 0 6px; white-space: nowrap; min-width: 34px; }
.transport.is-scrubbed .tp-time { color: var(--accent-ink); }
.tp-now {
  font: 500 11.5px/1 var(--sans); background: var(--accent-wash); color: var(--accent-ink);
  border: 0; border-radius: 999px; padding: 7px 10px; cursor: pointer; margin-right: 3px; flex: none;
}
.tp-now:hover { background: var(--accent); color: #fff; }
.transport--compact .tp-btn { width: 30px; height: 30px; }
.transport--compact .tp-time { font-size: 12px; }
.transport--compact .tp-now { padding: 6px 9px; }

.playhead-badge {
  display: inline-block; margin-left: var(--s2); vertical-align: middle;
  font: 500 11.5px/1 var(--mono); color: var(--accent-ink); background: var(--accent-wash);
  border-radius: 999px; padding: 5px 8px;
}
.playhead-badge.is-playing { background: var(--accent); color: #fff; }
.playhead-badge[hidden] { display: none; }

/* The strip as a scrubber. */
.strip-head { justify-content: space-between; align-items: center; margin-top: var(--s4); }
.strip-day { font: 600 13px/1 var(--sans); color: var(--ink-2); }
.hero .strip { position: relative; cursor: ew-resize; touch-action: none; user-select: none; }
.strip-cell { pointer-events: none; }
.strip-cell.is-live { box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--ink); position: relative; z-index: 1; }
.strip-cell.is-at { box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--accent); position: relative; z-index: 2; }
.strip-cell.is-empty { background: var(--surface-warm); }
.strip-head-mark { position: absolute; top: -6px; width: 0; height: 0; transform: translateX(-5px); border: 5px solid transparent; border-top: 7px solid var(--accent); pointer-events: none; }
.strip-head-mark[hidden] { display: none; }
.hero.is-scrubbed { border-left-style: dashed; }

/* Live meters at the playhead. */
.meter.is-scrubbed { border-style: dashed; }
.meter.is-scrubbed.is-none .meter-value { color: var(--ink-3); }
.meter-arrow { display: inline-flex; align-items: center; }

.fc-head { align-items: center; }
.map-time { align-items: center; }

/* ------------------------------------------------------------- quieter */

.footer-line { margin: 0 0 var(--s3); font: 400 12.5px/1.6 var(--sans); color: var(--ink-3); }
.footer-line a { color: var(--ink-2); }
.footer-pages { padding-top: var(--s3); border-top: 1px solid var(--rule); }
.footer .shell { padding-top: var(--s5); padding-bottom: var(--s6); }
.meter { padding-bottom: var(--s3); }
.section-head { margin-bottom: var(--s3); }
.hero-why { margin-top: 8px; }

/* ----------------------------------------------------------- the dock */

/* One transport. Above the tab bar on a phone, in the picker on a laptop. */
.playdock {
  position: fixed; left: 0; right: 0; bottom: calc(52px + env(safe-area-inset-bottom, 0px)); z-index: 59;
  display: flex; justify-content: center; padding: 6px var(--gutter);
  background: linear-gradient(to top, var(--surface) 70%, rgba(255,255,255,0));
  pointer-events: none;
}
.playdock .transport { pointer-events: auto; box-shadow: var(--shadow-card); }
@media (min-width: 900px) { .playdock { display: none; } }
main.shell { padding-bottom: calc(118px + env(safe-area-inset-bottom, 0px)); }
@media (min-width: 900px) { main.shell { padding-bottom: 0; } }

.sectionnav-row { display: flex; align-items: center; gap: var(--s3); border-top: 1px solid var(--rule); }
.sectionnav-row .sectionnav-scroll { border-top: 0; flex: 1; min-width: 0; }
.picker-dock { flex: none; display: none; }
@media (min-width: 900px) { .picker-dock { display: block; } }

/* Transport, tightened: the time reads as a label, not a button. */
.tp-time { padding: 0 10px 0 8px; }
.transport--compact .tp-time { padding: 0 8px 0 6px; }

/* Hero strip head: the day, and the scrubbed hour when there is one. */
.strip-head { min-height: 22px; }
.strip-scrub { font: 500 12.5px/1 var(--mono); color: var(--accent-ink); }

/* Graph readout: one line, models on a second only where there is room. */
.fc-readout { flex-wrap: nowrap; overflow: hidden; }
.fc-main { display: inline-flex; gap: var(--s3); align-items: baseline; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.fc-readout .fc-models { display: none; flex-basis: auto; margin-left: auto; }
@media (min-width: 620px) { .fc-readout .fc-models { display: inline; } }
.fc-head { margin-bottom: var(--s2); }
.chart-key { font-size: 11.5px; }

.fc-readout .when { white-space: nowrap; flex: none; }

/* ------------------------------------------------------------ alerts */
.alert-switch { display: flex; align-items: center; gap: var(--s3); font-size: 14px; color: var(--ink); min-height: var(--tap); }
.alert-switch input { width: 20px; height: 20px; accent-color: var(--accent); }
.alert-spots { display: grid; grid-template-columns: 1fr 1fr; gap: 2px var(--s3); margin-top: var(--s2); }
.alert-spot { display: flex; align-items: center; gap: var(--s2); font-size: 13px; color: var(--ink-2); min-height: 32px; }
.alert-spot input { accent-color: var(--accent); }
.hero-swell { color: var(--ink-2); }
.hero-swell[hidden] { display: none; }

/* Our line. */
.c-corrected { fill: none; stroke: #7A4EAB; stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.c-dot-corrected { fill: #7A4EAB; stroke: var(--surface); stroke-width: 1.5; }
.chart-key i.k-corrected { border-color: #7A4EAB; }

/* ------------------------------------------------------ wind layers */
.map-heat { opacity: .82; image-rendering: auto; }
.map-particles { position: absolute; inset: 0; pointer-events: none; }
.map-frame { background: #CFE1EA; }
.map-land   { fill: #F3F0E8; stroke: #B9B3A3; stroke-width: 0.7; }
.field-arrow { stroke: #0E3E5C; stroke-width: 0.95; fill: none; opacity: .7; }
.field-head  { fill: #0E3E5C; opacity: .7; }
.map-spot rect.tile { stroke: rgba(20,23,26,.5); }
@media (prefers-reduced-motion: reduce) { .map-particles { display: none; } }

/* Tiles above the particles, with halos so they read on any shading. */
.map-top { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.map-top .map-spot { pointer-events: auto; cursor: pointer; }
.map-top .map-pin { fill: var(--ink); }
.map-spot rect.tile-halo { fill: rgba(255,255,255,.92); stroke: none; }
.map-spot rect.tile { stroke: rgba(20,23,26,.55); stroke-width: 0.6; }
.map-spot.is-selected rect.tile { stroke: var(--ink); stroke-width: 1.5; }
.map-wind { font: 600 7.6px/1 var(--mono); }
.map-label { font: 600 5.8px/1 var(--sans); fill: var(--ink); paint-order: stroke; stroke: rgba(255,255,255,.95); stroke-width: 2.4px; stroke-linejoin: round; }
.map-leader { stroke: var(--ink-2); stroke-width: 0.6; stroke-dasharray: 1.5 1.5; paint-order: stroke; }

/* Tide. */
.hero-tide { color: var(--ink-2); }
.hero-tide[hidden] { display: none; }
.c-tide { fill: none; stroke: #2F7D8C; stroke-width: 1.4; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.c-tide-area { fill: rgba(47,125,140,.16); stroke: none; }
.chart-key i.k-tide { border-color: #2F7D8C; }

/* ---------------------------------------------------------- sleeker */
/* The transport shows a time only when there is one to show. */
.transport:not(.is-scrubbed) .tp-time { display: none; }
/* Window line: the link sits inline, not on its own row. */
.hero-go { margin-left: 0; border: 0; padding: 0 2px; background: none; color: var(--accent-ink); text-decoration: underline dotted; text-underline-offset: 3px; font-size: 13.5px; }
.hero-go:hover { background: none; color: var(--ink); }
/* Readout labels: words on a laptop, a letter on a phone. */
.fc-readout .lbl-short { display: none; }
@media (max-width: 619px) {
  .fc-readout .lbl-long { display: none; }
  .fc-readout .lbl-short { display: inline; margin-right: 2px; color: var(--ink-3); }
  .fc-main { gap: 8px; }
}
.hero-why { margin-top: 7px; }
.hero-facts { margin-top: 4px; }
