/* GraySky - styles for the /forecast tool, blog, support/privacy/compare
   pages, and the Dark Sky alternative landing page.
   The marketing landing page (/) inlines its own styles in index.html.
   Top-nav and footer styles live in ./nav.css (imported below).
*/

@import url("./nav.css");

/* TOKENS:START site generated by scripts/sync-tokens.py from design/tokens.json — do not edit between markers, edit the JSON and re-run */
:root {
  /* Site core — every public page's chrome reads these. Pages that
     intentionally inline their CSS (roadmap.html) carry a generated
     mirror of the bg/ink/rule/bar subset; run scripts/sync-tokens.py
     after editing design/tokens.json and every copy updates together. */
  --bg: #ffffff;
  --bg-muted: #f6f6f6;
  --ink: #171717;
  --ink-2: color-mix(in oklab, var(--ink) 70%, transparent);
  --ink-3: color-mix(in oklab, var(--ink) 45%, transparent);
  --rule: #e6e6e6;
  --bar-bg: #000000;
  --bar-ink: #d6d6d6;
  --bar-ink-strong: #ffffff;
  --link: #1a73e8;
  --accent: #2f7bff;
  /* UV badges */
  --uv-low: #4caf50;
  --uv-mod: #ffc107;
  --uv-high: #ff9800;
  --uv-veryhigh: #f44336;
  --uv-extreme: #9c27b0;
  --rule-soft: rgba(127,127,127,0.06);
  --maxw: 1280px;
  --pad-x: clamp(16px, 4vw, 48px);

  /* Prose typography — long-form reading on .legal + .blog-post pages.
     Body sizes ride a fluid clamp (17→20px); headings use a modular
     scale relative to body so they breathe with the viewport. */
  --font-prose: "InterVariable", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --text-body: clamp(1.0625rem, 0.844rem + 0.610vw, 1.25rem);
  --text-small: 0.875em;
  --text-lead: 1.176em;
  --text-h4: 1em;
  --text-h3: 1.333em;
  --text-h2: 1.777em;
  --text-h1: 2.369em;
  --leading-body: 1.65;
  --leading-heading: 1.18;
  --measure: 68ch;
  --prose-text: #1a1a1a;
  --prose-muted: #5c5c5c;
  --prose-faint: #6a6a6a;
  --prose-rule: #e5e5e5;
  --prose-surface: #ffffff;
  --prose-page: #f9f9f9;
  --prose-code-bg: #f5f5f5;
  --prose-link: var(--link);
  --prose-shadow: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);

  /* System scales (radius / elevation / motion / stacking) — formalized
     2026-07 for new work. See design/STYLE-GUIDE.md for usage rules. */
  /* Corner ladder — see design/STYLE-GUIDE.md for the concentric-radius rule. */
  --radius-2: 2px;
  --radius-4: 4px;
  --radius-6: 6px;
  --radius-8: 8px;
  --radius-10: 10px;
  --radius-12: 12px;
  --radius-16: 16px;
  --radius-24: 24px;
  --radius-pill: 999px;
  /* Elevation tiers: card (resting) / chip (floating chrome) / pop (top-level dialogs). */
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.04), 0 2px 6px rgba(0, 0, 0, 0.04);
  --shadow-lift: 0 4px 8px rgba(0, 0, 0, 0.05), 0 12px 28px rgba(0, 0, 0, 0.07);
  --shadow-chip: 0 1px 4px rgba(0, 0, 0, 0.25);
  --shadow-pop: 0 12px 48px rgba(0, 0, 0, 0.28);
  /* Motion: fast = hover/press color, base = standard transitions, slow = sheet/drawer travel. */
  --dur-fast: 120ms;
  --dur-base: 150ms;
  --dur-slow: 380ms;
  --ease-sheet: cubic-bezier(0.32, 0.72, 0, 1);
  /* Stacking contract: in-page overlays < 100, topnav 100, top-level dialogs 200. */
  --z-drawer: 60;
  --z-overlay: 70;
  --z-nav: 100;
  --z-modal: 200;
  /* Weight ladder tuned for variable system fonts — see primitive.type. Use these over literal 500/600/700. */
  --w-normal: 400;
  --w-medium: 510;
  --w-semibold: 590;
  --w-bold: 680;
  /* Size-scaled tracking: display ≥28px, heading 18–28px, body = dense UI text only (never prose), caps = uppercase micro-labels. */
  --track-display: -0.022em;
  --track-heading: -0.012em;
  --track-body: -0.011em;
  --track-caps: 0.06em;
  /* Flat surface ladder — depth from solid color steps, per the house no-borders/no-gradients rule. 0 = card/page white, 1 = raised-page tint (= prose page bg), 2 = muted section, 3 = deepest inset (wells, pills). */
  --surface-0: #ffffff;
  --surface-1: #f9f9f9;
  --surface-2: #f6f6f6;
  --surface-3: #f2f2f2;
  --ease-out: cubic-bezier(0.215, 0.61, 0.355, 1);
}
/* TOKENS:END site */

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font: 400 16px/1.45 var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif);
  color: var(--ink);
  background: var(--bg);
  font-feature-settings: "ss01" 1;
  font-variant-numeric: proportional-nums;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Stop the browser from faking bold/italic when a requested face isn't
     loaded — better to ship the real weight than to render synthesised one. */
  font-synthesis: none;
}

a { color: inherit; text-decoration: none; }
a:hover { text-decoration: underline; }
a[aria-disabled="true"] { cursor: default; opacity: 0.55; pointer-events: none; }
a[aria-disabled="true"]:hover { text-decoration: none; }
button { font: inherit; color: inherit; cursor: pointer; }
select, input { font: inherit; color: inherit; }

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

/* Top-nav and site-footer styles live in ./nav.css (imported above). */


