/* Maverick Wx — Radar. Loads after tokens.css, shell.css and styles.css.

   The page is a WORKSPACE: the map fills the viewport under the two bars and the layer
   panel is a variant of the shared `.panel` component (`.panel--controls`), not a sidebar
   of its own. Before this it was `.radar-shell` / `.radar-panel` / `.radar-panel-toggle`
   with its own grid, its own bottom-sheet collapse and its own masthead measurement —
   three mechanisms that did the same job as /nws's three, differently.

   What is left here is genuinely radar-specific: the feed row's interior, the legend, the
   animation transport, and the map markers. */

/* ============================================================================
   The layer panel — three sections, in the order the work happens
   ==========================================================================*/

/* `Active layers` is the map's own legend, and reads as the panel's subject: card ground,
   full-width rows, the controls that act on a layer already drawn. `Add a layer` is
   discovery and is deliberately quieter — flush rows inside collapsed disclosures, one
   line each, with the prose behind a `?`. The difference in weight IS the information
   architecture: it is what tells you, before reading a word, which part of the panel is
   about the map in front of you. */

.radar-row {
  margin-bottom: var(--sp-3); background: var(--wash-strong); padding: var(--sp-3);
}

.radar-check { width: 16px; height: 16px; flex: none; }
.radar-row-label { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.radar-row-name { font-weight: 700; font-size: var(--fs-bulletin); line-height: 1.25; }
/* Who publishes this imagery, in the interface face. It was uppercase mono at 10px, which
   made the one piece of attribution on the row the least readable text in the panel. */
.radar-row-provider {
  font-size: var(--fs-bulletin); color: var(--muted);
}
/* Where this layer sits in the stack, in words. The arrows say a reorder is possible; this
   says what the current order actually is, which is the question they exist to answer. */
.radar-row-order {
  font-size: var(--fs-micro); color: var(--muted); margin-top: 2px;
}
/* A forecast layer is not an observation and must never be mistaken for one — the tag is
   the panel-side half of the rule the timeline enforces on the frame readout below. */
.radar-forecast-tag {
  display: inline-block; margin-left: 6px; padding: 0 6px;
  border: 1px solid var(--edge);
  color: var(--ink); letter-spacing: 0; font-weight: 600;
}
.radar-row-summary { font-size: var(--fs-bulletin); color: var(--ink); margin: 0 0 var(--sp-1); opacity: 0.85; }
.radar-row-meta { font-family: var(--font-mono); font-size: var(--fs-micro); color: var(--muted); margin: 0; }

/* Reorder, hide and remove: a symbol AND a word on every one.
 *
 * These were four unlabelled glyphs — ▲ ▼ ● ✕ — 30x28px, with the meaning in a `title`.
 * That is a tooltip a touch screen never shows and a hover a reader has to go looking for,
 * on the control that deletes a layer. The glyph stays as a second signal; the word is what
 * is read. Below 380px the words drop and the `aria-label` carries them, which is the one
 * width where four labelled controls genuinely do not fit. */
.radar-row-tools { display: flex; gap: var(--sp-1); margin-top: var(--sp-3); flex-wrap: wrap; }
.radar-tool-btn {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  font: inherit; font-size: var(--fs-bulletin); font-weight: 600; line-height: 1; cursor: pointer;
  padding: 7px var(--sp-2); min-height: 32px;
  color: var(--ink-2); background: var(--paper);
  border: 1px solid var(--edge);
}
.radar-tool-glyph { font-size: var(--fs-micro); opacity: 0.8; }
.radar-tool-btn:hover:not(:disabled) { color: var(--ink); border-color: var(--ink); }
.radar-tool-btn:disabled { opacity: 0.4; cursor: default; }
/* A destructive control reverses on hover rather than turning red: the one device this
   system has for "this is the serious one", and it cannot be confused with a storm tier. */
.radar-tool-btn--remove:hover:not(:disabled) { color: var(--paper); background: var(--ink); border-color: var(--ink); }
.radar-tool-btn[aria-pressed="true"] {
  color: var(--ink); border-color: var(--ink); background: var(--wash-strong);
}
/* 340px, not 380: at 375 — the commonest phone width there is — four labelled buttons wrap
   to two rows inside the drawer and stay readable, which is the whole point of labelling
   them. Only at 320 does the label genuinely stop fitting. */
@media (max-width: 340px) {
  .radar-tool-word {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .radar-tool-glyph { font-size: var(--fs-bulletin); opacity: 1; }
}

/* The `?` disclosure on a catalogue row: the one place a bare glyph is still right, since
   the row beside it names itself and the glyph expands into the text it stands for. */
.radar-icon-btn {
  display: grid; place-items: center; width: 32px; height: 32px; flex: none;
  font: inherit; font-size: var(--fs-bulletin); line-height: 1; cursor: pointer;
  color: var(--muted); background: var(--paper);
  border: 1px solid var(--edge);
}
.radar-icon-btn:hover:not(:disabled) { color: var(--ink); border-color: var(--ink); }
.radar-icon-btn:disabled { opacity: 0.35; cursor: default; }

/* A hidden layer stays in the list, at its place in the stack, holding its opacity and
   its pickers — it is just not drawn. Dimming the row says that without removing the
   controls that make it worth keeping. */
.radar-row.is-hidden .radar-row-label,
.radar-row.is-hidden .radar-row-controls { opacity: 0.45; }

/* Feed health, in the site's shared freshness component rather than a filled badge whose
   colour was the whole signal. "Unavailable" has to be legible at a glance: a dead feed
   draws nothing, and a blank radar map reads as clear skies — the same "outage is not no
   weather" rule the pipeline enforces everywhere else, reached through the interface.

   The idle state keeps its space rather than collapsing it, so the row does not jump when
   the first tile reports in. */
.radar-status { display: block; margin-top: var(--sp-2); min-height: 1.4em; }
.radar-status .freshness { font-size: var(--fs-bulletin); }

.radar-row-controls { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: 10px; }
.radar-field, .radar-opacity-wrap {
  display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-bulletin);
}
.radar-field > span, .radar-opacity-wrap > span {
  font-size: var(--fs-bulletin); font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--muted); width: 58px; flex: none;
}
.radar-select {
  flex: 1; min-width: 0; font: inherit; font-size: var(--fs-bulletin); padding: 7px var(--sp-2);
  color: var(--ink); background: var(--paper);
  border: 1px solid var(--edge);
}
.radar-opacity { flex: 1; min-width: 0; }
.radar-opacity-value {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-bulletin); color: var(--muted); width: 38px; text-align: right; flex: none;
}

