/* ─── Dark theme (default) ─────────────────────────────────────────────────── */
:root,
[data-theme="dark"] {
  /* Deep plum → midnight blue canvas. All panels read as one continuous
   * cool-dark surface; accent colors are neon so they pop against it. */
  --bg: #09071a;
  --bg-alt: #05040f;
  --card: #15122b;
  --card-soft: #1c1838;
  --border: #3a2f5e;
  --border-strong: #553f8a;
  --text: #e8e6f2;
  --muted: #9b96c0;
  --accent: #b388ff;        /* neon lavender */
  --accent-strong: #c9a8ff;
  --accent-2: #38fff0;      /* neon cyan — charts / highlights */
  --danger: #ff2b5a;        /* hot neon pink-red */
  --danger-strong: #ff577a;
  --success: #3dffa0;       /* neon mint */
  --warn: #ffb300;          /* amber neon */
  --info: #38bdf8;
  --chip-bg: rgba(22, 18, 44, 0.75);
  --shadow: 0 18px 46px rgba(2, 1, 12, 0.55);
  --glow-accent: 0 0 20px rgba(179, 136, 255, 0.35);
  --glow-danger: 0 0 24px rgba(255, 43, 90, 0.45);
  --manilla: #d7c69c;
  --manilla-border: #a98a56;
  --event-color: #b388ff;
  --font-size-base: 15px;

  /* Spacing scale — anchor every gap/padding/margin to one of these so
   * cross-module visual rhythm doesn't drift. Old ad-hoc values
   * (0.4 / 0.55 / 0.6 / 0.65 / 0.85 / 1.1 / 1.2 rem) all collapse here. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-7: 2rem;
  --space-8: 2.5rem;

  /* Typography scale — anchor type sizes to a fixed step ladder. */
  --text-xs: 0.72rem;
  --text-sm: 0.82rem;
  --text-base: 0.92rem;
  --text-md: 1rem;
  --text-lg: 1.1rem;
  --text-xl: 1.35rem;
  --text-display: 1.9rem;

  /* Radius scale. */
  --radius-sm: 0.35rem;
  --radius-md: 0.55rem;
  --radius-lg: 0.85rem;
  --radius-pill: 999px;
}

/* ─── Light theme ──────────────────────────────────────────────────────────── */
[data-theme="light"] {
  --bg: #f0f4f8;
  --bg-alt: #e4ecf4;
  --card: #ffffff;
  --card-soft: #f7fafc;
  --border: #c5d5e8;
  --border-strong: #8aaecc;
  --text: #0e1e2e;
  --muted: #4a6278;
  --accent: #c59e1e;
  --accent-strong: #d9b430;
  --danger: #c62828;
  --success: #1a7c3e;
  --warn: #b45309;
  --info: #1565c0;
  --chip-bg: rgba(200, 220, 240, 0.55);
  --shadow: 0 8px 24px rgba(14, 30, 46, 0.12);
  /* Light-theme has to override the dark-theme drop-shadow tokens too —
   * otherwise rgba(2,1,12,…) shadows from the dark palette inherit and
   * smudge every card with a muddy bluish halo. */
  --glow-accent: 0 0 16px rgba(197, 158, 30, 0.22);
  --glow-danger: 0 0 18px rgba(198, 40, 40, 0.28);
}

[data-theme="light"] body {
  background:
    radial-gradient(circle at top left, rgba(197, 158, 30, 0.08), transparent 22%),
    radial-gradient(circle at top right, rgba(21, 101, 192, 0.06), transparent 20%),
    linear-gradient(180deg, #e8f0f8 0%, #f0f4f8 52%, #f5f8fb 100%);
}

[data-theme="light"] .wx-header {
  background: rgba(240, 244, 248, 0.92);
  border-bottom-color: rgba(197, 213, 232, 0.7);
}

[data-theme="light"] .wx-nav-link--active {
  color: #fff;
}

[data-theme="light"] .overlay-content,
[data-theme="light"] .preview-panel {
  background: linear-gradient(180deg, rgba(215, 198, 156, 0.98), rgba(203, 186, 145, 0.96));
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  color: var(--text);
  font-size: var(--font-size-base);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", Roboto, "Helvetica Neue", Arial, sans-serif;
  background:
    radial-gradient(circle at top left, rgba(242, 193, 78, 0.14), transparent 22%),
    radial-gradient(circle at top right, rgba(56, 189, 248, 0.12), transparent 20%),
    linear-gradient(180deg, #0c1723 0%, #07111a 52%, #04090d 100%);
  min-height: 100vh;
}

a {
  color: inherit;
}

button,
input,
select,
textarea {
  font: inherit;
}

.wx-header {
  position: sticky;
  top: 0;
  z-index: 20;
  /* Tightened from 1rem 1.35rem 0.9rem so the sticky header reclaims ~10px
   * of vertical space on every page. The dashboard is dense by design;
   * the header chrome shouldn't compete with content for fold real-estate. */
  padding: 0.6rem 1rem 0.55rem;
  /* Honor the iOS safe-area inset when the app is installed as a PWA in
   * landscape (notch / Dynamic Island). Without this the nav clips. */
  padding-left: max(1rem, env(safe-area-inset-left));
  padding-right: max(1rem, env(safe-area-inset-right));
  padding-top: max(0.6rem, env(safe-area-inset-top));
  border-bottom: 1px solid rgba(61, 103, 132, 0.35);
  background: rgba(5, 11, 17, 0.88);
  backdrop-filter: blur(14px);
}

.wx-header-main,
.wx-header-title,
.wx-status,
.wx-header-meta,
.wx-controls,
.wx-button-row,
.wx-card-actions,
.metric-grid,
.dashboard-grid,
.panel-grid,
.two-column,
.split-layout,
.settings-grid,
.settings-actions,
.field-row,
.table-toolbar,
.status-grid {
  display: flex;
  gap: 0.85rem;
  flex-wrap: wrap;
}

.wx-header-main {
  justify-content: space-between;
  align-items: flex-start;
}

.wx-header-title {
  align-items: flex-end;
}

.wx-header h1 {
  margin: 0;
  /* Was 1.2rem — but at 1.2rem the wordmark visually outranked the
   * 1.25rem h2 section heads, making the page title feel demoted. Lift
   * to 1.3rem so the title is the largest piece of chrome again
   * without breaking the 1280px-tablet nav-on-one-line goal. */
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: 0.01em;
}

.wx-version {
  display: inline-block;
  margin-left: 0.45rem;
  color: var(--muted);
  font-size: 0.85rem;
  font-weight: 500;
}

.wx-nav {
  display: flex;
  gap: 0.35rem;
  flex-wrap: wrap;
  align-items: center;
}

/* ─── "More" overflow disclosure ─── */
.wx-nav-more {
  position: relative;
}
.wx-nav-more > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
}
.wx-nav-more > summary::-webkit-details-marker { display: none; }
.wx-nav-more-panel {
  position: absolute;
  top: calc(100% + 0.35rem);
  left: 0;
  /* Above Leaflet's max internal z-index (zoom controls = 1000). Without
     this the map's popup pane (700) overlays the dropdown items. Paired
     with the .leaflet-container isolation rule below so the map's
     stacking ladder is contained, but keep this defensive in case any
     module forgets to load the global stylesheet. */
  z-index: 1100;
  min-width: 12rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
  padding: 0.3rem;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.wx-nav-more-item {
  display: block;
  padding: 0.45rem 0.7rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--muted);
  font-size: var(--text-sm);
}
.wx-nav-more-item:hover {
  color: var(--text);
  background: rgba(255,255,255,0.04);
}
.wx-nav-more-item--active {
  color: #0a0815;
  background: var(--accent);
}
[data-theme="light"] .wx-nav-more-item:hover { background: rgba(14,30,46,0.06); }

.wx-nav-link,
.nav-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Compacted nav pills: was 2.1rem / 0.42 0.85. The pills were tall
   * enough to feel like buttons; with 11 modules + Home + Logout they
   * also wrapped onto a second row at 1280px. Tighter padding fits all
   * links on one row on a typical landscape tablet. */
  min-height: 1.8rem;
  padding: 0.3rem 0.7rem;
  font-size: 0.88rem;
  border-radius: 999px;
  text-decoration: none;
  color: var(--muted);
  border: 1px solid transparent;
  transition: 0.18s ease;
}

.wx-nav-link:hover,
.nav-chip:hover {
  color: var(--text);
  border-color: rgba(242, 193, 78, 0.32);
  background: rgba(242, 193, 78, 0.08);
}

.wx-nav-link--active {
  color: #101820;
  /* Solid accent — the old 135deg gradient read as a washed-out band
     against dark/light variants alike. Keep the soft glow for emphasis. */
  background: var(--accent);
  border-color: transparent;
  box-shadow: 0 10px 30px rgba(242, 193, 78, 0.25);
}

.wx-nav-link--soon {
  opacity: 0.45;
  pointer-events: none;
}

.wx-status {
  align-items: center;
  justify-content: flex-end;
}

.wx-header-meta {
  margin-top: 0.4rem;
  color: var(--muted);
  font-size: 0.78rem;
}

.timestamp-stack {
  display: inline-flex;
  flex-direction: column;
  line-height: 1.1;
}

.timestamp-date {
  font-weight: 600;
}

.timestamp-time {
  font-size: 0.84rem;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.38rem 0.68rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(16, 32, 54, 0.55);
  color: var(--text);
  white-space: nowrap;
}

.status-ok {
  border-color: rgba(34, 197, 94, 0.55);
  background: rgba(34, 197, 94, 0.15);
}

.status-stale {
  border-color: rgba(245, 158, 11, 0.55);
  background: rgba(245, 158, 11, 0.16);
}

.status-error {
  border-color: rgba(239, 68, 68, 0.55);
  background: rgba(239, 68, 68, 0.16);
}

.status-unknown,
.status-disabled {
  border-color: rgba(168, 183, 196, 0.3);
  background: rgba(168, 183, 196, 0.14);
}

.wx-main {
  /* Was capped at 1380px which left ~half the viewport empty on wide
   * monitors and forced the alerts list rows to wrap onto 2-3 lines.
   * Operators run this on whatever screen they have during severe
   * coverage; let the dashboard scale up. The 2200px ceiling is a soft
   * bound for ultra-wide displays where unbroken sweeps of data would
   * otherwise become hard to scan. */
  width: calc(100% - 1.4rem);
  max-width: 2200px;
  margin: 0 auto;
  /* Padding tightened (was 1.2rem / 2rem) so the home dashboard fits a
   * 1080p display without scrolling — operators monitoring multiple
   * panels at once can't afford to hunt for content below the fold. */
  padding: 0.7rem 0 1.1rem;
}

/* Map shell soft cap — without this, on a 2200px window the map aside
 * would grow to ~1000px wide and dominate the layout. The alerts list
 * is the primary product of the dashboard; the map is supporting
 * context, so cap it and let the list keep the rest. */
.split-layout > .map-shell {
  max-width: 880px;
  flex-grow: 1;
}

.page-hero,
.section-card,
.metric-card,
.dashboard-card,
.data-card,
.wx-placeholder,
.map-shell,
.preview-panel,
.modal-content,
.settings-panel,
.status-card,
.table-shell {
  border-radius: 1rem;
  border: 1px solid rgba(61, 103, 132, 0.36);
  background: linear-gradient(180deg, rgba(16, 32, 54, 0.92), rgba(9, 20, 32, 0.95));
  box-shadow: var(--shadow);
}

.page-hero,
.section-card,
.settings-panel,
.table-shell {
  padding: 1.1rem 1.2rem;
}

.section-title,
.panel-title,
.page-hero h2,
.section-card h2,
.settings-panel h2 {
  margin: 0 0 0.35rem;
  font-size: 1.15rem;
}

.section-subtitle,
.muted-text,
.page-copy {
  color: var(--muted);
}

.dashboard-grid,
.panel-grid,
.metric-grid,
.status-grid {
  display: grid;
}

.dashboard-grid {
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1rem;
}

.panel-grid {
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1rem;
}

.metric-grid,
.status-grid {
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.85rem;
}

.dashboard-card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1rem;
  text-decoration: none;
  transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}

.dashboard-card:hover {
  transform: translateY(-3px);
  border-color: rgba(242, 193, 78, 0.45);
  box-shadow: 0 20px 46px rgba(2, 8, 14, 0.52);
}

.dashboard-card.disabled-overlay {
  opacity: 0.45;
}

.dashboard-card h2,
.dashboard-card h3 {
  margin: 0;
}

.dashboard-card p {
  margin: 0;
  color: var(--muted);
}

.card-kicker,
.module-kicker {
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.74rem;
  font-weight: 700;
}

.metric-card {
  padding: 0.95rem 1rem;
}

.metric-value {
  font-size: 1.9rem;
  font-weight: 700;
  line-height: 1;
  margin-bottom: 0.35rem;
}

.metric-label {
  color: var(--muted);
  font-size: 0.88rem;
}

.wx-controls {
  align-items: center;
  margin-bottom: 1rem;
}

.control-group,
.filter-group {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.btn-primary,
.btn-secondary,
.btn-danger,
.btn-icon,
.btn-chip,
.download-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  min-height: 2.4rem;
  padding: 0.55rem 0.95rem;
  border-radius: 999px;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: transform 0.15s ease, opacity 0.15s ease, border-color 0.15s ease;
}

/* Neon-lavender primary — solid fill, no gradient. Glow picks up on hover. */
.btn-primary,
.download-btn {
  background: var(--accent);
  color: #0a0815;
  font-weight: 700;
  border-color: var(--accent-strong);
}
.btn-primary:hover,
.download-btn:hover {
  background: var(--accent-strong);
  box-shadow: var(--glow-accent);
}
.btn-primary:active,
.download-btn:active {
  transform: translateY(0);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.25);
}

.btn-secondary,
.btn-chip {
  background: rgba(28, 24, 56, 0.75);
  border-color: var(--border);
  color: var(--text);
}
.btn-secondary:hover,
.btn-chip:hover {
  border-color: var(--accent);
  box-shadow: var(--glow-accent);
}

.btn-danger {
  background: rgba(255, 43, 90, 0.15);
  color: #ffd2de;
  border-color: rgba(255, 43, 90, 0.5);
}
.btn-danger:hover {
  background: rgba(255, 43, 90, 0.28);
  box-shadow: var(--glow-danger);
}

.btn-icon {
  width: 2.3rem;
  min-width: 2.3rem;
  padding: 0;
  background: rgba(28, 24, 56, 0.75);
  color: var(--text);
  border-color: var(--border);
}

/* ─── Leaflet z-index isolation ─────────────────────────────────────────
 *
 * Leaflet's internal panes use a fixed z-index ladder (tiles 200,
 * overlay 400, marker 600, tooltip 650, popup 700, zoom-controls 1000).
 * The map container is `position: relative` with `z-index: auto`, so
 * those internal panes do NOT get contained — they leak into the page
 * stacking context and can overlay navbar dropdowns / modals / toasts
 * with lower z-index values.
 *
 * `isolation: isolate` creates a new stacking context on the map
 * container, sandboxing the entire Leaflet ladder inside it. Outside
 * elements stack against the map container as a single unit (its
 * `z-index: auto` is now equivalent to 0 for stacking purposes), not
 * against each internal pane.
 *
 * Without this rule, every module's "More" dropdown / settings flyout
 * / toast / modal needs to know Leaflet's highest internal z-index
 * (1000 for zoom-controls) and exceed it. With this rule, anything
 * outside the map container that sits above z-index 0 wins
 * automatically.
 *
 * Reported by operator on the Tropical Dashboard 2026-06-11: the
 * "More ▼" navbar dropdown rendered BEHIND the map. Fix applies
 * globally so other module maps (SPC, LSR, Geological, Chasers,
 * etc.) inherit it.
 */
.leaflet-container {
  isolation: isolate;
}

/* ─── Map Room shell — full-width map with floating glass panel ─────────
 *
 * Originally built for the Alerts page (1.30.3); generalized to
 * "Map Room" in 1.30.4 so SPC, LSR, Tropical, and Geological can all
 * adopt the same layout. The .alerts-* names below are aliased to
 * .maproom-* via duplicated selectors so existing module HTML keeps
 * working while we migrate.
 *
 * Layout trick: .maproom-shell is itself a flex column constrained to
 * roughly viewport height, with the options bar fixed-size and the
 * mapwrap taking flex:1. That makes the map's height a real pixel
 * value (Leaflet requires) without hard-coding the toolbar height. */
.alerts-shell,
.maproom-shell {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  /* Use dvh so iOS Safari's collapsing URL bar doesn't leave a
   * permanent dead band. 8.5rem covers the sticky header on wx-main.
   * Falls back to 100vh for older browsers via the min-height pair. */
  min-height: calc(100vh - 8.5rem);
  height: calc(100dvh - 8.5rem);
}

.alerts-category-toggles,
.maproom-category-toggles {
  margin-top: 0.4rem;
  flex-wrap: wrap;
}

.alerts-mapwrap,
.maproom-mapwrap {
  position: relative;
  flex: 1 1 auto;
  min-height: 280px;
  overflow: hidden;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
}
.alerts-map-canvas,
.maproom-map-canvas {
  width: 100%;
  height: 100%;
}

/* ─── Floating glass panel (Map Room) ───
 * Both .alerts-list-floating (legacy) and .maproom-panel are valid
 * class names on the outer panel container. The interior elements
 * use the maproom-panel-* names; alerts/index.php was migrated to
 * those names as part of the Map Room generalization (1.30.4). */