/* ---------- Stats bar ---------- */
.stats {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 14px var(--pad-x);
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 14px;
  font-size: 14px;
  border-bottom: 1px solid var(--rule);
  font-variant-numeric: tabular-nums;
}
.stat {
  display: flex; align-items: baseline; gap: 6px;
  white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.stat-label { color: var(--ink); font-weight: 600; }
.stat-value { color: var(--ink-3); }
.uv-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 18px;
  padding: 0 5px;
  border-radius: 3px;
  background: var(--uv-low);
  color: #fff;
  font-size: 12px; font-weight: 700;
}
.uv-badge[data-level="moderate"] { background: var(--uv-mod); color: #1a1a1a; }
.uv-badge[data-level="high"]     { background: var(--uv-high); }
.uv-badge[data-level="very-high"]{ background: var(--uv-veryhigh); }
.uv-badge[data-level="extreme"]  { background: var(--uv-extreme); }

/* ---------- Hero ---------- */
.hero {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 28px var(--pad-x) 16px;
  text-align: center;
}
.hero-icon { display: inline-block; }
.hero-icon svg { width: 80px; height: 80px; vertical-align: middle; margin-right: 8px; }
.hero-headline {
  display: inline-block;
  margin: 0;
  font-size: clamp(34px, 5.5vw, 44px);
  font-weight: 600;
  letter-spacing: -0.5px;
  vertical-align: middle;
}
.hero-temp { font-weight: 600; }
.hero-deg { font-weight: 300; margin-right: 4px; }
.hero-cond { font-weight: 600; }

.hero-meta {
  margin: 6px 0 0;
  font-size: 14px;
  color: var(--ink-2);
  display: flex; gap: 24px; justify-content: center; flex-wrap: wrap;
}
.hero-meta strong { color: var(--ink-2); font-weight: 600; }

/* Subtle units toggle blended into the .hero-meta row. Reads as
   muted meta text; the active unit is the same color/weight as the
   sibling labels and the inactive one fades. No chrome — both
   buttons inherit the meta font so they sit in the line as text. */
.units-toggle {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
}
.units-toggle-btn {
  appearance: none;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  color: var(--ink-2);
  opacity: 0.5;
  cursor: pointer;
  transition: opacity 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.units-toggle-btn:hover { opacity: 0.85; }
.units-toggle-btn:focus-visible {
  outline: 2px solid var(--ink-2);
  outline-offset: 2px;
  border-radius: 2px;
  opacity: 1;
}
.units-toggle-btn[aria-pressed="true"] {
  opacity: 1;
  font-weight: 600;
}
.units-toggle-sep {
  color: var(--ink-2);
  opacity: 0.35;
  user-select: none;
}

.hero-summary {
  margin: 28px auto 0;
  max-width: 720px;
  font-size: clamp(20px, 2.5vw, 24px);
  font-weight: 400;
  color: var(--ink);
}

/* ---------- Next hour precipitation timeline ---------- */
.next-hour {
  max-width: var(--maxw);
  margin: 18px auto 0;
  padding: 0 var(--pad-x);
}
.next-hour[hidden] { display: none; }
.next-hour-plot {
  position: relative;
  height: 84px;
}
.next-hour-canvas {
  width: 100%;
  height: 100%;
  display: block;
}
.next-hour-bands {
  position: absolute; inset: 0;
  pointer-events: none;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: var(--ink-3);
}
.next-hour-bands .band {
  position: absolute;
  left: 0;
  transform: translateY(-50%);
}
.next-hour-bands .band--heavy { top: 16.6667%; }
.next-hour-bands .band--medium { top: 50%; }
.next-hour-bands .band--light { top: 83.3333%; }
.next-hour-ticks {
  position: relative;
  height: 18px;
  margin-top: 4px;
}
.next-hour-ticks span {
  position: absolute;
  top: 6px;
  transform: translateX(-50%);
  font-size: 9px;
  font-weight: 500;
  color: var(--ink-3);
}
.next-hour-ticks span::before {
  content: '';
  display: block;
  position: absolute;
  left: 50%;
  top: -6px;
  width: 1px;
  height: 4px;
  background: var(--ink-3);
  opacity: 0.6;
  transform: translateX(-50%);
}

/* ---------- Hourly bar ---------- */
.hourly {
  max-width: var(--maxw);
  margin: 14px auto 0;
  padding: 0 var(--pad-x);
}
.hourly-bar {
  display: flex; flex-wrap: nowrap;
  height: 38px;
  border-radius: 2px;
  overflow: hidden;
  user-select: none;
}
.hourly-seg {
  display: flex; align-items: center; justify-content: center;
  min-width: 0; overflow: hidden;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  padding: 0 8px;
  border-right: 1px solid rgba(255,255,255,0.6);
}
.hourly-seg:last-child { border-right: none; }
.hourly-seg.is-narrow { color: transparent; }

.hourly-ticks {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  margin-top: 4px;
  font-size: 12px;
}
.hourly-tick {
  display: flex; flex-direction: column; align-items: flex-start;
  padding-top: 6px;
  border-top: 1px solid var(--rule);
  color: var(--ink);
  line-height: 1.3;
}
.hourly-tick .t-time { font-weight: 600; }
.hourly-tick .t-temp { color: var(--ink-2); }
.hourly-tick.is-night .t-time,
.hourly-tick.is-night .t-temp { color: var(--ink-3); }

/* ---------- Radar ---------- */
.radar-section {
  margin: 22px 0 40px;
}
.radar-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 7 / 2;
  background: #0c1017;
  overflow: hidden;
}
@media (max-width: 720px) { .radar-wrap { aspect-ratio: 2 / 1; } }

.radar-frame {
  width: 100%; height: 100%;
  border: 0; display: block;
}
.radar-wrap > .radar-frame { pointer-events: none; }

/* Mount target for the shared radar controls (radar-controls.js fills it
   in). Stretched over the wrap; the controls themselves manage their own
   pointer-events so the user can pan the map between them. The same DOM
   node moves between this inline mount and the modal mount on expand. */
.radar-controls-mount {
  position: absolute; inset: 0;
  pointer-events: none;
}

/* Mini radar (inline mount): only the info icon stays visible - the rest
   of the overlay (layer / PWS / expand button + the entire play+scrubber
   bottom bar) is reserved for the expanded modal view. Click anywhere on
   the map preview to expand; the click-catcher under the controls catches
   the press because the hidden children leave pointer-events untouched. */
.radar-controls-mount[data-mount="inline"] .rdr-rail-btn:not(.rdr-info-btn),
.radar-controls-mount[data-mount="inline"] .rdr-rail-divider,
.radar-controls-mount[data-mount="inline"] .rdr-bottom-bar {
  display: none;
}
/* With the bottom bar hidden, the rail no longer needs to clear it. */
.radar-controls-mount[data-mount="inline"] .rdr-rail {
  bottom: calc(env(safe-area-inset-bottom, 0px) + 12px);
}

/* ---- Station tap popover ---- */
.station-card {
  position: absolute;
  bottom: 56px; right: 12px;
  width: 280px;
  padding: 14px 16px 12px;
  background: rgba(20, 24, 32, 0.92);
  color: #eef2f7;
  border-radius: 12px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  pointer-events: auto;
  z-index: 5;
  font: 13px/1.4 var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif);
}
.station-card[hidden] { display: none; }
.station-card-close {
  position: absolute; top: 2px; right: 6px;
  background: transparent; border: 0; color: #aab3c0;
  font-size: 18px; line-height: 1; cursor: pointer;
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border-radius: 50%;
  transition: color 0.15s, scale 0.12s ease;
}
.station-card-close:hover { color: #fff; }
.station-card-close:active { scale: 0.96; }
.station-card-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 10px;
}
.station-card-title { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.station-card-id { font-weight: 600; font-size: 14px; }
.station-card-provider { font-size: 11px; color: #8c95a3; }
.station-card-temp { font-size: 22px; font-weight: 600; font-variant-numeric: tabular-nums; }
.station-card-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px 16px;
  margin: 0;
}
.station-card-grid > div { display: flex; justify-content: space-between; }
.station-card-grid dt { color: #8c95a3; margin: 0; }
.station-card-grid dd { margin: 0; font-variant-numeric: tabular-nums; }
.station-card.loading .station-card-grid { opacity: 0.5; }

@media (max-width: 720px) {
  .station-card { left: 12px; right: 12px; width: auto; bottom: 64px; }
}
.radar-click-catcher {
  position: absolute; inset: 0;
  background: transparent;
  border: 0; padding: 0; margin: 0;
  cursor: pointer;
}

/* Climate Info pill overlaid on the radar — same chrome as the standalone
   maps.graycloud.app header, now linking to /climate/{slug} for the active
   location. SSR rewrites the href in functions/forecast/[slug].js. Sits
   above the click-catcher (z-index 5) and the rdr-controls (z-index 10)
   so it stays tappable. */
.radar-brand {
  position: absolute; bottom: 10px; right: 10px;
  z-index: 11;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 10px 4px 4px;
  height: 32px;
  background: #ffffff;
  border: 0.5px solid rgba(0, 0, 0, 0.08);
  border-radius: 10px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
  color: #0c1017;
  text-decoration: none;
  white-space: nowrap;
  transition: background 160ms cubic-bezier(.22,.61,.36,1);
}
.radar-brand:hover { background: #f4f6fa; }
.radar-brand-mark {
  width: 22px; height: 22px;
  border-radius: 6px;
  display: block; object-fit: cover;
}
.radar-brand-word {
  font-size: 11px; font-weight: 600; line-height: 1;
  letter-spacing: -0.01em;
}
.radar-brand--modal { top: 14px; left: 14px; bottom: auto; right: auto; }

.radar-modal {
  position: fixed; inset: 0;
  z-index: 9999;
  background: rgba(12, 16, 23, 0.72);
  display: flex; align-items: center; justify-content: center;
  padding: clamp(12px, 3vh, 32px);
}
.radar-modal[hidden] { display: none; }
.radar-modal-wrap {
  position: relative;
  width: min(1200px, 100%);
  height: min(800px, 100%);
  background: #0c1017;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
}
.radar-frame-modal {
  width: 100%; height: 100%;
  border: 0; display: block;
}
body.radar-modal-open { overflow: hidden; }

/* ---------- Daily ---------- */
.daily {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--pad-x) 64px;
}
.daily-summary {
  /* Bottom 26 px + the first row's 14 px padding-top equals the 40 px the
     radar-section reserves below itself, so the summary sits centred between
     the radar and the forecast list. */
  margin: 0 0 26px;
  font-size: clamp(18px, 2vw, 20px);
  text-align: center;
  color: var(--ink);
}
.daily-list {
  list-style: none;
  margin: 0; padding: 0;
}
.daily-row {
  display: grid;
  grid-template-columns: 56px 36px 1fr;
  align-items: center;
  gap: 12px;
  padding: 14px 0;
  cursor: pointer;
  user-select: none;
  transition: background-color 120ms ease;
}
.daily-row:hover { background: var(--rule-soft, rgba(127,127,127,0.06)); }
.daily-daycol { display: flex; flex-direction: column; gap: 2px; }
.daily-day {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--ink);
  letter-spacing: 0.02em;
}
.daily-precip {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 12px;
  font-weight: 600;
  color: #1f7ae0;
}
.daily-precip[data-zero="true"] { color: var(--ink-3); }
.daily-precip .daily-drop { width: 11px; height: 11px; }
.daily-icon { width: 32px; height: 32px; color: var(--ink-2); display: block; }
.daily-icon svg { width: 100%; height: 100%; }
.daily-range {
  position: relative;
  height: 28px;
  display: flex;
  align-items: center;
}
.daily-range-inner {
  position: relative;
  flex: 1;
  margin: 0 50px;
  height: 20px;
}
.daily-range-pill {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--start, 0%);
  right: calc(100% - var(--end, 100%));
  background: var(--rule);
  border-radius: 999px;
  min-width: 28px;
}
.daily-low, .daily-high {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  font-size: 18px;
  font-weight: 400;
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.daily-low {
  right: calc(100% - var(--start, 0%));
  padding-right: 6px;
  text-align: right;
}
.daily-high {
  left: var(--end, 100%);
  padding-left: 6px;
}

.daily-hourly {
  display: none;
  grid-template-columns: 20px 1fr;
  gap: 26px;
  padding: 14px 0 20px;
  list-style: none;
}
.daily-hourly.is-open { display: grid; }
.hourly-spine {
  border-radius: 999px;
  align-self: stretch;
}
.hourly-list { list-style: none; margin: 0; padding: 0; }
.hourly-row {
  display: grid;
  grid-template-columns: 52px auto 1fr;
  align-items: center;
  column-gap: 14px;
  height: 44px;
}
.hourly-time {
  font-size: 16px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--ink);
}
.hourly-condition {
  font-size: 13px;
  font-style: italic;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hourly-condition:empty { display: none; }
.hourly-condition:empty + .hourly-track { grid-column: 2 / span 2; }
.hourly-track {
  position: relative;
  height: 100%;
  margin-right: 50px;
}
.hourly-rule {
  position: absolute;
  top: 50%;
  left: 0;
  right: calc(100% - var(--pill-pos, 100%));
  height: 1px;
  background: var(--rule);
}
.hourly-pill {
  position: absolute;
  top: 50%;
  left: var(--pill-pos, 100%);
  transform: translate(-2px, -50%);
  padding: 6px 14px;
  border-radius: 999px;
  background: #ededee;
  border: 1px solid #d6d6d8;
  color: var(--ink);
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

@media (max-width: 540px) {
  .daily-row {
    grid-template-columns: 48px 28px 1fr;
    gap: 8px;
  }
  .daily-day { font-size: 12px; }
  .daily-precip { font-size: 11px; }
  .daily-icon { width: 26px; height: 26px; }
  .daily-range { height: 24px; }
  .daily-range-inner { margin: 0 40px; height: 16px; }
  .daily-low, .daily-high { font-size: 16px; }
  .daily-hourly { grid-template-columns: 16px 1fr; gap: 18px; padding: 10px 0 14px; }
  .hourly-row { grid-template-columns: 44px auto 1fr; column-gap: 10px; height: 38px; }
  .hourly-time { font-size: 14px; }
  .hourly-condition { font-size: 12px; }
  .hourly-track { margin-right: 40px; }
  .hourly-pill { font-size: 13px; padding: 4px 11px; }
}

/* ---------- Time machine CTA ---------- */
.time-machine-cta {
  text-align: center;
  padding: 28px var(--pad-x) 40px;
  border-top: 1px solid var(--rule);
  margin-top: 24px;
}
.time-machine-cta p {
  margin: 0 0 12px;
  font-size: 15px;
  color: var(--ink-2);
}
.time-machine {
  display: inline-block;
  background: #2f7bff;
  color: #fff;
  font-weight: 700;
  letter-spacing: 0.6px;
  font-size: 13px;
  padding: 10px 28px;
  border-radius: 4px;
  text-decoration: none;
  text-transform: uppercase;
  transition: background 0.15s, scale 0.12s ease;
}
.time-machine:hover { background: #2667d9; text-decoration: none; }
.time-machine:active { scale: 0.96; }

/* ---------- Legal / Support pages ----------
   Long-form reading frame. Fluid body, 68ch measure, modular-scale
   headings, AA-contrast prose tokens; flips for dark mode via the
   --prose-* token block at the top of the file. */
.legal {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 56px var(--pad-x) 80px;
  font-family: var(--font-prose);
  color: var(--prose-text);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  font-variant-numeric: proportional-nums;
  font-optical-sizing: auto;
}
.legal h1 {
  font-size: var(--text-h1);
  font-weight: var(--w-bold);
  line-height: var(--leading-heading);
  letter-spacing: var(--track-display);
  margin: 0 0 0.4em;
  text-wrap: balance;
}
.legal .legal-meta {
  color: var(--prose-faint);
  font-size: var(--text-small);
  margin: 0 0 2em;
}
.legal h2 {
  font-size: var(--text-h2);
  font-weight: var(--w-bold);
  line-height: var(--leading-heading);
  letter-spacing: var(--track-display);
  margin: 2em 0 0.5em;
  text-wrap: balance;
}
.legal h3 {
  font-size: var(--text-h3);
  font-weight: var(--w-semibold);
  line-height: var(--leading-heading);
  letter-spacing: var(--track-heading);
  margin: 1.75em 0 0.4em;
  text-wrap: balance;
}
.legal p, .legal ul, .legal ol { margin: 0 0 1.25em; }
.legal p { text-wrap: pretty; }
.legal ul, .legal ol { padding-left: 1.4em; }
.legal li { margin-bottom: 0.4em; }
.legal li::marker { color: var(--prose-faint); }
.legal a {
  color: var(--prose-link);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 0.06em;
}
.legal a:hover { text-decoration: underline; }
.legal strong { font-weight: var(--w-semibold); color: var(--prose-text); }
.legal blockquote {
  margin: 0 0 1.25em;
  padding-inline-start: 1em;
  border-inline-start: 2px solid var(--prose-rule);
  color: var(--prose-muted);
  font-style: italic;
}
.legal code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  background: var(--prose-code-bg);
  padding: 0.1em 0.32em;
  border-radius: 4px;
}
.legal pre {
  margin: 0 0 1.25em;
  padding: 1em 1.2em;
  background: var(--prose-code-bg);
  border-radius: 8px;
  overflow-x: auto;
  font-size: 0.92em;
  line-height: 1.55;
}
.legal pre code {
  background: transparent;
  padding: 0;
  border-radius: 0;
  font-size: inherit;
}

.legal table {
  width: 100%;
  margin: 0 0 1.5em;
  border-collapse: collapse;
  font-size: var(--text-small);
  line-height: 1.5;
  font-variant-numeric: tabular-nums lining-nums;
}
.legal th, .legal td {
  text-align: left;
  padding: 0.7em 0.8em 0.7em 0;
  border-bottom: 1px solid var(--prose-rule);
  vertical-align: top;
}
.legal th {
  font-weight: var(--w-semibold);
  color: var(--prose-text);
  font-size: var(--text-small);
}
.legal thead th { border-bottom: 1px solid var(--prose-muted); }
.legal td:first-child, .legal th:first-child {
  font-weight: var(--w-medium);
  color: var(--prose-muted);
  width: 38%;
}

/* App Store CTA - single component shared across hero, blog, support, compare. */
.appstore-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
  margin: 0 0 24px;
}

/* App Store badge - links to the live product page. */
.btn-appstore {
  display: inline-flex;
  align-items: center;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  position: relative;
  opacity: 1;
  font-family: inherit;
  transition: opacity 0.2s, scale 0.12s ease;
}
.btn-appstore:hover { opacity: 0.85; }
.btn-appstore:active { scale: 0.97; }
.btn-appstore img,
.btn-appstore-badge { display: block; height: 48px; width: auto; }

/* ---------- Blog editorial ---------- */
/* Page background: subtly off-white (or near-black in dark mode) so the
   card pops. Scoped to body class so other pages keep their own bg. */
body.blog-post-page {
  background: var(--prose-page);
}

/* Outer wrapper. The .legal max-width (68ch) sets the reading measure;
   we trim its vertical padding since the card supplies its own. */
.legal.blog-post {
  padding: 48px var(--pad-x) 80px;
}

/* Header block (breadcrumb + h1 + meta) sits on the page background,
   outside the white card. Centered to match the roadmap page header
   pattern; the climate page overrides this back to its flex/left
   layout below. */
.blog-post .post-header {
  margin: 0 0 2em;
  text-align: center;
}

.blog-post .breadcrumb {
  font-family: var(--font-prose);
  font-size: var(--text-small);
  color: var(--prose-faint);
  margin: 0 0 2em;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
}
.blog-post .breadcrumb a {
  color: var(--prose-faint);
  text-decoration: none;
}
.blog-post .breadcrumb a:hover {
  color: var(--prose-text);
  text-decoration: underline;
}
.blog-post .breadcrumb-sep {
  margin: 0 0.6em;
  color: var(--prose-faint);
}

.blog-post .post-header h1 {
  font-family: var(--font-prose);
  font-size: var(--text-h1);
  font-weight: var(--w-bold);
  letter-spacing: var(--track-display);
  line-height: var(--leading-heading);
  margin: 0;
  color: var(--prose-text);
  text-wrap: balance;
}

/* Short content-page headings sit a notch below the standard content-page
   H1. (/about carried this too until 2026-08-21, when the page retired and
   its text moved to the "Introducing GraySky" blog post.) */
.support-page .post-header h1 {
  font-size: var(--text-h2);
}

/* Give the short Support content more breathing room before the footer. */
.support-page .legal.blog-post {
  padding-block-end: 160px;
}

.blog-post .post-meta {
  font-family: var(--font-prose);
  font-size: var(--text-small);
  color: var(--prose-faint);
  margin: 0.5em 0 0;
  font-variant-numeric: tabular-nums;
}
.blog-post .post-meta time { font-variant-numeric: tabular-nums; }

/* Standfirst caption under the H1 (blog post deck + blog index description).
   Kept deliberately small, one notch darker than .post-meta (muted vs faint)
   so it reads as content while the timestamp recedes. Measure-capped and
   centered to sit inside the centered .post-header. */
.blog-post .post-deck {
  font-family: var(--font-prose);
  font-size: var(--text-small);
  line-height: 1.55;
  color: var(--prose-muted);
  max-width: 52ch;
  margin: 0.9em auto 0;
  text-wrap: pretty;
}

/* The card holding the article body. */
.blog-post .post-card {
  background: var(--prose-surface);
  border: 1px solid var(--prose-rule);
  border-radius: 24px;
  padding: clamp(28px, 4vw, 48px);
  box-shadow: var(--prose-shadow);
  font-family: var(--font-prose);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  color: var(--prose-text);
  font-variant-numeric: proportional-nums;
  font-optical-sizing: auto;
}

.blog-post .post-card > *:first-child { margin-top: 0; }
.blog-post .post-card > *:last-child { margin-bottom: 0; }

/* Lead paragraph — slightly larger, muted to set the intro voice. */
.blog-post .post-card .lead {
  font-size: var(--text-lead);
  font-weight: 400;
  line-height: 1.5;
  color: var(--prose-muted);
  margin: 0 0 1.25em;
  text-wrap: pretty;
}
.blog-post .post-card .lead a { color: var(--prose-link); }

.blog-post .post-card p,
.blog-post .post-card ul,
.blog-post .post-card ol {
  font-size: 1em;
  line-height: var(--leading-body);
  color: var(--prose-text);
  margin: 0 0 1.25em;
}
.blog-post .post-card p { text-wrap: pretty; }
.blog-post .post-card ul,
.blog-post .post-card ol { padding-left: 1.4em; }
.blog-post .post-card li { margin-bottom: 0.4em; }
.blog-post .post-card li::marker { color: var(--prose-faint); }

.blog-post .post-card a {
  color: var(--prose-link);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 0.06em;
}
.blog-post .post-card a:hover { text-decoration: underline; }
.blog-post .post-card strong { font-weight: var(--w-semibold); color: var(--prose-text); }
.blog-post .post-card .signature {
  margin-top: 1.75em;
  color: var(--prose-muted);
  font-style: italic;
}
.blog-post .post-card figure { margin: 1.75em 0; }
.blog-post .post-card figure img,
.blog-post .post-card figure video,
.blog-post .post-card p > img {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: 12px;
  border: 1px solid var(--prose-rule);
}
/* Portrait phone captures (screenshots + screen recordings) share one width
   token so they always render at the same size. Kept compact so a 9:19.5
   capture doesn't tower over the prose. */
.blog-post .post-card figure.blog-figure--phone {
  max-width: 240px;
  margin-inline: auto;
}

/* Video figures get a large, centered play button so it's obvious the capture
   is a playable recording rather than a still. blog-video enhancer (inlined on
   posts that contain a <video>) wraps each video in .blog-figure__media and
   injects the button; the overlay covers the video only (not the caption) and
   fades out during playback, leaving the native controls for scrubbing. */
.blog-post .post-card .blog-figure__media {
  position: relative;
  display: block;
  border-radius: 12px;
}
.blog-post .post-card .blog-figure__media video {
  display: block;
}
.blog-figure__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: 12px;
  color: #fff;
  cursor: pointer;
  transition: opacity 0.2s var(--ease-out);
}
.blog-figure__play-disc {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: rgba(20, 20, 20, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  box-shadow: 0 2px 14px rgba(0, 0, 0, 0.35);
  transition: transform var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out);
}
.blog-figure__play svg {
  transform: translateX(2px); /* optical centering of the triangle in the disc */
}
.blog-figure__play:hover .blog-figure__play-disc,
.blog-figure__play:focus-visible .blog-figure__play-disc {
  background: rgba(20, 20, 20, 0.72);
  transform: scale(1.06);
}
.blog-figure__play:focus-visible {
  outline: none;
}
.blog-figure__play:focus-visible .blog-figure__play-disc {
  box-shadow: 0 0 0 3px var(--prose-link, #4a90d9), 0 2px 14px rgba(0, 0, 0, 0.35);
}
.blog-figure.is-playing .blog-figure__play {
  opacity: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .blog-figure__play,
  .blog-figure__play-disc {
    transition: none;
  }
  .blog-figure__play:hover .blog-figure__play-disc,
  .blog-figure__play:focus-visible .blog-figure__play-disc {
    transform: none;
  }
}
.blog-post .post-card figcaption {
  margin-top: 0.6em;
  font-size: 0.875em;
  line-height: 1.4;
  color: var(--prose-muted);
  text-align: center;
  text-wrap: pretty;
}

.blog-post .post-card h2 {
  font-family: var(--font-prose);
  font-size: var(--text-h2);
  font-weight: var(--w-bold);
  letter-spacing: var(--track-display);
  line-height: var(--leading-heading);
  margin: 2em 0 0.5em;
  color: var(--prose-text);
  text-wrap: balance;
}

.blog-post .post-card h3 {
  font-family: var(--font-prose);
  font-size: var(--text-h3);
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-heading);
  line-height: var(--leading-heading);
  margin: 1.75em 0 0.4em;
  color: var(--prose-text);
  text-wrap: balance;
}

