/* Open map extras (base/templates/base/open_map.html): the USGS gauge
   overlay drawn by static/js/open_map_usgs.js. Everything else on the page is
   map_page.css, shared with a saved map. */

/* One-line status under the map: how many gauges and how fresh their colours
   are, "loading…", or "unavailable". (The gauges themselves are one MapLibre
   circle layer — there is no per-pin element to style.) */
.usgs-status {
  margin: 6px 0 0;
  min-height: 1.2em;
  font-size: 0.82rem;
  color: var(--ink-3, #6b7280);
}
.usgs-status.is-hint { color: var(--brand-blue-deep, #1f6f93); }
/* The pins come from our own catalogue in milliseconds, but USGS takes 3-14
   seconds to say what each one reads; while it is thinking the line ticks the
   elapsed seconds and wears a turning mark, so the wait is visible work
   rather than a map that seems to have stopped. */
.usgs-status.is-loading { color: var(--brand-blue-deep, #1f6f93); }
.usgs-status.is-loading::before {
  content: "";
  display: inline-block;
  width: 0.72em; height: 0.72em;
  margin-right: 0.45em;
  vertical-align: -0.06em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: usgs-spin 0.9s linear infinite;
}
/* The elapsed seconds: hidden from the accessibility tree by the script, so
   it is decoration for the eye and wants no weight of its own. */
.usgs-status__tick { font-variant-numeric: tabular-nums; opacity: 0.85; }
@keyframes usgs-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .usgs-status.is-loading::before { animation: none; }
}
.usgs-status.is-error { color: #991b1b; }
body.dark-mode .usgs-status.is-error { color: #fca5a5; }

/* A gauge's popup (static/js/open_map_usgs.js): name, site number, the
   condition class as a coloured dot beside its label, the latest value with
   its time and age, today's normal range, and the way out to USGS. The dot's
   colour is an SVG attribute set from the class table — no style attribute is
   written anywhere (CSP), and the palette lives in one place, the JS table
   pinned to base/usgs_conditions.py. */
.usgs-popup { font-size: 0.85rem; line-height: 1.35; }
.usgs-popup__name { display: block; }
.usgs-popup__site { color: var(--ink-3, #6b7280); font-size: 0.78rem; margin-bottom: 4px; }
/* What the station measures — a standing fact about the station, so it must
   not read as one of the numbers below it. */
.usgs-popup__measures { color: var(--ink-2, #4b5563); font-size: 0.78rem; margin-bottom: 4px; }
.usgs-popup__condition { display: flex; align-items: flex-start; gap: 6px; margin: 6px 0 2px; }
.usgs-popup__dot { flex: none; margin-top: 2px; }
.usgs-popup__conditionText { display: block; }
.usgs-popup__conditionLabel { display: block; font-weight: 600; }
.usgs-popup__conditionNote { display: block; color: var(--ink-3, #6b7280); font-size: 0.74rem; }
.usgs-popup__value { margin-top: 2px; font-variant-numeric: tabular-nums; }
.usgs-popup__flag { color: #92400e; font-size: 0.78rem; }
body.dark-mode .usgs-popup__flag { color: #fbbf24; }
.usgs-popup__normals { margin-top: 3px; color: var(--ink-2, #4b5563); font-size: 0.78rem; }
.usgs-popup__none { margin-top: 4px; color: var(--ink-3, #6b7280); }
/* The detail request is in flight: said in a different voice from a fact. */
.usgs-popup__pending { color: var(--brand-blue-deep, #1f6f93); font-style: italic; }
/* THE SAFETY AND ACCESS LINES on a mineral record, and the scope line on a
 * bedrock answer. Emphasised because a card row that reads like another
 * attribute is a row people skim: "never enter a mine opening" has to look
 * different from "Quadrangle q39124NEF4". Not red — red on this map is
 * reserved for a station in alarm, and borrowing it here would say a mine is
 * an emergency. A rule and a warm ink instead: it stops the eye without
 * claiming an urgency the record does not have. */
.usgs-popup__warn {
  margin-top: 5px;
  padding-left: 7px;
  border-left: 2px solid #b45309;
  color: #7c2d12;
  font-size: 0.78rem;
}
body.dark-mode .usgs-popup__warn { border-left-color: #f59e0b; color: #fcd9a8; }
.usgs-popup__error { color: #991b1b; }
body.dark-mode .usgs-popup__error { color: #fca5a5; }
.usgs-popup__link { display: inline-block; margin-top: 6px; text-decoration: underline; }
.usgs-popup__source { margin-top: 6px; font-size: 0.72rem; color: var(--ink-3, #6b7280); }

/* ---------------------------------------------------------------------- */
/* MapLibre (Wave 25)                                                      */
/*                                                                         */
/* This page is the site's one MapLibre map; every other map is Leaflet and */
/* keeps map.css. What is below is only what MapLibre needs and Leaflet did */
/* not: the DOM markers for the platform's own sensors and the handful of   */
/* vendor classes that have to be pulled into the site's own palette so the */
/* map does not arrive wearing MapLibre's.                                  */
/* ---------------------------------------------------------------------- */

/* One sensor pin: the shape plus its permanent name label. A grid rather
   than absolute positioning, so the label sits above the shape and the pair
   stays centred on the coordinate however long the name is. */
.nh-gl-pin {
  display: grid;
  justify-items: center;
  gap: 2px;
  cursor: pointer;
  line-height: 1;
}
.nh-gl-pin__shape { display: block; }
/* Frosted rather than solid, for the reason map.css records for the Leaflet
   tooltip it replaces: a translucent fill with a backdrop blur lifts the text
   off the tiles while still letting the map read through, so a dense cluster
   of labels does not become a wall of white boxes. Where backdrop-filter is
   unsupported the fill alone still carries it. */
.nh-gl-pin__label {
  background: rgba(255, 255, 255, 0.55);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
  border-radius: var(--r-xs, 4px);
  padding: 1px 6px;
  color: var(--ink);
  font-weight: 600;
  font-size: 12px;
  white-space: nowrap;
  text-shadow: 0 1px 2px rgba(255, 255, 255, 0.7);
}
.nh-gl-pin__label:empty { display: none; }
body.dark-mode .nh-gl-pin__label {
  background: rgba(26, 26, 25, 0.6);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
}

/* The pin dropped by the "Go to lat, long" box. */
.nh-gl-coordpin {
  width: 18px; height: 18px;
  border-radius: 50%;
  border: 3px solid var(--brand-gold, #cb8616);
  background: rgba(203, 134, 22, 0.25);
}

/* The map could not load at all (offline, blocked, a failed deploy): say so
   where the map would have been rather than leaving an empty grey box. */
.nh-gl-failed { padding: 1.5rem; color: var(--ink-3, #6b7280); text-align: center; }
.mp-empty { padding: 1rem; color: var(--ink-3, #6b7280); }

/* MapLibre's own chrome, brought into the site's palette. Only the four
   surfaces a visitor actually sees on this page — popup, controls,
   attribution and the cooperative-gesture veil — and only colour, radius and
   type; none of MapLibre's geometry is overridden, because that is what makes
   its anchors and tips line up. */
.maplibregl-popup-content {
  background: var(--surface, #ffffff);
  color: var(--ink);
  border: 1px solid var(--line, #e3e0d7);
  border-radius: var(--r-sm, 6px);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16);
  padding: 10px 12px;
  font-family: inherit;
}
.maplibregl-popup-tip { border-top-color: var(--surface, #ffffff); }
.maplibregl-popup-anchor-top .maplibregl-popup-tip,
.maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.maplibregl-popup-anchor-top-right .maplibregl-popup-tip {
  border-bottom-color: var(--surface, #ffffff);
  border-top-color: transparent;
}
.maplibregl-popup-close-button {
  color: var(--ink-3, #6b7280);
  font-size: 1.1rem;
  padding: 0 6px;
  background: transparent;
}
.maplibregl-popup-close-button:hover { background: var(--surface-2, #f4f2ec); }
.maplibregl-popup-close-button:focus-visible {
  outline: 3px solid var(--accent-ring, #2887b1);
  outline-offset: -2px;
}
.maplibregl-ctrl-group {
  border-radius: var(--r-sm, 6px);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.22);
}
.maplibregl-ctrl-attrib.maplibregl-compact { font-size: 0.7rem; }

/* Both of these are MapLibre controls, so they arrive inside a
   .maplibregl-ctrl slot rather than a .leaflet-control one; the panel and the
   coordinate box themselves are styled by map.css exactly as on every other
   map, and only the positioning context differs. */
.maplibregl-ctrl.map-panel,
.maplibregl-ctrl.coord-search { clear: both; pointer-events: auto; }

body.dark-mode .maplibregl-popup-content {
  background: var(--surface, #1a1a19);
  border-color: var(--line, #34342f);
}
body.dark-mode .maplibregl-popup-tip { border-top-color: var(--surface, #1a1a19); }
body.dark-mode .maplibregl-popup-anchor-top .maplibregl-popup-tip,
body.dark-mode .maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
body.dark-mode .maplibregl-popup-anchor-top-right .maplibregl-popup-tip {
  border-bottom-color: var(--surface, #1a1a19);
}

/* The pointer over a clickable gauge. A class rather than a style write,
   because nothing in open_map_usgs.js writes a style attribute. */
.nh-gl-hoverable { cursor: pointer; }

/* ---------------------------------------------------------------------- */
/* The control panel (static/js/open_map_panel.js)                         */
/*                                                                         */
/* Built on .map-panel from map.css, so this map's controls are the same    */
/* object every other map on the site has — same box, same head, same fold. */
/* What is here is only what the three views add: the active list at rest,  */
/* the grouped picker, the info card, the two legends and the filters.      */
/*                                                                         */
/* QUIET AT REST is the whole idea. Seventeen sources will not fit as       */
/* seventeen checkboxes, and a panel that covers a third of the map is not  */
/* a legend, so at rest this is a short list of what is ON and two ways in. */
/* ---------------------------------------------------------------------- */
/* A swatch whose layer handed over a bare CSS colour rather than markup — see
   `paintSwatch` in open_map_panel.js, which is the only thing that builds this
   node. Sized and ringed like the small circles the vector layers draw, so the
   flood-warning layer's key reads as the same kind of mark as its neighbours'
   rather than as a different shape that happens to be the right colour. */
.map-panel__dot {
  display: inline-block;
  width: 11px; height: 11px;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.45);
  align-self: center;
}

.open-panel { max-width: 17rem; }
/* The body is a scroll region and says so — see `.nh-scrollcue` in map.css
   for why, and open_map_panel.js for where the class is put on. Measured at
   1440x900 the rest view is 1168px of content in a 540px box, so more than
   half of this panel — the legend and the basemap among it — is below the
   fold on every visit. `--nh-cue-surface` is the panel's own background,
   because the technique paints opaque covers over the shadows at each end
   and a cover in the wrong colour is a stripe. */
.open-panel .map-panel__body {
  max-height: 60vh;
  overflow-y: auto;
  --nh-cue-surface: #fff;
}
body.dark-mode .open-panel .map-panel__body { --nh-cue-surface: #2a3b4a; }

/* SECONDARY INK, RE-TUNED FOR THE GROUND THE MAP FURNITURE ACTUALLY PAINTS.

   `--ink-3` is #8B8F92 in dark mode (tokens.css), chosen against the page's
   own dark ground. The map's floating furniture does not sit on that ground:
   the panel and the search box paint #2A3B4A, the two answer cards #23303C.
   Against #2A3B4A, #8B8F92 measures 3.53:1 — below the 4.5:1 AA needs for
   body text, and it was carrying almost all of the writing in the source
   browser. Measured in headless Chromium at 1440x900 with the browser open:
   33 failing elements, every one of them 3.53:1, including all twenty-two
   layer blurbs, all five group headings and their counts, the "i" on every
   info button, and the "Search sensors and gauges" label; the flood card's
   hint failed at 4.13:1 on the darker #23303C. Light mode measured zero
   failures, which is why this went unseen — the panel is white there and the
   same token clears 5:1. The tide card inside a station card is the same
   fault a layer deeper: thirteen more elements at 4.13:1 on #23303C, the
   constituent table and every method note under it.

   Redefining the variable ON these surfaces rather than editing the token or
   listing thirty selectors: every `var(--ink-3)` inside them inherits the
   corrected value, including ones added later, and nothing outside the map's
   furniture is touched. #B9C9D6 is not a new colour — it is the secondary
   ink open_map_gallery.css already uses on this exact #2A3B4A ground — and
   it measures 6.8:1 on #2A3B4A and 8.0:1 on #23303C. */
body.dark-mode .open-panel,
body.dark-mode .station-search,
body.dark-mode .flood-ctrl,
body.dark-mode .nh-wsctrl,
body.dark-mode .tide-card,
body.dark-mode .glofas-card { --ink-3: #B9C9D6; }

/* A count of what is switched on, in the head, so the fold is not a way to
   lose track of it. */
.open-panel__badge {
  display: inline-block;
  min-width: 1.15rem;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--accent-tint, #E6F0F5);
  color: var(--accent-tint-ink, #175571);
  font-size: 0.7rem; font-weight: 700; text-align: center;
  font-variant-numeric: tabular-nums;
}

/* One row per switched-on source: swatch, name, count in view, and a way off.
   The count is the point of the row — it is the answer to "is this layer
   doing anything here?" and it comes from the response the overlay already
   has, never from a query of the panel's own. */
.open-panel__active {
  display: flex; align-items: flex-start; gap: 7px;
  padding: 4px 0;
  border-top: 1px solid var(--line, #e3e0d7);
}
.open-panel__active:first-of-type { border-top: 0; }
.open-panel__activeText { flex: 1 1 auto; min-width: 0; }
.open-panel__count {
  display: block;
  color: var(--ink-3, #746E62);
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
}
/* The per-layer age, under the count on the row it describes. Same size and
   colour as the count: it is the same KIND of fact — a small number about the
   answer, not about the water — and giving it its own weight would make every
   row shout. */
.open-panel__age {
  display: block;
  color: var(--ink-3, #746E62);
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
}
/* A layer past its OWN promise. Not red: this is "worth a look", not an
   error, and the map is full of layers that are legitimately a day old.

   THE TOKEN IS `--warning-ink`. This rule asked for `--warn-ink`, which is
   defined nowhere in the stylesheets, so every visit fell through to the
   literal — and the literal is the LIGHT-mode value. On the panel's dark
   ground that measured 1.95:1 against a 4.5:1 requirement: "never confirmed",
   the line whose entire job is to be noticed, all but invisible in dark mode.
   Found by measuring the phone at 390x844 in dark, where the sheet opens on
   the view that carries these ages. tokens.css already had the answer —
   #E0A446 in dark, 5.2:1 on #2A3B4A — and the rule simply never reached it.
   The fallback is now the token's own light value rather than a near-miss of
   it, so the two agree if it is ever reached again. */
.open-panel__age.is-stale {
  color: var(--warning-ink, #8A5A0D);
  font-weight: 600;
}
/* The one summary line that replaced eight repetitions below the map. */
.open-panel__freshness {
  margin: 8px 0 0;
  color: var(--ink-3, #746E62);
  font-size: 0.72rem;
  line-height: 1.35;
}
.open-panel__off {
  flex: none;
  border: 0; background: none; padding: 1px 4px;
  font: inherit; font-size: 0.72rem;
  color: var(--link, #1F6D8F); cursor: pointer; text-decoration: underline;
}
.open-panel__off:focus-visible,
.open-panel__browse:focus-visible,
.open-panel__back:focus-visible,
.open-panel__info:focus-visible,
.open-panel__segment:focus-visible,
.open-panel__legendHead:focus-visible,
.open-panel__groupHead:focus-visible {
  outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 1px;
}

.open-panel__browse, .open-panel__back {
  display: block; width: 100%;
  margin: 8px 0 2px;
  padding: 5px 8px;
  border: 1px solid var(--line-strong, #CFCABD);
  border-radius: var(--r-xs, 4px);
  background: var(--surface-2, #F4F2EC);
  font: inherit; font-size: 0.76rem; font-weight: 600;
  color: var(--ink-2, #56534C);
  cursor: pointer;
  text-align: center;
}
.open-panel__browse:hover, .open-panel__back:hover { background: var(--band, #F0ECE2); }
.open-panel__back { text-align: left; margin-top: 2px; }
.open-panel__back::before { content: "\2190\00a0"; }

.open-panel__empty, .open-panel__note {
  margin: 4px 0; color: var(--ink-3, #746E62); font-size: 0.72rem; line-height: 1.35;
}

/* The picker. A group is a <details>, so the fold is the browser's and works
   from the keyboard without a line of JavaScript. */
.open-panel__search {
  width: 100%;
  margin: 6px 0 2px;
  padding: 4px 7px;
  border: 1px solid var(--line-strong, #CFCABD);
  border-radius: var(--r-xs, 4px);
  background: var(--field, #fff);
  color: var(--ink);
  font: inherit; font-size: 0.78rem;
}
.open-panel__group { margin: 4px 0; }
.open-panel__groupHead {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  cursor: pointer;
  padding: 3px 0;
  font-size: var(--fs-0, 0.7rem);
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--ink-3, #746E62);
}
.open-panel__groupCount { font-variant-numeric: tabular-nums; letter-spacing: 0; }
.open-panel__pick { padding: 1px 0 3px; position: relative; }
/* THE INFO BUTTON GETS A GUTTER, IT DOES NOT SHARE THE NAME'S SPACE.
   `.open-panel__info` below is absolutely positioned against this row, so it
   is out of flow and a long layer name simply ran underneath it. Measured at
   1440x900 in the source browser: "Watershed boundaries — HUC12 (USGS WBD)"
   ended at x1400 against a button starting at x1383 — 17px of collision, with
   "USACE water management (CWMS)" at 12px and "Soil and land cover (NRCS,
   MRLC)" at 3px, so the closing bracket of three of the twenty-two rows was
   printed through a button. 23px is the button's own 17px plus the 6px gap,
   and is the same 23px the blurb below is already indented by, so the name
   column and the blurb column line up on both edges. */
.open-panel__pick .map-panel__row { padding-right: 23px; }
.open-panel__blurb {
  margin: 0 23px 0 23px;
  color: var(--ink-3, #746E62); font-size: 0.7rem; line-height: 1.35;
}
/* The info affordance: hover gives the one-liner (title), the button gives
   the card. Same information, two depths, and the cheap one costs no click. */
.open-panel__info {
  position: absolute; top: 1px; right: 0;
  width: 17px; height: 17px;
  border: 1px solid var(--line-strong, #CFCABD);
  border-radius: 50%;
  background: transparent;
  color: var(--ink-3, #746E62);
  font: inherit; font-size: 0.66rem; font-weight: 700; font-style: italic;
  line-height: 1; cursor: pointer;
}
.open-panel__info:hover { background: var(--accent-tint, #E6F0F5); color: var(--accent-tint-ink, #175571); }

/* The info card. A definition list in all but name — key above value, because
   the panel is too narrow for two columns and a wrapped value beside a key is
   harder to read than one beneath it. */
.open-panel__card { margin-top: 6px; }
.open-panel__cardName { margin: 0 0 4px; font-size: 0.86rem; }
.open-panel__cardKey {
  margin-top: 6px;
  font-size: var(--fs-0, 0.7rem); text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--ink-3, #746E62);
}
.open-panel__cardValue { margin: 1px 0 0; font-size: 0.74rem; line-height: 1.4; }
/* A caveat is not fine print: it is the sentence that stops a reader treating
   a provisional number, or a three-month-old lab sample, as a live reading. */
.open-panel__caveat {
  margin: 6px 0 0;
  padding-left: 7px;
  border-left: 2px solid var(--provisional, #8A5A0D);
  color: var(--ink-2, #56534C);
  font-size: 0.72rem; line-height: 1.4;
}
.open-panel__link { display: inline-block; margin-top: 8px; font-size: 0.74rem; }

/* The legend: every source that is on, and under a source that registered
   one, its own key — the USGS layer's eleven condition classes. The "Shape:
   the station" block is drawn only for an overlay that asks for it. */
.open-panel__legend { margin-top: 2px; }
.open-panel__legendHead {
  padding: 6px 0 2px;
  cursor: pointer;
  font-size: 0.74rem; font-weight: 600;
  color: var(--ink-2, #56534C);
}
.open-panel__legendBlock { margin-bottom: 4px; }
.open-panel__state { align-items: flex-start; }
.open-panel__stateText { display: block; }
.open-panel__state .open-panel__note { margin: 0; }
/* A source's own rows, indented past its swatch so they read as an
   explanation of that source rather than more sources. */
.open-panel__legendRows { margin: 1px 0 4px 10px; }
.open-panel__legendRows .map-panel__key { margin: 1px 0; }
.open-panel__legendRows .open-panel__note { font-size: 0.68rem; }
/* A key row is a NAME and, under it, the sentence explaining it. Both are
   spans, so they need saying: without this the two run together as one
   paragraph ("FloodingAt or above an official flood stage"), which is how the
   shared water scale's key first drew on 2026-09-06. */
.open-panel__state .map-panel__name,
.open-panel__state .open-panel__note { display: block; }
/* The state swatches take their stroke from the text colour, so the key is
   drawn in whatever ink the panel is using and reads in both themes. */
.open-panel__state .map-panel__swatch { color: var(--ink-2, #56534C); }

/* ==================================================== THE SHARED WATER SCALE
   One key for "how is the water?", drawn once above every layer that paints
   it (2026-09-06, audit/open-map-colour/STUDY.md Part 3). It is IN THE OPEN
   rather than behind the fold below, because it is now the primary encoding
   of nine thousand pins rather than one layer's private vocabulary. */
.open-panel__scale {
  margin: 8px 0 0;
  padding-top: 7px;
  border-top: 1px solid var(--line, #e3e0d7);
}
.open-panel__scale > .open-panel__note { margin: 2px 0 4px; }
.open-panel__scale .open-panel__legendRows { margin-left: 0; }
/* How old each layer's answer is and how often it is recomputed. Set apart
   from the key by a hairline so it reads as provenance, not as more classes. */
.open-panel__scaleAges {
  margin: 5px 0 3px;
  padding-top: 4px;
  border-top: 1px dashed var(--line, #e3e0d7);
}
.open-panel__scaleAges .open-panel__note { margin: 1px 0; font-size: 0.68rem; }
/* The Agency colours switch: a checkbox and its label on one line, the
   sentence explaining it beneath, indented past the box. */
.open-panel__switch {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 6px;
  align-items: center;
  margin: 6px 0 2px;
  font-size: 0.73rem;
  cursor: pointer;
}
.open-panel__switch input { margin: 0; }
.open-panel__switch .open-panel__note {
  grid-column: 2;
  margin: 0;
  font-size: 0.67rem;
  line-height: 1.35;
}

/* THE ONE VISIBLE BUTTON. A MapLibre control beside the zoom, so the pins the
   map is holding back are never held back silently. It is a whole sentence
   wide on purpose — "Show 12,431 unranked / stale" says the rule, the number
   and the way out in the space a bare icon would have said nothing. */
/* MapLibre's control group is sized for a 29px icon; this one is a sentence,
   so it takes its own width and keeps the group's card and shadow. */
.nh-stale-ctrl.maplibregl-ctrl-group {
  pointer-events: auto;
  width: auto;
  max-width: 15rem;
  background: var(--surface, #ffffff);
  overflow: hidden;
}
body.dark-mode .nh-stale-ctrl.maplibregl-ctrl-group { background: var(--surface, #1a1a19); }
/* MapLibre sizes every button in a control group to a 29px SQUARE, at a
   higher specificity than a single class — so this one says its own size at
   the same weight. A sentence in a 29px box is what the button first drew as. */
.nh-stale-ctrl.maplibregl-ctrl-group button.nh-stale-ctrl__btn {
  display: block;
  width: 100%;
  height: auto;
  border: 0;
  border-radius: inherit;
  background: none;
  padding: 6px 10px;
  font: inherit;
  font-size: 0.72rem;
  line-height: 1.3;
  text-align: left;
  white-space: normal;
  color: var(--ink-1, #23211C);
  cursor: pointer;
}
.nh-stale-ctrl.maplibregl-ctrl-group button.nh-stale-ctrl__btn:hover {
  background: var(--surface-2, #f4f2ec);
}
.nh-stale-ctrl.maplibregl-ctrl-group button.nh-stale-ctrl__btn:focus-visible {
  outline: 3px solid var(--accent-ring, #2887b1);
  outline-offset: -2px;
}
.nh-stale-ctrl.maplibregl-ctrl-group button.nh-stale-ctrl__btn[aria-pressed="true"] {
  font-weight: 600;
}
body.dark-mode .nh-stale-ctrl.maplibregl-ctrl-group button.nh-stale-ctrl__btn {
  color: var(--ink-1, #EDE9E0);
}
body.dark-mode .nh-stale-ctrl.maplibregl-ctrl-group button.nh-stale-ctrl__btn:hover {
  background: #2a3b4a;
}

/* THE HOVER TOOLTIP — the first legend surface that is on the map itself.
   It says the state, or the REASON a pin is grey, without a click. Narrow,
   quiet, and never in the way of the pointer (`pointer-events: none`). */
.nh-scale-hover { pointer-events: none; }
.nh-scale-hover .maplibregl-popup-content {
  padding: 5px 8px;
  font-size: 0.72rem;
  line-height: 1.3;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
}

/* THE CARD'S TWO ROWS. The shared scale first — what the pin was painted
   from — and the agency's own class beneath it, stepped in and quieter, as
   the second opinion it now is rather than the headline it used to be. */
.usgs-popup__state { margin-top: 7px; }
.usgs-popup__stateDot { display: inline-flex; flex: none; }
.usgs-popup__stateDot svg { display: block; }
.usgs-popup__agency { margin-left: 10px; opacity: 0.86; }
.usgs-popup__agency .usgs-popup__conditionLabel {
  font-weight: 500;
  font-size: 0.76rem;
}

/* The one sentence that says what colour MEANS, above the folded key. It is
   the rule the whole map obeys, so it is not typeset as a footnote. */
.open-panel__legendRule {
  margin: 8px 0 0;
  padding-top: 7px;
  border-top: 1px solid var(--line, #e3e0d7);
  font-size: 0.71rem; line-height: 1.4;
  color: var(--ink-2, #56534C);
}
.open-panel__legendRule strong { font-weight: 700; }

/* Filters as dropdowns, not more checkboxes: a checkbox says "also show me
   these" and these say "show me ONLY these", which is a different question.
   The block folds (open_map_panel.js says why); its head is styled like the
   key's so the two folds in this panel read as the same kind of thing. */
.open-panel__filters { margin-top: 6px; }
.open-panel__filtersHead {
  display: flex; align-items: baseline; gap: 6px;
  padding: 6px 0 2px;
  cursor: pointer;
  font-size: 0.74rem; font-weight: 600;
  color: var(--ink-2, #56534C);
}
.open-panel__filtersHead:focus-visible {
  outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 1px;
}
.open-panel__filters.is-empty { margin-top: 0; }
.open-panel__filter { display: block; margin: 3px 0; }
.open-panel__filterLabel { display: block; font-size: 0.72rem; color: var(--ink-3, #746E62); }
.open-panel__select {
  width: 100%;
  padding: 3px 5px;
  border: 1px solid var(--line-strong, #CFCABD);
  border-radius: var(--r-xs, 4px);
  background: var(--field, #fff);
  color: var(--ink);
  font: inherit; font-size: 0.75rem;
}
.open-panel__select:disabled { opacity: 0.55; cursor: not-allowed; }
.open-panel__select:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 1px; }

.open-panel__basemaps { margin-top: 8px; }
.open-panel__segmented {
  display: flex;
  border: 1px solid var(--line-strong, #CFCABD);
  border-radius: var(--r-xs, 4px);
  overflow: hidden;
}
.open-panel__segment {
  flex: 1 1 0;
  border: 0; border-left: 1px solid var(--line-strong, #CFCABD);
  padding: 4px 6px;
  background: var(--surface, #fff);
  font: inherit; font-size: 0.74rem;
  color: var(--ink-2, #56534C);
  cursor: pointer;
}
.open-panel__segment:first-child { border-left: 0; }
.open-panel__segment.is-on {
  background: var(--accent, #1F6D8F); color: var(--accent-ink, #fff); font-weight: 600;
}

/* Find a station: the one question this map answers that is not about the
   viewport. Debounced and bounded in the script; here it is just a box. */
.station-search {
  background: var(--surface, #fff);
  border-radius: var(--r-sm, 6px);
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.35);
  padding: 6px 8px;
  width: 14rem;
  max-width: 60vw;
}
.station-search__label {
  display: block;
  font-size: var(--fs-0, 0.7rem); text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--ink-3, #746E62);
}
.station-search__input {
  width: 100%;
  padding: 4px 7px;
  border: 1px solid var(--line-strong, #CFCABD);
  border-radius: var(--r-xs, 4px);
  background: var(--field, #fff);
  color: var(--ink);
  font: inherit; font-size: 0.78rem;
}
.station-search__input:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 1px; }
.station-search__status {
  margin: 3px 0 0; min-height: 1em;
  color: var(--ink-3, #746E62); font-size: 0.7rem;
}
.station-search__list { list-style: none; margin: 2px 0 0; padding: 0; max-height: 40vh; overflow-y: auto; }
.station-search__hit {
  display: block; width: 100%;
  padding: 4px 5px;
  border: 0; border-radius: var(--r-xs, 4px);
  background: none;
  font: inherit; text-align: left; cursor: pointer;
  color: var(--ink);
}
.station-search__hit:hover { background: var(--surface-2, #F4F2EC); }
.station-search__hit:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: -1px; }
/* The two halves of an answer, each under its source (Wave 25). Without the
   heading a row reading "Headworks" and a row reading "SACRAMENTO R AT FREEPORT"
   sit in one undifferentiated list and the reader has to click to find out
   which is one of ours. Sticky, because the list scrolls at 40vh and a heading
   that scrolls away takes the answer to that question with it. */
.station-search__group {
  position: sticky; top: 0;
  padding: 3px 5px 2px;
  background: var(--surface, #fff);
  color: var(--ink-3, #746E62);
  font-size: 0.64rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
}
/* Every row is an <li>, headings included, so the separator is "a heading that
   is not the first thing in the list". */
.station-search__list li + .station-search__group { margin-top: 4px; }
body.dark-mode .station-search__group { background: #2a3b4a; }
.station-search__name { display: block; font-size: 0.76rem; line-height: 1.25; }
.station-search__id {
  display: block;
  color: var(--ink-3, #746E62); font-size: 0.68rem; font-variant-numeric: tabular-nums;
}

body.dark-mode .open-panel__browse, body.dark-mode .open-panel__back,
body.dark-mode .open-panel__segment { background: #223140; color: var(--ink); }
body.dark-mode .open-panel__segment.is-on { background: var(--accent, #1F6D8F); color: #fff; }
body.dark-mode .open-panel__select,
body.dark-mode .open-panel__search,
body.dark-mode .station-search__input { background: #1b2733; color: var(--ink); border-color: #40556a; }
body.dark-mode .station-search { background: #2a3b4a; color: var(--ink); }
body.dark-mode .station-search__hit { color: var(--ink); }
body.dark-mode .station-search__hit:hover { background: #33475a; }
body.dark-mode .open-panel__state .map-panel__swatch { color: var(--ink); }

/* On a phone the panel is a BOTTOM SHEET, not a shrunken desktop panel: it
   spans the width, sits against the bottom edge where a thumb is, and folds
   to its header so the map is never mostly panel. MapLibre positions its
   control corners absolutely, so the corner itself is what moves. */
@media (max-width: 640px) {
  .maplibregl-ctrl-top-right:has(.open-panel) {
    position: absolute;
    top: auto; right: 0; bottom: 0; left: 0;
    display: block;
    /* WHY THIS LINE EXISTS (2026-09-04). Moving the corner to the bottom put
       it in the same place as `.maplibregl-ctrl-bottom-right`, which MapLibre
       appends to the control container AFTER this one — so with no z-index
       the attribution painted on top of the sheet. Measured at 360x780:
       the Layers header was a 176x30 box at y539-569 and
       `document.elementFromPoint()` at its centre returned
       `DIV.maplibregl-ctrl-attrib-inner`; a click on it timed out. There
       were no layer toggles, no legend and no source browser on a phone at
       all. The sheet is the reader's control surface and the attribution is
       a line of credit, so the sheet is on top and the credit lifts clear
       of it (below) rather than the other way round. */
    z-index: 3;
  }
  /* Selector deliberately as specific as MapLibre's own
     `.maplibregl-ctrl-top-right .maplibregl-ctrl`, which sets `float: right`
     and `margin: 10px 10px 0 0`. A plain `.open-panel` lost to it: the float
     and the right margin survived, so `width: 100%` made a 330px box inside a
     320px corner and it floated 10px off the map's left edge. */
  .maplibregl-ctrl-top-right .maplibregl-ctrl.open-panel {
    max-width: none;
    margin: 0;
    border-radius: var(--r-sm, 6px) var(--r-sm, 6px) 0 0;
    box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.28);
    /* MapLibre floats every `.maplibregl-ctrl`, so `max-width: none` alone
       left the sheet shrink-wrapped to its own text — measured 176px of a
       320px map, a sheet in name only and a small target for a thumb. */
    float: none;
    width: 100%;
  }
  /* UNFOLDED, THE SHEET IS THE SCREEN'S, NOT THE MAP'S (2026-09-04).
     Folded it is a 30px bar on the map's bottom edge and stays there. Open
     it and it becomes what a phone bottom sheet is: anchored to the
     VIEWPORT, the same 56vh the station card uses, with the map showing
     through above it. Anchoring an OPEN sheet to the map instead is what
     made this unusable — measured at 360x780 the map is 351px tall, the
     unfolded panel 381px, so the sheet was taller than the box it hung
     inside: its own header sat above the map's top edge, and the bottom
     controls, lifted by its full height, were thrown off the map
     altogether. Same argument, and the same 56vh, as the card dock's phone
     block at the foot of this file. */
  .maplibregl-ctrl-top-right:has(.open-panel:not(.is-collapsed)) {
    position: fixed;
    top: auto; bottom: 0; left: 0; right: 0;
    /* Below the station card (`#plotOverlay` is z-index 2000 in map.css): a
       card a reader opened is the thing they are reading, and the sheet
       must not land on top of it. */
    z-index: 900;
  }
  .maplibregl-ctrl-top-right .maplibregl-ctrl.open-panel:not(.is-collapsed) {
    border-radius: var(--r-sm, 6px) var(--r-sm, 6px) 0 0;
  }
  /* 32px is the folded header; the rest of the sheet is the scroll region. */
  .open-panel .map-panel__body { max-height: calc(var(--nh-dock-height, 56vh) - 32px); }
  .station-search { width: auto; max-width: none; }

  /* The scale bar and the OSM/Esri attribution lift by however tall the
     Layers sheet currently is (`--nh-panel-lift`, measured by
     open_map_panel.js with a ResizeObserver, so folding and unfolding the
     sheet moves them). Attribution is a licence condition, not decoration:
     it must be legible, and burying it under our own panel is not a
     trade-off we are entitled to make. It stacks with the card dock's own
     lift, because on a phone a station card and the Layers sheet can be
     over the map at the same time. */
  /* NOT the time bar's lift, on a phone alone — and this is a measurement,
     not an oversight. At 390x844 the map is 350x380 and the furniture over it
     already exceeds that: the top-left stack (search, flood answer, watershed
     answer, plus MapLibre's own zoom and locate) runs to ~355 of those 380px,
     and MapLibre's compact attribution opens to 330x84 on its own. Adding the
     bar's 122px to these corners lifted the attribution INTO the search box —
     `elementFromPoint()` at the search input's centre came back
     `DIV.maplibregl-ctrl-attrib-inner`, a control that had been reachable
     before. Trading a buried attribution for a buried search box is not a fix.
     So on a phone the bar clears the Layers sheet by sitting above it (which
     is what recovered the sheet's header) and the two bottom corners stay
     where they were. The attribution is still under the bar here, which is
     wrong and is written down rather than papered over: it needs a decision
     about which controls a 380px map shows at all, not another lift. */
  .maplibregl-ctrl-bottom-right,
  .maplibregl-ctrl-bottom-left {
    margin-bottom: calc(var(--nh-dock-map-overlap, 0px) + var(--nh-panel-lift, 0px));
  }
  /* And the sheet itself gets out of the way of an open station card, which
     is anchored to the VIEWPORT and would otherwise bury the Layers header
     the same way the attribution buried it. */
  body.nh-card-docked .maplibregl-ctrl-top-right:has(.open-panel) {
    margin-bottom: var(--nh-dock-map-overlap, 0px);
  }

  /* THE DECISION THE NOTE ABOVE ASKED FOR (2026-09-06, sweep finding L1-5).
     Measured at 390x844 the map was 380px tall (map.css gives it 45vh on a
     phone) and at 360x740 it was 333px, while the top-left stack — zoom,
     locate, the station search, the Watershed answer, Draw a shape — ran
     331px from the map's top edge. So Draw a shape sat under the coordinate
     box, the scale bar, the attribution AND the folded Layers bar, all of
     which are pinned to the bottom edge: five measured overlaps, and at
     360x740 `elementFromPoint()` at the draw button's centre could answer
     with any of them. Two decisions, not another lift:

       - The map is never shorter than 480px on a phone. The furniture that
         has to fit on it is ~340px of controls down the left plus ~75px of
         bottom edge (the folded sheet and the scale bar lifted above it),
         and 45vh of a 740px screen is less than that. 480px still sits
         inside a 740px viewport under the page header.
       - The coordinate box is not shown on a phone at all. The station
         search above it already takes "38.53, -121.97" and lists it as a
         Coordinates hit, so nothing a thumb could do is lost, and the
         bottom-left corner then holds the scale bar and nothing else.

     Verified with Playwright at 390x844 and 360x740 after the change: no
     two visible controls intersect and the draw button answers
     elementFromPoint() with itself (audit/playwright-sweep/shots/fix-l1/). */
  #map { min-height: 480px; }
}

/* --------------------------------------------------------------------------
   Monitor My Watershed overlay (static/js/open_map_mmw.js)
   --------------------------------------------------------------------------
   The status line reuses `.usgs-status` — it is the same control in the same
   place doing the same job, and duplicating forty declarations to rename them
   would leave two blocks to keep in step. `.mmw-status` only carries what is
   genuinely different: it sits under the USGS line rather than beside it.

   The popup and chart do get their own block, because they are a different
   shape: an MMW popup carries an organisation and a row of measurement
   buttons where a USGS one carries a reading list, and the accent is teal
   rather than green so the two layers stay distinguishable inside a popup as
   well as on the map. */
.mmw-status { margin-top: 2px; }

.mmw-popup { font-size: 0.85rem; line-height: 1.35; }
.mmw-popup__name { display: block; }
.mmw-popup__site { color: var(--ink-3, #6b7280); font-size: 0.78rem; }
.mmw-popup__org { color: var(--ink-2, #4b5563); font-size: 0.78rem; }
.mmw-popup__type { color: var(--ink-3, #6b7280); font-size: 0.78rem; }
.mmw-popup__state { margin: 4px 0; color: var(--ink-2, #4b5563); font-size: 0.78rem; }
.mmw-popup__link { display: inline-block; margin-top: 4px; text-decoration: underline; }
.mmw-popup__source { margin-top: 6px; font-size: 0.72rem; color: var(--ink-3, #6b7280); }

.mmw-chart { margin-top: 8px; border-top: 1px solid var(--line, #e5e7eb); padding-top: 6px; }
.mmw-chart__svg { display: block; max-width: 100%; height: auto; }
.mmw-chart__state { margin: 6px 0; color: var(--ink-3, #6b7280); font-size: 0.8rem; }
.mmw-chart__state.is-loading { color: var(--brand-blue-deep, #1f6f93); font-style: italic; }
.mmw-chart__state.is-error { color: #991b1b; }
.mmw-chart__line { fill: none; stroke: #0f766e; stroke-width: 1.6;
                   stroke-linejoin: round; stroke-linecap: round; }
.mmw-chart__now { fill: #0f766e; }
.mmw-chart__axis { fill: none; stroke: var(--line-strong, #cbd5e1); stroke-width: 1; }
.mmw-chart__tick { font-size: 8px; fill: var(--ink-3, #6b7280); }
.mmw-chart__summary { margin: 4px 0 0; font-size: 0.72rem; line-height: 1.35;
                      color: var(--ink-2, #4b5563); }
/* Wraps, unlike the USGS chart's two tabs: an EnviroDIY station can offer nine
   measurements and a single row of nine buttons would push the popup wider
   than the map. */
.mmw-chart__tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.mmw-chart__tab { font: inherit; font-size: 0.72rem; padding: 2px 7px; cursor: pointer;
                  border: 1px solid var(--line-strong, #cbd5e1); border-radius: 999px;
                  background: var(--surface-2, #f8fafc); color: inherit; }
.mmw-chart__tab.is-on { background: #0f766e; border-color: #0f766e; color: #ffffff; }

.mmw-cell-tip { font-size: 0.82rem; font-weight: 600; line-height: 1.3; }
.mmw-cell-tip__hint { font-weight: 400; font-size: 0.72rem; color: var(--ink-3, #6b7280); }
.mmw-cell-popup { pointer-events: none; }
.mmw-cell-popup .maplibregl-popup-content { padding: 6px 9px; }

/* The series window (static/js/open_map_series_window.js): the platform's
   plot dialog, fed by a USGS gauge or a Monitor My Watershed station. The
   charts wear .plot-window__chart so map_dashboard.js purges them on close;
   these are only the pieces around them. */
.series-window__charts { margin-top: 6px; }
.series-window__series + .series-window__series { margin-top: 10px; border-top: 1px solid var(--line, #e5e7eb); padding-top: 8px; }
.series-window__label { margin: 4px 0 0; font-weight: 600; }
/* THE THRESHOLDS THAT DID NOT FIT. A flood stage far above a gauge reading
   below action stage used to set the y-axis and flatten the fortnight of data
   into a line on the floor (see chartRange in open_map_series_window.js). The
   axis now belongs to the data, so a stage that is off the top of the chart is
   said HERE instead — with its distance, so "off the chart" is a measurement
   rather than an absence. Marked with the same red the lines are drawn in. */
.series-window__offscale {
  margin: 4px 0 0;
  padding-left: 8px;
  border-left: 2px dotted #e63232;
  font-size: 0.76rem;
  line-height: 1.35;
  color: var(--ink-2, #4b5563);
  font-variant-numeric: tabular-nums;
}
body.dark-mode .series-window__offscale { border-left-color: #fca5a5; color: var(--ink-3); }
.plot-window__msg.is-error { color: #991b1b; }
body.dark-mode .plot-window__msg.is-error { color: #fca5a5; }
/* A station's own summary block above its charts (the USGS condition card,
   the MMW organisation line): the popup styles, reused in the window. */
.series-window__head { margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid var(--line, #e5e7eb); }
/* One button per further variable a station records — the first is charted
   on open, the rest on request, so a click costs one upstream request. */
.series-window__vars { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.series-window__var { font: inherit; font-size: 0.8rem; padding: 3px 10px; cursor: pointer;
  border: 1px solid var(--line-strong, #cbd5e1); border-radius: 999px;
  background: transparent; color: var(--ink-2, #4b5563); }
.series-window__var.is-on { background: #1f6f93; border-color: #1f6f93; color: #ffffff; }
.series-window__var:disabled { opacity: 0.6; cursor: default; }

/* --------------------------------------------------------------------------
   Monitor My Watershed, whole-catalogue shape (static/js/open_map_mmw.js,
   2026-09-02). The pins are one circle layer; the legend rows are constant
   SVG swatches drawn with the paint's own numbers; a click opens the series
   window rather than a popup, so what is left to style is the head block
   above the charts and the meta link beside the title. The .mmw-popup and
   .mmw-chart rules above are the old popup's and no longer have a caller. */
.mmw-head { font-size: 0.85rem; line-height: 1.4; }
.mmw-head__site { color: var(--ink-3, #6b7280); font-size: 0.8rem; }
.mmw-head__state { margin-top: 3px; color: var(--ink-2, #4b5563); }
.mmw-head__source { margin-top: 4px; font-size: 0.74rem; color: var(--ink-3, #6b7280); }
.mmw-head__link { text-decoration: underline; }
/* The teal is the layer's: a charted MMW variable's button matches its pin. */
.series-window__vars--mmw .series-window__var.is-on { background: #0f766e; border-color: #0f766e; }
.plot-window__msg.is-loading { color: var(--brand-blue-deep, #1f6f93); font-style: italic; }
/* static/js/plotly_on_demand.js: a chart whose drawing library is still on
   its way. Same voice as the loading message above. */
.plot-window__loading-chart { margin: 0.5rem 0; font-size: 0.85rem;
  color: var(--brand-blue-deep, #1f6f93); font-style: italic; }
body.dark-mode .plot-window__loading-chart { color: #8cc8e8; }
.plot-window__msg.is-hint { color: var(--ink-2, #4b5563); }
/* The two things a reader can do with a third-party station, as links styled
   as buttons: open it on the analytics page, or adopt it as a sensor so an
   alert can hang off it. Same-origin, so no external-link affordance. */
.series-window__actions { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 4px; }
.series-window__action { display: inline-block; font-size: 0.8rem; padding: 4px 12px;
  border: 1px solid #0f766e; border-radius: 999px; color: #0f766e;
  background: transparent; text-decoration: none; }
.series-window__action:hover, .series-window__action:focus-visible {
  background: #0f766e; color: #ffffff; }
/* The river buttons (Upstream / Downstream / Watershed) are <button>, not
   <a>: they draw on the map rather than navigating anywhere. A button
   inherits neither the page font nor a pointer cursor, so without this it
   renders in the browser's own UI font beside its identical-looking
   neighbours. */
button.series-window__action { font: inherit; font-size: 0.8rem; cursor: pointer;
  line-height: 1.45; }
button.series-window__action:disabled { opacity: 0.6; cursor: default; }
button.series-window__action.is-error { border-color: #991b1b; color: #991b1b; }
body.dark-mode button.series-window__action.is-error { border-color: #fca5a5; color: #fca5a5; }
/* A PARTIAL walk: the river IS drawn, so this is not an error — amber rather
   than red, and the button keeps working. The sentence naming what is missing
   (usually the basin, when the index used up the twenty-five seconds one walk
   is allowed) is in the tooltip. See `shortfall` in static/js/open_map_river.js. */
button.series-window__action.is-partial { border-color: #b45309; color: #b45309; }
body.dark-mode button.series-window__action.is-partial { border-color: #fcd34d; color: #fcd34d; }
/* The river row inside the PLOT WINDOW — the platform's own sensors, which
   have no provider card and use the shared dialog instead. The window is a
   flex column with its own 20px gutters, so a row borrowed from a station
   card takes those rather than sitting flush against the edge. */
.plot-window .series-window__actions--river { padding: 0 20px; flex: none; }

/* THE WAYS OUT of one of this platform's own station cards
   (open_map_card_dock.installStationLinks). Deliberately NOT the teal pill
   the river tools wear: those three DRAW ON THE MAP and stay on this page,
   these NAVIGATE AWAY, and a reader is entitled to be able to tell the two
   apart before pressing one. Links look like links. */
.plot-window .station-links { padding: 0 20px; flex: none; align-items: baseline; }
.station-links__link {
  font-size: 0.8rem;
  color: var(--link, #1F6D8F);
  text-decoration: underline;
}
.station-links__link + .station-links__link { margin-left: 2px; }
.station-links__link::after { content: " \2192"; text-decoration: none; }
.station-links__link:focus-visible {
  outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 2px;
}
body.dark-mode .station-links__link { color: #7dd3fc; }
body.dark-mode .series-window__action { border-color: #5eead4; color: #5eead4; }
body.dark-mode .series-window__action:hover, body.dark-mode .series-window__action:focus-visible {
  background: #5eead4; color: #0b0f14; }

/* CDEC's sensor buttons (static/js/open_map_cdec.js): the same row the MMW
   layer draws, in the reservoir blue the layer paints with. */
.series-window__vars--cdec .series-window__var.is-on { background: #1f6f93; border-color: #1f6f93; color: #ffffff; }

/* ---------------------------------------------------------------------- */
/* The GloFAS panel in the plot window (static/js/open_map_glofas.js).     */
/*                                                                        */
/* It sits below the charts and is styled as a NORMAL panel in all three   */
/* of its states, including the refusal — which is the ordinary answer     */
/* (only ~87 of 3,491 linked stations passed the drainage-area guard on    */
/* 2026-09-04). A refusal painted in error colours would read as a broken  */
/* card on nine stations in ten; it is a statement, so it looks like one.  */
/* The only tinted state is the near-miss warning, which is a caveat on an */
/* attribution that stands.                                               */
.glofas-card {
  margin: 4px 20px 20px; padding: 14px 16px;
  border: 1px solid var(--line, #d9dde1); border-radius: 8px;
  background: var(--surface-2, #f7f9fa);
}
.glofas-card__title { margin: 0 0 6px; font-size: 0.95rem; font-weight: 600; }
.glofas-card__lede { margin: 0 0 8px; font-size: 0.85rem; line-height: 1.5; }
.glofas-card__working {
  margin: 0 0 8px; font-size: 0.78rem; color: var(--ink-3, #6b7280);
  font-variant-numeric: tabular-nums;
}
/* As .tide-card__warning, and for the same reason: the attribution's own
   caveats, set in from the left in full ink instead of boxed in amber. */
.glofas-card__warning {
  margin: 0 0 8px; padding: 0 0 0 12px; font-size: 0.78rem; line-height: 1.45;
  color: var(--ink, #1A1A19);
}
.glofas-card__section { margin-top: 14px; }
.glofas-card__heading {
  margin: 0 0 4px; font-size: 0.82rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--ink-2, #4b5156);
}
.glofas-card__note, .glofas-card__method {
  margin: 4px 0 0; font-size: 0.75rem; line-height: 1.5;
  color: var(--ink-3, #6b7280);
}
.glofas-card__method { margin: 2px 0 0; }
.glofas-card__source {
  margin: 12px 0 0; font-size: 0.72rem; color: var(--ink-3, #6b7280);
}
body.dark-mode .glofas-card { background: #23303c; border-color: var(--line, #444); }
/* The source link inherits the page's link colour, which is a dark blue that
   all but disappears on this panel's dark ground. Named here rather than left
   to inheritance: the attribution is the one thing on the card that must stay
   readable in both themes. */
body.dark-mode .glofas-card a { color: #7fb8ff; }
@media (max-width: 640px) { .glofas-card { margin: 4px 12px 16px; } }

/* --------------------------------------------------------------------------
   THE FLOOD ANSWER FOR A PLACE (static/js/open_map_flood.js, 2026-09-04).
   Not a layer: a control that arms one map click and answers for the 0.05deg
   model cell the click lands in. Three things need styling — the control, the
   crosshair the armed mode wears, and the block of words above the chart that
   says what the number is and is not.
   -------------------------------------------------------------------------- */
.flood-ctrl {
  background: var(--surface, #fff);
  border-radius: var(--r-sm, 6px);
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.35);
  padding: 6px 8px;
  width: 14rem;
  max-width: 60vw;
}
.flood-ctrl__button {
  display: block; width: 100%;
  font: inherit; font-size: 0.78rem; font-weight: 600;
  padding: 5px 10px; cursor: pointer;
  border: 1px solid #6d28d9; border-radius: var(--r-xs, 4px);
  background: transparent; color: #6d28d9;
}
.flood-ctrl__button:hover, .flood-ctrl__button:focus-visible {
  background: #6d28d9; color: #ffffff;
}
/* Armed. The button says "Cancel" and looks pressed, because a mode that is
   on and does not look on is a map that has stopped responding to clicks. */
.flood-ctrl__button.is-on { background: #6d28d9; color: #ffffff; }
.flood-ctrl__hint {
  margin: 3px 0 0; font-size: 0.7rem; line-height: 1.35;
  color: var(--ink-3, #746E62);
}
.flood-ctrl__hint.is-armed { color: #6d28d9; font-weight: 600; }
/* The armed cursor, on the canvas container — the same element the one-shot
   click listener sits on. !important because MapLibre sets `cursor` inline on
   that element as it drags and hovers. */
.nh-flood-picking, .nh-flood-picking canvas { cursor: crosshair !important; }
body.dark-mode .flood-ctrl { background: #23303c; }
body.dark-mode .flood-ctrl__button { border-color: #c4b5fd; color: #c4b5fd; }
body.dark-mode .flood-ctrl__button:hover,
body.dark-mode .flood-ctrl__button:focus-visible,
body.dark-mode .flood-ctrl__button.is-on { background: #c4b5fd; color: #0b0f14; }
body.dark-mode .flood-ctrl__hint.is-armed { color: #c4b5fd; }

/* The head block above the chart. The order on the page is the argument: the
   number, then the cell it belongs to, then what it cannot promise — and the
   caveats are ABOVE the chart and never behind a disclosure control, because
   a modelled discharge beside a small creek without them is confidently
   wrong. */
/* Set a little tighter than the rest of the card, on purpose. This head is
   five blocks of prose standing between the reader and the chart that the
   button they pressed exists to draw — measured 551px of a 589px scroll box
   on 2026-09-04, with none of the chart on screen. Not a word of it is cut
   (the caveats especially: see the block comment above), but every line of
   leading it does not need is a line of the chart the reader does get. */
.flood-head { font-size: 0.82rem; line-height: 1.42; }
.flood-head__value { margin: 0; }
.flood-head__flow { font-size: 1.15rem; color: #6d28d9; }
/* The cell sentence — the twin of the rectangle drawn on the map. Ruled and
   tinted so it reads as a statement about the answer rather than as prose. */
.flood-head__cell {
  margin: 6px 0 0; padding: 5px 9px;
  border-left: 3px solid #6d28d9;
  background: rgba(109, 40, 217, 0.07);
  color: var(--ink-2, #4b5156); font-size: 0.8rem;
}
.flood-head__caveats {
  margin: 7px 0 0; padding-left: 16px;
  color: var(--ink-2, #4b5156); font-size: 0.75rem; line-height: 1.4;
}
.flood-head__caveats li + li { margin-top: 4px; }
/* The unit switch, beside the number it governs. Two buttons rather than a
   select: there are exactly two, and the one in force has to be readable at
   a glance from across the card. */
.flood-head__units {
  display: inline-flex; margin-top: 6px;
  border: 1px solid var(--line-strong, #CFCABD);
  border-radius: var(--r-xs, 4px);
  overflow: hidden;
}
.flood-head__unit {
  border: 0; padding: 3px 9px;
  background: var(--surface-2, #F4F2EC);
  font: inherit; font-size: 0.74rem; font-weight: 600;
  color: var(--ink-2, #56534C); cursor: pointer;
}
.flood-head__unit + .flood-head__unit { border-left: 1px solid var(--line-strong, #CFCABD); }
.flood-head__unit.is-on { background: #6d28d9; color: #fff; cursor: default; }
.flood-head__unit:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: -3px; }
body.dark-mode .flood-head__unit { background: #223140; color: var(--ink); }
body.dark-mode .flood-head__unit.is-on { background: #7c3aed; color: #fff; }

/* Under the chart, not above it — open_map_flood.js says why. */
.flood-foot { margin-top: 2px; }
.flood-head__seam, .flood-head__source {
  margin: 8px 0 0; font-size: 0.74rem; color: var(--ink-3, #6b7280);
}
.flood-head__link { text-decoration: underline; }
body.dark-mode .flood-head__flow { color: #c4b5fd; }
body.dark-mode .flood-head__cell {
  border-left-color: #c4b5fd; background: rgba(196, 181, 253, 0.12);
}

/* ------------------------------------------------------------------------
   THE STATION CARD, DOCKED BESIDE THE MAP INSTEAD OF ON TOP OF IT (2026-09-04)

   #plotOverlay is a full-viewport modal with a 55% scrim (map.css). On a group
   map beside a column of cards that is right: the dialog IS the answer. On the
   open map it is not. Upstream / Downstream / Watershed draw a basin polygon
   and a river network ON THE MAP — measured at ~9.5 s of work — and then the
   reader sees none of it, because a 1440x900 viewport was covered by a 900x792
   card and everything left over was dimmed. The Flood answer panel says
   "drawn on the map" over a map nobody can see.

   So on THIS page the card docks to the right-hand edge of the map: no scrim,
   and `pointer-events: none` on the overlay so every pixel of map outside the
   card is still live — pannable, zoomable, clickable. The top/bottom of the
   dock are set from the map's own bounding box by open_map_card_dock.js, so it
   covers the map and not the site header.

   Only the two RIGHT-hand MapLibre control corners move out of its way: the
   layers panel and the attribution. The left-hand corners carry the station
   search, the Flood answer panel, the zoom buttons, the scale and the
   coordinate box, and none of them move.

   Scoped with the id so it wins over `.plot-overlay { inset: 0 }` regardless of
   which stylesheet a future page loads first, and applied only where the
   template asks for it — every other page's dialog is untouched.
   ------------------------------------------------------------------------ */
:root { --nh-dock-width: min(440px, 38vw); }

#plotOverlay.plot-overlay--docked {
  --nh-dock-top: 0px;
  --nh-dock-bottom: 0px;
  top: var(--nh-dock-top);
  bottom: var(--nh-dock-bottom);
  right: 0;
  left: auto;
  width: var(--nh-dock-width);
  padding: 8px 8px 8px 0;
  background: none;               /* no scrim: the map is the subject */
  align-items: stretch;
  justify-content: flex-end;
  /* The overlay is a frame, not a surface. Without this it would still eat
     every click aimed at the map even while fully transparent. */
  pointer-events: none;
}
#plotOverlay.plot-overlay--docked .plot-window {
  pointer-events: auto;
  width: 100%;
  height: 100%;
  max-height: 100%;
  border-radius: var(--r-md);
  box-shadow: 0 10px 34px rgba(15, 23, 42, 0.30);
}

/* The layers panel and the attribution slide left while a card is docked.
   `transition` keeps that legible rather than a jump. */
body.nh-card-docked .maplibregl-ctrl-top-right,
body.nh-card-docked .maplibregl-ctrl-bottom-right {
  margin-right: var(--nh-dock-width);
}
.maplibregl-ctrl-top-right, .maplibregl-ctrl-bottom-right {
  transition: margin-right 0.15s ease, margin-bottom 0.15s ease;
}
@media (prefers-reduced-motion: reduce) {
  .maplibregl-ctrl-top-right, .maplibregl-ctrl-bottom-right { transition: none; }
}

/* A tablet-width window has a narrower panel but is still a panel: 38vw of
   900px is 342px, which reads. */
@media (max-width: 1024px) {
  :root { --nh-dock-width: min(400px, 46vw); }
}

/* ==========================================================================
   SIMPLER MAP CHROME (2026-10-08, operator: "simple is good")
   --------------------------------------------------------------------------
   One search bar, one Tools button, a folded Layers panel with tick boxes,
   an ⓘ menu for everything read once, and cards that say a name once.
   Layout only: every control that was on the map is still reachable, by
   mouse and by keyboard. Each block names the file that builds it.
   ========================================================================== */

/* --- the head row (base/templates/base/open_map.html) ------------------- */
.map-head .mp-analytics {
  font-size: 0.85rem;
  color: var(--brand-blue-deep, var(--link));
  text-decoration: underline;
  text-underline-offset: 2px;
}
body.dark-mode .map-head .mp-analytics { color: var(--brand-blue-light, var(--link)); }
.mp-more > summary.mp-more__summary {
  list-style: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px;
  border: 1px solid var(--line-strong, #CFCABD);
  border-radius: 999px;
  font-size: 1.05rem; line-height: 1;
  color: var(--ink-2, #4b5563);
}
.mp-more > summary.mp-more__summary::-webkit-details-marker { display: none; }
.mp-more[open] > summary.mp-more__summary { background: var(--surface-2, #F4F2EC); }
.mp-more__panel {
  max-height: min(70vh, 640px);
  overflow-y: auto;
  width: min(60ch, calc(100vw - 40px));
}
.mp-more .mp-id { gap: 6px 14px; margin-bottom: 8px; }
.mp-more__list {
  border: 0; background: none; padding: 0;
  font: inherit; font-size: 0.85rem;
  color: var(--brand-blue-deep, var(--link));
  text-decoration: underline; text-underline-offset: 2px;
  cursor: pointer;
}
body.dark-mode .mp-more__list { color: var(--brand-blue-light, var(--link)); }
.mp-sub { border-top: 1px solid var(--line, #e3e0d7); padding: 6px 0; }
.mp-sub > summary { cursor: pointer; font-size: 0.85rem; font-weight: 600; color: var(--ink-2, #4b5563); }
.mp-sub > summary:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }
.mp-sub__panel { padding-top: 6px; }
/* The theme toggle, moved here from the window's corner by
   static/js/open_map_chrome.js. Same button, in the row's flow. */
.map-head .dark-mode-toggle.is-in-head {
  position: static;
  width: 36px; height: 36px;
  margin-left: auto;
  opacity: 1; pointer-events: auto;
}

/* "Map as list" lives in the ⓘ menu now; the list's own toggle below the map
   stays the one control (and the skip link's target) but is drawn only
   while it is focused or the list is open. Off-screen, not display:none, so
   it can still take focus. */
.map-list__toggle[aria-expanded="false"]:not(:focus) {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; padding: 0; border: 0;
}

/* --- the search bar (open_map_panel.js stationSearch) ------------------- */
.station-search { width: 17rem; }
.station-search__open { display: none; }
.station-search__glyph {
  position: relative; display: inline-block;
  width: 12px; height: 12px;
  border: 2px solid currentColor; border-radius: 50%;
}
.station-search__glyph::after {
  content: ""; position: absolute; right: -6px; bottom: -5px;
  width: 7px; height: 2px; background: currentColor; transform: rotate(45deg);
}

/* --- the Tools menu (open_map_panel.js toolsMenu) ------------------------ */
.nh-tools {
  background: var(--surface, #fff);
  border-radius: var(--r-sm, 6px);
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.35);
  width: 17rem; max-width: 60vw;
}
body.dark-mode .nh-tools { background: #2a3b4a; color: var(--ink); --ink-3: #B9C9D6; }
.nh-tools__toggle {
  display: flex; align-items: center; justify-content: space-between; width: 100%;
  padding: 6px 10px;
  border: 0; background: none; border-radius: var(--r-sm, 6px);
  font: inherit; font-size: 0.82rem; font-weight: 600; color: inherit;
  cursor: pointer;
}
.nh-tools__toggle::after { content: "\25BE"; font-size: 0.75rem; color: var(--ink-3, #746E62); }
.nh-tools.is-open .nh-tools__toggle::after { content: "\25B4"; }
/* A tool is armed: the button says so even with the menu folded. */
.nh-tools.has-armed .nh-tools__toggle::before {
  content: ""; width: 8px; height: 8px; margin-right: 6px; border-radius: 50%;
  background: #15803d; order: 0;
}
.nh-tools__toggle:focus-visible,
.nh-tools__close:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 1px; }
.nh-tools__menu { padding: 0 8px 8px; }
.nh-tools__head { display: none; }        /* the sheet's head, on a phone */
.nh-tools__close {
  width: 30px; height: 30px; border: 0; border-radius: var(--r-sm, 6px);
  background: var(--surface-2, #F4F2EC); color: inherit; font-size: 1.2rem; cursor: pointer;
}
/* The tools' own boxes become rows of the menu rather than cards on the map. */
.nh-tools__items .maplibregl-ctrl {
  float: none; margin: 0; max-width: none;
  background: transparent; box-shadow: none; border-radius: 0;
  padding: 6px 0;
}
.nh-tools__items .maplibregl-ctrl + .maplibregl-ctrl { border-top: 1px solid var(--line, #e3e0d7); }
body.dark-mode .nh-tools__items .maplibregl-ctrl { background: transparent; }

/* --- the Layers panel (open_map_panel.js create) ------------------------ */
/* A row is a <label> around its tick box now, so the whole row is the
   target. The box is the native control, in the brand colour. */
.open-panel__active,
.open-panel__terrain { cursor: pointer; align-items: center; }
.open-panel__terrain { display: flex; gap: 7px; padding: 4px 0 8px; }
input.open-panel__off,
input.open-panel__terrainBox {
  flex: none; width: 16px; height: 16px; margin: 0;
  accent-color: var(--brand-blue-deep, #1f6f93);
  cursor: pointer;
}
input.open-panel__off:focus-visible,
input.open-panel__terrainBox:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 1px; }

/* --- the station card (open_map_series_window.js) ----------------------- */
/* A long name wraps to a second line rather than losing its end to "…";
   past two lines it clamps, and the close button never moves. */
#plotOverlay .plot-window__title {
  white-space: normal;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-height: 1.25;
}
/* The chart first, the chips that choose it under it: the chart is what a
   reader opened the card for. Order only — the DOM keeps the layer's order,
   so a screen reader still meets the choices before the result. */
.series-window__charts { display: flex; flex-direction: column; }
.series-window__charts > * { order: 1; min-width: 0; }
.series-window__charts > .series-window__series,
.series-window__charts > .plot-window__msg { order: 0; }
/* One switch for a station that reports at more than one cadence. */
.series-window__durs { display: inline-flex; flex: 0 0 100%; gap: 0; margin-bottom: 2px; }
.series-window__durs .series-window__dur {
  font: inherit; font-size: 0.78rem; padding: 3px 12px; cursor: pointer;
  border: 1px solid var(--line-strong, #cbd5e1); background: transparent; color: var(--ink-2, #4b5563);
}
.series-window__durs .series-window__dur:first-child { border-radius: 999px 0 0 999px; }
.series-window__durs .series-window__dur:last-child { border-radius: 0 999px 999px 0; }
.series-window__durs .series-window__dur + .series-window__dur { border-left: 0; }
.series-window__durs .series-window__dur.is-on { background: var(--ink-2, #374151); color: #fff; border-color: var(--ink-2, #374151); }
.series-window__durs .series-window__dur:focus-visible,
.series-window__var:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 1px; }
/* The name is the window's title; the head's own copy of it stands down. */
.usgs-popup__name.is-in-title { display: none; }
/* The search's status line takes no room until it has something to say. */
.station-search__status:empty { display: none; }
/* The source paragraph, folded to "Source: <agency>". */
.usgs-popup__sourceFold { margin-top: 6px; font-size: 0.72rem; color: var(--ink-3, #6b7280); }
.usgs-popup__sourceFold > summary { cursor: pointer; }
.usgs-popup__sourceFold > .usgs-popup__source { margin-top: 3px; }

/* --- phone: the simpler chrome (2026-10-08; the rest of it is the
   SIMPLER MAP CHROME section just above)  */
@media (max-width: 640px) {
  /* The map takes the screen under the header and the one-row head; 480px
     stays the floor (the furniture still has to fit). */
  #map { height: calc(100svh - 150px); }
  .map-head { column-gap: 14px; }

  /* Search is an icon until it is asked for. */
  .station-search { padding: 0; width: auto; background: transparent; box-shadow: none; }
  .station-search__open {
    display: inline-flex; align-items: center; justify-content: center;
    width: 29px; height: 29px; border: 0; border-radius: 4px;
    background: var(--surface, #fff); color: var(--ink, #1a1a19);
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1); cursor: pointer;
  }
  .station-search:not(.is-open) .station-search__form { display: none; }
  .station-search.is-open { padding: 6px 8px; width: calc(100vw - 60px); background: var(--surface, #fff);
                            box-shadow: 0 1px 5px rgba(0, 0, 0, 0.35); }
  .station-search.is-open .station-search__open { display: none; }
  body.dark-mode .station-search__open,
  body.dark-mode .station-search.is-open { background: #2a3b4a; color: var(--ink); }

  /* Tools: a small button on the map, and its menu a bottom sheet.
     MapLibre gives every control `transform: translate(0)`, which makes the
     control the containing block of anything fixed inside it — the sheet
     came out 60px wide, pinned to the button. The Tools control has nothing
     to composite, so it drops the transform and the sheet is the screen's. */
  .maplibregl-ctrl.nh-tools { width: auto; transform: none; }
  .nh-tools__menu:not([hidden]) {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 950;
    max-height: var(--nh-dock-height, 56vh); overflow-y: auto;
    padding: 0 14px 14px;
    background: var(--surface, #fff);
    border-radius: var(--r-md, 10px) var(--r-md, 10px) 0 0;
    box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.28);
  }
  body.dark-mode .nh-tools__menu:not([hidden]) { background: #2a3b4a; }
  /* MapLibre's corners are stacking contexts at z-index 2, so the sheet
     could rise no higher than its own corner and the Layers bar, scale and
     attribution (later corners, same z) painted over it. While the sheet is
     open its corner goes on top. */
  .maplibregl-ctrl-top-left:has(.nh-tools.is-open) { z-index: 950; }
  .nh-tools__head {
    display: flex; align-items: center; justify-content: space-between;
    position: sticky; top: 0; padding: 10px 0 6px; background: inherit;
    font-weight: 700;
  }
  /* A tool armed: the sheet shrinks to that tool alone, so the map above it
     can take the tap the tool is waiting for. */
  .nh-tools.has-armed .nh-tools__head,
  .nh-tools.has-armed .nh-tools__items > :not(.is-armed) { display: none; }
  .nh-tools.has-armed .nh-tools__menu:not([hidden]) { padding-top: 10px; }
}

/* A PHONE has no room for one at all — 46vw of 360px is 166px — so at the same
   breakpoint where map.css shortens the map to 45vh the card becomes a BOTTOM
   SHEET.

   WHAT THE SHEET IS ANCHORED TO, AND WHY IT CHANGED (2026-09-04). The sheet
   used to take its bottom edge from `--nh-dock-bottom` — the gap between the
   MAP's bottom and the bottom of the screen — like the desktop panel does, and
   it capped its height against the map's measured height. Measured at 360x780
   that produced a 218px sheet with a 123px readable body holding 956px of
   content (a CDEC station; a USGS one is longer still), floating in the middle
   of the screen with page text below it. Worse, the map is part of the PAGE:
   scroll down to read the status lines under it and the map's box leaves the
   viewport, taking the open card with it — measured at scrollY 600 the sheet
   sat at y -249..-31, entirely above the screen and unrecoverable without
   scrolling back.

   The map's box is the right anchor for the DESKTOP dock, which sits beside
   the map and is read at the same time as it. It is the wrong anchor for a
   phone, where the card is the thing being read and the map is context behind
   it. So on a phone the sheet is anchored to the VIEWPORT: `bottom: 0`, height
   from vh. It cannot drift off-screen, it does not move when the page scrolls,
   and 56vh of a 780px screen is a 437px sheet with a ~340px readable body.

   Two things still hold. The sheet never takes the whole screen — 56vh leaves
   44vh above it, which is a guarantee about the SCREEN rather than about the
   map's box, so it survives any scroll position; that strip is where the map
   shows through and, with no Escape key on a phone, is the surface a reader
   taps to dismiss the card. And the bottom control corners lift clear of the
   sheet so the scale bar and the OSM attribution — a licence condition, not a
   decoration — are never buried. They lift by exactly how much of the map the
   sheet covers (`--nh-dock-map-overlap`, measured by open_map_card_dock.js),
   not by the sheet's whole height: the controls live inside the map, and on a
   351px map a 437px lift would throw them off the top of it. */
@media (max-width: 640px) {
  :root { --nh-dock-height: min(56vh, 460px); }
  #plotOverlay.plot-overlay--docked {
    top: auto;
    bottom: 0;                    /* the VIEWPORT's bottom, not the map's */
    left: 0;
    right: 0;
    width: auto;
    height: var(--nh-dock-height);
    padding: 0;
  }
  #plotOverlay.plot-overlay--docked .plot-window {
    border-radius: var(--r-md) var(--r-md) 0 0;
  }
  body.nh-card-docked .maplibregl-ctrl-top-right { margin-right: 0; }
  body.nh-card-docked .maplibregl-ctrl-bottom-right,
  body.nh-card-docked .maplibregl-ctrl-bottom-left {
    margin-right: 0;
    /* Both lifts, not just the card's: the Layers sheet is still over the
       map's bottom edge while a card is open, and dropping its term here
       (which this rule did until 2026-09-04, by winning on specificity)
       put the attribution back under the sheet. The time bar's lift is
       deliberately absent from both phone rules — see the note above. */
    margin-bottom: calc(var(--nh-dock-map-overlap, 0px) + var(--nh-panel-lift, 0px));
  }
}

/* --- The white-labelled chrome (base/templates/base/open_map.html) ---------
   Only a member whose workbench wears one group's face sees any of this: the
   anonymous page, which is the platform-wide one, renders the deployment's own
   bar and footer and none of these classes appear in its markup.

   Here rather than in site.css because the public shell paints every other page
   in this deployment and these three rules belong to one page's branded chrome;
   a stylesheet that is one feature's can be removed with that feature.

   Both theme variants are in the markup and CSS picks one — dark mode is a
   class on <body>, which a <picture> media query cannot see. Same arrangement
   as the app bar (app_nav.css) and the group site's own (group_site.css). */
.om-brandmark {
  display: block;
  height: 46px;
  width: auto;
  max-width: 220px;
  object-fit: contain;
  object-position: left center;
}
.om-brandmark--dark { display: none; }
body.dark-mode .om-brandmark--light { display: none; }
body.dark-mode .om-brandmark--dark { display: block; }

/* A group branded by its typeface or its site title alone has no mark to draw,
   and an <img> with an empty src is a broken picture where the way home is. */
.om-brandword { font-weight: 800; font-size: 1.25rem; }

/* The credit, in the head row beside the site and group counts. It inherits
   `.meta`'s size and colour so it reads as one more fact about the map rather
   than as a badge, and it is never inside a details/summary. */
.om-credit { white-space: nowrap; }

/* The footer's mark sits centred over the group's name, at the size the
   platform's own mark uses there. */
.om-footmark {
  margin: 0 auto 0.5rem;
  max-height: 64px;
  max-width: 150px;
  height: auto;
}
.om-footname { font-weight: 700; }

/* Hash bust 2026-09-07 — drill-window CDN 404 cache; see audit/failover-drill-2026-09-07.md */

/* Foldable map tools (NHOpenMapPanel.foldable): a small chevron in the corner
   folds a control down to its own button or label. */
.nh-foldable { position: relative; padding-right: 26px; }
.nh-fold {
  position: absolute; top: 4px; right: 4px;
  width: 20px; height: 20px; padding: 0;
  border: 0; border-radius: 4px; background: transparent;
  color: var(--ink-3, #746E62); cursor: pointer;
  font-size: 0.75rem; line-height: 20px; text-align: center;
}
.nh-fold::before { content: "\25BE"; }                 /* ▾ open */
.nh-foldable.is-folded .nh-fold::before { content: "\25B8"; }  /* ▸ folded */
.nh-fold:hover { background: var(--surface-2, #F4F2EC); }
.nh-fold:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 1px; }
body.dark-mode .nh-fold { color: #B9C9D6; }
body.dark-mode .nh-fold:hover { background: #33475a; }
.nh-foldable.is-folded .nh-fold-host > :not(.nh-fold-keep) { display: none; }

/* --- Radar 3D (open_map_radar3d.js) ---------------------------------------- */
/* The switch and its two sliders sit under 3D terrain in the Layers panel. */
.open-panel__r3d { padding-left: 23px; }
.open-panel__r3d .open-panel__terrain { margin-left: -23px; }
.open-panel__r3dRange { display: grid; gap: 2px; padding: 2px 0 6px; font-size: .82rem; }
.open-panel__r3dRange output { font-variant-numeric: tabular-nums; font-weight: 600; }
.open-panel__r3dRange input[type="range"] { width: 100%; accent-color: var(--brand-blue-deep, #1f6f93); }
.open-panel__r3dRange input[type="range"]:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 1px; }

/* The legend: a map control at the bottom left, folded to its title on a phone. */
.maplibregl-ctrl.nh-r3d-legend {
  background: var(--surface, #fff); color: var(--ink, #1d2329);
  border-radius: 8px; box-shadow: 0 1px 4px rgba(0,0,0,.25);
  padding: 6px 10px 8px; max-width: 230px; font-size: .78rem; line-height: 1.35;
}
.nh-r3d-legend.is-folded { padding-bottom: 6px; }
.nh-r3d-legend__title {
  all: unset; cursor: pointer; font-weight: 700; font-size: .82rem; display: block;
}
.nh-r3d-legend__title:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 2px; border-radius: 3px; }
.nh-r3d-legend__enc { margin: 4px 0 2px; color: var(--muted, #5b636b); }
.nh-r3d-legend__bands { list-style: none; margin: 0; padding: 0; }
.nh-r3d-legend__bands li { display: grid; grid-template-columns: 18px 3.2em 1fr; align-items: end; gap: 6px; padding: 1px 0; }
.nh-r3d-legend__bar { display: block; width: 18px; border-radius: 1px; }
.nh-r3d-legend__num { font-variant-numeric: tabular-nums; }
.nh-r3d-legend__status { margin: 6px 0 2px; display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: center; }
.nh-r3d-legend__status.is-warn { color: #9a3b00; font-weight: 600; }
.nh-r3d-legend__show {
  font: inherit; padding: 1px 8px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--brand-blue-deep, #1f6f93); background: transparent; color: var(--brand-blue-deep, #1f6f93);
}
.nh-r3d-legend__show:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); outline-offset: 1px; }
.nh-r3d-legend__foot { margin: 4px 0 0; color: var(--muted, #5b636b); font-size: .72rem; }
body.dark-mode .maplibregl-ctrl.nh-r3d-legend { background: #23272b; color: #e6e8ea; }
body.dark-mode .nh-r3d-legend__enc,
body.dark-mode .nh-r3d-legend__foot { color: #b4bac0; }
body.dark-mode .nh-r3d-legend__show { color: #8cc8e6; border-color: #8cc8e6; }
body.dark-mode .nh-r3d-legend__status.is-warn { color: #ffb37a; }

/* The tooltip over a block: dBZ, its band in words, the rain rate it implies. */
.nh-r3d-tip {
  position: absolute; z-index: 3; transform: translate(-50%, calc(-100% - 12px));
  min-width: 170px; max-width: 210px; padding: 6px 10px; border-radius: 8px;
  background: var(--surface, #fff); color: var(--ink, #1d2329);
  box-shadow: 0 2px 8px rgba(0,0,0,.3); font-size: .78rem; pointer-events: none;
}
.nh-r3d-tip.is-below { transform: translate(-50%, 14px); }
.nh-r3d-tip.is-pinned { pointer-events: auto; padding-right: 26px; }
.nh-r3d-tip__val { font-size: 1.15rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.nh-r3d-tip__val small { font-size: .7rem; font-weight: 600; }
.nh-r3d-tip__band { display: flex; align-items: center; gap: 6px; font-weight: 600; }
.nh-r3d-key { display: inline-block; width: 10px; height: 10px; border-radius: 2px; }
.nh-r3d-tip__sub small { color: var(--muted, #5b636b); }
.nh-r3d-tip__x {
  position: absolute; top: 3px; right: 4px; border: 0; background: transparent;
  font-size: 1rem; line-height: 1; padding: 2px 5px; cursor: pointer; color: inherit;
}
.nh-r3d-tip__x:focus-visible { outline: 3px solid var(--accent-ring, #2887b1); }
body.dark-mode .nh-r3d-tip { background: #23272b; color: #e6e8ea; }