.radar-section-note { color: var(--muted); font-size: var(--fs-bulletin); margin: 0 0 var(--sp-3); }

/* A collapsible group: presets, the catalogue, map settings. The summary is the shared
   `.panel-section` heading with a disclosure marker, so a folded group still reads as the
   same kind of heading as an open one. */
.radar-group { border-top: 1px solid var(--line); margin-top: var(--sp-5); }
.radar-group[open] { padding-bottom: var(--sp-3); }
.radar-group-summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: var(--sp-2);
  padding-top: var(--sp-3); margin-top: 0; min-height: 44px;
}
.radar-group-summary::-webkit-details-marker { display: none; }
.radar-group-summary::before {
  content: "›"; display: inline-block; color: var(--muted);
  transition: transform var(--dur) var(--ease); font-size: var(--fs-remarks); line-height: 1;
}
.radar-group[open] > .radar-group-summary::before { transform: rotate(90deg); }
.radar-group-summary:focus-visible { outline: var(--focus-ring); outline-offset: -2px; }
.radar-basemaps { margin-bottom: 10px; }
.radar-basemaps .choice { padding: 6px 11px; }

/* ---- Presets --------------------------------------------------------------
   A preset is a whole map in one tap, so it is a row with a name and a promise, not a
   toggle. It carries `.panel-item`, which means "currently applied" is marked with the
   same inset accent bar a selected storm and a current nav row get. */