.blog-post .post-card h4 {
  font-family: var(--font-prose);
  font-size: var(--text-h4);
  font-weight: var(--w-semibold);
  letter-spacing: 0.04em;
  line-height: var(--leading-heading);
  margin: 1.5em 0 0.3em;
  color: var(--prose-muted);
  text-transform: uppercase;
}

.blog-post .post-card blockquote {
  margin: 0 0 1.25em;
  padding-inline-start: 1em;
  border-inline-start: 2px solid var(--prose-rule);
  color: var(--prose-muted);
  font-style: italic;
}
.blog-post .post-card code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  background: var(--prose-code-bg);
  padding: 0.1em 0.32em;
  border-radius: 4px;
}
.blog-post .post-card pre {
  margin: 0 0 1.25em;
  padding: 1em 1.2em;
  background: var(--prose-code-bg);
  border-radius: 8px;
  overflow-x: auto;
  font-size: 0.92em;
  line-height: 1.55;
}
.blog-post .post-card pre code {
  background: transparent;
  padding: 0;
  border-radius: 0;
  font-size: inherit;
}
.blog-post .post-card hr {
  border: 0;
  border-top: 1px solid var(--prose-rule);
  margin: 2em 0;
}
.blog-post .post-card table {
  width: 100%;
  margin: 0 0 1.5em;
  border-collapse: collapse;
  font-size: var(--text-small);
  line-height: 1.5;
  font-variant-numeric: tabular-nums lining-nums;
}
.blog-post .post-card th,
.blog-post .post-card td {
  text-align: left;
  padding: 0.7em 0.8em 0.7em 0;
  border-bottom: 1px solid var(--prose-rule);
  vertical-align: top;
}
.blog-post .post-card th {
  font-weight: var(--w-semibold);
  color: var(--prose-text);
}

