/* Tropics overview — the workspace under the title strip.
 *
 * One toolbar, then a map beside a compact list of systems, bounded to the viewport on a
 * desktop so the list scrolls on its own; stacked on a phone. The WebGL map is an
 * enhancement: the static overview stays in the DOM at its own aspect and is the whole
 * product when the map cannot run. Everything here uses the shared token roles; the map
 * plate's own colours (markers, cluster badge, stage ground) are the one deliberate
 * exception, because they sit on imagery rather than on the page. */

/* --- Map plate roles ---------------------------------------------------------------------
   Things drawn on the imagery, not on the page: fixed across themes, as radar.css's
   --radar-* roles are, and kept apart from the interface tokens on purpose (DESIGN.md,
   "Scientific colors and graphics"). The WebGL paint in storm-overview.mjs uses the same
   values; the HTML legend and markers must match it. */
:root {
  --map-plate: #07131f;
  --map-plate-text: #f7fbff;
  --map-track: #007fc4;
  --map-track-focus: rgb(0 127 196 / 42%);
  --map-area: #ffb43c;
  --map-area-fill: rgb(255 180 60 / 28%);
  --map-invest: #ffcf70;
  --map-cluster: #0a6ea6;
  --map-cluster-hover: #085683;
  --map-callout-link: #9fd4ff;
  --map-callout-note: #c3d6e6;
}

/* --- The title strip on this page: one line where the width allows ------------------- */

body[data-page="index"] .pagehead .shell-inner {
  padding-block: var(--sp-4);
}

body[data-page="index"] .pagehead-titles {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--sp-4);
  row-gap: var(--sp-1);
}

body[data-page="index"] .pagehead-sub {
  flex: 1 1 24rem;
  margin: 0;
  max-width: none;
  font-size: var(--fs-remarks);
  line-height: var(--lh-remarks);
}

/* --- The page frame -------------------------------------------------------------------- */

.tropics {
  max-width: var(--wrap-wide);
  margin: 0 auto;
  padding: var(--sp-3) var(--gutter) var(--sp-8);
}

/* --- Toolbar --------------------------------------------------------------------------- */

.tropics-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-4);
  margin-bottom: var(--sp-3);
}

/* Every basin, always, in one order. A chip's count appears when it has storms; an empty
   basin recedes but keeps its place, so the control never rearranges under a reader. */
.tropics-basins {
  flex: 1 1 auto;
}

.tropics-toolbar-aux {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

.tropics-control {
  display: inline-flex;
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
  align-items: center;
  gap: var(--sp-2);
  color: var(--ink-2);
  font-size: var(--fs-bulletin);
}

.tropics-control-label {
  font-weight: 650;
}

.tropics-select {
  min-width: 0;
  max-width: 100%;
  min-height: 2.25rem;
  padding: 0 var(--sp-2);
  border: 1px solid var(--edge);
  border-radius: var(--radius-control);
  color: var(--ink);
  background: var(--surface);
  font: inherit;
  font-size: var(--fs-bulletin);
}

/* The source-status control: a disclosure that reads like the freshness stamp and opens
   into one row per source. The marker is the shared printed one, never colour alone. */
.tropics-sources {
  position: static;
}

.tropics-toolbar {
  position: relative;
}

.tropics-sources:not([open]) > .tropics-sources-body {
  display: none;
}

.tropics-sources-summary {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 2.25rem;
  padding: 0 var(--sp-3);
  border: 1px solid var(--edge);
  border-radius: var(--radius-control);
  color: var(--ink);
  background: var(--surface);
  font-size: var(--fs-bulletin);
  font-weight: 650;
  cursor: pointer;
  list-style: none;
}

.tropics-sources-summary::-webkit-details-marker { display: none; }
.tropics-sources-summary::marker { content: ""; }

/* The state is the word in the control ("Sources current", "JTWC not answering", "No new
   data"); a failure also takes the ink edge and weight, never colour alone. */
.tropics-sources[data-state="degraded"] .tropics-sources-summary,
.tropics-sources[data-state="stale"] .tropics-sources-summary { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); }

/* Display: wind unit and time, folded into one control that names what is set. */
.tropics-display { position: static; }
.tropics-display:not([open]) > .tropics-display-body { display: none; }

.tropics-display-summary {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 2.25rem;
  padding: 0 var(--sp-3);
  border: 1px solid var(--edge);
  border-radius: var(--radius-control);
  color: var(--ink);
  background: var(--surface);
  font-size: var(--fs-bulletin);
  cursor: pointer;
  list-style: none;
}

.tropics-display-summary::-webkit-details-marker { display: none; }
.tropics-display-summary::marker { content: ""; }
.tropics-display-now { color: var(--ink-2); }

.tropics-display-body {
  position: absolute;
  right: 0;
  z-index: 5;
  display: grid;
  gap: var(--sp-3);
  width: min(18rem, 100%);
  box-sizing: border-box;
  margin-top: var(--sp-2);
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-surface);
  background: var(--surface);
  box-shadow: 0 8px 24px rgb(7 19 31 / 14%);
}

.tropics-display-body .tropics-control { justify-content: space-between; }

.tropics-sources-body {
  position: absolute;
  right: 0;
  z-index: 5;
  width: min(26rem, 100%);
  max-width: 100%;
  box-sizing: border-box;
  overflow-wrap: anywhere;
  margin-top: var(--sp-2);
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-surface);
  background: var(--surface);
  box-shadow: 0 8px 24px rgb(7 19 31 / 14%);
  color: var(--ink-2);
  font-size: var(--fs-bulletin);
}

.tropics-sources-lead { margin: 0 0 var(--sp-3); color: var(--ink); font-weight: 650; }
.tropics-sources-list { display: grid; grid-template-columns: minmax(0, max-content) minmax(0, 1fr); gap: var(--sp-1) var(--sp-3); margin: 0; }
.tropics-sources-list dt { font-weight: 650; color: var(--ink); }
.tropics-sources-list dd { margin: 0; }
.tropics-sources-list dd[data-ok="false"] { color: var(--ink); font-weight: 650; }
.tropics-sources-detail { display: block; font-weight: 400; color: var(--ink-2); }
.tropics-sources-note { margin: var(--sp-3) 0 0; font-size: var(--fs-small); }

/* --- Workspace ------------------------------------------------------------------------- */

/* Bounded to the viewport: the page sets --tropics-top to the workspace's own offset once
   it has laid out (tropics-page.mjs), so the frame ends where the viewport does whatever
   the masthead and title strip measured. The list beside the map scrolls on its own. */
.tropics-workspace {
  --tropics-gap: var(--sp-4);
  display: grid;
  grid-template-columns: 20rem minmax(0, 1fr);
  grid-template-areas: "list map";
  gap: var(--tropics-gap);
  align-items: stretch;
  /* Leave a gutter at the bottom of the first-screen workspace. */
  height: calc(100dvh - var(--tropics-top, 180px) - 1rem);
  min-height: 24rem;
}

.storm-overview-map-panel { grid-area: map; }
.tropics-sidebar { grid-area: list; }

.storm-overview-map-panel,
.tropics-sidebar {
  min-width: 0;
  min-height: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-surface);
  background: var(--surface);
}

/* The static overview showing: the row is as tall as the picture at its own aspect, and
   the list beside it is bounded to that height by the page (a `max-height` it measures),
   so the panel never overflows the controls below the workspace. */
.tropics-workspace.is-static {
  height: auto;
  min-height: 0;
  max-height: none;
  align-items: start;
}

.tropics-workspace.is-static .tropics-sidebar {
  align-self: stretch;
}

.tropics-departed { margin-bottom: var(--sp-3); }
.tropics-departed[hidden] { display: none; }

/* --- Map panel ------------------------------------------------------------------------- */

/* Not `overflow: hidden` on the panel itself: the stage clips its own canvas, and a panel
   that clipped would also clip the visually hidden map summary a screen reader relies on.
   The rounded corners are carried by the head and the footer instead. */
.storm-overview-map-panel {
  display: flex;
  flex-direction: column;
}

.storm-overview-map-head { border-radius: var(--radius-surface) var(--radius-surface) 0 0; }
.storm-overview-map-meta { border-radius: 0 0 var(--radius-surface) var(--radius-surface); }

.storm-overview-map-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  background: var(--intro);
  border-bottom: 1px solid var(--line);
}

.storm-overview-map-head h2 {
  margin: 0;
  color: var(--ink);
  font-size: var(--fs-bulletin);
  font-weight: 750;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.storm-overview-map-mode {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-small);
}

.storm-map-basemaps {
  display: flex;
  flex: 0 0 auto;
  gap: var(--sp-1);
  padding: var(--sp-1);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
}

.storm-overview-map-panel:not(.is-live) .storm-map-basemaps {
  display: none;
}

.storm-map-basemaps button {
  min-height: 2rem;
  padding: 0 var(--sp-3);
  border: 0;
  border-radius: 999px;
  color: var(--ink-2);
  background: transparent;
  font: inherit;
  font-size: var(--fs-small);
  font-weight: 750;
  cursor: pointer;
}

.storm-map-basemaps button[aria-pressed="true"] {
  color: var(--on-enamel);
  background: var(--enamel);
}

/* The stage grows to fill the panel while the interactive map is live. In fallback it is
   exactly as tall as the static overview at its own aspect: no frame to fill, no void. */
.storm-overview-stage {
  position: relative;
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: var(--map-plate);
}

.storm-overview-canvas {
  position: absolute;
  inset: 0;
  z-index: 2;
  min-height: 0;
  visibility: hidden;
}

.storm-overview-map-panel.is-live .storm-overview-canvas {
  visibility: visible;
}

.storm-overview-map-panel.is-live .storm-overview-fallback {
  display: none;
}

.storm-overview-map-panel.is-fallback .storm-overview-stage {
  flex: 0 0 auto;
  background: var(--surface);
}

/* Until the map has decided — the panel still `is-fallback`, the workspace not yet
   `is-static` — the workspace is bounded to the viewport, so the picture is contained in
   the stage at its own aspect, scaled to fit, rather than running out of the panel and under
   the controls below for the second the map takes to load. Once the map is known to be
   unavailable the workspace takes the picture's own height instead (`.is-static`, above). */
.tropics-workspace:not(.is-static) .storm-overview-map-panel.is-fallback :is(.storm-overview-stage, .storm-overview-fallback, .storm-overview-fallback .overview-map, .storm-overview-fallback .product-figure, .storm-overview-fallback .product-open, .storm-overview-fallback picture) {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

.tropics-workspace:not(.is-static) .storm-overview-map-panel.is-fallback .storm-overview-fallback img {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  height: auto;
  object-fit: contain;
}

.storm-overview-fallback {
  position: relative;
  z-index: 1;
}

.storm-overview-fallback .overview-map {
  margin: 0;
  border: 0;
  border-radius: 0;
}

.storm-overview-fallback .product-figure {
  margin: 0;
}

.storm-overview-fallback .product-open {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: zoom-in;
}

.storm-overview-fallback .product-open:focus-visible {
  outline: 3px solid var(--focus-ring, var(--link));
  outline-offset: -3px;
}

.storm-overview-fallback :is(picture, img) {
  display: block;
  width: 100%;
  height: auto;
}

.storm-overview-fallback .freshness--attached {
  margin: 0;
  padding: var(--sp-2) var(--sp-4);
  border-bottom: 1px solid var(--line);
}

/* The caption strip under the picture is the shared component's (styles.css
   `.product-actions`): its own ground and ink, measured there. Nothing is restyled here. */

/* Below the fallback image the panel is done: the footer sits directly under it. */
.storm-overview-map-panel.is-fallback .storm-map-gesture {
  display: none;
}

/* A <footer> of the panel, not the page's: the site footer's top margin (shell.css) is not
   its to inherit, and left a 44px empty band between the map and its legend. */
.storm-overview-map-meta {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-4);
  padding: var(--sp-2) var(--sp-4);
  color: var(--ink-2);
  background: var(--surface);
  border-top: 1px solid var(--line);
  font-size: var(--fs-small);
}