.radar-presets { display: flex; flex-direction: column; gap: var(--sp-1); margin-bottom: var(--sp-2); }
.radar-preset { display: flex; flex-direction: column; gap: 2px; }
.radar-preset-name { font-weight: 650; font-size: var(--fs-bulletin); line-height: 1.2; }
.radar-preset-summary { font-size: var(--fs-bulletin); color: var(--muted); line-height: 1.4; }

/* ---- Catalogue ------------------------------------------------------------
   Collapsed by default and open while a search is narrowing it. The whole point is that
   nothing here is read unless it is asked for. */
.radar-search { margin-bottom: var(--sp-2); }
.radar-catalog { display: flex; flex-direction: column; gap: 1px; }

.radar-cat { border-bottom: 1px solid var(--line); }
.radar-cat-summary {
  display: flex; align-items: center; gap: var(--sp-2); cursor: pointer;
  padding: 10px 2px; list-style: none;
  font-family: var(--font-body); font-weight: 600; font-size: var(--fs-bulletin);
  color: color-mix(in srgb, var(--ink) 85%, transparent);
}
.radar-cat-summary::-webkit-details-marker { display: none; }
/* The disclosure triangle, drawn rather than inherited, so it points the same way in
   every engine and matches the square character of the rest of the controls. */
.radar-cat-summary::before {
  content: "▸"; color: var(--muted); font-size: var(--fs-bulletin);
  transition: transform var(--dur) var(--ease); display: inline-block;
}
.radar-cat[open] > .radar-cat-summary::before { transform: rotate(90deg); }
.radar-cat-summary:hover { color: var(--ink); }
.radar-cat[open] > .radar-cat-summary { color: var(--ink); }

.radar-cat-row { padding-bottom: var(--sp-1); }
.radar-cat-head { display: flex; align-items: center; gap: 4px; }
/* Borderless until hovered: 31 boxed rows is the ink that made the old panel a wall. */
.radar-add {
  position: relative; flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 1px;
  border-color: transparent; background: transparent;
  padding: 7px 52px 7px var(--sp-2);
}
.radar-add:hover { background: var(--wash-strong); border-color: var(--ink); }
.radar-add .radar-row-name { font-weight: 600; font-size: var(--fs-bulletin); }
/* What the row does, said only when it is being considered — a column of 31 permanent
   "+ Add" labels is the same wall of ink in a different font. */
.radar-add::after {
  content: "+ Add"; position: absolute; right: var(--sp-2); top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-body); font-size: var(--fs-micro); letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted); opacity: 0;
}
.radar-add:hover::after, .radar-add:focus-visible::after { opacity: 1; }

.radar-about { padding: 0 var(--sp-2) var(--sp-2); }
.radar-about[hidden] { display: none; }

/* The label overlay is a property of the basemap, not a feed, so it is a plain checkbox
   rather than a row in any of the three lists. */
.radar-inline-check {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-bulletin); color: var(--ink); cursor: pointer; padding: var(--sp-2) 0;
}

/* ============================================================================
   Map stage
   ==========================================================================*/

/* The ground the map paints over before any tile lands. It is the page's own paper, which
   on this page is the night value because radar.html carries `data-dark` — so the ground
   under the tiles and the ground under the controls are the same surface, by construction
   rather than by two hexes that happened to match. */
.radar-map { position: absolute; inset: 0; background: var(--paper); }

/* --- The map could not start ------------------------------------------------
   A flat navy rectangle is the one thing this region must never be left as: it is
   exactly what a working map over a quiet ocean looks like. When the map fails, the
   region says so in plain words rather than going quiet. */
