/* ============================================================================
   GoCheckMyWeather - design system
   Media-desk chassis (News/Sports/Crypto dashboard language) on the family
   master palette. Two modes: light is default, dark follows system preference
   unless the user overrides via html[data-theme]. Every text/ground pair here
   was contrast-checked to WCAG AA before it shipped; Medium Teal #3F8F97 and
   Soft Teal #79B8BE are decorative-only in light mode (family -ink standard).
   Motion discipline: nothing autoplays, nothing blinks; transitions are subtle
   and removed under prefers-reduced-motion.
   ========================================================================== */

:root{
  --paper:#F5F4EF;      --card:#FFFFFF;       --ink:#1C1E1F;
  --muted:#585E62;      --faint:#5F6569;      --line:#E3E0D6;
  --rule:#184454;       /* Deep Teal: masthead rule, brand, kickers */
  --accent:#3F8F97;     /* Medium Teal: decorative accents only */
  --accent-soft:#79B8BE;/* Soft Teal: decorative data accents only */
  --teal-ink:#2A6B72;   /* teal TEXT that must pass AA */
  --copper:#9C4A21;     /* Burnt Copper: alert-adjacent accents only */
  --copper-ink:#8F431D; /* copper TEXT that must pass AA */
  --link:#155A74;       --link-hover:#0D3D50;
  --chip-bg:#ECE9DF;    --chip-fg:#44494E;
  --sev-extreme-fg:#7A1F1F; --sev-extreme-bg:#F6DEDE;
  --sev-severe-fg:#8F431D;  --sev-severe-bg:#F7E4D9;
  --sev-moderate-fg:#6E5300;--sev-moderate-bg:#F6ECCB;
  --sev-minor-fg:#28546B;   --sev-minor-bg:#DFEAF1;
  --ok-fg:#1F6B45;
  --map-sea:#E4EBEB; --map-land:#F8F7F1; --map-coast:#A9B8B8; --map-line:#CBD2CC;
  --map-label:#242B30; --map-label-halo:rgba(255,255,255,.95);
  --shadow:0 22px 50px -34px rgba(20,26,30,.4);
  --serif:'Newsreader',Georgia,'Times New Roman',serif;
  --sans:'Inter',system-ui,-apple-system,sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,'SFMono-Regular',monospace;
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme=light]){
    --paper:#1F2021; --card:#2B2B2B; --ink:#EDEBE6;
    --muted:#ADB2B3; --faint:#A0A5A7; --line:#3A3B3C;
    --rule:#79B8BE; --accent:#3F8F97; --accent-soft:#79B8BE;
    --teal-ink:#8FC6CC; --copper:#E0906A; --copper-ink:#E0906A;
    --link:#8FC6CC; --link-hover:#B6DCE0;
    --chip-bg:#353637; --chip-fg:#C4C9CA;
    --sev-extreme-fg:#F0B9B9; --sev-extreme-bg:#3A2020;
    --sev-severe-fg:#EFB694;  --sev-severe-bg:#3A2A1E;
    --sev-moderate-fg:#EAD28A;--sev-moderate-bg:#393012;
    --sev-minor-fg:#A9CBDD;   --sev-minor-bg:#1E3340;
    --ok-fg:#7FC9A0;
    --map-sea:#191F22; --map-land:#2A2E30; --map-coast:#55605F; --map-line:#3C4442;
  --map-label:#DCE2E5; --map-label-halo:rgba(8,12,16,.95);
    --shadow:0 22px 50px -30px rgba(0,0,0,.7);
  }
}
:root[data-theme=dark]{
  --paper:#1F2021; --card:#2B2B2B; --ink:#EDEBE6;
  --muted:#ADB2B3; --faint:#A0A5A7; --line:#3A3B3C;
  --rule:#79B8BE; --accent:#3F8F97; --accent-soft:#79B8BE;
  --teal-ink:#8FC6CC; --copper:#E0906A; --copper-ink:#E0906A;
  --link:#8FC6CC; --link-hover:#B6DCE0;
  --chip-bg:#353637; --chip-fg:#C4C9CA;
  --sev-extreme-fg:#F0B9B9; --sev-extreme-bg:#3A2020;
  --sev-severe-fg:#EFB694;  --sev-severe-bg:#3A2A1E;
  --sev-moderate-fg:#EAD28A;--sev-moderate-bg:#393012;
  --sev-minor-fg:#A9CBDD;   --sev-minor-bg:#1E3340;
  --ok-fg:#7FC9A0;
  --map-sea:#191F22; --map-land:#2A2E30; --map-coast:#55605F; --map-line:#3C4442;
  --map-label:#DCE2E5; --map-label-halo:rgba(8,12,16,.95);
  --shadow:0 22px 50px -30px rgba(0,0,0,.7);
}

*{box-sizing:border-box}
[hidden]{display:none!important}
html{scroll-behavior:smooth}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--sans);font-size:17px;line-height:1.6;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
.wrap{max-width:1080px;margin:0 auto;padding:0 22px}
.narrow{max-width:760px}
a{color:var(--link);text-decoration:none}
a:hover{color:var(--link-hover);text-decoration:underline}
img{max-width:100%;height:auto}
:focus-visible{outline:3px solid var(--rule);outline-offset:2px;border-radius:2px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.skip-link{position:absolute;left:-9999px;top:0;background:var(--card);color:var(--ink);
  padding:10px 16px;z-index:200;border:2px solid var(--rule);border-radius:0 0 6px 0;font-weight:600}
.skip-link:focus{left:0}

/* ---- masthead -------------------------------------------------------------- */
.top-rule{height:4px;background:var(--rule)}
.masthead{background:var(--card);border-bottom:1px solid var(--line)}
.masthead .wrap{padding-top:16px;padding-bottom:12px}
.mh-top{display:flex;align-items:baseline;justify-content:space-between;gap:16px;flex-wrap:wrap}
.mh-dateline{font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--faint)}
.mh-family{font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);font-weight:600}
.mh-brand{display:flex;align-items:center;gap:12px;text-decoration:none;margin-top:8px}
.mh-brand:hover{text-decoration:none}
.mh-mark{width:38px;height:38px;flex:none}
.mh-word{font-family:var(--serif);font-weight:600;color:var(--ink);line-height:1;
  font-size:clamp(28px,5.2vw,46px);letter-spacing:-.01em}
.mh-word-site{color:var(--rule);font-style:italic}
.mh-slogan{font-family:var(--serif);font-style:italic;color:var(--muted);
  font-size:clamp(13px,1.6vw,16px);text-align:right;max-width:240px;margin-left:auto}
.mh-nav{border-top:1px solid var(--line);border-bottom:1px solid var(--line);background:var(--card);
  position:sticky;top:0;z-index:50}
.mh-nav .wrap{display:flex;gap:2px;align-items:center;overflow-x:auto}
.mh-nav a{font-family:var(--mono);font-size:12.5px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--muted);padding:11px 12px;white-space:nowrap;border-bottom:3px solid transparent}
.mh-nav a:hover{color:var(--ink);text-decoration:none}
.mh-nav a.active{color:var(--ink);border-bottom-color:var(--rule);font-weight:600}
.theme-toggle{margin-left:auto;font-family:var(--mono);font-size:12px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--muted);background:none;border:1px solid var(--line);
  border-radius:6px;padding:6px 10px;cursor:pointer;white-space:nowrap}
.theme-toggle:hover{color:var(--ink);border-color:var(--muted)}
@media (max-width:700px){
  /* narrow widths: wrap the links into rows at a legible size with tappable
     targets, instead of a tiny strip scrolling off-screen with no hint; a
     two or three row bar must not ride sticky over a small screen */
  .mh-nav{position:static}
  .mh-nav .wrap{flex-wrap:wrap;overflow-x:visible}
  .mh-nav a{font-size:14px;padding:12px 13px}
  .theme-toggle{margin:8px 0 8px auto;min-height:44px;padding:6px 14px}
}

/* ---- section heads and cards ---------------------------------------------- */
main{padding:26px 0 40px}
.sec-head{display:flex;align-items:baseline;gap:14px;margin:26px 0 14px}
.sec-head h2{font-family:var(--serif);font-weight:600;font-size:24px;margin:0;letter-spacing:-.01em}
.sec-head .bar{flex:1;height:1px;background:var(--line)}
.sec-head .sec-note{font-family:var(--mono);font-size:11px;color:var(--faint);white-space:nowrap}
/* nowrap is right on a wide screen and wrong on a phone: the hurricane
   section head carries "advisory 46 | 1100 AM HST Sun Aug 23 2026", which
   measured 271px and pushed the whole page 29px sideways at 390. It wraps
   below 640 instead, where there is no room to hold it on one line. */
@media (max-width:640px){
  .sec-head .sec-note{white-space:normal;min-width:0}
  .sec-head{flex-wrap:wrap;row-gap:4px}
}
.card{background:var(--card);border:1px solid var(--line);border-radius:10px;
  box-shadow:var(--shadow);padding:18px 20px;margin:0 0 18px}
.card h3{font-family:var(--serif);font-weight:600;font-size:19px;margin:0 0 10px;letter-spacing:-.01em}
.card .kicker{display:block;font-family:var(--mono);font-size:11px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--teal-ink);font-weight:600;margin-bottom:4px}
.card-foot{display:flex;flex-wrap:wrap;gap:6px 16px;justify-content:space-between;align-items:baseline;
  border-top:1px solid var(--line);margin-top:14px;padding-top:10px}
.stamp{font-family:var(--mono);font-size:11px;color:var(--faint)}
.stamp.stale{color:var(--copper-ink);font-weight:600}
.src{font-family:var(--mono);font-size:11px;color:var(--faint)}
/* ---- Today against the record book ----------------------------------------
   One shared scale from the coldest this date has ever been to the warmest,
   with today's forecast range, the normal, and the current reading on it.

   THE GRADIENT IS SAMPLED FROM THE SCALE IN JS, not declared here. A fixed
   gradient painted across the bar would put red at the right hand end whether
   that end is 94 degrees or 44, which makes the colour decorative. Sampling
   the temperature ramp at the real values means a colour on this bar always
   means the same temperature, and the delineation from blue through green and
   yellow to red is the full saturated ramp rather than a washed out three
   stop version of it.

   Every mark carries its own label in ONE row. The reading used to float above
   the bar with its number on a second line and a separate legend below that,
   which put four values on three rows and read as clutter. */
.rb{margin-top:6px}
.rb-cap{font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  color:#C9D2D8;margin:0 0 8px}
.rb-track{position:relative;height:58px;margin:30px 0 8px}
/* the bar is a thin rail; the marks hang below it, never on top of the colour */
.rb-rail{position:absolute;left:0;right:0;top:14px;height:9px;border-radius:99px;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.25)}

/* today's forecast range: a bracket over the bar, because it is a different
   kind of claim from the historical marks under it */
.rb-today{position:absolute;top:6px;height:7px;border-radius:99px;
  border:1.5px solid rgba(255,255,255,.85);border-bottom:0;
  box-shadow:0 -1px 6px rgba(0,0,0,.35)}
.rb-today-lab{position:absolute;top:-16px;transform:translateX(-50%);white-space:nowrap;
  font-family:var(--mono);font-size:10px;letter-spacing:.06em;color:#F4F1EA;
  text-shadow:0 1px 4px rgba(0,0,0,.8)}

.rb-tick{position:absolute;top:10px;transform:translateX(-50%);text-align:center;z-index:2}
.rb-tick i{display:block;width:2px;height:17px;margin:0 auto;border-radius:2px;
  background:rgba(255,255,255,.75);box-shadow:0 0 0 1px rgba(10,15,20,.45)}