.storm-map-legend,
.storm-map-live-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
}

/* A touch target, not a 21px line of text beside the gesture hint (WCAG 2.2 target size). The
   padding is taken back by the margin, so the footer, and with it the map above, keeps its size. */
.storm-map-live-actions a {
  display: inline-block;
  padding-block: 11px;
  margin-block: -11px;
}

.storm-map-legend span {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
}

.storm-map-key {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  background: var(--map-plate-text);
  border: 3px solid var(--map-track);
  box-sizing: border-box;
}

.storm-map-key--area {
  border: 2px solid var(--map-area);
  background: var(--map-area-fill);
}

.storm-map-failure,
.storm-map-status {
  margin: 0;
  padding: var(--sp-2) var(--sp-4);
  color: var(--ink);
  background: var(--archive);
  border-top: 1px solid var(--edge);
  font-size: var(--fs-small);
}

.storm-map-status {
  color: var(--ink-2);
  background: var(--briefing);
}

.storm-map-failure[hidden],
.storm-map-status[hidden] {
  display: none;
}

/* --- Markers and clusters (map plate colours) ------------------------------------------- */

.storm-map-marker {
  display: inline-flex;
  align-items: center;
  min-height: 1.75rem;
  max-width: 11rem;
  padding: 0.22rem 0.5rem;
  border: 1px solid rgb(255 255 255 / 55%);
  border-radius: 999px;
  color: #fff;
  background: color-mix(in srgb, var(--map-plate) 88%, transparent);
  box-shadow: 0 2px 8px rgb(0 0 0 / 35%);
  font: 750 var(--fs-micro)/1.15 var(--font-body, sans-serif);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  transform-origin: left center;
  transition: transform 120ms ease, background-color 120ms ease;
}

.storm-map-marker--invest {
  border-color: var(--map-invest);
}

.storm-map-marker:is(:hover, :focus-visible, .is-map-selected, .is-map-current) {
  z-index: 3;
  color: var(--map-plate);
  background: #fff;
  border-color: #fff;
  outline: 3px solid var(--map-track-focus);
  transform: scale(1.06);
}

.storm-map-marker.is-map-current {
  outline-color: var(--map-invest);
}

/* Overlapping markers merge into this badge rather than stacking illegible text; it opens a
   plain list of the storms/areas it stands in for. */
.storm-map-cluster {
  display: inline-flex;
  align-items: center;
  min-width: 2.5rem;
  min-height: 2.5rem;
  padding: 0 0.6rem;
  border: 2px solid #fff;
  border-radius: 999px;
  color: #fff;
  /* White text on #007fc4 is 4.35:1, under the AA floor; this is the map's own darker step
     of the same blue, not the page's action token (test_contrast.py measures it). */
  background: var(--map-cluster);
  box-shadow: 0 2px 10px rgb(0 0 0 / 45%);
  font: 800 0.78rem/1 var(--font-body, sans-serif);
  cursor: pointer;
}

.storm-map-cluster:is(:hover, :focus-visible) {
  background: var(--map-cluster-hover);
  outline: 3px solid var(--map-track-focus);
}

.storm-map-cluster-list {
  color: var(--map-plate-text);
}

.storm-map-cluster-list p {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-remarks);
  font-weight: 750;
}