.radar-map--failed {
  display: grid; place-items: center; background: var(--wash);
  border: 1px dashed var(--edge);
}
/* A capability failure is a compact status state, not an empty full-height canvas. */
.stage.radar-stage--failed { min-height: 15rem; }
.stage.radar-stage--failed .radar-map { position: relative; min-height: 15rem; }
.radar-map-failnote {
  margin: 0; padding: var(--sp-4); text-align: center;
  font-family: var(--font-body); font-size: var(--fs-bulletin);
  color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em;
}

.radar-failure { display: grid; gap: var(--sp-3); }
.radar-failure-title {
  margin: 0; font-family: var(--font-body); font-weight: 600;
  font-size: var(--fs-lead); color: var(--ink);
}
.radar-failure-body { margin: 0; font-size: var(--fs-bulletin); color: var(--ink); }
.radar-fallback-links { margin: 0; padding-left: 1.1em; display: grid; gap: 4px; }
.radar-fallback-links li { font-size: var(--fs-bulletin); }
.radar-failure-detail {
  margin: 0; font-size: var(--fs-bulletin); color: var(--muted);
  overflow-wrap: anywhere;
}

/* Both overlays are toggled with the `hidden` attribute, which a display rule would
   otherwise override. */
.radar-legend[hidden],
.radar-timeline[hidden] { display: none; }

/* Attached to the map workspace, bottom-left, and readable over whatever is drawn under
   it. 96% rather than 92%: at 92% a bright reflectivity core showed through the panel and
   the dBZ numbers sat on top of the colour they were labelling. */
.radar-legend {
  position: absolute; left: var(--sp-3); bottom: var(--sp-3); z-index: 2; max-width: 280px;
  background: color-mix(in srgb, var(--paper) 96%, transparent);
  border: 1px solid var(--edge);
  padding: var(--sp-3);
}
.radar-legend h2 {
  margin: 0 0 var(--sp-2); font-size: var(--fs-bulletin); font-weight: 700;
  letter-spacing: 0; text-transform: none; color: var(--ink);
}
.radar-legend-scale { display: flex; gap: 0; }
.radar-legend-stop { display: flex; flex-direction: column; align-items: center; gap: 3px; flex: 1; }
.radar-legend-stop i { display: block; width: 100%; height: 10px; }
.radar-legend-stop span {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-micro); color: var(--muted);
}
.radar-legend-note { margin: var(--sp-2) 0 0; font-size: var(--fs-bulletin); color: var(--muted); line-height: 1.4; }

/* Animation transport. Only shown while an animated feed is on. */
.radar-timeline {
  position: absolute; left: 50%; transform: translateX(-50%);
  /* Clear of the attribution/scale strip along the bottom edge (two rows tall when the
     attribution is expanded), and narrow enough not to collide with the legend parked
     bottom-left. */
  bottom: 58px; z-index: 2;
  display: flex; align-items: center; gap: var(--sp-3);
  width: min(480px, calc(100% - 330px));
  background: color-mix(in srgb, var(--paper) 96%, transparent);
  border: 1px solid var(--edge);
  padding: var(--sp-2) var(--sp-3);
}
.radar-play {
  font: inherit; font-size: var(--fs-bulletin); line-height: 1; cursor: pointer;
  border: 1px solid var(--line); background: var(--paper); color: var(--ink); padding: 5px 9px; min-width: 34px; min-height: 30px;
}
.radar-play:hover { border-color: var(--ink); }
.radar-frame { flex: 1; min-width: 0; }
.radar-frame-readout { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; }
.radar-frame-time { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--fs-bulletin); white-space: nowrap; color: var(--ink); }
/* A forecast frame is not an observation, and the two must never look alike: nowcast
   frames and every model frame are marked in the accent, in italics, against the upright
   mono of a measured time. The layer's name sits under it because "+3:00" is meaningless
   until you know whose lead time it is. */