.rb-tick b{display:block;font-family:var(--mono);font-size:10px;font-weight:400;
  margin-top:6px;white-space:nowrap;color:#DDE4E8;text-shadow:0 1px 4px rgba(0,0,0,.75)}
.rb-norm i{background:#fff;width:3px}
.rb-norm b{color:#fff;font-weight:600}

/* the reading: the only mark here that is a measurement rather than
   climatology, so it is the only one that is lit */
.rb-now{z-index:3}
.rb-now i{width:4px;height:25px;background:#fff;margin-top:-4px;
  box-shadow:0 0 14px 3px var(--t-ink-dark,#fff), 0 0 26px 7px var(--t-ink-dark,transparent)}
.rb-now b{color:#fff;font-weight:700;font-size:11px}

/* dropped to a second line because it collided with a label already placed */
.rb-tick-drop b{margin-top:24px}
.rb-say{font-size:15px;line-height:1.55;color:var(--ink);margin:22px 0 0}
@media (max-width:640px){
  .rb-track{height:64px}
  .rb-tick b{font-size:9px}
  /* four labels in one row will collide on a phone, so they alternate */
  .rb-tick:nth-child(even) b{margin-top:20px}
}

/* ---- the week ---------------------------------------------------------------
   Four columns, matching the design prototype: what day, what it will be like,
   how warm across one shared scale, and how likely to rain. The earlier version
   showed only the bars and pushed conditions, rain and wind into a collapsed
   table, which made the board prettier and less useful.

   The bar tints by its own two temperatures, so a cold day and a hot day of the
   same swing do not look identical. Colour is never the only carrier: both
   numbers sit at the ends of every bar.

   The low and high labels ride the bar ends rather than sitting in fixed
   columns, which is what makes the week's shape legible at a glance. That needs
   horizontal padding on the rail so a label at 0 or 100 percent has somewhere
   to go. */
.wk{margin:2px 0 0}
.wk-head,.wk-row{display:grid;grid-template-columns:6.4em minmax(0,1fr) minmax(150px,2fr) 7.2em;
  gap:0 16px;align-items:center}
.wk-head{font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--faint);padding-bottom:9px;border-bottom:1px solid var(--line)}
.wk-h-right{text-align:right}
.wk-row{padding:11px 0;border-bottom:1px solid var(--line)}
.wk-row:last-child{border-bottom:0}
.wk-day{font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.wk-cond{display:flex;align-items:center;gap:10px;min-width:0}
.wk-cond-text{font-family:var(--serif);font-style:italic;font-size:14.5px;color:var(--ink);line-height:1.35}
/* 44px is a measured floor, not a taste call. Below it these illustrations stop
   distinguishing themselves from each other, which would make the icon actively
   misleading rather than merely small. overflow:visible so a ray or a streak
   reaching past the viewBox is never clipped. */
.wk-icon{flex:none;width:44px;height:44px;display:block}
.wk-icon svg{width:100%;height:100%;display:block;overflow:visible}
.wk-rail{position:relative;height:26px;padding:0 2.6em;min-width:0}
.wk-inner{position:relative;display:block;height:100%}
.wk-track{position:absolute;left:0;right:0;top:11px;height:4px;border-radius:99px;background:var(--chip-bg)}
.wk-bar{position:absolute;top:7px;height:12px;border-radius:99px}
.wk-only{position:absolute;top:7px;width:12px;height:12px;border-radius:50%;transform:translateX(-50%)}
.wk-lo,.wk-hi{position:absolute;top:5px;font-family:var(--mono);font-size:12.5px;line-height:16px;
  white-space:nowrap;font-weight:600;color:var(--t-ink-light)}
/* The temperature ink is emitted as BOTH values and chosen here, so it can
   never be picked for a ground that changes a moment later. The saturated ramp
   fails AA as text on a white card at every stop (1.68 to 3.34), so light mode
   uses the same hues darkened until each clears 4.5; dark and sky grounds keep
   the saturated values. */
:root.sky-active .wk-lo,:root.sky-active .wk-hi,
:root[data-theme=dark] .wk-lo,:root[data-theme=dark] .wk-hi{color:var(--t-ink-dark)}
@media (prefers-color-scheme:dark){
  :root:not([data-theme=light]) .wk-lo,:root:not([data-theme=light]) .wk-hi{color:var(--t-ink-dark)}
}
.wk-lo{transform:translateX(-100%);padding-right:9px}
.wk-hi{padding-left:9px}
.wk-meta{font-family:var(--mono);font-size:10.5px;color:var(--faint);text-align:right;line-height:1.5}
.wk-meta b{display:block;font-weight:600;color:var(--teal-ink)}
.wk-meta b.dry{color:var(--faint);font-weight:400}
.wk-note{font-size:13px;color:var(--muted);margin:12px 0 0;line-height:1.5}
.wk-table{margin-top:12px}
.wk-table summary{font-family:var(--mono);font-size:12px;color:var(--link);cursor:pointer;padding:4px 0}
.wk-table summary:hover{color:var(--link-hover)}
/* Narrow: the bar keeps its own line under the day and conditions, because at
   this width four columns would crush the rail to nothing and the labels at its
   ends would collide. */
@media (max-width:720px){
  .wk-head{display:none}
  .wk-row{grid-template-columns:1fr auto;gap:2px 12px;padding:12px 0}
  .wk-cond{grid-column:1;font-size:14px}
  .wk-meta{grid-column:2;grid-row:1/3;align-self:center}
  .wk-rail{grid-column:1/-1;height:24px;padding:0 2.8em;margin-top:4px}
  .wk-day{grid-column:1}
}

.board{display:grid;grid-template-columns:1fr 1fr;gap:18px;align-items:start}
.board .card{margin:0;min-width:0}
.board .span2{grid-column:1/-1}
@media (max-width:820px){.board{grid-template-columns:1fr}}
.table-scroll{overflow-x:auto}

/* ---- degrade and skeleton states ------------------------------------------ */
.unavail{color:var(--muted);font-size:15px}
.unavail a{font-weight:600}
.failsafe{border-left:4px solid var(--copper);padding:10px 14px;background:var(--chip-bg);
  border-radius:0 8px 8px 0;color:var(--ink);font-size:15px}
.failsafe a{font-weight:600}
.skel{background:var(--chip-bg);border-radius:6px;min-height:14px}
.skel+.skel{margin-top:10px}
.reveal-in{opacity:1;transition:opacity .35s ease}
@media (prefers-reduced-motion:reduce){.reveal-in{transition:none}}

/* ---- location bar ---------------------------------------------------------- */
.loc-bar{background:var(--card);border:1px solid var(--line);border-radius:10px;
  padding:14px 18px;margin:0 0 8px;display:flex;flex-wrap:wrap;gap:10px;align-items:center}
.loc-bar form{display:flex;gap:8px;flex-wrap:wrap;align-items:center;flex:1;min-width:260px}
.loc-bar label{font-family:var(--mono);font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);font-weight:600}
.loc-bar input[type=text]{flex:1;min-width:150px;font:inherit;font-size:15px;color:var(--ink);
  background:var(--paper);border:1px solid var(--line);border-radius:7px;padding:8px 12px}
.loc-bar input[type=text]::placeholder{color:var(--faint)}
.btn{font-family:var(--sans);font-weight:600;font-size:14px;color:#FFFFFF;
  background:var(--rule);border:1px solid var(--rule);border-radius:7px;
  padding:8px 14px;cursor:pointer}
:root[data-theme=dark] .btn,html[data-theme=dark] .btn{color:#1A2A2E}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .btn{color:#1A2A2E}}
.btn:hover{filter:brightness(1.08)}
.btn-quiet{font-family:var(--sans);font-weight:600;font-size:14px;color:var(--teal-ink);
  background:none;border:1px solid var(--line);border-radius:7px;padding:8px 14px;cursor:pointer}
.btn-quiet:hover{border-color:var(--teal-ink)}
/* toggle buttons keep a constant name; pressed state shows visually too */
.btn-quiet[aria-pressed=true]{background:var(--chip-bg);border-color:var(--teal-ink);box-shadow:inset 0 1px 3px rgba(0,0,0,.15)}
.loc-current{display:flex;gap:10px;align-items:center;font-size:15px}
.loc-current b{font-weight:600}
.loc-clear{font-family:var(--mono);font-size:11px;color:var(--muted);background:none;
  border:1px solid var(--line);border-radius:6px;padding:4px 8px;cursor:pointer}
.loc-clear:hover{color:var(--ink)}
.loc-note{font-size:13.5px;color:var(--muted);width:100%}
.loc-choices{display:flex;flex-wrap:wrap;gap:8px;width:100%;margin-top:4px}

/* ---- alert banner ----------------------------------------------------------
   Severity chips use the NWS severity scale; the event band color is the
   official weather.gov event color, carried as a border so alert text always
   sits on our AA-verified grounds. */
.alerts-live{margin:14px 0 4px}
.alert{background:var(--card);border:1px solid var(--line);border-left:6px solid var(--copper);
  border-radius:8px;padding:14px 18px;margin:0 0 10px;box-shadow:var(--shadow)}
.alert-head{display:flex;flex-wrap:wrap;gap:8px 12px;align-items:center}
.alert-event{font-family:var(--serif);font-weight:600;font-size:19px;letter-spacing:-.01em}
.sev{font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  font-weight:600;border-radius:5px;padding:2px 8px}
.sev-extreme{color:var(--sev-extreme-fg);background:var(--sev-extreme-bg)}
.sev-severe{color:var(--sev-severe-fg);background:var(--sev-severe-bg)}
.sev-moderate{color:var(--sev-moderate-fg);background:var(--sev-moderate-bg)}
.sev-minor,.sev-unknown{color:var(--sev-minor-fg);background:var(--sev-minor-bg)}
.alert-headline{margin:8px 0 0;font-size:15.5px}
.alert-meta{font-family:var(--mono);font-size:11.5px;color:var(--faint);margin-top:6px}
.alert details{margin-top:10px}
.alert summary{cursor:pointer;font-weight:600;font-size:14px;color:var(--link)}
.alert-text{white-space:pre-wrap;font-size:14.5px;line-height:1.55;color:var(--ink);
  background:var(--paper);border:1px solid var(--line);border-radius:7px;
  padding:12px 14px;margin:10px 0 0;font-family:var(--sans)}
.alert-links{display:flex;flex-wrap:wrap;gap:14px;margin-top:10px;font-size:14px}
.alert-links a{font-weight:600}
.storm-line{margin-top:10px;padding-top:10px;border-top:1px solid var(--line);font-size:14.5px;color:var(--muted)}

/* ---- the condition hero -------------------------------------------------------
   The one expressive surface on the site. It wears the CURRENT SKY: the
   gradient and the motion layer are driven by the live observation, not by
   decoration. Family chassis (same band/scrim/pause pattern as the News,
   Sports and Crypto desks) so a reader crossing between sites stays home.

   Register safeguards, non-negotiable:
   - When an alert is active the hero goes QUIET: motion stops, the video is
     removed, and the palette drops to neutral. The site never looks pretty
     while a warning is up, and the alert always renders ABOVE this band.
   - Every stop below was contrast-checked through the scrim; the faintest
     text on the lightest sky still clears AA.
   - prefers-reduced-motion removes every animation and the video outright.
   ============================================================================ */
.wx-hero{position:relative;overflow:hidden;border-radius:14px;margin:14px 0 18px;
  border:1px solid var(--line);box-shadow:var(--shadow);isolation:isolate;
  min-height:360px;display:flex;flex-direction:column;justify-content:flex-end;
  background:linear-gradient(180deg,#3C4B5A,#5A6874 72%,#7E8992)}
.wx-hero[data-tod=day][data-wx=sun]{background:linear-gradient(180deg,#1D5A8F,#3E7CAC 54%,#C9954E)}
.wx-hero[data-tod=day][data-wx=partly]{background:linear-gradient(180deg,#2B5A85,#4A769B 60%,#8FA0AC)}
.wx-hero[data-tod=day][data-wx=cloud]{background:linear-gradient(180deg,#3A4956,#55636F 70%,#828C95)}
.wx-hero[data-tod=day][data-wx=rain]{background:linear-gradient(180deg,#1E2F3C,#374E5C 62%,#5A6E7C)}
.wx-hero[data-tod=day][data-wx=storm]{background:linear-gradient(172deg,#18213A,#2E2A4A 42%,#57405A 68%,#8F4E38 88%,#B0763F)}
.wx-hero[data-tod=day][data-wx=snow]{background:linear-gradient(180deg,#384C64,#566B82 62%,#8DA2B3)}
.wx-hero[data-tod=day][data-wx=fog]{background:linear-gradient(180deg,#434B53,#5F676F 70%,#88909A)}
.wx-hero[data-tod=night]{background:linear-gradient(180deg,#0E1626,#1B2740 58%,#3C4A63)}
.wx-hero[data-tod=night][data-wx=storm]{background:linear-gradient(174deg,#0B1020,#1E1B33 44%,#3A2C42 72%,#5C3A2C)}
.wx-hero[data-tod=night][data-wx=fog]{background:linear-gradient(180deg,#1A1E24,#2B3138 62%,#454C55)}
/* Alert active: the sky steps back so the warning above owns the page.
   The selector carries all three attributes on purpose. The condition rules
   above are [data-tod][data-wx] and would otherwise outrank a plain
   [data-alert] rule, leaving a cheerful sky under a live warning. */
.wx-hero[data-tod][data-wx][data-alert=true]{
  background:linear-gradient(180deg,#242A2E,#33393E 70%,#434A50)}

/* The loop sits UNDER the condition sky's tint rather than replacing it.
   At full opacity the footage would hide the sky entirely and the hero would
   stop responding to the weather, which is the whole point of it. Holding the
   video back lets the sky's color wash through: the room takes on the tone of
   the actual sky outside, and both the motion and the condition read at once.

   CONTRAST, measured not assumed: footage is not uniformly dark (this clip
   has a bright screen and a lamp), so a bright pixel LIGHTENS the ground under
   the text. Composited worst case is a pure-white video pixel over the
   lightest sky stop. At video .55 the scrim must reach .62 for the smallest
   text to clear AA; the video-on scrim below runs .72, which lands every sky
   at 6.2 or better. Re-run that check before easing either number. */
.wx-hero-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:1;
  opacity:0;transition:opacity .8s ease}
.wx-hero-video.on{opacity:.55}
/* deeper scrim whenever real footage is running */
.wx-hero.video-on .wx-scrim{
  background:linear-gradient(180deg,rgba(10,15,20,.34) 0%,rgba(10,15,20,.46) 30%,rgba(10,15,20,.72) 52%,rgba(10,15,20,.84) 100%)}
.wx-hero[data-alert=true] .wx-hero-video{display:none}
/* with real footage running, the drawn weather effects step back to a hint,
   so we never render rain falling inside a room */
.wx-hero.video-on .wx-fx{opacity:.18}
.wx-hero.video-on[data-wx=storm] .wx-fx,.wx-hero.video-on[data-wx=rain] .wx-fx{opacity:.3}

/* ---- the pre-location identity hero ---------------------------------------
   THE VIDEO LIVES HERE, AND ONLY HERE. Before a location is set there is no
   observation for footage to contradict, so a fixed loop is honest: the job of
   this screen is to say what the site IS, not what the weather is. The moment a
   location exists the Living Sky takes over, because then a sunlit room behind
   a blizzard would be a small lie.

   The band is the brand's deep teal on purpose, and NOT the grey default.
   Neutral grey is not neutral: it is the visual language of loading, broken and
   empty, which is the worst thing a front door can say. This gradient never
   appears on the located board, so it can never be misread as a condition.

   It carries no data-wx or data-tod attribute, which is what keeps it out of
   the condition rules above. Those are [data-tod][data-wx] at three classes,
   so a plain .wx-hero-identity would lose to them; the two-class selector here
   only has to beat bare .wx-hero. */
.wx-hero.wx-hero-identity{
  min-height:400px;
  background:linear-gradient(180deg,#0E2A33,#17404A 58%,#2C5F66)}

/* Measured, not assumed, and the reason this rule exists at all. This hero
   carries more copy than the conditions hero, so its text reaches higher up
   the band, into the region where the standard video scrim is only .46. There,
   against the worst case of a pure white video pixel over the lightest
   gradient stop, #DDE4E8 lands at 4.39 and FAILS AA. Starting the floor at .58
   puts that same text at 5.95 and the faintest at 4.98. Re-run the check
   before easing either number. */
.wx-hero.wx-hero-identity.video-on .wx-scrim{
  background:linear-gradient(180deg,rgba(10,15,20,.58) 0%,rgba(10,15,20,.66) 40%,rgba(10,15,20,.80) 100%)}

.wx-id-eyebrow{font-family:var(--mono);font-size:11.5px;letter-spacing:.09em;
  text-transform:uppercase;color:#C9D2D8;margin:0 0 10px}
.wx-id-head{font-family:var(--serif);font-weight:400;font-size:clamp(26px,4.2vw,40px);
  line-height:1.14;color:#fff;margin:0 0 10px;max-width:20ch}
.wx-id-say{font-size:15.5px;line-height:1.55;color:#DDE4E8;margin:0 0 18px;max-width:54ch}
.wx-id-act{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center}
.wx-id-cta{font-family:var(--sans);font-size:15px;font-weight:600;cursor:pointer;
  padding:11px 18px;border-radius:9px;border:1px solid #F4F1EA;
  background:#F4F1EA;color:#12222A}
.wx-id-cta:hover{background:#fff;border-color:#fff}
.wx-id-cta:focus-visible{outline:3px solid #fff;outline-offset:3px}
.wx-id-alt{font-size:14px;color:#DDE4E8}
@media (max-width:560px){
  .wx-hero.wx-hero-identity{min-height:340px}
  .wx-id-act{gap:10px 12px}
  .wx-id-cta{width:100%}
}

/* condition motion layer: weather, not decoration */
.wx-fx{position:absolute;inset:0;z-index:1;pointer-events:none;opacity:.55}
.wx-hero[data-alert=true] .wx-fx{display:none}
.wx-hero[data-wx=rain] .wx-fx,.wx-hero[data-wx=storm] .wx-fx{
  background-image:repeating-linear-gradient(102deg,rgba(255,255,255,.30) 0 1px,transparent 1px 7px);
  background-size:auto 140px;animation:wx-rain .85s linear infinite}
.wx-hero[data-wx=storm] .wx-fx{opacity:.72;animation-duration:.6s}
.wx-hero[data-wx=snow] .wx-fx{
  background-image:radial-gradient(2.2px 2.2px at 20% 15%,rgba(255,255,255,.85),transparent),
    radial-gradient(1.8px 1.8px at 65% 45%,rgba(255,255,255,.75),transparent),
    radial-gradient(2.4px 2.4px at 85% 25%,rgba(255,255,255,.80),transparent),
    radial-gradient(1.6px 1.6px at 40% 75%,rgba(255,255,255,.70),transparent);
  background-size:200px 200px;animation:wx-snow 9s linear infinite}
.wx-hero[data-wx=cloud] .wx-fx,.wx-hero[data-wx=partly] .wx-fx,.wx-hero[data-wx=fog] .wx-fx{
  background-image:radial-gradient(60% 42% at 18% 26%,rgba(255,255,255,.16),transparent 70%),
    radial-gradient(52% 38% at 72% 18%,rgba(255,255,255,.13),transparent 72%);
  animation:wx-drift 42s ease-in-out infinite alternate}
.wx-hero[data-wx=fog] .wx-fx{opacity:.85;
  background-image:linear-gradient(0deg,rgba(255,255,255,.13) 0 18%,transparent 18% 34%,rgba(255,255,255,.10) 34% 52%,transparent 52%)}
.wx-hero[data-tod=day][data-wx=sun] .wx-fx{
  background-image:radial-gradient(38% 30% at 78% 16%,rgba(255,236,190,.42),transparent 70%);animation:none}
@keyframes wx-rain{from{background-position:0 0}to{background-position:-28px 140px}}
@keyframes wx-snow{from{background-position:0 0}to{background-position:-40px 200px}}
@keyframes wx-drift{from{background-position:0 0}to{background-position:80px 0}}

/* The scrim stays light where there is only sky and deepens under the text,
   so the gradient reads as weather instead of as a colored panel. The ramp
   reaches .58 by 52 percent, which is where content starts: every text tone
   below was verified to clear AA against the LIGHTEST stop of every sky at
   that alpha (worst case 5.65, snow). Do not soften the ramp without
   re-running that check. */
.wx-scrim{position:absolute;inset:0;z-index:2;
  background:linear-gradient(180deg,rgba(10,15,20,.18) 0%,rgba(10,15,20,.26) 30%,rgba(10,15,20,.58) 52%,rgba(10,15,20,.78) 100%)}
.wx-hero-inner{position:relative;z-index:3;padding:26px 28px 22px;color:#FFFFFF}
/* top right, clear of the source credit that sits bottom right */
.wx-hero .hero-pause{position:absolute;right:12px;top:12px;z-index:4;width:38px;height:38px;
  border-radius:50%;border:1px solid rgba(255,255,255,.4);background:rgba(8,13,20,.72);
  color:#fff;font-size:13px;line-height:1;cursor:pointer;
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}
.wx-hero .hero-pause:hover{border-color:#fff}
.wx-hero .hero-pause:focus-visible{outline:3px solid #fff;outline-offset:2px}

.wx-place{font-family:var(--mono);font-size:11.5px;letter-spacing:.09em;text-transform:uppercase;
  color:#DDE4E8;margin:0 0 10px;display:flex;flex-wrap:wrap;gap:6px 14px;align-items:baseline}
.wx-place .wx-quiet-note{color:#C9D2D8;text-transform:none;letter-spacing:.02em;font-size:11.5px}
.wx-read{display:flex;flex-wrap:wrap;gap:4px 26px;align-items:baseline}
/* The numeral is tinted by its own temperature. Solid fill, not a
   background-clip:text gradient: this element runs line-height .95, and a
   paint box shorter than the glyphs renders the BOTTOM OF EVERY DIGIT
   transparent, which reads as numbers with their feet cut off. Escaping that
   means line-height 1 plus vertical padding and negative margins to restore the
   spacing, and the result is a fragile box for no gain the eye can see at a
   single temperature.

   Contrast measured where the numeral actually sits, 16 to 41 percent down the
   hero, over the BLUE UPPER HALF of each condition sky rather than the bright
   bottom stop I first assumed: worst case 3.19 on a sunny day, against the 3.0
   floor for large text. */
.wx-temp{font-family:var(--mono);font-weight:600;font-size:clamp(68px,13vw,140px);line-height:.95;
  letter-spacing:-.03em;color:var(--t-ink-dark)}
.wx-cond{font-family:var(--serif);font-size:clamp(24px,3.2vw,34px);color:#fff;line-height:1.25}
.wx-feels{font-size:17px;color:#DDE4E8;margin-top:4px}
.wx-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(112px,1fr));
  gap:12px 20px;margin-top:20px;padding-top:16px;border-top:1px solid rgba(255,255,255,.22)}
.wx-stats .nk{font-family:var(--mono);font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:#C9D2D8}
.wx-stats .nv{font-family:var(--mono);font-size:16px;font-weight:600;color:#fff;margin-top:2px}
.wx-hero .card-foot{border-top-color:rgba(255,255,255,.22);margin-top:16px}
.wx-hero .stamp,.wx-hero .src{color:#C9D2D8}
.wx-hero .stamp.stale{color:#F0C08A}
.wx-hero-skel{padding:26px 28px;min-height:200px}
.wx-hero-skel .skel{background:rgba(255,255,255,.14)}
@media (max-width:640px){
  .wx-hero-inner{padding:20px 18px 18px}
  .wx-stats{grid-template-columns:repeat(auto-fit,minmax(96px,1fr));gap:10px 14px}
}
@media (prefers-reduced-motion:reduce){
  .wx-fx{animation:none!important}
  .wx-hero-video{display:none}
}

/* ---- NOW card --------------------------------------------------------------- */
.now-head{display:flex;flex-wrap:wrap;gap:6px 22px;align-items:baseline}
.now-temp{font-family:var(--mono);font-weight:600;font-size:clamp(46px,8vw,64px);
  line-height:1;letter-spacing:-.02em}
.now-cond{font-family:var(--serif);font-size:20px;color:var(--ink)}
.now-feels{font-size:14.5px;color:var(--muted)}
.now-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));
  gap:10px 18px;margin-top:16px}
.now-grid .nk{font-family:var(--mono);font-size:10.5px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--faint)}
.now-grid .nv{font-family:var(--mono);font-size:16px;font-weight:600}
.ctx-line{margin-top:14px;font-size:14.5px;color:var(--muted);font-style:italic;font-family:var(--serif)}

/* ---- hourly strip ----------------------------------------------------------- */
.hourly{display:flex;gap:0;overflow-x:auto;padding:4px 0 8px;margin:0;list-style:none;
  scrollbar-width:thin}
.hourly li{flex:0 0 74px;text-align:center;border-right:1px solid var(--line);padding:2px 4px}
.hourly li:last-child{border-right:none}
.hourly .ht{font-family:var(--mono);font-size:11px;color:var(--faint);text-transform:uppercase}
.hourly .hv{font-family:var(--mono);font-size:18px;font-weight:600;margin:2px 0}
.hourly .hp{font-family:var(--mono);font-size:11.5px;color:var(--teal-ink)}
.hourly .hp.dry{color:var(--faint)}

/* ---- the hour strip -----------------------------------------------------------
   Scrollable hourly forecast (wx-chart.js). Two kinds of ground in one
   component, and the split decides every colour here:

   ON THE SKY BAND (temp numerals, day names, the observation ring): the band
   is the real daypart colours from the sky engine, identical in both themes,
   so these inks are fixed values that never consult the theme. Every numeral
   and name carries a dark halo (paint-order stroke) because the band runs
   from near-black night to bright day blue and no single ink clears both
   bare. Measured with the halo composited over each band stop: on the
   brightest (#2E86AE) the halo ground is #102837, where the dark ink ramp's
   worst stop measures 6.11; across all four daypart grounds the ramp spans
   6.11 to 11.27 and the day-name white measures 13.4 at worst. Verified
   computationally; re-measure if the halo alpha or the band stops change.

   ON THE CARD (hour labels, percent labels, detail line, table): normal
   theme tokens, already measured on the cards.

   Nothing here animates on its own; the only motion is the reader's own
   scrolling, and centring respects prefers-reduced-motion. */
.hstrip-wrap{position:relative}
.hstrip{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;cursor:grab;
  scrollbar-width:thin;scrollbar-color:var(--faint) transparent}
.hstrip.drag{cursor:grabbing;user-select:none}
.hstrip::-webkit-scrollbar{height:8px}
.hstrip::-webkit-scrollbar-thumb{background:var(--line);border-radius:99px}
.hstrip:focus-visible{outline:3px solid var(--rule);outline-offset:2px;border-radius:8px}
.hs-svg{display:block}
.hstrip-fade{position:absolute;top:0;bottom:10px;width:38px;pointer-events:none;z-index:2;
  opacity:0;transition:opacity .2s}
@media(prefers-reduced-motion:reduce){.hstrip-fade{transition:none}}
.hstrip-fade.l{left:0;background:linear-gradient(90deg,var(--card),transparent)}
.hstrip-fade.r{right:0;background:linear-gradient(270deg,var(--card),transparent)}
:root.sky-active .hstrip-fade.l{background:linear-gradient(90deg,rgba(12,18,26,.92),transparent)}
:root.sky-active .hstrip-fade.r{background:linear-gradient(270deg,rgba(12,18,26,.92),transparent)}

/* marks on the band: halo first, ink over it */
.hs-tv{font-family:var(--mono);font-size:13px;font-weight:600;text-anchor:middle;
  paint-order:stroke;stroke:rgba(8,14,22,.78);stroke-width:3.2px;stroke-linejoin:round}
.hs-dayname{font-family:var(--mono);font-size:9.5px;fill:#F4F1EA;letter-spacing:.14em;
  paint-order:stroke;stroke:rgba(8,14,22,.78);stroke-width:3px;stroke-linejoin:round}
.hs-line-under{fill:none;stroke:rgba(8,14,22,.66);stroke-width:5;stroke-linejoin:round;stroke-linecap:round}
.hs-line{fill:none;stroke:rgba(244,241,234,.85);stroke-width:2.5;stroke-linejoin:round;stroke-linecap:round}
.hs-dot{stroke:rgba(8,14,22,.9);stroke-width:1.7}
.hs-day{stroke:rgba(244,241,234,.28);stroke-width:1;stroke-dasharray:3 4}
.hs-sel{fill:rgba(244,241,234,.14)}

/* the observation ring, a measurement against a projection. The card charts
   used --copper-ink, measured on cards; this ring sits on the sky band, so it
   is a fixed lighter copper with its own halo-weight stroke. */
.hs-obs-ring-under{fill:none;stroke:rgba(8,14,22,.78);stroke-width:5.5}
.hs-obs-ring{fill:none;stroke:#F0A45E;stroke-width:2.5}
.hs-obs-tie-under{stroke:rgba(8,14,22,.78);stroke-width:3.5;stroke-dasharray:3 3}
.hs-obs-tie{stroke:#F0A45E;stroke-width:1.5;stroke-dasharray:3 3;opacity:.9}
.hs-obs-label{font-family:var(--mono);font-size:12px;font-weight:600;fill:#F0C08A;
  paint-order:stroke;stroke:rgba(8,14,22,.78);stroke-width:3px;stroke-linejoin:round}
.hs-obs-mid{text-anchor:middle}

/* below the band: the card's own ground and tokens */
.hs-precipband{fill:var(--accent);opacity:.07}
.hs-base{stroke:var(--line);stroke-width:1}
.hs-bar{fill:var(--accent);opacity:.55}
.hs-hl{font-family:var(--mono);font-size:11px;fill:var(--faint);text-anchor:middle}
.hs-pl{font-family:var(--mono);font-size:10px;fill:var(--teal-ink);text-anchor:middle}
.hs-hit{cursor:pointer}

.hstrip-detail{display:flex;gap:14px;align-items:baseline;flex-wrap:wrap;
  border-top:1px solid var(--line);margin-top:10px;padding-top:10px;min-height:24px}
.hstrip-when{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.hstrip-line{font-size:14.5px;color:var(--ink)}
.hs-table{margin-top:10px}
.hs-table summary{cursor:pointer;font-size:13.5px;color:var(--link);font-weight:600}
.hs-table summary:hover{text-decoration:underline}

/* screen-reader-only text: the hero strip announces its selected hour without
   drawing a panel, because the NOW card above it already owns that space */
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---- the forecast page's week: rows that open to the as-issued text ---------
   Reuses the board's shared-scale bar idiom. The row is a real button so it is
   keyboard reachable and announces its own state; the bar is aria-hidden
   because both numbers are printed beside it as text. */
.wk-lede{font-size:15.5px;line-height:1.55;color:var(--muted);margin:0 0 14px}
.wk-open{border-bottom:1px solid var(--line)}
.wk-open:last-child{border-bottom:0}
.wk-row-btn{display:grid;grid-template-columns:minmax(84px,auto) minmax(0,2.4fr) minmax(140px,1.6fr) auto auto;
  gap:14px;align-items:center;width:100%;text-align:left;background:none;border:0;
  padding:11px 4px;cursor:pointer;color:inherit;font:inherit}
/* the condition column was 1.5fr against a 2fr track, which wrapped
   "Chance Showers And Thunderstorms" onto five lines and left every row a
   different height. It now gets the larger share and is capped at two lines. */
.wk-row-btn .wk-cond-text{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;line-height:1.35}
.wk-row-btn:hover{background:rgba(127,127,127,.06)}
.wk-row-btn:focus-visible{outline:3px solid var(--rule);outline-offset:-3px;border-radius:6px}
.wk-nums{display:flex;align-items:center;gap:10px;min-width:0}
.wk-nums b{font-family:var(--mono);font-size:13px;font-weight:600;width:34px;flex:none}
.wk-lo{color:var(--muted);text-align:right}
.wk-hi{color:var(--ink)}
.wk-track{position:relative;flex:1;height:7px;border-radius:99px;background:rgba(127,127,127,.18);min-width:60px}
.wk-bar{position:absolute;top:0;height:7px;border-radius:99px}
.wk-onlylow{position:absolute;top:-2px;width:4px;height:11px;border-radius:2px;transform:translateX(-2px)}
.wk-rw{display:flex;align-items:baseline;gap:12px;font-family:var(--mono);font-size:12px;white-space:nowrap}
.wk-rain{color:var(--teal-ink);font-weight:600}
.wk-rain.dim{color:var(--faint);font-weight:400}
.wk-wind{color:var(--faint)}
.wk-chev{font-size:9px;color:var(--faint);transition:transform .15s}
@media(prefers-reduced-motion:reduce){.wk-chev{transition:none}}
.wk-row-btn[aria-expanded=true] .wk-chev{transform:rotate(180deg)}
.wk-panel{padding:2px 4px 16px}
.wk-as{font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--faint);margin:12px 0 6px;font-weight:600}
.wk-panel p{margin:0 0 6px}
@media(max-width:640px){
  .wk-row-btn{grid-template-columns:1fr auto;gap:6px 10px;padding:12px 4px}
  .wk-row-btn .wk-cond{grid-column:1/-1;order:3}
  .wk-nums{grid-column:1/-1;order:4}
  .wk-rw{grid-column:1/-1;order:5}
  .wk-chev{order:2}
}

/* ---- 7-day board ------------------------------------------------------------ */
.days{width:100%;border-collapse:collapse}
.days th{font-family:var(--mono);font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;
  color:var(--faint);text-align:left;font-weight:600;padding:4px 10px 8px;border-bottom:1px solid var(--line)}
.days td{padding:9px 10px;border-bottom:1px solid var(--line);font-size:14.5px;vertical-align:top}
.days tr:last-child td{border-bottom:none}
.days .d-name{font-weight:600;white-space:nowrap}
.days .d-hi,.days .d-lo{font-family:var(--mono);font-weight:600;white-space:nowrap}
.days .d-lo{color:var(--muted);font-weight:500}
.days .d-pop{font-family:var(--mono);color:var(--teal-ink);white-space:nowrap}
.days .d-pop.dry{color:var(--faint)}
.days .d-cond{color:var(--muted)}
.days .d-wind{font-family:var(--mono);font-size:12.5px;color:var(--faint);white-space:nowrap}

/* ---- radar and images -------------------------------------------------------- */
.radar-frame{position:relative;border:1px solid var(--line);border-radius:8px;overflow:hidden;
  background:var(--chip-bg)}
.radar-frame img{display:block;width:100%;height:auto}
.radar-ctl{display:flex;gap:10px;align-items:center;margin-top:10px;flex-wrap:wrap}

/* ---- sun and moon ------------------------------------------------------------ */
.astro-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px 18px}
.astro-grid .nk{font-family:var(--mono);font-size:10.5px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--faint)}
.astro-grid .nv{font-family:var(--mono);font-size:16px;font-weight:600;white-space:nowrap}

/* ---- national board ---------------------------------------------------------- */
.stat-row{display:flex;flex-wrap:wrap;gap:8px 26px;align-items:baseline}
.stat-row .big{font-family:var(--mono);font-weight:600;font-size:34px;line-height:1}
.stat-row .lbl{font-family:var(--mono);font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--faint)}
.state-table{width:100%;border-collapse:collapse;margin-top:8px}
.state-table td{padding:6px 8px;border-bottom:1px solid var(--line);font-size:14px}
.state-table tr:last-child td{border-bottom:none}
.state-table .st{font-family:var(--mono);font-weight:600}
.state-table .ct{font-family:var(--mono);text-align:right;color:var(--muted)}
.evt-list{margin:8px 0 0;padding:0;list-style:none}
.evt-list li{padding:7px 0;border-bottom:1px solid var(--line);font-size:14.5px;
  display:flex;gap:10px;align-items:baseline;flex-wrap:wrap}
.evt-list li:last-child{border-bottom:none}
.evt-count{font-family:var(--mono);font-weight:600;color:var(--muted)}

/* ---- alerts page ------------------------------------------------------------- */
.sev-group{margin:0 0 26px}
.sev-group>h3,.sev-group>h4{display:flex;gap:10px;align-items:center}

/* ---- forecast page ----------------------------------------------------------- */
.period{border-bottom:1px solid var(--line);padding:14px 0}
.period:last-child{border-bottom:none}
.period h4{font-family:var(--serif);font-size:18px;margin:0 0 4px;font-weight:600}
.period .p-line{font-family:var(--mono);font-size:13px;color:var(--muted);margin-bottom:6px}
.period p{margin:4px 0 0;font-size:15.5px}
.hr-detail{width:100%;border-collapse:collapse;margin-top:8px}
.hr-detail th{font-family:var(--mono);font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--faint);text-align:left;padding:4px 8px;border-bottom:1px solid var(--line)}
.hr-detail td{font-size:13.5px;padding:5px 8px;border-bottom:1px solid var(--line)}
.hr-detail td.mono{font-family:var(--mono)}

/* ---- prose pages -------------------------------------------------------------- */
.prose{font-size:16.5px}
.prose h2{font-family:var(--serif);font-weight:600;font-size:24px;margin:30px 0 10px;letter-spacing:-.01em}
.prose h3{font-family:var(--serif);font-weight:600;font-size:19px;margin:22px 0 8px}
.prose ul{padding-left:22px}
.prose li{margin:6px 0}
.lede{font-family:var(--serif);font-size:20px;line-height:1.55;color:var(--ink)}

/* ---- tides and rivers (Phase 4) ------------------------------------------------
   The stage bar is a measuring scale, not a risk gradient we invented: the
   marks ARE the official action, minor, moderate and major stages, and the
   fill only shows where the water sits among them. Every mark clears the 3:1
   non-text contrast bar against its track in BOTH modes, which is why the
   colors differ by mode; re-check before changing any of them. */
.tide-now{display:flex;flex-wrap:wrap;gap:6px 18px;align-items:baseline;margin:2px 0 12px}
.tide-now-v{font-family:var(--mono);font-weight:600;font-size:34px;line-height:1;letter-spacing:-.01em}
.tide-now-k{font-family:var(--mono);font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--faint)}
.tide-now-t{font-size:13.5px;color:var(--muted);margin-top:2px}
.tide-next{margin:0 0 12px;font-size:16px;font-weight:600}
.tide-past td{color:var(--faint)}

.rv-head{display:flex;flex-wrap:wrap;gap:4px 14px;align-items:baseline}
.rv-name{font-family:var(--serif);font-weight:600;font-size:19px;letter-spacing:-.01em}
.rv-dist{font-family:var(--mono);font-size:11.5px;color:var(--faint)}
.rv-read{display:flex;flex-wrap:wrap;gap:8px 14px;align-items:center;margin-top:8px}
.rv-stage{font-family:var(--mono);font-weight:600;font-size:26px;letter-spacing:-.01em}
.rv-when{margin:4px 0 0;font-family:var(--mono);font-size:11.5px;color:var(--faint)}
.rv-cat{font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  font-weight:600;border-radius:5px;padding:3px 9px}
.rv-cat-no_flooding{color:#1F6B45;background:#F0F6F2}
.rv-cat-action{color:#6E5300;background:#F6ECCB}
.rv-cat-minor{color:#8F431D;background:#F7E4D9}
.rv-cat-moderate{color:#8A2E14;background:#F6DFD7}
.rv-cat-major{color:#7A1F1F;background:#F6DEDE}
.rv-nodef{margin:12px 0 0;font-size:14px;color:var(--muted);
  border-left:3px solid var(--line);padding-left:12px}

.rv-bar-wrap{margin-top:14px}
.rv-bar{position:relative;height:14px;border-radius:7px;background:var(--chip-bg);overflow:hidden}
.rv-fill{position:absolute;left:0;top:0;bottom:0;background:var(--teal-ink);opacity:.85}
.rv-tick{position:absolute;top:-3px;bottom:-3px;width:2.5px;border-radius:2px}
.rv-sw{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:5px;vertical-align:-1px}
.rv-tick-action{background:#7A5A12}
.rv-tick-minor{background:#9A4517}
.rv-tick-moderate{background:#7E260F}
.rv-tick-major{background:#5F1414}
.rv-legend{display:flex;flex-wrap:wrap;gap:4px 16px;margin:8px 0 0;
  font-family:var(--mono);font-size:11px;color:var(--muted)}
@media (prefers-color-scheme:dark){
  :root:not([data-theme=light]) .rv-cat-no_flooding{color:#7FC9A0;background:#16281F}
  :root:not([data-theme=light]) .rv-cat-action{color:#EAD28A;background:#393012}
  :root:not([data-theme=light]) .rv-cat-minor{color:#EFB694;background:#3A2A1E}
  :root:not([data-theme=light]) .rv-cat-moderate{color:#F0A98A;background:#3A2318}
  :root:not([data-theme=light]) .rv-cat-major{color:#F0B9B9;background:#3A2020}
  :root:not([data-theme=light]) .rv-tick-action{background:#E8CB86}
  :root:not([data-theme=light]) .rv-tick-minor{background:#F0A87C}
  :root:not([data-theme=light]) .rv-tick-moderate{background:#F2907A}
  :root:not([data-theme=light]) .rv-tick-major{background:#F3A6A6}
}
:root[data-theme=dark] .rv-cat-no_flooding{color:#7FC9A0;background:#16281F}
:root[data-theme=dark] .rv-cat-action{color:#EAD28A;background:#393012}
:root[data-theme=dark] .rv-cat-minor{color:#EFB694;background:#3A2A1E}
:root[data-theme=dark] .rv-cat-moderate{color:#F0A98A;background:#3A2318}
:root[data-theme=dark] .rv-cat-major{color:#F0B9B9;background:#3A2020}
:root[data-theme=dark] .rv-tick-action{background:#E8CB86}
:root[data-theme=dark] .rv-tick-minor{background:#F0A87C}
:root[data-theme=dark] .rv-tick-moderate{background:#F2907A}
:root[data-theme=dark] .rv-tick-major{background:#F3A6A6}

/* ---- severe-weather mode -------------------------------------------------------
   Deeper, not louder. The panel earns attention through POSITION and SIZE,
   never through a color we invented: the only strong color here is the
   official weather.gov event color on the left edge. No countdown, no pulse,
   no siren fill behind body text. */
.severe-panel{background:var(--card);border:1px solid var(--line);border-left:6px solid var(--copper);
  border-radius:10px;padding:18px 22px;margin:0 0 14px;box-shadow:var(--shadow)}
.sv-head{display:flex;flex-wrap:wrap;gap:6px 14px;align-items:baseline}
.sv-event{font-family:var(--serif);font-weight:600;font-size:26px;letter-spacing:-.01em}
.sv-by{font-family:var(--mono);font-size:11.5px;color:var(--faint)}
.sv-here{margin:10px 0 0;font-size:16px;font-weight:600;color:var(--ink)}
.sv-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
  gap:12px 20px;margin:16px 0 0;padding-top:14px;border-top:1px solid var(--line)}
.sv-facts .nk{font-family:var(--mono);font-size:10.5px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--faint)}
.sv-facts .nv{font-family:var(--mono);font-size:16px;font-weight:600;margin-top:2px}
.sv-instruction{margin-top:18px;padding:14px 16px;background:var(--paper);
  border:1px solid var(--line);border-radius:8px}
.sv-instruction p{margin:6px 0 0;font-size:17px;line-height:1.55;white-space:pre-wrap}
.sv-route{margin:14px 0 0;font-size:14.5px;color:var(--muted)}
.sv-route a{font-weight:600;text-decoration:underline}
.severe-map{margin:0 0 18px}
.severe-map .map-frame{height:380px}
@media (max-width:640px){
  .sv-event{font-size:22px}
  .severe-panel{padding:15px 16px}
  .severe-map .map-frame{height:300px}
}

/* ---- storm cards (2026-08-24, from Jack's draft) -------------------------------
   Closed by default so every active system fits on one screen. The name is the
   hero, in caps and tier-coloured; the class chip sits beside it; the sustained
   wind and its position on the Saffir-Simpson scale sit beneath. Every tier
   colour was measured on both grounds: all clear 4.5 on the dark card and on
   white, and the WORDS always carry the category so colour never stands alone. */
/* the historical record card, kept visually distinct from the live systems
   above it so history is never mistaken for a forecast */
.hist-card{border-left:3px solid var(--line)}
.hist-lede{font-size:15.5px;line-height:1.55;margin:0 0 12px}
.hist-list{list-style:none;padding:0;margin:0 0 12px;display:grid;gap:8px}
.hist-list li{font-size:14.5px;line-height:1.5;padding-left:14px;position:relative}
.hist-list li::before{content:"";position:absolute;left:0;top:9px;width:5px;height:5px;
  border-radius:50%;background:var(--faint)}
.hist-list b{font-weight:600}
/* underlined for the same reason the handoff link is: axe's link-in-text-block
   wants a link distinguishable from surrounding prose by more than colour, and
   these sit mid-sentence inside each item. */
.hist-list a,.hist-more a{text-decoration:underline}
.hist-more{margin:0;font-size:14px}

.storm-index{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 16px}
.sx-chip{display:inline-flex;align-items:center;gap:8px;font-family:var(--mono);font-size:12px;
  padding:6px 12px;border:1px solid var(--line);border-radius:999px;background:var(--card);
  color:var(--ink);text-decoration:none;white-space:nowrap}
.sx-chip:hover{border-color:var(--muted);text-decoration:none}
.sx-chip:focus-visible{outline:3px solid var(--rule);outline-offset:2px}
.sx-dot{width:9px;height:9px;border-radius:50%;flex:none;background:var(--tc-light)}
:root[data-theme=dark] .sx-dot{background:var(--tc-dark)}
@media (prefers-color-scheme: dark){:root:not([data-theme=light]) .sx-dot{background:var(--tc-dark)}}
:root.sky-active .sx-dot{background:var(--tc-dark)}

/* ONE CARD PER STORM, as the draft has it, and it is also what makes the
   header measurable: the name, class chip and advisory line used to sit on
   the page with no opaque ancestor, so they rode on the fixed sky at z-index
   -1 and axe, unable to find a ground, assumed white and reported 1.95. A
   real card gives them a real ground. The inner cards flatten so the storm
   reads as one object rather than a stack of boxes. */
.storm-card{margin:0 0 22px;background:var(--card);border:1px solid var(--line);
  border-radius:14px;padding:18px 20px;box-shadow:var(--shadow)}
:root.sky-active .storm-card{background:rgba(12,18,26,.88);border-color:rgba(255,255,255,.12)}
.storm-card.is-hit{border-left:3px solid var(--copper-ink)}
.storm-card .card{background:none;border:0;box-shadow:none;padding:0;margin:0}
.storm-card .board{display:block}
.storm-card .card + .card{margin-top:18px}
.sc-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 2px}
.sc-chip{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:700;padding:5px 10px;border-radius:6px;white-space:nowrap;
  color:var(--tc-light);border:1px solid currentColor}
.sc-name{font-family:var(--mono);font-weight:700;letter-spacing:.06em;
  font-size:clamp(26px,4.4vw,44px);line-height:1.02;color:var(--tc-light)}
:root[data-theme=dark] .sc-chip,:root[data-theme=dark] .sc-name{color:var(--tc-dark)}
@media (prefers-color-scheme: dark){
  :root:not([data-theme=light]) .sc-chip,:root:not([data-theme=light]) .sc-name{color:var(--tc-dark)}
}
:root.sky-active .sc-chip,:root.sky-active .sc-name{color:var(--tc-dark)}
.sc-meta{font-family:var(--mono);font-size:11px;color:var(--faint);margin:0 0 12px}

.sc-summary{padding-bottom:4px}
.sc-wind{display:flex;align-items:baseline;gap:10px;margin:0 0 10px}
.sc-wind b{font-family:var(--mono);font-size:clamp(34px,5vw,54px);font-weight:600;line-height:1}
.sc-wind span{font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint)}
.sc-scale{margin:0 0 14px}
.sc-track{display:grid;grid-template-columns:repeat(6,1fr);gap:5px}
.sc-seg{position:relative;height:8px;border-radius:99px;background:var(--line)}
.sc-seg.on{background:var(--tc-light)}
:root[data-theme=dark] .sc-seg.on{background:var(--tc-dark)}
@media (prefers-color-scheme: dark){:root:not([data-theme=light]) .sc-seg.on{background:var(--tc-dark)}}
:root.sky-active .sc-seg.on{background:var(--tc-dark)}
.sc-mark{position:absolute;top:-4px;width:3px;height:16px;border-radius:2px;background:var(--ink);
  transform:translateX(-1.5px)}
.sc-labels{display:grid;grid-template-columns:repeat(6,1fr);gap:5px;margin-top:5px;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.08em;color:var(--faint);text-align:center}
.sc-labels .on{color:var(--ink);font-weight:700}

.sc-rel{display:flex;gap:10px;align-items:flex-start;border-top:1px solid var(--line);
  margin-top:12px;padding:12px 0 2px;font-size:14.5px;line-height:1.5}
.sc-rel .sc-ic{flex:none;font-size:11px;line-height:1.6;color:var(--faint)}
.sc-rel.hit .sc-ic{color:var(--copper-ink)}
.sc-rel b{display:block;font-weight:600}
.sc-rel small{display:block;margin-top:4px;font-size:13px;color:var(--muted)}
.sc-rel p{margin:0;color:var(--muted)}

/* the Storm handoff, gated in JS to a watch or warning over the reader */
.storm-handoff{border-top:1px solid var(--line);margin-top:12px;padding-top:10px;font-size:14.5px}
/* underlined on purpose: axe's link-in-text-block wants a link distinguishable
   from surrounding prose by more than colour, and it measured 1.41 against the
   body text in sky mode. An underline satisfies it without inventing a colour. */
.storm-handoff a{font-weight:600;text-decoration:underline}
.sc-fold{margin-top:10px}
.sc-fold summary{cursor:pointer;font-family:var(--mono);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--link);font-weight:600;padding:6px 0}
.sc-fold summary:hover{text-decoration:underline}
.sc-fold summary:focus-visible{outline:3px solid var(--rule);outline-offset:2px;border-radius:4px}
.sc-fold[open] summary{margin-bottom:10px}
@media (max-width:640px){
  .sc-labels{font-size:8.5px;letter-spacing:.02em}
  .sc-track,.sc-labels{gap:3px}
}

/* ---- maps and the hurricane center (Phase 2) ----------------------------------- */
.map-frame{height:440px;border:1px solid var(--line);border-radius:8px;overflow:hidden;background:var(--map-sea)}
.map-frame.tall{height:520px}
@media (max-width:640px){.map-frame,.map-frame.tall{height:340px}}
.leaflet-container{font-family:var(--sans);font-size:12px}
.leaflet-container:focus-visible{outline:3px solid var(--rule);outline-offset:-3px}
.leaflet-control-zoom a{background:var(--card)!important;color:var(--ink)!important;border-color:var(--line)!important}
.leaflet-control-attribution{background:var(--card)!important;color:var(--faint)!important;font-family:var(--mono);font-size:9.5px!important}
.leaflet-control-attribution a{color:var(--faint)!important}
/* radar loop controls */
.rl-scrub{flex:1;min-width:150px;display:flex;align-items:center}
.rl-scrub input[type=range]{width:100%;accent-color:var(--teal-ink);cursor:pointer}
.rl-scrub input[type=range]:disabled{cursor:default;opacity:.5}
.rl-warnings{margin-top:10px}
.rl-warnings .ww-list li{display:flex;gap:8px;align-items:baseline;flex-wrap:wrap}

/* city labels: legible over radar without competing with it. The halo is what
   keeps the name readable on top of a green echo or a warning polygon. */
.wx-city{width:auto!important;height:auto!important;margin:0!important;pointer-events:none}
.wx-city-in{display:flex;align-items:center;gap:4px;white-space:nowrap}
/* near the right edge the name sits left of its dot so it never clips. The
   transform is on this inner element on purpose: Leaflet owns the transform
   on the marker root and overriding it would break positioning. */
.wx-city.flip .wx-city-in{flex-direction:row-reverse;transform:translateX(-100%)}
.wx-city-dot{width:4px;height:4px;border-radius:50%;background:var(--map-label);
  box-shadow:0 0 0 1.5px var(--map-label-halo);flex:none}
.wx-city-name{font-family:var(--sans);font-size:11px;font-weight:600;letter-spacing:.01em;
  color:var(--map-label);
  text-shadow:0 0 3px var(--map-label-halo),0 0 3px var(--map-label-halo),
              0 0 5px var(--map-label-halo),1px 1px 0 var(--map-label-halo)}

/* ---- radar legend and empty-view note -------------------------------------
   The ramp is NOAA's own colour scale for this layer, read out of its
   GetLegendGraphic response rather than approximated, so the key cannot drift
   from the imagery it explains. */
/* SPC severe outlook. The chip takes its colour from the government's own
   fill for that category, so the swatch beside the sentence is the same colour
   as the shading on the map. */
.spc-box{margin-top:14px}
.spc-say{font-size:14.5px;line-height:1.6;color:var(--ink);margin:0}
.spc-chip{display:inline-block;padding:2px 9px;border-radius:99px;margin-right:8px;
  font-family:var(--mono);font-size:11px;font-weight:600;color:#14202B;
  border:1px solid rgba(0,0,0,.28);vertical-align:1px}
.spc-none{font-size:14px;color:var(--muted);margin:0}
.spc-stamp{font-family:var(--mono);font-size:11px;color:var(--faint);margin:6px 0 0}

.wxr-legend{margin-top:0}
.wxr-legend-h{font-family:var(--serif);font-size:16px;margin:0 0 10px}
.wxr-key{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px}
.wxr-key-label{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint)}
.wxr-ramp{display:block;flex:1 1 220px;min-width:200px;height:14px;border-radius:3px;
  border:1px solid var(--line)}
.wxr-ends{display:flex;justify-content:space-between;flex:1 1 100%;
  font-family:var(--mono);font-size:10.5px;color:var(--faint)}
.wxr-toggle{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin:10px 0 4px}
.wxr-toggle-note{font-size:12.5px;color:var(--muted)}
.wxr-note{font-size:13.5px;line-height:1.55;color:var(--muted);margin:10px 0 0}
.wxr-swatches{display:flex;flex-wrap:wrap;gap:8px 18px;align-items:center;margin-top:14px}
.wxr-sw{display:inline-flex;align-items:center;gap:7px;font-size:13.5px;color:var(--ink)}
.wxr-sw i{width:12px;height:12px;border-radius:3px;flex:none;border:1px solid rgba(0,0,0,.25)}
.rl-local{margin-bottom:16px}
.rl-local:empty{margin-bottom:0}
.rl-empty{margin:10px 0 0;font-size:13.5px;line-height:1.55;color:var(--muted)}
/* Warned areas, grouped by hazard family. Each group is a disclosure whose
   summary always states its counts, so folding one hides the place names but
   never the fact that something is in effect. */
.ww-groups{margin:0}
.rl-source{font-size:13px;color:var(--muted);margin:8px 0 0}
.ww-hint{font-size:13px;color:var(--muted);margin:0 0 9px}
/* warned shapes are tappable; they reveal their own text in the list below */
.leaflet-interactive{cursor:pointer}
.ww-group{border:1px solid var(--line);border-radius:9px;margin:0 0 8px;
  background:var(--chip-bg)}
.ww-group summary{display:flex;align-items:center;gap:9px;cursor:pointer;
  padding:10px 13px;font-size:14px;list-style:none}
.ww-group summary::-webkit-details-marker{display:none}
.ww-group summary::after{content:"\25BC";margin-left:auto;font-size:9px;color:var(--faint);
  transition:transform .15s ease}
.ww-group[open] summary::after{transform:rotate(180deg)}
.ww-group summary:hover{color:var(--ink)}
.ww-group summary:focus-visible{outline:3px solid var(--rule);outline-offset:-2px;border-radius:9px}
.ww-group summary .sw{width:12px;height:12px;border-radius:3px;flex:none;
  border:1px solid rgba(0,0,0,.3)}
.ww-count{font-family:var(--mono);font-size:11.5px;color:var(--muted);font-weight:400}
/* county-wide alerts have no polygon, so they are marked as such rather than
   implying a shape on the map that does not exist */
.ww-scope{display:block;font-family:var(--mono);font-size:10.5px;color:var(--faint);margin-top:2px}
.ww-zone{opacity:.95}
.ww-group .ww-list{margin:0;padding:2px 13px 12px 13px;list-style:none}
/* Each entry is now a full as-issued alert card from WX.alertItem, the same
   component /alerts renders, so the official wording cannot drift between the
   two surfaces. The row styling that used to sit here is gone: the card brings
   its own severity chip and colour band. */
.ww-group .ww-item{padding:10px 0;border-top:1px solid var(--line)}
.ww-group .ww-item:first-child{border-top:0}
/* focus ring when a tap on the map sends the reader here */
.ww-group .ww-item:focus-visible{outline:3px solid var(--rule);outline-offset:3px;border-radius:8px}
.ww-group .ww-item .alert{margin:0}
.ww-area{font-family:var(--mono);font-size:11.5px;color:var(--muted);margin:6px 0 0;line-height:1.5}
@media (prefers-reduced-motion:reduce){.ww-group summary::after{transition:none}}

.ww-intro{font-size:13.5px;color:var(--ink);margin:10px 0 6px}
.ww-more{font-size:13px;color:var(--copper-ink);margin:8px 0 0;font-weight:600}

.map-legend{display:flex;flex-wrap:wrap;gap:6px 16px;margin-top:10px;font-family:var(--mono);font-size:11.5px;color:var(--muted)}
.map-legend .sw{display:inline-block;width:12px;height:12px;border-radius:3px;vertical-align:-1px;margin-right:6px;border:1px solid var(--line)}
.storm-row{display:flex;flex-wrap:wrap;gap:8px 22px;align-items:baseline}
.storm-name{font-family:var(--serif);font-weight:600;font-size:24px;letter-spacing:-.01em}
.storm-class{font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--copper-ink);font-weight:600}
.storm-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));gap:10px 18px;margin-top:12px}
.storm-stats .nk{font-family:var(--mono);font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--faint)}
.storm-stats .nv{font-family:var(--mono);font-size:16px;font-weight:600}
.pos-table{width:100%;border-collapse:collapse}
.pos-table th{font-family:var(--mono);font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--faint);text-align:left;padding:4px 8px;border-bottom:1px solid var(--line)}
.pos-table td{font-size:13.5px;padding:6px 8px;border-bottom:1px solid var(--line);font-family:var(--mono)}
.pos-table tr:last-child td{border-bottom:none}
.ww-list{margin:8px 0 0;padding:0;list-style:none}
.ww-list li{padding:7px 0;border-bottom:1px solid var(--line);font-size:14.5px}
.ww-list li:last-child{border-bottom:none}
.ww-list .sw{display:inline-block;width:12px;height:12px;border-radius:3px;margin-right:8px;vertical-align:-1px}
.buoy-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-top:8px}
.buoy{border:1px solid var(--line);border-radius:8px;padding:10px 12px}
.buoy .b-id{font-family:var(--mono);font-size:11px;color:var(--faint);text-transform:uppercase;letter-spacing:.05em}
.buoy .b-id a{text-decoration:underline}
.buoy .b-vals{font-family:var(--mono);font-size:14px;font-weight:600;margin-top:4px;line-height:1.7}
.center-strip{background:var(--card);border:1px solid var(--line);border-left:6px solid var(--copper);border-radius:8px;padding:12px 18px;margin:14px 0 4px;box-shadow:var(--shadow);display:flex;flex-wrap:wrap;gap:8px 18px;align-items:baseline}
.center-strip b{font-family:var(--serif);font-size:18px}
.center-strip a{font-weight:600}
.adv-text{white-space:pre-wrap;font-family:var(--mono);font-size:13px;line-height:1.55;background:var(--paper);border:1px solid var(--line);border-radius:7px;padding:12px 14px;margin:10px 0 0;overflow-x:auto}


/* ---- the Living Sky ------------------------------------------------------------
   The board wears the weather. The base scene is built ONLY from the observed
   condition and the daypart, so it is always literally true; a hazard is a
   treatment layered over it (see wx-sky.js). Card scrim below is a MEASURED
   floor, not a taste call: at 0.68 over the lightest possible sky (day/clear
   bottom stop #8FCBDF) the three text tones clear AA at 7.44, 5.67 and 4.60.
   The prototype shipped 10px labels at 48 percent opacity, which measured
   2.09 there. Do not soften either number without re-running that check. */
.wxsky{position:fixed;inset:0;z-index:-1;overflow:hidden;pointer-events:none}
.wxsky-grad{position:absolute;inset:0}
.wxsky-fx{position:absolute;inset:0;overflow:hidden}
.wxsky-wash{position:absolute;inset:0;pointer-events:none}
/* multiply so the hazard can only DARKEN the true scene, never recolour it */
.wxsky-hazard{position:absolute;inset:0;pointer-events:none;mix-blend-mode:multiply}

/* cards floating on the sky */
.sky-card{background:rgba(12,18,26,.88);border:1px solid rgba(255,255,255,.10);
  border-radius:14px;padding:20px 22px;margin:0 0 16px;
  -webkit-backdrop-filter:blur(9px);backdrop-filter:blur(9px)}
.sky-card .v{color:#F4F1EA}
.sky-card .k{color:#CBD6DC;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.08em;text-transform:uppercase}
.sky-card .m{color:#B4C2CA;font-size:12.5px}
.sky-card a{color:#EAF1F6;text-decoration:underline}

/* the sky is decorative; it must never be announced or focusable */
@media (prefers-reduced-motion:reduce){
  .wxsky-fx *{animation:none!important}
}

/* illustration animations */
.wxsky-spin-slow{transform-origin:100px 100px;animation:rot 120s linear infinite}
@keyframes rot{to{transform:rotate(360deg)}}
.wxsky-gust{animation:gustA 3.4s ease-in-out infinite}
@keyframes gustA{0%,100%{transform:translateX(-4px);opacity:.75}50%{transform:translateX(6px);opacity:1}}
@keyframes fallA{0%{transform:translateY(-8px);opacity:0}25%{opacity:1}100%{transform:translateY(16px);opacity:0}}
@keyframes fallB{0%{transform:translateY(-10px);opacity:0}30%{opacity:1}100%{transform:translateY(18px);opacity:0}}
@keyframes zapA{0%,88%{opacity:1}90%{opacity:.25}92%{opacity:1}94%{opacity:.3}96%{opacity:1}}
@keyframes waveA{0%,100%{transform:translateX(-6px)}50%{transform:translateX(6px)}}
@keyframes shim{0%,100%{transform:translateY(0);opacity:.7}50%{transform:translateY(-5px);opacity:1}}
/* sun / moon */
.wxsky-orb{position:absolute;border-radius:50%;transition:all 1.4s cubic-bezier(.2,.7,.2,1)}
.wxsky-sun{width:120px;height:120px;background:radial-gradient(circle at 42% 38%,#FFF6DA,var(--glow) 42%,rgba(242,193,78,.35) 66%,transparent 72%);
  filter:blur(.4px);box-shadow:0 0 70px 24px rgba(242,193,78,.20),0 0 190px 70px rgba(242,193,78,.09)}
.wxsky-rays{position:absolute;width:520px;height:520px;left:50%;top:50%;transform:translate(-50%,-50%);
  /* REPEATING, and that word is the whole fix. A plain conic-gradient whose
     last stop sits at 22deg fills 22deg to 360deg with that final colour, so
     this drew exactly ONE 3deg wedge on the sun and rotated it: a ball on a
     stick. 22.5deg divides 360 exactly, giving 16 evenly spaced rays with no
     seam where the gradient wraps. */
  background:repeating-conic-gradient(from 0deg,rgba(255,240,200,.16) 0 3deg,transparent 3deg 22.5deg);
  border-radius:50%;-webkit-mask:radial-gradient(circle,transparent 28%,#000 46%,transparent 74%);
  mask:radial-gradient(circle,transparent 28%,#000 46%,transparent 74%);animation:spin 190s linear infinite}
@keyframes spin{to{transform:translate(-50%,-50%) rotate(360deg)}}
.wxsky-moon{width:86px;height:86px;background:radial-gradient(circle at 38% 34%,#FBF7EC,#C9CFD8 58%,#9AA6B4);
  box-shadow:0 0 60px 18px rgba(210,225,245,.20),inset -16px -6px 0 -2px rgba(8,17,28,.62)}
/* stars */
.wxsky-star{position:absolute;background:#fff;border-radius:50%;opacity:0;animation:tw 5s ease-in-out infinite}
@keyframes tw{0%,100%{opacity:.15}50%{opacity:.9}}
/* clouds: soft blurred blobs, drifting */
.wxsky-cloud{position:absolute;border-radius:50%;filter:blur(26px);opacity:.5;animation:drift linear infinite}
@keyframes drift{from{transform:translateX(-22vw)}to{transform:translateX(122vw)}}
/* rain */
.wxsky-drop{position:absolute;width:1.4px;border-radius:2px;
  background:linear-gradient(transparent,rgba(198,226,246,.85));animation:fall linear infinite}
@keyframes fall{from{transform:translateY(-14vh)}to{transform:translateY(112vh)}}
/* lightning */
.wxsky-streak{position:absolute;height:2px;border-radius:2px;background:linear-gradient(90deg,transparent,rgba(226,238,252,.5),transparent);animation:blow linear infinite}
@keyframes blow{from{transform:translateX(-30vw)}to{transform:translateX(130vw)}}
@keyframes swim{from{transform:translate(-20vw,0)}to{transform:translate(120vw,-40px)}}
.wxsky-lightning .bolt{animation:flash 9s steps(1) infinite}
@keyframes flash{0%,96%{opacity:0}96.5%{opacity:.5}97%{opacity:0}97.6%{opacity:.32}98.1%{opacity:0}}
@keyframes breathe{0%,100%{opacity:.5}50%{opacity:.95}}


/* CONTRAST IS CARRIED BY THE SCRIM ALONE, NOT BY THE BLUR.
   backdrop-filter makes the true text ground unpredictable: it depends on
   whatever sky happens to sit behind the card, and neither axe nor we can
   compute it (axe measured #5A5E63 where the colour math predicted #364D59,
   and 51 nodes failed). So the scrim is opaque enough to guarantee the ratio
   on its own and the blur is left as pure depth. The sky reads in the gaps
   between cards and around the page, which is where the atmosphere actually
   lives. Do not thin this scrim to show more sky through the text. */
/* ---- sky mode ---
   SPECIFICITY NOTE: these rules must use :root.sky-active, not html.sky-active.
   The theme blocks are :root[data-theme=dark] and :root:not([data-theme=light]),
   both (0,2,0); html.sky-active is only (0,1,1) and silently loses, which put
   the dark-mode link token back on the footer at 4.15 against a 4.5 floor.
   :root.sky-active ties at (0,2,0) and wins on source order from here.
   ------------------------------------------------------------------
   Active only when a location is set, i.e. when there is real weather to
   represent. Every token below was measured against the LIGHTEST possible sky
   (day/clear bottom stop #8FCBDF) through the 0.68 card scrim: ink 7.86,
   muted 5.99, faint 4.86, link 5.55, kicker 5.38. Overriding the custom
   properties means every existing component inherits sky-safe colour with no
   per-component work.

   The masthead keeps its OWN scrim rather than sitting naked on the sky: the
   wordmark directly on a bright day sky measures 1.58, which is why the
   prototype's transparent masthead could not ship as drawn. */
:root.sky-active{
  /* --faint was #B4C2CA, which measured 4.29 on the masthead's translucent
     ground in sky mode and failed AA by a hair. #C9D4DA is 5.20 there, and
     higher still on the card ground, so nothing else regresses. */
  --ink:#F4F1EA; --muted:#CBD6DC; --faint:#C9D4DA;
  --line:rgba(255,255,255,.14);
  --card:rgba(12,18,26,.88);
  --paper:transparent;
  --link:#9FD6DE; --link-hover:#C6E8EF;
  --teal-ink:#9BD3DC;
  --copper-ink:#F0B98A;
  --chip-bg:rgba(255,255,255,.10); --chip-fg:#DCE6EA;
  --shadow:0 22px 50px -30px rgba(0,0,0,.55);
}
:root.sky-active body{background:transparent}
:root.sky-active .card,
:root.sky-active .loc-bar,
:root.sky-active .alert,
:root.sky-active .severe-panel,
:root.sky-active .center-strip{
  background:var(--card);
  border-color:rgba(255,255,255,.12);
  -webkit-backdrop-filter:blur(9px);backdrop-filter:blur(9px);
}
:root.sky-active .masthead,
:root.sky-active .mh-nav{
  background:rgba(10,15,22,.72);
  border-color:rgba(255,255,255,.12);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
}
:root.sky-active .top-rule{background:rgba(255,255,255,.22)}
:root.sky-active .mh-word{color:#F4F1EA}
:root.sky-active .mh-word-site{color:#9BD3DC}
:root.sky-active footer.site{background:rgba(10,15,22,.72);border-color:rgba(255,255,255,.12);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}
:root.sky-active .theme-toggle{border-color:rgba(255,255,255,.18)}
/* THE SECTION HEAD WAS THE ONE THING PAINTING STRAIGHT ONTO THE SKY.
   Every other surface earns a ground somewhere up its ancestor chain (cards,
   the location bar, alerts, the masthead, the footer). The section head did
   not: html, body and .sec-head were all transparent, so its true background
   was the sky gradient itself, and sky-mode had already switched its text to
   near-white for a dark sky.

   Measured against the lightest stop of a clear-day sky, rgb(137,195,214):
   the heading was 1.72 and its note 1.06. Not marginal, invisible. It read
   correctly at dawn and at night, which is exactly why it survived the first
   pass; only a bright afternoon exposes it.

   A scrim at .78 puts the heading at 10.6 and the note at 6.6 on that same
   worst case, and the panel reads as deliberate rather than as a patch. */
:root.sky-active .sec-head{
  background:rgba(12,18,26,.78);border-radius:9px;padding:9px 14px;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
:root.sky-active .sec-head h2{color:#F4F1EA}
:root.sky-active .sec-head .bar{background:rgba(255,255,255,.16)}
:root.sky-active .skel{background:rgba(255,255,255,.10)}
/* The alerts page has the same defect .sec-head had, in three more places:
   its section heads, its severity group heads and its trailing source line
   sit straight on the sky with no card under them. Measured against the
   lightest clear-day stop rgb(143,203,223), the group head ran 2.22 and the
   source line 1.30. Both read fine at dawn and at night, which is why they
   survived; a bright afternoon is what exposes them. Same remedy and the
   same .78 as the section head above, so the page reads as one system. The
   group head hugs its own content, since a full width bar per severity
   stacks into three heavy slabs. */
:root.sky-active .al-sec{
  background:rgba(12,18,26,.78);border-radius:9px;padding:9px 14px;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
:root.sky-active .sev-group>h4{
  display:inline-flex;background:rgba(12,18,26,.78);border-radius:9px;padding:7px 13px;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
:root.sky-active .al-foot{
  background:rgba(12,18,26,.78);border-radius:9px;padding:8px 13px;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
/* the alert keeps its official event colour band on the left */
:root.sky-active .alert-text,
:root.sky-active .adv-text,
:root.sky-active .sv-instruction{background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.14)}

/* delight affordances stand down once the situation is a watch or a warning */
:root.sky-active[data-tier=watch] .sky-note,
:root.sky-active[data-tier=warning] .sky-note{display:none}
.sky-note{margin:10px 0 0;font-family:var(--serif);font-style:italic;font-size:15px;color:var(--muted)}
/* In the hero the ground is the scrim, not a card, so the colour is the hero's
   own proven value rather than a token: #DDE4E8 is the same one .wx-feels uses
   and was measured against the deepest scrim stop. */
.wx-hero .sky-note{color:#DDE4E8}

/* The condition illustration. Sized well inside the hero rather than fitted to
   it: the hero is overflow:hidden, and art fitted exactly loses pixels top and
   bottom the moment a viewBox overshoots its box. overflow:visible on the svg
   itself means a stray stroke is never clipped either. Purely decorative, so it
   sits under the text layer and takes no pointer events. */
/* The reading and the condition illustration side by side, the proportions the
   design uses. The art was a small badge pinned to the top corner, which left a
   hole beside the temperature exactly where the eye goes next.

   overflow:visible on the svg because the hero is overflow:hidden and art
   fitted tight to its box loses a ray or a streak that reaches past the
   viewBox. */
/* The art column used to be .85fr, which on a 1036px hero made it 409px wide
   holding a 196px drawing: 107px of dead space on its left and 106px on its
   right. It is sized to the artwork now, and the artwork fills it, so the
   reading gets the width back and the gaps close. */
.wx-hero-grid{display:grid;grid-template-columns:auto minmax(0,380px);gap:44px;
  align-items:center;justify-content:center}
/* no art for this condition: one column, no hole beside the reading */
.wx-hero-grid:has(.wx-art[hidden]){grid-template-columns:1fr}
/* under a live alert the drawing stays but steps back, so the warning above
   keeps the page */
.wx-hero[data-alert=true] .wx-art{opacity:.62}

/* ---- the hero's reading, rail and hour wash -----------------------------------
   Every ink here was measured against the card ground AFTER the hour wash is
   applied, at all four dayparts. Worst cases: rain #8EC9E8 8.74, labels 6.13,
   values 13.95, the vs-normal arrows 6.68 and 5.35. The wash is capped at 0.16
   precisely so it can never become load-bearing for legibility, the same rule
   the scrim follows: it tints the hour, it does not carry the text. */

/* today's high and low, beside the reading */
.wx-hilo{display:flex;flex-direction:column;gap:6px;padding-top:14px}
.wx-hilo-row{display:flex;align-items:baseline;gap:8px;font-family:var(--mono);font-size:13px}
.wx-hilo-row em{font-style:normal;color:#9AA3A9;width:11px;letter-spacing:.06em}
.wx-hilo-row b{font-weight:600;color:var(--t-ink-dark,#F4F1EA)}

/* vs normal: the archive figure the card already cited but never showed.
   The words say above/below too, so the arrow is never the only carrier. */
.wx-norm{display:inline-flex;align-items:center;gap:8px;margin:12px 0 0;
  font-family:var(--mono);font-size:12px;letter-spacing:.02em;
  padding:5px 12px;border-radius:999px;background:rgba(244,241,234,.08);
  border:1px solid rgba(244,241,234,.16);color:#DDE4E8}
.wx-norm b{font-weight:500;color:#F4F1EA}
.wx-norm-arrow{font-size:11px;line-height:1}
.wx-norm.up .wx-norm-arrow{color:#F09248}
.wx-norm.down .wx-norm-arrow{color:#6C97E0}

/* THE RAIL: bordered cells, not a footer row of equal-weight numbers. Rain is
   tinted because it is the thing most people opened the page to find. */
/* values never wrap mid-unit: wind was breaking to "SSE 8" / "mph" */
.wx-stats .nv{white-space:nowrap}
.wx-stats .wx-rain-cell .nv.rain{color:#8EC9E8}
.wx-stats .wx-rain-cell{position:relative}
.wx-stats .wx-rain-cell:empty{display:none}

/* the hour wash: one tinted layer keyed to the daypart, so 5 PM and 8 PM do
   not look identical on a card that is otherwise flat charcoal */
.wx-hero .wx-hourwash{position:absolute;inset:0;pointer-events:none;z-index:0;
  opacity:0;transition:opacity .5s,background .5s}
@media(prefers-reduced-motion:reduce){.wx-hero .wx-hourwash{transition:none}}
:root.sky-active .wx-hero .wx-hourwash{opacity:1}
.wx-hero[data-tod=day] .wx-hourwash{background:linear-gradient(160deg,rgba(46,134,174,.16),transparent 78%)}
.wx-hero[data-tod=night] .wx-hourwash{background:linear-gradient(160deg,rgba(11,29,51,.16),transparent 78%)}
.wx-hero[data-wx=storm] .wx-hourwash,.wx-hero[data-wx=rain] .wx-hourwash{background:linear-gradient(160deg,rgba(90,110,130,.16),transparent 78%)}

/* the hero on a scrubber: a scrubbed hour must never read as the present.
   Both wear opaque chips because the amber measured 3.61 bare on the bright
   hero band; on the chip ground it clears 9. The dot pulse is decorative and
   stops under reduced motion. */
.wx-when{display:inline-flex;align-items:center;gap:7px;font-family:var(--mono);
  font-size:11px;letter-spacing:.08em;text-transform:uppercase;white-space:nowrap;
  background:rgba(10,16,24,.72);border:1px solid rgba(242,193,78,.55);color:#F2C14E;
  border-radius:99px;padding:4px 11px;margin-left:auto}
.wx-backnow{font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  background:rgba(10,16,24,.72);border:1px solid rgba(244,241,234,.4);color:#F4F1EA;
  border-radius:99px;padding:4px 11px;cursor:pointer;opacity:0;pointer-events:none;transition:opacity .15s}
.wx-backnow.on{opacity:1;pointer-events:auto}
.wx-backnow:hover{border-color:#F4F1EA}
.wx-backnow:focus-visible{outline:3px solid #fff;outline-offset:2px}
@media(prefers-reduced-motion:reduce){.wx-backnow{transition:none}}
/* min-height matches the drawing rather than exceeding it: the reading column
   is ~108px tall, so an oversized row left 88px of air beside it. */
.wx-art{position:relative;display:grid;place-items:center;min-height:0;
  pointer-events:none;opacity:.96}
.wx-art svg{width:100%;max-width:380px;height:auto;display:block;overflow:visible}

/* THE ART ANIMATIONS. These never ran. The illustrations carry class="spin-slow",
   "spin-med" and "spin-fast", and the stylesheet only defined .wxsky-spin-slow,
   a different name, with the other two missing entirely. Ten of the twenty four
   conditions were drawing rays, shimmer and storm bands that simply sat still,
   which is why the hero looked flat next to the prototype.

   transform-origin is the CENTRE OF THE VIEWBOX, not of the element. These are
   200x200 SVGs and a group rotating about its own bounding box would wobble off
   axis instead of turning about the sun. */
.wx-art svg .spin-slow,.wk-icon svg .spin-slow,
.wx-art svg .spin-med,.wk-icon svg .spin-med,
.wx-art svg .spin-fast,.wk-icon svg .spin-fast{transform-origin:100px 100px}
.wx-art svg .spin-slow,.wk-icon svg .spin-slow{animation:rot 120s linear infinite}
.wx-art svg .spin-med,.wk-icon svg .spin-med{animation:rot 42s linear infinite}
.wx-art svg .spin-fast,.wk-icon svg .spin-fast{animation:rot 13s linear infinite}
/* The other four hooks the artwork carries and the stylesheet never defined:
   gust (wind streaks), shimmer (heat rising), wave (moving water) and zap
   (lightning). Same story as the spin classes, so wind, high wind, high heat,
   flooding and thunderstorm all drew their moving parts standing still.

   These translate in USER UNITS, not viewport units. The sky layer's particles
   use vw because it is fixed to the viewport; these live inside a 200x200
   viewBox, where a vw offset would fling them far outside the drawing. */
@keyframes art-gust{
  0%{transform:translateX(-10px);opacity:0}
  25%{opacity:.95}
  75%{opacity:.95}
  100%{transform:translateX(16px);opacity:0}}
@keyframes art-wave{
  0%,100%{transform:translateX(0)}
  50%{transform:translateX(6px)}}
@keyframes art-zap{
  0%,90%{opacity:0}
  91%{opacity:1}
  94%{opacity:.2}
  96%{opacity:1}
  100%{opacity:0}}

.wx-art svg .gust,.wk-icon svg .gust{animation:art-gust 3.4s ease-in-out infinite}
/* stagger, so four streaks read as wind rather than as one bar sliding */
.wx-art svg .gust:nth-of-type(2),.wk-icon svg .gust:nth-of-type(2){animation-delay:.5s}
.wx-art svg .gust:nth-of-type(3),.wk-icon svg .gust:nth-of-type(3){animation-delay:1.1s}
.wx-art svg .gust:nth-of-type(4),.wk-icon svg .gust:nth-of-type(4){animation-delay:1.7s}
.wx-art svg .shimmer,.wk-icon svg .shimmer{animation:shim 2.6s ease-in-out infinite}
.wx-art svg .shimmer:nth-of-type(2),.wk-icon svg .shimmer:nth-of-type(2){animation-delay:.8s}
.wx-art svg .wave,.wk-icon svg .wave{animation:art-wave 4.2s ease-in-out infinite}
.wx-art svg .zap,.wk-icon svg .zap{animation:art-zap 5.5s linear infinite}
/* Cloud masses drift. cloudG is the shared helper every cloud-bearing
   illustration builds from, so one hook there moves all of them: cloudy, rain,
   snow, fog, sleet, hail and the rest were all completely still, which is what
   Jack noticed on a cloudy afternoon in Charleston.

   Small amplitude on purpose. The viewBox is 200 units wide and these are
   drawn at 232px, so a few units reads as weather breathing rather than as a
   cloud sliding across a card. */
.wx-art svg .cloudmass,.wk-icon svg .cloudmass{animation:art-cloud 11s ease-in-out infinite}
@keyframes art-cloud{
  0%,100%{transform:translateX(-3px)}
  50%{transform:translateX(4px)}}

@media (prefers-reduced-motion:reduce){
  .wx-art svg .spin-slow,.wx-art svg .spin-med,.wx-art svg .spin-fast,
  .wk-icon svg .spin-slow,.wk-icon svg .spin-med,.wk-icon svg .spin-fast,
  .wx-art svg .gust,.wx-art svg .shimmer,.wx-art svg .wave,.wx-art svg .zap,.wx-art svg .cloudmass,
  .wk-icon svg .gust,.wk-icon svg .shimmer,.wk-icon svg .wave,.wk-icon svg .zap,.wk-icon svg .cloudmass{animation:none}
}
@media (max-width:820px){
  /* Single column, and the READING stays first. The design prototype floats
     the art above it on narrow screens; on a site whose whole argument is data
     before decoration, pushing the actual temperature below an illustration on
     the smallest screen is the wrong way round. */
  .wx-hero-grid{grid-template-columns:1fr;gap:10px}
  .wx-art{min-height:168px;justify-items:start}
  .wx-art svg{width:min(58%,132px)}
}


/* Under sky mode the hero stops painting its own gradient: the full-bleed
   Living Sky behind the page is the atmosphere now, and the hero becomes a
   card floating on it. Its private fx and scrim layers stand down so the two
   systems never fight. */
:root.sky-active .wx-hero{background:rgba(12,18,26,.88)!important;min-height:0;
  border:1px solid rgba(255,255,255,.12);
  -webkit-backdrop-filter:blur(9px);backdrop-filter:blur(9px)}
:root.sky-active .wx-hero .wx-fx,
:root.sky-active .wx-hero .wx-scrim,
:root.sky-active .wx-hero .wx-hero-video,
:root.sky-active .wx-hero .hero-pause{display:none}
:root.sky-active .wx-hero-inner{padding:22px 24px 18px}

/* ---- footer -------------------------------------------------------------------- */
footer.site{border-top:1px solid var(--line);background:var(--card);margin-top:30px}
footer.site .wrap{padding:26px 22px 34px}
.frow{display:flex;flex-wrap:wrap;gap:12px 26px;align-items:baseline;justify-content:space-between}
.fbrand{font-family:var(--serif);font-weight:600;font-size:20px}
.flinks{display:flex;flex-wrap:wrap;gap:4px 18px;font-size:14px}
.fnote{font-size:13px;color:var(--muted);margin:14px 0 0;line-height:1.6}
.fnote b{color:var(--ink)}
/* links inside running text carry a non-color cue (WCAG 1.4.1) */
.fnote a,.prose p a,.prose li a,.lede a,.unavail a,.failsafe a,.loc-note a{text-decoration:underline}

/* ---- small screens --------------------------------------------------------------- */
@media (max-width:640px){
  body{font-size:16px}
  .card{padding:15px 16px}
  .mh-slogan{display:none}
  .now-grid{grid-template-columns:repeat(auto-fit,minmax(104px,1fr))}
  .days .d-wind{display:none}
  .days th,.days td{padding:8px 6px;font-size:13.5px}
}
@media (max-width:360px){
  .days .d-cond{font-size:13px}
}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation:none!important;transition:none!important}
}


/* Ambient ground on the non-board pages. The layer itself is the same fixed
   element the Living Sky uses, so it inherits the z-index and the pointer
   behaviour that were already settled there. */
/* PROSE NEEDS A GROUND, and this is measured rather than assumed. Body copy
   painted straight onto the ambient layer fails everywhere: 4.34 on the brand
   gradient's lightest stop, 2.02 at dusk, and 1.08 on the day sky, which is
   pale blue. The panel is the same rgba(12,18,26,.88) the cards use, whose
   pairings were already verified, and it takes the worst case to 9.10.

   It also makes the contrast COMPUTABLE. Without an opaque ancestor, axe walks
   up to nothing and assumes white, which reported 23 failures at 1.64 that were
   measuring an imaginary ground. A real panel means the checker and the eye
   agree. */
:root.sky-active main.prose{background:rgba(12,18,26,.88);border:1px solid rgba(255,255,255,.14);
  border-radius:12px;padding:26px 30px;margin-top:22px;margin-bottom:30px;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
@media (max-width:640px){:root.sky-active main.prose{padding:20px 18px}}
:root.sky-active .prose{color:var(--ink)}
:root.sky-active .prose h1,:root.sky-active .prose h2,
:root.sky-active .prose h3{color:#F4F1EA}
:root.sky-active .prose a{color:var(--link)}
:root.sky-active .gd-index li{border-color:rgba(255,255,255,.16)}
:root.sky-active .gd-cta{background:rgba(12,18,26,.88);border-color:rgba(255,255,255,.16)}
:root.sky-active .crumb a{color:#CBD6DC}

/* ---- guide pages ------------------------------------------------------------
   Server-rendered prose, readable with JavaScript off, which is the entire
   reason these pages exist. They reuse .prose from the About page and add only
   what the guides need. */
.crumb{font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--faint);margin:0 0 18px}
.crumb a{color:var(--muted)}
.prose .lede{font-family:var(--serif);font-size:19px;line-height:1.6;color:var(--ink);
  margin:0 0 26px}
.gd-list{margin:18px 0 0;padding:0}
.gd-list dt{font-family:var(--mono);font-size:12.5px;letter-spacing:.05em;font-weight:600;
  color:var(--teal-ink);margin-top:16px}
.gd-list dd{margin:5px 0 0;padding:0 0 0 0;color:var(--ink);line-height:1.6}
.gd-faq{margin:14px 0 0}
.gd-faq dt{font-family:var(--serif);font-size:17px;font-weight:600;margin-top:20px;color:var(--ink)}
.gd-faq dd{margin:6px 0 0;color:var(--muted);line-height:1.65}
.gd-cta{margin:30px 0 0;padding:18px 20px;border:1px solid var(--line);border-radius:10px;
  background:var(--card)}
.gd-cta p{margin:0}
.gd-cta p + p{margin-top:10px}
.gd-cta-link{font-weight:600}
.gd-rel{margin:12px 0 0;padding-left:20px}
.gd-rel li{margin:6px 0}
.gd-index{list-style:none;margin:22px 0 0;padding:0}
.gd-index li{border-top:1px solid var(--line);padding:16px 0}
.gd-index li:last-child{border-bottom:1px solid var(--line)}
.gd-index a{font-family:var(--serif);font-size:19px;font-weight:600}
.gd-index span{display:block;color:var(--muted);font-size:14.5px;line-height:1.55;margin-top:4px}
.gd-src{margin-top:28px;padding-top:14px;border-top:1px solid var(--line);
  font-size:13px;color:var(--faint);line-height:1.6}