.storm-map-cluster-list ul {
  display: grid;
  gap: var(--sp-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.storm-map-cluster-list :is(a, button) {
  color: var(--map-callout-link);
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

.storm-map-cluster-hint {
  margin: var(--sp-2) 0 0;
  padding-top: var(--sp-2);
  border-top: 1px solid rgb(255 255 255 / 18%);
  color: var(--map-callout-note);
  font-size: var(--fs-small);
  font-weight: 400;
}

.storm-map-cluster-popup .maplibregl-popup-content {
  background: var(--map-plate);
  border-radius: var(--radius-control);
  padding: var(--sp-3) var(--sp-4);
  box-shadow: 0 6px 18px rgb(0 0 0 / 45%);
}

.storm-map-cluster-popup .maplibregl-popup-tip {
  border-top-color: var(--map-plate);
  border-bottom-color: var(--map-plate);
}

/* --- Sidebar ---------------------------------------------------------------------------- */

/* The sidebar's scroll area is its own child; the aside itself does not clip, so nothing a
   reader can scroll to is ever "clipped" by an ancestor. */
.tropics-sidebar {
  display: flex;
  flex-direction: column;
}

.tropics-sidebar-scroll,
.tropics-preview {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.tropics-sidebar-scroll[hidden],
.tropics-preview[hidden] {
  display: none;
}

.tropics-list,
.tropics-dev {
  padding: var(--sp-3) var(--sp-4);
}

.tropics-dev {
  border-top: 1px solid var(--line);
  background: var(--intro);
}

.tropics-list-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}

.tropics-list-title {
  margin: 0 0 var(--sp-2);
  color: var(--ink);
  font-size: var(--fs-bulletin);
  font-weight: 750;
  letter-spacing: 0.01em;
}

.tropics-list-head .tropics-list-title { margin-bottom: 0; }

.tropics-count {
  display: inline-block;
  min-width: 1.4em;
  padding: 0 0.4em;
  border-radius: 999px;
  background: var(--enamel-wash);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  text-align: center;
  vertical-align: 0.1em;
}

.tropics-control--sort .tropics-select { min-height: 2rem; font-size: var(--fs-small); }

.tropics-rows {
  display: grid;
  gap: var(--sp-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A compact record: name and class, the wind and its direction, the product's age and what
   changed, and a badge only where a watch or warning is verified. The whole row is the
   control that opens the preview. */
.tropics-row-button {
  position: relative;
  display: grid;
  gap: 2px;
  width: 100%;
  padding: var(--sp-2) calc(var(--sp-3) + 1.25rem) var(--sp-2) var(--sp-3);
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.tropics-row-button:hover,
.tropics-row.is-map-selected .tropics-row-button {
  background: var(--enamel-wash);
  border-color: var(--line);
}

.tropics-row-button:focus-visible {
  outline: 3px solid var(--focus-ring, var(--link));
  outline-offset: 1px;
}

.tropics-row.is-selected .tropics-row-button {
  border-color: var(--link);
  box-shadow: inset 3px 0 0 var(--link);
}

.tropics-row-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

.tropics-row-name {
  font-weight: 750;
  font-size: var(--fs-remarks);
  color: var(--ink);
}

.tropics-row-button:hover .tropics-row-name {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.tropics-row-chevron {
  position: absolute;
  top: 50%;
  right: var(--sp-3);
  width: 1rem;
  height: 1rem;
  color: var(--ink-2);
  transform: translateY(-50%);
}

.tropics-row-button:hover .tropics-row-chevron { color: var(--link); }

.row-agency {
  padding: 0.1rem 0.4rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-2);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.02em;
}

.tropics-row-wind {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-3);
}

.tropics-row-value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-remarks);
  font-weight: 600;
}

.tropics-row-dir,
.tropics-row-change,
.tropics-row-age,
.tropics-row-note {
  color: var(--ink-2);
  font-size: var(--fs-small);
}

.tropics-row-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
}

.tropics-row-age { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.tropics-state--aging { color: var(--ink); font-weight: 650; }
.tropics-arrow { display: inline-block; min-width: 1em; margin-right: 0.2em; font-family: var(--font-mono); }
.tropics-dir--up .tropics-arrow, .tropics-dir--down .tropics-arrow { color: var(--ink); font-weight: 700; }

/* The badge means "a centre has this in effect and we read it". Its ground is the shared
   alarm-free ink; the kind is spelled out, never a colour alone. */
.tropics-badge {
  display: inline-block;
  justify-self: start;
  margin-top: 2px;
  padding: 2px var(--sp-2);
  border-radius: var(--radius-node);
  background: var(--ink);
  color: var(--paper);
  font-size: var(--fs-micro);
  font-weight: 750;
  letter-spacing: 0.01em;
}

.tropics-badge--watch {
  background: transparent;
  color: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--ink);
}

.tropics-empty {
  margin: 0;
  padding: var(--sp-3);
  border: 1px dashed var(--line);
  border-radius: var(--radius-control);
  color: var(--ink-2);
  font-size: var(--fs-bulletin);
}

.tropics-empty[data-state="unavailable"] {
  border-style: solid;
  border-color: var(--edge);
  color: var(--ink);
  font-weight: 600;
}

.tropics-dev-note,
.tropics-fine {
  margin: var(--sp-2) 0 0;
  color: var(--ink-2);
  font-size: var(--fs-small);
  line-height: 1.45;
}

.systems-table .invest-risk,
.tropics-row .invest-risk {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--muted);
}

.tropics-row .invest-risk.risk-high { background: #e0483a; }
.tropics-row .invest-risk.risk-medium { background: #f2a53b; }
.tropics-row .invest-risk.risk-low { background: #e6cf45; }
.tropics-row .invest-risk.risk-unknown { background: #93a4b5; }

/* --- Preview ---------------------------------------------------------------------------- */

.tropics-preview {
  padding: var(--sp-3) var(--sp-4) var(--sp-5);
}

.tropics-back {
  margin-bottom: var(--sp-3);
}

.tropics-preview-head {
  display: grid;
  gap: var(--sp-1);
  margin-bottom: var(--sp-3);
}

.tropics-preview-kicker { margin: 0; }
.tropics-preview-title {
  margin: 0;
  color: var(--ink);
  font-size: var(--fs-lead);
  font-weight: 800;
  letter-spacing: -0.02em;
}
.tropics-preview-title:focus { outline: none; }
/* Five tabs, an underline for the selected one, and a word never broken across lines: one row
   where the panel allows it, three and two below that (TW-9), and whole tabs onto a second row
   when enlarged text needs it (TW-13). Never a sideways strip. */
.tropics-preview-body { container: tropics-panel / inline-size; }
.tropics-tabs { display: flex; flex-wrap: wrap; gap: 0; border-bottom: 1px solid var(--line); margin-block: var(--sp-2) var(--sp-3); }
.tropics-tabs button { flex: 1 1 auto; min-width: 0; min-height: 44px; border: 0; border-bottom: 3px solid transparent; background: transparent; color: var(--ink-2); padding: 8px 5px; font: 700 .8125rem/1.3 Manrope, sans-serif; white-space: nowrap; cursor: pointer; }
.tropics-tabs button:hover { color: var(--ink); }
.tropics-tabs button[aria-selected="true"] { color: var(--tw-selected, var(--link)); border-bottom-color: var(--tw-selected, var(--link)); }
.tropics-tabs button:focus-visible { outline: var(--focus-ring); outline-offset: -3px; }
@container tropics-panel (max-width: 19.75rem) {
  .tropics-tabs { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .tropics-tabs button { grid-column: span 2; }
  .tropics-tabs button:nth-child(n + 4) { grid-column: span 3; }
}
.tropics-tab-panel[hidden], .tropics-model-summary[hidden] { display: none; }
.tropics-tab-panel { min-width: 0; }
.tropics-genesis summary { min-height: 44px; padding-block: 10px; cursor: pointer; }
/* Its summary is the section's heading: no second rule or heading under it (TW-12). */
.tropics-genesis .tropics-guidance { margin-top: 0; padding-top: 0; border-top: 0; }
.tropics-tab-panel h3 { margin: 12px 0 8px; font-size: 1rem; }
.tropics-official-switches { display: flex; flex-wrap: wrap; gap: 6px; }
.tropics-official-switches button, [data-detail-layer="models"], .storm-guidance-policies button { min-height: 44px; border: 1px solid var(--edge); border-radius: 6px; background: var(--surface); color: var(--ink); padding: 6px 10px; font: inherit; cursor: pointer; }
.tropics-official-switches button[aria-pressed="true"], [data-detail-layer="models"][aria-pressed="true"], .storm-guidance-policies button[aria-pressed="true"] { background: var(--enamel); color: var(--on-enamel); }
.tropics-current-facts { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: .875rem; }
.tropics-advisory-time { margin: 6px 0 0; }
.tropics-advisory-time .tropics-clock { display: block; }
.tropics-data-details { border-top: 1px solid var(--line); margin-top: 12px; padding-block: 8px; }
.tropics-data-details summary { min-height: 44px; display: flex; align-items: center; cursor: pointer; }
.tropics-record-links { display: flex; flex-wrap: wrap; gap: 10px; font-size: .875rem; }
.tropics-forecast-points { list-style: none; margin: 0; padding: 0; }
.tropics-forecast-points li { display: grid; gap: 2px; padding-block: 8px; border-bottom: 1px solid var(--line); font-size: .875rem; }
.tropics-share-output { flex-basis: 100%; width: 100%; }
.tropics-share-output input { width: 100%; min-width: 0; font: inherit; }
.storm-guidance-legend { display: flex; flex-wrap: wrap; gap: 6px 12px; font-size: .75rem; }
.storm-guidance-key { width: 24px; height: 6px; margin-right: 4px; }
.storm-guidance-policies { display: flex; gap: 6px; flex-wrap: wrap; }
.tropics-model-summary { border-left: 3px solid var(--edge); padding-left: 8px; margin-block: 8px; }
.tropics-preview-title:focus-visible { outline: 3px solid var(--focus-ring, var(--link)); outline-offset: 2px; }
.tropics-preview-where { margin: 0; color: var(--ink-2); font-size: var(--fs-bulletin); }
.tropics-open { justify-self: start; margin-top: var(--sp-1); }

/* --- Comparison table, ended shelf, notice ------------------------------------------------ */

.tropics-compare {
  margin-top: var(--sp-4);
}

.tropics-compare[hidden] { display: none; }

.tropics-compare-summary {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 2.25rem;
  padding: 0 var(--sp-3);
  border: 1px solid var(--edge);
  border-radius: var(--radius-control);
  color: var(--link);
  background: var(--surface);
  font-weight: 650;
  cursor: pointer;
}

.tropics-compare[open] .tropics-compare-summary { margin-bottom: var(--sp-3); }

.tropics-compare .systems-scroll { margin-bottom: 0; }
.tropics-compare-table td { white-space: normal; }
.tropics-compare-table td:first-child { white-space: nowrap; }

.tropics-sort-button {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  cursor: pointer;
}

th[aria-sort="descending"] .tropics-sort-button::after { content: " ↓"; }
th[aria-sort="ascending"] .tropics-sort-button::after { content: " ↑"; }

.tropics-ended {
  margin-top: var(--sp-6);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--divider);
}

.tropics-ended .readout-head { margin-top: 0; }

.tropics-notice {
  margin-top: var(--sp-4);
  color: var(--ink-2);
  font-size: var(--fs-small);
}

.tropics-notice > .updated--limits { margin: 0; }

/* Folded detail: the official bulletin under the parsed watch list, and the basin rule under
   the limits line. One click away and never gone; the summary is a 24px target. */
.tropics-official,
.tropics-basin-rule { margin-top: var(--sp-2); }

.tropics-official > summary,
.tropics-basin-rule > summary {
  display: inline-flex;
  align-items: center;
  min-height: 1.5rem;
  color: var(--link);
  font-size: var(--fs-small);
  font-weight: 650;
  cursor: pointer;
}

.tropics-official > summary:focus-visible,
.tropics-basin-rule > summary:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }

.tropics-official-text {
  margin: var(--sp-2) 0 0;
  white-space: pre-line;
  color: var(--ink-2);
  font-size: var(--fs-small);
  line-height: 1.45;
}

.tropics-basin-rule > p { max-width: 68ch; margin: var(--sp-1) 0 0; line-height: 1.5; }

.tropics-notice-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-4);
  margin: var(--sp-2) 0 0;
}

.tropics-notice-links a {
  display: inline-flex;
  align-items: center;
  min-height: 1.5rem;
  font-weight: 600;
}

/* Said only when the map is the static one; the live map needs no label. */
.storm-overview-map-mode:empty { display: none; }

.storm-map-visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0 0 0 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* --- Skeleton ------------------------------------------------------------------------- */

.skeleton--toolbar { height: 44px; margin-bottom: var(--sp-3); }

.skeleton--workspace {
  display: grid;
  grid-template-columns: 20rem minmax(0, 1fr);
  grid-template-areas: "list map";
  gap: var(--sp-4);
  height: calc(100dvh - 153px - 1rem);
  min-height: 24rem;
}

.skeleton--workspace .skeleton--map { grid-area: map; }
.skeleton--workspace .skeleton--rail { grid-area: list; }

.skeleton--workspace .skeleton--map,
.skeleton--workspace .skeleton--rail {
  height: 100%;
  min-height: 0;
  aspect-ratio: auto;
  margin: 0;
}

/* --- Widths ----------------------------------------------------------------------------- */

/* Where the list scrolls inside a bounded frame (a desktop), a soft edge says there is more
   below or above; the shadows ride the scroll and the covers ride the content. */
@media (min-width: 900px) {
  .tropics-sidebar-scroll,
  .tropics-preview {
    background:
      linear-gradient(var(--surface) 30%, transparent) center top / 100% 2.5rem no-repeat local,
      linear-gradient(transparent, var(--surface) 70%) center bottom / 100% 2.5rem no-repeat local,
      radial-gradient(farthest-side at 50% 0, rgb(7 19 31 / 22%), transparent) center top / 100% 0.75rem no-repeat scroll,
      radial-gradient(farthest-side at 50% 100%, rgb(7 19 31 / 22%), transparent) center bottom / 100% 0.75rem no-repeat scroll;
    background-color: var(--surface);
    border-radius: var(--radius-surface);
  }
}

@media (max-width: 1199px) {
  .tropics-workspace,
  .skeleton--workspace {
    grid-template-columns: 19rem minmax(0, 1fr);
  }
}

@media (max-width: 899px) {
  .tropics-workspace,
  .skeleton--workspace {
    grid-template-columns: 1fr;
    /* The phone layout below places the map above the systems panel. */
    grid-template-areas: none;
    height: auto;
    max-height: none;
    min-height: 0;
  }

  .storm-overview-map-panel,
  .tropics-sidebar,
  .skeleton--workspace .skeleton--map,
  .skeleton--workspace .skeleton--rail { grid-area: auto; }

  .skeleton--workspace .skeleton--map { aspect-ratio: 1.6; height: auto; }
  .skeleton--workspace .skeleton--rail { height: 20rem; }

  .storm-overview-map-panel.is-live .storm-overview-stage {
    min-height: 20rem;
    aspect-ratio: 1.15;
    flex: 0 0 auto;
  }

  .tropics-sidebar {
    overflow: visible;
  }

  .tropics-sidebar-scroll,
  .tropics-preview {
    overflow: visible;
  }

  .tropics-toolbar { align-items: flex-start; }
  .tropics-toolbar-aux { width: 100%; justify-content: flex-start; }
  .tropics-sources-body { right: 0; left: 0; width: 100%; }
}

@media (max-width: 639px) {
  .storm-overview-map-head { flex-wrap: wrap; }
  .storm-map-basemaps { width: 100%; }
  .storm-map-basemaps button { flex: 1; min-height: 2.5rem; }
  .tropics-list, .tropics-dev, .tropics-preview { padding-inline: var(--sp-3); }
  .tropics-facts { grid-template-columns: 1fr; gap: 0; }
  .tropics-facts dt { margin-top: var(--sp-2); }
}

@media (pointer: coarse) {
  .tropics-row-button { padding-block: var(--sp-3); }
  .tropics-select, .tropics-sources-summary, .tropics-display-summary, .tropics-compare-summary { min-height: 2.75rem; }
  .tropics-location .tropics-linkbutton { min-height: 2.75rem; }
}

@media (prefers-reduced-motion: reduce) {
  .storm-map-marker { transition: none; }
}

/* The page's answer, visible (TW-13; TW-1 had hidden it from sighted readers): the title,
   the sentence that says what is active, how current it is, and whether NWS's alerts could be
   read. One line on a desktop, aligned with the workspace's own edges below it, on the sky
   field the masthead starts. Stale and unreachable reverse, as everywhere on the site. */
body[data-tropics-workspace] .tropics-page-summary .shell-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-4);
  width: 100%;
  max-width: none;
  box-sizing: border-box;
  padding: var(--sp-3) var(--sp-4) var(--sp-2);
}
body[data-tropics-workspace] .tropics-page-summary .pagehead-title {
  flex: 0 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: var(--fs-subhead);
  line-height: var(--lh-lead);
  letter-spacing: -0.02em;
}
body[data-tropics-workspace] .tropics-page-summary .pagehead-sub {
  flex: 1 1 22rem;
  min-width: 0;
  margin: 0;
  max-width: none;
  color: var(--ink);
  font-size: var(--fs-remarks);
  font-weight: 650;
  line-height: var(--lh-lead);
}
body[data-tropics-workspace] .tropics-page-summary .pagehead-meta {
  flex: 0 1 auto;
  margin: 0 0 0 auto;
  text-align: left;
  font-size: var(--fs-small);
}
@media (min-width: 900px) {
  body[data-tropics-workspace] .tropics-page-summary .pagehead-meta:empty { display: none; }
}
body[data-tropics-workspace] .tropics-page-summary .pagehead-meta .freshness { font-size: var(--fs-small); }
body[data-tropics-workspace] .tropics-page-summary .pagehead-meta .freshness--attached {
  display: inline-flex;
  padding: 2px var(--sp-2);
  border-radius: var(--radius-control);
}
@media (max-width: 899px) {
  body[data-tropics-workspace] .tropics-page-summary .shell-inner { padding-inline: 18px; gap: 2px var(--sp-3); }
  /* Lines reserved from the first paint, so the sentence and the clock arriving never move the
     page under them: two for the sentence, two for the stamp (a stale one is reversed and long). */
  body[data-tropics-workspace] .tropics-page-summary .pagehead-sub { flex-basis: 100%; min-height: calc(2 * var(--lh-lead) * var(--fs-remarks)); }
  body[data-tropics-workspace] .tropics-page-summary .pagehead-meta { flex: 1 1 100%; margin-left: 0; min-height: calc(3 * var(--fs-small) + 2 * var(--sp-1)); }
  body[data-tropics-workspace] .tropics-page-summary .pagehead-meta .freshness:not(.freshness--attached) { flex-wrap: wrap; column-gap: var(--sp-2); }
}

/* The skip link's target is the panel, whatever it shows (TW-13). */
.tropics-sidebar:focus { outline: none; }
.tropics-sidebar:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