/* A forecast frame is not an observed one, and the accent used to say so alongside the
   italic. With the accent gone the pair becomes weight and italic against ink and upright —
   still two signals, still neither of them colour. */
.radar-frame-time.is-forecast { color: var(--muted); font-style: italic; }
/* Wraps; never ellipsised. This line names the layer driving the axis and, once frames
   carry real valid times, the RUN it came from — and two runs produce the same "Sun 06:00
   UTC" frame and disagree about it. `text-overflow: ellipsis` on a 220px box dropped the
   run label off the end of exactly the readings where it decides which frame is stale.
   Same rule as `.pagehead-sub` in shell.css: source, safety and status copy is not
   truncated. A second line here is cheaper than a sentence a reader cannot finish. */
.radar-frame-source {
  font-size: var(--fs-micro); letter-spacing: 0;
  text-transform: none; color: var(--muted);
  max-width: 220px; text-align: right;
}
.radar-frame-source.is-forecast { color: var(--muted); font-style: italic; }

/* ============================================================================
   Markers & popups
   ==========================================================================*/

.radar-storm-marker { display: flex; align-items: center; gap: 5px; background: none; border: 0; padding: 0; cursor: pointer; font: inherit; }
.radar-storm-dot {
  width: 13px; height: 13px; flex: none;
  border: 2px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5);
  background: var(--muted);
}
/* Wind-tier colours come from the shared chip ramp in styles.css — the same guardrail
   values, so a storm reads identically on the map and in the rail. */
/* The same ramp the chips use, from the same eight properties (styles.css, which every
   page with a map loads before this file). It was eight duplicated literals: the map and
   the list could disagree about what a Category 4 looks like, and only one of them was
   under test. */
.radar-storm-dot.tier-unknown { background: var(--wx-tier-unknown); }
.radar-storm-dot.tier-td { background: var(--wx-tier-td); }
.radar-storm-dot.tier-ts { background: var(--wx-tier-ts); }
.radar-storm-dot.tier-c1 { background: var(--wx-tier-c1); }
.radar-storm-dot.tier-c2 { background: var(--wx-tier-c2); }
.radar-storm-dot.tier-c3 { background: var(--wx-tier-c3); }
.radar-storm-dot.tier-c4 { background: var(--wx-tier-c4); }
.radar-storm-dot.tier-c5 { background: var(--wx-tier-c5); }
.radar-storm-name {
  font-family: var(--font-body); font-weight: 600; font-size: var(--fs-bulletin); color: #fff;
  text-shadow: 0 0 3px rgba(0, 0, 0, 0.9), 0 0 6px rgba(0, 0, 0, 0.7); white-space: nowrap;
}
.radar-invest-marker { display: block; width: 10px; height: 10px; border: 2px dashed rgba(255, 255, 255, 0.8); background: transparent; }
.radar-invest-marker.risk-high { background: rgba(224, 72, 58, 0.5); }
.radar-invest-marker.risk-medium { background: rgba(242, 165, 59, 0.5); }
.radar-invest-marker.risk-low { background: rgba(230, 207, 69, 0.5); }
.radar-invest-marker.risk-unknown { background: rgba(147, 164, 181, 0.5); }

/* The popup is drawn by MapLibre into its own container, outside the themed tree, so it
   carries explicit light-ground colours rather than tokens. */
