/* NWS Data Explorer — the /nws section of MaverickWX.

   Loads after tokens.css, shell.css and styles.css, and owns only what is specific to
   this section: the API catalog, the concepts pages, the SDM feed and message card, the
   glossary, and the reference tables.

   WHAT CHANGED, AND WHY IT IS WORTH SAYING
   ----------------------------------------
   This file used to open with 130 lines of its own `:root` — a second palette, a second
   type scale, a second set of status colours — and then restate primitives the storm
   pages already had. Both stylesheets loaded on every /nws page, so eight class names
   (.card .chip .rail .pane .product .provenance .lede .corner) were resolved by cascade
   order rather than by intent, and the section quietly depended on being second.

   The header comment that used to sit here defended a distinct "technical blueprint"
   character as deliberate. That distinction is gone by decision, not by accident: the
   section now takes its palette, spacing, type, controls, panel and title bar from the
   shared layers, and the classes that used to collide are renamed to what they actually
   are (`.box`, `.sev`, `.view`, `.subrail`, `.prodcode`, `.gloss-provenance`). What
   remains distinct is content density, not styling — a reference section is denser than a
   storm dashboard because it has more to say per screen, which is a layout property.

   See docs/explorer-migration.md and docs/website.md for the record. */

/* ============================================================================
   Section primitives
   ==========================================================================*/

/* The generic hairline container. Was `.card`, which collided with the storm card on
   every /nws page; a box is what it actually is. */
.box {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  background: transparent;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: var(--sp-4) 0;
}

/* No registration marks. The four corner brackets that every box here used to carry —
   `.blueprint` and the `corners()` helper that emitted them — are gone: the rest of the
   site has no decorative device, and a frame is the rule above and below the box. */

/* Severity chips. Was `.chip`, which collided with the wind-tier classification ramp —
   a genuinely dangerous collision, since that ramp is a meteorological guardrail and this
   is an operational-status colour. Renamed so the two can never be confused again. */
.sev {
  display: inline-block; padding: 2px 10px;
  font-size: var(--fs-micro); font-weight: 600; font-family: var(--font-body);
  letter-spacing: 0.02em; border: 1px solid transparent;
}
/* The severity chips take the same ladder as `.freshness` and the masthead pill: nothing,
   a rule, a reversal. The tints they had are gone with the status tokens — a tint is the one
   thing this system does not have, and an amber chip here sat in the same hue as a Category
   2 storm on the Storms section. */
.sev--ok, .sev--none { background: var(--wash-strong); color: var(--ink); border-color: var(--line-strong); }
.sev--caution { background: var(--wash); color: var(--ink); border-color: var(--ink); font-weight: 700; }
.sev--critical { background: var(--ink); color: var(--paper); border-color: var(--ink); font-weight: 700; }
.sev--accent { background: var(--wash); color: var(--ink); border-color: var(--line-strong); }
.sev--unknown, .sev--quiet { background: transparent; color: var(--muted); border-color: var(--divider); }

/* ============================================================================
   Navigation panel interior (.panel--nav from shell.css)
   ==========================================================================*/

/* `.panel-brand` / `.section-brand` / `.brand-mark` / `.brand-name` used to live here:
   a second wordmark and a second disclaimer badge at the head of this rail, under the
   Maverick masthead. They are gone, markup and all. A CSS wrapper could never have fixed
   that — the duplication was in what the rail *rendered*, not in how it was painted. */

.panel-nav { padding: var(--sp-1) var(--sp-3); }
.panel-nav ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1px; }
.nav-icon { display: grid; place-items: center; width: 18px; height: 18px; color: var(--muted); flex: none; }
.nav-label { flex: 1; }
.panel-item[aria-current="page"] .nav-icon { color: var(--ink); }

.panel-divider { margin: 10px var(--sp-4); height: 1px; background: var(--divider); }

/* The rail's way to the operations feed.

   A `.panel-item` from shell.css — the same row a layer in the Radar panel and a section
   in the API docs' index get. It used to carry three readings of its own (Critical Weather
   Day, open notices, satellite sectors), which were the same three cells as the feed's
   dashboard one click away; a rail is furniture and says where, not what. The freshness
   line stays because it qualifies the link. */
.mini-panel { padding: 2px var(--sp-4) 6px; }
.mini-card { display: flex; flex-direction: column; gap: var(--sp-1); padding: 13px 14px; color: var(--ink); }
.mini-card:hover { text-decoration: none; }
.mini-name { font-family: var(--font-body); font-weight: 600; font-size: var(--fs-bulletin); }
.mini-foot { font-size: var(--fs-bulletin); color: var(--muted); }

/* The page foot: the standing disclaimer and the source links, at the end of the content
   inside the scrolling stage.

   It was the foot of the navigation rail, at 10.5px — the smallest type on the page, in a
   column narrow enough to clip the sentence at 1366px (audit M-49). A sentence that says
   this is not an official product and not for life-safety decisions is the last thing on
   the page that should be hard to read, so it is 13px, it wraps in the content column
   rather than in a gutter, and it sits where a reader who has finished reading ends up. */
.page-foot {
  /* `flex: none` because the stage is a flex column: the footer states its own height
     rather than being squeezed by a long page above it. */
  flex: none;
  padding: var(--sp-6) var(--sp-7) var(--sp-8);
  border-top: 1px solid var(--divider);
  color: var(--muted);
}
.disclaimer {
  font-size: var(--fs-remarks); font-family: var(--font-body);
  line-height: 1.6;
  color: var(--muted);
  margin: 0 0 var(--sp-2);
  max-width: 68ch;
  /* Wrapping is the whole point: nothing here may be truncated to fit. */
  overflow-wrap: break-word;
}
.page-foot-links { font-size: var(--fs-bulletin); margin: 0; color: var(--muted); }