/* Without scripts: the sentence and where to go, inside the page's gutters. */
.tropics-noscript { margin: var(--sp-4) var(--sp-4) 0; }
.tropics-noscript p { max-width: var(--wrap-prose); }
@media (max-width: 899px) { .tropics-noscript { margin-inline: 18px; } }
.tropics { max-width: none; padding-block: var(--sp-3); }
.tropics-toolbar { gap: var(--sp-2); align-items: center; }
.tropics-basins { min-width: 0; flex: 0 1 20rem; }
.tropics-basin-select { width: 100%; min-height: 44px; font-weight: 700; }
.tropics-toolbar-aux { flex: 1 1 auto; gap: var(--sp-2); align-items: center; }
.tropics-action,
.tropics-reference > summary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 6px var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-small);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
}
.tropics-action[hidden] { display: none; }
.tropics-action:hover { background: var(--enamel-wash); }
.tropics-action:focus-visible,
.tropics-reference > summary:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
.tropics-toolbar .tropics-layers-summary,
.tropics-toolbar .tropics-alerts-summary,
.tropics-display-summary { min-height: 44px; border-radius: var(--radius-control); }
.tropics-toolbar .tropics-layers,
.tropics-display { position: static; }
.tropics-toolbar { position: relative; }
.tropics-toolbar .tropics-layers-body,
.tropics-display-body { right: 0; max-height: 65dvh; overflow-y: auto; }
.tropics-display-body .tropics-sources { margin-top: var(--sp-3); }
.tropics-display-body .tropics-sources-body { position: static; width: auto; box-shadow: none; padding-inline: 0; border: 0; }
.tropics-display-body .storm-map-basemaps { display: flex; flex-wrap: wrap; margin-top: var(--sp-3); }
.tropics-display-body .storm-map-basemaps[hidden] { display: none; }
.tropics-list-head { flex-wrap: wrap; }
.tropics-control--sort { margin-left: auto; }
.tropics-reference { margin-top: var(--sp-3); }
.skeleton--readout { height: 44px; margin-top: var(--sp-3); }
.tropics-reference > summary { list-style: none; }
.tropics-reference > nav { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); margin-block: var(--sp-3); }

@media (max-width: 899px) {
  .tropics-toolbar-aux { width: auto; justify-content: flex-start; flex-wrap: wrap; }
  .tropics-basins { flex-basis: 100%; }
  .skeleton--toolbar { height: 126px; }
}

/* Short viewports use the document's scroll rather than a bounded frame. */
@media (max-height: 540px) {
  .tropics-workspace { height: auto; min-height: 0; }
  .tropics-sidebar { max-height: none !important; overflow: visible; }
  .tropics-sidebar-scroll,
  .tropics-preview { overflow: visible; }
}

/* --- TW-9: panel, toolbar and graphics refinement ------------------------------------------
   Route-scoped roles: the workspace's own panel, text, divider, selection and wash, light and
   dark, without retheming the site. Shared tokens are remapped inside `.tropics` only, so every
   component the workspace uses (menus, rows, the alert list) takes them without a fork. */
body[data-tropics-workspace] {
  --tw-page: #f5f8fc;
  --tw-panel: #ffffff;
  --tw-text: #172b45;
  --tw-text-2: #52647b;
  --tw-divider: #d7e1ec;
  --tw-selected: #0969c8;
  --tw-wash: #e9f3ff;
}
:root[data-theme="dark"] body[data-tropics-workspace],
:root[data-dark]:not([data-theme="light"]) body[data-tropics-workspace] {
  --tw-page: #0d1726;
  --tw-panel: #142338;
  --tw-text: #eaf1f8;
  --tw-text-2: #adbed0;
  --tw-divider: #30445b;
  --tw-selected: #67b6ff;
  --tw-wash: #203d5b;
}
.tropics {
  --surface: var(--tw-panel);
  --ink: var(--tw-text);
  --ink-2: var(--tw-text-2);
  --line: var(--tw-divider);
  --intro: var(--tw-wash);
  --enamel-wash: var(--tw-wash);
  padding-inline: var(--sp-4);
  font-size: 0.9375rem;
}

/* Toolbar: basin and Find a place on the left; freshness, Satellite, Alerts, Layers, Share and
   Settings on the right. Every control is a 44px target. */
.tropics-toolbar { gap: var(--sp-2); padding-block: var(--sp-2); margin-bottom: var(--sp-1); }
.tropics-toolbar-lead { display: flex; flex: 0 1 auto; align-items: center; gap: var(--sp-2); min-width: 0; }
.tropics-basins { flex: 0 1 16rem; }
.tropics-toolbar-aux { justify-content: flex-end; }
.tropics-toolbar :is(.tropics-find-summary, .tropics-display-summary, .tropics-layers-summary, .tropics-alerts-summary) {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font-size: var(--fs-small);
  font-weight: 700;
  justify-content: center;
  min-width: 44px;
  box-sizing: border-box;
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
}
.tropics-toolbar .tropics-find-summary::-webkit-details-marker { display: none; }
.tropics-toolbar .tropics-find-summary::marker { content: ""; }
.tropics-toolbar :is(.tropics-find, .tropics-display)[open] > summary { background: var(--enamel); color: var(--on-enamel); border-color: var(--enamel); }
.tropics-toolbar summary:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
.tropics-find { position: static; }
.tropics-find:not([open]) > .tropics-find-body { display: none; }
.tropics-find-body {
  position: absolute;
  z-index: 9;
  top: calc(100% - var(--sp-1));
  box-sizing: border-box;
  max-height: min(70dvh, 36rem);
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 8px 24px rgb(7 19 31 / 14%);
}
.tropics-find-body { left: 0; width: min(24rem, calc(100vw - 2rem)); padding: var(--sp-2) var(--sp-4) var(--sp-4); }
.tropics-find .tropics-location > h2 {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.tropics-share-status:empty, .tropics-share-output[hidden], .tropics-share-graphic[hidden], .tropics-share-storm[hidden] { display: none; }
.tropics-share-graphic { display: inline-flex; align-items: center; min-height: 44px; font-weight: 700; }
.tropics-share-storm { min-height: 44px; }

/* Desktop geometry: a 360px panel (320px below 1280px), a 12px gap, and the map the rest. */
/* The skeleton takes the same boxes, so the first paint does not shift (renditions.test.ts). */
.skeleton--toolbar { height: 60px; margin-bottom: var(--sp-1); }
@media (min-width: 900px) {
  .skeleton--workspace { height: calc(100dvh - 173px); }
  .tropics-workspace,
  .skeleton--workspace { grid-template-columns: 22.5rem minmax(0, 1fr); gap: 12px; }
  .tropics-workspace { --tropics-gap: 12px; height: calc(100dvh - var(--tropics-top, 180px) - var(--sp-3)); }
}
@media (min-width: 900px) and (max-width: 1279px) {
  .tropics-workspace,
  .skeleton--workspace { grid-template-columns: 20rem minmax(0, 1fr); }
}
.storm-overview-map-panel,
.tropics-sidebar { border-radius: 8px; }

/* The visible heading follows the selected subject and the product actually displayed. */
.tropics-workspace:not(.is-static) .storm-overview-map-head {
  position: relative;
  min-height: 36px;
  padding: var(--sp-1) var(--sp-3);
}
.tropics-workspace:not(.is-static) .storm-overview-map-head h2 { font-size: var(--fs-small); margin: 0; }

/* The basin panel: counted sections, compact rows with one clock, and the alerts in one line. */
.tropics-list, .tropics-dev { padding: var(--sp-3) var(--sp-4); }
.tropics-list-title { font-size: 0.875rem; font-weight: 700; }
.tropics-row-button { min-height: 68px; padding: 10px calc(var(--sp-4) + 1.25rem) 10px var(--sp-3); align-content: center; }
.tropics-row-name { font-size: 1rem; }
.tropics-row-wind { align-items: center; gap: var(--sp-1) var(--sp-2); }
.tropics-row-wind .tropics-badge { margin-top: 0; }
.tropics-row.is-selected .tropics-row-button { border-color: var(--tw-selected); box-shadow: inset 3px 0 0 var(--tw-selected); }
.tropics-alert-summary { padding: var(--sp-3) var(--sp-4) var(--sp-4); border-top: 1px solid var(--line); }
.tropics-alert-summary .tropics-list-title { margin-bottom: var(--sp-1); }
.tropics-alert-summary .tropics-fine { margin: 0; }
.tropics-alert-summary-open {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--link);
  font: inherit;
  font-weight: 700;
  text-align: left;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.tropics-alert-summary-open:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
.tropics-alerts-view { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: var(--sp-3) var(--sp-4) var(--sp-5); }
.tropics-alerts-view[hidden] { display: none; }
.tropics-alerts-view .tropics-alerts--sidebar { padding: 0; border-top: 0; }
.tropics-back, .tropics-alerts-back { margin-bottom: var(--sp-1); }

/* The selected storm's header: name, class and authority, wind large, pressure and movement,
   then each clock on its own line. */
.tropics-preview { padding: var(--sp-2) var(--sp-4) var(--sp-5); }
.tropics-preview-head { gap: 2px; margin-bottom: 0; }
.tropics-preview-title { font-size: 1.375rem; font-weight: 800; line-height: 1.2; }
.tropics-preview-authority { color: var(--ink-2); font-size: var(--fs-small); font-weight: 700; }
.tropics-current-facts { align-items: baseline; gap: 0 var(--sp-3); color: var(--ink-2); font-size: 0.875rem; }
.tropics-fact-wind { flex-basis: 100%; color: var(--ink); font-size: 1.5rem; font-weight: 750; line-height: 1.25; }
.tropics-advisory-time { margin-top: 2px; }

/* Overview: trend, the storm's own warnings, NWS's alerts, key messages, then the record. */
.tropics-tab-panel .tropics-preview-section { margin: 0 0 var(--sp-3); }
.tropics-tab-panel .tropics-preview-section > h3 { margin: 0 0 var(--sp-1); font-size: 0.875rem; font-weight: 700; }
.tropics-trend > h3 { display: flex; align-items: baseline; gap: var(--sp-1); font-size: 1rem !important; }
.tropics-trend.tropics-dir--none .tropics-arrow { display: none; }
.tropics-trend-detail { margin: 0; }
.tropics-overview-warnings .tropics-badge-line, .tropics-overview-warnings .tropics-ww-state { margin: 0; }
.tropics-overview-nws { margin: 0 0 var(--sp-3); padding-top: var(--sp-2); border-top: 1px solid var(--line); }
.tropics-tab-panel .tropics-linkbutton { min-height: 44px; }

/* Alerts tab: the storm's own watches and warnings as one card per type, most severe first,
   edged in the colour the map draws that coastline in. The type is written out, so colour
   is never the only cue; a warning's card is tinted and a watch's is plain. Areas are a list
   in the reader's body face, one stretch of coast to a line. */
.tropics-warnings .tropics-ww-list { display: grid; gap: var(--sp-2); margin: var(--sp-2) 0 0; }
.tropics-warnings .tropics-ww {
  padding: var(--sp-2) var(--sp-3) var(--sp-2) calc(var(--sp-3) + 5px);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--surface);
  box-shadow: inset 5px 0 0 var(--ww-color, var(--line-strong));
}
.tropics-warnings .tropics-ww--warning { background: color-mix(in srgb, var(--ww-color, var(--line-strong)) 10%, var(--surface)); }
.tropics-ww-type { display: block; color: var(--ink); font-size: var(--fs-bulletin); font-weight: 750; line-height: 1.3; }
.tropics-ww-areas { margin: var(--sp-1) 0 0; padding: 0 0 0 1.1em; list-style: disc; color: var(--ink); font-size: var(--fs-small); line-height: 1.45; }
.tropics-ww-areas li + li { margin-top: 2px; }
.tropics-ww-areas li::marker { color: var(--ink-2); }
.tropics-warnings > .tropics-fine { margin: var(--sp-2) 0 0; }
/* Impacts read as words, not as product text: the body face, not the monospace. */
.tropics-impacts .tropics-fact-value { font-family: inherit; line-height: 1.45; }
.tropics-impacts .tropics-facts { margin-bottom: 0; }
/* NWS's alerts under the storm's: a heading the size of the tab's others. */
.tropics-alerts.tropics-alerts--storm { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--line); }
.tropics-alerts--storm > .tropics-list-title { margin: 0 0 var(--sp-1); color: var(--ink); font-size: 0.875rem; font-weight: 700; }
.tropics-key-messages { margin: 0; padding-left: 1.25rem; display: grid; gap: var(--sp-1); }
.tropics-record-links { align-items: center; gap: var(--sp-1) var(--sp-4); margin: 0; }
.tropics-record-links a { display: inline-flex; align-items: center; min-height: 44px; font-weight: 700; }
.tropics-open { margin-top: 0; }