.radar-popup { font-family: var(--font-body); font-size: var(--fs-bulletin); color: #1a2733; }
.radar-popup strong { font-family: var(--font-body); font-size: var(--fs-remarks); }
.radar-popup p { margin: var(--sp-1) 0 0; }
.radar-popup-meta { font-family: var(--font-mono); font-size: var(--fs-micro); color: #5c6b7a; }

/* MapLibre's own chrome, toned to the site rather than left in library default blue.

   The zoom group and the attribution button are the last rounded objects on the site: the
   library ships them at 4px and 12px with a 2px black halo, and nothing in `tokens.css`
   reaches them because MapLibre writes its own stylesheet. A computed-style sweep at
   320/390/1280 in both themes found these four and nothing else, which is the only reason
   they are named individually here rather than swept with a wildcard — a `[class^=maplibregl]`
   rule would also square things the library has not shipped yet. */
.maplibregl-ctrl-attrib { font-size: var(--fs-micro); }
.maplibregl-popup-content { padding: 11px var(--sp-3); }
.maplibregl-ctrl.maplibregl-ctrl-group {
  border-radius: 0;
  box-shadow: none;
  border: 1px solid var(--edge);
}
.maplibregl-ctrl-attrib.maplibregl-compact,
.maplibregl-ctrl-attrib-button { border-radius: 0; }

@media (max-width: 900px) {
  .radar-timeline { width: calc(100% - var(--sp-6)); }
  .radar-legend { max-width: 200px; bottom: 64px; }
}

/* --- Touch targets on a coarse pointer --------------------------------------------
   Measured at 390px in a touch context: MapLibre's own controls render 29x29, and the
   storm markers 20px tall. Both are things a finger is meant to hit.

   The map's attribution links ("OpenStreetMap", "CARTO", 11px tall) are deliberately
   left alone. They are inline links inside a sentence — the case WCAG's target-size
   rule exempts — and growing them would put opaque hit areas over the map they are
   attributing. */
/* WCAG 1.4.1 for MapLibre's own attribution control.

   Its links are #404040 on #000000 text — 2.02:1 where colour alone needs 3:1 — so a
   reader who cannot distinguish those greys cannot tell which words are clickable. The
   attribution is legally required and must stay readable, so it is fixed rather than
   restyled away.

   It lives here rather than in styles.css because maplibre-gl.css loads *after* that
   file and wins at equal specificity; radar.css is the only sheet that loads later. */
.maplibregl-ctrl-attrib-inner a,
.maplibregl-ctrl-attrib a {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

@media (pointer: coarse) {
  /* Vendored MapLibre ships 29px controls; this is the one place we override its CSS. */
  .maplibregl-ctrl button.maplibregl-ctrl-zoom-in,
  .maplibregl-ctrl button.maplibregl-ctrl-zoom-out,
  .maplibregl-ctrl button.maplibregl-ctrl-geolocate,
  .maplibregl-ctrl button.maplibregl-ctrl-compass,
  .maplibregl-ctrl button.maplibregl-ctrl-fullscreen {
    width: 44px;
    height: 44px;
  }

  /* Padding, not a pseudo-element. The masthead's trick does not survive here: a
     MapLibre marker is positioned over the canvas by the library, and an expanded
     ::after does not reliably win that stacking contest — measured, it took no taps at
     all. Padding grows the button's own box, which does.

     The dot and the label keep their drawn size, so the marker still points at the same
     pixel; only the region that accepts a tap grows. */
  .radar-storm-marker {
    padding-block: 12px;
  }
}

/* --- Every active feed is down ----------------------------------------------------
   Sits over the map, not in the layer panel, because on a phone that panel is a closed
   drawer and a reader who never opens it sees only an empty map — which is exactly what
   a working map over a quiet region looks like. */
.radar-outage {
  position: absolute;
  z-index: 3;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  max-width: min(92%, 30rem);
  display: grid;
  gap: 6px;
  padding: var(--sp-4);
  text-align: center;
  background: color-mix(in srgb, var(--paper) 94%, transparent);
  border: 2px solid var(--ink);
}
.radar-outage-title {
  margin: 0; font-family: var(--font-body); font-weight: 600;
  font-size: var(--fs-lead); color: var(--ink);
}
.radar-outage-body { margin: 0; font-size: var(--fs-bulletin); color: var(--ink); }
.radar-outage-link { font-size: var(--fs-bulletin); }

/* Radar's controls are controls; the global link underline does not apply to them. */
.radar-tool-btn, .radar-icon-btn, .radar-add, .radar-play { text-decoration: none; }
