/* Libre Franklin, self-hosted since I-fu3 (2026-10-08): Google Fonts' own files and rules (assets/fonts/libre-franklin/, OFL),
   so the masthead's latin file has one stable URL to preload (Google serves each browser a different URL). */
/* cyrillic-ext */
@font-face{font-family:'Libre Franklin';font-style:italic;font-weight:400;font-display:swap;src:url(../fonts/libre-franklin/italic-cyrillic-ext.woff2) format('woff2');unicode-range:U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F}
/* cyrillic */
@font-face{font-family:'Libre Franklin';font-style:italic;font-weight:400;font-display:swap;src:url(../fonts/libre-franklin/italic-cyrillic.woff2) format('woff2');unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116}
/* vietnamese */
@font-face{font-family:'Libre Franklin';font-style:italic;font-weight:400;font-display:swap;src:url(../fonts/libre-franklin/italic-vietnamese.woff2) format('woff2');unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
/* latin-ext */
@font-face{font-family:'Libre Franklin';font-style:italic;font-weight:400;font-display:swap;src:url(../fonts/libre-franklin/italic-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
/* latin */
@font-face{font-family:'Libre Franklin';font-style:italic;font-weight:400;font-display:swap;src:url(../fonts/libre-franklin/italic-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
/* cyrillic-ext */
@font-face{font-family:'Libre Franklin';font-style:normal;font-weight:400 900;font-display:swap;src:url(../fonts/libre-franklin/normal-cyrillic-ext.woff2) format('woff2');unicode-range:U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F}
/* cyrillic */
@font-face{font-family:'Libre Franklin';font-style:normal;font-weight:400 900;font-display:swap;src:url(../fonts/libre-franklin/normal-cyrillic.woff2) format('woff2');unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116}
/* vietnamese */
@font-face{font-family:'Libre Franklin';font-style:normal;font-weight:400 900;font-display:swap;src:url(../fonts/libre-franklin/normal-vietnamese.woff2) format('woff2');unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
/* latin-ext */
@font-face{font-family:'Libre Franklin';font-style:normal;font-weight:400 900;font-display:swap;src:url(../fonts/libre-franklin/normal-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
/* latin */
@font-face{font-family:'Libre Franklin';font-style:normal;font-weight:400 900;font-display:swap;src:url(../fonts/libre-franklin/normal-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
/* Metric-matched fallbacks while the font loads (I-fu3): Arial / Liberation Sans, then Roboto (Android), sized and
   spaced like Libre Franklin per weight band (width ratio as size-adjust; ascent 0.966 em and descent 0.246 em divided by it),
   so text keeps its size and lines when the font swaps in. Numbers from the font files; tools repo fonts/, Round I-fu3 report. */
@font-face{font-family:'LF Fallback';src:local('Arial'),local('ArialMT'),local('Liberation Sans'),local('LiberationSans');font-weight:100 449;size-adjust:102.9%;ascent-override:93.84%;descent-override:23.90%;line-gap-override:0%}
@font-face{font-family:'LF Fallback';src:local('Arial'),local('ArialMT'),local('Liberation Sans'),local('LiberationSans');font-weight:450 649;size-adjust:106.4%;ascent-override:90.76%;descent-override:23.11%;line-gap-override:0%}
@font-face{font-family:'LF Fallback';src:local('Arial Bold'),local('Arial-BoldMT'),local('Liberation Sans Bold'),local('LiberationSans-Bold');font-weight:650 849;size-adjust:103.6%;ascent-override:93.21%;descent-override:23.74%;line-gap-override:0%}
@font-face{font-family:'LF Fallback';src:local('Arial Bold'),local('Arial-BoldMT'),local('Liberation Sans Bold'),local('LiberationSans-Bold');font-weight:850 1000;size-adjust:110.5%;ascent-override:87.46%;descent-override:22.27%;line-gap-override:0%}
@font-face{font-family:'LF Fallback Roboto';src:local('Roboto'),local('Roboto-Regular');font-weight:100 449;size-adjust:102.8%;ascent-override:93.92%;descent-override:23.92%;line-gap-override:0%}
@font-face{font-family:'LF Fallback Roboto';src:local('Roboto Medium'),local('Roboto-Medium');font-weight:450 649;size-adjust:107.5%;ascent-override:89.82%;descent-override:22.87%;line-gap-override:0%}
@font-face{font-family:'LF Fallback Roboto';src:local('Roboto Bold'),local('Roboto-Bold');font-weight:650 849;size-adjust:108.3%;ascent-override:89.16%;descent-override:22.70%;line-gap-override:0%}
@font-face{font-family:'LF Fallback Roboto';src:local('Roboto Black'),local('Roboto-Black');font-weight:850 1000;size-adjust:118.8%;ascent-override:81.31%;descent-override:20.71%;line-gap-override:0%}
/* FBLTWX · newspaper weather page. What pages share, and home's own (home loads nothing new, Round P). A rule only one
   page uses is in that page's stylesheet (V-fu1.2, Oct. 25, 2026); npcss_test.py holds this file to 32 KB gzipped. */
:root{
  --ink:#1a1a1a; --ink2:#444; --ink3:#555; --rule:#bdbdbd; --paper:#fdfcf8;
  --blue:#1b5fae; --navy:#0e3f7a; --blue2:#2a74c8; --red:#d7261e; --cream:#fff4c8; --cold:#1565c0; --slate:#546e7a; --slate-bg:#eceff1;
  --nice:#8f6708; --nice-bg:#fdf6e3;   /* seven-day "Nicest day" gold: 5.1:1 on white, 5.0:1 on paper, 4.7:1 on its own card (was #b8860b, 3.0:1; Oct. 7) */
  --gutter:40px;
  /* report card heatmap (models.js reads these): 1.5 F at hm0 to 6 F and up at hm4; warm/cold bias bars; close bars */
  --hm0:#0e3f7a; --hm1:#6f95c6; --hm2:#e9e6dc; --hm3:#f2a65a; --hm4:#c8461f; --hm-none:#f1efe8; --hm-none-ink:#6b6b6b;
  --hm-ink:#000;   /* dark text on heat cells: black, so the worst cell is 4.6:1 (ink #1a1a1a gave 4.18:1) */
  /* the report card's miss ramp (Round S2, Models 4; Travis, Oct. 20, 2026: one hue, light for a small miss and dark for a
     large one): one brown from 1.5° (miss0) to 6° and up (miss4), CIELAB lightness 92, 79, 64, 47 and 29 at hue 78°;
     models.js heat() blends between them and picks black or white text, whichever contrasts more. --hm0 to --hm4 stay
     for the storm log and the outlook cards. */
  --miss0:#f7e5d0; --miss1:#dfbf95; --miss2:#bd9459; --miss3:#8e692c; --miss4:#594015;
  --warm:#c41f17; --close2:#0e3f7a; --close5:#8fb0d8; --wk:#e2e8f1;
  --nbm:#2e7d32;   /* NBM's line on the models page (5.1:1 on white) */
  /* storm log category keys, kept from the old storm log: hail/tornado red, wind ink, flood/snow gray */
  --storm-hot:#d62d20; --storm-wind:#111111; --storm-cool:#6b6860;
  /* the storm-day pages' warning outlines and bars, and the map's county (Round Q4, Q5; the colors stormlog.py's day maps have used since Round C) */
  --storm-sv:#e8a317; --storm-ff:#2e7d32; --storm-county:#f1efe8;
  /* home's highs map (Round P19's server drawing, homemap.py): the gray of a map with no data, and its rain stipple's dots
     (np.js's map key draws the same dots) */
  --map-nodata:#efeee8; --map-rain:#1f7a3a;
  /* home's next 24 hours (Round P6, the server's and np.js's drawing alike): the drop on an hour the HRRR has rain in */
  --drop:#2e8fe0;
  /* a 7-day card with no temperature: its head's gray (np.js week() and the server's ssr.week_cards, P-fu6) */
  --day-none:#e8e8e8;
  /* Round M1, the restyle. Page bars, each with the text color that passes on it (style_test.py checks every pair): the
     logo bands plus nav blue and navy. White on --bar-red is 4.0:1, so only bold 19px or larger sits on red. The bands
     are never a text color on paper (each fails 4.5:1); --red-text is the red for text on paper (7.3:1, apart from the
     warning red). The band values are the temperature bands --t90 to --t50: a bar never stands in for a temperature. */
  --bar-red:#e8412c; --bar-red-ink:#fff; --bar-orange:#f79a2e; --bar-orange-ink:#1a1a1a; --bar-yellow:#fbd43b; --bar-yellow-ink:#1a1a1a;
  --bar-lime:#c9dc4a; --bar-lime-ink:#1a1a1a; --bar-green:#7cc576; --bar-green-ink:#1a1a1a; --bar-blue:#1b5fae; --bar-blue-ink:#fff;
  --bar-navy:#0e3f7a; --bar-navy-ink:#fff;
  --red-text:#9e2a1c;
  /* Round U3 (Radar 27): the radar's two palettes, weakest step first (15, 25, 35, 45, 55 and 65 dBZ): the site's
     (server/app/radar.py LEVELS) and the color-blind-safe one (LEVELS_CB, viridis); data colors for the radar keys only */
  --rl1:#bfe3a6; --rl2:#5fb15a; --rl3:#f2d23a; --rl4:#f28c28; --rl5:#d7261e; --rl6:#7b2fa8;
  --rlcb1:#fde725; --rlcb2:#7ad151; --rlcb3:#22a884; --rlcb4:#2a788e; --rlcb5:#414487; --rlcb6:#440154;
  /* U-fu1.2 (Radar 13): the 24-hour rain layer's six steps, under 0.1 in. first (server/app/mrms.py RAIN_STEPS, six of
     ColorBrewer's YlGnBu, safe for the three kinds of color blindness: palette_test.py); for its keys only */
  --rr1:#c7e9b4; --rr2:#7fcdbb; --rr3:#1d91c0; --rr4:#225ea8; --rr5:#253494; --rr6:#081d58;
  /* Round U2: the radar base map's colors (assets/np/radar-base.svg's own), for the county view's inline copy (.rp-cbase) */
  --rmap-land:#f3efe4; --rmap-urban:#e6dcc6; --rmap-county:#d3cab6; --rmap-stream:#9fc4de; --rmap-water:#8ab8da; --rmap-road:#b9ad97; --rmap-state:#7d776b;
  /* illustrations only (Round M10 and the page rounds), never data. --illo-warm and --illo-cold: np.css already has
     --warm and --cold as data colors. --sidebar-bg is #f5d3d0, not the scan's #f3cbc8, so link blue passes on it (4.6:1) */
  --sky-top:#6fa8dc; --sky-low:#eaf4fb; --illo-warm:#f28c3a; --illo-warm-soft:#f9c9a0; --illo-cold:#5db3e6; --illo-cold-soft:#bfe2f5;
  --airmass-cold:#9a86c4; --moist:#3fb8a6; --ground:#8cc896; --land:#e6c99a; --cloud-shadow:#9db4c8; --storm-cloud:#5e7c99;
  --sidebar-bg:#f5d3d0; --sidebar-rule:#3ba0d8;
}
*{box-sizing:border-box}
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--paper);color:var(--ink);font-family:'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;font-size:16px;line-height:1.4}
a{color:var(--blue);text-decoration:none}
a:hover{text-decoration:underline}
a:focus-visible,button:focus-visible,input:focus-visible,[tabindex]:focus-visible{outline:3px solid var(--blue);outline-offset:2px}
#week:focus-visible{outline-offset:-3px}   /* inside the edge: the strip's parent clips anything outside */
.np{max-width:1280px;margin:0 auto;padding:0 var(--gutter)}
.np-small{font-size:13px;color:var(--ink3)}
.np-source{margin:6px 0 0;font-size:12px;font-style:italic;color:var(--ink3)}
.np-note{margin:10px 0 0;font-size:14px;line-height:1.45}

/* masthead + nav */
.np-mast{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;padding:22px 0 14px}
.np-brand{display:flex;align-items:baseline;gap:18px;color:var(--ink)}
.np-brand:hover{text-decoration:none}
/* banded FBLTWX wordmark: real text, filled with the highs-map bands, thin dark outline.
   With line-height 1, Libre Franklin's cap tops sit 11.8% down the line box and its baseline at 86%
   (ascent 966, descent 246, cap 742 per 1000), so the stops split the caps 26/16/16/16/26 from top to bottom. */
.np-logo{font-weight:900;font-size:62px;letter-spacing:-.02em;line-height:1;color:var(--ink)}
@supports ((-webkit-background-clip:text) or (background-clip:text)) {
  .np-logo{background:linear-gradient(180deg,var(--t90) 0 31.1%,var(--t80) 31.1% 43%,var(--t70) 43% 54.8%,var(--t60) 54.8% 66.7%,var(--t50) 66.7% 100%);-webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-stroke:1.5px var(--ink)}
}
.np-tag{font-weight:500;font-size:17px;color:var(--ink2);padding-left:18px;border-left:2px solid var(--ink)}
.np-dateline{text-align:right;line-height:1.3;display:flex;flex-direction:column}
.np-dateline strong{font-weight:800;font-size:20px;color:var(--ink);min-height:1.3em}   /* the date comes in the HTML (SSI api/ssr/date.txt, H-fu6), so the header has its final height in the first paint; never less than a line */
/* Round M13: a 4px strip on paper runs along the nav's top, and each item carries its page's color there (np.css --nav-c,
   Round M-fu3; Today the five bands). The current page's item is a paper tab under its color, its text ink: filling it
   with the color would put small white text on the storm log's red (4.0:1) and lose Today's and Winter's blue in the
   bar's own blue. The bar stays 52px tall. */
.np-nav{display:flex;align-items:stretch;min-height:52px;background:linear-gradient(var(--paper),var(--paper)) top/100% 4px no-repeat,var(--blue);overflow-x:auto;scrollbar-width:none}
.np-nav::-webkit-scrollbar{display:none}
.np-nav.more{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 48px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 48px),transparent)}   /* links hidden past the right edge (assets/np/navcue.js) */
.np-section{display:flex;align-items:center;padding:4px 22px 0;background:linear-gradient(var(--paper),var(--paper)) top/100% 4px no-repeat,var(--navy);color:#fff;font-weight:900;font-size:24px;letter-spacing:.06em;flex-shrink:0}
.np-nav a{display:flex;align-items:center;padding:4px 18px 0;color:#fff;font-weight:600;font-size:16px;white-space:nowrap;background:linear-gradient(var(--nav-c,var(--blue)),var(--nav-c,var(--blue))) top/100% 4px no-repeat}
.np-nav a:hover{background-color:var(--blue2);text-decoration:none}
.np-nav a[aria-current],.np-nav a[aria-current]:hover{background-color:var(--paper);color:var(--ink);font-weight:700}
.np-now{margin-left:auto;display:flex;align-items:center;padding:0 20px;color:#fff;font-weight:600;font-size:15px;white-space:nowrap}

.np-nowarn{margin:14px 0 0;font-size:13px;font-weight:600;color:var(--ink3)}   /* quiet all-clear: plain gray text, nothing like an alert */
/* warning mode: banner, full-width radar with the polygons, plain-English details */
.np-warnradar{margin-top:12px}
.np-warnradar:empty{display:none}
.np-radar-warn path{stroke-width:4;stroke-linejoin:round}
.np-radar-warn text{font-size:max(15px,calc(12.5px*var(--k,1)));font-weight:900;fill:var(--ink);text-anchor:middle;paint-order:stroke;stroke:#fff;stroke-width:6px;stroke-linejoin:round}
/* the full-width warning radar is about twice as wide: keep its labels near their normal size */
#warn-radar .rl-towns text{font-size:max(15px,calc(12.5px*var(--k,1)))}
#warn-radar .rl-fbl text{font-size:max(18px,calc(12.5px*var(--k,1)))}
#warn-radar .rl-rings text,#warn-radar .rl-states text{font-size:max(12px,calc(12.5px*var(--k,1)))}
#warn-radar .rl-shields g{transform-box:fill-box}
#warn-radar .rl-towns circle{r:3.5px}
@media (max-width:800px){ .np-radar-warn text{font-size:max(22px,calc(12.5px*var(--k,1)))} #warn-radar .rl-towns text{font-size:max(25px,calc(12.5px*var(--k,1)))} #warn-radar .rl-fbl text{font-size:max(29px,calc(12.5px*var(--k,1)))} #warn-radar .rl-rings text,#warn-radar .rl-states text{font-size:max(19px,calc(12.5px*var(--k,1)))} #warn-radar .rl-towns circle{r:5px} }
.np-warninfo{--wc:var(--red);margin-top:12px;border:2px solid var(--wc);border-left-width:8px;background:#fff;padding:12px 16px}
.np-warninfo.ffw{--wc:var(--t80)}
.np-warninfo h3{margin:0 0 8px;font-size:18px;font-weight:900}
.np-warninfo dl{margin:0;display:grid;grid-template-columns:auto minmax(0,1fr);gap:4px 14px;font-size:16px}
.np-warninfo dt{font-weight:900;text-transform:uppercase;font-size:13px;letter-spacing:.05em;padding-top:2px}
.np-warninfo dd{margin:0}
.np-warninfo h4{margin:12px 0 4px;font-size:16px;font-weight:900}
.np-warninfo p{margin:0 0 6px;font-size:16px}
.np-warnfull{margin-top:8px;white-space:pre-wrap;font-size:14px;line-height:1.45;border-top:1px solid var(--rule);padding-top:8px}
/* the cam takes the whole row while the radar is up under the warning banner */
.np-looks.solo{grid-template-columns:minmax(0,1fr)}
/* freshness: a section past its limit is grayed, with a small note above it */
.is-stale{opacity:.45;filter:grayscale(1)}
.is-gone{visibility:hidden}   /* past its "gone" limit: hidden, its space kept (Round I-fu18) */
.np-stalenote{margin:6px 0;padding:3px 10px;width:fit-content;max-width:100%;border:1px dashed var(--ink3);background:var(--slate-bg);font-size:12.5px;font-weight:700;color:var(--ink)}

/* ---------- home grid ----------
   Round P1 (Home 2, Oct. 17, 2026): <main class="np-home"> lists the sections in ssr.HOME_ORDER, by how often they're
   needed (the conditions box, the next 24 hours, the 7-day, sky cam and radar, tonight's sky, the models box, the map, the
   cities, storms and rivers), and that is the reading order at every width. Over 1060 px this grid pairs them in the
   same order: next 24 hours and the 7-day | the box; sky cam and radar; tonight's sky | models; the map | the cities;
   storms and rivers. Column lines: the left column ends at c-end (800 of 1168 px), 32 px gap, d = the right column
   (the box's 368). Each section opens with its bar (.np-secbar, the color of the page it links to); the box keeps the
   five-band stripe. 1060 px and under: one column, in source order. */
.np-home{display:grid;grid-template-columns:[a] minmax(0,520px) [a-end] 32px [b] minmax(0,calc((100% - 32px) * 800 / 1168 - 552px)) [c-end] 32px [d] minmax(0,1fr) [end]}
.np-home{grid-template-rows:auto 1fr}   /* P1 fix (Oct. 17): the box spans rows 1 and 2; its extra height goes under the 7-day (row 2, flexible), not into row 1, so the 7-day doesn't jump up when its cards draw */
.np-hours{grid-column:a / c-end;grid-row:1}
.np-side{grid-column:d / end;grid-row:1 / span 2;margin-top:28px;align-self:stretch}
.np-week{grid-column:a / c-end;grid-row:2}
.np-looks{grid-column:a / end;grid-row:3}
.np-tonight{grid-column:a / c-end;grid-row:4;min-width:0}
.np-numbers{grid-column:d / end;grid-row:4}
.np-mapcol{grid-column:a / c-end;grid-row:5;min-width:0}
.np-row4{grid-column:d / end;grid-row:5}
.np-row5{grid-column:a / end;grid-row:6}
.np-home .np-secbar{margin:28px 0 10px}
.np-home .np-secmeta{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:0 14px;margin:0 0 8px}   /* Round P2: the stamp, and the section's own note or link */
.np-home .np-secmeta .np-stamp{margin:0}
.np-home .np-secsub{margin:0;font-size:13px;font-weight:700}
.np-home .np-secsub a{text-decoration:underline;text-underline-offset:2px}
.np-row4 .np-agate{grid-template-columns:minmax(0,1fr)}   /* the cities beside the map: one column */
.np-key{display:flex;flex-wrap:wrap;align-items:center;gap:6px 0;margin-top:10px;font-weight:800;font-size:14px;min-height:32px}   /* its drawn row (the band chips): no 4 px push of the map when np.js fills it (I-fu3) */
.np-key .sw{display:inline-flex;align-items:center;gap:6px;margin-right:14px}   /* a band's swatch with its range beside it, in ink on paper: 14px on the 90s band fails AA (Round M-fu2) */
.np-key .sw i{flex:none;width:22px;height:16px}
.np-key .lg{margin-left:22px;display:flex;align-items:center;gap:8px;font-weight:600}
.np-key .grp{display:inline-flex;flex-wrap:wrap;row-gap:6px;max-width:100%;align-items:center}   /* Round P1 (Home 21): temperatures, weather, fronts; never a chip alone on a line. N-fu72: a piece wider than the line wraps inside itself, not push the page sideways (Oct. 24 at 390: cold front, stationary front, low and high, 378 px in 358) */
.np-key .grp+.grp>.lg:first-child{margin-left:22px}
.np-key .lg.ctr+.lg.ctr{margin-left:16px}   /* N-fu72: the high beside the low, as far from it as when they were one chip */
.np-key .grp.fl{display:contents}   /* N-fu73: the fronts and centers flow chip by chip, so one can share a line with the chips before it (np.js keyFit) */
.np-key .brk{flex-basis:100%;height:0}   /* N-fu73: keyFit's line break, so the last front chip isn't alone on a line */
.np-map{position:relative;margin-top:10px;border:1px solid var(--rule);aspect-ratio:760/641;background:#a9d4f2}
.np-map canvas,.np-map svg{position:absolute;inset:0;width:100%;height:100%;display:block}
.np-mapmsg{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;padding:12px 16px;background:#fff;border:1px solid var(--rule);font-size:15px;text-align:center;max-width:80%}
.np-side{display:flex;flex-direction:column;gap:22px;min-width:0}
.np-box{border:1px solid var(--rule);background:#fff}
.np-side .np-box{flex:1;display:flex;flex-direction:column}   /* the Faribault box runs the full height of the map */
.np-boxhead{display:flex;justify-content:space-between;align-items:baseline;padding:8px 14px;background:var(--t60)}
.np-boxhead h2{margin:0;font-weight:900;font-size:20px}
.np-boxhead span{font-weight:700;font-size:13px;padding:1px 6px;background:var(--paper);color:var(--ink)}   /* the station on paper, off the band fill: 13px on the 90s band fails AA in white or ink (Round M-fu2) */
.np-fbl{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:16px 16px 12px}   /* V-fu1.4: High / Low drops under the temperature when the row can't hold it (320 px; a 103° day at 390), never past the page's edge */
.np-fbl-icon svg{width:80px;height:80px;display:block}
/* current KFBL temperature, then today's forecast high / tonight's low beside it */
.np-fbl-now{display:flex;flex-direction:column}
.np-fbl-big{font-weight:900;font-size:64px;line-height:1}
.np-fbl-hl{margin-left:auto;display:flex;flex-direction:column;align-items:flex-end;text-align:right}
.np-fbl-hl b{font-weight:800;font-size:22px;line-height:1.1;white-space:nowrap}
.np-fbl-already{margin-top:2px;font-weight:700;color:var(--ink)}   /* Round P3: the airport past the stated high, in the cell's room (no shift) */
/* 2 x 3 tiles: small label over a bold value */
.np-tiles{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));border-top:1px solid var(--rule)}
.np-tiles:empty{display:none}
.np-tile{padding:8px 9px;border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);min-width:0}
.np-tile:nth-child(3n){border-right:0}
.np-tile span{display:block;font-size:12px;color:var(--ink3);white-space:nowrap}
@media (max-width:359px){.np-tile span{white-space:normal}}   /* V-fu1.4: at 320 "Rain Chance (24 hr)" takes two lines, inside its tile */
.np-tile b{display:block;font-size:17px;font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.np-tile.wind b{white-space:normal;overflow:visible}   /* wind is never cut: "WNW 28 mph" can outgrow the tile, so it wraps */
.np-tile .sub{display:block;font-size:13px;font-weight:700;color:var(--ink);line-height:1.25;margin-top:1px;white-space:normal}   /* "Gusts 16 mph"; Round P4's words may take two lines */
.np-tiles .np-tile{min-height:88px}   /* Round P4: room for the value and two lines of words in every tile, so a word coming or going never moves the box */
.np-warr{display:inline-block;width:14px;height:14px;margin-right:4px;vertical-align:-1px;fill:currentColor}   /* Round P4 (Home 14): where the wind blows to */
.np-dewnote{margin:6px 9px 0}
.np-sundiff{display:block}   /* Round P4 (Home 11): the change in day length, in words, under the times */
/* normals range bar: record low to record high in band colors, normal range bracket, forecast markers */
.np-normals{padding:10px 16px 10px;border-bottom:1px solid var(--rule)}
.np-nhead{display:flex;align-items:baseline;gap:8px}
.np-nhead h3{margin:0;font-size:15px;font-weight:800}
#normals-diff{font-size:14px;font-weight:700}
#normals-diff.warm{color:var(--red)}
#normals-diff.cool{color:var(--blue)}
.np-since{margin-left:auto;font-size:12px;text-decoration:underline}
.np-climate{margin-left:auto;font-size:13px;font-weight:700;white-space:nowrap}   /* the climate page (Round H4) */
.np-since:not([hidden])+.np-climate{margin-left:0}
.np-nbar{position:relative;height:12px;margin:18px 0 12px;border:1px solid var(--ink)}
.np-nbar .br{position:absolute;top:-8px;height:6px;border:2px solid var(--ink);border-bottom:0}
.np-nbar .tri{position:absolute;top:13px;width:0;height:0;margin-left:-5px;border:5px solid transparent;border-bottom:7px solid var(--ink);border-top:0}
.np-nlabels{display:flex;justify-content:space-between;gap:6px;font-size:12px;color:var(--ink2);line-height:1.25}
.np-nlabels span{text-align:center}
.np-nlabels span:first-child{text-align:left}
.np-nlabels span:last-child{text-align:right}
.np-nlabels b{display:block;font-size:14px;color:var(--ink)}
/* daylight strip: 24-hour bar, night navy, day gold, a marker at the current time */
.np-sun{padding:10px 16px 10px;border-bottom:1px solid var(--rule)}
.np-yday{margin:0;padding:8px 16px;border-bottom:1px solid var(--rule);font-size:14px;line-height:1.35}   /* Round P10 (Home 18): yesterday in one line, after the normals */
.np-ask{margin:0 16px 10px;font-size:15px;line-height:1.4;font-weight:600}   /* Round P11 (Home 19): jacket, umbrella and wind in words, under the box's line */
.np-sunline{margin:0;font-size:15px;font-weight:800}
.np-sunline span{font-weight:400}
.np-daybar{position:relative;height:8px;margin:8px 0 4px}
.np-daybar i{position:absolute;top:-4px;width:3px;height:16px;margin-left:-1px;background:var(--ink);border:1px solid #fff}
.np-daylen{margin:0;text-align:right;font-size:12px;color:var(--ink3)}
.np-moonrow svg{flex-shrink:0}
/* Round P12 (Home 10): Tonight's sky, one box written by the worker (nightpage.home_sky): the verdict, the moon, the
   aurora answer, the next event and the link to /night/, each once */
.np-skybox{margin-top:14px;border:1px solid var(--rule);background:#fff;padding:12px 16px}
.np-skybox p{margin:0}
.np-skybox .np-nightline{margin:0 0 10px;font-size:16px;line-height:1.4}
.np-skymoon{display:flex;align-items:center;gap:14px}
.np-skymoon svg{flex-shrink:0}
#moon-name{font-size:17px}
.np-moonmore{margin:4px 0 0!important;line-height:1.35}
.np-moonmore span{display:block}   /* the next rise and set; the next new and full moon (O-fu18) */
.np-skyaur,.np-skynext,.np-skylink{margin-top:10px!important;font-size:15px;line-height:1.4}
/* season snowfall in one line under the sky strip, winter mode only (Round I3; the tracker is on /winter/#season) */
.np-snowline{margin:10px 0 0;font-size:15px;font-weight:700}
.np-snowline:empty{display:none}
.moon-dark{fill:#9a9a9a}
.moon-lit{fill:#fff4b8}
.moon-edge{fill:none;stroke:var(--ink);stroke-width:2}
.np-chips{display:flex;flex-wrap:wrap;gap:8px;padding:10px 16px 12px;border-top:1px solid var(--rule)}
.np-chip{padding:5px 10px;border:2px solid var(--c);color:var(--c);font-size:13px;font-weight:700;line-height:1.25}
.np-chip b{font-weight:900}
.np-chip.on{background:var(--c);color:#fff}
.np-chip.frost{--c:var(--cold)}
.np-chip.snow{--c:var(--slate)}
.np-fbl-text{margin:0;padding:0 16px 14px;font-size:18px;line-height:1.45}
/* school-day bus stop line (only 3 p.m. the day before to 8:30 a.m.) */
.np-bus{margin:0;padding:8px 16px;background:var(--t70);color:var(--ink);font-weight:800;font-size:15px;border-bottom:1px solid var(--rule)}
/* KFBL station plot */
.np-plot{border-top:1px solid var(--rule);padding:10px 16px 12px}
.np-nline{margin:4px 0 6px;font-size:14px;line-height:1.35}   /* Round P5 (Home 4): the normals as a sentence over the bar */
.np-plot-h{margin:0;font-weight:800;font-size:14px}
/* the plot is the part of the box that flexes: at desktop width it grows or shrinks so the box ends with the map column */
.np-side .np-plot{flex:0 0 auto}
.np-plot-svg{display:block;width:100%;height:190px;margin:6px 0 4px;overflow:visible}   /* Round P5: a fixed height, open or closed nothing moves */
.np-plot-more{align-self:flex-start}
#plot-g{fill:var(--ink);stroke:var(--ink);stroke-linecap:round;stroke-linejoin:round}
#plot-g text{stroke:var(--paper);stroke-width:4px;paint-order:stroke;font-family:'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif}
.sp-ring{fill:#fff;stroke-width:2} .sp-ring.o{fill:none}
.sp-big{font-size:24px;font-weight:800}
.sp-num{font-size:17px;font-weight:700}
.sp-unit,.sp-m{font-size:12px;font-weight:800}
.sp-unit{fill:var(--ink3)}
.sp-wx{font-size:22px;font-weight:700}
.np-plot-more{margin-top:6px;padding:6px 10px;border:1px solid var(--rule);border-radius:0;background:#fff;color:var(--blue);font:700 13px 'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;cursor:pointer}
.np-plot-more:hover{border-color:var(--blue);text-decoration:underline}
.np-plot-more::after{content:' ▾'}
/* Go Back to Live: shown on the cam box while a timelapse is loaded */
.np-live{position:absolute;left:8px;top:8px;z-index:3;padding:6px 10px;border:1px solid var(--rule);background:#fff;color:var(--blue);font:700 13px 'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;cursor:pointer}
.np-live:hover{border-color:var(--blue);text-decoration:underline}
.np-plot-more[aria-expanded="true"]::after{content:' ▴'}
.np-plot-explain{margin:8px 0 0;padding:0;list-style:none;font-size:14px;line-height:1.4}
.np-plot-explain li{margin-top:4px}
.np-plot-explain span{font-weight:700;color:var(--ink3)}

/* sky cam + radar row: two equal frames in the sky cam's 16:9 shape */
.np-looks{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 32px}
.np-looks>.np-secbar{grid-column:1/-1;margin-bottom:0}
.np-cam{margin:0}
/* Round P13: the cam's caption (where it looks, the picture's time, today's timelapse) and the radar's rain line with its
   scan time, each one line under its picture */
.np-camcap,.np-radarline{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px;margin-top:6px;font-size:14px;line-height:1.35}
.np-camcap .np-stamp,.np-radarline .np-stamp{margin:0}
.np-rline{margin:0;font-weight:700}
@media (min-width:801px){   /* the radar and its line share the radar's cell (both placed, or the radar would flow to the next row), the
                              radar at its top and the line at its foot, level with the cam's caption */
  .np-looks>.np-radar{grid-column:2;grid-row:2;align-self:start}
  .np-radarline{grid-column:2;grid-row:2;align-self:end}
}
.np-cam-frame{position:relative;aspect-ratio:16/9;overflow:hidden;border:1px solid var(--rule);background:#20242b}
.np-cam-frame img,.np-cam-frame video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.np-cam-frame video{background:#20242b;cursor:pointer}
/* controls laid over the bottom of a picture: label or key on the left, round button on the right */
.np-ov{position:absolute;left:0;right:0;bottom:0;z-index:2;display:flex;align-items:center;gap:10px;padding:34px 10px 10px;background:linear-gradient(to top,rgba(0,0,0,.6),rgba(0,0,0,.25) 60%,rgba(0,0,0,0));color:#fff;pointer-events:none}
.np-ov>*{pointer-events:auto}
.np-ov-label{margin-right:auto;font-weight:800;font-size:15px;text-shadow:0 1px 3px rgba(0,0,0,.7)}
.np-ovbtn{width:44px;height:44px;border:2px solid #fff;background:rgba(26,26,26,.72)}
.np-ovbtn:hover{background:var(--ink)}
.np-ovbtn:focus-visible{outline:3px solid #fff;outline-offset:2px;box-shadow:0 0 0 6px var(--blue)}
/* on the radar the map stays clear: key on a white tag, loop controls in a small dark pill */
.np-radar .np-ov{background:none;padding:8px;align-items:flex-end;justify-content:space-between}
.np-radar .np-rkey{padding:4px 8px;background:#fff;border:1px solid var(--ink);color:var(--ink);text-shadow:none}
.np-radar .np-rkey i{box-shadow:none}
.np-radar .np-radarbar{flex:0 1 46%;padding-left:14px;border-radius:24px;background:rgba(26,26,26,.78)}
.np-sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.np-rule{border-top:4px solid var(--ink);padding-top:8px}
.np-h3{margin:0;font-weight:900;font-size:22px}
.np-h2{margin:0;font-weight:900;font-size:26px;line-height:1.1}
.np-radar{position:relative;aspect-ratio:16/9;overflow:hidden;border:1px solid var(--rule);background:#f3efe4}
/* the base map and frames are 4:3 (800x600); the 16:9 box shows the middle and trims the top and bottom */
.np-radar-stage{position:absolute;left:0;right:0;top:50%;aspect-ratio:4/3;transform:translateY(-50%)}
.np-radar>img,.np-radar-stage>img,.np-radar-stage>svg,.np-radar-frames,.np-radar-frames img{position:absolute;inset:0;width:100%;height:100%;display:block}
.np-radar-frames{mix-blend-mode:multiply}
.np-radar-frames img{opacity:0;will-change:opacity}
.np-radar-frames img.on{opacity:1}
.np-radar-labels{pointer-events:none;font-family:'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif}
/* Map labels (Round E5): each label's size is max(its design size, 12.5 px on screen). --k is the SVG's user units per
   screen pixel, set on the radar SVGs by np.js and radar.js (labelScale); without it the design sizes apply. */
.np-radar-labels text{paint-order:stroke;stroke:#fff;stroke-width:7px;stroke-linejoin:round}
.rl-towns circle{fill:var(--ink);stroke:#fff;stroke-width:2.5px}
.rl-towns text{font-size:max(25px,calc(12.5px*var(--k,1)));font-weight:700;fill:var(--ink)}
.rl-states text{font-size:max(22px,calc(12.5px*var(--k,1)));font-weight:800;letter-spacing:.06em;fill:#6f695e;stroke-width:5px}
.rl-rings text{font-size:max(19px,calc(12.5px*var(--k,1)));font-weight:700;fill:var(--ink3);text-anchor:middle;stroke-width:5px}
.rl-shields .s1{fill:var(--blue);stroke:#fff;stroke-width:2.5px}
.rl-shields .s2{fill:var(--red)}
.rl-shields text{font-size:max(19px,calc(12.5px*var(--k,1)));font-weight:900;fill:#fff;stroke:none}
.rl-fbl rect{fill:var(--red);stroke:#fff;stroke-width:3px}
.rl-fbl text{font-size:max(29px,calc(12.5px*var(--k,1)));font-weight:900;fill:var(--ink)}   /* ink, not red: red text was 4.4:1 at small sizes; the red square marks the town */
.np-radar-time{position:absolute;left:8px;top:8px;padding:3px 8px;background:#fff;border:1px solid var(--ink);font-weight:800;font-size:14px;font-variant-numeric:tabular-nums;line-height:1.2}
/* "Updated 4 min ago" tag, top right of the cam and radar; amber once the picture is stale */
.np-age{position:absolute;right:8px;top:8px;z-index:2;padding:3px 8px;background:#fff;border:1px solid var(--ink);font-weight:700;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums}
.np-radar.gif{background:#111}
.np-radar.gif>img.np-radar-gif{object-fit:cover}
.np-radar.gif>:not(.np-radar-gif){display:none}
.np-radarbar{flex:1;min-width:0;display:flex;align-items:center;gap:10px}
.np-play{flex-shrink:0;width:40px;height:40px;border:0;border-radius:50%;background:var(--ink);color:#fff;display:grid;place-items:center;cursor:pointer;padding:0}
.np-play svg{width:15px;height:15px;fill:currentColor}
.np-play .i-play,.np-play.paused .i-pause{display:none}
.np-play.paused .i-play{display:inline}
.np-scrub{flex:1;min-width:0;margin:0;accent-color:#fff}
.np-rkey{display:flex;align-items:center;gap:3px;font-size:12px;font-weight:700;text-shadow:0 1px 3px rgba(0,0,0,.7)}
.np-rkey i{width:18px;height:12px;display:block;box-shadow:0 0 0 1px rgba(255,255,255,.7)}
.np-rkey .w{margin:0 6px}

/* row 2: models | next 24 hours (placed by the home grid) */
.np-numbox{background:var(--cream);padding:14px 18px 16px}   /* Round P1: the section bar replaced the blue rule and the kicker */
.np-numbox .np-h2{margin-top:0}
/* Round P8 (Home 7): the models' dot strip, one row a model, highest first, on one scale; the blend's likely range shaded
   and its center a line (server/app/ssr.py models_box) */
.np-mstrip{margin:10px 0 4px}
.ms-row{display:grid;grid-template-columns:76px minmax(0,1fr) 36px;align-items:center;gap:8px;min-height:24px}
.ms-n{font-size:13px;font-weight:700;white-space:nowrap}
.ms-v{font-size:13px;font-weight:800;text-align:right}
.ms-t{position:relative;height:24px;border-left:1px solid var(--rule);border-right:1px solid var(--rule)}
.ms-t::before{content:"";position:absolute;left:0;right:0;top:50%;border-top:1px solid var(--rule)}
.ms-band{position:absolute;top:0;bottom:0;background:var(--wk)}
.ms-mid{position:absolute;top:0;bottom:0;width:2px;margin-left:-1px;background:var(--ink)}
.ms-dot{position:absolute;top:50%;width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;background:var(--navy);border:2px solid #fff}
#models-chart{margin-top:10px}
#models-chart svg{display:block;width:100%;height:auto}
.np-mlabels{display:grid;margin-top:6px;text-align:center;font-size:14px;line-height:1.25}
.np-mlabels small{display:block;font-size:13px}
/* NWS rain strip under the hourly bars: chance per hour, amounts per 6-hour block */
.np-rainstrip{margin-top:4px}
.np-chartsrc{margin:6px 0 0;font-size:12px;color:var(--ink3)}   /* which model feeds the chart; changes on fallback */
.np-compare{margin:10px 0 0;font-size:14px;font-weight:800}
.np-rainstrip .ch{display:flex;gap:3px;height:12px}
.np-rainstrip .ch i{flex:1 1 0;background:var(--blue)}
.np-rainstrip .qp{position:relative;height:20px;font-size:13px;font-weight:700;color:var(--blue)}
.np-rainstrip .qp span{position:absolute;top:2px;padding-top:2px;border-top:2px solid var(--blue);text-align:center;white-space:nowrap;overflow:hidden}
@media (max-width:899px){ .np-bar span.minor{visibility:hidden} }
@media (max-width:519px){ .np-axis span:not(.first):not(.a6){display:none} }   /* Round P6: times every 6 hours on phones, by CSS (nothing measured) */   /* a value on every third bar below 900px */
/* the hourly chart stretches to the height of the models box beside it; np.js scales the bars to fit */
.np-hours{display:flex;flex-direction:column;position:relative}
/* tap tip: what a bar's (or rain cell's) hover title says, for touch screens; np.js hoursTip() */
#hours-chart [data-tip],#hours-rain [data-tip]{cursor:pointer}
.np-tip{position:absolute;z-index:5;max-width:calc(100% - 8px);padding:6px 9px;background:var(--ink);color:var(--paper);font-size:13px;font-weight:700;line-height:1.3;pointer-events:none}
.np-bar.on i,#hours-rain .on{outline:2px solid var(--ink);outline-offset:1px}
/* Round P6 (Home 5): a fixed height (the server writes each bar's share of it), a 24 px band on top for the airport's mark
   and room for the tallest bar's value under it, so no value ever reaches the section's bar or stamp */
.np-bars{position:relative;margin-top:6px;flex:0 0 290px;height:290px;display:flex;align-items:stretch;gap:3px;border-bottom:2px solid var(--ink)}
.np-bar{flex:1 1 0;min-width:0;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;gap:3px}
.np-bar.night{background:var(--slate-bg)}   /* sunset to sunrise */
.np-bar.obs i{box-shadow:inset 0 0 0 2px var(--ink)}   /* the airport's reading */
.np-bar span{font-size:13px;font-weight:800;line-height:18px;white-space:nowrap}
.np-bar i{display:block;width:100%}
.np-drop{width:9px;height:12px;margin-right:1px;vertical-align:-1px}
.np-obsnote{position:absolute;left:0;top:2px;font-size:12px;font-weight:700;white-space:nowrap;line-height:18px}
.np-obsnote::before{content:"\2193  "}
.np-rainrow{position:relative;height:20px;margin-top:4px;font-size:13px;font-weight:700;color:var(--blue)}
.np-rainrow span{position:absolute;top:2px;text-align:center}
.np-axis{position:relative;height:20px;margin-top:6px;font-size:13px;font-weight:700}
.np-axis span{position:absolute;top:0;transform:translateX(-50%);white-space:nowrap}
.np-axis span.first{left:0!important;transform:none}
.np-axis.two{height:36px}   /* "Now / observed" on two lines under the first bar */
.np-axis span.first{line-height:1.2}
.np-axis span.last{left:auto!important;right:0;transform:none}
.np-legend span{display:flex;align-items:center;gap:6px}
.np-legend i{width:14px;height:14px;display:inline-block}
.np-empty{margin:16px 0 0;font-size:15px}

/* 7-day */
.np-week{min-width:0}
.np-days{margin-top:14px;display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:10px}
.np-day{position:relative;border:1px solid var(--rule);text-align:center;background:#fff;display:flex;flex-direction:column}   /* relative: holds its .sr-only High/Low inside the scrolling row */
/* seven-day highlights: a 2px frame (inset, so the box keeps its size) and a small tag in the category color */
.np-day{--hl:transparent;box-shadow:inset 0 0 0 1px var(--hl);border-color:var(--rule)}
.np-day[class*="hl-"]{border-color:var(--hl)}
.np-hltag{order:-1;padding:4px 6px 3px;font-size:12px;font-weight:800;line-height:1.2;text-align:left;color:var(--hl);min-height:1.2em}
.np-day.hl-severe{--hl:#c62828}
.np-day.hl-snow{--hl:var(--slate);background:var(--slate-bg)}
.np-day.hl-hot{--hl:#e65100}
.np-day.hl-cold{--hl:var(--cold)}
.np-day.hl-wet{--hl:#2e7d32}
.np-day.hl-nice{--hl:var(--nice);background:var(--nice-bg)}
.np-ddate{padding:3px 4px 0;font-size:12px;font-weight:700;line-height:1.2;color:var(--ink2);text-align:center}   /* Round P7 (Home 25): "Sat. Oct. 17", on the card's white under the band strip */
.np-best{display:inline-block;margin-left:4px;padding:1px 6px;background:var(--nice);color:#fff;font-weight:800}   /* Round P7 (Home 26): white on the nicest-day gold, 5.1:1 */
.np-hltag .np-best:first-child{margin-left:0}
.np-day h3{margin:0;padding:6px 0;font-weight:900;font-size:17px}
.np-day h3.np-hot{font-size:19px;line-height:23.8px}   /* white on the 90s band is 4.0:1, AA only for bold 19px and up (Round M-fu2); 17px's line height, so the card keeps its height */
.np-day svg{width:70px;height:70px;margin:10px auto 0;display:block}
.np-day .hi{font-weight:900;font-size:32px;margin-top:4px}
.np-day .lo{font-weight:700;font-size:18px;color:var(--blue)}
.np-day .hi.night{color:var(--blue)}   /* a tonight-only first card: the low in the big slot (Round E4) */
.np-day .lo.night{font-size:14px;line-height:1.25}
.np-day .lo.night small{display:block;font-size:12px;font-weight:600;color:var(--ink3)}
.np-day .tx{font-size:13px;margin:6px 6px 12px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;overflow:hidden}   /* full NWS wording, at most three lines */
.np-day .pop{font-size:12px;font-weight:700;color:var(--blue);padding-bottom:10px;margin-top:-6px}

/* row 4 */
.np-row4{display:grid;grid-template-columns:minmax(0,1fr);gap:32px}
/* storms + rivers: two equal columns; one column when the rivers box is hidden */
.np-row5{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 32px}
.np-row5.one{grid-template-columns:minmax(0,1fr)}
.np-row5>div{display:flex;flex-direction:column}
/* the storm log sits in a card that fills the row's height; an empty year centers its note */
.np-row5 #storms{flex:1;margin-top:10px;padding:4px 12px 10px;border:1px solid var(--rule);background:#fff}
.np-row5 #storms:has(>p:only-child){display:flex;align-items:center;justify-content:center;text-align:center}
.np-row5 #storms>p:only-child{margin:0;max-width:30em}
.np-river{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:baseline;gap:2px 12px;margin-top:10px;padding:10px 12px;border:1px solid var(--rule);background:#fff}
.np-river .nm{font-size:15px}
.np-river .nm b{font-weight:800}
.np-river .wh{grid-column:1;font-size:13px;color:var(--ink3)}
.np-river .st{grid-row:1/3;grid-column:2;align-self:center;font-weight:900;font-size:26px;font-variant-numeric:tabular-nums;white-space:nowrap}
.np-river .st small{font-size:15px;font-weight:700}
.np-river .tr{margin-left:4px;font-size:22px}
.np-river .fl{grid-column:1/-1;font-size:13px;color:var(--ink2)}
/* Round P15 (Home 28): the river's plain status (rivers.py: USGS's flow class for the part of the month, or the NWS's
   stage) and its flow on a small bar against the day's percentiles: the shaded part is normal (25th to 75th), the tick
   the median, the mark the flow (rivers.py flow_pos) */
.np-river .fs{grid-column:1/-1;font-size:15px;font-weight:800}
.rv-bar{grid-column:1/-1;position:relative;height:8px;margin:4px 0 2px;border:1px solid var(--ink);background:linear-gradient(90deg,#fff 25%,var(--wk) 25% 75%,#fff 75%)}
.rv-bar::after{content:"";position:absolute;left:50%;top:-1px;bottom:-1px;border-left:1px solid var(--ink3)}
.rv-bar i{position:absolute;top:-5px;width:4px;height:16px;margin-left:-2px;background:var(--ink);border:1px solid #fff}
.np-river.lvl-action{background:#fff3cd;border-color:#b7791f}
.np-river.lvl-flood{background:#fde2e1;border-color:var(--red)}
.np-river.out{display:block;padding:8px 12px;font-size:14px;color:var(--ink3)}   /* configured gauge with no valid reading */
.np-river.out b{font-weight:700}
/* air quality row in the Faribault Today card (AQI 51+): the EPA category color is the left border, set by np.js */
.np-air{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 10px;padding:8px 9px;border-left:6px solid var(--rule);border-bottom:1px solid var(--rule);min-height:62px}   /* Round P4 (Home 16): the AQI as the tiles' last row, full width, the EPA color on its edge */
.np-air[hidden]{display:none}
.np-air .lb{font-size:12px;color:var(--ink3);flex:0 0 100%}
.np-air b{font-size:17px;font-weight:800}
.np-air .sub{font-size:13px;font-weight:700;color:var(--ink2)}
/* ---------- Round M8: this year against an average year, storm days (server/app/stormyear.py; moved from restyle.css with Round P15, home's storm box). Flat; the size is
   reserved by the svg's width and height, and it is never drawn wider than that. This year's line is --bar-red (3.9:1
   on paper, enough for a line); its label is --red-text. ---------- */
.sy{margin:16px 0}
.sy-title{margin:0 0 6px;font-size:17px;font-weight:800;line-height:1.3}
.sy-svg{display:block;width:100%;height:auto;overflow:visible}
.sy-full .sy-svg{max-width:460px}
.sy-compact .sy-svg{max-width:340px}
.sy-grid{stroke:var(--rule);stroke-width:1}
.sy-band{fill:var(--wk)}
.sy-avg{fill:none;stroke:var(--ink3);stroke-width:2}
.sy-this{fill:none;stroke:var(--bar-red);stroke-width:3;stroke-linejoin:round}
.sy-today{stroke:var(--ink);stroke-width:1;stroke-dasharray:3 3}
.sy-ax{fill:var(--ink3);font-size:12px}
.sy-lab{fill:var(--ink2);font-size:12px;font-weight:700}
.sy-lab-this{fill:var(--red-text)}
.sy-lab-band{fill:var(--ink3);font-weight:400}
.sy-full .sy-ax,.sy-full .sy-lab{font-size:16px}
.sy-years{margin:4px 0 0}
.np-agate{margin-top:10px;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0 22px}
.np-agate table{width:100%;border-collapse:collapse;font-size:13px;font-variant-numeric:tabular-nums}
.np-agate th{text-align:left;font-size:12px;font-weight:800;padding:4px 2px;border-bottom:1px solid var(--ink)}
.np-agate th.n,.np-agate td.n{text-align:right;width:26px}
.np-agate th.w,.np-agate td.w{text-align:left;padding-left:6px}
.np-agate td.w{font-size:12px;line-height:1.2}   /* Round P14: the weather in words, with its icon */
.np-agate .cw-i svg{width:16px;height:16px;vertical-align:-3px;margin-right:3px}
.np-agate th.gap,.np-agate td.gap{width:8px;padding:0}
.np-agate td{padding:3px 2px;border-bottom:1px dotted var(--rule)}
@media (max-width:374px){.np-agate td.w{overflow-wrap:anywhere;hyphens:auto}}   /* N-fu77: a one-word weather ("Thunderstorms") breaks inside the word, never cut; two columns of it ran 53 px past the edge at 320 */
.np-agate tr.me td{background:var(--cream);font-weight:800}
.np-keyline{margin:10px 0 0;color:var(--ink2);font-size:12px}
.np-storm{display:flex;flex-wrap:wrap;gap:4px 12px;padding:10px 0;border-bottom:1px dotted var(--rule);color:var(--ink);font-size:14px;line-height:1.4}
.np-storm:last-child{border-bottom:0}
.np-storm i{width:14px;height:14px;margin-top:3px;flex-shrink:0}
.np-storms p{font-size:14px;margin:10px 0 0}
.np-storms .np-storm-k{margin:8px 0 0;font-size:12px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--ink3)}
.np-storm .sd-tag{flex:0 1 auto;align-self:flex-start;margin-top:1px}
.np-storm>span:last-child{flex:1 1 12em}   /* N-fu76: the headline wraps under a long tag, the tag's own words at 320 (Oct. 28's "Severe thunderstorm warning" ran 18 px past the edge at 390, 88 at 320) */
.np-storms .np-storm-n{margin:6px 0 0;line-height:1.45}
.np-storms .np-storm-all{margin:10px 0 0;font-weight:700}
.np-storms .np-storm-out{color:var(--ink3)}

.np-foot{margin-top:40px;border-top:2px solid var(--ink);padding:14px 0 22px;display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:6px 20px;font-size:12px;color:var(--ink2)}
.np-sources h2{margin:0 0 6px;font-size:15px;font-weight:900;color:var(--ink)}
.np-footnote:empty{display:none}
/* footer link to the sources page */
/* Round P16 (Home 29): every page's footer is one template (ssr.site_footer, api/ssr/footer.html): the site map in four
   groups, then the credit; a page's own credits line (.np-pcredit, models.html's .mp-credit, the archive's .ar-credit)
   comes first */
.np-sitemap{flex-basis:100%;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px 24px;margin:6px 0 4px}
.np-smh{margin:0 0 6px;font-size:13px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--ink)}
.np-smgrp ul{list-style:none;margin:0;padding:0}
.np-smgrp li{margin:0;font-size:14px;line-height:1.35}
.np-smgrp a{display:inline-block;padding:3px 0;color:var(--ink);text-decoration:underline;text-underline-offset:3px}   /* a 24 px target (WCAG 2.2 target size; Lighthouse, Round Q14) */
.np-pcredit{flex-basis:100%;margin:4px 0 0}
.np-srcpage .np-footnote{margin-top:22px;font-size:14px}
.np-footnote{flex-basis:100%;margin:4px 0 0;font-size:12px;color:var(--ink3)}
.np-footnote:target{background:var(--cream)}
/* site credit: the footer's last line */
.fw-credit{flex-basis:100%;margin:4px 0 0;font-size:12px;color:var(--ink3)}
.fw-credit a{color:var(--blue);text-decoration:underline;text-underline-offset:2px;cursor:pointer}
.fw-credit a:hover{color:var(--navy);text-decoration-thickness:2px}
.np-foot-logo{font-weight:900;font-size:20px;color:var(--ink)}

/* tablet */
@media (max-width:1060px){
  .np-plot-svg{flex:none;height:190px}   /* box sits below the map here: nothing to match */
  .np-home{grid-template-columns:minmax(0,1fr)}   /* home grid, one column, in source order (ssr.HOME_ORDER; Round P1) */
  .np-home{grid-template-rows:none}
  .np-home>*{grid-column:1 / -1;grid-row:auto}
  .np-row4{grid-template-columns:1fr}
  .np-agate,.np-row4 .np-agate{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:800px){
  .np-looks{grid-template-columns:1fr;row-gap:18px}
  .np-row5{grid-template-columns:1fr}
}
@media (max-width:720px){
  .np-age,.np-radar-time{top:6px;padding:2px 6px;font-size:12px}
  .np-radar-time{left:6px}
  .np-radar{aspect-ratio:4/3}   /* home radar on phones: the full 4:3 scan, so the corner tags clear Minneapolis and St. Paul */
  .np-rkey{font-size:12px}
  .np-rkey i{width:11px;height:10px}
  .np-rkey .w{margin:0 4px}
  .np-radar .np-ov{padding:6px}
}
/* phone */
@media (max-width:720px){
  :root{--gutter:16px}
  .np-mast{flex-direction:column;align-items:flex-start;gap:8px;padding:16px 0 12px}
  .np-logo{font-size:44px}
  .np-tag{font-size:15px}
  .np-dateline{text-align:left}
  .np-section{font-size:18px;padding:4px 14px 0}
  .np-nav a{padding:4px 12px 0;font-size:15px}
  .np-now{display:none}
  .np-key .lg{margin-left:12px}
  .np-days{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:128px;overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:6px}
  .np-day{scroll-snap-align:start}
  .np-hltag{min-height:2.5em}   /* room for a two-line tag, so day names stay in line */
  .np-bars{flex:0 0 220px;height:220px;gap:2px}
  .np-agate,.np-row4 .np-agate{grid-template-columns:1fr}
  .np-mlabels small{display:none}
  .np-foot{flex-direction:column;gap:6px}
  .np-sitemap{grid-template-columns:repeat(2,minmax(0,1fr));width:100%}
}
/* phones, under 700 px: the page runs in source order (ssr.HOME_ORDER, Round P1), so what you see, the tab order and the
   screen-reader order are the same. */
@media (max-width:699px){
  .np-day .tx{-webkit-line-clamp:4;line-clamp:4;margin-left:2px;margin-right:2px}   /* phones: four lines and 4 px more width, for long winter wording (weather.py _short) */
  main,.np-home{display:flex;flex-direction:column}
  .np-side{margin-top:26px}
}

/* ---------- radar page (radar.html, assets/np/radar.js) ---------- */
.np-radarpage{padding:20px 0 30px}
.np-seg{display:inline-flex;border:2px solid var(--ink);background:#fff}
.np-seg button{font:800 14px 'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;padding:8px 14px;background:#fff;color:var(--ink);border:0;cursor:pointer;min-height:40px}
.np-seg button+button{border-left:2px solid var(--ink)}
.np-seg button[aria-pressed="true"]{background:var(--ink);color:#fff}
/* radar.html local view: the full 4:3 KMPX scan (a 16:9 box cut about 17 miles off the top and bottom); the regional
   mosaic stays 16:9, the shape of its frames. The map's height is capped so the map, the play bar and the color key
   all fit in the window; radar.js (fit) sets --rp-h from where the map really starts and how tall the controls are,
   never under 280 px. The value below is the fallback before the script runs. The bar, the warning outlines' key and
   the note line up under the map at its width (the color key is inside the map since N-fu17). On phones the width limits the map first, so the cap never bites. */
.np-radarpage{--rp-h:max(280px, calc(100dvh - 376px));container-type:inline-size}   /* 376: what fit() works out with no banner and the subtitle and rain line on one row (header to map 276 with Round U1's page tab, the bar with its times and gaps 100; 316 before Round U, 335 until N-fu17 moved the 19 px key row into the map), so the first paint is already the right size; ssr.alert_hold adds its room to the same 376. Under 1100 px a long rain line takes a second row: then fit() trims 20 px after the first paint; from 1100 px it always has its own row (U-fu1.1: 394 there) */
.rp-box{width:100%;aspect-ratio:4/3;max-width:calc(var(--rp-h) * 4 / 3);margin-inline:auto}
/* The regional view keeps the local box's height, min(75% of the page width, --rp-h), so switching views moves nothing
   below the map (Oct. 7, 2026). On a wide screen it is wider (16:9 at that height); where the width runs out (phones)
   it stays 4:3 and the 16:9 map sits in the middle, land color above and below. The loading message, the loop and the
   dead-feed NWS loop all fill this same box. */
/* Safari before 16 has no container units: there the regional box is plain 16:9 (its height then changes with the view
   on phones, as before H-fu5) instead of collapsing (H-fu8). */
.rp-box.rg{aspect-ratio:16/9;max-width:calc(var(--rp-h) * 16 / 9)}
@supports (height:1cqw){ .rp-box.rg{aspect-ratio:auto;height:min(75cqw, var(--rp-h))} }
.np-radarpage .rp-bar,.np-radarpage .rp-legends,.np-radarpage .rp-note{max-width:max(820px, calc(var(--rp-h) * 4 / 3));margin-inline:auto}   /* 820 px or more: the bar stays one row (with Slow / Normal / Fast, Round D6) */
.np-radarpage:has(.rp-box.rg) .rp-bar,.np-radarpage:has(.rp-box.rg) .rp-legends,.np-radarpage:has(.rp-box.rg) .rp-note{max-width:max(820px, calc(var(--rp-h) * 16 / 9))}
.rp-box.rg .rp-stage{aspect-ratio:16/9}   /* centered in the box (.np-radar-stage) */
.rp-warn{pointer-events:none}
.rp-warn path{stroke-linejoin:round;stroke-linecap:round}
.rp-warn .rp-case{fill:none;stroke:var(--ink);stroke-opacity:.6}
.rp-warn text{font-family:'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;font-weight:900;fill:var(--ink);text-anchor:middle;paint-order:stroke;stroke:#fff;stroke-width:5px;stroke-linejoin:round}
.rp-warn text{font-size:max(20px,calc(12.5px*var(--k,1)))}
.rp-box.rg .rp-warn text{font-size:max(17px,calc(12.5px*var(--k,1)))}
@media (max-width:720px){ .rp-warn text{font-size:max(30px,calc(12.5px*var(--k,1)))} .rp-box.rg .rp-warn text{font-size:max(40px,calc(12.5px*var(--k,1)))} }
.rp-msg{position:absolute;left:0;right:0;top:45%;margin:0;padding:0 16px;text-align:center;font-weight:700}
.rp-rain{margin:0;font-size:15px;font-weight:800;color:var(--ink)}   /* "is rain coming?" (radar.js rainLine) */
.rp-subrow .rp-sub{margin-top:0;margin-bottom:0}
.rp-subrow .rp-rain[hidden]{display:block!important;visibility:hidden}   /* radar.js keeps the old words in a hidden line, so its room doesn't change */
.rp-box.feed-down .rp-stage{visibility:hidden}
.rp-bar{position:relative}
.rp-bar>.rp-msg{inset:0;display:flex;align-items:center;justify-content:center;padding:0 8px;visibility:visible}
.rp-bar{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;margin-top:10px}
/* a hidden play bar (loading, one scan, dead feed) keeps its room, invisible, so the key and note below never move */
.np-radarpage #rp-bar[hidden]{display:flex!important;visibility:hidden}
.rp-btn{font:800 14px 'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;padding:8px 14px;min-height:40px;border:2px solid var(--ink);background:#fff;color:var(--ink);cursor:pointer}
.rp-play{width:44px;padding:0;display:grid;place-items:center}
.rp-play svg{width:18px;height:18px;fill:currentColor}
.rp-play .i-play,.rp-play.paused .i-pause{display:none}
.rp-play.paused .i-play{display:inline}
.rp-step{width:44px;padding:0;display:grid;place-items:center}
.rp-step svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
.rp-step:disabled{opacity:.35;cursor:default}
.rp-scrub{flex:1 1 120px;min-width:100px;height:44px;margin:0;accent-color:var(--blue)}
.rp-stage{cursor:pointer}   /* a tap on the map plays or pauses (radar.js); the play button stays the accessible control */
.rp-stage:focus-visible{outline:3px solid var(--blue);outline-offset:2px}   /* focusable for the arrow and space keys (Round D4) */
.rp-legends{margin-top:14px;display:grid;gap:8px}
.rp-legend{display:flex;flex-wrap:wrap;align-items:center;gap:6px 16px;font-size:14px;font-weight:600}
.rp-legend span{display:inline-flex;align-items:center;gap:4px}
.rp-legend i{display:inline-block;width:18px;height:12px;border:1px solid var(--rule)}
/* radar.html's color key sits inside the map's bottom-left corner (N-fu17, Travis, Oct. 16, 2026: under an alert row
   the key under the play bar went below the window at 390x844 and 1366x650, when readers need it most, and the map
   doesn't shrink for it): a white box like the home radar's key, two rows of two, so it leaves the bottom-right corner
   to the Updated tag; the time tag moves to the top-left corner (below). storm.html's key stays under its play bar. */
.rp-box > .rp-legend{position:absolute;left:8px;bottom:8px;z-index:2;display:grid;grid-template-columns:auto auto;gap:3px 10px;padding:3px 6px;background:#fff;border:1px solid var(--ink);font-size:12px;font-weight:700;pointer-events:none}
.rp-box > .rp-legend span{gap:3px}
.rp-box > .rp-legend i{width:10px;height:10px}
.rp-lgname{font-weight:900}
/* local labels at full page width: the home page's sizes would be oversized here (same as #warn-radar) */
.rp-box .rl-towns text{font-size:max(15px,calc(12.5px*var(--k,1)))}
.rp-box .rl-fbl text{font-size:max(18px,calc(12.5px*var(--k,1)))}
.rp-box .rl-rings text,.rp-box .rl-states text{font-size:max(12px,calc(12.5px*var(--k,1)))}
.rp-box .rl-shields g{transform-box:fill-box}
.rp-box .rl-towns circle{r:3.5px}
.rp-box .rp-cut{visibility:hidden}   /* U-fu1.1: a label the map's cut edge would split (radar.js edgeCut) */
@media (max-width:800px){ .rp-box .rl-towns text{font-size:max(25px,calc(12.5px*var(--k,1)))} .rp-box .rl-fbl text{font-size:max(29px,calc(12.5px*var(--k,1)))} .rp-box .rl-rings text,.rp-box .rl-states text{font-size:max(19px,calc(12.5px*var(--k,1)))} .rp-box .rl-towns circle{r:5px} }
/* regional labels on the 1280-wide map; bigger and fewer on phones */
.rg text{font-size:max(21px,calc(12.5px*var(--k,1)));font-weight:700;fill:var(--ink)}
.rg circle{fill:var(--ink);stroke:#fff;stroke-width:2px}
.rg-states text{font-size:max(19px,calc(12.5px*var(--k,1)));font-weight:800;letter-spacing:.08em;fill:#6f695e;stroke-width:5px}
.rg .rl-fbl text{font-size:max(24px,calc(12.5px*var(--k,1)));font-weight:900}
@media (max-width:720px){
  .rg text{font-size:max(38px,calc(12.5px*var(--k,1)))} .rg-states text{font-size:max(32px,calc(12.5px*var(--k,1)))} .rg .rl-fbl text{font-size:max(42px,calc(12.5px*var(--k,1)))}
  .rg .minor{display:none} .rg circle{r:8px}
}
/* phones: 44 px touch targets; the play bar is two rows (play, earlier, slider, later / speed, latest) and the time is on the map, not repeated */
@media (max-width:720px){
  .np-radarpage .rp-btn,.np-radarpage .np-seg button{min-height:44px}
  .rp-bar{gap:8px}
  .rp-scrub{flex:1 1 0;min-width:100px}
}
.np-radarpage > .np-pagetab{margin-top:0}   /* main's own 20 px is above it */
.rp-track{position:relative;flex:1 1 200px;min-width:160px;padding-bottom:20px}
.rp-tick{position:absolute;top:0;font-size:13px;font-weight:700;line-height:18px;color:var(--ink2);white-space:nowrap}
.rp-gap{position:absolute;top:-27px;height:10px;background:repeating-linear-gradient(135deg,var(--ink) 0 2px,#fff 2px 5px);border:1px solid var(--ink)}
.rp-gapnote{display:block;font-size:12px;font-weight:700}
/* the county view's base map (radar-county.svg, put into the page inline by radar.js): the local base map's colors */
.rp-cbase path,.rp-cbase g{fill:none}
.rp-cbase .rm-land{fill:var(--rmap-land)} .rp-cbase .rm-urban{fill:var(--rmap-urban)} .rp-cbase .rm-county{stroke:var(--rmap-county)}
.rp-cbase .rm-stream{stroke:var(--rmap-stream)} .rp-cbase .rm-water{stroke:var(--rmap-water)} .rp-cbase .rm-road{stroke:var(--rmap-road)}
.rp-cbase .rm-state{stroke:var(--rmap-state)} .rp-cbase .rm-ring{stroke:var(--ink);stroke-opacity:.3}
@media (min-width:1100px){
  .np-radarpage{--rp-h:max(280px, calc(100dvh - 394px))}
}
/* U-fu1.1 (Travis, Oct. 24, 2026): from 1100 px the map and its play bar fill the width left of the 300 px column. The
   map is 4:3 at that width, capped by the window (--rp-h, fit()) so the bar and the key stay in the first screen; when
   the cap bites, the map keeps the width and its top and bottom are cut evenly, as home's 16:9 radar is (the stage is
   centered in the box, .np-radar-stage). Every view is the same height (H-fu5): the regional map is 16:9 across the
   width, cut the same way, or with the box's color above and below where the box is taller. Full screen keeps the whole
   map (the rules below leave it alone). Browsers without container units or :fullscreen keep the capped 4:3 box. */
@supports (height:1cqw) and selector(:fullscreen){
}
.rp-vbtn{flex:1 1 0;min-width:0;max-width:150px;display:flex;flex-direction:column;align-items:stretch;gap:4px;padding:4px;border:2px solid var(--ink);background:#fff;color:var(--ink);font:800 14px 'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;line-height:1.15;text-align:center;cursor:pointer}
.np-radarpage .rp-fs[hidden]{display:inline-flex!important;visibility:hidden}   /* keeps its room where the browser has no full screen */
/* ---------- Round U3: radar.html's keys and palettes (Radar 3, 27) ----------
   A swatch is i.rl.rlN, its color the palette's step N; the page takes .pal-cb for the color-blind-safe palette, and both
   keys and the view pictures follow it. The corner key is home's: Light, the six steps, Heavy (np.js radar key). */
.rl{display:inline-block;width:14px;height:12px;border:1px solid var(--rule);flex:none}
          .rp-ramp .rl{width:12px;height:10px;border-color:var(--ink3)}
.rp-kh{margin:0 0 6px;font-size:16px;font-weight:900}
.rp-klist li{display:grid;grid-template-columns:18px auto;gap:0 8px;align-items:start;font-size:14px;line-height:1.3}
.rp-klist .rl{width:18px;height:14px;margin-top:2px;grid-row:span 2}
/* U-fu1.2 (Radar 13): the 24-hour rain layer (mrms.py), its picture over the base map as the scans are, in their place
   while it's on (radar.js drawR24: the frames and the bar put away, the bar's room kept, its line in their place) */
.rr{display:inline-block;width:14px;height:12px;border:1px solid var(--rule);flex:none}
     .rp-ramp .rr{width:12px;height:10px;border-color:var(--ink3)}
.rp-klist .rr{width:18px;height:14px;margin-top:2px}
.rp-stage.r24on .np-radar-frames{visibility:hidden}
.rp-bar.r24on>:not(.rp-msg){visibility:hidden}
.rp-klist b{font-weight:800}
.rp-wlist{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.rp-wlist li{display:grid;grid-template-columns:34px 1fr;gap:0 8px;align-items:start;font-size:14px;line-height:1.35;padding:6px 8px;background:#fff;border:1px solid var(--ink);border-left-width:6px}
.rp-wlist li.tor{border-left-color:var(--red)} .rp-wlist li.svr{border-left-color:var(--t70)} .rp-wlist li.ffw{border-left-color:var(--t50)}
.rp-wlist svg{margin-top:3px}
.rp-wleft{color:var(--ink2)}
.rp-tog input{width:22px;height:22px;margin:0;accent-color:var(--ink)}
.rp-replist li{display:grid;grid-template-columns:18px 1fr;gap:0 8px;align-items:start}
#rp-reports .rp-rep.later{display:none}
/* ---------- Round U5: the illustration kit's shared parts (moved from winter.css: /how-it-works/'s radar drawing uses them
   too, M10) and the radar beam's cutaway (illo.beam_html) ---------- */
.il-s-skytop{stop-color:var(--sky-top)} .il-s-skylow{stop-color:var(--sky-low)} .il-s-white{stop-color:#fff}
.il-cloud{fill:#fff}
.il-cloud-shade{fill:none;stroke:var(--cloud-shadow);stroke-width:3;stroke-linecap:round}
.il-land{fill:var(--land)} .il-cut{stroke:var(--ink2);stroke-width:1.2}
.il-badge{fill:var(--ink)} .il-badge-n{fill:#fff;font-family:inherit;font-size:13px;font-weight:800;text-anchor:middle}
/* home page: the radar box opens radar.html (its controls sit above this link) */
.np-radar-open{position:absolute;inset:0;z-index:1}

/* ---------- models page (models.html, assets/np/models.js) ---------- */
.sr-only{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.mp-title{margin:0;font-size:40px;font-weight:900;line-height:1.1}
.mp-intro{margin:6px 0 0;max-width:760px;font-size:17px}
.mp-sec{margin-top:34px}
.mp-tabs a{display:flex;align-items:center;min-height:48px;padding:0 16px;margin-bottom:-2px;border-bottom:5px solid transparent;font-size:16px;font-weight:800;color:var(--ink);white-space:nowrap}
.mp-tabs a:hover{text-decoration:none;background:var(--slate-bg)}
.mp-tabs a[aria-selected="true"]{border-bottom-color:var(--red)}
html[data-mptab] .mp-panel{display:none}
html[data-mptab="card"] #p-card,html[data-mptab="forecast"] #p-forecast,html[data-mptab="ensembles"] #p-ensembles,
html[data-mptab="upperair"] #p-upperair,html[data-mptab="outlooks"] #p-outlooks,html[data-mptab="guide"] #p-guide{display:block}
@media (max-width:560px){ .mp-tabs a{flex:1 1 auto;justify-content:center;padding:0 8px;font-size:14px;min-height:44px} }
.mp-foot{margin:8px 0 0}
.mp-pill.gold{background:var(--t70);border-color:var(--ink)}
.rc-table th,.rc-table td{padding:8px 10px;border-bottom:1px solid var(--rule);text-align:center;white-space:nowrap}
.rc-table thead th{font-size:12.5px;font-weight:800;text-transform:uppercase;letter-spacing:.03em;background:var(--slate-bg);white-space:normal}
.rc-table tbody th,.rc-table thead th:first-child{position:sticky;left:0;z-index:1;text-align:left;background:#fff;font-weight:800;box-shadow:inset -1px 0 0 var(--rule)}   /* inset: a collapsed table doesn't draw a cell's outer shadow (O-fu14) */
.rc-table td.na{color:var(--ink3)}
.rc-table td.snap{color:var(--ink2);background:var(--slate-bg)}   /* under 7 scored days: gray, no green-to-red */
@media (max-width:720px){
  /* the frozen model column: name on one line, source and pills on a second, at most 130 px, so the numbers show */
  .rc-table tbody th{white-space:normal;max-width:130px;min-width:0;line-height:1.25}
  .rc-table tbody th .mp-pill{margin:3px 0 0;display:inline-block}
}
/* Round S1 and S2: the worker's lines above and under the report card (server/app/modelspage.py) */
.rc-top{margin:2px 0 10px;max-width:900px}
.rc-verdict{margin:0 0 6px;font-size:19px;font-weight:800;line-height:1.3}
.rc-lean{margin:0 0 6px;font-size:16px;line-height:1.4}
.rc-top .np-small,.rc-notes .np-small{margin:0 0 4px}
.rc-seg button{min-height:44px;font-size:15px}
.hm-table th,.hm-table td{border:1px solid #fff;padding:0;text-align:center}
.hm-table thead th{padding:8px 4px;font-size:12.5px;font-weight:800;text-transform:uppercase;letter-spacing:.03em;background:var(--slate-bg)}
.hm-table thead th:first-child{text-align:left;padding-left:10px}
.hm-table tbody th{padding:6px 8px 6px 10px;text-align:left;background:#fff;border-bottom:1px solid var(--rule)}
.hm-c b{display:block;font-size:16px;font-weight:800}

/* Round S1 (Models 13): a row that stops before day 7 ends in one gray block; why is said once under the table */
.hm-apart th[scope="rowgroup"]{padding:6px 10px;text-align:left;font-size:12.5px;font-weight:800;text-transform:uppercase;letter-spacing:.03em;color:var(--ink2);background:#fff;border-top:2px solid var(--ink)}
.hm-legend span{display:inline-flex;align-items:center;gap:5px}
.rc-panel h3{margin:0 0 2px;font-size:17px;font-weight:900}
.rc-panel p{margin:0 0 8px;font-size:13px;color:var(--ink2)}
.pn-row b{font-weight:800}
.pn-key span{display:inline-flex;align-items:center;gap:5px}
 .rc-how{margin-top:16px;max-width:900px;font-size:14px}
.rc-how p{margin:0 0 8px}
/* phones: the days 1-2 column and all seven days at about 33 px, the numbers and any differing n, model column about
   82 px; the subtitles drop (Round S1: days 1-2 shows here too, first) */
@media (max-width:560px){
  .hm-table thead th{padding:6px 1px;font-size:12px;letter-spacing:0}
  .hm-c b{font-size:12.5px}
  .rc-seg button{padding:8px 11px;font-size:14px}
}
/* temperature chart */
.tc-chart{position:relative;border:1px solid var(--rule);background:#fff;padding:8px 6px 6px}
.gb-table{width:100%;border-collapse:collapse;font-size:14px;font-variant-numeric:tabular-nums}
.gb-table th,.gb-table td{padding:6px 4px;border-bottom:1px solid var(--rule);text-align:right}
.gb-table thead th{font-weight:900;vertical-align:bottom;border-bottom:2px solid var(--ink)}
.gb-table thead th small{display:block;font-size:12px;font-weight:800;color:var(--cold)}
.gb-table tbody th{text-align:left;font-weight:800;white-space:nowrap}
.gb-table td.gb-none{color:var(--ink3)}
.mx-x{font-size:13px}
.mv-x{text-anchor:middle;font-size:12px}
.tc-svg{display:block;width:100%;height:auto;font-family:'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;touch-action:pan-y}
.tc-grid{stroke:var(--rule);stroke-width:1;opacity:.6}
.tc-day{stroke:var(--ink3);stroke-width:1;stroke-dasharray:2 4;opacity:.5}
.tc-y{font-size:13px;fill:var(--ink3);text-anchor:end;font-weight:600}
.tc-x{font-size:13px;fill:var(--ink);font-weight:800}
.tc-line{fill:none;stroke-width:2.6;stroke-linejoin:round;stroke-linecap:round}
.tc-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin:6px 4px 0;font-size:13px;font-weight:700}
.tc-legend span{display:inline-flex;align-items:center;gap:5px}
  /* question cards (models.js questionCards()): above the Range / Every run toggle; the rating word carries the meaning,
   the top border color repeats it (navy sure, orange fairly sure, red not sure) */
.qc-cards{list-style:none;margin:12px 0 0;padding:0;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}
.qc-card{display:grid;gap:4px;align-content:start;padding:10px 12px 12px;background:#fff;border:1px solid var(--rule);border-top:5px solid var(--navy)}
.qc-card.fair{border-top-color:#e07b12} .qc-card.not{border-top-color:var(--red)}
.qc-q{font-size:13px;font-weight:900;letter-spacing:.06em;text-transform:uppercase;color:var(--ink2)}
.qc-range{font-size:28px;font-weight:900;line-height:1.05}
.qc-rate{font-size:15px;font-weight:900}
.qc-card.not .qc-rate{color:var(--red)}
.qc-per{font-size:13px;color:var(--ink3)}
@media (max-width:899px){ .qc-cards{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media (max-width:380px){ .qc-cards{grid-template-columns:minmax(0,1fr)} }
/* Every run (models.js plume()): members thin and faint, each ensemble's average thick; callouts under the chart */
.hs-mem{fill:none;stroke-width:1;opacity:.28;stroke-linejoin:round}
.hs-mean{fill:none;stroke-width:3.5;stroke-linejoin:round;stroke-linecap:round}
.hs-says span{color:var(--ink3);font-size:13px}
/* grouped bars: one block per day, a labeled bar per model */
.gb{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:12px}
.gb-day h3{margin:0 0 6px;font-size:15px;font-weight:900}
.mg-table th,.mg-table td{padding:8px 10px;border-bottom:1px solid var(--rule);text-align:left;vertical-align:top}
.mg-table thead th{font-size:12.5px;font-weight:800;text-transform:uppercase;letter-spacing:.03em;background:var(--slate-bg)}
.mg-ens th[scope=rowgroup]{background:var(--slate-bg);font-size:13px;font-weight:900;text-transform:uppercase;letter-spacing:.03em}
.mp-subh{margin:22px 0 6px;font-size:18px;font-weight:900}
.yd-table thead th:first-child{text-align:left}
.yd-apart th[scope="rowgroup"]{padding:10px 4px 6px;text-align:left;font-size:12.5px;font-weight:800;text-transform:uppercase;letter-spacing:.03em;color:var(--ink2);border-bottom:2px solid var(--ink)}
@media (max-width:720px){
  .mp-title{font-size:30px}
  /* the spec table stacks: one block per model, each value labeled */
  .mg-table,.mg-table tbody,.mg-table tr,.mg-table th,.mg-table td{display:block}
  .mg-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
  .mg-table tr{padding:8px 10px;border-bottom:1px solid var(--rule)}
  .mg-table th,.mg-table td{padding:2px 0;border:0}
  .mg-table td .mg-bar,.mg-table td .mg-range,.mg-table td .mg-runs{grid-column:2}
}

/* ---------- storm log (storms.html, storm.html; assets/np/storms.js) ---------- */
.sl{padding:22px 0 30px}
.sl-head{border-bottom:3px solid var(--ink);padding-bottom:10px}
.sl-h1{font-size:44px;font-weight:900;line-height:1.02;margin:0;letter-spacing:-.01em}
.sl-stat{padding:10px 12px;border-right:1px solid var(--rule);display:grid;align-content:start;gap:2px}   /* a storm day's airport panel */
.sl-stat:last-child{border-right:0}
.sl-stat b{font-size:30px;font-weight:900;line-height:1}
.sl-stat span{font-size:13.5px;color:var(--ink2);font-weight:600}
.sl-statgrp b{font-weight:900}
.gl-line{margin:3px 0;max-width:86ch}
.sl-areasvg{display:block;width:180px;height:180px;border:1px solid var(--rule)}
.sl-key{list-style:none;margin:8px 0 0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,215px),1fr));gap:4px 14px;font-size:13.5px;font-weight:700}
.sl-key li{display:flex;align-items:center;gap:7px}
.sl-key svg{flex:none}
.sl-top .np-stamp{margin:12px 0 0}
.sl-top .np-hiw{margin:4px 0 0}
.sl-otd ol{list-style:none;margin:0;padding:0;display:grid;gap:5px;font-size:15px;line-height:1.35}
.sl-otd a{font-weight:800}
.sl-jump{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;margin:14px 0 0}
.sl-jump label{font-size:15px;font-weight:800}
.sl-jump input{min-height:44px;padding:0 8px;font:inherit;font-size:16px;color:var(--ink);background:#fff;border:2px solid var(--ink)}
.sl-jump .np-small{flex-basis:100%;margin:0}
.sl-hit{outline:3px solid var(--ink);outline-offset:3px}
.sl-heattable th,.sl-heattable td{padding:3px 0;text-align:center;border:1px solid #fff}
.sl-heattable thead th{font-weight:800;color:var(--ink2)}
.sl-heattable thead th:first-child,.sl-heattable tbody th{width:3.4em;text-align:left;font-weight:700}
.sl-hbar{flex:1;min-height:1px;background:var(--ink3)}
/* the views (R1, R2): the year strip, the filters (in reach while scrolling: a sticky bar, one line on a phone), the view switch */
.sl-years{margin:0 0 4px;overflow-x:auto;overscroll-behavior-x:contain}
.sl-years ol{display:flex;gap:2px;margin:0;padding:0;list-style:none;white-space:nowrap}
.sl-years a{display:inline-flex;align-items:baseline;gap:5px;min-height:44px;padding:11px 9px 6px;color:var(--ink);font-weight:800;font-size:16px;text-decoration:none;border-bottom:4px solid transparent}
.sl-years a b{font-size:12.5px;font-weight:700;color:var(--ink2)}
.sl-years a[aria-current]{border-bottom-color:var(--page,var(--ink))}
.sl-years a:hover{border-bottom-color:var(--ink3)}
.sl-filters a{display:inline-flex;align-items:center;gap:5px;min-height:36px;padding:0 10px;border:2px solid var(--ink);background:#fff;color:var(--ink);font-weight:800;font-size:14px;text-decoration:none}
.sl-filters a[aria-current]{background:var(--ink);color:#fff}
.sl-views a{display:inline-flex;align-items:center;min-height:36px;padding:0 6px;color:var(--ink);text-decoration:underline;text-underline-offset:3px}
.sl-views a[aria-current]{text-decoration:none;box-shadow:inset 0 -4px 0 var(--page,var(--ink))}
.sl-count{font-size:15px;font-weight:800;margin:0 0 6px;color:var(--ink2)}
.sl-monthh,.sl-day{scroll-margin-top:64px}   /* below the sticky filter bar: one line on a phone */
@media (min-width:700px){ .sl-monthh,.sl-day{scroll-margin-top:110px} }   /* the bar at its tallest, two lines (91 px) */
/* a row (R1, R3): its date with the year, its headline once as a link, its tags, a winter row's number, the warnings
   (more than 3 fold to a count), its map when the map shows something; a big day larger and bolder, nothing else */
.sl-day{display:grid;grid-template-columns:112px minmax(0,1fr);gap:14px;padding:12px 0;border-bottom:1px solid var(--rule)}
.sl-maplink img{display:block;width:112px;height:112px;border:1px solid var(--rule);background:var(--paper)}
.sl-date{margin:0;font-size:14.5px;font-weight:700;display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.sl-hl a{color:var(--blue);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}   /* Storm Log 12 */
.sl-tags{margin:6px 0 0}
.sl-wfold .sl-warns{margin-top:2px}
.sl-line a{font-weight:700}
.sl-main>.np-secbar,.sl-side>.np-secbar{margin-top:0}
.sl-side>:not(.np-secbar){margin-left:16px;margin-right:16px}
@media (max-width:560px){
  .sl-h1{font-size:34px}
  .sl-day{grid-template-columns:76px minmax(0,1fr);gap:10px}
  .sl-maplink img{width:76px;height:76px}
  .sl-stat b{font-size:24px}
  .sl-areasvg{width:130px;height:130px}
}
.rp-rep{stroke:#fff;stroke-width:2}
.rp-rep.ring{stroke:var(--ink3);stroke-width:2.5}
/* tornadoes near Faribault (storms.html) */
.sl-torn{margin-top:32px}
.sl-torn .sd-tablewrap{max-height:520px;overflow:auto;border-bottom:1px solid var(--rule)}
/* one storm day: /storms/YYYY-MM-DD/ (Round Q Phase 1, Oct. 2026: stormpages.py writes every module from stormday.py's
   rules; each shows only when the day has what it needs). Red bars, the page tab and the masthead rule come from
   body[data-page="storms"]; nothing smaller than bold 19 px sits on red (M1's rule), so the tags and the map's marks
   carry their colors as swatches and strokes, never behind small text. */
.sd .sl-date{margin-bottom:4px}
.sd-map{margin:0}   /* the storm log's tornado map (storms.html) */
.sd-map img{display:block;width:100%;height:auto;max-width:480px;border:1px solid var(--rule);background:var(--paper)}
.sd-crumb a[aria-current]{color:var(--ink);text-decoration:none}
.sd-head .sl-h1{margin-top:4px}
.sd-tags{list-style:none;display:flex;flex-wrap:wrap;gap:6px 8px;margin:12px 0 0;padding:0}
.sd-tag{display:inline-flex;align-items:center;gap:6px;padding:2px 9px;font-size:13px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;background:#fff;color:var(--ink);border:2px solid var(--ink)}
.sd-tag::before{content:"";flex:none;width:11px;height:11px;background:var(--sw,var(--ink3))}
.sd-tag.hot{--sw:var(--storm-hot)}
.sd-tag.wind{--sw:var(--storm-wind)}
.sd-tag.cool{--sw:var(--storm-cool)}
.sd-tag.warn{font-weight:700;color:var(--ink2);border:1px dashed var(--ink3)}   /* a warning is a secondary tag (Storm Day 16) */
.sd-tag.warn::before{display:none}
.air-lab b{display:block;font-weight:800}
#sd-air{--labw:280px}
.sd-likes a{font-weight:800}
/* the map (Storm Day 5, 6, 21): inline, the marks numbered as the table */
.sd-rounds{margin:0 0 10px}
@media (min-width:900px){
  .sd-mapfig .sd-legend{flex-direction:column;margin-top:0}
}
.sd-kstats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));border:1px solid var(--rule);background:#fff;margin:10px 0}
.sd-replay{padding:0}
.sd-ctls{display:flex;flex-wrap:wrap;align-items:center;gap:8px 18px;margin:12px 0 0}
.sd-only{display:inline-flex;align-items:center;gap:6px;font-size:15px;font-weight:700;min-height:40px}
.sd-only input{width:18px;height:18px;margin:0}
.sd-tablewrap{overflow-x:auto}
.sd-table{width:100%;border-collapse:collapse;font-size:14px;margin-top:8px}
.sd-table th,.sd-table td{text-align:left;padding:6px 8px;border-bottom:1px solid var(--rule);vertical-align:top}
.sd-table thead th{border-bottom:2px solid var(--ink);font-weight:900}
.sd-table td:nth-child(2){white-space:nowrap;font-weight:700}
.sd-table tr[hidden]{display:none}
.sd-rem p{margin:3px 0 0;font-size:13.5px;max-width:48ch}
@media (max-width:640px){
  .air-lab b{display:inline;margin-right:6px}
  /* a phone's reports: one stacked row each, the number beside it, the last two cells labeled (the report card's way) */
  .sd-table{font-size:14px}
  .sd-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
  .sd-table tr{display:grid;grid-template-columns:2.4em minmax(0,1fr);padding:8px 0;border-bottom:1px solid var(--rule)}
  .sd-table td{padding:1px 0;border:0}
  .sd-table td:nth-child(n+2){grid-column:2}
  .sd-table td[data-k]{font-size:13px;color:var(--ink2)}
  .sd-table td[data-k]::before{content:attr(data-k) ": ";font-weight:800}
  /* the log's tornado table (Round R1): the date and rating on the first line, the labeled cells under them */
  #sl-torn-table tr{grid-template-columns:max-content minmax(0,1fr);column-gap:12px}
  #sl-torn-table td:nth-child(n+3){grid-column:1 / -1}
  #sl-torn-table td:empty{display:none}
}
/* Radar time and "Updated" tags off the Twin Cities (Round D1, review #26 / home #17): radar.html puts them in the
   map's bottom corners; the home radar keeps its color key and play bar in the bottom corners, so the tags sit just
   above them (--rad-ov: the height of that bottom row) */
.rp-box .np-radar-time,.rp-box .np-age{top:auto;bottom:8px}
/* N-fu17: with radar.html's color key in the bottom-left corner, its time tag goes back to the top-left one. The local
   view shows the whole scan now, so the Twin Cities sit well below it (radar_test: no tag or key covers a label) */
.rp-box:has(> .rp-legend) .np-radar-time{top:8px;bottom:auto}
#radar{--rad-ov:44px}
#radar #radar-time{top:auto;left:auto;right:8px;bottom:calc(var(--rad-ov) + 12px)}
#radar #radar-age{top:auto;right:auto;left:8px;bottom:calc(var(--rad-ov) + 12px)}
#radar.gif #radar-time{display:none}
@media (max-width:720px){
  .rp-box .np-radar-time,.rp-box .np-age{bottom:6px}
  .rp-box:has(> .rp-legend) .np-radar-time{top:6px;bottom:auto}
  .rp-box > .rp-legend{left:6px;bottom:6px}
  #radar .np-play{width:44px;height:44px}    /* home radar controls at least 44 px tall on phones (Round D4, home #19) */
  #radar .np-scrub{height:44px}
  #radar{--rad-ov:44px}
  #radar #radar-time{right:6px;bottom:calc(var(--rad-ov) + 10px)}
  #radar #radar-age{left:6px;bottom:calc(var(--rad-ov) + 10px)}
}
/* Faribault box on phones (Round E2, review home #7): under 650 px tall at 390, the temperature shown once. The station
   plot folds behind "Station details" (np.js), the frost and snow chips share a row, the sun and normals rows are
   tighter. Desktop is unchanged: the button is hidden and the plot is always open. */
/* Round P5 (Home 3): the station plot is a closed fold at every width (it was a phone-only button, Round E2) */
.np-plot-sum{min-height:44px;display:flex;align-items:center;cursor:pointer;font-weight:800;font-size:14px}
.np-plot[open] .np-plot-sum{min-height:36px}
@media (max-width:720px){
  .np-plot{padding:3px 16px}
  .np-chips{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;padding:7px 16px 8px}
  .np-chip{padding:4px 7px;font-size:12.5px}
  .np-sun{padding:7px 16px 7px}
  .np-normals{padding:7px 16px 7px}
  .np-yday{padding:6px 16px}
  .np-box .np-tile{padding:6px 8px}
  .np-box .np-tile b{font-size:16px}
}

.sk text{font-family:'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;fill:var(--ink);font-size:max(13px,calc(13.5px*var(--k,1)))}

.co-card h3{margin:0;font-size:14px;font-weight:800;color:var(--ink)}
.so-card h3{margin:0;font-size:14px;font-weight:800}

.rc-rain .np-small{margin-top:8px}

/* "Copy link" on storm days and the climate page (Round H8; assets/np/track.js copies, Umami counts the click) */
.np-copy{font:800 14px 'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;min-height:44px;padding:0 14px;border:2px solid var(--ink);background:#fff;color:var(--ink);cursor:pointer}




/* ---------- Round M2, M4 and M6 pieces a live page uses (Round N1, /winter/, the first page to opt in): moved here from
   assets/np/restyle.css unchanged, as each page round starts using them. A page opts in with <body data-page="...">;
   each page's color line moves with its round. Colors are the M1 tokens; caps come from text-transform. ---------- */
body[data-page]{--page:var(--bar-blue);--page-ink:var(--bar-blue-ink)}
body[data-page="winter"]{--page:var(--bar-blue);--page-ink:var(--bar-blue-ink)}
body[data-page="forecast"]{--page:var(--bar-orange);--page-ink:var(--bar-orange-ink)}   /* Round O2: /forecast/ (7-day) */
body[data-page="storms"]{--page:var(--bar-red);--page-ink:var(--bar-red-ink)}   /* Round Q1: the storm-day pages (moved from restyle.css) */
body[data-page="models"]{--page:var(--bar-yellow);--page-ink:var(--bar-yellow-ink)}   /* Round S1: models.html (moved from restyle.css) */
body[data-page="radar"]{--page:var(--bar-lime);--page-ink:var(--bar-lime-ink)}   /* Round U1: radar.html, lime, ink on it (M1) */
body[data-page="night"]{--page:var(--bar-navy);--page-ink:var(--bar-navy-ink)}   /* Round X1: /night/, navy (M-fu1; moved from night.css) */
body[data-page="climate"],body[data-page="archive"],body[data-page="about"]{--page:var(--bar-green);--page-ink:var(--bar-green-ink)}   /* Round T2: the archive and /climate/, green (M-fu3; moved from restyle.css), ink on it; Round V1: /about/ */
/* page tab: a short caps label above the H1 (the H1 stays as it is), and a 4px rule in the page color under the masthead */
body[data-page] .np-mast{border-bottom:4px solid var(--page)}
.np-pagetab{display:block;width:fit-content;align-self:flex-start;margin:18px 0 8px;padding:2px 10px;background:var(--page,var(--bar-blue));color:var(--page-ink,var(--bar-blue-ink));font-size:19px;font-weight:800;letter-spacing:.06em;line-height:1.3;text-transform:uppercase}
.np-pagetab+h1{margin-top:0}
/* section bar: full width in the page color, the h2 inside it, a 2px ink rule under it. Nothing smaller sits in the bar. */
.np-secbar{margin:32px 0 12px;padding:7px 12px;background:var(--page,var(--bar-blue));color:var(--page-ink,var(--bar-blue-ink));border-bottom:2px solid var(--ink)}
.np-secbar h2,.np-secbar h3{margin:0;font-size:19px;font-weight:800;letter-spacing:.05em;line-height:1.3;text-transform:uppercase}
.np-secbar a{color:inherit;text-decoration:underline}
/* P-fu4 (Oct. 17, 2026): under 360 px a bar's label keeps its bold 19 px caps without the letter spacing and with 8 px
   sides, and a label whose section repeats it may drop one word there (.np-secwide: home's "Weather" by the numbers,
   /winter/'s "next" 72 hours), so every bar fits one line at 320 */
@media (max-width:359px){.np-secbar{padding-left:8px;padding-right:8px}.np-secbar h2,.np-secbar h3{letter-spacing:0}.np-secwide{display:none}}
/* one piece in another page's color: home's section bars take the color of the page each links to (Round P1; moved
   from restyle.css) */
.np-pc-red{--page:var(--bar-red);--page-ink:var(--bar-red-ink)}
.np-pc-orange{--page:var(--bar-orange);--page-ink:var(--bar-orange-ink)}
.np-pc-yellow{--page:var(--bar-yellow);--page-ink:var(--bar-yellow-ink)}
.np-pc-lime{--page:var(--bar-lime);--page-ink:var(--bar-lime-ink)}
.np-pc-green{--page:var(--bar-green);--page-ink:var(--bar-green-ink)}
.np-pc-blue{--page:var(--bar-blue);--page-ink:var(--bar-blue-ink)}
.np-pc-navy{--page:var(--bar-navy);--page-ink:var(--bar-navy-ink)}
/* the home lead box's stripe: the five logo bands, flat (Round P1; moved from restyle.css) */
.np-bandstripe{height:8px;background:linear-gradient(90deg,var(--bar-red) 0 20%,var(--bar-orange) 20% 40%,var(--bar-yellow) 40% 60%,var(--bar-lime) 60% 80%,var(--bar-green) 80%)}
/* sidebar box: how this works, history, definitions */
.np-sidebox{margin:16px 0;padding:12px 16px;background:var(--sidebar-bg);border:1px solid var(--sidebar-rule);font-size:15px;line-height:1.45}
.np-sidebox>:first-child{margin-top:0}
.np-sidebox>:last-child{margin-bottom:0}
.np-sidebox h3{margin:0 0 6px;font-size:16px;font-weight:900}
/* links in running text look like links, one underline style (Q-fu2 item 4, Travis, Oct. 18: site-wide; Lighthouse's
   link-in-text-block): a class-less link in a paragraph, list item, definition or caption on every page, and every
   class-less link in main on a page that has opted in (data-page). A link with a class of its own (a nav item, a button,
   a card, a tab) keeps its own look. */
body[data-page] main a:not([class]),main :is(p,li,dd,figcaption) a:not([class]){text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}
body[data-page] main a:not([class]):hover,main :is(p,li,dd,figcaption) a:not([class]):hover{text-decoration-thickness:2px}
/* margin note: a short fact in red, beside the text at 1100px and wider, in line below that. The note comes just
   before the paragraph it goes with. */
.np-mnote{margin:10px 0;padding-left:10px;border-left:3px solid var(--red-text);color:var(--red-text);font-size:15px;font-weight:700;line-height:1.35}
@media (min-width:1100px){
  .np-withnotes{padding-right:250px}
  .np-withnotes .np-mnote{float:right;clear:right;width:220px;margin:2px -250px 12px 0}
  .np-withnotes::after{content:"";display:table;clear:both}
}
/* Round M2's key (moved from restyle.css by Round O2, /forecast/'s key) */
/* key: small swatches, one label each; a group never wraps inside (Home 21), groups wrap as wholes. .stack: one per line */
.np-keylist{display:flex;flex-wrap:wrap;gap:6px 18px;margin:8px 0 0;padding:0;list-style:none;font-size:14px;line-height:1.3}
.np-keylist.stack{flex-direction:column;gap:4px}
.np-keylist .grp{display:inline-flex;flex-wrap:nowrap;gap:6px 14px}
.np-keylist .it{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.np-keylist .sw{flex:none;width:14px;height:14px;background:var(--sw,var(--rule))}
.np-keylist .sw.line{height:3px;width:18px}
/* ---------- Round M7 (moved from restyle.css by Round O8, /forecast/'s day bar): the one sticky bar a page may have (a day bar, controls, filters or a section nav). CSS only; the
   bar is in the raw HTML with its height, so nothing moves when it sticks. It comes after the warning banner in the
   page, so it sticks only once the banner is off screen, and the floating warning bar (z-index 50) sits over it; it
   never sits over a warning. Anchors and focused elements land below it (scroll-padding-top). At 390 its extra items
   scroll inside the bar, never the page. Which item is current is the page round's choice ([aria-current]). ---------- */
.np-sticky{position:sticky;top:0;z-index:40;min-height:48px;margin:0 0 12px;background:var(--paper);border-bottom:2px solid var(--ink)}
.np-sticky-in{display:flex;align-items:center;gap:4px 10px;min-height:48px;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:thin;white-space:nowrap}
.np-sticky-in>*{flex:none}
.np-sticky a,.np-sticky button{display:inline-flex;align-items:center;min-height:44px;padding:0 10px;border:0;background:none;font:700 15px 'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif;color:var(--ink);text-decoration:none;cursor:pointer}
.np-sticky a:hover,.np-sticky button:hover{text-decoration:underline}
.np-sticky [aria-current],.np-sticky [aria-pressed="true"]{background:linear-gradient(var(--page,var(--bar-blue)),var(--page,var(--bar-blue))) bottom/100% 4px no-repeat}   /* a flat 4px rule: no small text on a bar color */
html:has(.np-sticky){scroll-padding-top:60px}
@media print{ .np-sticky{display:none} }
/* ---------- Round M4: the freshness stamp (ssr.stamp, warnings.js FW_STAMP). It carries is-stale / is-gone like the
   module it belongs to, but stays readable: stale and gone stamps look like the site's stale notes. */
.np-stamp{margin:6px 0;font-size:13px;line-height:1.35;color:var(--ink3)}
.np-stamp.is-stale,.np-stamp.is-gone{opacity:1;filter:none;visibility:visible;padding:3px 10px;width:fit-content;max-width:100%;border:1px dashed var(--ink3);background:var(--slate-bg);font-size:12.5px;font-weight:700;color:var(--ink)}

/* ---------- Round M6: glossary terms (server/app/glossary.py). A term looks like plain text unless the browser has
   popovers; then it is dotted-underlined and opens its definition in the top layer (nothing on the page moves). ---------- */
.np-term{margin:0;padding:0;border:0;background:none;font:inherit;color:inherit;text-align:inherit;cursor:text}
@supports selector(:popover-open){
  .np-term{cursor:help;text-decoration:underline dotted;text-decoration-thickness:1px;text-underline-offset:3px}
  .np-term:hover{text-decoration-style:solid}
  .np-gloss{max-width:min(340px,calc(100vw - 32px));margin:auto;padding:12px 14px;border:2px solid var(--ink);background:var(--paper);color:var(--ink);font-size:15px;font-weight:400;line-height:1.45;text-align:left;text-transform:none;letter-spacing:0}
  .np-gloss b{display:block;margin-bottom:2px;font-weight:800}
  .np-gloss a{display:block;margin-top:6px;font-size:13px;text-decoration:underline}
}
@supports not selector(:popover-open){ .np-gloss{display:none} }

/* ---------- The rest of Round M2, M7 and M8 (the other pages' colors, sticky bar, storm-day chart): assets/np/restyle.css
   until a page round uses them (Round M13). The page colors' nav strip stays here: ---------- */
/* the nav's items in their pages' colors (Round M-fu3; M13 draws them): Today is the five bands, as its stripe */
.np-nav a[href="./"],.np-nav a[href="/"]{--nav-c:var(--bar-blue);background-image:linear-gradient(90deg,var(--bar-red) 0 20%,var(--bar-orange) 20% 40%,var(--bar-yellow) 40% 60%,var(--bar-lime) 60% 80%,var(--bar-green) 80%)}
.np-nav a[href="radar.html"]{--nav-c:var(--bar-lime)}
.np-nav a[href="forecast/"]{--nav-c:var(--bar-orange)}
.np-nav a[href="night/"]{--nav-c:var(--bar-navy)}
.np-nav a[href="models.html"]{--nav-c:var(--bar-yellow)}
.np-nav a[href="storms.html"]{--nav-c:var(--bar-red)}
.np-nav a[href="winter/"]{--nav-c:var(--bar-blue)}
.np-nav a[href="archive/"]{--nav-c:var(--bar-green)}

/* ---------- Round M3: the scalloped-cloud icons' colors (np.js ICON, live since M13). Flat fills from the
   tokens; the in-between steps are mixes of two tokens (the first line of each is the fallback without color-mix). */
.npi-w{fill:#fff}
.npi-e{fill:var(--cloud-shadow);stroke:var(--cloud-shadow);stroke-width:3}
.npi-l{fill:var(--cloud-shadow);fill:color-mix(in srgb,var(--cloud-shadow) 42%,#fff)}
.npi-g{fill:var(--cloud-shadow)}
.npi-sc{fill:var(--storm-cloud)}
.npi-sd{fill:var(--slate);fill:color-mix(in srgb,var(--storm-cloud) 62%,var(--ink))}
.npi-y{fill:var(--bar-yellow)}
.npi-ym{fill:var(--bar-orange);fill:color-mix(in srgb,var(--bar-yellow) 50%,var(--bar-orange))}
.npi-o{fill:var(--bar-orange)}
.npi-ray{fill:none;stroke:var(--bar-orange);stroke-width:4;stroke-linecap:round}
.npi-rain{fill:none;stroke:var(--blue2);stroke-width:4;stroke-linecap:round}
.npi-snow{fill:none;stroke:var(--cold);stroke-width:2.6;stroke-linecap:round}
.npi-ice{fill:var(--blue2)}
.npi-pel{fill:var(--cold)}

/* ---------- Round M9: the copy-link box, where the Clipboard API isn't there (assets/np/share.js) ---------- */
.np-copytext{margin:6px 0 0 8px;min-height:44px;width:min(100%,360px);padding:0 8px;border:1px solid var(--ink3);background:var(--paper);color:var(--ink);font:14px 'Libre Franklin','LF Fallback','LF Fallback Roboto',system-ui,sans-serif}

/* Round L14: the site-wide aurora banner (server/app/nightpage.py aurora_banner, api/ssr/aurora-banner.html), in every page's
   raw HTML just before <main>, so under the watch bar and the warning banner, never over them; only while /night/'s answer is
   "Active now, and it's clear". Navy, not a warning's red or yellow, and not sticky. It leaves when its Kp estimate goes
   stale: warnings.js sets hidden at data-until, and the animation (its delay written by the worker) does it without script. */
.fw-aurora{margin:14px 0 0;padding:10px 14px 9px;background:var(--navy);color:var(--bar-navy-ink);border-left:6px solid var(--moist);animation:fw-aurora-go 0s forwards}
.fw-aurora[hidden]{display:none}
.fw-aurora p{margin:0;font-size:16px;line-height:1.4}
.fw-aurora .fw-aurora-k{font-weight:800;text-transform:uppercase;letter-spacing:.04em;margin-right:4px}
.fw-aurora a{color:var(--bar-navy-ink);font-weight:800;text-decoration:underline}
.fw-aurora .np-stamp{margin:3px 0 0;color:var(--bar-navy-ink);opacity:.85}
@keyframes fw-aurora-go{to{visibility:hidden;height:0;margin:0;padding:0;border:0;overflow:hidden}}

/* ---------- Round W (Oct. 2026): /how-it-works/, every page's explanations in one place (server/app/howitworks.py), and
   each page's one line to its section ("How this page works ›", under its stamp). Keys stay beside their charts. ---------- */
.np-hiw{margin:6px 0 0}
.np-hiw a{font-weight:700}
.np-box .np-hiw{padding:0 16px 12px}   /* Round P11: home's line, at the foot of the box */