/* ---------- Blog listing (/blog, /blog/category/*, /blog/page/*) ----------
   Three-column card grid on the off-white prose page, matching the LookAway
   reference in light mode. Everything below rides the shared design tokens —
   no raw hex, no gradients, hairline + shadow for depth (design/STYLE-GUIDE.md).
   Only scripts/build-blog.mjs emits .blog-listing-page. */
body.blog-listing-page {
  background: var(--prose-page);
}

.blog-listing {
  max-width: var(--maxw);
  margin-inline: auto;
  padding: clamp(32px, 6vh, 56px) var(--pad-x) clamp(64px, 12vh, 112px);
  font-family: var(--font-prose);
}

.blog-listing__header {
  text-align: center;
  margin: 0 0 28px;
}
.blog-listing__header h1 {
  font-family: var(--font-prose);
  font-size: var(--text-h1);
  font-weight: var(--w-bold);
  letter-spacing: var(--track-display);
  line-height: var(--leading-heading);
  color: var(--prose-text);
  margin: 0;
  text-wrap: balance;
}
.blog-listing__intro {
  max-width: 54ch;
  margin: 14px auto 0;
  font-size: var(--text-lead);
  line-height: 1.5;
  color: var(--prose-muted);
  text-wrap: pretty;
}
/* Links sitting directly on the page background, not inside the white card.
   --prose-link (#1a73e8) is 4.28:1 on --prose-page (#f9f9f9) — under AA. Inside
   a card it clears, which is why every other prose link is fine. A 10% pull
   toward the ink takes it to 4.95:1 and reads as the same blue. */
.blog-listing__intro a,
.post-lede a {
  color: color-mix(in oklab, var(--prose-link) 90%, var(--prose-text));
  text-underline-offset: 0.18em;
}

/* Category filter row. Unlike the reference this renders on EVERY listing
   view (including a filtered one), carries an "All" pill, marks the active
   pill, and stays visible on small screens — the reference hides the whole
   row below 600px, which puts categories out of reach on a phone. */
.blog-categories {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding-block: 16px;
  border-top: 1px solid var(--prose-rule);
  border-bottom: 1px solid var(--prose-rule);
}
.blog-categories__label {
  margin-inline-end: 4px;
  font-size: var(--text-small);
  color: var(--prose-faint);
}
.blog-category {
  padding: 6px 12px;
  border-radius: var(--radius-8);
  background: color-mix(in oklab, var(--prose-text) 7%, transparent);
  color: var(--prose-muted);
  font-size: 0.9375rem;
  font-weight: var(--w-medium);
  line-height: 1.35;
  text-decoration: none;
  transition:
    background var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}
.blog-category:hover {
  background: color-mix(in oklab, var(--prose-text) 12%, transparent);
  color: var(--prose-text);
}
/* The active pill and the current pagination page share one selected
   language: solid ink. The reference uses a blue fill for pagination and no
   active state at all for categories. */
.blog-category.is-active,
.blog-category.is-active:hover {
  background: var(--prose-text);
  color: var(--prose-surface);
}
.blog-category:focus-visible,
.blog-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- Card grid ---------- */
.post-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
  margin-top: 32px;
}
@media (max-width: 900px) {
  .post-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .post-grid { grid-template-columns: minmax(0, 1fr); }
}

.post-card-item {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--prose-surface);
  border: 1px solid var(--prose-rule);
  border-radius: var(--radius-24);
  box-shadow: var(--prose-shadow);
  transition:
    transform var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out);
}
.post-card-item:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lift);
}
/* A fixed hero ratio is what keeps the card tops aligned across a row and
   holds CLS at zero. The reference sizes nothing, so its rows go ragged and
   the grid reflows as each image lands. */
.post-card-item__hero {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1200 / 630;
  object-fit: cover;
  background: var(--prose-code-bg);
}
.post-card-item__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 12px;
  padding: 24px;
}
.post-card-item__title {
  margin: 0;
  font-family: var(--font-prose);
  font-size: 1.5rem;
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-heading);
  line-height: 1.25;
  color: var(--prose-text);
  text-wrap: balance;
}
.post-card-item__title a {
  color: inherit;
  text-decoration: none;
}
/* Stretched link: the title anchor covers the card, so the whole card is one
   hit target without a second aria-hidden overlay anchor in the DOM. */
.post-card-item__title a::after,
.related-card h3 a::after {
  content: "";
  position: absolute;
  inset: 0;
}
.post-card-item:hover .post-card-item__title a {
  color: var(--prose-link);
}
.post-card-item__excerpt {
  flex: 1;
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--prose-muted);
  text-wrap: pretty;
}
.post-card-item--draft {
  border-style: dashed;
}

.post-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.post-tag {
  padding: 4px 8px;
  border-radius: var(--radius-6);
  background: color-mix(in oklab, var(--prose-text) 7%, transparent);
  color: var(--prose-muted);
  font-size: 0.8125rem;
  font-weight: var(--w-medium);
  line-height: 1.3;
  text-decoration: none;
}
a.post-tag {
  position: relative;
  z-index: 1;
}
a.post-tag:hover {
  background: color-mix(in oklab, var(--prose-text) 12%, transparent);
  color: var(--prose-text);
}

.post-date {
  margin: 0;
  font-size: var(--text-small);
  color: var(--prose-faint);
  font-variant-numeric: tabular-nums;
}

/* ---------- Hairline pill button ----------
   The house button shape, per design/STYLE-GUIDE.md. Declared here rather
   than importing .fcx-action, which lives in src/weather-events.styles.css and
   is scoped to that SPA. */
.blog-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 9px 16px;
  border-radius: var(--radius-pill);
  background: var(--prose-surface);
  border: 1px solid var(--prose-rule);
  color: var(--prose-text);
  font-family: var(--font-prose);
  font-size: 0.875rem;
  font-weight: var(--w-semibold);
  line-height: 1.2;
  text-decoration: none;
  transition:
    background var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}
.blog-btn--full {
  width: 100%;
}
a.blog-btn:hover,
.post-card-item:hover .blog-btn {
  background: color-mix(in oklab, var(--prose-text) 7%, transparent);
  border-color: color-mix(in oklab, var(--prose-text) 25%, transparent);
}

.blog-pagination {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin-top: 44px;
}
.blog-page {
  min-width: 42px;
}
.blog-page.is-current,
.blog-page.is-current:hover {
  background: var(--prose-text);
  border-color: var(--prose-text);
  color: var(--prose-surface);
  cursor: default;
}

@media (prefers-reduced-motion: reduce) {
  .post-card-item,
  .post-card-item:hover {
    transform: none;
    transition: none;
  }
}

/* ---------- Blog article (single post) ----------
   Editorial layout on the off-white prose page: back link, title, a meta rule
   carrying the date/byline/categories, a lede, a full-width hero, then prose
   beside a sticky app promo. The body reuses every shared `.blog-post
   .post-card` prose rule (lists, figures, tables, code) — the wrapper carries
   `.blog-post` for exactly that reason — and only rebases size and measure.
   Only scripts/build-blog.mjs renderPost emits .blog-article, so the shared
   .legal/.blog-post chrome on privacy/terms/about/support is left untouched. */
body.blog-article {
  background: var(--prose-page);
}

.post-container {
  /* Page-local editorial width, matching the reference. Deliberately NOT
     --maxw (1280px, the tool-page container): this column holds prose. */
  --post-w: 900px;
  display: block;
  padding-block: clamp(32px, 6vh, 56px) clamp(48px, 9vh, 80px);
}
.post-container__inner {
  max-width: var(--post-w);
  margin-inline: auto;
  padding-inline: var(--pad-x);
  font-family: var(--font-prose);
}

.post-back {
  display: inline-block;
  margin: 0 0 24px;
  font-size: var(--text-small);
  color: var(--prose-muted);
  text-decoration: none;
}
.post-back:hover {
  color: var(--prose-text);
}