.alerts-list-floating,
.maproom-panel {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 500;
  width: min(24rem, 38vw);
  max-height: calc(100% - 1.5rem);
  display: flex;
  flex-direction: column;
  /* 0.80, not 0.55: over the light OSM basemap the thinner glass turned the
   * muted text grey-on-grey (WXAPI-099). */
  background: rgba(13, 16, 32, 0.80);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-lg);
  box-shadow:
    0 10px 28px rgba(2, 1, 12, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  will-change: transform;
}
[data-theme="light"] .alerts-list-floating,
[data-theme="light"] .maproom-panel {
  background: rgba(255, 255, 255, 0.62);
  border-color: rgba(14, 30, 46, 0.12);
}

.maproom-panel-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.5rem 0.65rem 0.4rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  cursor: grab;
  user-select: none;
  touch-action: none;
}
[data-theme="light"] .maproom-panel-head {
  border-bottom-color: rgba(14, 30, 46, 0.08);
}
.maproom-panel-head.is-dragging { cursor: grabbing; }

.maproom-panel-title {
  margin: 0;
  font-size: 0.92rem;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.maproom-panel-title::before {
  content: "";
  width: 14px;
  height: 6px;
  background: linear-gradient(
    to bottom,
    var(--muted) 0 2px,
    transparent 2px 4px,
    var(--muted) 4px 6px
  );
  opacity: 0.55;
  border-radius: 2px;
}

.maproom-panel-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.1rem;
}

.maproom-panel-body {
  overflow-y: auto;
  padding: 0.4rem 0.5rem 0.55rem;
  flex: 1 1 auto;
  min-height: 0;
}

/* In-panel tab strip — used by Geological to split Events vs Volcanoes
 * inside the same floating panel. */
.maproom-tabs {
  display: flex;
  gap: 0.25rem;
  padding: 0 0.6rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
[data-theme="light"] .maproom-tabs { border-bottom-color: rgba(14, 30, 46, 0.08); }
.maproom-tab {
  background: transparent;
  border: none;
  color: var(--muted);
  padding: 0.4rem 0.55rem;
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.maproom-tab:hover { color: var(--text); }
.maproom-tab--active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.maproom-tab-count {
  color: var(--muted);
  font-size: var(--text-xs);
}
.maproom-tab--active .maproom-tab-count { color: var(--accent-strong); }

.maproom-panel.is-collapsed,
.alerts-list-floating.is-collapsed { display: none; }

.alerts-list-expand,
.maproom-panel-expand {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 500;
  background: rgba(13, 16, 32, 0.55);
  backdrop-filter: blur(10px);
}

/* ─── LSR marker shapes (1.30.6) ─────────────────────────────────────
 * LSR events render as distinct SVG shapes via L.divIcon — tornadoes
 * are downward triangles, hail are squares, floods are equals signs,
 * etc. Lives in the shared stylesheet so any Map Room page that
 * overlays LSR data inherits the styling. */
.leaflet-div-icon.lsr-marker-wrap {
  background: transparent;
  border: none;
  box-shadow: none;
  display: flex;
  align-items: center;
  justify-content: center;
}
.lsr-marker {
  display: flex;
  align-items: center;
  justify-content: center;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.45));
  transition: transform 0.12s ease;
}
.lsr-marker:hover { transform: scale(1.15); cursor: pointer; }

/* Casualty marker — injuries/fatalities mentioned in the LSR remarks.
 * The SVG itself draws a thick black stroke; the wrapper adds a pulse
 * so the eye catches it across a busy map. */
.lsr-marker--casualty {
  animation: lsr-casualty-pulse 1.2s ease-in-out infinite;
  filter:
    drop-shadow(0 0 6px rgba(0, 0, 0, 0.85))
    drop-shadow(0 0 10px rgba(239, 68, 68, 0.55));
}
@keyframes lsr-casualty-pulse {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%      { transform: scale(1.18); opacity: 0.92; }
}
.lsr-marker--casualty:hover { animation: none; transform: scale(1.18); }
@media (prefers-reduced-motion: reduce) {
  .lsr-marker--casualty { animation: none; }
}

/* ─── Layers picker panel (cross-module overlay manager) ─────────────
 * A second .maproom-panel pinned to the top-right of any mapwrap;
 * driven by [data-maproom-layers-toggle] buttons from the options bar. */
.maproom-layers-panel {
  top: 0.75rem;
  left: auto;
  right: 0.75rem;
  width: min(20rem, 38vw);
}
.maproom-layers-list {
  font-size: var(--text-sm);
}
.maproom-layers-group {
  margin: 0.3rem 0 0.6rem;
}
.maproom-layers-group-title {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin: 0.15rem 0.1rem 0.3rem;
}
.maproom-layers-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.25rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.maproom-layers-row:hover {
  background: rgba(255, 255, 255, 0.05);
}
[data-theme="light"] .maproom-layers-row:hover {
  background: rgba(14, 30, 46, 0.05);
}
.maproom-layers-row input[type="checkbox"] {
  accent-color: var(--accent);
}

/* Small glass legend chip stack pinned to the bottom-right of a
 * .maproom-mapwrap. Used by Tropical to show active storm-type
 * colors; the volcano legend will likely use it next. */
.maproom-legend {
  position: absolute;
  bottom: 0.75rem;
  right: 0.75rem;
  z-index: 450;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.45rem 0.6rem;
  font-size: var(--text-xs);
  background: rgba(13, 16, 32, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-md);
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  color: var(--text);
  max-width: 14rem;
}
[data-theme="light"] .maproom-legend {
  background: rgba(255, 255, 255, 0.62);
  border-color: rgba(14, 30, 46, 0.12);
}
.maproom-legend:empty { display: none; }
.maproom-legend .tropical-legend-title,
.maproom-legend-title {
  font-weight: 600;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin-bottom: 0.15rem;
}
.maproom-legend .tropical-legend-row,
.maproom-legend-row {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.maproom-legend .tropical-legend-swatch,
.maproom-legend-swatch {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.2);
}

/* ─── Compact 2-line row variant inside any Map Room panel ───
 * Works on .alert-row (alerts page) and .maproom-row (other modules).
 * Line 1: event/category badge + label (truncated) + action icons
 * Line 2: chips (severity / time / etc) */
.maproom-panel .alert-list-compact,
.maproom-panel .maproom-list {
  display: block;
}
.maproom-panel .alert-row,
.maproom-panel .maproom-row {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    "event counties actions"
    "meta  meta     meta";
  align-items: center;
  gap: 0.15rem 0.5rem;
  padding: 0.4rem 0.55rem 0.4rem 0.7rem;
  margin: 0.25rem 0;
  min-height: 3.1rem;
  background: rgba(0, 0, 0, 0.22);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: var(--radius-md);
  font-size: 0.78rem;
  cursor: pointer;
}
[data-theme="light"] .maproom-panel .alert-row,
[data-theme="light"] .maproom-panel .maproom-row {
  background: rgba(255, 255, 255, 0.55);
  border-color: rgba(14, 30, 46, 0.08);
}
.maproom-panel .alert-row-stripe,
.maproom-panel .maproom-row-stripe {
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--event-color, var(--accent));
  border-radius: var(--radius-md) 0 0 var(--radius-md);
}
.maproom-panel .alert-event,
.maproom-panel .maproom-row-event {
  grid-area: event;
  font-weight: 600;
  font-size: 0.78rem;
  padding: 0.05rem 0.4rem;
  white-space: nowrap;
}
.maproom-panel .alert-counties,
.maproom-panel .maproom-row-label {
  grid-area: counties;
  align-self: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 0.78rem;
  color: var(--text);
  min-width: 0;
}
.maproom-panel .alert-meta-pills,
.maproom-panel .maproom-row-meta {
  grid-area: meta;
  display: flex;
  flex-wrap: nowrap;
  overflow: hidden;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.7rem;
}
.maproom-panel .alert-meta-pills .chip,
.maproom-panel .alert-meta-pills .exp-chip,
.maproom-panel .alert-meta-pills .threat-pill,
.maproom-panel .maproom-row-meta .chip {
  padding: 0.02rem 0.35rem;
  font-size: 0.66rem;
  line-height: 1.3;
}
.maproom-panel .alert-states,
.maproom-panel .alert-threats { display: none; }

.maproom-panel .alert-actions,
.maproom-panel .maproom-row-actions {
  grid-area: actions;
  justify-self: end;
  align-self: center;
  display: inline-flex;
  gap: 0.05rem;
}
.maproom-panel .alert-actions .btn-flat,
.maproom-panel .maproom-row-actions .btn-flat {
  padding: 0.1rem 0.32rem;
  font-size: 0.82rem;
  line-height: 1;
  background: transparent;
  border: none;
}
.maproom-panel .alert-actions .btn-flat:hover,
.maproom-panel .maproom-row-actions .btn-flat:hover {
  background: rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-sm);
}

/* Phones: float panel becomes a bottom sheet so the map stays usable. */
@media (max-width: 720px) {
  .alerts-list-floating,
  .maproom-panel {
    top: auto;
    left: 0.5rem;
    right: 0.5rem;
    bottom: 0.5rem;
    width: auto;
    max-height: 50vh;
    transform: none !important;
  }
  .maproom-panel-head { cursor: default; }
}

/* Flat (no-circle) icon-only buttons. Used by the SPC options bar and
 * the shared FilterProfiles bar (open / save / delete). Replaces the
 * encircled .btn-icon look on those surfaces; keep icons, drop chrome. */
.btn-icon-pill {
  appearance: none;
  background: transparent;
  color: var(--muted);
  border: none;
  border-radius: var(--radius-sm);
  padding: 0.3rem 0.4rem;
  font-size: 1.05rem;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: color 0.12s ease, background 0.12s ease, transform 0.12s ease;
}
.btn-icon-pill:hover    { color: var(--accent); background: rgba(255,255,255,0.04); }
.btn-icon-pill:active   { transform: scale(0.94); }
.btn-icon-pill:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-icon-pill:disabled:hover { color: var(--muted); background: transparent; }
.btn-icon-pill.filter-profile-delete:hover { color: var(--danger); }
[data-theme="light"] .btn-icon-pill:hover { background: rgba(14,30,46,0.06); }

/* Theme toggle: sun shown in light mode (to switch back to dark),
 * moon shown in dark mode (to switch to light). Single button, two
 * SVGs, CSS picks the visible one based on [data-theme]. */
.wx-theme-icon { display: none; }
[data-theme="dark"]  .wx-theme-icon--moon { display: inline-block; }
[data-theme="light"] .wx-theme-icon--sun  { display: inline-block; }
.btn-icon:hover {
  border-color: var(--accent);
  box-shadow: var(--glow-accent);
}

.btn-primary:hover,
.btn-secondary:hover,
.btn-danger:hover,
.btn-icon:hover,
.btn-chip:hover,
.download-btn:hover {
  opacity: 1;
  transform: translateY(-1px);
}

.btn-toggle {
  border: 1px solid var(--border);
  border-radius: 999px;
  background: rgba(28, 24, 56, 0.6);
  color: var(--muted);
  min-height: 2.4rem;
  padding: 0.55rem 0.9rem;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.btn-toggle:hover {
  border-color: var(--accent);
  color: var(--text);
}
.btn-toggle--active {
  background: rgba(179, 136, 255, 0.18);
  border-color: var(--accent);
  color: var(--text);
  box-shadow: inset 0 0 12px rgba(179, 136, 255, 0.25);
}

.checkbox-inline,
.filter-label,
.inline-label {
  display: inline-flex;
  align-items: center;
  gap: 0.42rem;
  color: var(--muted);
}

.filter-label select,
.filter-label input,
.field input,
.field select,
.field textarea,
.form-group input,
.form-group select,
.form-group textarea,
.setting-input {
  min-height: 2.45rem;
  padding: 0.55rem 0.75rem;
  border-radius: 0.75rem;
  border: 1px solid rgba(61, 103, 132, 0.46);
  background: rgba(5, 11, 17, 0.58);
  color: var(--text);
}

.field textarea {
  min-height: 6rem;
  resize: vertical;
}

.wx-list {
  display: grid;
  gap: 0.85rem;
}

.alert-card,
.data-card,
.lsr-card,
.geo-event,
.tropical-card {
  position: relative;
  overflow: hidden;
}

.geo-event {
  padding: 0.45rem 0.7rem;
  border-left: 4px solid var(--event-color, var(--warn));
  display: grid;
  gap: 0.2rem;
}

.geo-event h3 {
  margin: 0;
  font-size: 0.88rem;
}

.geo-meta {
  margin: 0;
  color: var(--muted);
  font-size: 0.84rem;
}

.alert-card,
.data-card {
  display: grid;
  gap: 0.35rem;
  padding: 0.55rem 0.75rem;
}

/* Compact variant for modules that need dense listings */
.compact-card {
  padding: 0.45rem 0.7rem !important;
  gap: 0.25rem !important;
}

.compact-card h3 {
  font-size: 0.9rem;
  margin: 0;
}

.compact-card .card-kicker {
  font-size: 0.65rem;
}

.compact-card .muted-text,
.compact-card .alert-times,
.compact-card .lsr-meta {
  font-size: 0.75rem;
}

.alert-card {
  border-left: 4px solid var(--event-color);
}

.alert-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.03), transparent 30%);
  pointer-events: none;
}

.alert-header,
.card-header,
.lsr-header {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  align-items: flex-start;
}

.alert-body,
.card-body {
  display: grid;
  gap: 0.4rem;
}

.alert-badge,
.lsr-badge,
.tag-pill {
  display: inline-flex;
  align-items: center;
  padding: 0.28rem 0.62rem;
  border-radius: 999px;
  background: var(--event-color);
  color: #101820;
  font-weight: 700;
  font-size: 0.78rem;
}

.alert-tags,
.card-tags {
  display: flex;
  gap: 0.35rem;
  flex-wrap: wrap;
}

.chip {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.48rem;
  border-radius: 999px;
  border: 1px solid rgba(168, 183, 196, 0.32);
  background: var(--chip-bg);
  font-size: 0.74rem;
}

.chip-severity,
.sev-extreme {
  border-color: rgba(239, 68, 68, 0.55);
}

.sev-minor {
  border-color: rgba(56, 189, 248, 0.6);
}

.chip-certainty {
  border-color: rgba(34, 197, 94, 0.55);
}

.chip-urgency {
  border-color: rgba(245, 158, 11, 0.55);
}

.chip-tag {
  border-color: rgba(242, 193, 78, 0.6);
}

.alert-area,
.alert-headline,
.alert-times,
.lsr-meta,
.feed-meta,
.geo-meta,
.overlay-area,
.overlay-times {
  margin: 0;
}

.alert-times,
.lsr-meta,
.overlay-times,
.feed-platform,
.table-note {
  color: var(--muted);
  font-size: 0.84rem;
}

.alert-actions,
.card-actions {
  display: flex;
  gap: 0.35rem;
  flex-wrap: wrap;
}

.preview-panel {
  width: min(100%, 58rem);
  padding: 1rem 1rem 1.05rem;
  background: linear-gradient(180deg, rgba(215, 198, 156, 0.97), rgba(199, 181, 135, 0.96));
  color: #2d2415;
  border-color: var(--manilla-border);
}

.preview-panel .preview-toolbar {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  padding-bottom: 0.75rem;
  background: linear-gradient(180deg, rgba(215, 198, 156, 0.98), rgba(215, 198, 156, 0.82));
}

.preview-panel .preview-body {
  display: grid;
  gap: 0.7rem;
}

.preview-panel pre,
/* ── Alert detail overlay — dark theme ─────────────────────────────────
 * Was: parchment-colored manilla background with dark-brown text. That
 * looked like a pre-WW2 telegram and clashed with the rest of the UI.
 * Now: matches the rest of the dashboard — deep-blue panel, neon accent
 * stripe keyed off the event color, white text.
 */
.overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(3, 7, 11, 0.78);
  backdrop-filter: blur(4px);
  /* 2000 keeps the overlay above Leaflet's internal layers even in browsers
     that don't honor `isolation: isolate` on the map canvas. Matches the
     `.modal` bump below. */
  z-index: 2000;
}

.overlay.hidden,
.modal.hidden { display: none; }

.overlay-content {
  width: min(52vw, 860px);
  max-height: calc(100vh - 3rem);
  overflow: auto;
  padding: 1.1rem 1.2rem 1.3rem;
  border-radius: 1rem;
  background: linear-gradient(180deg, rgba(16, 32, 54, 0.98), rgba(11, 22, 40, 0.98));
  color: var(--text);
  border: 1px solid var(--border);
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(108, 0, 240, 0.06) inset;
  position: relative;
}

.overlay-content > .overlay-section + .overlay-section { margin-top: 0.9rem; }

.overlay-close {
  position: sticky;
  top: 0.25rem;
  float: right;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  cursor: pointer;
  font-size: 1.1rem;
  transition: background 0.12s ease, border-color 0.12s ease;
  z-index: 2;
}
.overlay-close:hover {
  background: rgba(220, 38, 38, 0.18);
  border-color: rgba(220, 38, 38, 0.6);
}