/* The official switches in the Layers drawer, shown while a storm is open. */
.tropics-layer-group--official:has(.tropics-official-slot:empty) { display: none; }
.tropics-layer-group--official .tropics-official-switches button[hidden] { display: none; }

/* Forecast tab: one row per official point, Time · Wind · Stage · Position. */
.tropics-forecast-head { display: none; }
@container tropics-panel (min-width: 18rem) {
  .tropics-forecast-head,
  .tropics-forecast-points li { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.1fr); gap: var(--sp-2); align-items: baseline; }
  :is(.tropics-forecast-head, .tropics-forecast-points li) > * { min-width: 0; overflow-wrap: anywhere; }
  .tropics-forecast-head { margin: 0; padding-bottom: var(--sp-1); border-bottom: 1px solid var(--line); color: var(--ink-2); font-size: var(--fs-micro); font-weight: 700; }
  .tropics-forecast-points li .tropics-fine { margin: 0; }
}
.tropics-forecast-stage { color: var(--ink-2); }

/* Single-PR tropical refinement: stable panel navigation and published forecast values. */
.tropics-preview { scrollbar-gutter: stable; }
.tropics-tabs { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); }
.tropics-tabs button { grid-column: span 2; }
.tropics-tabs button:nth-child(n + 4) { grid-column: span 3; }
.tropics-forecast-head,
.tropics-forecast-points li { grid-template-columns: minmax(0, 1.1fr) minmax(0, .8fr) minmax(0, 1fr); }
.tropics-forecast-points--full li { grid-template-columns: 1fr; }
.tropics-forecast-full > summary { min-height: 44px; padding-block: var(--sp-2); cursor: pointer; }
.tropics-model-graphic { display: block; min-height: 44px; padding-block: var(--sp-2); }
.tropics-sheet-controls { display: none; }

/* Phones: the toolbar in two rows, the overflow control at the end of the first (TW-9). The
   workspace's own phone layout, one column in reading order, is TW-13's, at the end of this file. */
@media (max-width: 899px) {
  .tropics-toolbar { padding-block: var(--sp-1); }
  .tropics-toolbar-lead { flex: 1 1 100%; }
  .tropics-basins { flex: 1 1 auto; }
  .tropics-toolbar-aux { flex: 1 1 100%; justify-content: flex-start; gap: var(--sp-1); }
  /* The overflow mark ends the first row, so the second row's width (the Alerts count arrives
     after the first paint) can never wrap it onto a third. */
  .tropics-toolbar-lead { padding-right: calc(44px + var(--sp-2)); }
  .tropics-toolbar .tropics-display { position: absolute; top: var(--sp-1); right: 0; }
  .tropics-toolbar :is(.tropics-find-summary, .tropics-display-summary, .tropics-layers-summary, .tropics-alerts-summary) { padding: 0 10px; }
  .skeleton--toolbar { height: 124px; }
  /* The map's footer in one short line: the gesture hint is what a phone already does. */
  .storm-overview-map-meta { padding-block: var(--sp-1); gap: 0 var(--sp-3); }
  .storm-map-gesture { display: none; }
  .storm-map-legend { gap: var(--sp-1) var(--sp-3); }
}
/* Narrow phones: the basin menu keeps its whole label (the counts are what it is chosen by), so
   Find a place shows its first word, its name whole for assistive technology (TW-12). */
@media (max-width: 599px) {
  .tropics-find-rest { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .tropics-basin-select { font-size: var(--fs-small); }
  /* The first row keeps the second row's 4px rhythm, so the 18px gutters (TW-13) still leave the
     busiest label whole from 360px. */
  .tropics-toolbar-lead { gap: var(--sp-1); padding-right: calc(44px + var(--sp-1)); }
}
@media (max-width: 359px) {
  /* One row of presets: below 360px Wind extent stays in the Layers drawer, where the same
     switch lives, rather than wrapping a second row over the map's markers (TW-12). */
  .tropics-presets .tropics-preset--toggle { display: none; }
  .tropics-toolbar-aux { gap: 4px; }
  .tropics-toolbar :is(.tropics-display-summary, .tropics-layers-summary, .tropics-alerts-summary) { padding: 0 5px; }
}

/* Enlarged text: the document scrolls rather than squeezing the panel and the map into a frame. */
.tropics-workspace.is-large-text { grid-template-rows: auto auto; height: auto; min-height: 0; }
.tropics-workspace.is-large-text .tropics-sidebar { height: auto !important; max-height: none !important; box-shadow: none; }
.tropics-workspace.is-large-text :is(.tropics-sidebar-scroll, .tropics-preview, .tropics-alerts-view) { overflow: visible; }
.tropics-workspace.is-large-text .storm-overview-map-panel .storm-overview-stage { height: 60dvh; min-height: 12rem; flex: 0 0 auto; }

/* --- TW-10: map presets, the active-layer key and each product's clock --------------------
   The selector sits on the map's upper-left edge, apart from the page's toolbar: it changes the
   one map's switches. Plate colours, like the markers', because it sits on imagery. */
.tropics-presets {
  position: absolute;
  z-index: 4;
  top: var(--sp-2);
  left: var(--sp-2);
  right: 3.5rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-2);
  pointer-events: none;
}
.tropics-presets[hidden] { display: none; }
.tropics-presets > * { pointer-events: auto; }
.tropics-preset-group {
  display: inline-flex;
  flex-wrap: wrap;
  max-width: 100%;
  min-width: 0;
  padding: 2px;
  border-radius: 8px;
  background: rgb(7 19 31 / 82%);
  box-shadow: 0 2px 10px rgb(7 19 31 / 25%);
}
.tropics-preset {
  min-height: 44px;
  min-width: 44px;
  padding: 0 var(--sp-3);
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--map-plate-text);
  font: inherit;
  font-size: var(--fs-small);
  font-weight: 700;
  cursor: pointer;
}
.tropics-preset[aria-pressed="true"] { background: var(--map-plate-text); color: var(--map-plate); }
.tropics-preset:focus-visible { outline: 3px solid var(--map-callout-link); outline-offset: 1px; }
.tropics-preset--toggle { min-height: 44px; background: rgb(7 19 31 / 82%); box-shadow: 0 2px 10px rgb(7 19 31 / 25%); }
.tropics-preset--toggle[aria-pressed="true"] { box-shadow: inset 0 0 0 2px var(--map-callout-link); background: rgb(7 19 31 / 82%); color: var(--map-plate-text); }
.tropics-preset--toggle[aria-pressed="true"]::before { content: "✓ "; }
.tropics-preset-custom {
  padding: 4px var(--sp-2);
  border-radius: 6px;
  background: rgb(7 19 31 / 82%);
  color: var(--map-plate-text);
  font-size: var(--fs-micro);
  font-weight: 700;
}
.tropics-preset-note {
  flex-basis: 100%;
  margin: 0;
  max-width: 26rem;
  padding: var(--sp-1) var(--sp-2);
  border-radius: 6px;
  background: rgb(7 19 31 / 88%);
  color: var(--map-plate-text);
  font-size: var(--fs-small);
}
.tropics-preset-note .tropics-linkbutton { min-height: 32px; padding: 0; border: 0; background: none; color: var(--map-callout-link); font: inherit; font-weight: 700; text-decoration: underline; cursor: pointer; }