.blog-article .post-container__inner > h1 {
  font-family: var(--font-prose);
  font-size: var(--text-h1);
  font-weight: var(--w-bold);
  letter-spacing: var(--track-display);
  line-height: var(--leading-heading);
  color: var(--prose-text);
  margin: 0 0 24px;
  text-align: left;
  text-wrap: balance;
}

.blog-article .post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
  margin: 0;
  padding-block: 16px;
  border-top: 1px solid var(--prose-rule);
  border-bottom: 1px solid var(--prose-rule);
}
.blog-article .post-meta p {
  margin: 0;
  font-family: var(--font-prose);
  font-size: var(--text-small);
  color: var(--prose-muted);
  font-variant-numeric: tabular-nums;
}

.post-lede {
  margin: 28px 0 0;
  font-size: var(--text-lead);
  line-height: 1.5;
  color: var(--prose-muted);
  text-wrap: pretty;
}

.post-hero {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1200 / 630;
  object-fit: cover;
  margin: 36px 0 0;
  border: 1px solid var(--prose-rule);
  border-radius: var(--radius-24);
  background: var(--prose-code-bg);
}

/* Strip the card chrome — the body reads flat on the page, as it does on the
   reference. The shared `.blog-post .post-card` rule supplies it for the legal
   pages; this override is scoped to the article. Capped at --measure so the
   line length stays readable even though the container is wider. */
body.blog-article .post-container .post-card {
  margin-top: 40px;
  min-width: 0;
  max-width: var(--measure);
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  font-family: var(--font-prose);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  color: var(--prose-text);
  font-variant-numeric: proportional-nums;
  font-optical-sizing: auto;
}
body.blog-article .post-card > *:first-child { margin-top: 0; }
body.blog-article .post-card > *:last-child { margin-bottom: 0; }

/* Highlighted opening sentence. Used by blog/posts/introducing-graycloud.md.
   Rebased from the retired --article-ink onto the prose palette. */
body.blog-article .post-card .opening-question {
  display: inline-block;
  margin: 0 0 1.5em;
  padding: 0.16em 0.34em 0.2em;
  border-radius: var(--radius-6);
  background: color-mix(in oklab, var(--prose-text) 10%, transparent);
  color: var(--prose-text);
  font-weight: var(--w-medium);
  text-wrap: balance;
}

/* Mid-article promo. Authored inline in the markdown (markdown-it runs with
   html:true), so a writer drops it wherever it earns its place. */
.blog-article .post-card .post-cta {
  display: flex;
  align-items: center;
  gap: 20px;
  margin: 2.25em 0;
  padding: 20px 24px;
  background: color-mix(in oklab, var(--prose-text) 4%, transparent);
  border: 1px solid var(--prose-rule);
  border-radius: var(--radius-16);
}
.blog-article .post-card .post-cta img {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  margin: 0;
  border: 0;
  border-radius: var(--radius-10);
}
.blog-article .post-card .post-cta__text {
  flex: 1;
}
.blog-article .post-card .post-cta__text > * {
  margin: 0;
}
.blog-article .post-card .post-cta__text p {
  margin-top: 4px;
  font-size: var(--text-small);
  color: var(--prose-muted);
}

/* ---------- Closing app promo ----------
   A full-width band at the foot of the article, spanning the same column as
   the title, meta rule and hero. Laid out as a row so the badge sits opposite
   the copy instead of leaving the right half empty. */
.post-promo {
  display: flex;
  align-items: center;
  gap: 24px;
  margin-top: 56px;
  padding: 24px 28px;
  background: var(--prose-surface);
  border: 1px solid var(--prose-rule);
  border-radius: var(--radius-16);
  box-shadow: var(--prose-shadow);
}
.post-promo__icon {
  display: block;
  flex-shrink: 0;
  width: 56px;
  height: 56px;
  margin: 0;
  border-radius: var(--radius-12);
}
.post-promo__body {
  flex: 1;
  min-width: 0;
}
.post-promo__title {
  margin: 0 0 6px;
  font-family: var(--font-prose);
  font-size: 1.125rem;
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-heading);
  line-height: 1.3;
  color: var(--prose-text);
}
.post-promo__text {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--prose-muted);
  text-wrap: pretty;
}
.post-promo .appstore-cta {
  flex-shrink: 0;
  margin: 0;
}

/* ---------- Related posts ---------- */
.related-posts {
  border-top: 1px solid var(--prose-rule);
  padding-block: clamp(40px, 8vh, 64px) clamp(56px, 11vh, 96px);
}
.related-posts__inner {
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--pad-x);
  font-family: var(--font-prose);
}
.related-posts__inner h2 {
  margin: 0 0 28px;
  font-family: var(--font-prose);
  font-size: var(--text-h2);
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-heading);
  line-height: var(--leading-heading);
  color: var(--prose-text);
}
.related-posts__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
}
@media (max-width: 900px) {
  .related-posts__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .related-posts__grid { grid-template-columns: minmax(0, 1fr); }
}
.related-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--prose-surface);
  border: 1px solid var(--prose-rule);
  border-radius: var(--radius-16);
  box-shadow: var(--prose-shadow);
  transition:
    transform var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out);
}
.related-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lift);
}
.related-card img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1200 / 630;
  object-fit: cover;
  background: var(--prose-code-bg);
}
.related-card__body {
  padding: 18px 20px 20px;
}
.related-card h3 {
  margin: 0 0 8px;
  font-family: var(--font-prose);
  font-size: 1.0625rem;
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-heading);
  line-height: 1.35;
  color: var(--prose-text);
  text-wrap: balance;
}
.related-card h3 a {
  color: inherit;
  text-decoration: none;
}
.related-card:hover h3 a {
  color: var(--prose-link);
}
.related-card p {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--prose-muted);
  text-wrap: pretty;
}
@media (prefers-reduced-motion: reduce) {
  .related-card,
  .related-card:hover {
    transform: none;
    transition: none;
  }
}

/* Narrow: the promo row stacks so the badge keeps its full hit area. */
@media (max-width: 620px) {
  .post-promo {
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
  }

  .blog-article .post-card .post-cta {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }
}

/* ---------- FAQ question list ---------- */
/* Stack of question rows used inside .blog-post .post-card on /faq, and
   reused (with dev-shell overrides) on /dev/pricing. Structural only —
   typography inherits from the surrounding shell. */
.faq-item {
  padding: 20px 0;
  border-bottom: 1px solid var(--rule);
}
.faq-item:last-child { border-bottom: 0; }
/* Inside the post-card, h3/p inherit Inter from .blog-post
   .post-card h3 / p — we just override the size + collapse the margins. */
.blog-post .post-card .faq-item h3 {
  margin: 0 0 8px;
  font-size: 18px;
}
.blog-post .post-card .faq-item p {
  margin: 0;
  line-height: 1.6;
}
.blog-post .post-card .faq-section-head {
  margin: 56px 0 16px;
}
.blog-post .post-card .faq-section-head:first-of-type {
  margin-top: 40px;
}

/* ---------- FAQ jump-nav ---------- */
/* Used on /faq to provide a section-anchor picker above the question list.
   Pills give each link a real 40+px hit target instead of relying on raw
   inline text. */
.faq-jump {
  margin: 32px 0 48px;
  padding: 20px 24px;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: #fff;
}
.faq-jump-label {
  margin: 0 0 12px;
  font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 13px;
  font-weight: var(--w-semibold);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.faq-jump ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.faq-jump li { margin: 0; }
.faq-jump a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 8px 14px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 14px;
  font-weight: var(--w-medium);
  color: var(--ink);
  background: #fff;
  text-decoration: none;
  transition: background-color var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out), scale var(--dur-fast) var(--ease-out);
}
.faq-jump a:hover {
  background: var(--bg-muted);
  border-color: color-mix(in oklab, var(--ink) 25%, transparent);
  text-decoration: none;
}
.faq-jump a:active { scale: 0.97; }

/* ---------- Responsive ---------- */
@media (max-width: 720px) {
  .stats { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 480px) {
  .stats { grid-template-columns: repeat(2, 1fr); font-size: 13px; }
  .hero-icon svg { width: 56px; height: 56px; }
  .hourly-ticks { grid-template-columns: repeat(6, 1fr); }
  .hourly-ticks .hourly-tick:nth-child(2n) { display: none; }
}

/* Honour the user's motion preference without killing instantaneous press
   feedback. Pattern (W3C / a11y-project recommendation): collapse durations
   to ~0ms so transitions still fire (state classes that read transitionend
   keep working) but visually snap. Keyframe animations also collapse. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .radar-section, .time-machine-cta { display: none; }
}

/* Fallback content for noscript / SSR-only */
.noscript-fallback ul { list-style: none; padding: 0; margin: 0; }
.noscript-fallback li { padding: 8px 0; border-bottom: 1px solid var(--rule); }

/* ====================================================================
   /climate/<slug> page — per-location climatology facts.
   Lives on the blog-post-page chrome (Inter body
   headings, gray bg, white cards). Only the cards grid + feature card
   are new; the .post-card / .post-header / .lead / .breadcrumb rules
   are reused from the existing blog-post styles above.
   ==================================================================== */
/* Climate page widens beyond the default .legal 720px reading column so
   its content's left edge aligns with the header logo. `--maxw-nav`
   (80rem / 1280px, defined in nav.css) is the nav's container, so using
   the same value + the same --pad-x lines the columns up exactly. */
.legal.climate-page {
  max-width: var(--maxw-nav);
}

/* Wikipedia-style page background — the gray we use for other blog posts
   doesn't match the editorial "white canvas + serif headings + rules"
   look, so override at the page-class level. */
body.blog-post-page:has(.climate-page) {
  background: #ffffff;
}

/* Climate-page header — Wikipedia-article-style title band. Serif H1 at
   normal weight (the distinctive Wikipedia look), italic gray subtitle,
   horizontal rule under the entire row separating header from body.
   Flex row keeps the current-temp + locator map on the right edge. */
.climate-page .post-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  padding-bottom: 12px;
  border-bottom: 1px solid #c8ccd0;
  margin-bottom: 24px;
  text-align: left;
}
.climate-page .post-header h1 {
  /* Serif stack mirrors Wikipedia's Linux Libertine fallback chain; on
     Mac this lands on Georgia, on Windows on Georgia/Times. */
  font-family: 'Linux Libertine', Georgia, 'Times New Roman', Times, serif;
  font-size: clamp(28px, 3.4vw, 36px);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: 0;
}
.climate-page .post-meta {
  font-style: italic;
  color: var(--ink-3);
  margin: 6px 0 0;
}
.climate-page .post-meta strong {
  font-style: normal;
  font-weight: var(--w-semibold);
  color: var(--ink-2);
}
/* Coverage-class note rendered when the picker falls back to a precip-only
   station — sets the user's expectation that temperature/snow/freeze facts
   are intentionally absent rather than missing-in-error. */