/* ============================================================================
   Pagehead extras
   ==========================================================================*/

.topsearch { position: relative; flex: 1 1 260px; max-width: 420px; min-width: 180px; }
.topsearch-ico {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--muted); display: grid; place-items: center;
  pointer-events: none;
}
.topsearch-input { padding-left: 34px; }

/* The stale banner is a full-width band (shell.css) and its sentence ran ~180 characters
   per line at 1440px. The band keeps its width; the sentence takes the prose measure. */
.databanner-text { display: block; max-width: var(--wrap-prose); }

/* Reading / developer mode. The active side is reflected from the <html> attribute, so
   the control is correct on first paint without JS. Reading is the default. */
html:not([data-mode="dev"]) .seg-opt input[value="reading"] + span,
html[data-mode="dev"] .seg-opt input[value="dev"] + span {
  background: var(--wash); color: var(--ink);
}
/* Developer-only content declares itself with `data-dev-only`, and this pair of rules is
   the whole of what the switch does. Keying on the attribute rather than on a list of
   class names is what lets `render/mode.ts` decide, from the rendered HTML alone, whether
   a page has anything for the switch to change — and therefore whether to offer it at
   all (audit M-19). A page that grows dev-only content gets the behaviour by marking it. */
[data-dev-only] { display: none; }
html[data-mode="dev"] [data-dev-only] { display: revert; }

/* The catalog's own control row: the result count, and the Reading/Developer switch that
   acts on the cards below it. */
.view-controls {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap; margin: 0 0 var(--sp-6);
}
.view-controls .result-count { margin: 0; }

/* ============================================================================
   Views (the section's work surface)
   ==========================================================================*/

/* Was `.pane`, which the storm viewer also claimed. */
.view { padding: var(--sp-6) var(--sp-7) 72px; max-width: 860px; min-width: 0; }
.view--single, .view--home { max-width: 1080px; margin: 0 auto; }
.view--prose { max-width: 760px; }
.view--message { max-width: 780px; margin: 0 auto; }
.view-meta { font-size: var(--fs-bulletin); color: var(--muted); margin: 6px 0 var(--sp-5); }

/* An in-body heading, for pages whose title is carried by the pagehead but which still
   introduce a sub-section. The page's own <h1> lives in the pagehead now. */
.result-count { font-size: var(--fs-bulletin); color: var(--muted); margin: 0 0 var(--sp-6); }
/* Standfirst and section labels, sentence case in the interface face.
 *
 * These were uppercase mono at 11px, which is the "REFERENCE" / "LIVE OBSERVATIONS" voice
 * the redesign is removing everywhere. A section label is a short, direct heading — set it
 * like one and it can carry a real sentence instead of two tracked-out words. */
.kicker {
  font-size: var(--fs-bulletin); font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--ink); margin: 0 0 var(--sp-2);
}
.section-kicker {
  font-family: var(--font-body); font-size: var(--fs-lead); font-weight: 700;
  letter-spacing: var(--track-title); text-transform: none; color: var(--ink);
  margin: var(--sp-7) 0 var(--sp-4);
}

/* Emphasis by the site's own device — a full-measure rule above — rather than a coloured
   side tab, which is a pattern this system does not have. The warning steps the rule up to
   ink and sits on the wash. */
.callout { background: var(--paper); border-top: 1px solid var(--line-strong); padding: 14px 0; margin: var(--sp-5) 0; }
.callout--warn { background: var(--wash); border-top: 2px solid var(--ink); padding-inline: var(--sp-5); }

/* The about page's way across to the site's own About, and its live figures. */
.crosslink {
  font-size: var(--fs-remarks); font-family: var(--font-body); color: var(--ink-2);
  margin: 0 0 var(--sp-5); padding-bottom: var(--sp-4); border-bottom: 1px solid var(--line);
}
.about-data { font-family: var(--font-body); font-size: var(--fs-remarks); }
.about-data time { font-family: var(--font-mono); font-size: var(--fs-bulletin); font-variant-numeric: tabular-nums; }

.breadcrumb { font-size: var(--fs-bulletin); font-family: var(--font-body); margin: 0 0 var(--sp-4); }
.source-link { font-size: var(--fs-bulletin); color: var(--muted); margin-top: 14px; }

/* The reading measure for this section's explanatory pages. `.prose` is defined in
   shell.css at --wrap-prose (68ch); this narrows nothing and only adds the heading rhythm,
   so the two do not disagree about what a comfortable line length is. */
.prose h2 { font-size: var(--fs-lead); margin: var(--sp-7) 0 var(--sp-3); }
.prose ul, .prose ol { padding-left: var(--sp-5); }
.prose li { margin-bottom: 6px; }

/* ============================================================================
   Split layouts — a facet rail beside the view
   ==========================================================================*/

/* An in-section rail, distinct from the shell's navigation panel: it filters what the
   view is showing rather than moving between sections. Was `.rail`, which the storm
   dashboard also claimed. */
.split { display: grid; align-items: start; }
/* One width, from the token, rather than 236px here and 230px six pixels away — a
   difference nobody chose and nobody can see, which is exactly how a codebase ends up
   with four rail widths and no rule. */
.split--glossary,
.split--products,
.split--sdm,
.split--concepts { grid-template-columns: var(--subrail-w) 1fr; }
/* The endpoint catalog has no rail: its categories are a row above the list. */
.catalog { min-width: 0; }