.overlay-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 0.95rem;
  border-radius: 0.7rem;
  background: linear-gradient(135deg, color-mix(in srgb, var(--event-color) 55%, #081425), rgba(12, 22, 40, 0.95));
  border-left: 5px solid var(--event-color);
  box-shadow: 0 0 24px -10px var(--event-color);
  color: var(--text);
}
.overlay-badge {
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  color: var(--text);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}
.overlay-tags { display: flex; flex-wrap: wrap; gap: 0.35rem; }

.overlay-section h2 {
  margin: 0 0 0.4rem;
  font-size: 1.05rem;
  color: var(--text);
}
.overlay-area {
  margin: 0 0 0.3rem;
  font-size: 0.85rem;
  color: var(--muted);
}
.overlay-times {
  margin: 0;
  font-size: 0.75rem;
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
}

.overlay-body-text {
  margin: 0;
  padding: 0.9rem;
  border-radius: 0.6rem;
  border: 1px solid var(--border);
  background: rgba(6, 14, 26, 0.75);
  color: var(--text);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 0.85rem;
  line-height: 1.55;
}

.overlay-instruction {
  margin: 0;
  padding: 0.8rem 0.95rem;
  border-radius: 0.55rem;
  border-left: 4px solid #f97316;
  background: linear-gradient(90deg, rgba(249, 115, 22, 0.14), rgba(249, 115, 22, 0.03));
  color: var(--text);
  font-size: 0.9rem;
}

.map-shell {
  padding: 0.85rem;
}

.map-canvas {
  width: 100%;
  min-height: 360px;
  border-radius: 0.85rem;
  overflow: hidden;
  border: 1px solid rgba(61, 103, 132, 0.42);
  /* Give Leaflet its own stacking context. Without this, its internal
     z-indexes (panes at 400, controls at 800, tooltips at 1000) compete
     with our overlay (z-index: 30) at the root level and the map ends up
     painted over details popups on SPC/alerts/tropical. `isolation: isolate`
     is the minimum-impact fix — no layout change, just a new stacking root. */
  isolation: isolate;
  position: relative;
  z-index: 0;
}

.map-shell .map-canvas {
  background: linear-gradient(180deg, rgba(8, 16, 24, 0.48), rgba(8, 16, 24, 0.62));
}

.map-note {
  margin-top: 0.65rem;
  color: var(--muted);
  font-size: 0.84rem;
}

.table-shell {
  overflow: hidden;
}

.table-toolbar {
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.8rem;
}

.table-responsive {
  overflow: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
}

th,
td {
  padding: 0.72rem 0.65rem;
  border-bottom: 1px solid rgba(61, 103, 132, 0.22);
  text-align: left;
  vertical-align: top;
}

th {
  color: var(--muted);
  font-size: 0.82rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.message {
  padding: 0.8rem 1rem;
  border-radius: 0.9rem;
  border: 1px solid rgba(61, 103, 132, 0.3);
  margin-bottom: 1rem;
}

.message-success {
  background: rgba(34, 197, 94, 0.16);
}

.message-error {
  background: rgba(239, 68, 68, 0.16);
}

.message-info {
  background: rgba(56, 189, 248, 0.16);
}

.wx-placeholder {
  padding: 0.65rem 0.9rem;
  text-align: center;
  color: var(--muted);
  font-size: 0.85rem;
  position: relative;
}

/* Loading state — pulse the text so the user can tell something is
 * actively trying. Trigger by adding `.loading` (or by the literal text
 * starting with "Loading" — handled via :where in the rule below). */
.wx-placeholder.loading,
.wx-placeholder[data-state="loading"] {
  color: var(--muted);
  animation: wx-placeholder-pulse 1.4s ease-in-out infinite;
}

@keyframes wx-placeholder-pulse {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1; }
}

/* Empty state — slightly emphasized, no animation. */
.wx-placeholder.empty,
.wx-placeholder[data-state="empty"] {
  color: var(--muted);
  font-style: italic;
}

.wx-placeholder.error,
.wx-placeholder[data-state="error"] {
  color: #ffd2d2;
  border: 1px dashed rgba(239, 68, 68, 0.42);
  border-radius: var(--radius-md);
  background: rgba(239, 68, 68, 0.06);
}

/* Retry button slot — placeholders can render an action inline. */
.wx-placeholder .wx-placeholder-action {
  display: inline-block;
  margin-left: 0.6rem;
  color: var(--accent);
  background: none;
  border: none;
  cursor: pointer;
  text-decoration: underline;
  font: inherit;
}
.wx-placeholder .wx-placeholder-action:hover { color: var(--accent-strong); }

/* ─── Skeleton shimmer ─────────────────────────────────────────────────────
 * Cheap perceived-performance win — use in place of `Loading…` strings
 * for rows/cards while data is in flight. */
.wx-skeleton {
  display: block;
  background: linear-gradient(90deg,
    rgba(255,255,255,0.04) 0%,
    rgba(255,255,255,0.10) 50%,
    rgba(255,255,255,0.04) 100%);
  background-size: 200% 100%;
  border-radius: var(--radius-md);
  animation: wx-skeleton-shimmer 1.4s ease-in-out infinite;
  min-height: 1rem;
}
[data-theme="light"] .wx-skeleton {
  background: linear-gradient(90deg,
    rgba(14,30,46,0.05) 0%,
    rgba(14,30,46,0.12) 50%,
    rgba(14,30,46,0.05) 100%);
}
.wx-skeleton--text { height: 0.85rem; margin: 0.3rem 0; }
.wx-skeleton--row  { height: 2.4rem; margin: 0.35rem 0; }
.wx-skeleton--card { height: 5.5rem; margin: 0.5rem 0; }

@keyframes wx-skeleton-shimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/* ─── Toast / snackbar system ──────────────────────────────────────────────
 * Singleton container injected by toasts.js. Stacks at bottom-right on
 * desktop, bottom-centered on phones. Auto-dismisses; supports info /
 * success / error variants. */
.wx-toast-stack {
  position: fixed;
  z-index: 1100;
  right: max(1rem, env(safe-area-inset-right));
  bottom: max(1rem, env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  pointer-events: none;
  max-width: 22rem;
}
.wx-toast {
  pointer-events: auto;
  background: var(--card);
  color: var(--text);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-md);
  padding: 0.6rem 0.85rem;
  font-size: var(--text-sm);
  box-shadow: var(--shadow);
  transform: translateY(8px);
  opacity: 0;
  transition: transform 0.18s ease, opacity 0.18s ease;
}
.wx-toast.is-visible { transform: translateY(0); opacity: 1; }
.wx-toast--success { border-left-color: var(--success); }
.wx-toast--error   { border-left-color: var(--danger); }
.wx-toast--warn    { border-left-color: var(--warn); }

@media (max-width: 720px) {
  .wx-toast-stack {
    right: max(0.75rem, env(safe-area-inset-right));
    left: max(0.75rem, env(safe-area-inset-left));
    max-width: none;
  }

  /* Header shrink on phones — pills overflowed the title row badly at
   * 360-420px wide. Smaller h1 + tighter pill padding + slightly
   * smaller font keeps the nav usable in portrait mobile. The "More"
   * disclosure picks up most of the catalog anyway. */
  .wx-header { padding: 0.5rem 0.7rem 0.45rem; }
  .wx-header h1 { font-size: 1.1rem; }
  .wx-version { font-size: 0.78rem; }
  .wx-nav-link,
  .nav-chip {
    min-height: 1.6rem;
    padding: 0.22rem 0.55rem;
    font-size: 0.82rem;
  }
  /* Honor safe-area on the main content too, not just the header — was
   * missing pre-audit; PWA landscape installs clipped side content. */
  .wx-main {
    padding-left: max(0.75rem, env(safe-area-inset-left));
    padding-right: max(0.75rem, env(safe-area-inset-right));
  }
}

/* ─── Inline-prompt modal (replaces window.prompt for profile names) ─── */
.wx-prompt-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(2, 1, 12, 0.65);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1200;
  padding: 1rem;
}
.wx-prompt {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  max-width: 24rem;
  width: 100%;
  padding: 1rem 1.1rem;
}
.wx-prompt h3 { margin: 0 0 0.4rem; font-size: var(--text-md); }
.wx-prompt p  { margin: 0 0 0.7rem; color: var(--muted); font-size: var(--text-sm); }
.wx-prompt input[type="text"] {
  width: 100%;
  padding: 0.5rem 0.6rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--card-soft);
  color: var(--text);
}
.wx-prompt-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.85rem;
}

/* ─── Keyboard shortcut cheatsheet ─────────────────────────────────── */
.wx-cheatsheet { max-width: 22rem; }
.wx-cheatsheet-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
.wx-cheatsheet-table td {
  padding: 0.25rem 0.4rem;
  border-bottom: 1px dashed var(--border);
}
.wx-cheatsheet-table td:first-child {
  white-space: nowrap;
  color: var(--muted);
}
kbd {
  display: inline-block;
  font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
  font-size: 0.78em;
  padding: 0.05rem 0.4rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--card-soft);
  color: var(--text);
  box-shadow: 0 1px 0 var(--border);
}

/* ─── Improved :focus-visible ring system-wide ─────────────────────────── */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ─── Skip-to-content link ────────────────────────────────────────────── */
.wx-skip-link {
  position: fixed;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 2000;
  background: var(--accent);
  color: #0a0815;
  padding: 0.55rem 0.85rem;
  border-radius: var(--radius-md);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-200%);
  transition: transform 0.18s ease;
}
.wx-skip-link:focus,
.wx-skip-link:focus-visible {
  transform: translateY(0);
  outline: 2px solid var(--accent-strong);
  outline-offset: 2px;
}

/* ─── Online / offline indicator ──────────────────────────────────────── */
.wx-offline-banner {
  position: fixed;
  top: max(0.6rem, env(safe-area-inset-top));
  left: 50%;
  transform: translate(-50%, -200%);
  z-index: 1050;
  background: var(--warn);
  color: #2a1d00;
  font-weight: 600;
  font-size: var(--text-sm);
  padding: 0.45rem 0.85rem;
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow);
  transition: transform 0.22s ease;
  pointer-events: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.wx-offline-banner.is-visible { transform: translate(-50%, 0); }
.wx-offline-banner::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #b45309;
}

/* ─── Compact alert rows ─────────────────────────────────────────────────── */

.alert-list-compact {
  display: grid;
  /* Real breathing room between rows so high-threat pulses don't blur into
   * one solid bar of red during a multi-warning outbreak. */
  gap: 8px;
}

/* 1.17 alerts list rework v2 — flex-wrap layout. The earlier grid version
 * collapsed the counties column to single characters ("R.") under tight
 * widths because grid `minmax(0, 1fr)` will shrink to zero before any
 * other column gives. Flex with min-width on counties keeps the county
 * name readable and pushes wrap responsibility onto the threat row, where
 * wrapping is desirable. Sharp corners + full-width event name per spec. */
.alert-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.55rem 0.45rem 0;
  border-radius: 3px;
  border: 1px solid rgba(61, 103, 132, 0.22);
  background: linear-gradient(90deg, rgba(16, 32, 54, 0.88), rgba(9, 20, 32, 0.9));
  overflow: hidden;
  cursor: default;
  font-size: 0.78rem;
}

.alert-row-stripe {
  align-self: stretch;
  background: var(--event-color, var(--accent));
  width: 8px;
  flex: 0 0 8px;
}

.alert-event {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.6rem;
  border-radius: 3px;
  background: var(--event-color, var(--accent));
  color: #101820;
  font-weight: 700;
  font-size: 0.8rem;
  white-space: nowrap;
  margin-left: 0.3rem;
  flex: 0 0 auto;
}

.alert-states {
  display: flex;
  gap: 0.2rem;
  align-items: center;
  flex: 0 0 auto;
}
.state-chip {
  display: inline-flex;
  align-items: center;
  padding: 0.14rem 0.38rem;
  border-radius: 3px;
  background: rgba(56, 189, 248, 0.16);
  border: 1px solid rgba(56, 189, 248, 0.4);
  color: #bae6fd;
  font-weight: 600;
  font-size: 0.7rem;
  letter-spacing: 0.04em;
}
.state-chip--unknown {
  background: rgba(148, 163, 184, 0.1);
  border-color: rgba(148, 163, 184, 0.25);
  color: var(--muted);
}

.alert-counties {
  flex: 1 1 12rem;
  min-width: 8rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--text);
}

.alert-meta-pills {
  display: flex;
  gap: 0.25rem;
  align-items: center;
  flex-wrap: nowrap;
  flex: 0 0 auto;
}

.alert-actions--flat {
  display: flex;
  gap: 0.1rem;
  align-items: center;
  flex: 0 0 auto;
  margin-left: auto;  /* push to right edge */
}

.alert-threats {
  margin-left: calc(8px + 0.3rem);  /* align under stripe + event left edge */
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
  flex: 1 1 100%;  /* break to its own line */
}

.threat-group {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.05rem 0.1rem;
  font-size: 0.78rem;
}

/* Threat pills — tier-coded per the 1.17 mockup. Filled fill = a positive
 * detection ("there IS a threat"), outline = neutral data carrier (max
 * value, etc.). The escalation order operators read top-down:
 *   RADAR  →  OBS  →  Considerable  →  Destructive  →  PDS  →  EMERGENCY */
.threat-pill {
  display: inline-flex;
  align-items: center;
  padding: 0.12rem 0.42rem;
  border-radius: 3px;
  background: rgba(148, 163, 184, 0.12);
  border: 1px solid rgba(148, 163, 184, 0.3);
  color: #cbd5e1;
  font-size: 0.7rem;
  font-weight: 600;
  white-space: nowrap;
  letter-spacing: 0.02em;
}

/* Detection: RADAR INDICATED (yellow filled) */
.threat-pill--radar {
  background: #facc15;
  border-color: #facc15;
  color: #1f2937;
}

/* Detection: OBSERVED — visually confirmed, escalation step 1 */
.threat-pill--obs {
  background: #dc2626;
  border-color: #dc2626;
  color: #fff;
}

/* Detection: POSSIBLE — NWS embedded-tornado-threat tag inside an SVR.
 * Sits between RADAR and OBSERVED in operational urgency. */
.threat-pill--possible {
  background: #f97316;
  border-color: #c2410c;
  color: #fff;
  font-weight: 700;
}

/* Severe Thunderstorm damage tiers */
.threat-pill--considerable {
  background: transparent;
  border-color: #f97316;
  color: #fdba74;
}
.threat-pill--destructive {
  background: transparent;
  border-color: #dc2626;
  color: #fca5a5;
  font-weight: 700;
}

/* Tornado escalation pills (PDS = Considerable, EMERGENCY = Catastrophic) */
.threat-pill--pds {
  background: #b91c1c;
  border-color: #7f1d1d;
  color: #fff;
  font-weight: 700;
  letter-spacing: 0.08em;
}
.threat-pill--emergency {
  background: #7e22ce;
  border-color: #581c87;
  color: #fff;
  font-weight: 800;
  letter-spacing: 0.1em;
}

/* Numeric value pills (max gust, hail size) — outlined yellow/amber */
.threat-pill--value {
  background: transparent;
  border-color: #f59e0b;
  color: #fcd34d;
}