.climate-page .climo-coverage-note {
  font-style: italic;
  color: #b45309;
}
.climate-page .post-header-text {
  flex: 1 1 auto;
  min-width: 0;
}

/* Right side of the header — wraps the current-conditions block + locator
   map in a sub-flex with a tight gap so they sit close together, while
   the parent header's space-between still pushes the whole group to the
   right edge. */
.climate-page .climo-header-right {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

/* Current-conditions block in the header — sits between the title column
   and the locator map. Whole block is a link to /forecast for the same
   city. Empty when the forecast fetch failed so the header still lays
   out cleanly. */
.climate-page .climo-header-now {
  flex: 0 0 auto;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 0 12px;
  height: 90px;
  border-radius: 10px;
  color: inherit;
  text-decoration: none;
  transition: background 140ms cubic-bezier(0.2, 0, 0, 1);
  align-self: flex-start;
}
.climate-page .climo-header-now,
.climate-page .climo-header-now:hover {
  text-decoration: none;
}
.climate-page .climo-header-now:hover { background: rgba(0, 0, 0, 0.04); }
.climate-page .climo-header-now:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.climate-page .climo-header-now-temp {
  display: block;
  text-align: center;
  font-size: clamp(44px, 5vw, 58px);
  font-weight: 400;
  letter-spacing: -0.03em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 0.95;
}
.climate-page .climo-header-now-meta {
  display: block;
  text-align: center;
  line-height: 1.2;
}
.climate-page .climo-header-now-label {
  display: block;
  text-align: center;
  font-size: 10px;
  font-weight: var(--w-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.climate-page .climo-header-now-summary { display: none; }

/* Locator map anchor — wraps the iframe so all clicks navigate to
   /forecast/<slug> instead of trying to interact with the map below.
   iframe has pointer-events:none so the anchor catches every click. */
.climate-page .climo-header-map {
  flex: 0 0 auto;
  display: block;
  width: 150px;
  height: 90px;
  border-radius: 10px;
  background: #f4f5f7;
  overflow: hidden;
  text-decoration: none;
  /* Layered shadow stands in for a hard border — adapts to any background
     and reads as a quiet image outline instead of a chrome stroke. */
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.06),
    0 1px 2px rgba(0, 0, 0, 0.04);
  transition-property: box-shadow, transform;
  transition-duration: 160ms;
  transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
}
.climate-page .climo-header-map:hover {
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.08),
    0 2px 4px rgba(0, 0, 0, 0.06),
    0 8px 20px -6px rgba(0, 0, 0, 0.12);
  transform: translateY(-1px);
}
.climate-page .climo-header-map:active {
  transform: scale(0.97);
}
.climate-page .climo-header-map:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.climate-page .climo-header-map-frame {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  pointer-events: none;
}

/* Mobile: stack the map below the title at the same size. */
@media (max-width: 600px) {
  .climate-page .post-header {
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
  }
  .climate-page .climo-header-map {
    width: 150px;
    height: 90px;
  }
  .climate-page .climo-header-now { height: auto; padding: 0; }
}

/* Lede paragraph sits directly on the page (no card chrome) so it reads
   as the article's opening prose — Wikipedia-style. */
.climate-page .post-card.intro {
  background: transparent;
  border: 0;
  box-shadow: none;
  padding: 0;
  margin: 0 0 28px;
  border-radius: 0;
}
.climate-page .post-card.intro .lead {
  font-size: clamp(16px, 1.3vw, 18px);
  line-height: 1.65;
  color: var(--ink);
  margin: 0;
}

/* Promoted full-width sections (WeatherSpark-inspired) — each block is a
   labeled chart with a narrative paragraph above it, stacked vertically
   between the lede and the secondary card grid. The chart hosts inherit
   --climo-accent from data-category so the SVG fill picks up the category
   tint via currentColor. */
/* Promoted sections — Wikipedia article sections, not cards. No background,
   no shadow, no border; just an H2 with a thin rule, narrative below, and
   the chart in flow. Section spacing comes from margins, not padding. */
.climate-page .climo-section {
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin: 0 0 32px;
  box-shadow: none;
}
.climate-page .climo-section + .climo-section { margin-top: 0; }
.climate-page .climo-section-title {
  margin: 0 0 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid #c8ccd0;
  /* Wikipedia H2: serif, normal weight, large, with thin rule below. */
  font-family: 'Linux Libertine', Georgia, 'Times New Roman', Times, serif;
  font-size: clamp(20px, 2.2vw, 24px);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.3;
  color: var(--ink);
  text-wrap: balance;
}
.climate-page .climo-narrative {
  margin: 0 0 16px;
  color: var(--ink-2);
  font-size: 14.5px;
  line-height: 1.55;
  text-wrap: pretty;
  max-width: 64ch;
}
.climate-page .climo-narrative strong {
  color: var(--ink);
  font-weight: var(--w-semibold);
}
.climate-page .climo-section-chart {
  /* Hosts the same SVG charts the modal uses. Min-height matches the
     largest renderer (monthly_temps/cumulative at 160) plus padding so
     the layout doesn't jump while climate-sections.js hydrates. */
  min-height: 180px;
  color: var(--climo-accent, var(--ink-2));
}
.climate-page .climo-section-chart svg {
  width: 100%;
  height: auto;
  max-height: 240px;
  display: block;
}

@media (max-width: 600px) {
  .climate-page .climo-narrative { font-size: 14px; }
}

.climo-section-head {
  font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 13px;
  font-weight: var(--w-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 4px 12px;
}

/* Two-column layout beneath the intro: promoted full-width sections on
   the left, the secondary cards stacked vertically on the right. CSS
   grid handles column independence so the longer column doesn't push
   the shorter one's items into wasted space. */
.climate-page .climo-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  /* Wider column gap pushes the right-rail infobox off the body
     content; row gap doesn't matter (single-row layout). */
  gap: 40px;
  align-items: start;
}
.climate-page .climo-grid-left  { min-width: 0; }
.climate-page .climo-grid-right {
  min-width: 0;
  /* Drop the rail's top so it sits below the first promoted section's
     H2, not flush with the page top — Wikipedia-style "infobox floats
     in from the side a bit lower than the title." */
  padding-top: 12px;
}

/* Right rail = one Wikipedia-style infobox: a single bordered container,
   cards inside become rows separated by a thin divider. The grid is the
   container; individual cards drop their borders below. */
.climate-page .climo-grid-right .cards {
  grid-template-columns: 1fr;
  gap: 0;
  border: 1px solid #c8ccd0;
  border-radius: 2px;
  background: #f8f9fa;
  overflow: hidden;
}
.climate-page .climo-grid-right .cards .climo-card {
  border: 0;
  border-radius: 0;
  border-top: 1px solid #e3e6ea;
  background: transparent;
}
.climate-page .climo-grid-right .cards .climo-card:first-child {
  border-top: 0;
}
.climate-page .climo-grid-right .cards .climo-card:hover {
  background: #eaecf0;
}

@media (max-width: 800px) {
  .climate-page .climo-grid {
    grid-template-columns: 1fr;
    gap: 16px;
  }
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
}

.climo-card {
  background: #ffffff;
  border: 1px solid #f0f0f0;
  border-radius: 16px;
  padding: 18px 20px 16px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);
  font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif);
  display: flex; flex-direction: column; gap: 6px;
}
.climo-card .eyebrow {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0;
  font-weight: var(--w-medium);
}
.climo-card .v {
  font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 15px;
  font-weight: 450;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 0;
  font-variant-numeric: tabular-nums;
  line-height: 1.3;
}
/* Provenance line under a card value when the fact was sourced from a
   different station than the page's anchor (the snow-override path). */
.climo-card-via {
  font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 11.5px;
  font-style: italic;
  color: var(--ink-3);
  margin: 4px 0 0;
}
.climo-card .desc {
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1.55;
  text-wrap: pretty;
}

/* Feature card — same infobox treatment as the rest of the rail.
   The "feature" distinction stays in the data model but the visual
   pop is dropped so the right column reads as a uniform Wikipedia
   infobox column. */
.climo-card.feature {
  grid-column: auto;
  margin: 0;
}
.climo-card.feature .v { font-size: 15px; }
.climo-card.feature .desc { font-size: 13px; }

/* Minimized page footer — back-link + one-line attribution, no card chrome.
   Per-fact provenance lives in the modal footer, so this is intentionally
   sparse: just enough to get the user back to today's forecast plus a
   single-line credit to the underlying public-domain dataset. */
/* Page footer — Wikipedia-style closing band: thin top rule, small
   italic gray text. Mirrors the "Retrieved from..." footer on enwiki. */
.climate-page .climo-page-footer {
  margin: 40px 0 0;
  padding: 12px 0 0;
  border-top: 1px solid #c8ccd0;
  color: var(--ink-3);
  font-size: 12.5px;
  line-height: 1.5;
  font-style: italic;
}
.climate-page .climo-page-footer strong,
.climate-page .climo-page-footer a { font-style: normal; }
.climate-page .climo-page-footer-src { color: var(--ink-3); }

/* Empty state when no station within range (rare; AK/HI long-tail
   coordinates). Quiet, doesn't pretend to have data we don't. */
.climo-empty {
  background: #fff;
  border: 1px solid #f0f0f0;
  border-radius: 16px;
  padding: 28px;
  font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif);
  color: var(--ink-2);
}
.climo-empty a { color: var(--link); }

/* ====================================================================
   /climate v2 — card-as-button + modal + viz.
   Strictly additive over the existing .climo-* rules above. Existing
   selectors stay intact for backwards compat with the cached SSR HTML
   from the v1 cards (they keep looking right while wrangler rolls the
   new bundle out across edges).
   ==================================================================== */

/* Per-category accent palette. The accent shows on the card's glyph
   (currentColor on the <svg>) + the eyebrow text. Card body stays
   neutral so 15 colored cards never feel like a marketing landing. */