.subrail { padding: var(--sp-6) 14px var(--sp-6) var(--sp-6); }
.subrail--sticky { position: sticky; top: 0; align-self: start; max-height: 100vh; overflow-y: auto; }
.subrail-label {
  font-family: var(--font-body); font-size: var(--fs-bulletin); font-weight: 700;
  letter-spacing: 0; text-transform: none; color: var(--ink-2); margin: 0 0 var(--sp-2);
}
.subrail-label + .facet-group { margin-bottom: var(--sp-5); }
.facet-group { display: flex; flex-direction: column; gap: 1px; }

/* Facets are `.panel-item--flush` rows: the same hover, the same current-state accent as
   the section nav and the storm rail. */
.facet span:first-child { flex: 1; }
/* The count sits where `.panel-count` does on the section nav — same row, same face,
   same muted-to-accent shift when the row is current. */
.facet-count {
  margin-left: auto; flex: none; font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; font-size: var(--fs-micro); color: var(--muted);
}
.facet[aria-current="true"] .facet-count { color: var(--ink); font-weight: 700; }
.facet-clear { display: inline-block; margin-top: 14px; font-size: var(--fs-bulletin); font-family: var(--font-body); font-weight: 600; }

/* The row form of the facets: chips that wrap, above the list they filter. Sticky on a
   wide screen so a reader forty endpoints down can still change category; square, like
   every other bounded control here. */
.facet-bar {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; gap: var(--sp-2) var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-7);
  background: var(--paper); border-bottom: 1px solid var(--line);
}
.facet-bar-label {
  flex: none; font-family: var(--font-body); font-size: var(--fs-bulletin); font-weight: 700; color: var(--ink-2);
}
.facet-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); min-width: 0; }
.facet--chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px;
  border: 1px solid var(--line); background: var(--paper);
  font-family: var(--font-body); font-weight: 600; font-size: var(--fs-bulletin); color: var(--ink);
  text-decoration: none;
}
.facet--chip:hover { border-color: var(--ink); text-decoration: none; }
.facet--chip[aria-current="true"], .facet--chip.facet--active { border-color: var(--ink); background: var(--wash-strong); }

/* The narrow-screen form of the same facets: a GET form with a select, which works with
   no script at all. Hidden above the breakpoint, where the links carry the counts; the
   submit button is the no-JS path and the script hides it once it can apply the choice. */
.facet-select { display: none; align-items: center; gap: var(--sp-2); flex-wrap: wrap; width: 100%; }
.facet-select-caption { font-family: var(--font-body); font-size: var(--fs-bulletin); font-weight: 600; color: var(--ink-2); flex: none; }
.facet-select select {
  font: inherit; font-size: var(--fs-bulletin); min-height: 38px; padding: var(--sp-1) var(--sp-2);
  border: 1px solid var(--edge); background: var(--paper); color: var(--ink);
  flex: 1 1 200px; min-width: 0; max-width: 100%;
}
.facet-select.is-auto .btn { display: none; }

/* The concepts page's own table of contents. The number and the label are two spans and
   had no rule between them, so the list read "1Everything starts with /points" (audit). */
.toc-link {
  display: flex; align-items: baseline; gap: var(--sp-2); padding: 6px var(--sp-3);
  font-family: var(--font-body); font-weight: 600; font-size: var(--fs-bulletin); color: var(--ink);
  text-decoration: none;
}
.toc-link:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); text-decoration: none; }
.toc-num {
  flex: none; min-width: 1.6ch; color: var(--muted);
  font-family: var(--font-mono); font-weight: 600; font-variant-numeric: tabular-nums;
}

/* ============================================================================
   Home
   ==========================================================================*/

/* Subordinate to the page's own <h1> in the title strip, which is the thing that names
   where you are. It was clamped to 2.9rem — larger than the H1 above it — so the page had
   two competing first-lines and the smaller one was the real heading. */
.home-title { font-size: var(--fs-title); line-height: 1.15; margin: 0 0 var(--sp-4); max-width: 28ch; }
.home-lede { font-size: var(--fs-remarks); font-family: var(--font-body); max-width: 62ch; margin-bottom: var(--sp-6); }

.home-search { position: relative; max-width: 620px; margin-bottom: var(--sp-8); }
.home-search-ico {
  position: absolute; left: 15px; top: 50%; transform: translateY(-50%);
  width: 19px; height: 19px; color: var(--muted); display: grid; place-items: center;
  pointer-events: none;
}
.home-search-input { height: 52px; padding: 0 var(--sp-4) 0 46px; font-size: var(--fs-remarks); }

.task-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--sp-4); margin-bottom: var(--sp-8); }
.task { gap: 9px; padding: var(--sp-5) 0; background: var(--paper); color: var(--ink); }
.task-ico { display: grid; place-items: center; width: 22px; height: 22px; color: var(--muted); }
.task-title { font-family: var(--font-body); font-weight: 600; font-size: var(--fs-lead); line-height: var(--lh-lead); margin: 0; }
/* The title is the whole link. The arrow is its affordance at rest; the underline arrives
   on hover and focus, the way the section's other headed links behave. */
.task-title a { text-decoration: none; }
.task-title a:hover, .task-title a:focus-visible { text-decoration: underline; }
.task-body { font-size: var(--fs-remarks); font-family: var(--font-body); line-height: var(--lh-remarks); color: var(--ink-2); margin: 0; }