/* Expiration / EXPIRED chip */
.exp-chip {
  display: inline-flex;
  align-items: center;
  padding: 0.14rem 0.4rem;
  border-radius: 3px;
  background: rgba(148, 163, 184, 0.12);
  color: var(--muted);
  font-size: 0.7rem;
  white-space: nowrap;
}
.exp-chip--expired {
  background: rgba(148, 163, 184, 0.22);
  border: 1px solid rgba(148, 163, 184, 0.5);
  color: #94a3b8;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Pinned-but-expired: keep visible per operator request, but fade the row
 * so it visually reads as historical context rather than a live alert. */
.alert-row--expired {
  opacity: 0.55;
  filter: grayscale(40%);
}
.alert-row--pinned {
  border-color: rgba(56, 189, 248, 0.55);
  box-shadow: 0 0 0 1px rgba(56, 189, 248, 0.25) inset;
}

/* Flat (no-circle) action buttons — replaces .btn-icon's circular bg.
 * Just emoji on hover-highlight. Active state for the pin toggle uses
 * the cyan accent so the operator sees pinned state at a glance. */
.btn-flat {
  background: transparent;
  border: 1px solid transparent;
  color: var(--text);
  padding: 0.15rem 0.35rem;
  border-radius: 3px;
  font-size: 0.95rem;
  line-height: 1;
  cursor: pointer;
  transition: background 80ms, border-color 80ms;
}
.btn-flat:hover {
  background: rgba(148, 163, 184, 0.12);
  border-color: rgba(148, 163, 184, 0.28);
}
.btn-flat--active {
  background: rgba(56, 189, 248, 0.18);
  border-color: rgba(56, 189, 248, 0.5);
  color: #bae6fd;
}
.btn-flat--lg {
  padding: 0.35rem 0.65rem;
  font-size: 0.85rem;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.btn-flat--danger { color: #fda4af; }
.btn-flat--danger:hover { background: rgba(220, 38, 38, 0.18); border-color: rgba(220, 38, 38, 0.5); color: #fecaca; }

/* Sharp pills throughout the alerts list (was 999px / fully rounded) */
.alert-row .chip { border-radius: 3px; font-size: 0.7rem; }

.overlay-actions {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 0.8rem;
  padding-top: 0.8rem;
  border-top: 1px solid rgba(148, 163, 184, 0.18);
}
.overlay-actions-spacer { flex: 1 1 auto; }

.alert-row--recent {
  animation: wx-flash-recent 1.2s ease-in-out infinite;
}

.alert-card--recent {
  animation: wx-flash-recent 1.2s ease-in-out infinite;
}

@keyframes wx-flash-recent {
  0%, 100% { box-shadow: 0 0 0 1px rgba(245, 158, 11, 0.8), 0 18px 40px rgba(2, 8, 14, 0.45); }
  50% { box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.25), 0 18px 40px rgba(2, 8, 14, 0.45); }
}

/* High-threat indicator: pulse the LEFT STRIPE only, not the whole row.
 * Earlier we flashed the entire row background + box-shadow, but during a
 * busy outbreak that produced a wall of strobing red where every row blurred
 * into the next. Stripe-only pulse keeps the alarm visible at the edge of
 * vision while leaving the row body readable. */
.alert-row--threat .alert-row-stripe {
  background: #dc2626;
  animation: wx-stripe-pulse 1.1s ease-in-out infinite;
}
@keyframes wx-stripe-pulse {
  0%, 100% { box-shadow: inset 0 0 0 1px rgba(220, 38, 38, 0.95), 0 0 6px rgba(220, 38, 38, 0.55); }
  50%      { box-shadow: inset 0 0 0 1px rgba(220, 38, 38, 0.4),  0 0 18px rgba(220, 38, 38, 0.95); }
}
@media (prefers-reduced-motion: reduce) {
  .alert-row--recent { animation: none; }
  .alert-row--threat .alert-row-stripe { animation: none; box-shadow: 0 0 4px rgba(220, 38, 38, 0.85); }
}

/* ── Multi-select filter dropdown (events) ───────────────────────────── */
.filter-multiselect {
  position: relative;
  display: inline-block;
}
.filter-multiselect > summary {
  list-style: none;
  cursor: pointer;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 0.3rem;
  background: var(--card);
  color: var(--text);
  font-size: 0.85rem;
  min-width: 8rem;
  user-select: none;
}
.filter-multiselect > summary::-webkit-details-marker { display: none; }
.filter-multiselect > summary::after {
  content: "▾";
  margin-left: 0.5rem;
  opacity: 0.6;
}
.filter-multiselect[open] > summary { border-color: var(--accent); }
.filter-multiselect-panel {
  position: absolute;
  top: calc(100% + 0.3rem);
  left: 0;
  z-index: 50;
  min-width: 18rem;
  max-height: 20rem;
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 0.4rem;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.45);
  padding: 0.5rem;
}
.filter-multiselect-actions {
  display: flex;
  gap: 0.5rem;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.4rem;
}
.filter-multiselect-actions .btn-link {
  background: none;
  border: none;
  color: var(--accent);
  cursor: pointer;
  font-size: 0.78rem;
  padding: 0.15rem 0.2rem;
}
.filter-multiselect-list {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.filter-multiselect-item {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  font-size: 0.82rem;
  padding: 0.15rem 0.25rem;
  border-radius: 0.25rem;
}
.filter-multiselect-item:hover { background: rgba(255, 255, 255, 0.04); }
.filter-events-box { display: inline-flex; align-items: center; gap: 0.35rem; }
.alert-row-exp { cursor: help; }

.btn-scroll-top {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  width: 3rem;
  height: 3rem;
  border-radius: 999px;
  border: 1px solid rgba(61, 103, 132, 0.45);
  background: rgba(5, 11, 17, 0.88);
  color: var(--accent);
  box-shadow: 0 12px 30px rgba(2, 8, 14, 0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease;
  z-index: 40;
}

.btn-scroll-top.visible {
  opacity: 1;
  pointer-events: auto;
}

.modal {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(3, 7, 11, 0.62);
  z-index: 2100;
}

.modal-content {
  width: min(34rem, 100%);
  padding: 1rem;
}

.modal-close {
  margin-left: auto;
  background: transparent;
  border: 0;
  color: var(--muted);
  font-size: 1.6rem;
  cursor: pointer;
}

.primary-grid-inner {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6rem;
}

.stream-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.35rem;
  font-size: 0.78rem;
  color: var(--muted);
}

.settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 1rem;
}

.settings-panel .field,
.field {
  display: grid;
  gap: 0.3rem;
  margin-bottom: 0.8rem;
}

.field-help {
  font-size: 0.78rem;
  line-height: 1.35;
  margin-top: 0.1rem;
}

.color-pair {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.color-pair input[type="color"] {
  width: 2.5rem;
  min-height: 2.45rem;
  padding: 0.2rem;
  border-radius: 0.5rem;
  border: 1px solid rgba(61, 103, 132, 0.46);
  background: rgba(5, 11, 17, 0.58);
  cursor: pointer;
  flex-shrink: 0;
}

/* Live swatch preview next to each event row. Sits at the start of
 * the row so the eye picks up the color instantly without resolving
 * the picker control. */
.color-pair .event-swatch {
  display: inline-block;
  width: 1.1rem;
  height: 1.1rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  flex-shrink: 0;
}

/* Grouped event-color sections. Each fieldset reads as a small card so
 * the 26-row picker breaks into scannable convective / winter / marine
 * etc. clusters. */
.color-group {
  margin: 0 0 var(--space-4);
  padding: var(--space-3) var(--space-4) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.015);
}
.color-group legend {
  padding: 0 var(--space-2);
  color: var(--accent);
  font-weight: 600;
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.color-group .color-pair {
  margin: var(--space-2) 0;
}

/* Event Colors pane (1.16.0). Two-column grid that wraps cleanly on mobile
   — the LSR version has 26 rows so space efficiency matters. */
.color-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
  gap: 0.5rem 1rem;
  max-height: 34rem;
  overflow-y: auto;
  padding: 0.3rem 0.2rem 0.5rem;
}

.field label,
.field legend,
.form-group label {
  color: var(--muted);
  font-size: 0.86rem;
}

.legend-row {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
}

.status-card {
  padding: 0.9rem 1rem;
}

.status-card h3 {
  margin: 0 0 0.35rem;
}

.status-card p {
  margin: 0;
  color: var(--muted);
}

.mini-list {
  display: grid;
  gap: 0.6rem;
}

.mini-list-item {
  display: flex;
  justify-content: space-between;
  gap: 0.8rem;
  align-items: center;
  padding: 0.65rem 0.75rem;
  border-radius: 0.75rem;
  background: rgba(5, 11, 17, 0.42);
  border: 1px solid rgba(61, 103, 132, 0.2);
}

/* ─── Home page ──────────────────────────────────────────────────────────── */

.home-status-bar {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 0.75rem;
  margin-bottom: 1.2rem;
}

.home-stat {
  padding: 1rem 1.1rem 0.85rem;
  border-radius: 1rem;
  border: 1px solid rgba(61, 103, 132, 0.32);
  background: linear-gradient(180deg, rgba(16, 32, 54, 0.9), rgba(9, 20, 32, 0.95));
  box-shadow: var(--shadow);
  text-align: center;
}

.home-stat-value {
  font-size: 2.2rem;
  font-weight: 800;
  line-height: 1;
  margin-bottom: 0.3rem;
  color: var(--accent);
}

.home-stat-value--time {
  font-size: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  align-items: center;
  padding-top: 0.4rem;
}

.home-stat[data-level="none"] .home-stat-value { color: var(--success); }
.home-stat[data-level="low"]  .home-stat-value { color: var(--warn); }
.home-stat[data-level="mid"]  .home-stat-value { color: #f97316; }
.home-stat[data-level="high"] .home-stat-value { color: var(--danger); }

.home-stat-value--ingestor[data-status="ok"]      { color: var(--success); }
.home-stat-value--ingestor[data-status="stale"]   { color: var(--warn); }
.home-stat-value--ingestor[data-status="error"]   { color: var(--danger); }
.home-stat-value--ingestor[data-status="unknown"] { color: var(--muted); }

.home-stat-label {
  color: var(--muted);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.home-dash-grid {
  display: grid;
  /* Was minmax(240px, ...). Modules are launchers — name + one-line
   * description. They don't need 240px each. Tightening to ~165px lets
   * a 1080p screen fit all 11 modules in one row, eliminating the
   * "scrolls off the bottom" symptom the operator reported. */
  grid-template-columns: repeat(auto-fill, minmax(165px, 1fr));
  gap: 0.55rem;
}

.home-dash-card {
  display: flex;
  align-items: stretch;
  border-radius: 0.7rem;
  border: 1px solid rgba(61, 103, 132, 0.28);
  background: linear-gradient(135deg, rgba(14, 28, 46, 0.95), rgba(8, 16, 28, 0.97));
  text-decoration: none;
  overflow: hidden;
  transition: transform 0.17s ease, border-color 0.17s ease, box-shadow 0.17s ease;
  box-shadow: var(--shadow);
}

.home-dash-card:hover {
  transform: translateY(-3px);
  border-color: var(--module-color, var(--accent));
  box-shadow: 0 0 0 1px var(--module-color, var(--accent)), 0 20px 44px rgba(2, 8, 14, 0.5);
}

.home-dash-accent {
  width: 3px;
  flex-shrink: 0;
  background: var(--module-color, var(--accent));
  box-shadow: 0 0 14px var(--module-color, var(--accent));
}

.home-dash-body {
  flex: 1;
  padding: 0.5rem 0.65rem 0.55rem;
  min-width: 0;
}

.home-dash-id {
  color: var(--module-color, var(--accent));
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.09em;
  margin-bottom: 0.1rem;
}

.home-dash-name {
  margin: 0 0 0.15rem;
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--text);
}

.home-dash-desc {
  margin: 0;
  font-size: 0.72rem;
  line-height: 1.35;
  color: var(--muted);
  /* Was nowrap+ellipsis — chopped off all useful detail on tiles
   * narrower than the longest description. Allow two lines and clamp
   * with -webkit-line-clamp so cards stay aligned but copy is readable. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
}

.home-dash-arrow {
  display: flex;
  align-items: center;
  padding-right: 0.55rem;
  color: var(--module-color, var(--accent));
  opacity: 0.5;
  font-size: 1rem;
  transition: opacity 0.17s ease, transform 0.17s ease;
}

.home-dash-card:hover .home-dash-arrow {
  opacity: 1;
  transform: translateX(3px);
}

.hero-actions {
  display: flex;
  gap: 0.65rem;
  flex-wrap: wrap;
  margin-top: 0.9rem;
}

.list-inline {
  display: flex;
  gap: 0.55rem;
  flex-wrap: wrap;
}

.is-hidden {
  display: none !important;
}

/* ─────────────────────────────────────────────────────────────────────
 * Utility classes (1.23.0 / B2) — replacements for the 56 inline style=""
 * attributes that used to require CSP `style-src-attr 'unsafe-inline'`.
 * Each utility names a single declaration so a class soup like
 * `class="u-mt-md u-text-md u-mb-sm"` reads obviously.
 *
 * Naming: `.u-` prefix to signal utility / non-semantic. Keep the set
 * small — operators editing a module page should be able to skim this
 * block and find the one they need rather than memorize Tailwind.
 * ──────────────────────────────────────────────────────────────────── */

/* margins */
.u-mt-xs { margin-top: 0.2rem; }
.u-mt-sm { margin-top: 0.5rem; }
.u-mt-md { margin-top: 0.8rem; }
.u-mt-lg { margin-top: 1rem; }
.u-mt-xl { margin-top: 1.2rem; }
.u-mb-sm { margin-bottom: 0.5rem; }
.u-mb-md { margin-bottom: 0.6rem; }
.u-mb-lg { margin-bottom: 0.7rem; }
.u-mb-xl { margin-bottom: 0.75rem; }
.u-mb-2xl { margin-bottom: 1rem; }
.u-mx-auto { margin-left: auto; margin-right: auto; }
.u-mt-section { margin: 1rem 0 0.4rem; }   /* h3 inside a section */
.u-m-0 { margin: 0; }
.u-mb-0 { margin-bottom: 0 !important; }

/* font sizes (small/notes) */
.u-text-xs { font-size: 0.7rem; }
.u-text-sm { font-size: 0.78rem; }
.u-text-md { font-size: 0.82rem; }
.u-text-lg { font-size: 0.95rem; }

/* color overrides */
.u-text-default { color: var(--text); }
.u-text-muted   { color: var(--muted); }

/* flex sizing for split-layout panels */
.u-flex-1            { flex: 1; }
.u-min-w-0           { min-width: 0; }
.u-flex-fixed-22rem  { flex: 0 0 22rem; }
.u-flex-grow-26rem   { flex: 1 1 26rem; }
.u-flex-grow-30rem   { flex: 1 1 30rem; }
.u-flex-grow-32rem   { flex: 1 1 32rem; min-width: 0; }
.u-flex-grow-34rem   { flex: 1 1 34rem; }

/* layout */
.u-align-start    { align-items: flex-start; }
.u-flex-col-gap-sm { display: flex; flex-direction: column; gap: 0.5rem; }
.u-flex-row-gap-sm { display: flex; gap: 0.5rem; align-items: center; }

/* sticky aside (alerts page map) */
.u-sticky-top-5 { position: sticky; top: 5rem; }

/* width caps */
.u-max-w-30rem    { max-width: 30rem; }
.u-max-w-300px    { max-width: 300px; }
.u-w-10rem        { width: 10rem; }

/* fixed/min heights for charts and maps */
.u-h-250    { height: 250px; }
.u-h-340    { height: 340px; }
.u-min-h-280 { min-height: 280px; }
.u-min-h-440 { min-height: 440px; }

/* a positioned chart wrapper */
.u-chart-frame { position: relative; height: 340px; }

/* scrolling list panes used in Logs / Headlines settings tabs */
.u-scroll-30rem { max-height: 30rem; overflow-y: auto; }

/* compact card padding for special-case panels */
.u-pad-sm   { padding: 0.5rem; }
.u-radius-md { border-radius: 0.65rem; }

/* The forecast-grid section wraps sub-panels with display:grid; gap. */
.u-grid-gap-md { display: grid; gap: 0.85rem; }

/* placefile bbox row — column-stacked controls */
.u-flex-col-stack { display: flex; flex-direction: column; gap: 0.5rem; }

/* Login card sizing — special-cased because the form lives outside
 * any other container width constraint. */
.login-card { max-width: 30rem; margin: 2rem auto; }

.wx-login-main {
  min-height: calc(100vh - 8rem);
  display: flex;
  align-items: center;
  justify-content: center;
}

.login-brand {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  margin-bottom: 1rem;
}
.login-brand-mark {
  width: 44px;
  height: 44px;
  filter: drop-shadow(0 0 12px rgba(179, 136, 255, 0.45));
}
.login-brand-title {
  margin: 0;
  font-size: var(--text-xl);
}
.login-brand-sub {
  margin: 0.15rem 0 0;
  color: var(--muted);
  font-size: var(--text-sm);
}

/* Telestrator control buttons (Leaflet-rendered toolbar). The JS used
 * to set these via element.style.cssText which was blocked by
 * style-src-attr 'none' (1.23.0 / B2). Class form is identical
 * visually but CSP-clean. */
.telestrator-btn-square {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  font-size: 16px;
  text-decoration: none;
}

/* ─────────────────────────────────────────────────────────────────────
 * Additional utility classes for the JS-template sweep (1.24.0 / B2.2).
 * Same naming convention as 1.23.0's `.u-*` block. Most of these fill
 * gaps for the inline styles that were embedded in JS template strings.
 * ──────────────────────────────────────────────────────────────────── */

/* extra font sizes */
.u-text-2xs   { font-size: 0.65rem; }
.u-text-tiny  { font-size: 0.72rem; }
.u-text-tiny-em { font-size: 0.75rem; }
.u-text-md-em { font-size: 0.8rem; }
.u-text-card  { font-size: 0.88rem; }
.u-text-h-sm  { font-size: 0.95rem; }
.u-text-em-sm { font-size: 0.85em; }
.u-text-em-md { font-size: 0.8em; }
.u-text-em-lg { font-size: 0.75em; }

/* extra widths / min-widths */
.u-w-6rem      { width: 6rem; }
.u-w-1-8rem    { width: 1.8rem; min-width: 1.8rem; }
.u-min-w-9rem  { min-width: 9rem; }
.u-min-w-11rem { min-width: 11rem; }
.u-min-w-16rem { min-width: 16rem; }
.u-min-w-200px { min-width: 200px; }

/* layout helpers */
.u-flex-shrink-0  { flex-shrink: 0; }
.u-text-right     { text-align: right; }
.u-actions-right  { margin-left: auto; display: inline-flex; gap: 0.4rem; }
.u-list-row-head  { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.2rem; }
.u-row-action-cluster { display: flex; gap: 0.3rem; flex-shrink: 0; }
.u-lsr-header-tight { gap: 0.35rem; }
.u-lsr-loc-text { font-size: 0.8rem; flex: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }

/* status-pill size variants used in JS-rendered lists */
.u-pill-xs { font-size: 0.7rem; padding: 0.15rem 0.45rem; }
.u-pill-2xs { font-size: 0.65rem; padding: 0.1rem 0.3rem; }
.u-pill-em-sm { font-size: 0.7rem; padding: 0.15rem 0.4rem; }
.u-pill-log-level { font-size: 0.7rem; padding: 0.2rem 0.5rem; }

/* compact action buttons in admin list rows */
.u-btn-tiny { font-size: 0.72rem; padding: 0.2rem 0.5rem; }

/* role/visual color helpers */
.u-color-info     { color: #38bdf8; }
.u-color-spc-pds  { color: #7e22ce; font-weight: 700; }
.u-color-faint    { color: #888; }
.u-color-danger   { color: var(--danger); }
.u-text-weight-normal { font-weight: 400; }

/* misc one-off */
.u-mt-3px { margin-top: 0.15rem; }
.u-mb-3xs { margin-bottom: 0.3rem; }
.u-mt-tag { margin-top: 0.4rem; }
.u-overlay-h2 { margin: 0 0 0.75rem; }
.u-pre-context {
  font-size: 0.72rem; color: var(--muted); margin: 0.2rem 0 0;
  white-space: pre-wrap; max-height: 4rem; overflow: hidden;
}

/* pre-allocated chip used in tropical legend */
.tropical-legend-row {
  display: flex; align-items: center; gap: 0.4rem;
  font-size: 0.75rem; margin: 0.15rem 0;
}
.tropical-legend-swatch {
  display: inline-block; width: 12px; height: 12px; border-radius: 50%;
}
.tropical-legend-title {
  font-size: 0.78rem; font-weight: 600; margin-bottom: 0.3rem;
}

/* tropical card heading */
.tropical-card-h3 { font-size: 0.95rem; margin: 0; }

/* tropical card body — clamped multi-line */
.tropical-card-body {
  font-size: 0.8rem; white-space: pre-wrap; max-height: 6rem; overflow: hidden;
}

/* spc preview popup body */
.spc-preview-keys-row { font-size: 0.75em; }
.spc-preview-top      { margin-top: 0.4rem; }
.spc-area-text        { font-size: 0.8rem; }

/* Volcano-marker triangle color resolved from data-aviation attribute
 * (1.24.0 / B2.2). Was inline-styled `border-bottom-color:${color}`,
 * which is blocked by style-src-attr 'none'. Same 4 colors as the
 * AVIATION_COLORS map in geological.js — keep in sync if changed. */
.volcano-marker-triangle[data-aviation="GREEN"]  { border-bottom-color: #22c55e; }
.volcano-marker-triangle[data-aviation="YELLOW"] { border-bottom-color: #facc15; }
.volcano-marker-triangle[data-aviation="ORANGE"] { border-bottom-color: #f97316; }
.volcano-marker-triangle[data-aviation="RED"]    { border-bottom-color: #ef4444; }
.volcano-marker-triangle:not([data-aviation])    { border-bottom-color: #64748b; }

/* Module-launcher accent colors. Driven by data-module="<id>" so we
 * don't inline `style="--module-color: ..."` per card. Adding a new
 * module requires adding one rule here. */
.home-dash-card[data-module="alerts"]        { --module-color: #ff2b5a; }
.home-dash-card[data-module="spc"]           { --module-color: #ff7a00; }
.home-dash-card[data-module="lsr"]           { --module-color: #38bdf8; }
.home-dash-card[data-module="tropical"]      { --module-color: #06b6d4; }
.home-dash-card[data-module="geological"]    { --module-color: #f59e0b; }
.home-dash-card[data-module="livechasers"]   { --module-color: #b388ff; }
.home-dash-card[data-module="placefile"]     { --module-color: #22c55e; }
.home-dash-card[data-module="forecasts"]     { --module-color: #14b8a6; }
.home-dash-card[data-module="localforecast"] { --module-color: #8b5cf6; }
.home-dash-card[data-module="settings"]      { --module-color: #94a3b8; }
.home-dash-card[data-module="wxstation"]     { --module-color: #38fff0; }


/* ─── Forecasts ──────────────────────────────────────────────────────────── */

.forecast-summary-bar {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: wrap;
  padding: 0.5rem 0;
}

.forecast-wfo {
  font-weight: 700;
  font-size: 1rem;
  color: var(--accent);
}

.forecast-periods-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 0.6rem;
}

.forecast-period {
  display: grid;
  gap: 0.25rem;
  padding: 0.6rem 0.7rem;
  border-radius: 0.85rem;
  border: 1px solid rgba(61, 103, 132, 0.32);
  background: linear-gradient(180deg, rgba(16, 32, 54, 0.92), rgba(9, 20, 32, 0.95));
  font-size: 0.82rem;
}

.forecast-period--night {
  border-color: rgba(61, 103, 132, 0.2);
  background: linear-gradient(180deg, rgba(10, 20, 36, 0.92), rgba(6, 13, 22, 0.95));
}

.forecast-period-name {
  font-weight: 700;
  font-size: 0.75rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.forecast-period-icon {
  font-size: 1.6rem;
  line-height: 1;
  margin: 0.15rem 0;
}

.forecast-period-temp {
  font-size: 1.3rem;
  font-weight: 800;
  line-height: 1;
}

.forecast-period-short {
  color: var(--text);
  font-size: 0.78rem;
  line-height: 1.3;
}

.forecast-period-wind {
  color: var(--muted);
  font-size: 0.72rem;
}

.forecast-period-detail {
  margin-top: 0.2rem;
}

.forecast-period-detail summary {
  color: var(--muted);
  font-size: 0.7rem;
  cursor: pointer;
}

.forecast-period-detail p {
  margin: 0.35rem 0 0;
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--muted);
}

/* ─── Diagnostics ────────────────────────────────────────────────────────── */

.diag-item {
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.5rem;
}

.diag-item--alert {
  border-left: 3px solid var(--warning, #f59e0b);
  padding-left: 0.75rem;
}

.diag-reason {
  margin-top: 0.4rem;
  padding: 0.35rem 0.6rem;
  background: rgba(245, 158, 11, 0.08);
  border-radius: 0.35rem;
  font-size: 0.78rem;
  color: var(--text);
  line-height: 1.5;
  word-break: break-word;
}

.diag-reason code,
.diag-reason .diag-reason-icon {
  color: var(--warning, #f59e0b);
}

/* ─── Placefile cards ────────────────────────────────────────────────────── */

.placefile-card {
  display: grid;
  /* minmax(0, 1fr): without it the single track sizes to the URL row's
   * min-content (input intrinsic width + nowrap Copy button), which is
   * wider than the card, so rows and the Preview button ran past the
   * card edge (WXAPI-101). */
  grid-template-columns: minmax(0, 1fr);
  gap: 0.6rem;
  min-width: 0;
}

.placefile-icon {
  font-size: 1.6rem;
  line-height: 1;
}

.placefile-url-row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.placefile-url-input {
  flex: 1;
  min-width: 0;
  min-height: 2.4rem;
  padding: 0.4rem 0.65rem;
  border-radius: 0.65rem;
  border: 1px solid rgba(61, 103, 132, 0.46);
  background: rgba(5, 11, 17, 0.7);
  color: var(--accent);
  font-size: 0.8rem;
  font-family: "Consolas", "Courier New", monospace;
  cursor: text;
}

.placefile-copy-btn {
  white-space: nowrap;
  flex-shrink: 0;
}


@media (max-width: 860px) {
  .wx-main {
    width: min(100% - 1rem, 1380px);
  }

  .wx-header {
    padding: 0.9rem 0.8rem 0.8rem;
  }

  .overlay-content {
    width: min(100%, 820px);
  }

  .primary-grid-inner {
    grid-template-columns: 1fr;
  }

  .split-layout {
    flex-direction: column;
  }

  .map-shell {
    flex: 1 1 auto !important;
    min-height: 300px;
  }

  .wx-nav {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    flex-wrap: nowrap;
    scrollbar-width: none;
  }
  .wx-nav::-webkit-scrollbar {
    display: none;
  }
}

@media (max-width: 640px) {
  .wx-header-main {
    align-items: stretch;
  }

  .wx-header h1 {
    font-size: 1.25rem;
  }

  .dashboard-grid,
  .panel-grid,
  .metric-grid,
  .settings-grid,
  .status-grid {
    grid-template-columns: 1fr;
  }

  .wx-main {
    width: calc(100% - 0.75rem);
    padding-top: 0.8rem;
  }

  .btn-scroll-top {
    right: 0.8rem;
    bottom: 0.8rem;
  }

  .modal-content {
    width: calc(100% - 1rem);
    max-width: none;
    margin: 0.5rem;
  }

  .overlay-content {
    width: calc(100% - 1rem);
    max-width: none;
  }

  .home-status-bar {
    flex-direction: column;
    gap: 0.5rem;
  }

  .home-dash-grid {
    grid-template-columns: 1fr;
  }

  .wx-controls {
    flex-direction: column;
    align-items: stretch;
  }

  .filter-profiles-bar {
    flex-wrap: wrap;
  }

  .settings-grid {
    flex-direction: column;
  }

  .forecast-summary-bar {
    flex-wrap: wrap;
  }

  .table-shell {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  .wx-nav-link, .nav-chip {
    padding: 0.35rem 0.6rem;
    font-size: 0.82rem;
    min-height: 1.8rem;
  }
}

/* ─── Filter Profiles ─────────────────────────────────────────────────────── */
.filter-profiles-bar { display:inline-flex; gap:0.4rem; align-items:center; }
.filter-profile-select { padding:0.35rem 0.5rem; border-radius:0.5rem; border:1px solid var(--border); background:var(--card); color:var(--text); font-size:0.82rem; }

@media (max-width: 420px) {
  .wx-header h1 {
    font-size: 1.1rem;
  }
  .wx-version {
    display: none;
  }
  .wx-main {
    width: calc(100% - 0.5rem);
    padding: 0.6rem 0 1rem;
  }
  .section-card, .settings-panel, .table-shell {
    padding: 0.7rem 0.8rem;
  }
}

/* Telestrator controls */
.telestrator-controls {
  margin-top: 0.5rem;
}
.telestrator-btn {
  background: var(--card, #fff);
  color: var(--text, #333);
  cursor: pointer;
}
.telestrator-btn:hover {
  background: var(--accent, #b388ff);
  color: #0a0815;
}

/* ──────────────────────────────────────────────────────────────────────
 * Home dashboard
 * ──────────────────────────────────────────────────────────────────── */

/* Home dashboard density. The home page has 6 sections vertically (banner,
 * headlines, stats, 3-map row, snapshot, modules). On a 1080p display the
 * old gap/padding pushed Modules below the fold. Tightening these by
 * ~30-40% lets the whole dashboard sit in one viewport at desktop and
 * reduces tablet scrolling to a minimum. */
.home-main { display: flex; flex-direction: column; gap: 0.7rem; }

.home-section {
  background: linear-gradient(180deg, var(--card), var(--card-soft));
  border: 1px solid var(--border);
  border-radius: 0.85rem;
  padding: 0.7rem 0.95rem 0.85rem;
  box-shadow: var(--shadow);
}

.home-section-head {
  display: flex;
  flex-wrap: wrap;   /* controls drop under the title when they don't fit (Station Trends on a phone) */
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem 1rem;
  margin-bottom: 0.5rem;
}
.home-section-head > .wx-controls { max-width: 100%; }
.home-section-head > .wx-controls select { max-width: 100%; }
.home-section-head h2 {
  margin: 0;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  color: var(--text);
}
.home-section-link {
  color: var(--accent);
  font-size: 0.82rem;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 0.15s ease;
}
.home-section-link:hover { border-bottom-color: var(--accent); }

/* ── Threat banner ──────────────────────────────────────────────────── */
.home-threat-banner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.7rem 1rem;
  border-radius: 0.85rem;
  color: #fff;
  background: linear-gradient(135deg, #b10222 0%, #ff2b5a 60%, #ff7a9a 100%);
  border: 1px solid #ff5572;
  box-shadow: 0 0 0 1px rgba(255, 43, 90, 0.35) inset, 0 20px 50px rgba(255, 43, 90, 0.3);
}
.home-threat-banner.hidden { display: none; }

/* "At Home" local-impact strip — visually distinct from national headlines
   so a single Polk SPS doesn't get mistaken for one more entry in a long
   list during a multi-region outbreak. Cyan accent rather than red so it
   reads as informational priority, not threat-level alarm (the threat
   banner above already owns that semantic). */
.home-local {
  border-left: 4px solid #38bdf8;
  background: rgba(56, 189, 248, 0.06);
  padding: 0.6rem 0.9rem 0.9rem;
  border-radius: 0 0.6rem 0.6rem 0;
}
.home-local.hidden { display: none; }
.home-local .home-section-head h2 {
  color: #38bdf8;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.home-local-pin   { font-size: 1.1em; line-height: 1; }
.home-local-count { font-size: 0.75em; color: #94a3b8; font-weight: 500; }

.home-threat-banner--pulse {
  animation: home-threat-pulse 1.1s ease-in-out infinite;
}
@keyframes home-threat-pulse {
  0%, 100% { box-shadow: 0 0 0 1px rgba(255, 43, 90, 0.35) inset, 0 0 30px rgba(255, 43, 90, 0.45); }
  50%      { box-shadow: 0 0 0 2px rgba(255, 43, 90, 0.65) inset, 0 0 60px rgba(255, 43, 90, 0.75); }
}
@media (prefers-reduced-motion: reduce) {
  .home-threat-banner--pulse { animation: none; }
}

.home-threat-icon {
  font-size: 1.9rem;
  line-height: 1;
  filter: drop-shadow(0 0 10px rgba(255, 255, 255, 0.55));
}
.home-threat-body { flex: 1 1 auto; min-width: 0; }
.home-threat-title {
  font-weight: 800;
  letter-spacing: 0.1em;
  font-size: 0.9rem;
  text-transform: uppercase;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6);
}
.home-threat-summary {
  font-size: 1rem;
  margin-top: 0.15rem;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.45);
}
.home-threat-cta {
  flex: 0 0 auto;
  padding: 0.55rem 0.9rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.35);
  color: #fff;
  text-decoration: none;
  font-weight: 600;
  border: 1px solid rgba(255, 255, 255, 0.4);
}
.home-threat-cta:hover { background: rgba(0, 0, 0, 0.55); }

/* ── Headline strip ─────────────────────────────────────────────────── */
.home-headlines {
  display: grid;
  /* Was minmax(19rem, ...) — 4 fit on a 1366 tablet. Tightening to 15rem
   * lets ~5 fit on a 1080p, ~6 on 1440p, so during multi-warning events
   * the strip doesn't wrap to a 2nd row and push everything else down. */
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 0.55rem;
}

.home-headline-card {
  --event-color: var(--accent);
  position: relative;
  display: block;
  padding: 0.55rem 0.75rem 0.55rem 0.9rem;
  border-radius: 0.65rem;
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--event-color) 16%, var(--card) 84%) 0%,
    var(--card-soft) 60%
  );
  border: 1px solid var(--border);
  color: var(--text);
  text-decoration: none;
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
  overflow: hidden;
}
.home-headline-card:hover {
  transform: translateY(-2px);
  border-color: var(--event-color);
  box-shadow: 0 0 22px -6px var(--event-color);
}
.home-headline-stripe {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 4px;
  background: var(--event-color);
  box-shadow: 0 0 14px var(--event-color);
}
.home-headline-head {
  display: flex;
  gap: 0.5rem;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
}
.home-headline-event {
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--text);
}
.home-headline-tags { display: flex; gap: 0.25rem; flex-wrap: wrap; }
.home-headline-area {
  margin-top: 0.2rem;
  color: var(--muted);
  font-size: 0.72rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.home-headline-exp {
  margin-top: 0.15rem;
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 0.65rem;
  color: var(--muted);
}

/* ── Stats row ──────────────────────────────────────────────────────── */
.home-stats-row {
  display: grid;
  /* Was minmax(11rem, ...); tightened so all 6 stat tiles sit in one row
   * on a 1080p display (~120px per tile). On narrower viewports auto-fit
   * still wraps gracefully. */
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
  gap: 0.5rem;
}
.home-stat-tile {
  background: linear-gradient(180deg, var(--card), var(--card-soft));
  border: 1px solid var(--border);
  border-radius: 0.7rem;
  padding: 0.5rem 0.7rem 0.55rem;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  align-items: flex-start;
  position: relative;
  overflow: hidden;
}
.home-stat-tile::after {
  content: "";
  position: absolute;
  right: -30%;
  top: -40%;
  width: 120%;
  height: 120%;
  background: radial-gradient(circle, rgba(179, 136, 255, 0.14) 0%, transparent 55%);
  pointer-events: none;
}
.home-stat-glyph {
  font-size: 1rem;
  line-height: 1;
  opacity: 0.85;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
/* SVG glyphs picked up the surrounding accent color via currentColor so
 * each tile's icon tints to match its severity hue. */
.home-stat-tile[data-stat="alerts"]    .home-stat-glyph svg { color: var(--danger); }
.home-stat-tile[data-stat="spc"]       .home-stat-glyph svg { color: var(--warn); }
.home-stat-tile[data-stat="lsr"]       .home-stat-glyph svg { color: var(--info); }
.home-stat-tile[data-stat="geo"]       .home-stat-glyph svg { color: var(--accent-2); }
.home-stat-tile[data-stat="heartbeat"] .home-stat-glyph svg { color: var(--success); }

/* ─── Quiet-day empty state on home ─── */
.home-quiet-state {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--muted);
}
.home-quiet-glyph { color: var(--success); margin-bottom: 0.4rem; opacity: 0.7; }
/* "Active alerts exist but scope hides them" — warn color so the
 * operator clocks that something IS happening even if no card paints. */
.home-quiet-glyph--filtered { color: var(--warn); }
.home-quiet-headline { color: var(--text); font-size: var(--text-lg); font-weight: 600; }
.home-quiet-sub      { font-size: var(--text-sm); margin-top: 0.25rem; }
.home-stat-number {
  /* Was 1.9rem — too large for 6-up density. 1.4rem still reads at a
   * glance from across the room while leaving room for the caption. */
  font-size: 1.4rem;
  font-weight: 800;
  line-height: 1.05;
  color: var(--accent);
  text-shadow: 0 0 18px rgba(179, 136, 255, 0.5);
}
.home-stat-tile[data-stat="alerts"] .home-stat-number { color: var(--danger); text-shadow: 0 0 18px rgba(255, 43, 90, 0.55); }
.home-stat-tile[data-stat="spc"]    .home-stat-number { color: var(--warn);   text-shadow: 0 0 18px rgba(255, 179, 0, 0.45); }
.home-stat-tile[data-stat="lsr"]    .home-stat-number { color: var(--info);   text-shadow: 0 0 18px rgba(56, 189, 248, 0.45); }
.home-stat-tile[data-stat="geo"]    .home-stat-number { color: var(--accent-2); text-shadow: 0 0 18px rgba(56, 255, 240, 0.45); }
.home-stat-tile[data-stat="heartbeat"] .home-stat-number { color: var(--success); text-shadow: 0 0 16px rgba(61, 255, 160, 0.4); }
.home-stat-tile[data-stat="time"]   .home-stat-number { color: var(--text); text-shadow: none; font-size: 0.82rem; font-weight: 600; }

.home-stat-number--time {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}
.home-stat-number--time span { line-height: 1.05; }

#metric-heartbeat[data-status="error"]   { color: var(--danger); text-shadow: 0 0 16px rgba(255, 43, 90, 0.5); }
#metric-heartbeat[data-status="stale"]   { color: var(--warn);   text-shadow: 0 0 16px rgba(255, 179, 0, 0.4); }
#metric-heartbeat[data-status="unknown"] { color: var(--muted);  text-shadow: none; }

.home-stat-caption {
  color: var(--muted);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* ── Home Snapshot tiles ────────────────────────────────────────────── */
/* The Home Snapshot has 5 tiles (alerts / SPC tier / LSR / forecast /
 * station). Old layout: 4-up grid, so the 5th wrapped to a half-empty
 * second row that wasted ~70px of vertical space and looked unfinished.
 * Now 5-up at desktop so it stays one row; tablet collapses to 3-up. */
.home-snapshot-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0.55rem;
}
@media (max-width: 1280px) {
  .home-snapshot-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .home-snapshot-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 480px) {
  .home-snapshot-grid { grid-template-columns: 1fr; }
}
.home-snapshot-tile {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.7rem;
  border-radius: 0.6rem;
  border: 1px solid var(--border);
  background: linear-gradient(135deg, rgba(28, 24, 56, 0.55), rgba(15, 10, 35, 0.85));
  text-decoration: none;
  color: var(--text);
  transition: border-color 120ms, transform 120ms, background 120ms;
}
.home-snapshot-tile:hover {
  border-color: rgba(56, 189, 248, 0.5);
  transform: translateY(-1px);
}
.home-snapshot-tile .snap-glyph {
  font-size: 1.3rem;
  line-height: 1;
  flex: 0 0 auto;
}
.home-snapshot-tile .snap-body { min-width: 0; flex: 1 1 auto; }
.home-snapshot-tile .snap-headline {
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1.15;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.home-snapshot-tile .snap-caption {
  font-size: 0.65rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Severity-coded outline so the tile reads "everything's fine" / "watch
 * out" without you having to read the headline first. */
.home-snapshot-tile.snap-tile--ok    { border-color: rgba(34, 197, 94, 0.4); }
.home-snapshot-tile.snap-tile--warn  { border-color: rgba(249, 115, 22, 0.55); background: linear-gradient(135deg, rgba(249, 115, 22, 0.12), rgba(15, 10, 35, 0.85)); }
.home-snapshot-tile.snap-tile--alarm { border-color: rgba(220, 38, 38, 0.7);  background: linear-gradient(135deg, rgba(220, 38, 38, 0.18), rgba(15, 10, 35, 0.85)); }

/* ── 3-column mini-map row (SPC | Local Alerts | Tropical) ─────────── */
.home-map-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.7rem;
}
@media (max-width: 1100px) {
  /* On narrower windows, drop the tropical column under the other two so
   * the operationally important pair (outlook + alerts) stay side by side. */
  .home-map-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .home-map-row > #home-tropical-wrap { grid-column: 1 / -1; }
}
@media (max-width: 720px) {
  .home-map-row { grid-template-columns: 1fr; }
  .home-map-row > #home-tropical-wrap { grid-column: auto; }
}
.home-mini { display: flex; flex-direction: column; }
.home-mini-map {
  /* Was 320px — half the vertical budget of a 1080p home page went to
   * three side-by-side preview maps. They're navigation hints, not the
   * working map. Drop to 240px so SPC/Local/Tropical still convey shape
   * but don't crowd out the snapshot row below. */
  height: 240px;
  border-radius: 0.6rem;
  border: 1px solid var(--border);
  overflow: hidden;
  background: #0a0a14;
}
@media (max-width: 1280px) {
  .home-mini-map { height: 220px; }
}
@media (max-width: 720px) {
  .home-mini-map { height: 200px; }
}

/* Legacy alias kept so any other consumer of .home-spc-map still works */
.home-spc-map {
  height: 240px;
  border-radius: 0.6rem;
  border: 1px solid var(--border);
  overflow: hidden;
  background: #0a0a14;
}
.home-spc-legend {
  display: flex;
  gap: 0.55rem;
  flex-wrap: wrap;
  padding-top: 0.55rem;
  font-size: 0.78rem;
  color: var(--muted);
}
.home-spc-legend-chip {
  display: inline-flex;
  gap: 0.35rem;
  align-items: center;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  background: rgba(28, 24, 56, 0.75);
  border: 1px solid var(--border);
}
.home-spc-legend-chip i {
  display: inline-block;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 2px;
  box-shadow: 0 0 6px currentColor;
}

@media (max-width: 720px) {
  .home-stats-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .home-threat-banner { flex-wrap: wrap; }
  .home-threat-cta { width: 100%; text-align: center; }
}

/* ─── Support Request (Praetor intake; assets/js/support.js) ─────────────── */

.wx-support-link {
  font: inherit;
  font-size: 0.88rem;
  background: transparent;
  cursor: pointer;
}
.wx-support-link:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.wx-support-dialog {
  width: min(34rem, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--bg);
  color: var(--text);
  box-shadow: 0 18px 50px rgba(2, 1, 12, 0.55);
}
.wx-support-dialog::backdrop {
  background: rgba(2, 1, 12, 0.6);
}

.wx-support-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.45rem;
  padding: 1.1rem 1.2rem 1rem;
}
.wx-support-form h2 {
  margin: 0;
  font-size: var(--text-lg);
}
.wx-support-note {
  margin: 0 0 0.3rem;
  font-size: var(--text-sm);
  color: var(--muted);
}
.wx-support-form label {
  font-size: var(--text-sm);
  color: var(--muted);
}
.wx-support-form input,
.wx-support-form textarea,
.wx-support-form select {
  width: 100%;
  min-width: 0;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 0.55rem;
  background: var(--bg-alt);
  color: var(--text);
  font: inherit;
  font-size: var(--text-base);
}
.wx-support-form textarea {
  resize: vertical;
}
.wx-support-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 1fr);
  gap: 0.5rem;
  align-items: center;
}
.wx-support-status {
  min-height: 1.2rem;
  margin: 0.2rem 0 0;
  font-size: var(--text-sm);
}
.wx-support-status[data-kind="ok"] { color: var(--success); }
.wx-support-status[data-kind="error"] { color: var(--danger-strong); }
.wx-support-status[data-kind="info"] { color: var(--muted); }
.wx-support-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

@media (max-width: 520px) {
  .wx-support-row {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ─── Site footer: public-site disclaimer (wx_render_footer) ─────────────── */
/* Footer (page.php): disclaimers on the left, © and version on the right;
 * the version moved here from the header with the rail (WXAPI-110). */
.wx-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: 0.5rem 1.5rem;
  width: calc(100% - 1.4rem);
  max-width: 2200px;
  box-sizing: border-box;
  margin: 1.5rem auto 0;
  padding: 0.9rem 0.25rem calc(1.1rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--border);
  font-size: var(--text-sm);
  color: var(--muted);
}
.wx-footer p {
  margin: 0;
}
.wx-footer-text {
  display: grid;
  gap: 0.25rem;
  max-width: 62rem;
}
.wx-footer-meta {
  display: flex;
  gap: 0.9rem;
  white-space: nowrap;
}
.wx-footer-version {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
}
.wx-footer a {
  color: var(--accent);
}

/* ─── WxUI.form / WxUI.secret (in-page replacements for browser dialogs) ── */
.wx-form-dialog,
.wx-secret-dialog { max-width: 28rem; }
.wx-form-row {
  display: grid;
  gap: 0.25rem;
  margin-bottom: 0.6rem;
}
.wx-form-row label {
  font-size: var(--text-sm);
  color: var(--muted);
}
.wx-form-row--check {
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 0.5rem;
}
.wx-form-dialog input:not([type="checkbox"]),
.wx-form-dialog select,
.wx-form-dialog textarea,
.wx-secret-value {
  width: 100%;
  min-width: 0;
  padding: 0.5rem 0.6rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--card-soft);
  color: var(--text);
  font: inherit;
}
.wx-form-hint {
  color: var(--muted);
  font-size: var(--text-xs);
}
.wx-form-error {
  min-height: 1rem;
  margin: 0.2rem 0 0;
  color: var(--danger-strong);
  font-size: var(--text-sm);
}
.wx-secret-row {
  display: flex;
  gap: 0.5rem;
}
.wx-secret-value {
  flex: 1;
  font-family: "Consolas", "Courier New", monospace;
  letter-spacing: 0.04em;
}

/* ─── Settings → Users: per-user module access checklist ─────────────── */
.wx-access-details {
  margin-top: 0.4rem;
}
.wx-access-details summary {
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--muted);
}
.wx-access-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.25rem 0.75rem;
  margin-top: 0.4rem;
}
.wx-access-item {
  font-size: var(--text-sm);
}

/* Support form honeypot: off-screen for people, still in the DOM for bots. */
.wx-support-hp {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* NWS Damage Survey popups (maproom-providers.js, lsr.damage_surveys overlay). */
.wx-dat-kind {
  font-size: 0.72rem;
  color: var(--muted);
}
.wx-dat-note {
  margin-top: 0.35rem;
  max-width: 20rem;
  max-height: 9rem;
  overflow-y: auto;
  font-size: 0.8rem;
}

/* WXCON badge in the header (page.php, assets/js/wxcon.js). Level colors are
 * fixed, not theme tokens: they mean the same thing in dark and light. */
.wx-wxcon {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  min-height: 44px;
  box-sizing: border-box;
  padding: 0.25rem 0.75rem 0.25rem 0.3rem;
  border-radius: 0.7rem;
  border: 1px solid var(--wxcon-color);
  background: color-mix(in srgb, var(--wxcon-color) 12%, transparent);
  color: var(--text);
  text-decoration: none;
  /* Takes the room between the clock and the links, so the reason shows in
   * full when it fits (ellipsis only when it doesn't). */
  flex: 1 1 12rem;
  min-width: 0;
}
.wx-wxcon ~ .wx-header-spacer { flex: 0 0 0; }
.wx-wxcon:hover { background: color-mix(in srgb, var(--wxcon-color) 20%, transparent); }
.wx-wxcon:focus-visible { outline: 2px solid var(--wxcon-color); outline-offset: 2px; }
.wx-wxcon--1 { --wxcon-color: #3dffa0; --wxcon-ink: #06231a; }   /* Clear */
.wx-wxcon--2 { --wxcon-color: #ffe14d; --wxcon-ink: #2b2400; }   /* Active */
.wx-wxcon--3 { --wxcon-color: #ff9f1a; --wxcon-ink: #2b1700; }   /* Elevated */
.wx-wxcon--4 { --wxcon-color: #ff2b5a; --wxcon-ink: #ffffff; box-shadow: 0 0 18px rgba(255, 43, 90, 0.35); }   /* High */
.wx-wxcon-num {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 0.5rem;
  background: var(--wxcon-color);
  color: var(--wxcon-ink);
  font-weight: 800;
  font-size: 1.05rem;
}
.wx-wxcon-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.wx-wxcon-label { font-size: 0.72rem; font-weight: 800; letter-spacing: 0.06em; }
.wx-wxcon-reason { font-size: 0.75rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wx-wxcon--changed { animation: wx-wxcon-pulse 1.4s ease-out 2; }
@keyframes wx-wxcon-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--wxcon-color) 70%, transparent); }
  100% { box-shadow: 0 0 0 14px transparent; }
}
@media (prefers-reduced-motion: reduce) { .wx-wxcon--changed { animation: none; } }
@media (max-width: 720px) { .wx-wxcon-reason { display: none; } }
/* Level 4 doesn't let up: a stronger fill, full-strength reason text, and a
 * steady glow pulse (it replaces the one-off change pulse). */
.wx-wxcon--4 { background: color-mix(in srgb, var(--wxcon-color) 26%, transparent); }
.wx-wxcon--4 .wx-wxcon-reason { color: var(--text); }
@media (prefers-reduced-motion: no-preference) {
  .wx-wxcon--4,
  .wx-wxcon--4.wx-wxcon--changed { animation: wx-wxcon-alarm 1.6s ease-in-out infinite alternate; }
}
@keyframes wx-wxcon-alarm {
  from { box-shadow: 0 0 4px rgba(255, 43, 90, 0.35); }
  to   { box-shadow: 0 0 24px rgba(255, 43, 90, 0.9); }
}

/* ─── Shell: left rail + body column (WXAPI-110, app/common/rail.php) ───
 * The rail is the same on every page and at every WXCON level; only badges
 * change. Wide screens: a sticky column under the sticky header (rail.js
 * keeps --wx-header-h current). Under 900px: a strip under the header that
 * scrolls sideways and scrolls away with the page. Theme colors come only
 * from the vars api.js sets (house rule 11); the warm tones are fixed, like
 * the WXCON level colors. */
.wx-shell {
  display: flex;
  align-items: flex-start;
}
.wx-shell-body {
  flex: 1 1 auto;
  min-width: 0;
}
.wx-rail {
  position: sticky;
  top: var(--wx-header-h, 4.5rem);
  z-index: 15;
  flex: 0 0 5.75rem;
  width: 5.75rem;
  height: calc(100vh - var(--wx-header-h, 4.5rem));
  height: calc(100dvh - var(--wx-header-h, 4.5rem));
  box-sizing: border-box;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.6rem 0.45rem calc(0.6rem + env(safe-area-inset-bottom));
  padding-left: max(0.45rem, env(safe-area-inset-left));
  background: color-mix(in srgb, var(--card) 70%, transparent);
  border-right: 1px solid var(--border);
}
.wx-rail-sep {
  flex: 0 0 1px;
  height: 1px;
  margin: 0.35rem 0.6rem;
  background: var(--border);
}
.wx-rail-item {
  --rail-tone: var(--accent);
  --rail-ink: #ffffff;
  position: relative;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  min-height: 3.6rem;
  padding: 0.45rem 0.2rem;
  box-sizing: border-box;
  border-radius: 0.75rem;
  border: 1px solid transparent;
  color: color-mix(in srgb, var(--text) 78%, var(--card));
  font-size: 0.7rem;
  line-height: 1.15;
  text-align: center;
  text-decoration: none;
}
.wx-rail-icon {
  flex: 0 0 auto;
  color: var(--muted);
}
.wx-rail-item:hover {
  background: color-mix(in srgb, var(--text) 7%, transparent);
  color: var(--text);
}
.wx-rail-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.wx-rail-item[aria-current="page"] {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--text);
  font-weight: 700;
}
.wx-rail-item[aria-current="page"] .wx-rail-icon { color: var(--accent); }
.wx-rail-item.is-warm {
  background: color-mix(in srgb, var(--rail-tone) 13%, transparent);
  border-color: color-mix(in srgb, var(--rail-tone) 55%, transparent);
  color: var(--text);
  font-weight: 700;
}
.wx-rail-item.is-warm .wx-rail-icon { color: var(--rail-tone); }
.wx-rail-item.is-warm[aria-current="page"] { box-shadow: inset 0 0 0 1px var(--rail-tone); }
.wx-rail-badge {
  position: absolute;
  top: 0.2rem;
  right: 0.3rem;
  min-width: 1.1rem;
  box-sizing: border-box;
  padding: 0 0.3rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text) 18%, var(--card));
  color: var(--text);
  font-size: 0.62rem;
  font-weight: 800;
  line-height: 1.1rem;
  text-align: center;
}
.wx-rail-badge[hidden] { display: none; }
.wx-rail-item.is-warm .wx-rail-badge {
  background: var(--rail-tone);
  color: var(--rail-ink);
}
.wx-rail-item--alerts   { --rail-tone: #ff4d6d; --rail-ink: #2a0610; }
.wx-rail-item--spc      { --rail-tone: #ffb300; --rail-ink: #2b1a00; }
.wx-rail-item--tropical { --rail-tone: #ff7a45; --rail-ink: #2a0e02; }
.wx-rail-item--lsr      { --rail-tone: #60a5fa; --rail-ink: #04122a; }

/* Tabs for a page family under the header (SPC | SPC Logs, Resources |
 * Placefiles): the child pages have no rail item of their own. */
.wx-subnav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  width: calc(100% - 1.4rem);
  max-width: 2200px;
  margin: 0.7rem auto 0;
}
.wx-subnav-tab {
  display: inline-flex;
  align-items: center;
  min-height: 2.2rem;
  box-sizing: border-box;
  padding: 0.3rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: var(--text-sm);
  font-weight: 600;
  text-decoration: none;
}
.wx-subnav-tab:hover {
  color: var(--text);
  background: color-mix(in srgb, var(--text) 6%, transparent);
}
.wx-subnav-tab[aria-current="page"] {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
}

/* Site header: one row, the same on every page (page.php, mockup board 1):
 * brand, clock, WXCON badge | links, theme toggle. */
.wx-header-main {
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: 0.5rem 1.1rem;
}
.wx-header-spacer { flex: 1 1 0; }
.wx-header-links {
  display: flex;
  align-items: center;
  gap: 0.15rem;
}
.wx-clock {
  display: flex;
  flex-direction: column;
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 0.74rem;
  line-height: 1.3;
  color: var(--muted);
  white-space: nowrap;
}
.wx-clock-local { color: var(--text); }
.wx-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--text);
  text-decoration: none;
}
.wx-brand-name {
  font-size: 1.3rem;
  font-weight: 800;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.wx-logo {
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  border-radius: 0.5rem;
}
.wx-logo--placeholder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  background: color-mix(in srgb, var(--accent) 20%, var(--card));
  color: var(--accent);
  font-size: 0.78rem;
  font-weight: 800;
}
/* Page bar: the page's title, counters / last-updated stamp, status pills. */
.wx-pagebar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  width: calc(100% - 1.4rem);
  max-width: 2200px;
  margin: 0.8rem auto 0;
}
.wx-pagebar-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2rem 1rem;
  min-width: 0;
}
.wx-pagebar h1 {
  margin: 0;
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: 0.01em;
}
.wx-pagebar-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.9rem;
  color: var(--muted);
  font-size: 0.8rem;
}
.wx-pagebar-meta .timestamp-stack {
  flex-direction: row;
  gap: 0.4em;
}
.wx-pagebar-meta .timestamp-date { font-weight: 500; }
.wx-pagebar-meta .timestamp-time { font-size: inherit; }
.wx-pagebar-status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.82rem;
}

.wx-visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Light mode: the chrome (header, rail, tabs, footer) sits on the light page
 * background, but api.js pins the saved theme colors, which are dark on prod,
 * to :root (house rule 11). So these surfaces take the light palette back for
 * their own subtree, and restate `color` so it inherits from the new --text.
 * Cards keep the saved colors. */
[data-theme="light"] .wx-header,
[data-theme="light"] .wx-rail,
[data-theme="light"] .wx-subnav,
[data-theme="light"] .wx-pagebar,
[data-theme="light"] .wx-footer {
  --card: #ffffff;
  --border: #c5d5e8;
  --text: #0e1e2e;
  --muted: #4a6278;
  --accent: #9a7a0c;
  color: var(--text);
}
[data-theme="light"] .wx-rail { background: rgba(255, 255, 255, 0.72); }

@media (max-width: 899px) {
  .wx-shell { display: block; }
  .wx-rail {
    position: static;
    width: auto;
    height: auto;
    flex-direction: row;
    gap: 0.15rem;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 0.35rem max(0.5rem, env(safe-area-inset-right)) 0.35rem max(0.5rem, env(safe-area-inset-left));
    border-right: 0;
    border-bottom: 1px solid var(--border);
    scrollbar-width: none;
  }
  .wx-rail::-webkit-scrollbar { display: none; }
  .wx-rail-item {
    flex: 0 0 4.4rem;
    min-height: 3.3rem;
  }
  .wx-rail-sep {
    width: 1px;
    height: auto;
    margin: 0.5rem 0.2rem;
  }
}
/* Tablets: the clock goes first. Phones: brand and links on one row, the
 * WXCON badge and the theme toggle on the next. */
@media (max-width: 1023px) {
  .wx-clock { display: none; }
}
@media (max-width: 720px) {
  .wx-header-main {
    align-items: center;
    gap: 0.45rem 0.5rem;
  }
  .wx-wxcon {
    order: 10;
    flex: 1 1 calc(100% - 3.2rem);
    min-width: 0;
    max-width: none;
    min-height: 40px;
  }
  .wx-theme-toggle { order: 11; }
  .wx-wxcon-reason { display: block; } /* room for it now the badge is full width */
  .wx-header-links .wx-nav-link {
    padding: 0.3rem 0.45rem;
    font-size: 0.82rem;
  }
  .wx-brand-name { font-size: 1.12rem; }
  .wx-logo { width: 1.75rem; height: 1.75rem; }
  .wx-pagebar h1 { font-size: 1.05rem; }
}
@media (max-width: 340px) {
  .wx-brand-name { display: none; }
}

/* ─── Overview headlines (WXAPI-103, assets/js/headlines.js) ───────────
 * The WXCON area's alerts: Tornado Emergency banner, one box per warning
 * type, event headlines, advisories strip. Colors come from
 * productColors.json through data-event-color → --event-color; tier chips
 * use the severityTags colors, fixed like the WXCON level colors. */
.wx-headlines {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  margin-bottom: 1rem;
}
.wx-headlines-quiet {
  margin: 0;
  padding: 0.7rem 0.9rem;
  border-radius: 0.75rem;
  border: 1px dashed var(--border);
  color: var(--muted);
  font-size: 0.9rem;
}

/* Tornado Emergency: solid red, the strongest thing on the page. The WXCON 4
 * banner (.wx-alarm, below) is the only other solid-filled block. */
.wx-tore {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1.1rem;
  padding: 1rem 1.15rem;
  border-radius: 0.9rem;
  background: #b91c1c;
  border: 3px solid #ef4444;
  box-shadow: 0 0 34px rgba(239, 68, 68, 0.55);
  color: #ffffff;
  text-decoration: none;
}
.wx-tore:hover { background: #a51818; }
.wx-tore-body {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  flex: 1 1 22rem;
  min-width: 0;
}
.wx-tore-title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  font-size: 1.6rem;
  font-weight: 900;
  letter-spacing: 0.04em;
}
.wx-tore-chip {
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: #ffffff;
  color: #b91c1c;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.02em;
}
.wx-tore-where { font-size: 1.05rem; font-weight: 700; }
.wx-tore-say { font-size: 0.9rem; }
.wx-tore-until {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 0.9rem;
  font-weight: 700;
  white-space: nowrap;
}
@media (prefers-reduced-motion: no-preference) {
  .wx-tore { animation: wx-tore-glow 1.6s ease-in-out infinite alternate; }
}
@keyframes wx-tore-glow {
  from { box-shadow: 0 0 16px rgba(239, 68, 68, 0.4); }
  to   { box-shadow: 0 0 42px rgba(239, 68, 68, 0.8); }
}

/* WXCON 4 banner (headlines.js alarm()): the level, the top threat, what to
 * do, and links. Solid, so it reads the same in light and dark mode. */
.wx-alarm {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.8rem 1.1rem;
  padding: 0.95rem 1.1rem;
  border-radius: 0.9rem;
  background: linear-gradient(120deg, #6e0820 0%, #a50f36 55%, #c8173f 100%);
  border: 2px solid #ff2b5a;
  box-shadow: 0 0 28px rgba(255, 43, 90, 0.5);
  color: #ffffff;
}
.wx-alarm-num {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.4rem;
  height: 3.4rem;
  border-radius: 0.7rem;
  background: #ffffff;
  color: #a50f36;
  font-size: 2.2rem;
  font-weight: 900;
  line-height: 1;
}
.wx-alarm-body {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  flex: 1 1 24rem;
  min-width: 0;
}
.wx-alarm-kicker { font-size: 0.78rem; font-weight: 800; letter-spacing: 0.1em; opacity: 0.9; }
.wx-alarm-what { font-size: 1.5rem; font-weight: 900; line-height: 1.2; overflow-wrap: anywhere; }
.wx-alarm-say { font-size: 1rem; font-weight: 600; }
.wx-alarm-also { font-size: 0.85rem; opacity: 0.9; }
/* Tropical tornado risk inside the WXCON 4 banner (headlines.php wx_headline_alarm). */
.wx-alarm-tor {
  align-self: flex-start;
  margin-top: 0.15rem;
  padding: 0.2rem 0.55rem;
  border-radius: 0.4rem;
  background: #ffe14d;
  color: #2b1d00;
  font-size: 0.88rem;
  font-weight: 800;
}
.wx-alarm-links { display: flex; flex-wrap: wrap; gap: 0.45rem; }
.wx-alarm-link {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 0.3rem 0.85rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.55);
  color: #ffffff;
  font-weight: 700;
  font-size: 0.88rem;
  text-decoration: none;
  white-space: nowrap;
}
.wx-alarm-link:hover { background: rgba(255, 255, 255, 0.26); }
.wx-alarm-link:focus-visible { outline: 2px solid #ffffff; outline-offset: 2px; }
@media (prefers-reduced-motion: no-preference) {
  .wx-alarm { animation: wx-alarm-glow 1.6s ease-in-out infinite alternate; }
}
@keyframes wx-alarm-glow {
  from { box-shadow: 0 0 12px rgba(255, 43, 90, 0.35); }
  to   { box-shadow: 0 0 40px rgba(255, 43, 90, 0.85); }
}
@media (max-width: 720px) {
  .wx-alarm { padding: 0.8rem 0.85rem; gap: 0.6rem 0.8rem; }
  .wx-alarm-num { width: 2.7rem; height: 2.7rem; font-size: 1.7rem; }
  .wx-alarm-body { flex-basis: calc(100% - 4rem); }
  .wx-alarm-what { font-size: 1.2rem; }
  .wx-alarm-say { font-size: 0.92rem; }
}

/* Priority headlines: one box per warning type; the border is the color of
 * its most severe row. */
.wx-prio-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  align-items: start;
  gap: 0.6rem;
}
.wx-prio {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0.6rem 0.7rem;
  border-radius: 0.9rem;
  border: 2px solid var(--event-color, var(--danger));
  background: color-mix(in srgb, var(--event-color, var(--danger)) 10%, var(--card));
}
.wx-prio-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
}
.wx-prio-title {
  margin: 0;
  font-size: 0.88rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: color-mix(in srgb, var(--event-color, var(--danger)) 70%, var(--text));
}
.wx-prio-count { font-size: 0.76rem; color: var(--muted); }
.wx-prio-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  box-sizing: border-box;
  padding: 0.5rem 0.6rem;
  border-radius: 0.55rem;
  border: 1px solid transparent;
  background: color-mix(in srgb, var(--event-color, var(--danger)) 8%, transparent);
  color: var(--text);
  text-decoration: none;
}
.wx-prio-row:hover { background: color-mix(in srgb, var(--event-color, var(--danger)) 16%, transparent); }
.wx-prio-row--pds,
.wx-prio-row--destructive,
.wx-prio-row--observed { background: color-mix(in srgb, var(--event-color, var(--danger)) 20%, transparent); }
.wx-prio-row--emergency {
  background: #7f1d1d;
  border-color: #ef4444;
  color: #ffffff;
}
.wx-prio-where {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 700;
  overflow-wrap: anywhere;
}
.wx-prio-until {
  flex: 0 0 auto;
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 0.76rem;
  color: var(--muted);
  white-space: nowrap;
}
.wx-prio-row--emergency .wx-prio-until { color: #ffffff; }
/* A box whose warnings set WXCON 4 (Hurricane, Storm Surge, Extreme Wind,
 * PDS tornado, destructive storm, flash flood emergency): a solid title bar
 * in its color (lettering from headlines.js inkFor), a heavier border and a
 * glow. */
.wx-prio--critical {
  padding-top: 0;
  overflow: hidden;
  border-width: 3px;
  box-shadow: 0 0 20px color-mix(in srgb, var(--event-color, var(--danger)) 45%, transparent);
  background: color-mix(in srgb, var(--event-color, var(--danger)) 16%, var(--card));
}
.wx-prio--critical .wx-prio-head {
  margin: 0 -0.7rem 0.15rem;
  padding: 0.5rem 0.7rem;
  background: var(--event-color, var(--danger));
}
.wx-prio--critical .wx-prio-title { font-size: 0.98rem; font-weight: 900; color: #ffffff; }
.wx-prio--critical .wx-prio-count { font-weight: 700; color: #ffffff; }

/* Tier chips (productColors.json severityTags). */
.wx-tier {
  flex: 0 0 auto;
  padding: 0.12rem 0.5rem;
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  white-space: nowrap;
}
.wx-tier--emergency { background: #ffffff; color: #7f1d1d; }
.wx-tier--pds,
.wx-tier--considerable { background: #fb7185; color: #2a0610; }
.wx-tier--destructive { background: #f97316; color: #2b1000; }
.wx-tier--observed { background: #ef4444; color: #ffffff; }
.wx-tier--radar,
.wx-tier--base {
  border-color: var(--event-color, var(--danger));
  color: color-mix(in srgb, var(--event-color, var(--danger)) 60%, var(--text));
}

/* Event headlines and advisories: the label above, the cards in an even
 * grid that fills the row (no ragged chip rows). */
.wx-events,
.wx-advisories {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
  align-items: stretch;
  gap: 0.4rem 0.5rem;
  min-width: 0;
}
.wx-events { grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr)); }
.wx-advisories { grid-template-columns: repeat(auto-fill, minmax(min(100%, 21rem), 1fr)); }
.wx-strip-label {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--muted);
}
/* Title and time on the first line, the detail under them. */
.wx-event {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 0.1rem 0.6rem;
  min-width: 0;
  min-height: 44px;
  box-sizing: border-box;
  padding: 0.4rem 0.7rem;
  border-radius: 0.7rem;
  border: 1px solid color-mix(in srgb, var(--event-color) 60%, transparent);
  border-left: 4px solid var(--event-color);
  background: color-mix(in srgb, var(--event-color) 9%, var(--card));
  color: var(--text);
  text-decoration: none;
}
.wx-event.is-pds {
  border-width: 2px 2px 2px 4px;
  box-shadow: 0 0 14px color-mix(in srgb, var(--event-color) 45%, transparent);
}
.wx-event-title { grid-column: 1; grid-row: 1; font-size: 0.88rem; font-weight: 800; }
.wx-event-until { grid-column: 2; grid-row: 1; white-space: nowrap; }
.wx-event-where { grid-column: 1 / -1; font-size: 0.8rem; color: color-mix(in srgb, var(--text) 85%, var(--card)); }
.wx-event-until,
.wx-advisory-until {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 0.72rem;
  color: var(--muted);
}
/* One line: name, counties, time on the right (wraps only when it must). */
.wx-advisory {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.1rem 0.5rem;
  min-width: 0;
  min-height: 44px;
  box-sizing: border-box;
  padding: 0.4rem 0.7rem;
  border-radius: 0.65rem;
  border: 1px solid color-mix(in srgb, var(--event-color) 60%, transparent);
  background: color-mix(in srgb, var(--event-color) 8%, var(--card));
  color: var(--text);
  font-size: 0.82rem;
  text-decoration: none;
}
.wx-advisory-name {
  font-weight: 700;
  color: color-mix(in srgb, var(--event-color) 75%, var(--text));
}
.wx-advisory-until { margin-left: auto; white-space: nowrap; }
/* Mouse and trackpad: tighter rows. Touch keeps the 44 px targets. */
@media (pointer: fine) {
  .wx-prio-row { min-height: 36px; padding: 0.4rem 0.6rem; }
  .wx-event,
  .wx-advisory { min-height: 36px; }
}
.wx-event:hover,
.wx-advisory:hover { background: color-mix(in srgb, var(--event-color) 16%, var(--card)); }
.wx-tore:focus-visible,
.wx-prio-row:focus-visible,
.wx-event:focus-visible,
.wx-advisory:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Labels that sit straight on the page background (light in light mode). */
[data-theme="light"] .wx-strip-label,
[data-theme="light"] .wx-headlines-quiet { color: #4a6278; border-color: #c5d5e8; }

@media (max-width: 720px) {
  .wx-tore-title { font-size: 1.25rem; }
}

/* ─── Overview layouts by level (WXAPI-103 slice 4, index.php) ─────────
 * Levels 2-3 put one map large and full width ("Severe weather now" or
 * "Tropical focus"); the other cards pair up below. */
.home-map-row--focus { grid-template-columns: 1fr; }
.home-map-row--focus > #home-tropical-wrap { grid-column: auto; }
.home-map-row--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.home-map-row--pair > #home-tropical-wrap { grid-column: auto; }
.home-mini-map--large { height: 360px; }
/* Storm reports beside the lead map: the list runs the map's height. */
.home-map-row--lead .ov-reports-list { max-height: 360px; }
@media (max-width: 720px) {
  .home-map-row--pair { grid-template-columns: 1fr; }
  .home-mini-map--large { height: 320px; }
}

.ov-reports-list {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 280px;
  overflow-y: auto;
}
.ov-report {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.6rem;
  padding: 0.45rem 0.6rem;
  border-radius: 0.55rem;
  background: color-mix(in srgb, var(--text) 5%, var(--card));
  font-size: 0.85rem;
}
.ov-report { align-items: center; }
.ov-report > svg { flex: none; }
.ov-report-type { font-weight: 800; color: color-mix(in srgb, var(--event-color, #60a5fa) 80%, var(--text)); }
.ov-report-where { flex: 1 1 10rem; min-width: 0; }
.ov-report-mag { font-weight: 700; }
.ov-report-time {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 0.74rem;
  color: var(--muted);
}

/* Level-change prompt (headlines.js): WXCON level colors, fixed like the badge. */
.wx-level-prompt {
  --prompt: #ffb300;
  --prompt-ink: #2b1a00;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1rem;
  margin-bottom: 0.85rem;
  padding: 0.8rem 1rem;
  border-radius: 0.9rem;
  border: 1px solid var(--prompt);
  background: color-mix(in srgb, var(--prompt) 12%, var(--card));
  box-shadow: 0 0 24px color-mix(in srgb, var(--prompt) 30%, transparent);
  color: var(--text);
}
.wx-level-prompt[hidden] { display: none; }
.wx-level-prompt--1 { --prompt: #3dffa0; --prompt-ink: #06231a; }
.wx-level-prompt--2 { --prompt: #ffe14d; --prompt-ink: #2b2400; }
.wx-level-prompt--3 { --prompt: #ff9f1a; --prompt-ink: #2b1700; }
.wx-level-prompt--4 { --prompt: #ff2b5a; --prompt-ink: #ffffff; }
.wx-level-prompt-head { display: flex; align-items: center; gap: 0.6rem; font-weight: 800; }
.wx-level-prompt-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 0.5rem;
  background: var(--prompt);
  color: var(--prompt-ink);
}
.wx-level-prompt-why { flex: 1 1 18rem; font-size: 0.88rem; color: color-mix(in srgb, var(--text) 85%, var(--card)); }
.wx-level-prompt-actions { display: flex; gap: 0.5rem; }
.wx-level-prompt-go,
.wx-level-prompt-stay {
  min-height: 44px;
  padding: 0.55rem 1rem;
  border-radius: 0.6rem;
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
}
.wx-level-prompt-go { border: 0; background: var(--prompt); color: var(--prompt-ink); font-weight: 800; }
.wx-level-prompt-stay { border: 1px solid color-mix(in srgb, var(--prompt) 50%, transparent); background: transparent; color: var(--text); }

/* Headlines in two columns (headlines.js adds wx-headlines-body--split when
 * there's more than one kind): warnings, then advisories, on the left; the
 * side section (event cards, or the advisories when there are no events)
 * on the right, spanning both rows, so each column stacks on its own and a
 * short warning box leaves no hole. One column under 1100 px, in DOM order:
 * warnings, events, advisories. */
.wx-headlines-body {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  min-width: 0;
}
.wx-headlines-body--split {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  grid-template-rows: auto 1fr;
  align-items: start;
  gap: 0.7rem 1rem;
}
.wx-headlines-body--split > * { grid-column: 1; }
.wx-headlines-body--split > .wx-headlines-side {
  grid-column: 2;
  grid-row: 1 / span 2;
  grid-template-columns: minmax(0, 1fr);
}
.wx-headlines-body--split .wx-prio-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); }
/* Two or more warning boxes beside the side column: two masonry columns, so
 * a third box sits under the shorter one instead of leaving a hole. */
.wx-headlines-body--split .wx-prio-grid--multi {
  display: block;
  column-count: 2;
  column-gap: 0.6rem;
  margin-bottom: -0.6rem;
}
.wx-headlines-body--split .wx-prio-grid--multi > .wx-prio {
  break-inside: avoid;
  margin-bottom: 0.6rem;
}
/* Advisories under the event cards (headlines.js balance(), when that makes
 * the block shorter): the warnings span both rows on the left. */
.wx-headlines-body--adv-right > .wx-prio-grid { grid-row: 1 / span 2; }
.wx-headlines-body--adv-right > .wx-events.wx-headlines-side { grid-row: 1; }
.wx-headlines-body--adv-right > .wx-advisories { grid-column: 2; grid-row: 2; }
/* Advisories across the full width under both columns (balance(), when that
 * is the shortest): warnings and events share the first row. */
.wx-headlines-body--adv-full { grid-template-rows: auto auto; }
.wx-headlines-body--adv-full > .wx-events.wx-headlines-side { grid-row: 1; }
.wx-headlines-body--adv-full > .wx-advisories {
  grid-column: 1 / -1;
  grid-row: 2;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr));
}
@media (max-width: 1100px) {
  .wx-headlines-body--split { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .wx-headlines-body--split > .wx-headlines-side,
  .wx-headlines-body--adv-full > .wx-events.wx-headlines-side,
  .wx-headlines-body--adv-full > .wx-advisories,
  .wx-headlines-body--adv-right > .wx-prio-grid,
  .wx-headlines-body--adv-right > .wx-events.wx-headlines-side,
  .wx-headlines-body--adv-right > .wx-advisories {
    grid-column: 1;
    grid-row: auto;
  }
  .wx-headlines-body--split > .wx-headlines-side {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
  }
  .wx-headlines-body--split .wx-prio-grid--multi {
    display: grid;
    column-count: auto;
    margin-bottom: 0;
  }
  .wx-headlines-body--split .wx-prio-grid--multi > .wx-prio { margin-bottom: 0; }
}

/* ─── Storm report types (assets/js/lsr-types.js) ──────────────────────
 * Markers are a disc in the type's color with its icon (inline SVG, colors
 * as attributes). The Reports map gets a legend of the types on screen,
 * bottom right (the list panel floats top left, layers top right). */
.lsr-marker svg { display: block; }
.lsr-popup-casualty { color: #d62828; font-weight: 700; }
.lsr-popup-details { margin-top: 0.4rem; font-size: 0.8rem; max-width: 22rem; }
.lsr-legend {
  position: absolute;
  right: 0.6rem;
  bottom: 1.6rem;
  z-index: 500;
  max-width: min(17rem, calc(100% - 1.2rem));
  max-height: 45%;
  overflow-y: auto;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--card) 92%, transparent);
  color: var(--text);
  font-size: 0.78rem;
  box-shadow: var(--shadow);
}
.lsr-legend summary {
  cursor: pointer;
  font-weight: 800;
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}
.lsr-legend-list {
  display: grid;
  gap: 0.2rem;
  margin: 0.35rem 0 0;
  padding: 0;
  list-style: none;
}
.lsr-legend-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.45rem;
}
.lsr-legend-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lsr-legend-n {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  color: var(--muted);
}
/* Settings → Event Colors: preview, name, color, hex, icon. */
.lsr-type-row {
  display: grid;
  grid-template-columns: auto minmax(9rem, 1fr) auto auto minmax(7rem, auto);
  align-items: center;
  gap: 0.5rem;
}
.lsr-type-preview { display: inline-flex; }
@media (max-width: 720px) {
  .lsr-type-row { grid-template-columns: auto minmax(0, 1fr) auto; }
  .lsr-type-row input[type="text"] { display: none; }
}

/* ─── Radar page (modules/radar/index.php) ─────────────────────────────
 * The radar service framed under the site header: the frame fills the
 * window below the header and page bar; the footer sits below the fold. */
.wx-radar-main { padding-top: 0.25rem; }
.wx-radar-frame {
  display: block;
  width: 100%;
  height: calc(100dvh - var(--wx-header-h, 64px) - 6.5rem);
  min-height: 480px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: #0c1622;
}
@media (max-width: 899px) {
  .wx-radar-frame { height: calc(100dvh - var(--wx-header-h, 64px) - 10rem); min-height: 420px; }
}

/* ─── Beta tag, first-visit welcome and site tour (assets/js/tour.js) ───
 * The welcome reuses the .wx-prompt dialog. The tour dims the page with one
 * spotlight (a box-shadow around the target) and a card placed next to it,
 * or pinned to the bottom of the screen when there's no room. Positions are
 * set by tour.js through CSSOM (the CSP blocks style attributes). */
.wx-beta {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0.05rem 0.4rem;
  border: 1px solid color-mix(in srgb, var(--accent) 70%, transparent);
  border-radius: 999px;
  color: var(--accent);
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  vertical-align: middle;
  line-height: 1.4;
}
.wx-brand .wx-beta { align-self: center; }
/* Phones: the header row has no room for it (it pushed Resources/Support to a
 * third row); the first-visit welcome says "beta" instead. */
@media (max-width: 480px) {
  .wx-brand .wx-beta { display: none; }
}
.wx-welcome { max-width: 28rem; }
.wx-welcome h3 { display: flex; align-items: center; gap: 0.2rem; }
.wx-welcome p { color: var(--text); }
.wx-welcome .wx-welcome-beta {
  padding: 0.55rem 0.7rem;
  border-left: 3px solid var(--accent);
  border-radius: 0.4rem;
  background: color-mix(in srgb, var(--accent) 10%, var(--card));
}

.wx-tour-layer {
  position: fixed;
  inset: 0;
  z-index: 2200;
}
.wx-tour-spot {
  position: absolute;
  border-radius: 0.7rem;
  outline: 2px solid var(--accent);
  box-shadow: 0 0 0 200vmax rgba(2, 1, 12, 0.62);
  pointer-events: none;
  transition: top 0.2s ease, left 0.2s ease, width 0.2s ease, height 0.2s ease;
}
.wx-tour-card {
  position: absolute;
  width: min(22rem, calc(100vw - 24px));
  box-sizing: border-box;
  padding: 0.85rem 1rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  color: var(--text);
  box-shadow: var(--shadow);
}
.wx-tour-card:focus { outline: none; }
.wx-tour-card--pinned {
  left: 12px;
  right: 12px;
  bottom: max(12px, env(safe-area-inset-bottom));
  width: auto;
}
.wx-tour-step {
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}
.wx-tour-card h3 { margin: 0.15rem 0 0.35rem; font-size: var(--text-md); }
.wx-tour-card p { margin: 0; font-size: var(--text-sm); line-height: 1.45; }
.wx-tour-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 0.8rem;
}
.wx-tour-nav { display: flex; gap: 0.4rem; }
.wx-tour-skip,
.wx-footer-tour {
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.wx-tour-skip { font-size: var(--text-sm); min-height: 36px; }
.wx-tour-skip:hover,
.wx-footer-tour:hover { color: var(--text); }
@media (prefers-reduced-motion: reduce) {
  .wx-tour-spot { transition: none; }
}

/* ─── SPC outlook discussion (SPC details overlay, spc.js) ───────────────
 * The forecasters' text behind an outlook map, reflowed from SPC's 68-column
 * text: section markers as headings, the lead sentence set apart. */
.spc-disc { font-size: 0.92rem; line-height: 1.6; }
.spc-disc p { margin: 0 0 0.7rem; }
.spc-disc .overlay-times { margin-bottom: 0.6rem; }
.spc-disc-h {
  margin: 1rem 0 0.3rem;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--accent) 80%, var(--text));
}
.spc-disc-lead {
  padding: 0.55rem 0.7rem;
  border-left: 3px solid var(--accent);
  border-radius: 0.4rem;
  background: color-mix(in srgb, var(--accent) 8%, var(--card));
  font-weight: 700;
}
.spc-disc-src { font-size: 0.82rem; }
@media (max-width: 720px) {
  .overlay-content { width: calc(100vw - 1.5rem); }
}

/* Tropical model layers (maproom-providers.js tropical.models / .ensembles /
 * .lows): track end labels and the model-lows time picker and scale. */
.tc-model-label span {
  display: inline-block;
  padding: 0 0.25rem;
  border-radius: 0.25rem;
  background: rgba(11, 15, 25, 0.75);
  font-size: 0.68rem;
  font-weight: 800;
  white-space: nowrap;
  transform: translate(6px, -50%);
}
.tc-lows-ctrl {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1000;
  width: max-content;
  max-width: min(26rem, calc(100% - 7rem));
  padding: 0.45rem 0.6rem;
  border-radius: 0.6rem;
  background: rgba(11, 15, 25, 0.88);
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: #e5e7eb;
  font-size: 0.78rem;
}
.tc-lows-title { font-weight: 800; letter-spacing: 0.04em; margin-bottom: 0.3rem; }
.tc-lows-pick { display: flex; align-items: center; gap: 0.4rem; }
.tc-lows-pick select { flex: 1 1 auto; min-width: 0; min-height: 32px; }
.tc-lows-scale, .tc-lows-key { display: flex; flex-wrap: wrap; gap: 0.2rem 0.55rem; margin-top: 0.4rem; }
.tc-lows-scale i, .tc-lows-key i {
  display: inline-block; width: 0.7rem; height: 0.7rem; border-radius: 50%; margin-right: 0.2rem; vertical-align: -0.1rem;
}
.tc-lows-ring { border: 2px solid #ffffff; background: #fb923c; }
.tc-lows-dot { border: 1px solid #0b0f19; background: #fb923c; width: 0.55rem !important; height: 0.55rem !important; }
@media (max-width: 520px) { .tc-lows-ctrl { max-width: calc(100% - 5.5rem); font-size: 0.72rem; } }
.tc-arrival-label span { transform: translate(-50%, -50%); }

/* Page tours (tour.js PAGE_TOURS): the once-per-page offer, the "Page tour"
 * button in the page bar, and the labeled Layers button (maproom.js). */
.wx-tour-hint {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 1300;
  max-width: 21rem;
  padding: 0.8rem 0.9rem;
  border-radius: 0.8rem;
  background: var(--card);
  border: 1px solid color-mix(in srgb, var(--accent) 55%, var(--border));
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  color: var(--text);
}
.wx-tour-hint strong { display: block; margin-bottom: 0.25rem; }
.wx-tour-hint p { margin: 0 0 0.6rem; font-size: 0.86rem; color: var(--muted); }
.wx-tour-hint-actions { display: flex; justify-content: flex-end; gap: 0.5rem; }
@media (max-width: 520px) { .wx-tour-hint { left: 12px; right: 12px; max-width: none; } }
.wx-pagebar-tour {
  margin-left: 0.6rem;
  padding: 0.2rem 0.65rem;
  min-height: 30px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--accent) 50%, var(--border));
  background: transparent;
  color: var(--accent);
  font-size: 0.78rem;
  font-weight: 700;
  cursor: pointer;
  align-self: center;
}
.wx-pagebar-tour:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.maproom-layers-toggle--labeled { width: auto; padding: 0 0.65rem; gap: 0.35rem; }
.maproom-layers-label { font-size: 0.8rem; font-weight: 700; }
@media (max-width: 520px) {
  .maproom-layers-label { display: none; }
  .maproom-layers-toggle--labeled { padding: 0; }
}

/* What's new (whats-new.php, data/changelog.json). */
.wx-whatsnew > * { max-width: 52rem; margin-left: 0; margin-right: 0; }
.wx-release { margin-bottom: 0.8rem; }
.wx-release-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem 0.8rem; margin-bottom: 0.4rem; }
.wx-release-version { margin: 0; font-size: 1.05rem; }
.wx-release-date { font-size: 0.82rem; color: var(--muted); }
.wx-release-current {
  padding: 0.05rem 0.5rem; border-radius: 999px; font-size: 0.72rem; font-weight: 700;
  background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent);
}
.wx-release-items { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 0.35rem; }
.wx-release-item { display: flex; align-items: baseline; gap: 0.6rem; line-height: 1.45; }
.wx-release-tag {
  flex: 0 0 5.4rem; text-align: center; padding: 0.05rem 0; border-radius: 0.35rem;
  font-size: 0.7rem; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase;
}
.wx-release-item--new .wx-release-tag { background: color-mix(in srgb, #22c55e 22%, transparent); color: color-mix(in srgb, #22c55e 75%, var(--text)); }
.wx-release-item--improved .wx-release-tag { background: color-mix(in srgb, #38bdf8 22%, transparent); color: color-mix(in srgb, #38bdf8 75%, var(--text)); }
.wx-release-item--fixed .wx-release-tag { background: color-mix(in srgb, #f59e0b 22%, transparent); color: color-mix(in srgb, #f59e0b 75%, var(--text)); }
.wx-whatsnew-note { margin-top: 1rem; }
a.wx-footer-version { color: inherit; text-decoration: none; }
a.wx-footer-version:hover { text-decoration: underline; }
@media (max-width: 520px) { .wx-release-tag { flex-basis: 4.6rem; } }

/* Layer times (maproom.js): what each map layer's data is from and how old
 * it is. Bottom left of the map, beside an open side panel; on phones a
 * one-line summary at the top. Dark in both themes, like .tc-lows-ctrl. */
.maproom-times {
  position: absolute;
  bottom: 0.75rem;
  left: 0.75rem;
  z-index: 440;
  width: max-content;
  max-width: min(27rem, calc(100% - 15rem));
  max-height: 45%;
  overflow: auto;
  padding: 0.35rem 0.6rem;
  border-radius: 0.6rem;
  background: rgba(11, 15, 25, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: #e5e7eb;
  font-size: 0.74rem;
}
.maproom-times[hidden] { display: none; }
/* Clear of the legend at the bottom right (.maproom-legend, ~12rem). */
.maproom-mapwrap:has(> .maproom-panel:not(.maproom-layers-panel):not(.is-collapsed)) > .maproom-times {
  left: calc(min(24rem, 38vw) + 1.5rem);
  max-width: min(27rem, calc(100% - min(24rem, 38vw) - 14.5rem));
}
.maproom-times summary {
  display: flex; align-items: center; gap: 0.5rem; cursor: pointer; list-style: none;
  font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; color: #cbd5e1;
}
.maproom-times summary::-webkit-details-marker { display: none; }
.maproom-times summary::after { content: '\25B8'; margin-left: auto; color: #9ca3af; }
.maproom-times[open] summary::after { content: '\25BE'; }
.maproom-times-worst {
  padding: 0 0.45rem; border-radius: 999px; font-weight: 700; letter-spacing: 0; text-transform: none;
  color: #4ade80; background: rgba(74, 222, 128, 0.14);
}
.maproom-times[data-worst="old"] .maproom-times-worst { color: #fbbf24; background: rgba(251, 191, 36, 0.14); }
.maproom-times[data-worst="stale"] .maproom-times-worst { color: #f87171; background: rgba(248, 113, 113, 0.16); }
.maproom-times-group { margin-top: 0.35rem; }
.maproom-times-head { font-weight: 700; color: #f3f4f6; }
.maproom-times-row {
  position: relative; display: flex; justify-content: space-between; align-items: baseline; gap: 0.75rem;
  padding-left: 0.8rem; line-height: 1.4;
}
.maproom-times-row::before {
  content: ''; position: absolute; left: 0.1rem; top: 0.5em;
  width: 0.42rem; height: 0.42rem; border-radius: 50%; background: #4ade80;
}
.maproom-times-row[data-age="old"]::before { background: #fbbf24; }
.maproom-times-row[data-age="stale"]::before { background: #f87171; }
.maproom-times-label { min-width: 0; }
.maproom-times-when { white-space: nowrap; color: #9ca3af; font-variant-numeric: tabular-nums; }
.maproom-times-row[data-age="old"] .maproom-times-when { color: #fbbf24; }
.maproom-times-row[data-age="stale"] .maproom-times-when { color: #f87171; }
.maproom-times-row--note { color: #9ca3af; font-style: italic; }
.maproom-times-row--note::before { display: none; }
@media (max-width: 720px) {
  .maproom-times,
  .maproom-mapwrap:has(> .maproom-panel:not(.maproom-layers-panel):not(.is-collapsed)) > .maproom-times {
    top: 0.5rem; bottom: auto; left: 3.25rem; max-width: calc(100% - 7rem); max-height: 40vh;
  }
  .maproom-times[open] { z-index: 520; }   /* over the bottom-sheet panel */
  .maproom-mapwrap:has(> .maproom-times:not([hidden])) .tc-lows-ctrl { top: 2.9rem; }
}
/* A model run behind the newer ones (maproom-providers.js tcRun). */
.tc-model-label--old span { opacity: 0.6; font-weight: 600; }

/* "Keep me signed in" on the sign-in form (remember.php). */
.login-remember { display: flex; align-items: center; gap: 0.5rem; margin: 0.25rem 0 0.75rem; font-size: var(--text-sm); color: var(--muted); cursor: pointer; }
.login-remember input { width: 1.05rem; height: 1.05rem; margin: 0; }