.climo-card[data-category="heat"]  { --climo-accent: #c2410c; }
.climo-card[data-category="cold"]  { --climo-accent: #1d4ed8; }
.climo-card[data-category="rain"]  { --climo-accent: #0369a1; }
.climo-card[data-category="snow"]  { --climo-accent: #475569; }
.climo-card[data-category="storm"] { --climo-accent: #7c3aed; }

/* Cards in Wikipedia-infobox style: thin border, no shadow, small radius,
   subtle hover background. The right rail reads as a single "More facts"
   sidebar instead of a stack of competing cards. */
.climo-card {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
  background: #fafafa;
  border: 1px solid #e3e6ea;
  border-radius: 4px;
  box-shadow: none;
  padding: 12px 14px 12px;
  transition-property: background-color, border-color, transform;
  transition-duration: 140ms;
  transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
}
.climo-card:hover {
  background: #f1f3f5;
  border-color: #c8ccd0;
}
.climo-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.climo-card:active {
  transform: scale(0.97);
}

/* Glyph in the card's top-left, sized for visual weight ≈ the eyebrow
   text. Color inherits from --climo-accent (or --ink-3 as fallback) so
   the category palette propagates without extra selectors. */
.climo-card .climo-glyph {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  color: var(--climo-accent, var(--ink-3));
  align-self: flex-start;
}

/* Header row: glyph + eyebrow stacked horizontally so the visual
   anchor lives at the top of every card. */
.climo-card .climo-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 2px;
}
.climo-card .eyebrow {
  /* Existing rule already sets size/weight/transform/letter-spacing.
     Here we override the muted gray for cards that opted into a
     category so the eyebrow picks up the same accent as the glyph. */
  color: var(--climo-accent, var(--ink-3));
}

/* Feature card keeps its blue treatment but inherits the new button
   chrome + interaction states from above. Override the v1
   `background: #f5f8ff` only when no per-category accent is set
   (the feature card is currently the rainiest-dow which is "rain"). */
.climo-card.feature {
  border: 0;
}

/* Subtle chevron affordance — appears on hover/focus to signal that the
   card is interactive. SVG is inline-rendered by JS; selector reserves
   space + animates opacity. */
.climo-card .climo-chevron {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 14px;
  height: 14px;
  color: var(--ink-3);
  opacity: 0;
  transition: opacity 150ms cubic-bezier(0.2, 0, 0, 1);
  pointer-events: none;
}
.climo-card { position: relative; }
.climo-card:hover .climo-chevron,
.climo-card:focus-visible .climo-chevron { opacity: 1; }

/* Reduced-motion: strip the transform + shadow transitions so the
   page is fully static for users who asked for it. */
@media (prefers-reduced-motion: reduce) {
  .climo-card {
    transition: none;
  }
  .climo-card:active {
    transform: none;
  }
  .climo-card .climo-chevron {
    transition: none;
  }
}

/* ---- Modal (`<dialog class="climo-detail">`) -------------------- */

.climo-detail {
  /* Reset the user-agent's dialog defaults. We rebuild from scratch
     so the dialog matches the post-card surface. */
  padding: 0;
  border: 0;
  border-radius: 16px;
  background: #ffffff;
  color: var(--ink);
  max-width: min(600px, 92vw);
  width: 100%;
  max-height: min(82vh, 720px);
  overflow: hidden;
  box-shadow:
    0 24px 48px -16px rgba(0, 0, 0, 0.22),
    0 4px 8px rgba(0, 0, 0, 0.04);
  font: inherit;
}

/* Flex column only applies when the dialog is open — otherwise it
   overrides the user-agent's `display: none` and the closed dialog
   leaks into the page flow as a stray inline block. */
.climo-detail[open] {
  display: flex;
  flex-direction: column;
}

.climo-detail::backdrop {
  background: rgba(17, 17, 17, 0.42);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  animation: climo-detail-backdrop-in 180ms ease-out;
}

/* Enter animation — modeled on roadmap's rd-dialog-in. Fade + small
   scale lift, no translateY (we don't want a "slamming" feel). */
.climo-detail[open] {
  animation: climo-detail-in 220ms cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes climo-detail-in {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes climo-detail-backdrop-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.climo-detail-close {
  position: absolute;
  top: 10px;
  right: 10px;
  /* 40×40 minimum hit area; the visible glyph (18×18) is centered inside. */
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  border-radius: 10px;
  color: var(--ink-3);
  cursor: pointer;
  transition-property: background-color, color;
  transition-duration: 140ms;
  transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
}
.climo-detail-close:hover { background: rgba(0, 0, 0, 0.04); color: var(--ink); }
.climo-detail-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.climo-detail-close svg { width: 18px; height: 18px; }

/* Body wraps the headline + chart + explainer. The method disclosure and
   provenance live outside as sibling footer strips so they stay pinned to
   the bottom while the body flex-shrinks. */
.climo-detail-body {
  padding: 28px 36px 24px;
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
}

.climo-detail-header {
  /* Headline sits directly under the eyebrow; tighten the gap so they
     read as one block. */
  margin: 0 0 10px;
}
.climo-detail-title {
  margin: 0;
  font-size: clamp(15px, 1.6vw, 17px);
  font-weight: var(--w-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--climo-detail-accent, var(--ink-3));
  text-wrap: balance;
}

/* Chart sits beneath the headline group; min-height covers every
   renderer's natural viewBox without the layout jumping between fact
   types (top5 ~ 6 rows × 24px ≈ 144px; monthly_temps 160; etc.). */
.climo-detail-viz {
  margin: 20px 0 0;
  min-height: 160px;
}
.climo-detail-viz:empty { display: none; }
.climo-detail-viz svg { max-height: 220px; }

/* Headline absorbs the old big "August (4.9 in)" value. It's the lede
   under the chart, not a competing centerpiece — the chart's highlighted
   bar already shows the number. */
.climo-detail-headline {
  margin: 0;
  font-size: clamp(20px, 2.4vw, 24px);
  font-weight: var(--w-semibold);
  letter-spacing: -0.02em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  text-wrap: balance;
}

/* Comparison phrase — the "about 2× a typical month" line. Picks up the
   category accent so it reads as a quantitative caption, not body prose. */
.climo-detail-context {
  margin: 6px 0 0;
  font-size: 14.5px;
  line-height: 1.45;
  font-weight: var(--w-medium);
  color: var(--climo-detail-accent, var(--ink-2));
}
.climo-detail-context[hidden] { display: none; }

/* "What this measures" is now a single muted explainer line, no h3. */
.climo-detail-what {
  margin: 18px 0 0;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.55;
  text-wrap: pretty;
}

/* "How it's computed" — the dialog's bottom footer band. Muted background
   + top border gives the disclosure its own visual zone so the body above
   reads as the main content. Click anywhere on the strip to expand the
   methodology paragraph beneath. */
.climo-detail-method {
  flex: 0 0 auto;
  margin: 0;
  font-size: 13.5px;
  border-top: 1px solid var(--rule);
  background: var(--bg-muted);
}
.climo-detail-method > summary {
  list-style: none;
  cursor: pointer;
  color: var(--ink-3);
  font-weight: var(--w-semibold);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  /* Full-strip click target; padding gives 40px+ hit area without
     needing pseudo-element trickery. */
  padding: 14px 36px;
  display: flex;
  align-items: center;
  gap: 8px;
  transition-property: background-color, color;
  transition-duration: 140ms;
  transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
}
.climo-detail-method > summary::-webkit-details-marker { display: none; }
.climo-detail-method > summary::before {
  content: '';
  display: inline-block;
  width: 0;
  height: 0;
  border-left: 4px solid currentColor;
  border-top: 3px solid transparent;
  border-bottom: 3px solid transparent;
  transition: transform 140ms cubic-bezier(0.2, 0, 0, 1);
}
.climo-detail-method[open] > summary::before {
  transform: rotate(90deg);
}
.climo-detail-method > summary:hover {
  color: var(--ink);
  background: rgba(0, 0, 0, 0.03);
}
.climo-detail-method > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.climo-detail-method > p {
  margin: 0;
  padding: 0 36px 16px;
  color: var(--ink-2);
  line-height: 1.55;
  text-wrap: pretty;
}

/* ---- Mobile: bottom sheet -------------------------------------- */

@media (max-width: 600px) {
  .climo-detail {
    max-width: 100%;
    width: 100%;
    margin: 0;
    border-radius: 16px 16px 0 0;
    /* Pin to bottom — browser default centers; override the inset
       so showModal() lands the sheet at the bottom of the viewport. */
    position: fixed;
    inset: auto 0 0 0;
    max-height: 92vh;
    animation: climo-sheet-in 280ms cubic-bezier(0.32, 0.72, 0, 1);
  }
  @keyframes climo-sheet-in {
    from { transform: translateY(100%); opacity: 0.6; }
    to   { transform: translateY(0);    opacity: 1;   }
  }
  .climo-detail-body {
    padding: 36px 24px 20px;
  }
  .climo-detail-method > summary { padding-left: 24px; padding-right: 24px; }
  .climo-detail-method > p { padding-left: 24px; padding-right: 24px; }
}

/* Reduced-motion: simple opacity fade only. */
@media (prefers-reduced-motion: reduce) {
  .climo-detail[open] { animation: none; }
  .climo-detail::backdrop { animation: none; }
  @media (max-width: 600px) {
    .climo-detail { animation: none; }
  }
}

/* Body scroll lock while a dialog is open. Scrollbar-gutter keeps the
   layout from shifting when the scrollbar disappears. */
html { scrollbar-gutter: stable; }
body.modal-open { overflow: hidden; }

/* View Transitions API hint: keep cards + modal stable while the
   browser morphs them. Names are assigned per-card by the JS. */
.climo-card.is-opening,
.climo-detail[open] {
  view-transition-name: var(--vt-name, none);
}

/* ---- Viz containers (sub-elements of .climo-detail-viz) -------- */

.climo-detail-viz svg {
  width: 100%;
  height: auto;
  max-height: 200px;
  display: block;
  color: var(--climo-detail-accent, var(--ink-2));
}

/* Top-N row list (top5 / top3 renderers share this). */
.climo-detail-viz .climo-rank-list {
  display: grid;
  grid-template-columns: 24px 1fr auto;
  gap: 6px 12px;
  align-items: center;
  font-size: 13.5px;
}
.climo-detail-viz .climo-rank-row {
  display: contents;
}
.climo-detail-viz .climo-rank-num {
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.climo-detail-viz .climo-rank-bar {
  height: 6px;
  background: var(--climo-detail-accent, var(--ink-3));
  border-radius: 3px;
  align-self: center;
  opacity: 0.85;
}
.climo-detail-viz .climo-rank-bar-track {
  background: rgba(0,0,0,0.04);
  border-radius: 3px;
  height: 6px;
  width: 100%;
  position: relative;
}
.climo-detail-viz .climo-rank-meta {
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  font-weight: var(--w-semibold);
  font-size: 13.5px;
  white-space: nowrap;
}
.climo-detail-viz .climo-rank-meta small {
  display: block;
  color: var(--ink-3);
  font-weight: 400;
  font-size: 11.5px;
  margin-top: 1px;
}

/* /climate (bare) — landing index. Rendered by functions/climate/index.js
   inside `.legal.blog-post.climate-page`, so it inherits the Wiki-style
   post-header (serif H1, thin gray rule) and reuses `.climo-section-title`
   for the H2s. Cards link out to the per-city /climate/<slug> pages.
   Visual register matches the per-city secondary cards: white surface,
   1px light border, subtle shadow, no rounded marketing chrome. */
.climate-page .climo-index { margin-top: 8px; }

.climate-page .climo-index-lede {
  font-size: clamp(15px, 1.25vw, 17px);
  line-height: 1.65;
  color: var(--ink);
  margin: 0 0 28px;
  max-width: 70ch;
  text-wrap: pretty;
}

.climate-page .climo-index-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px;
  margin: 0 0 36px;
}

.climate-page .climo-index-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: #ffffff;
  border: 1px solid #e3e6ea;
  border-radius: 10px;
  padding: 16px 18px;
  text-decoration: none;
  color: inherit;
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.climate-page .climo-index-card:hover {
  border-color: #c8ccd0;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
  transform: translateY(-1px);
}
.climate-page .climo-index-card:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 2px;
}

.climate-page .climo-index-card-title {
  margin: 0;
  font-family: 'Linux Libertine', Georgia, 'Times New Roman', Times, serif;
  font-size: 19px;
  font-weight: 400;
  line-height: 1.2;
  color: var(--link);
}
.climate-page .climo-index-card-state {
  font-weight: 400;
  color: var(--ink-3);
}
.climate-page .climo-index-card:hover .climo-index-card-title {
  text-decoration: underline;
}

.climate-page .climo-index-card-type {
  margin: -4px 0 0;
  font-size: 12.5px;
  font-style: italic;
  color: var(--ink-3);
  letter-spacing: 0.01em;
}

.climate-page .climo-index-card-ribbon {
  display: block;
  width: 100%;
  height: auto;
  margin: 4px 0 2px;
}

.climate-page .climo-index-card-stat {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0;
  padding: 6px 0;
  border-top: 1px solid #eef0f2;
  border-bottom: 1px solid #eef0f2;
}
.climate-page .climo-index-card-stat-val {
  font-size: 17px;
  font-weight: var(--w-semibold);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.climate-page .climo-index-card-stat-label {
  font-size: 12px;
  color: var(--ink-3);
  letter-spacing: 0.01em;
}

.climate-page .climo-index-card-lede {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-2);
  text-wrap: pretty;
}

.climate-page .climo-index-about {
  font-size: 14px;
  line-height: 1.65;
  color: var(--ink-2);
  margin: 0;
  max-width: 75ch;
  text-wrap: pretty;
}
.climate-page .climo-index-about strong {
  color: var(--ink);
  font-weight: var(--w-semibold);
}

/* Long-tail "All covered locations" — region groups. Each region is a
   block: serif H3 heading, a list of city rows beneath. Rows are
   `<City, ST>` link + a small climate-type tag on the right, separated
   by a thin row rule (no card chrome — matches the right-rail infobox
   density on the per-city pages). Grid lays out the region blocks in a
   2-column flow on desktop, single-column on mobile. */
.climate-page .climo-index-region-intro {
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink-2);
  margin: 0 0 16px;
  max-width: 70ch;
}
.climate-page .climo-index-regions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 24px 40px;
  margin: 0 0 36px;
}
.climate-page .climo-index-region-name {
  font-family: 'Linux Libertine', Georgia, 'Times New Roman', Times, serif;
  font-size: 18px;
  font-weight: 400;
  color: var(--ink);
  margin: 0 0 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid #e3e6ea;
}
.climate-page .climo-index-region-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.climate-page .climo-index-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 5px 0;
  border-bottom: 1px solid #f0f2f4;
  font-size: 14px;
  line-height: 1.4;
}
.climate-page .climo-index-row:last-child {
  border-bottom: 0;
}
.climate-page .climo-index-row-link {
  color: var(--link);
  text-decoration: none;
  min-width: 0;
  flex: 0 1 auto;
}
.climate-page .climo-index-row-link:hover {
  text-decoration: underline;
}
.climate-page .climo-index-row-type {
  font-size: 12.5px;
  color: var(--ink-3);
  font-style: italic;
  flex-shrink: 0;
  text-align: right;
}

/* ============================================================
   /press — Press Kit
   Single light editorial column. All vertical rhythm comes from
   one --pk-gap token; section padding and inner width are shared.
   Media tiles share a frame + caption + hover treatment and open
   a full-screen <dialog> modal on click. Labeled placeholder
   slots stand in for media not yet exported (iPad / Mac / 2nd
   watch) so the layout is complete and real exports drop in.
   ============================================================ */

.press-kit-page {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.pk {
  --pk-maxw: 1040px;
  --pk-gap: clamp(52px, 7vw, 84px);
  --pk-frame-radius: 0;
  --pk-accent: var(--accent, #2f7bff);
  max-width: var(--pk-maxw);
  margin: 0 auto;
  padding: clamp(40px, 6vw, 76px) var(--pad-x) clamp(80px, 11vw, 128px);
  display: flex;
  flex-direction: column;
  gap: var(--pk-gap);
}
.pk *, .pk *::before, .pk *::after { box-sizing: border-box; }

/* ----- section heads ----- */
.pk-block-head { margin: 0 0 clamp(18px, 3vw, 28px); }
.pk-h2 {
  font-size: clamp(1.2rem, 2.6vw, 1.55rem);
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-heading);
  line-height: 1.2;
  margin: 0;
  color: var(--ink);
}
.pk-block-head p {
  margin: 8px 0 0;
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 64ch;
}

/* ----- masthead ----- */
.pk-mast-mark {
  width: clamp(48px, 7vw, 64px);
  height: auto;
  display: block;
  margin: 0 0 22px;
}
.pk-mast h1 {
  font-size: clamp(2rem, 5vw, 2.9rem);
  font-weight: var(--w-bold);
  letter-spacing: var(--track-display);
  line-height: 1.05;
  margin: 0;
  color: var(--ink);
}
.pk-mast-ver {
  display: inline-block;
  margin: 16px 0 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ----- intro ----- */
.pk-intro { display: flex; flex-direction: column; gap: 14px; max-width: 72ch; }
.pk-intro p {
  margin: 0;
  font-size: clamp(1.0625rem, 0.9rem + 0.5vw, 1.2rem);
  line-height: 1.6;
  color: var(--ink);
}

/* ----- highlights ----- */
.pk-highlights {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 48px;
}
@media (max-width: 600px) { .pk-highlights { grid-template-columns: 1fr; } }
.pk-highlights li {
  position: relative;
  padding: 10px 0 10px 20px;
  font-size: 15px;
  color: var(--ink);
  line-height: 1.5;
}
.pk-highlights li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 1.05em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #bcbcbc;
}

/* ----- media tiles: shared ----- */
.pk-tile {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  text-align: inherit;
  color: inherit;
}
.pk-tile:focus-visible { outline: 2px solid var(--pk-accent); outline-offset: 5px; border-radius: 4px; }

.pk-frame {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: #000;
  border: 1px solid var(--rule);
  border-radius: var(--pk-frame-radius);
}
.pk-frame img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* frame variants — proportions match each asset's real ratio */
/* iPhone captures show raw, with no added bezel/border/corners. */
.pk-frame--phone { aspect-ratio: 174 / 379; background: none; border: 0; border-radius: 0; }
.pk-frame--ipad  { aspect-ratio: 4 / 3; border-radius: 0; }

/* Rotato 3D renders and the promo card carry their own (transparent / white)
   backgrounds, so they sit on a light card, contained — not in the dark
   screenshot bezel that full-bleed simulator captures need. */
.pk-frame--render { background: #f6f6f6; }
.pk-frame--promo  { background: #fff; aspect-ratio: 754 / 424; }
.pk-frame--render img, .pk-frame--promo img { object-fit: contain; }
.pk-frame--watch { aspect-ratio: 2 / 3; border-radius: 0; }
.pk-frame--mac   { aspect-ratio: 919 / 551; border-radius: 0; }

/* ----- screenshots grid (iPhone) ----- */
.pk-shots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: clamp(16px, 2.4vw, 24px);
  margin: 0;
}
.pk-shot { margin: 0; }

/* ----- devices row (watch + mac) ----- */
.pk-devices {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(16px, 2.6vw, 28px);
  align-items: flex-start;
}
.pk-device { margin: 0; }
.pk-device--watch { flex: 1 1 180px; }
.pk-device--mac { flex: 2 1 360px; min-width: 280px; }

/* ----- iPad stack ----- */
.pk-ipads { display: grid; gap: clamp(18px, 2.6vw, 30px); margin: 0; }
.pk-ipad { margin: 0; }

/* ----- promo ----- */
.pk-promo-fig { margin: 0; }

/* ----- full-screen image modal ----- */
.pk-modal {
  width: 100vw;
  height: 100vh;
  max-width: 100vw;
  max-height: 100vh;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  inset: 0;
}
.pk-modal[open] { display: flex; align-items: center; justify-content: center; }
.pk-modal::backdrop {
  background: rgba(0, 0, 0, 0.78);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.pk-modal-inner {
  position: relative;
  padding: 24px;
  animation: pkModalIn 0.26s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes pkModalIn {
  from { opacity: 0; transform: scale(0.95) translateY(8px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .pk-modal-inner { animation: none; } }
.pk-modal-img {
  display: block;
  width: auto;
  height: auto;
  max-width: min(1100px, 92vw);
  max-height: 88vh;
  object-fit: contain;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.5);
}
.pk-modal-close {
  position: fixed;
  top: 18px;
  right: 18px;
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.24);
  background: rgba(0, 0, 0, 0.42);
  color: #fff;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}
.pk-modal-close svg { display: block; }
.pk-modal-close:hover { background: rgba(0, 0, 0, 0.66); }