.dashboard-wrap { margin-bottom: var(--sp-8); }
.dashboard-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--sp-4); margin-bottom: 14px; }
.dashboard-head h2 { font-size: var(--fs-lead); margin: 0; }
.dashboard-head a { font-family: var(--font-body); font-weight: 600; font-size: var(--fs-bulletin); }
.dashboard { padding: 0; background: var(--paper); }
/* Four cells in a row, two by two below 900px, one column below 560px. `auto-fit` used to
   decide, and at 768px it fit three and orphaned the outlook on a row of its own. */
.dashboard-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.dash-cell {
  padding: var(--sp-5); border-right: 1px solid var(--divider);
  /* Wrap, never clip: a cell's value is the reading. */
  min-width: 0; overflow-wrap: anywhere;
}
.dash-cell:last-child { border-right: 0; }
.dash-label {
  font-family: var(--font-body); font-size: var(--fs-bulletin); font-weight: 600;
  letter-spacing: 0; text-transform: none; color: var(--muted); margin: 0 0 var(--sp-2);
}
.dash-value { margin: 0 0 var(--sp-2); }
.dash-note { font-size: var(--fs-bulletin); line-height: 1.45; color: var(--muted); margin: 6px 0 0; }
.dash-list { list-style: none; margin: 6px 0 0; padding: 0; font-size: var(--fs-remarks); font-family: var(--font-body); display: flex; flex-direction: column; gap: 6px; }
.dash-list li { display: flex; flex-direction: column; }
.dash-list a { font-family: var(--font-body); font-weight: 600; }

.home-feed { margin-bottom: var(--sp-8); }
.home-feed .dashboard-head h2 { font-size: var(--fs-lead); }

/* The developer on-ramp: one enamel band on the page, marking the boundary between the
   reading half of this section and the machine-readable half. It is the committed colour
   carrying a whole region, as the masthead does, and every colour on it is the enamel's
   own measured pair — `--on-enamel` and `--on-enamel-muted` (7.57:1) — where it used to
   carry two hexes (#a9c8e8, #c7d6e6) no token had ever named. */
.devband {
  flex-direction: row; align-items: center; gap: var(--sp-6); flex-wrap: wrap;
  padding: var(--sp-6); background: var(--enamel); color: var(--on-enamel);
  border-color: var(--enamel);
}
.devband-text { flex: 1 1 320px; }
.devband-kicker {
  font-size: var(--fs-bulletin); font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--on-enamel-muted); margin: 0 0 var(--sp-1);
}
.devband-title { font-family: var(--font-body); font-weight: 600; font-size: var(--fs-lead); margin: 0 0 6px; color: var(--on-enamel); }
.devband-body { margin: 0; font-size: var(--fs-remarks); font-family: var(--font-body); color: var(--on-enamel); max-width: 60ch; }
.devband-body code { color: var(--on-enamel); background: color-mix(in srgb, var(--on-enamel) 14%, transparent); padding: 1px 5px; }
.devband-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.btn--onreverse { border-color: var(--on-enamel-muted); color: var(--on-enamel); background: transparent; }
.btn--onreverse:hover { background: color-mix(in srgb, var(--on-enamel) 14%, transparent); color: var(--on-enamel); border-color: var(--on-enamel); }
.btn--onreverse.btn--filled { background: var(--on-enamel); color: var(--enamel); border-color: var(--on-enamel); }
.btn--onreverse.btn--filled:hover { background: var(--on-enamel); color: var(--enamel); text-decoration: underline; }

/* ============================================================================
   API catalog
   ==========================================================================*/

.cat-section { scroll-margin-top: var(--sp-4); margin-bottom: 34px; }
.cat-section h2 { font-size: var(--fs-lead); margin: 0 0 var(--sp-1); }
.cat-blurb { font-size: var(--fs-remarks); font-family: var(--font-body); color: var(--muted); max-width: 70ch; margin: 0 0 var(--sp-4); }
.endpoint-list { display: flex; flex-direction: column; gap: var(--sp-3); }

/* The default view: eleven category cards instead of sixty-nine endpoint cards.

   `auto-fit` with a `minmax` floor rather than a fixed column count, so this reflows from
   three columns to one without a media query and without ever producing a card too narrow
   to read its own blurb in. */
.cat-overview { margin-top: var(--sp-7); }
.cat-overview h2 { font-size: var(--fs-lead); margin: 0 0 var(--sp-4); }
.cat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--sp-3);
}
.cat-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: var(--sp-4) var(--sp-5);
  background: var(--paper);
  color: inherit;
  text-decoration: none;
}
.cat-card h3 { font-family: var(--font-body); font-size: var(--fs-lead); margin: 0; }
/* The blurb is the reason to click, so it keeps its full colour contrast rather than
   being dimmed the way a caption would be. */
.cat-card .cat-blurb { margin: 0; flex: 1; }
.cat-count { font-size: var(--fs-bulletin); color: var(--muted); margin: 0; font-variant-numeric: tabular-nums; }
.cat-card:hover { border-color: var(--ink); }
.cat-card:hover h3 { color: var(--ink); text-decoration: underline; }

.cat-sample { display: flex; flex-wrap: wrap; gap: 5px; margin: 0; flex: 1; align-content: flex-start; }
.cat-sample code {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  padding: 1px 5px;
  border: 1px solid var(--line);
  color: var(--muted);
}
.cat-sample-more { font-size: var(--fs-micro); color: var(--muted); align-self: center; }

.view-more { margin: var(--sp-6) 0 0; }