/* The key: only what is drawn, each with its own mark. */
.storm-map-key--track { width: 1.25rem; height: 4px; border: 0; border-radius: 2px; background: #60c7ff; box-shadow: 0 0 0 1px #07131f; }
/* The map draws the past track near-white and dashed; the key takes the page's ink so it reads in both themes. */
.storm-map-key--past { width: 1.25rem; height: 0; border: 0; border-top: 2.5px dashed var(--ink-2); border-radius: 0; background: none; }
.storm-map-key--cone { width: 1rem; height: 0.75rem; border: 1.5px solid #8bd2ff; border-radius: 3px; background: rgb(101 191 255 / 30%); }
.storm-map-key--clouds { width: 1rem; height: 0.75rem; border: 1px solid var(--line); border-radius: 3px; background: linear-gradient(90deg, #f7fbff, #8b98a6 55%, #2a3540); }
.storm-map-key--r34, .storm-map-key--r50, .storm-map-key--r64 { width: 0.75rem; height: 0.75rem; border: 0; border-radius: 2px; margin-right: 2px; }
.storm-map-key--r34 { background: #f2c230; }
.storm-map-key--r50 { background: #ef8a2b; }
.storm-map-key--r64 { background: #d8344a; }
.storm-map-key--warning { width: 1rem; height: 0; border: 0; border-top: 3px solid var(--ink); border-radius: 0; background: none; }
.storm-map-key--watch { width: 1rem; height: 0; border: 0; border-top: 3px dashed var(--ink); border-radius: 0; background: none; }
.storm-map-key-radii { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 2px var(--sp-1); }
.storm-map-key-radii > span { display: inline-flex; align-items: center; }
.storm-map-key-note { color: var(--ink-2); }
.storm-map-clocks { flex-basis: 100%; margin: 0; color: var(--ink-2); font-size: var(--fs-micro); font-variant-numeric: tabular-nums; }
.storm-map-clocks[hidden] { display: none; }
.tropics-replay-note[hidden] { display: none; }
.tropics-satellite-help > summary { min-height: 32px; display: flex; align-items: center; cursor: pointer; font-size: var(--fs-small); font-weight: 700; }

@media (max-width: 599px) {
  /* One row at 390px, Wind extent included: a second row met the map's credits (TW-12). */
  .tropics-preset { padding: 0 6px; }
  .tropics-presets { right: 3rem; gap: var(--sp-1); }
}

/* The key and clocks fold into one line on a phone; on a desktop they are simply shown. */
.storm-map-keybox { display: block; min-width: 0; }
.storm-map-keybox > .storm-map-clocks { margin-top: var(--sp-1); }
.storm-map-keybox > summary { display: none; }
@media (max-width: 899px) {
  .storm-map-keybox { display: block; flex-basis: 100%; }
  .storm-map-keybox > summary { display: flex; align-items: center; min-height: 44px; cursor: pointer; font-weight: 700; color: var(--ink); }
  .storm-map-keybox[open] > summary { min-height: 32px; }
  /* Closed, it shares its line with the static map's link: a line more for the map (TW-12). */
  .storm-map-keybox:not([open]) { flex: 0 1 auto; }
  .storm-map-keybox > .storm-map-legend { margin-bottom: var(--sp-1); }
  /* The transport keeps its controls, its loading status and the replay note; the source line folds
     into the time label ("11:30Z · Infrared"). */
  .tropics-satellite-edge .tropics-layer-status:not([role="status"]):not(.tropics-replay-note) { display: none; }
  .tropics-satellite-edge .tropics-layer-status[role="status"]:is(:empty, [data-ok="true"]) { display: none; }
  .tropics-satellite-edge .tropics-transport-time { font-family: inherit; font-size: var(--fs-small); font-weight: 700; }
}

/* --- TW-11: a chosen place's result, a view of the panel ---------------------------------- */
.tropics-place-view { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: var(--sp-2) var(--sp-4) var(--sp-5); }
.tropics-place-view[hidden] { display: none; }
.tropics-place-back { margin-bottom: var(--sp-1); }
.tropics-place-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.tropics-place-body .tropics-location-title { margin: var(--sp-1) 0 2px; font-size: 1.125rem; font-weight: 800; }
.tropics-place-body .tropics-location-title:focus { outline: none; }
.tropics-location-group { margin: var(--sp-3) 0 var(--sp-1); padding-top: var(--sp-2); border-top: 1px solid var(--line); font-size: 0.875rem; font-weight: 700; }
.tropics-location-links a { display: inline-flex; align-items: center; min-height: 44px; font-weight: 700; }
.tropics-find-resume { min-height: 44px; margin-bottom: var(--sp-1); }
.tropics-find-resume[hidden] { display: none; }
@media (max-width: 899px) {
  .tropics-workspace:not(.is-static) .tropics-place-view { overflow-y: auto; }
  .tropics-workspace.is-static .tropics-place-view,
  .tropics-workspace.is-large-text .tropics-place-view { overflow: visible; }
}
@media (max-width: 899px) and (max-height: 540px) {
  .tropics-workspace:not(.is-static) .tropics-place-view { overflow: visible; }
}
/* In a 360px panel a label over its value reads better than two squeezed columns. */
.tropics-place-body .tropics-facts { display: block; margin: 0; }
.tropics-place-body .tropics-facts dt { margin-top: var(--sp-2); color: var(--ink-2); font-size: var(--fs-small); font-weight: 700; }
.tropics-place-body .tropics-facts dd { margin: 2px 0 0; }
.tropics-place-body .tropics-fact-value { display: block; font-family: inherit; font-size: 0.9375rem; color: var(--ink); }
.tropics-place-body .tropics-fact-sub { display: block; margin-top: 2px; color: var(--ink-2); font-size: var(--fs-small); line-height: 1.45; }

/* --- TW-13: briefing first -------------------------------------------------------------------
   The answer above the controls (the summary strip, earlier in this file), fewer controls, the
   place check's verdict before its readings, and on phones one column in reading order: the
   systems first, then the map at a height that is a map, with its views in a row above it. */

/* One overflow menu for Share and the display settings, at every width. */
.tropics-toolbar .tropics-display-summary { padding: 0 var(--sp-3); }
.tropics-display-more { display: inline; font-size: var(--fs-lead); line-height: 1; }
.tropics-toolbar .tropics-display-body { width: min(20rem, calc(100vw - 2rem)); padding: var(--sp-3) var(--sp-4) var(--sp-4); gap: var(--sp-4); }
.tropics-menu-section { display: grid; gap: var(--sp-2); justify-items: start; font-size: var(--fs-small); }
.tropics-menu-section + .tropics-menu-section { padding-top: var(--sp-3); border-top: 1px solid var(--line); }
.tropics-menu-section > .tropics-control { justify-self: stretch; justify-content: space-between; }
.tropics-menu-section > p { margin: 0; }
.tropics-menu-heading { margin: 0; color: var(--ink-2); font-size: var(--fs-small); font-weight: 700; }
.tropics-share-section .tropics-share-output { justify-self: stretch; }
.tropics-settings-body .tropics-sources { justify-self: stretch; margin-top: var(--sp-1); }

/* The imagery's options, inside the Satellite view's playback bar, opening in place. */
.tropics-satellite-edge .tropics-satellite-settings { position: static; margin-top: var(--sp-1); }
.tropics-satellite-edge .tropics-satellite-summary,
.tropics-satellite-edge .tropics-satellite-settings[open] .tropics-satellite-summary {
  display: inline-flex;
  align-items: center;
  min-height: 2.5rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--link);
  font-size: var(--fs-small);
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}
.tropics-satellite-edge .tropics-satellite-summary::-webkit-details-marker { display: none; }
.tropics-satellite-edge .tropics-satellite-summary:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.tropics-satellite-edge .tropics-satellite-body {
  position: static;
  width: auto;
  max-height: 40dvh;
  padding: var(--sp-2) 0 0;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
}

/* The basin's alerts: in force opens the list; none in force is a sentence, not a link; a feed
   not read is said in the ink's weight. On a phone the section keeps one height from the first
   paint, whichever it shows, because the map is under it. */
.tropics-alert-summary-none { margin: 0; padding-block: var(--sp-2); color: var(--ink); }
.tropics-alert-summary-none[data-state="unavailable"] { font-weight: 650; }
@media (max-width: 899px) {
  .tropics-alert-summary { min-height: 8.75rem; box-sizing: border-box; }
}
.tropics-alert-summary-open + .tropics-alert-summary-open { display: flex; font-weight: 600; }

/* Rows: the clock is words in the interface sans, its numbers aligned. */
.tropics-row-age { font-family: inherit; font-variant-numeric: tabular-nums; }

/* The comparison's summary keeps its text off its border at any height. */
.tropics-compare-summary { padding-block: var(--sp-1); }

/* The map's scale, at the page's smallest size, clear of the credits it shared a corner with. */
.storm-overview-canvas .maplibregl-ctrl-scale {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
  padding: 0 var(--sp-1) 1px;
}
.storm-overview-canvas .maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib:not(.maplibregl-compact) { max-width: calc(100% - 10rem); }

/* A place's answer: the verdict, in the reader's words, then the readings and the working. */
.tropics-location-verdict { display: grid; gap: var(--sp-2); margin: var(--sp-2) 0 var(--sp-1); }
.tropics-location-verdict p { margin: 0; color: var(--ink); font-size: var(--fs-remarks); font-weight: 600; line-height: 1.45; }
.tropics-location-verdict .tropics-location-official { color: var(--ink-2); font-size: var(--fs-small); font-weight: 600; }
.tropics-location-reconcile { margin: var(--sp-1) 0 0; }
.tropics-location-method { margin-top: var(--sp-3); padding-top: var(--sp-1); border-top: 1px solid var(--line); }
.tropics-location-method > summary { display: flex; align-items: center; min-height: 44px; color: var(--link); font-size: var(--fs-small); font-weight: 700; cursor: pointer; }
.tropics-location-method > summary:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.tropics-location-method p { margin: 0 0 var(--sp-2); }

/* Phones and narrow tablets: one column the document scrolls, in reading order. The systems
   (or the open storm, the alert list, a place's answer) below the map, its views in
   a row above the picture rather than over it, and the picture never shorter than 45% of the
   screen. Explicit sheet controls below refine the information height. */
@media (max-width: 899px) {
  .tropics { padding-inline: 18px; }
  .tropics-workspace,
  .tropics-workspace:not(.is-static),
  .tropics-workspace.is-large-text {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto;
    grid-template-areas: "map" "list";
    gap: var(--sp-3);
    height: auto;
    min-height: 0;
  }
  .tropics-workspace .tropics-sidebar,
  .tropics-workspace:not(.is-static) .tropics-sidebar {
    grid-area: list;
    height: auto !important;
    min-height: 0;
    max-height: none !important;
    margin-top: 0;
    border-radius: 8px;
    box-shadow: none;
  }
  .tropics-workspace .storm-overview-map-panel,
  .tropics-workspace:not(.is-static) .storm-overview-map-panel { grid-area: map; min-height: 0; border-radius: 8px; }
  .tropics-workspace:not(.is-static) .storm-overview-map-meta { border-radius: 0 0 8px 8px; }
  .tropics-workspace :is(.tropics-sidebar-scroll, .tropics-preview, .tropics-alerts-view, .tropics-place-view),
  .tropics-workspace:not(.is-static) :is(.tropics-sidebar-scroll, .tropics-preview, .tropics-alerts-view, .tropics-place-view) { overflow: visible; }

  .tropics-workspace:not(.is-static) .storm-overview-map-panel.is-live .storm-overview-stage {
    display: flex;
    flex-direction: column;
    flex: none;
    height: auto;
    min-height: 0;
    aspect-ratio: auto;
  }
  .tropics-workspace:not(.is-static) .storm-overview-map-panel.is-live .storm-overview-canvas {
    position: relative;
    inset: auto;
    flex: none;
    height: max(45dvh, 18rem);
    max-height: 70dvh;
    min-height: 0;
  }
  .tropics-workspace:not(.is-static) .storm-overview-map-panel.is-live .tropics-presets {
    position: static;
    flex: none;
    padding: var(--sp-2);
    background: var(--map-plate);
    pointer-events: auto;
  }
  .tropics-workspace:not(.is-static) .storm-overview-map-panel.is-live .tropics-presets .tropics-preset-group { box-shadow: none; }
  .tropics-workspace:not(.is-static) .storm-overview-map-panel.is-live .tropics-presets .tropics-preset--toggle { box-shadow: none; }

  /* The first paint takes the same order and boxes: the panel's first rows, then the map. */
  .skeleton--workspace {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto;
    grid-template-areas: "map" "list";
    gap: var(--sp-3);
    height: auto;
    min-height: 0;
  }
  .skeleton--workspace .skeleton--rail { grid-area: list; height: 15rem; min-height: 0; }
  .skeleton--workspace .skeleton--map { grid-area: map; height: calc(max(45dvh, 18rem) + 3.75rem); min-height: 0; aspect-ratio: auto; }
}

/* Phone sheet: explicit controls stay outside the independently scrolling information. */
@media (max-width: 899px) and (min-height: 501px) {
  .tropics-sheet-controls { display: flex; flex: none; gap: var(--sp-2); padding: var(--sp-2); border-bottom: 1px solid var(--line); }
  .tropics-sheet-controls button { min-height: 44px; flex: 1; padding: var(--sp-1); background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius-control); font: inherit; cursor: pointer; }
  .tropics-sheet-controls button[aria-pressed="true"] { background: var(--tw-wash); color: var(--tw-selected); }
  .tropics-workspace .tropics-sidebar[data-sheet-size="peek"] { max-height: 14rem !important; }
  .tropics-workspace .tropics-sidebar[data-sheet-size="details"] { max-height: 65dvh !important; }
  .tropics-workspace .tropics-sidebar[data-sheet-size="full"] { max-height: none !important; }
  .tropics-workspace .tropics-sidebar:not([data-sheet-size="full"]) :is(.tropics-sidebar-scroll, .tropics-preview, .tropics-alerts-view, .tropics-place-view) { overflow: auto; min-height: 0; }
  .tropics-workspace.is-large-text .tropics-sidebar { max-height: none !important; }
}

@media (min-width: 1280px) {
  body[data-tropics-workspace] .masthead .shell-inner { min-height: 63px; padding-block: 7px; }
  body[data-tropics-workspace] .masthead .brand .logo img { width: 149px; height: 48px; }
}

/* --- A storm at a glance (tropics cleanup, 2026-10-08) ---------------------------------------
   The head of an open storm is its name, its clock and the map's three views as one segmented
   control, the same on every tab. The Overview opens on four values in a grid, then a checklist
   of what the map draws, the warnings, and the centre's own words folded away. */
.tropics-preview-head { display: grid; gap: var(--sp-1); }
.tropics-preview-head .tropics-advisory-time { margin: 0; }
.tropics-current-facts { display: block; margin: 0 0 var(--sp-3); }
.tropics-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--line);
}
.tropics-stat { display: grid; align-content: start; gap: 1px; min-width: 0; margin: 0; padding: var(--sp-2) var(--sp-3); background: var(--surface); }
.tropics-stat dt { color: var(--ink-2); font-size: var(--fs-micro); font-weight: 700; letter-spacing: var(--track-micro); text-transform: uppercase; }
.tropics-stat dd { display: grid; min-width: 0; margin: 0; }
.tropics-stat-value { color: var(--ink); font-size: 1rem; font-weight: 750; line-height: 1.3; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.tropics-stat-value.tropics-fact-wind { flex-basis: auto; font-size: 1.25rem; line-height: 1.25; }
.tropics-stat-sub { color: var(--ink-2); font-size: var(--fs-micro); }

/* The views, moved off the map into the head while a storm is open: full width, three equal
   parts, the pressed one filled. Panel colours here, not the map's plate. */
.tropics-view-slot:empty { display: none; }
.tropics-presets.tropics-presets--panel { position: static; inset: auto; display: grid; gap: var(--sp-1); margin-top: var(--sp-2); pointer-events: auto; }
.tropics-presets.tropics-presets--panel[hidden] { display: none; }
.tropics-presets--panel .tropics-preset-group { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px; padding: 3px; border: 1px solid var(--line); border-radius: var(--radius-control); background: var(--tw-wash, var(--wash)); box-shadow: none; }
.tropics-presets--panel .tropics-preset { min-width: 0; padding: 0 var(--sp-1); border-radius: 6px; color: var(--ink); font-size: var(--fs-small); }
.tropics-presets--panel .tropics-preset:hover { background: var(--wash-strong); }
.tropics-presets--panel .tropics-preset[aria-pressed="true"] { background: var(--enamel); color: var(--on-enamel); }
.tropics-presets--panel .tropics-preset:focus-visible { outline: var(--focus-ring); outline-offset: 1px; }
.tropics-presets--panel :is(.tropics-preset-custom, .tropics-preset-note) { justify-self: start; max-width: none; background: var(--tw-wash, var(--wash)); color: var(--ink); }
.tropics-presets--panel .tropics-preset-note .tropics-linkbutton { color: var(--link); }

/* Five tabs in one row wherever they fit whole; the two-row grid stays for a narrow panel. */
@container tropics-panel (min-width: 18.75rem) {
  .tropics-tabs { display: flex; flex-wrap: nowrap; }
  .tropics-tabs button { flex: 1 1 auto; grid-column: auto; padding-inline: 2px; font-size: 0.78rem; }
  .tropics-tabs button:nth-child(n + 4) { grid-column: auto; }
}

/* What the map draws, as a checklist: a box that fills when the layer is on. */
.tropics-checklist { display: grid; gap: 0; }
.tropics-checklist button {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: 40px;
  padding: 0 var(--sp-1);
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}
.tropics-checklist button[hidden] { display: none; }
.tropics-checklist button:hover { background: var(--wash); }
.tropics-checklist button[aria-pressed="true"] { background: transparent; color: var(--ink); }
.tropics-checklist button::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  border: 2px solid var(--edge);
  border-radius: 4px;
  background: var(--surface) center / 12px no-repeat;
}
.tropics-checklist button[aria-pressed="true"]::before {
  border-color: var(--enamel);
  background-color: var(--enamel);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.2 4.8 9 10 3' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.tropics-checklist button:disabled { cursor: default; opacity: 0.6; }
.tropics-checklist button:focus-visible { outline: var(--focus-ring); outline-offset: -2px; }

/* The NWS line sits inside the warnings section now, under the storm's own, with no rule of its own. */
.tropics-overview-warnings .tropics-overview-nws { margin: var(--sp-1) 0 0; padding-top: 0; border-top: 0; }

/* Overview (2026-10-09): each watch or warning type on its own line, most severe first, marked
   with a short bar in the colour the map draws its coastline in, cased for either theme like
   NWS's swatches. The type is written out, so the colour is never the only cue. */
.tropics-ww-summary { display: grid; gap: 2px; margin: 0 0 var(--sp-1); padding: 0; list-style: none; }
.tropics-ww-line { display: flex; align-items: center; gap: var(--sp-2); min-height: 1.75rem; color: var(--ink); font-size: var(--fs-small); line-height: 1.3; }
.tropics-ww-mark {
  flex: none; width: 1.25rem; height: 0.375rem; border-radius: 999px;
  background: var(--ww-color, var(--line-strong)); box-shadow: 0 0 0 1px #0b1520, 0 0 0 2px #f1f7fc;
}
.tropics-ww-line .tropics-ww-type { display: inline; font-size: inherit; font-weight: 700; }
.tropics-ww-count { margin-left: auto; color: var(--ink-2); font-size: var(--fs-micro); font-weight: 600; white-space: nowrap; }

/* What the map draws: two columns wherever two fit, so five switches take three rows. */
.tropics-on-map .tropics-checklist { grid-template-columns: repeat(auto-fill, minmax(min(100%, 8.25rem), 1fr)); column-gap: var(--sp-1); }
.tropics-on-map .tropics-checklist button { font-size: var(--fs-small); line-height: 1.25; }

/* Local weather inside the storm panel: a heading the size of the tab's others, its sentence in
   the small face, and the five links as an even two-column list rather than a ragged wrap. */
.tropics-tab-body .wx-tropical-context { margin: 0 0 var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--line); }
.tropics-tab-body .wx-tropical-context > h3 { margin: 0 0 var(--sp-1); color: var(--ink); font-size: 0.875rem; font-weight: 700; }
.tropics-tab-body .wx-tropical-context > p { margin: 0 0 var(--sp-1); color: var(--ink-2); font-size: var(--fs-small); line-height: 1.45; }
.tropics-tab-body .wx-tropical-context .wx-next { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 8.25rem), 1fr)); gap: 0 var(--sp-2); padding: 0; font-size: var(--fs-small); }
.tropics-tab-body .wx-tropical-context .wx-next a { display: flex; align-items: center; min-height: 40px; }
.tropics-tab-body .wx-tropical-context [data-wx-places] { margin-top: var(--sp-2); }