.endpoint { gap: 9px; padding: var(--sp-4) var(--sp-5); background: var(--paper); scroll-margin-top: var(--sp-4); }
.endpoint-head { display: flex; gap: 9px; align-items: center; flex-wrap: wrap; }
.method {
  font-family: var(--font-mono); font-weight: 600; letter-spacing: 0.06em; font-size: var(--fs-micro);
  padding: 2px 7px; background: var(--ink); color: var(--paper);
}
.endpoint-path { font-size: var(--fs-bulletin); background: none; padding: 0; color: var(--ink); word-break: break-all; }
.endpoint-path .base-url { color: var(--muted); }
.endpoint-plain { margin: 0; font-size: var(--fs-remarks); font-family: var(--font-body); line-height: 1.55; }
.endpoint-audience { display: flex; gap: 7px; align-items: flex-start; font-size: var(--fs-bulletin); color: var(--muted); margin: 0; }
.endpoint-audience-ico { display: inline-grid; place-items: center; width: 14px; height: 14px; margin-top: 2px; flex: none; color: currentColor; }

details.params, details.example { border: 0; }
details.params > summary, details.example > summary {
  cursor: pointer; font-family: var(--font-body); font-weight: 600; font-size: var(--fs-bulletin);
  color: var(--ink); list-style: none; display: inline-flex; align-items: center; gap: 6px;
  width: fit-content; min-height: 28px;
}
details.params > summary::-webkit-details-marker, details.example > summary::-webkit-details-marker { display: none; }
details.params > summary::before, details.example > summary::before { content: '+'; font-family: var(--font-mono); }
details[open].params > summary::before, details[open].example > summary::before { content: '–'; }

.example-body {
  border: 1px dashed var(--divider); padding: 13px 15px; margin-top: 9px;
  display: flex; flex-direction: column; gap: 9px; background: var(--paper);
}
.example-label {
  font-size: var(--fs-bulletin); font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--muted); margin: 0;
}
.example-path { font-size: var(--fs-bulletin); word-break: break-all; color: var(--ink); background: none; padding: 0; }
.example-path .base-url { color: var(--muted); }
.example-note { margin: 0; font-size: var(--fs-remarks); font-family: var(--font-body); color: var(--muted); }
.example-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.example-actions .btn { max-width: 100%; white-space: normal; overflow-wrap: anywhere; }
.try-output { margin-top: 2px; }
.try-output pre { max-height: 420px; overflow: auto; font-size: var(--fs-bulletin); margin: 0; }
.curl { margin-top: 2px; border-top: 1px solid var(--divider); padding-top: 9px; }
.curl-label {
  display: flex; align-items: center; gap: 5px;
  font-size: var(--fs-bulletin); font-weight: 600; letter-spacing: 0; text-transform: none;
  color: var(--muted); margin: 0 0 5px;
}
.curl-block { font-size: var(--fs-bulletin); margin: 0; white-space: pre-wrap; word-break: break-word; }

/* Concepts */
.view--prose .lede { margin-bottom: 30px; }
.concept { margin-bottom: 36px; scroll-margin-top: var(--sp-4); }
.concept h2 { font-size: var(--fs-lead); margin: 0 0 10px; }
.concept-num { color: var(--muted); }
.concept p { font-size: var(--fs-remarks); font-family: var(--font-body); margin: 0 0 var(--sp-3); }
.concept ul { font-size: var(--fs-remarks); font-family: var(--font-body); }
.chain { list-style: none; padding: 0; margin: 0 0 14px; display: flex; flex-direction: column; gap: 10px; }
.chain li { display: flex; gap: 14px; align-items: flex-start; padding: 14px 0; border-bottom: 1px solid var(--line); }
/* The numeral is the reversal — paper on ink — so it is 17:1 in light and 15:1 in dark.
   It was `#fff`, and `.chain span` (0,1,1) outranked `.chain-num` (0,1,0) and painted it
   muted on ink instead: 2.81:1 light, 1.92:1 dark (audit). The step text is `.chain-text`
   now, so no descendant rule can reach the numeral. */
.chain-num {
  flex: none; width: 26px; height: 26px; background: var(--ink);
  color: var(--paper); display: grid; place-items: center; font-family: var(--font-mono);
  font-weight: 600; font-size: var(--fs-bulletin);
}
.chain li > div { flex: 1; min-width: 0; }
.chain code { display: block; margin-bottom: 5px; font-size: var(--fs-bulletin); color: var(--ink); background: none; padding: 0; }
.chain-text { font-size: var(--fs-remarks); font-family: var(--font-body); line-height: var(--lh-remarks); color: var(--ink-2); }
.code-dark { background: var(--ink); color: var(--paper); padding: var(--sp-3) 15px; font-size: var(--fs-bulletin); border: 0; }

/* ============================================================================
   Product codes
   ==========================================================================*/

.product-group { margin-bottom: 30px; }
.product-group h2 { font-size: var(--fs-lead); margin: 0 0 var(--sp-3); }
.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--sp-3); }
/* Was `.product`, which the storm page uses for a rendered graphic's frame. */
.prodcode { gap: 7px; padding: 14px var(--sp-4); background: var(--paper); }
.product-head { display: flex; gap: 9px; align-items: baseline; flex-wrap: wrap; }
.product-code { font-family: var(--font-mono); font-weight: 600; font-size: var(--fs-bulletin); color: var(--ink); background: var(--wash); padding: 1px 7px; }
.product-name { font-size: var(--fs-bulletin); color: var(--muted); }
.product-plain { margin: 0; font-size: var(--fs-bulletin); line-height: 1.5; color: var(--muted); }
.product-link { font-size: var(--fs-bulletin); font-family: var(--font-body); font-weight: 600; margin-top: 2px; }

/* Try page */
.try-form { display: flex; gap: var(--sp-3); flex-wrap: wrap; align-items: flex-start; margin: var(--sp-6) 0; }
.field {
  display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-bulletin); color: var(--muted);
  /* A field may never be wider than the column it is in: the endpoint select painted
     711px wide inside a 320px main and was clipped rather than scrolled (audit). */
  min-width: 0; max-width: 100%;
}
.field > span, .field > label { font-family: var(--font-body); font-weight: 600; color: var(--ink-2); }
.field--grow { flex: 1 1 320px; }
.field input, .field select {
  font: inherit; font-size: var(--fs-bulletin); padding: var(--sp-2) 10px; min-height: 38px;
  border: 1px solid var(--edge); background: var(--paper); color: var(--ink);
  width: 100%; min-width: 0; max-width: 100%;
}
.field select { width: auto; min-width: min(180px, 100%); }
/* Invalid by weight and a marker, not a hue: a 2px ink boundary and a "!" hint. */
.field input[aria-invalid="true"] { border-color: var(--ink); border-width: 2px; }
.field-hint { margin: 0; font-size: var(--fs-bulletin); font-family: var(--font-body); font-weight: 600; color: var(--ink); }
.field-hint::before { content: "! "; font-family: var(--font-mono); }
.try-form > .btn { margin-top: calc(var(--fs-bulletin) * 1.5 + var(--sp-1)); min-height: 38px; }
.try-status { font-size: var(--fs-bulletin); color: var(--muted); min-height: 1.4em; }
.try-result { min-height: 120px; max-height: 560px; overflow: auto; font-size: var(--fs-bulletin); }
/* Until the first response the box says what it is for, in the interface face. */
.try-result--empty { color: var(--muted); font-family: var(--font-body); }

/* ============================================================================
   SDM feed & message card
   ==========================================================================*/

/* The feed opens with the dashboard as one compact row and the explanation folded, so
   the first message is in the first viewport. */
.dashboard-wrap--compact { padding: var(--sp-5) var(--sp-7) 0; max-width: 1080px; margin-bottom: var(--sp-4); }
.dashboard-wrap--compact .dashboard-head { margin-bottom: var(--sp-2); }
.dashboard-wrap--compact .dashboard-head h2 { font-size: var(--fs-bulletin); font-weight: 700; }
.dashboard--compact .dash-cell { padding: var(--sp-3) var(--sp-4); }
.dashboard--compact .dash-label { margin-bottom: var(--sp-1); }
.dashboard--compact .dash-value { margin: 0; }
.outlook-list--compact { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); }
.outlook-list--compact li { padding: 0; gap: 6px; }
.outlook-list--compact .outlook-day { min-width: 0; }
.sdm-about { padding: 0 var(--sp-7); max-width: 1080px; margin-bottom: var(--sp-2); }
.sdm-about summary {
  cursor: pointer; display: inline-flex; align-items: center; min-height: 28px;
  font-family: var(--font-body); font-weight: 600; font-size: var(--fs-bulletin); color: var(--ink);
}
.sdm-about p {
  font-size: var(--fs-remarks); font-family: var(--font-body); line-height: var(--lh-remarks);
  color: var(--ink-2); max-width: var(--wrap-prose); margin: var(--sp-2) 0 0;
}
.split--sdm { padding-top: 0; }
.freshness { font-size: var(--fs-bulletin); color: var(--muted); margin: 0 0 var(--sp-4); }
.freshness-error { display: block; color: var(--ink); font-weight: 700; margin-top: var(--sp-1); }

.feed { display: flex; flex-direction: column; gap: 10px; }
.feed-item { gap: var(--sp-2); padding: 14px var(--sp-5); background: var(--paper); color: var(--ink); }
.feed-item:hover { text-decoration: none; border-color: var(--ink); }
.feed-item--alert { border-left: 2px solid var(--ink); }
.feed-badges { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.feed-headline { font-family: var(--font-body); font-weight: 600; font-size: var(--fs-lead); line-height: var(--lh-lead); }
.feed-meta {
  display: flex; gap: 7px; flex-wrap: wrap; align-items: center;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-bulletin); color: var(--muted);
}

.message-card { gap: 0; padding: var(--sp-6) var(--sp-7); background: var(--paper); }
.message-card--alert { border-left: 2px solid var(--ink); }
.card-badges { display: flex; gap: 6px; margin-bottom: var(--sp-3); flex-wrap: wrap; }
.card-title { font-family: var(--font-body); font-size: var(--fs-lead); margin: 0 0 var(--sp-2); line-height: 1.15; }
.card-meta { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--fs-bulletin); color: var(--muted); margin: 0 0 var(--sp-1); }
.card-body { margin-top: var(--sp-5); }

.section { border-top: 1px solid var(--divider); padding-top: var(--sp-5); margin-top: var(--sp-5); }
.card-body > .section:first-child { border-top: none; margin-top: 0; padding-top: 2px; }
.section-title { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; margin: 0 0 9px; }
.section-kind {
  font-size: var(--fs-micro); font-weight: 600; letter-spacing: 0;
  text-transform: none; background: var(--wash); color: var(--ink);
  padding: 3px 9px; font-weight: 600;
}
.section-heading { font-size: var(--fs-bulletin); color: var(--muted); font-weight: 600; }
.section p { font-size: var(--fs-remarks); font-family: var(--font-body); margin: 0 0 var(--sp-3); }
.section p:last-child { margin-bottom: 0; }

/* A glossary term inside translated prose. Dotted rather than solid so it never reads as
   a link out of the message. */