/* Data details opens like the tab's other rows: a chevron that turns. */
.tropics-tab-body .tropics-data-details > summary { list-style: none; justify-content: space-between; gap: var(--sp-2); color: var(--ink); font-size: var(--fs-small); font-weight: 700; }
.tropics-tab-body .tropics-data-details > summary::-webkit-details-marker { display: none; }
.tropics-tab-body .tropics-data-details > summary::after {
  content: ""; flex: none; width: 0.45rem; height: 0.45rem; margin: 0 2px 3px;
  border-right: 2px solid var(--ink-2); border-bottom: 2px solid var(--ink-2); transform: rotate(45deg);
}
.tropics-tab-body .tropics-data-details[open] > summary::after { margin-bottom: -3px; transform: rotate(-135deg); }
/* From NHC is a row that opens too: the same chevron at its right edge. */
.tropics-from-center > summary { position: relative; padding-right: calc(var(--sp-3) + 1.25rem); list-style: none; }
.tropics-from-center > summary::-webkit-details-marker { display: none; }
.tropics-from-center > summary::after {
  content: ""; position: absolute; top: 50%; right: var(--sp-3); width: 0.45rem; height: 0.45rem; margin-top: -0.35rem;
  border-right: 2px solid var(--ink-2); border-bottom: 2px solid var(--ink-2); transform: rotate(45deg);
}
.tropics-from-center[open] > summary::after { margin-top: -0.1rem; transform: rotate(-135deg); }

/* The centre's own words, one closed row until asked for. */
.tropics-from-center { margin: 0 0 var(--sp-3); border: 1px solid var(--line); border-radius: var(--radius-control); background: var(--surface); }
.tropics-from-center > summary { display: grid; gap: 1px; min-height: 44px; padding: var(--sp-2) var(--sp-3); cursor: pointer; font-weight: 700; list-style-position: inside; }
.tropics-from-center > summary > span:first-child { display: inline; }
.tropics-from-center-sub { color: var(--ink-2); font-size: var(--fs-micro); font-weight: 600; }
.tropics-from-center > summary:focus-visible { outline: var(--focus-ring); outline-offset: -2px; }
.tropics-from-center > :not(summary) { margin: 0 var(--sp-3) var(--sp-3); }
.tropics-from-center .tropics-key > h3 { font-size: var(--fs-small); }
.tropics-from-center .tropics-key-messages { font-size: var(--fs-small); }