.gloss { text-decoration: underline dotted; text-underline-offset: 3px; color: inherit; cursor: help; }
.gloss:hover { color: var(--ink); }

/* Invariant 3, corollary A10: AI-generated text is display-layer only, is labelled as AI,
   and the original stays one click away — `.raw-details` below is that click. */
.ai-note {
  font-size: var(--fs-remarks); font-family: var(--font-body); line-height: var(--lh-remarks);
  color: var(--ink); background: var(--wash); padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--line-strong); margin: var(--sp-3) 0 0;
}

.raw-details { margin-top: var(--sp-6); border-top: 1px solid var(--divider); padding-top: 14px; }
.raw-details summary { cursor: pointer; font-family: var(--font-body); font-size: var(--fs-bulletin); font-weight: 600; color: var(--ink); min-height: 28px; }
.raw-note { font-size: var(--fs-remarks); font-family: var(--font-body); color: var(--muted); margin: 10px 0; }
.raw-text { font-size: var(--fs-bulletin); line-height: 1.5; white-space: pre-wrap; word-break: break-word; background: var(--paper); }

/* ============================================================================
   Tables
   ==========================================================================*/

.view table { border-collapse: collapse; width: 100%; font-size: var(--fs-bulletin); }
.view th, .view td { text-align: left; padding: 9px var(--sp-3); border-bottom: 1px solid var(--divider); vertical-align: top; }
.view thead th {
  background: color-mix(in srgb, var(--ink) 4%, transparent);
  font-family: var(--font-body); font-size: var(--fs-bulletin); text-transform: none;
  letter-spacing: 0.05em; color: var(--muted); white-space: nowrap;
}
.view tbody tr:last-child th, .view tbody tr:last-child td { border-bottom: none; }
.station-id { white-space: nowrap; }
.callsign { font-family: var(--font-mono); font-weight: 600; display: block; }
.wmo { font-family: var(--font-mono); font-size: var(--fs-micro); color: var(--muted); }
.raw-status { font-size: var(--fs-bulletin); white-space: nowrap; }
.code-flag { display: inline-block; margin-left: 6px; font-size: var(--fs-bulletin); color: var(--ink); font-weight: 700; background: var(--wash); border: 1px solid var(--ink); padding: 1px 7px; }
.param-table td .muted { display: block; }
.unparsed { margin-top: 10px; font-size: var(--fs-bulletin); }
.unparsed summary { cursor: pointer; color: var(--ink); font-family: var(--font-body); font-weight: 600; }

/* ============================================================================
   Sectors & CWD
   ==========================================================================*/

.sector-block { border-top: 1px solid var(--line); padding: 14px 0; margin-bottom: var(--sp-3); }
.sector-plain { margin: 0 0 10px; font-size: var(--fs-remarks); font-family: var(--font-body); }
.sector-facts, .cwd-facts { display: grid; gap: var(--sp-2) var(--sp-6); grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); margin: 0; }
.sector-facts dt, .cwd-facts dt {
  font-family: var(--font-body); font-size: var(--fs-bulletin); text-transform: none;
  letter-spacing: 0.05em; color: var(--muted); font-weight: 600;
}
.sector-facts dd, .cwd-facts dd { margin: 2px 0 0; font-size: var(--fs-remarks); font-family: var(--font-body); }
.cwd-facts { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 14px 0; }
.map-link { font-size: var(--fs-bulletin); margin-left: var(--sp-2); }

.outlook-list { list-style: none; margin: 0; padding: 0; font-size: var(--fs-bulletin); }
.outlook-list li { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-1) 10px; padding: var(--sp-1) 0; }
.outlook-list--inline { margin-top: var(--sp-3); }
.outlook-day { min-width: 84px; font-family: var(--font-body); font-weight: 600; }

/* ============================================================================
   Glossary
   ==========================================================================*/

.glossary-section { scroll-margin-top: var(--sp-4); margin-bottom: 30px; }
.glossary-section > h2 { font-size: var(--fs-lead); margin: 0 0 var(--sp-1); }
.glossary-section > p { font-size: var(--fs-remarks); font-family: var(--font-body); color: var(--muted); max-width: 72ch; }
.glossary { margin: 0; }
.glossary-entry { padding: 15px 0; border-bottom: 1px solid var(--divider); scroll-margin-top: var(--sp-4); }
.glossary-entry:target { background: var(--wash-strong); padding-left: var(--sp-3); padding-right: var(--sp-3); border-bottom-color: transparent; }
.glossary-entry dt { font-family: var(--font-body); font-weight: 600; font-size: var(--fs-lead); margin-bottom: 5px; }
.glossary-entry dd { margin: 0; max-width: 72ch; }
.glossary-short { font-weight: 500; margin: 0 0 6px; font-size: var(--fs-remarks); font-family: var(--font-body); }
.glossary-entry dd p:last-child { margin: 0; font-size: var(--fs-remarks); font-family: var(--font-body); color: var(--muted); line-height: 1.55; }
.aliases { font-weight: 400; font-size: var(--fs-bulletin); color: var(--muted); font-family: var(--font-body); margin-left: 6px; }
/* Was `.provenance`, which the storm page uses for its source-tracing table. */
.gloss-provenance { font-style: italic; }

/* ============================================================================
   Responsive
   ==========================================================================*/

@media (max-width: 900px) {
  .subrail--sticky { position: static; max-height: none; }
  .split--glossary, .split--products, .split--concepts, .split--sdm { grid-template-columns: 1fr; }
  .subrail { padding: var(--sp-5) var(--sp-6) var(--sp-1); }
  .facet-group { flex-flow: row wrap; }
  .facet { border: 1px solid var(--divider); }
  /* Where the facets have a <select> twin, the links give way to it: a stack of boxes
     above the first entry was the finding. The SDM rail has no twin and keeps its rows. */
  .facet-group--links { display: none; }
  .facet-select { display: flex; }
  .facet-bar { position: static; padding-inline: var(--sp-6); }

  .dashboard-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dash-cell:nth-child(2n) { border-right: 0; }
  .dash-cell:nth-child(-n + 2) { border-bottom: 1px solid var(--divider); }

  .view, .dashboard-wrap--compact, .sdm-about { padding-left: var(--sp-6); padding-right: var(--sp-6); }
}

@media (max-width: 560px) {
  .dashboard-grid { grid-template-columns: 1fr; }
  .dash-cell { border-right: 0; border-bottom: 1px solid var(--divider); }
  .dash-cell:last-child { border-bottom: 0; }
  .view, .dashboard-wrap--compact, .sdm-about { padding-left: var(--sp-4); padding-right: var(--sp-4); }
  .facet-bar { padding-inline: var(--sp-4); }
}

@media print {
  .raw-details[open] { display: block; }
  .box { border: 1px solid var(--line-strong); }
}

/* ============================================================================
   Weather Hub NWS surfaces (WH-P3)

   The NWS Guide keeps its task-first reading and reference layouts. These rules connect
   those layouts to the shared sky/aqua vocabulary without turning endpoint catalogs,
   glossary entries or original SDM messages into decorative marketing cards.
   ==========================================================================*/

body[data-page="nws"] .stage { background: var(--paper); }
body[data-page="nws"] .pagehead-title { color: var(--link); }
body[data-page="nws"] .panel--nav { background: color-mix(in srgb, var(--intro) 55%, var(--surface)); }
body[data-page="nws"] .panel-divider { background: var(--line); }
body[data-page="nws"] .mini-card { background: var(--briefing); border-color: transparent; border-radius: var(--radius-surface); }

.view { padding-top: var(--sp-7); }
.view--home { max-width: 1160px; }
.home-title {
  color: var(--link);
  font-size: var(--fs-title);
  font-weight: 800;
  letter-spacing: -0.035em;
  max-width: 24ch;
  margin-top: 0;
}
.home-lede { font-size: var(--fs-lead); }
.home-search,
.topsearch-input,
.home-search-input { border-radius: var(--radius-control); }

.task-grid { gap: var(--sp-4); }
.task {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr);
  column-gap: var(--sp-3);
  align-content: start;
  background: var(--briefing);
  border: 0;
  border-radius: var(--radius-surface);
  padding: var(--sp-5);
}
.task:nth-child(3n + 2) { background: var(--intro); }
.task:nth-child(3n) { background: var(--archive); }
.task-ico { grid-row: 1 / span 2; color: var(--teal); }
.task-title { margin-top: 0; }
.task-title a { color: var(--link); }

.dashboard,
.feed-item,
.message-card,
.endpoint,
.prodcode,
.cat-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-surface);
}
.dashboard { overflow: hidden; }
.dashboard-wrap--compact .dashboard { background: var(--briefing); border-color: transparent; }
.dash-cell { background: transparent; }
.feed { gap: var(--sp-3); }
.feed-item { padding: var(--sp-4) var(--sp-5); }
.feed-item:hover,
.endpoint:hover,
.prodcode:hover,
.cat-card:hover { border-color: var(--teal); }
.feed-item--alert,
.message-card--alert { border-left-width: 1px; border-color: var(--edge); }
.feed-headline,
.card-title { color: var(--ink); }
.message-card { padding: clamp(20px, 3vw, 36px); }
.section-kind { background: var(--briefing); border-radius: var(--radius-control); color: var(--teal); }
.ai-note { background: var(--archive); border: 0; border-radius: var(--radius-surface); }
.raw-text,
.try-result,
.code-dark { background: #102a43; color: #f6fafd; border-radius: var(--radius-surface); }

.facet-bar { background: color-mix(in srgb, var(--paper) 94%, transparent); backdrop-filter: blur(8px); }
.facet[aria-current="true"],
.toc-link[aria-current="true"] { background: var(--briefing); color: var(--ink); }
.method { background: var(--enamel); color: var(--on-enamel); border-radius: var(--radius-control); }
.product-code { background: var(--intro); color: var(--link); border-radius: var(--radius-control); }
.example-body { background: var(--intro); border: 0; border-radius: var(--radius-surface); }
.try-form { background: var(--briefing); border-radius: var(--radius-surface); padding: var(--sp-5); }
.try-form > .btn { align-self: end; }

.glossary-entry { padding-block: var(--sp-5); }
.glossary-entry:target { background: var(--briefing); border-radius: var(--radius-surface); }
.glossary-entry dt { color: var(--link); }
.concept h2 { color: var(--link); }
.chain-num { background: var(--enamel); color: var(--on-enamel); border-radius: var(--radius-control); }
.devband { background: var(--enamel); color: var(--on-enamel); border: 0; border-radius: var(--radius-surface); padding: var(--sp-6); }
.devband code { color: inherit; }

@media (max-width: 900px) {
  .view { padding-top: var(--sp-6); }
  .subrail { background: color-mix(in srgb, var(--intro) 58%, var(--surface)); border-bottom: 1px solid var(--line); }
}
@media (max-width: 560px) {
  .task { grid-template-columns: 28px minmax(0, 1fr); padding: var(--sp-4); }
  .try-form { padding: var(--sp-4); }
}