/* Time and intensity beside each forecast point: a small plate, the same on any basemap. */
.storm-forecast-label {
  display: grid;
  padding: 2px 6px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--map-plate) 78%, transparent);
  color: #fff;
  font: 700 0.6875rem/1.2 var(--font-body, sans-serif);
  white-space: nowrap;
  pointer-events: none;
}
.storm-forecast-label[hidden], .storm-forecast-label.is-crowded { visibility: hidden; }
.storm-forecast-label-time { color: #cfe6ff; font-weight: 600; }

/* --- The Satellite view over a storm (2026-10-08) ---------------------------------------------
   Beside the panel the playback bar is one slim row along the map's lower edge, so the storm it
   plays stays in view: steps, play, the scrubber, the frame's time and channel, Latest, and the
   imagery's options, which open upward as a small card. The frames' source and cadence are in
   those options; only a loading or failed frame, or a replay's note, adds a line. The phone keeps
   its docked bar (TW-12). */
@media (min-width: 600px) {
  .storm-overview-stage > .tropics-satellite-edge:not([hidden]) {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    left: var(--sp-2);
    right: 3.25rem;
    max-width: 46rem;
    padding: 4px var(--sp-2);
    border-radius: var(--radius-control);
    background: color-mix(in srgb, var(--surface) 92%, transparent);
  }
  .storm-overview-stage > .tropics-satellite-edge .tropics-transport-wrap { flex: 1 1 auto; min-width: 0; }
  .storm-overview-stage > .tropics-satellite-edge .tropics-transport { flex-wrap: nowrap; gap: var(--sp-1); }
  .storm-overview-stage > .tropics-satellite-edge .tropics-transport-button { min-height: 2.5rem; min-width: 2.5rem; padding-inline: var(--sp-2); }
  .storm-overview-stage > .tropics-satellite-edge .tropics-scrub { flex: 1 1 6rem; min-width: 4rem; }
  .storm-overview-stage > .tropics-satellite-edge .tropics-transport-time { flex: none; font-family: inherit; font-size: var(--fs-small); font-weight: 700; white-space: nowrap; }
  .storm-overview-stage > .tropics-satellite-edge .tropics-transport-note { display: none; }
  .storm-overview-stage > .tropics-satellite-edge .tropics-layer-status[role="status"]:is(:empty, [data-ok="true"]) { display: none; }
  .storm-overview-stage > .tropics-satellite-edge .tropics-layer-status { margin: 2px 0 0; }
  .storm-overview-stage > .tropics-satellite-edge .tropics-satellite-settings { flex: none; margin: 0; }
  .storm-overview-stage > .tropics-satellite-edge .tropics-satellite-summary {
    min-height: 2.5rem;
    padding: 0 var(--sp-2);
    border: 1px solid var(--line);
    border-radius: 6px;
    color: var(--ink);
  }
  .storm-overview-stage > .tropics-satellite-edge .tropics-satellite-settings[open] .tropics-satellite-summary { border-color: var(--enamel); background: var(--enamel); color: var(--on-enamel); }
  .storm-overview-stage > .tropics-satellite-edge .tropics-satellite-body {
    position: absolute;
    top: auto;
    right: 0;
    bottom: calc(100% + var(--sp-2));
    width: min(20rem, calc(100% - var(--sp-2)));
    max-height: 50dvh;
    padding: var(--sp-3);
    border: 1px solid var(--line);
    border-radius: var(--radius-surface);
    background: var(--surface);
    box-shadow: 0 8px 24px rgb(7 19 31 / 18%);
  }
}

/* Infrared clouds in the key: the colour scale NASA GIBS draws them in ("Infrared Brightness
   Temperature", GOES-East, GOES-West and Himawari band 13 alike), -92 °C to 57 °C, with its
   ticks. The stops are taken from GIBS's colormap and held to it by
   tests/web/satellite_legend.test.mjs; colder is higher cloud. */
.storm-map-legend .storm-map-key-ir { display: inline-grid; grid-template-columns: minmax(9rem, auto); align-items: stretch; gap: 1px; }
.storm-map-legend .storm-map-key-ir-label { display: block; white-space: nowrap; }
.storm-map-key-ir-bar {
  display: block;
  height: 0.6rem;
  border: 1px solid var(--line);
  border-radius: 2px;
  background: linear-gradient(90deg, #ffffff 0.34%, #7f007f 1.01%, #ff7fcb 7.72%, #e6e6e6 8.39%, #050505 14.43%, #ff0000 21.14%, #ffff00 27.85%, #00ff00 34.56%, #002a60 41.11%, #000073 41.78%, #00007d 42.11%, #001a81 42.79%, #00ffff 48.83%, #c5c5c5 49.16%, #020202 99.83%);
}
.storm-map-legend .storm-map-key-ir-ticks { position: relative; display: block; height: 0.9rem; color: var(--ink-2); font-size: 0.625rem; font-variant-numeric: tabular-nums; }
.storm-map-legend .storm-map-key-ir-ticks > span { position: absolute; display: inline; top: 0; transform: translateX(-50%); white-space: nowrap; }
/* The same scale on the map, over the imagery it reads: wide enough to read a temperature from,
   on the plate colours the markers use, at the upper-left corner (under the views when they are
   on the map). It never takes a click from the map. */
.storm-map-ir-scale {
  position: absolute; z-index: 3; top: var(--ir-scale-top, var(--sp-2)); left: var(--sp-2);
  width: min(17rem, calc(100% - 5rem)); padding: 6px 12px 2px;
  border-radius: var(--radius-control); pointer-events: none;
  background: color-mix(in srgb, var(--map-plate) 84%, transparent); color: var(--map-plate-text);
  box-shadow: 0 4px 14px rgb(7 19 31 / 28%);
}
.storm-map-ir-scale .storm-map-key-ir { display: grid; gap: 3px; }
.storm-map-ir-scale .storm-map-key-ir-label { font-size: var(--fs-micro); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.storm-map-ir-scale .storm-map-key-ir-bar { height: 0.75rem; border-color: rgb(247 251 255 / 45%); }
.storm-map-ir-scale .storm-map-key-ir-ticks { position: relative; display: block; height: 1rem; font-family: var(--font-mono); font-size: 0.625rem; font-variant-numeric: tabular-nums; }
.storm-map-ir-scale .storm-map-key-ir-ticks > span { position: absolute; top: 0; transform: translateX(-50%); white-space: nowrap; }

/* --- Models (2026-10-08) ----------------------------------------------------------------------
   The switch and which runs come first; then a key that names every run, grouped by kind, with
   its line's colour once tracks are drawn; then the published graphics. While the Models tab is
   open its key is the legend, so the summary shown above the other tabs steps aside. */
.tropics-preview-body:has(#tropics-panel-models:not([hidden])) .tropics-model-summary { display: none; }
.tropics-model-controls { display: grid; gap: var(--sp-2); margin: 0 0 var(--sp-2); }
.tropics-model-controls .tropics-checklist button { font-weight: 700; }
.tropics-model-policies { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2px; padding: 3px; border: 1px solid var(--line); border-radius: var(--radius-control); background: var(--tw-wash, var(--wash)); }
.tropics-model-policies button { min-height: 40px; border: 0; border-radius: 6px; background: transparent; color: var(--ink); font-size: var(--fs-small); font-weight: 700; }
.tropics-model-policies button[aria-pressed="true"] { background: var(--enamel); color: var(--on-enamel); }
.tropics-model-policies button[hidden] { display: none; }
.tropics-model-controls .storm-guidance-policy-copy { margin: 0; }
#tropics-panel-models .storm-guidance-caution { margin: 0 0 var(--sp-3); color: var(--ink-2); font-size: var(--fs-small); }
.tropics-model-list { margin: 0 0 var(--sp-3); font-size: var(--fs-small); }
.tropics-model-count { margin: 0 0 var(--sp-2); color: var(--ink-2); font-size: var(--fs-micro); font-variant-numeric: tabular-nums; }
.tropics-model-group-title { margin: var(--sp-2) 0 2px; color: var(--ink-2); font-size: var(--fs-micro); font-weight: 700; letter-spacing: var(--track-micro); text-transform: uppercase; }
.tropics-model-group { list-style: none; margin: 0; padding: 0; }
.tropics-model-row { display: grid; grid-template-columns: 1.25rem 3.25rem minmax(0, 1fr); align-items: baseline; gap: var(--sp-2); padding: 3px var(--sp-1); border-radius: 4px; }
.tropics-model-row:hover { background: var(--wash); }
.tropics-model-swatch { align-self: center; width: 1.25rem; height: 4px; border-radius: 2px; background: var(--model-color, transparent); box-shadow: inset 0 0 0 1px var(--line); }
.tropics-model-row.is-drawn .tropics-model-swatch { box-shadow: none; }
/* The key draws each kind as the map does: consensus heavier, ensemble means dashed. */
.tropics-model-row--consensus .tropics-model-swatch { height: 5px; }
.tropics-model-row--ensemble_mean.is-drawn .tropics-model-swatch { background: repeating-linear-gradient(90deg, var(--model-color) 0 6px, transparent 6px 10px); }
:root:not([data-theme="dark"]) .tropics-model-row--consensus.is-drawn .tropics-model-swatch { box-shadow: 0 0 0 1px var(--line-strong); }
.tropics-model-code { font-family: var(--font-mono); font-weight: 600; color: var(--ink); }
.tropics-model-name { min-width: 0; color: var(--ink); overflow-wrap: anywhere; }
.tropics-model-name small { color: var(--ink-2); font-size: var(--fs-micro); }
.tropics-published-guidance { display: grid; gap: var(--sp-1); padding-top: var(--sp-2); border-top: 1px solid var(--line); }
.tropics-published-guidance h4 { margin: 0; font-size: var(--fs-small); }
.tropics-published-guidance .tropics-fine { margin: 0; }
.tropics-published-guidance .tropics-model-graphic { display: inline-flex; align-items: center; min-height: 40px; font-weight: 700; }

/* --- Forecast (2026-10-08) --------------------------------------------------------------------
   The published wind as a chart, then short rows: day and hour, wind, and the centre's stage with
   its Saffir-Simpson colour where it called the point tropical, the zone said once in the head. */
.tropics-intensity { margin: 0 0 var(--sp-3); }
.tropics-intensity figcaption { margin: 2px 0 0; }
.tropics-intensity-chart { display: block; width: 100%; height: auto; overflow: visible; font-family: var(--font-body, sans-serif); }
.tropics-chart-ref { stroke: var(--line-strong); stroke-width: 1; stroke-dasharray: 3 3; }
.tropics-chart-ref-label { fill: var(--ink-2); font-size: 9px; font-weight: 600; }
.tropics-chart-axis { stroke: var(--line); stroke-width: 1; }
.tropics-chart-tick { stroke: var(--line-strong); stroke-width: 1; }
.tropics-chart-tick-label { fill: var(--ink-2); font-size: 10px; font-weight: 700; }
.tropics-chart-line { fill: none; stroke: var(--ink-2); stroke-width: 1.5; stroke-linejoin: round; }
.tropics-chart-dot { fill: var(--surface); stroke: var(--ink); stroke-width: 1.5; }
.tropics-chart-dot.is-now { stroke-width: 2.5; }
.tropics-chart-peak { fill: var(--ink); font-size: 11px; font-weight: 800; }
.tropics-chart-dot.tier-unknown { fill: var(--wx-tier-unknown); }
.tropics-chart-dot.tier-td { fill: var(--wx-tier-td); }
.tropics-chart-dot.tier-ts { fill: var(--wx-tier-ts); }
.tropics-chart-dot.tier-c1 { fill: var(--wx-tier-c1); }
.tropics-chart-dot.tier-c2 { fill: var(--wx-tier-c2); }
.tropics-chart-dot.tier-c3 { fill: var(--wx-tier-c3); }
.tropics-chart-dot.tier-c4 { fill: var(--wx-tier-c4); }
.tropics-chart-dot.tier-c5 { fill: var(--wx-tier-c5); }

.tropics-forecast-points li.is-new-day { border-top: 2px solid var(--line-strong); }
.tropics-forecast-points:not(.tropics-forecast-points--full) li > strong { white-space: nowrap; font-variant-numeric: tabular-nums; }
.tropics-forecast-stage { display: inline-flex; align-items: baseline; gap: 6px; }
.tropics-forecast-stage[class*="tropics-stage--"]::before { content: ""; flex: none; width: 0.6rem; height: 0.6rem; border-radius: 50%; background: var(--stage-color); box-shadow: 0 0 0 1px var(--line-strong); transform: translateY(1px); }
.tropics-stage--tier-unknown { --stage-color: var(--wx-tier-unknown); }
.tropics-stage--tier-td { --stage-color: var(--wx-tier-td); }
.tropics-stage--tier-ts { --stage-color: var(--wx-tier-ts); }
.tropics-stage--tier-c1 { --stage-color: var(--wx-tier-c1); }
.tropics-stage--tier-c2 { --stage-color: var(--wx-tier-c2); }
.tropics-stage--tier-c3 { --stage-color: var(--wx-tier-c3); }
.tropics-stage--tier-c4 { --stage-color: var(--wx-tier-c4); }
.tropics-stage--tier-c5 { --stage-color: var(--wx-tier-c5); }


/* The storm list (2026-10-09). Rows stay records, not cards (no frame or ground at rest) and
   stay three lines (TW-1): a hairline between them, the name a size up, the wind in the body
   face, the warning badge as a quiet chip marked in the map's colour for its type, and the
   basin ahead of the authority and its age. */
.tropics-rows { gap: 3px; }
.tropics-rows > .tropics-row + .tropics-row { padding-top: 3px; border-top: 1px solid var(--line); }
.tropics-row-button { gap: 3px; }
.tropics-row-name { font-size: 1.0625rem; font-weight: 800; letter-spacing: 0.01em; }
.tropics-row-value { font-family: inherit; font-weight: 750; }
.tropics-row .tropics-badge--marked,
.tropics-row .tropics-badge--marked.tropics-badge--watch {
  display: inline-flex; align-items: center; gap: 5px; margin-top: 0;
  padding: 2px 6px; background: var(--surface); color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--line); font-weight: 700;
}
.tropics-badge--marked .tropics-ww-mark { width: 0.625rem; height: 0.3rem; }
.tropics-row-wind:has(.tropics-badge--marked) { column-gap: var(--sp-1); }
.tropics-row-meta { gap: 0; }
.tropics-row-basin { color: var(--ink-2); font-size: var(--fs-small); font-weight: 650; }
.tropics-row-basin::after { content: "\00a0·\00a0"; font-weight: 400; }

/* "164 tropical alerts …  →": the words wrap, the arrow keeps the right edge on every line. */
.tropics-alert-summary-open,
.tropics-alert-summary-open + .tropics-alert-summary-open { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-2); width: 100%; }
.tropics-alert-summary-open > span:last-child { flex: none; text-decoration: none; }

/* The category at each past fix (pastMark in storm-official-overlay.mjs): the Saffir-Simpson
   ramp's own grounds and inks, as the chips beside a storm's name carry them, on a dark ring so
   the lighter tiers read on imagery. A mark the page could not colour keeps the plain ground. */
.storm-past-mark {
  display: grid;
  place-items: center;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  border: 1.5px solid #07131f;
  border-radius: 999px;
  background: #e9f4ff;
  color: var(--wx-tier-ink);
  font: 800 0.625rem/1 var(--font-body, sans-serif);
  pointer-events: none;
}
.storm-past-mark[hidden], .storm-past-mark.is-crowded { visibility: hidden; }
.storm-past-mark.tier-unknown { background: var(--wx-tier-unknown); color: var(--wx-chip-ink); }
.storm-past-mark.tier-td { background: var(--wx-tier-td); }
.storm-past-mark.tier-ts { background: var(--wx-tier-ts); }
.storm-past-mark.tier-c1 { background: var(--wx-tier-c1); }
.storm-past-mark.tier-c2 { background: var(--wx-tier-c2); }
.storm-past-mark.tier-c3 { background: var(--wx-tier-c3); }
.storm-past-mark.tier-c4 { background: var(--wx-tier-c4); color: var(--wx-chip-ink); }
.storm-past-mark.tier-c5 { background: var(--wx-tier-c5); color: var(--wx-chip-ink); }
