/* Phase 2c.1 — draggable floating panels.
 * Map fills the entire main area; products / loop / info panels float
 * on top, each draggable by its header and persisting position in
 * localStorage. Leaflet zoom control relocated to bottom-right (out of
 * the way of the products panel's default anchor at top-left).
 */

* { box-sizing: border-box; }

/* `hidden` always hides. Several rules here give elements a display value
 * (.radar-hist-bar, .radar-motion, .radar-field, .motion-source), which
 * beats the browser's own [hidden] rule: the Event picker, + NOAA,
 * Re-analyze and the storm-motion fields showed in Live mode. */
[hidden] { display: none !important; }

/* The public Web Radar (deployment tier "basic") has no cells, boundaries,
 * historical replay or operator tooling; their controls carry
 * data-full-tier (index.html) and stay out of its toolbar. */
html[data-tier="basic"] [data-full-tier] { display: none !important; }

/* Inside the site (modules/radar/index.php frames this page under the site
 * header and rail): the site already says where you are and links home,
 * so the radar's own title, back link and badge go; the tools stay. */
.radar-embedded .radar-bar-title { display: none; }
.radar-embedded .radar-bar { padding: 0.4rem 0.6rem; }

/* Page = toolbar + map; the toolbar wraps to as many rows as it needs. */
body { display: flex; flex-direction: column; }
.radar-bar { flex: none; }
/* Phones: one row that scrolls sideways, so the toolbar doesn't eat the
 * map (it wrapped to ~260 px at 390 px wide). */
@media (max-width: 720px) {
  .radar-bar { overflow: hidden; }
  .radar-bar .radar-bar-controls {   /* beats the base rule further down */
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    padding-bottom: 0.2rem;
    min-width: 0;
  }
  .radar-bar .radar-bar-controls > * { flex: none; }

  /* Panels on phones (radar.js initPhonePanels): tap a title bar to
   * collapse or open it. Products top left, legend and info top right as
   * title chips at first; the loop bar docked at the bottom. */
  .radar-phone .glass-panel.gp-collapsed > :not(.gp-handle) { display: none !important; }
  .radar-phone .glass-panel.gp-collapsed { width: auto !important; min-width: 0 !important; height: auto !important; min-height: 0 !important; max-height: none !important; bottom: auto !important; }
  .radar-phone .glass-panel .gp-handle { cursor: pointer; }
  .radar-phone .glass-panel.gp-collapsed .gp-title::after { content: " ▸"; opacity: 0.7; }
  .radar-phone #panel-products { top: 8px !important; left: 8px !important; right: auto !important; }
  .radar-phone #panel-info     { top: 8px !important; right: 8px !important; left: auto !important; }
  .radar-phone #panel-legend   { top: 48px !important; right: 8px !important; left: auto !important; }
  .radar-phone #panel-loop     { top: auto !important; bottom: 34px !important; left: 8px !important; right: 8px !important; width: auto !important; }
  .radar-phone #panel-products:not(.gp-collapsed),
  .radar-phone #panel-info:not(.gp-collapsed) { width: calc(100% - 16px) !important; z-index: 650; }
}

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: #0c1622;
  color: #e7ecf2;
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

.radar-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 1rem;
  background: linear-gradient(180deg, #0f2236 0%, #08111c 100%);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.radar-bar-title { font-size: 1.05rem; font-weight: 700; letter-spacing: 0.02em; }

/* Back-link to the parent wxalert app. Hidden in standalone radar
   deployments (window.__WXALERT_PARENT_URL__ empty); unhidden when
   served inside the unified wxalert stack. Sits to the left of the
   "WxAlert Radar" title so the operator's eye registers it as part
   of the navbar, not a control. */
.radar-back-link {
  display: inline-flex;
  align-items: center;
  margin-right: 0.7rem;
  padding: 0.18rem 0.55rem;
  font: 600 0.78rem/1 system-ui, sans-serif;
  letter-spacing: 0.02em;
  color: #6ab3ff;
  background: rgba(74, 163, 255, 0.12);
  border: 1px solid rgba(74, 163, 255, 0.35);
  border-radius: 0.35rem;
  text-decoration: none;
}
.radar-back-link:hover {
  color: #fff;
  background: rgba(74, 163, 255, 0.28);
  border-color: rgba(74, 163, 255, 0.55);
}
.radar-bar-tag {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  margin-left: 0.4rem;
  border-radius: 0.4rem;
  background: rgba(242, 193, 78, 0.18);
  color: #f2c14e;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
}

.radar-bar-controls { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.radar-field { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.82rem; color: #9aa6b3; }
.radar-field select,
.radar-field input[type="number"] {
  background: #0e1c2a;
  color: #e7ecf2;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.35rem;
  padding: 0.25rem 0.5rem;
  font-size: 0.85rem;
}
.radar-field input[type="number"] { width: 4rem; }

/* Live ⇄ Historical mode switch — two-segment toggle in the header.
   Compact so it doesn't compete with the site picker visually; the
   active segment carries the brand-accent border + filled background.
   Historical mode reskins the toolbar (chip turns amber) so the
   operator can never confuse "is this live data" at a glance. */
.radar-mode-switch {
  display: inline-flex;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 6px;
  overflow: hidden;
  margin-right: 0.4rem;
}
.radar-mode-btn {
  background: transparent;
  border: 0;
  color: #9aa6b3;
  font: inherit;
  padding: 0.25rem 0.55rem;
  cursor: pointer;
  font-size: 0.82rem;
  letter-spacing: 0.02em;
}
.radar-mode-btn + .radar-mode-btn {
  border-left: 1px solid rgba(255, 255, 255, 0.18);
}
.radar-mode-btn.active {
  background: rgba(126, 255, 126, 0.16);
  color: #cffacf;
}
.radar-mode-btn.active#btn-mode-hist {
  /* Amber for historical so the entire UI signals "you are not on
     live data" — operationally important during validation testing
     so an analyst can't accidentally interpret 1999 cells as live. */
  background: rgba(242, 193, 78, 0.20);
  color: #ffdf91;
}
body.radar-mode-historical .radar-bar {
  /* Subtle amber tint across the header to make "we are in historical
     mode" impossible to miss without being shouty. */
  border-bottom: 1px solid rgba(242, 193, 78, 0.45);
}
body.radar-mode-historical .radar-bar-title::after {
  content: " · Historical";
  color: #f2c14e;
  font-weight: 600;
}

/* Historical-mode toolbar bar — replaces the live site picker. Event
   + site dropdowns + a horizontal timeline scrubber that spans the
   full event time range. The scrubber is the operator's primary
   navigation in historical mode (operator's choice per
   [[radar-historical-mode]]). */
.radar-hist-bar {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
/* Step buttons in the Loop panel — narrow caret buttons so the
   operator can advance by one frame without hunting for scrubber
   precision. */
.radar-btn.radar-btn-step {
  padding: 0 0.4rem;
  font-size: 0.7rem;
  line-height: 1.4rem;
}
.gp-frame-readout {
  font-size: 0.78rem;
  color: #ffdf91;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  margin-left: 0.4rem;
}
.hist-analyze-status {
  font-size: 0.74rem;
  color: #9aa6b3;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  min-width: 6rem;
}
.hist-analyze-status.is-running { color: #ffdf91; }
.hist-analyze-status.is-done    { color: #7eff7e; }
.hist-analyze-status.is-error   { color: #ff8a8a; }

/* Disabled-toggle visual: warn / LSR buttons go grey + crossed-out in
   historical mode since there's no archived NWS feed to back them. */
.radar-btn.is-mode-disabled {
  opacity: 0.4;
  cursor: not-allowed;
  text-decoration: line-through;
}

/* NOAA import dialog. Free-floating panel anchored to the upper-right
   of the header — the +NOAA button opens it, the form posts to
   /api/historical/import, the progress bar updates from the polling
   job-status response. Visual style mirrors the boundary settings
   flyout so the operator's eye expects "small focused panel with
   inputs + footer." */
.hist-import-dialog {
  position: absolute;
  top: 3.2rem;
  right: 1rem;
  width: 24rem;
  background: rgba(20, 26, 36, 0.96);
  border: 1px solid rgba(242, 193, 78, 0.55);
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  z-index: 800;
  color: #c2d0db;
  font-size: 0.85rem;
}
.hid-header {
  display: flex;
  align-items: center;
  padding: 0.55rem 0.75rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(242, 193, 78, 0.07);
}
.hid-title {
  flex: 1 1 auto;
  font-weight: 700;
  color: #ffdf91;
}
.hid-body {
  padding: 0.5rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.hid-body .sf-row { padding: 0.15rem 0; }
.hid-body .sf-row input[type="text"],
.hid-body .sf-row input[type="datetime-local"],
.hid-body .sf-row textarea {
  flex: 1 1 auto;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 4px;
  color: #c2d0db;
  padding: 0.25rem 0.4rem;
  font: inherit;
}
.hid-body .sf-row-wide { flex-direction: column; align-items: stretch; }
.hid-body .sf-row-wide .sf-label { margin-bottom: 0.2rem; }
.hid-hint {
  font-size: 0.78rem;
  color: #9aa6b3;
  margin: 0 0 0.3rem;
}
.hid-hint code {
  background: rgba(255, 255, 255, 0.06);
  padding: 0 0.25rem;
  border-radius: 3px;
  font-size: 0.74rem;
}
.hid-status {
  font-size: 0.78rem;
  color: #9aa6b3;
  min-height: 1.2em;
}
.hid-status.hid-status-error  { color: #ff8a8a; }
.hid-status.hid-status-done   { color: #7eff7e; }
.hid-progress {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.78rem;
}
.hid-progress-bar {
  flex: 1 1 auto;
  height: 6px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 3px;
  overflow: hidden;
}
.hid-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #f2c14e, #7eff7e);
  width: 0%;
  transition: width 0.2s ease;
}
.hid-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.4rem;
  padding: 0.5rem 0.75rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.radar-btn {
  background: #142536;
  color: #e7ecf2;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.35rem;
  padding: 0.32rem 0.7rem;
  font-size: 0.8rem;
  cursor: pointer;
}
.radar-btn:hover { background: #1b3047; }
.radar-btn.active { background: #2a4a6a; border-color: #4aa3ff; color: #fff; }
.radar-btn.paused { background: #6a3a14; border-color: #ffb84a; color: #fff; }

/* Profile tool endpoints — A and B labeled circles dropped where the
   operator clicked. Bright amber to match the dashed connecting line. */
.profile-endpoint-pin {
  width: 22px; height: 22px; border-radius: 50%;
  background: #ffd54a; color: #1b1300;
  border: 2px solid #6a4d00;
  font: 700 12px/18px system-ui, sans-serif;
  text-align: center;
  box-shadow: 0 1px 4px rgba(0,0,0,0.6);
}

/* Motion source chip — shows where the current storm motion vector
   came from (manual entry, an NWS warning, etc.) so the operator can
   tell at a glance whether SRV is keyed off the right number. The
   .flash class drives a brief amber highlight when motion auto-applies. */
.motion-source {
  display: inline-block;
  padding: 2px 8px;
  margin-left: 6px;
  font-size: 0.72rem;
  color: #d8e8ff;
  background: rgba(40, 60, 90, 0.6);
  border: 1px solid rgba(74, 163, 255, 0.4);
  border-radius: 0.3rem;
  white-space: nowrap;
}
.motion-source.flash {
  background: #6a4d00;
  border-color: #ffd54a;
  color: #fff;
  animation: motion-source-pulse 1.2s ease-out 2;
}
@keyframes motion-source-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 213, 74, 0.0); }
  50%      { box-shadow: 0 0 0 6px rgba(255, 213, 74, 0.35); }
}

/* SRV product button briefly pulses when motion auto-applies, so the
   operator's eye lands on the active product. */
.motion-pulse {
  animation: motion-btn-pulse 1.0s ease-out 3;
}
@keyframes motion-btn-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(74, 163, 255, 0); }
  50%      { box-shadow: 0 0 0 4px rgba(74, 163, 255, 0.55); }
}

/* Hover query chip — floats next to cursor with the active product's
   value at that lat/lon. Pointer-events: none so it can never block a
   click meant for a marker or cell underneath. */
.hover-chip {
  position: fixed;
  z-index: 9000;
  pointer-events: none;
  padding: 3px 8px;
  background: rgba(20, 30, 45, 0.92);
  color: #fff;
  border: 1px solid #4aa3ff;
  border-radius: 4px;
  font: 600 11px/1.2 system-ui, sans-serif;
  white-space: nowrap;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
}
.hover-chip .hc-na { color: rgba(255, 255, 255, 0.45); font-weight: 400; }
.hover-chip .hc-meta {
  display: block;
  color: rgba(255, 255, 255, 0.55);
  font-weight: 400;
  font-size: 10px;
  margin-top: 1px;
}

/* Tropical cyclone markers + side panel. */
.tropical-marker { pointer-events: auto; overflow: visible; }
.tcm {
  position: relative;
  width: 44px; height: 44px;
  color: var(--cat, #888);
}
/* Inline SVG cyclone swirl, tinted by Saffir-Simpson category via
   currentColor + a category-color glow so it reads from across the map. */
.tcm-symbol {
  width: 44px; height: 44px;
  filter: drop-shadow(0 0 5px var(--cat)) drop-shadow(0 1px 2px rgba(0,0,0,0.7));
}
.tcm-symbol svg { display: block; width: 100%; height: 100%; }
/* NH cyclones spin counter-clockwise; only organized systems animate. */
.tcm-spin-on .tcm-symbol { animation: tcm-swirl 8s linear infinite; transform-origin: 50% 50%; }
@keyframes tcm-swirl { to { transform: rotate(-360deg); } }
@media (prefers-reduced-motion: reduce) {
  .tcm-spin-on .tcm-symbol { animation: none; }
}
/* Category badge — '1'..'5' for hurricanes, 'TS' for tropical storms. */
.tcm-badge {
  position: absolute; top: -3px; right: -3px;
  min-width: 16px; height: 16px; padding: 0 3px; box-sizing: border-box;
  border-radius: 9px;
  background: var(--cat); color: #08111c;
  font: 800 11px/16px system-ui, sans-serif; text-align: center;
  box-shadow: 0 0 0 1.5px #08111c;
}
.tcm-badge--ts { font-size: 9px; letter-spacing: -0.5px; }
/* Motion arrow — anchored at marker center, rotated to the storm's
   translation bearing, head pushed out to the symbol edge. */
.tcm-motion { position: absolute; left: 50%; top: 50%; width: 0; height: 0; }
.tcm-motion::before {
  content: ''; position: absolute; left: -5px; top: -31px;
  border-left: 5px solid transparent; border-right: 5px solid transparent;
  border-bottom: 8px solid var(--cat);
  filter: drop-shadow(0 0 2px rgba(0,0,0,0.85));
}
/* Invests keep the dashed amber pulsing ring (pre-classification). */
.tcm-ring {
  width: 30px; height: 30px; border-radius: 50%;
  border: 3px solid var(--cat, #888);
  background: rgba(20, 30, 45, 0.85);
  display: flex; align-items: center; justify-content: center;
}
.tcm-invest .tcm-ring {
  position: absolute; top: 7px; left: 50%; transform: translateX(-50%);
}
.tcm-invest-ring {
  border-style: dashed; border-width: 2.5px;
  animation: tcm-invest-pulse 2.6s ease-in-out infinite;
}
@keyframes tcm-invest-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 213, 74, 0); }
  50%      { box-shadow: 0 0 0 4px rgba(255, 213, 74, 0.45); }
}
.tcm-glyph { font: 800 14px/1 system-ui, sans-serif; color: var(--cat, #ffd54a); }
.tcm-name {
  position: absolute; top: 43px; left: 50%; transform: translateX(-50%);
  text-align: center; white-space: nowrap;
  font: 700 10px/1.1 system-ui, sans-serif;
  color: #eaf2ff;
  text-shadow: 0 1px 2px rgba(0,0,0,0.95), 0 0 4px rgba(0,0,0,0.8);
}
.tropical-popup .tp-head {
  display: flex; gap: 8px; align-items: center;
  border-bottom: 2px solid #888;
  padding-bottom: 4px; margin-bottom: 6px;
}
.tp-cat {
  display: inline-block;
  padding: 2px 8px; border-radius: 4px;
  color: #1b1300; font-weight: 700; font-size: 11px;
}
.tp-name { font-weight: 700; font-size: 14px; }
.tp-basin { color: rgba(255,255,255,0.5); font-size: 11px; }
.tp-advisory { margin-top: 6px; font-size: 11px; color: rgba(255,255,255,0.7); }
.tp-products { margin-top: 6px; font-size: 11px; color: rgba(255,255,255,0.7); }
.tp-products-links { display: flex; flex-wrap: wrap; gap: 4px 10px; margin-top: 3px; }
.tp-products-links a { white-space: nowrap; }
.tp-actions { margin-top: 8px; }
.tropical-tooltip {
  background: rgba(20, 30, 45, 0.9) !important;
  color: #fff !important;
  border: 1px solid rgba(255, 255, 255, 0.2) !important;
  font-size: 11px !important;
}
.tropical-list { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; }
.tp-section-header {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.55);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-top: 6px;
  padding-bottom: 2px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.tp-outlook-row {
  display: grid;
  grid-template-columns: 50px 1fr 70px 70px;
  gap: 6px;
  align-items: center;
  background: rgba(20, 30, 45, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 4px;
  padding: 4px 6px;
  cursor: pointer;
}
.tp-outlook-row:hover { background: rgba(40, 60, 90, 0.7); }
.tp-out-tier {
  text-align: center;
  font: 700 10px/1.4 system-ui, sans-serif;
  color: #1b1300;
  border-radius: 3px;
  padding: 1px 2px;
}
.tp-out-name { font-weight: 600; }
.tp-out-basin { color: rgba(255,255,255,0.6); font-size: 11px; }
.tp-out-pct { text-align: right; font-variant-numeric: tabular-nums; }
.tp-out-pct b { color: #ffd54a; }
.tp-outlook-desc {
  max-height: 100px;
  overflow: auto;
  font-size: 11px;
  color: rgba(255, 255, 255, 0.75);
  background: rgba(0, 0, 0, 0.2);
  padding: 4px 6px;
  border-radius: 3px;
  margin: 6px 0;
}
.tp-narrative, .tp-models-legend {
  margin-top: 8px;
  font-size: 11px;
}
.tp-narrative summary, .tp-models-legend summary {
  cursor: pointer;
  color: rgba(255, 255, 255, 0.75);
  user-select: none;
}
.tp-narrative summary:hover, .tp-models-legend summary:hover { color: #fff; }
.tp-narrative-body {
  max-height: 240px;
  overflow: auto;
  white-space: pre-wrap;
  font: 11px/1.4 ui-monospace, Menlo, Consolas, monospace;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 3px;
  padding: 6px;
  margin-top: 4px;
  color: rgba(255, 255, 255, 0.85);
}
.tp-models-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px 8px;
  margin-top: 4px;
  font: 600 11px/1.4 system-ui, sans-serif;
}

/* Tropical diagnostics — external image embeds from CIMSS / OSPO /
   FSU / EMC / NHC TAFB. Each sub-section collapses by default to
   keep the panel scrollable and load-friendly. */
.tp-diag-body { margin-top: 4px; display: flex; flex-direction: column; gap: 4px; }
.tp-diag-sub {
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.18);
  padding: 4px 6px;
}
.tp-diag-sub > summary {
  cursor: pointer;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.85);
  font-weight: 600;
  padding: 2px 0;
}
.tp-diag-sub > summary:hover { color: #fff; }
.tp-diag-imgs {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  margin-top: 6px;
}
.tp-diag-imgs figure {
  margin: 0;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 3px;
  overflow: hidden;
}
.tp-diag-imgs figure img {
  display: block;
  width: 100%;
  height: auto;
  cursor: zoom-in;
  background: rgba(0, 0, 0, 0.4);
}
.tp-diag-imgs figcaption {
  font: 11px/1.3 system-ui, sans-serif;
  color: rgba(255, 255, 255, 0.7);
  padding: 4px 6px;
  background: rgba(0, 0, 0, 0.4);
}
.tp-diag-broken {
  padding: 8px;
  background: rgba(255, 58, 58, 0.18);
  color: rgba(255, 200, 200, 0.95);
  font-size: 11px;
}
.tp-diag-broken a { color: #ffd54a; }
.tp-diag-footer {
  margin-top: 6px;
  padding-top: 4px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 10.5px;
  color: rgba(255, 255, 255, 0.55);
}
.tp-diag-links {
  margin-top: 6px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  font-size: 11px;
}
.tp-diag-links a {
  color: #6ab3ff;
  text-decoration: none;
}
.tp-diag-links a:hover { text-decoration: underline; color: #fff; }
.tp-diag-marine details {
  margin: 4px 0;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 3px;
  padding: 4px 6px;
  background: rgba(0, 0, 0, 0.18);
}
.tp-diag-marine summary {
  cursor: pointer;
  font-size: 11.5px;
  color: rgba(255, 255, 255, 0.82);
}
.tp-mesoanalysis-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
  align-items: center;
  margin: 6px 0;
  font-size: 11px;
}
.tp-mesoanalysis-controls label {
  display: flex; gap: 4px; align-items: center;
  color: rgba(255, 255, 255, 0.8);
}
.tp-mesoanalysis-controls select {
  background: #142536;
  color: #e7ecf2;
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 0.3rem;
  font-size: 11px;
  padding: 2px 4px;
}
.tp-row {
  display: grid;
  grid-template-columns: 44px 1fr 60px 90px 60px;
  grid-template-rows: auto auto;
  gap: 6px;
  align-items: center;
  background: rgba(20, 30, 45, 0.6);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 4px;
  padding: 4px 6px;
  cursor: pointer;
}
.tp-row:hover { background: rgba(40, 60, 90, 0.7); }
.tp-row-cat {
  text-align: center;
  font: 700 10px/1.4 system-ui, sans-serif;
  color: #1b1300;
  border-radius: 3px;
  padding: 1px 2px;
}
.tp-diag-link {
  display: block;
  text-align: center;
  padding: 6px 8px;
  margin-top: 6px;
  background: rgba(74, 163, 255, 0.18);
  border: 1px solid rgba(74, 163, 255, 0.4);
  border-radius: 4px;
  color: #6ab3ff;
  font: 600 11px/1.2 system-ui, sans-serif;
  text-decoration: none;
}
.tp-diag-link:hover {
  background: rgba(74, 163, 255, 0.28);
  color: #fff;
}
.tp-row-name { font-weight: 600; }
.tp-row-wind { text-align: right; font-variant-numeric: tabular-nums; }
.tp-row-mot { color: rgba(255,255,255,0.75); font-size: 11px; font-variant-numeric: tabular-nums; }
.tp-row-srv {
  background: #2a4a6a; color: #fff;
  border: 1px solid #4aa3ff;
  border-radius: 3px;
  font: 600 10px/1 system-ui, sans-serif;
  padding: 3px 4px;
  cursor: pointer;
}
.tp-row-srv:hover { background: #3a5a8a; }
.tp-row-approach {
  grid-column: 1 / -1;
  font-size: 11px;
  color: rgba(255, 213, 74, 0.85);
  padding-top: 3px;
  border-top: 1px dashed rgba(255,255,255,0.1);
}
.tp-row-approach.tp-urg-watch     { color: #ffd54a; }
.tp-row-approach.tp-urg-approach  { color: #ff9500; font-weight: 600; }
.tp-row-approach.tp-urg-imminent {
  color: #ff3a3a; font-weight: 700;
  animation: tp-imminent-pulse 1.6s ease-in-out infinite;
}
@keyframes tp-imminent-pulse {
  0%, 100% { background: rgba(255, 58, 58, 0); }
  50%      { background: rgba(255, 58, 58, 0.22); }
}
.tp-footer {
  margin-top: 8px; padding-top: 6px;
  border-top: 1px solid rgba(255,255,255,0.1);
  font-size: 11px; color: rgba(255,255,255,0.6);
}
.tp-footer a { color: #6ab3ff; }

/* Pinned point queries — numbered marker + live value readout. */
.pin-query-pin {
  display: inline-flex; align-items: center; gap: 4px;
  background: rgba(20, 30, 45, 0.92); color: #fff;
  border: 1px solid #4aa3ff;
  border-radius: 4px;
  padding: 2px 6px;
  font: 600 11px/1 system-ui, sans-serif;
  white-space: nowrap;
  box-shadow: 0 1px 3px rgba(0,0,0,0.5);
  cursor: pointer;
}
.pin-query-pin:hover { background: rgba(40, 60, 90, 0.95); }
.pin-query-id {
  background: #4aa3ff; color: #001a2e;
  border-radius: 50%;
  width: 14px; height: 14px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px;
}
.pin-query-val { color: #d8e8ff; }

/* Diag perf rows — one line per recent load cycle. */
.diag-perf { display: flex; flex-direction: column; gap: 2px; font-size: 11px; }
.diag-perf-row { display: flex; gap: 8px; }
.diag-perf-ts { color: rgba(255,255,255,0.5); flex: 0 0 64px; }
.diag-perf-body { color: rgba(255,255,255,0.85); }

.radar-status {
  padding: 0.18rem 0.55rem;
  border-radius: 0.35rem;
  font-size: 0.75rem;
  background: rgba(255, 255, 255, 0.06);
  color: #9aa6b3;
}
.radar-status.ok    { background: rgba(34, 197, 94, 0.18); color: #4ade80; }
.radar-status.warn  { background: rgba(242, 193, 78, 0.18); color: #f2c14e; }
.radar-status.error { background: rgba(239, 68, 68, 0.22); color: #fca5a5; }

/* Build version chip — confirms which server build the UI is talking
   to. Amber (.warn) when a feature module failed to import server-side
   or the version fetch itself failed (likely cache / proxy issue). */
.radar-version {
  display: inline-block;
  padding: 0.18rem 0.5rem;
  border-radius: 0.35rem;
  font: 600 0.7rem/1 ui-monospace, Menlo, Consolas, monospace;
  background: rgba(74, 163, 255, 0.18);
  color: #6ab3ff;
  border: 1px solid rgba(74, 163, 255, 0.4);
  cursor: pointer;
  user-select: all;
}
.radar-version:hover { background: rgba(74, 163, 255, 0.28); color: #fff; }
.radar-version.warn {
  background: rgba(242, 193, 78, 0.22);
  color: #f2c14e;
  border-color: rgba(242, 193, 78, 0.5);
  animation: version-warn-pulse 2s ease-in-out infinite;
}
@keyframes version-warn-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(242, 193, 78, 0); }
  50%      { box-shadow: 0 0 0 3px rgba(242, 193, 78, 0.35); }
}

.radar-tilts {
  display: inline-flex;
  background: #0e1c2a;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.35rem;
  overflow: hidden;
}
.radar-tilts button {
  appearance: none;
  background: transparent;
  color: #9aa6b3;
  border: none;
  padding: 0.28rem 0.55rem;
  font-size: 0.74rem;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  cursor: pointer;
}
.radar-tilts button + button { border-left: 1px solid rgba(255, 255, 255, 0.08); }
.radar-tilts button:hover:not(:disabled) { background: rgba(255, 255, 255, 0.05); color: #e7ecf2; }
.radar-tilts button.active {
  background: rgba(242, 193, 78, 0.22);
  color: #f2c14e;
  font-weight: 600;
}
.radar-tilts button:disabled { opacity: 0.35; cursor: not-allowed; }

.radar-motion {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.18rem 0.45rem;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.35rem;
  background: rgba(242, 193, 78, 0.06);
}

/* Map fills entire main area; panels float on top. */
.radar-main {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}
.radar-map { width: 100%; height: 100%; background: #0a1420; }
.leaflet-container { background: #0a1420; }

/* Leaflet's default zoom control moves to bottom-right in JS; this
 * just ensures the bottom-right corner has comfortable spacing. */
.leaflet-bottom.leaflet-right { margin-bottom: 16px; margin-right: 16px; }

/* ─── Glass panels ────────────────────────────────────────────────── */
.glass-panel {
  position: absolute;
  z-index: 500;
  display: flex;
  flex-direction: column;
  background: rgba(12, 22, 34, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 0.7rem;
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45);
  overflow: hidden;
  /* Slight scale-on-drag feedback handled below. */
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}
/* The `display: flex` above overrides the HTML5 `hidden` attribute's
 * default `display: none`. Without this explicit override, calling
 * `panel.hidden = true` from JS sets the attribute but the panel
 * stays visible — operator hit this 2026-06-11 reporting "X buttons
 * don't close the floating menus." Author CSS wins over the UA
 * stylesheet's `[hidden]` rule, so we have to re-assert here. */
.glass-panel[hidden] { display: none !important; }
.glass-panel.dragging {
  box-shadow: 0 12px 48px rgba(0, 0, 0, 0.65);
  cursor: grabbing;
}

/* Drag handle — header bar with grip and panel title. */
.gp-handle {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.55rem;
  cursor: grab;
  user-select: none;
  background: rgba(255, 255, 255, 0.03);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  flex: 0 0 auto;
}
.gp-handle:active { cursor: grabbing; }
.gp-close-x {
  appearance: none;
  background: transparent;
  border: 1px solid transparent;
  color: rgba(255, 255, 255, 0.55);
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 0.3rem;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  margin-left: auto;
  flex: 0 0 auto;
}
.gp-close-x:hover {
  background: rgba(255, 80, 80, 0.18);
  border-color: rgba(255, 80, 80, 0.45);
  color: #fca5a5;
}
.gp-grip {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  color: rgba(255, 255, 255, 0.35);
  font-size: 0.85rem;
  letter-spacing: -0.1em;
  flex: 0 0 auto;
}
.gp-title {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #cdd5dd;
}

/* Default positions — overridden by inline left/top from saved drag state. */
/* Default panel positions. Panel-info and panel-cell-info both live
 * on the right edge, but cell-info needs to clear info's actual
 * rendered height (which auto-grows based on site name length +
 * freshness tag). Cap info to a fixed slice of the viewport and
 * anchor cell-info via `bottom` so they always stack without
 * overlapping regardless of content length. */
#panel-products  { top: 12px; left: 12px; width: 188px; max-height: calc(100% - 24px); }
#panel-loop      { top: 12px; left: calc(50% - 200px); width: 400px; }
#panel-info      { top: 12px; right: 12px; width: 280px; max-height: 50vh; }
#panel-cell-info { top: calc(50vh + 24px); right: 12px; width: 280px; max-height: calc(50vh - 36px); }
/* Legend panel — thin right-side dock between the map and the Info
 * panel. Default position is right edge above the cell info; can be
 * dragged anywhere on the screen like every other glass-panel. */
#panel-legend    { top: 12px; right: 300px; width: 132px; max-height: calc(100% - 24px); }

/* Horizontal layout for the Loop panel — controls in a row below
 * the handle, scrubber inline. */
.glass-panel--horiz .gp-loop-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.55rem;
}

.gp-section {
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.gp-section:last-child { border-bottom: none; }

.gp-heading {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #9aa6b3;
  margin: 0 0 0.35rem 0;
}

/* Products: vertical stack */
.gp-products { display: flex; flex-direction: column; gap: 0.18rem; }
.gp-products button {
  appearance: none;
  background: rgba(255, 255, 255, 0.04);
  color: #cdd5dd;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 0.4rem;
  padding: 0.32rem 0.55rem;
  font-size: 0.82rem;
  text-align: left;
  cursor: pointer;
  font-family: ui-monospace, Menlo, Consolas, monospace;
}
.gp-products button:hover {
  background: rgba(255, 255, 255, 0.08);
  color: #e7ecf2;
}
.gp-products button.active {
  background: rgba(242, 193, 78, 0.18);
  border-color: rgba(242, 193, 78, 0.45);
  color: #f2c14e;
  font-weight: 700;
}
/* Pending state — applied the moment a product is clicked, cleared
 * when the product is actually displayed. Dull-red wash so the
 * operator can tell "this one isn't ready yet" without staring at
 * the stale image hoping for a change. Subtle so it doesn't fight
 * the active-state highlight. */
.gp-products button.pending {
  background: rgba(255, 90, 90, 0.18);
  border-color: rgba(255, 90, 90, 0.45);
  color: #ffb3b3;
  font-style: italic;
  cursor: progress;
}
.gp-products button.pending.active {
  background: rgba(255, 90, 90, 0.32);
  color: #ffd0d0;
}

/* Background-prefetch status indicator — small dot in the top-right
 * corner of each product button showing whether the server has a
 * cached render ready, the queue is working on it, it failed, or
 * the operator has disabled the category. Subtle so it never fights
 * the chip's primary readability. */
.gp-products button {
  position: relative;
}
.gp-products button.proc-ready::after,
.gp-products button.proc-queued::after,
.gp-products button.proc-processing::after,
.gp-products button.proc-error::after,
.gp-products button.proc-disabled::after {
  content: '';
  position: absolute;
  top: 4px; right: 4px;
  width: 6px; height: 6px;
  border-radius: 50%;
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
}
.gp-products button.proc-ready::after      { background: #22c55e; }
.gp-products button.proc-queued::after     { background: #f59e0b; }
.gp-products button.proc-processing::after {
  background: #f59e0b;
  animation: prefetch-pulse 1s ease-in-out infinite;
}
.gp-products button.proc-error::after      { background: #ef4444; }
.gp-products button.proc-disabled::after   { background: #6b7280; }
@keyframes prefetch-pulse {
  0%, 100% { opacity: 0.4; }
  50%      { opacity: 1.0; }
}
.gp-products button.proc-disabled {
  opacity: 0.55;
}

/* ─── Product categories (Phase 1 of left-panel rework) ───────────── */

/* Categorized product list — one <details> per category. Operator-
 * collapsed state persists in localStorage. Open categories show their
 * button grid; closed ones show only the summary so the panel doesn't
 * scroll forever during outbreaks. */
.gp-products-cats {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.prod-cat {
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 0.35rem;
  background: rgba(255, 255, 255, 0.02);
  overflow: hidden;
}
.gp-cat-summary {
  list-style: none;
  cursor: pointer;
  padding: 0.32rem 0.55rem;
  font-size: 0.70rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #9aa6b3;
  background: rgba(255, 255, 255, 0.03);
  display: flex;
  align-items: center;
  gap: 0.4rem;
  user-select: none;
}
.gp-cat-summary::-webkit-details-marker { display: none; }
.gp-cat-summary::before {
  content: '▸';
  font-size: 0.6rem;
  opacity: 0.6;
  transition: transform 0.12s ease;
}
.prod-cat[open] > .gp-cat-summary::before { transform: rotate(90deg); }
.gp-cat-summary:hover { color: #d8e0ec; background: rgba(255, 255, 255, 0.06); }
.prod-cat-count {
  margin-left: auto;
  font-size: 0.62rem;
  opacity: 0.55;
  font-weight: 600;
}

/* Process-mode header — Auto / Manual selector at the top of the
 * Products panel + a small "Prefetching N…" status while the queue
 * is working. */
.prod-mode-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0 8px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  margin-bottom: 6px;
}
.prod-mode {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: #aab8c8;
  font-weight: 600;
}
.prod-mode select {
  background: rgba(255, 255, 255, 0.06);
  color: #e8eef8;
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 3px;
  font-size: 11px;
  padding: 2px 4px;
}
.prefetch-status {
  margin-left: auto;
  font-size: 10.5px;
  color: #f59e0b;
  font-weight: 600;
  font-style: italic;
}

/* Category disabled — operator turned this category off. Dim the
 * whole block + show the count grayed. */
.prod-cat.cat-disabled {
  opacity: 0.55;
}
.prod-cat.cat-disabled .gp-cat-name {
  text-decoration: line-through;
  color: #6b7892;
}

/* Per-category enable checkbox in the summary. Compact. */
.cat-enable-toggle {
  flex-shrink: 0;
  width: 13px;
  height: 13px;
  margin: 0;
  accent-color: #22c55e;
  cursor: pointer;
}
.gp-cat-name { flex: 0 1 auto; }

/* Baseline 3-column compact grid — short codes only (BR/BV/SW/etc.). */
.prod-grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.18rem;
  padding: 0.3rem 0.4rem 0.4rem;
}
.prod-grid-3 button {
  text-align: center;
  font-size: 0.74rem;
  padding: 0.28rem 0.2rem;
  line-height: 1.1;
}
/* Derived/specialized products — full-width labeled buttons. */
.prod-list {
  display: flex;
  flex-direction: column;
  gap: 0.18rem;
  padding: 0.3rem 0.4rem 0.4rem;
}

/* ─── Legend panel (right-docked, vertical) ───────────────────────── */

/* The Legend panel header gets a Details (ⓘ) button that toggles the
 * Product Details section in the Info panel. */
.glass-panel--legend .gp-handle {
  gap: 0.35rem;
}
.glass-panel--legend #btn-legend-details {
  font-size: 0.85rem;
  padding: 0 0.3rem;
}
.glass-panel--legend #btn-legend-details.active {
  background: rgba(95, 177, 255, 0.22);
  border-color: rgba(95, 177, 255, 0.55);
  color: #aee0ff;
}
/* Vertical-orientation legend — stacked rows in a single thin column.
 * Each cell is "swatch · label" on one line so the column reads top-
 * down through the value range. */
.gp-legend--vertical {
  display: flex;
  flex-direction: column-reverse;     /* highest values at top, like a thermometer */
  gap: 0.12rem;
  overflow-y: auto;
  max-height: calc(100vh - 200px);
}
.gp-legend--vertical .gp-legend-cell {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.18rem 0.3rem;
  border-radius: 0.25rem;
  font-size: 0.72rem;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.03);
}
.gp-legend--vertical .gp-legend-cell:hover {
  background: rgba(255, 255, 255, 0.08);
}
.gp-legend--vertical .gp-legend-cell.disabled {
  opacity: 0.35;
  text-decoration: line-through;
}
.gp-legend--vertical .swatch {
  width: 16px;
  height: 16px;
  border-radius: 3px;
  flex-shrink: 0;
  border: 1px solid rgba(255, 255, 255, 0.15);
}
.gp-legend--vertical .label {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  color: #d8e0ec;
}

/* ─── Product Details (educational section in the Info panel) ─────── */

.gp-product-details {
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.gp-product-details-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.4rem;
}
#product-details-title {
  margin: 0;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-transform: none;
  color: #e8eef8;
}
.pd-empty {
  color: #8aa0bc;
  font-style: italic;
  font-size: 0.78rem;
  margin: 0 0 0.3rem 0;
}
.pd-hint {
  color: #6b7892;
  font-size: 0.72rem;
  margin: 0;
}
.pd-what {
  font-size: 0.82rem;
  line-height: 1.4;
  color: #e8eef8;
  margin: 0 0 0.55rem 0;
}
.pd-block { margin-bottom: 0.5rem; }
.pd-h {
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #ffb84d;
  font-weight: 700;
  margin-bottom: 0.18rem;
}
.pd-list {
  margin: 0;
  padding-left: 1.05rem;
  font-size: 0.75rem;
  line-height: 1.4;
  color: #d8e0ec;
}
.pd-list li { margin-bottom: 0.12rem; }
.pd-p {
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.4;
  color: #d8e0ec;
}
.pd-p.pd-limits {
  color: #b8a886;
  font-style: italic;
}

/* ─── Responsive: smaller monitors / windowed mode ────────────────── */

@media (max-width: 1400px) {
  #panel-products  { width: 168px; }
  #panel-info      { width: 248px; }
  #panel-cell-info { width: 248px; }
  #panel-legend    { right: 268px; width: 120px; }
  .prod-grid-3 button { font-size: 0.72rem; }
}
@media (max-width: 1100px) {
  #panel-products  { width: 152px; }
  #panel-info      { width: 220px; max-height: 56vh; }
  #panel-cell-info { width: 220px; top: calc(56vh + 24px); max-height: calc(44vh - 36px); }
  #panel-legend    { right: 240px; width: 110px; }
  #panel-loop      { left: 50%; transform: translateX(-50%); width: min(380px, calc(100% - 380px)); }
  .gp-cat-summary { font-size: 0.66rem; padding: 0.26rem 0.45rem; }
  .prod-grid-3 button { font-size: 0.70rem; padding: 0.24rem 0.15rem; }
}
@media (max-width: 900px) {
  /* Tight layout — legend tucks under products on the left so the
   * Info panel can still own the right edge alone. Operator can still
   * drag any panel anywhere; this just changes the default position. */
  #panel-products  { width: 140px; }
  #panel-legend    { left: 12px; top: auto; bottom: 12px; right: auto; width: 140px; max-height: 40vh; }
  #panel-info      { width: 200px; }
  #panel-cell-info { width: 200px; }
}

/* Toolbar group separator — thin vertical line between groups of
 * related toggles in the top toolbar (moments / overlays / utilities).
 * Visual grouping only; no behavior. */
.radar-tb-sep {
  display: inline-block;
  width: 1px;
  height: 22px;
  margin: 0 4px;
  background: rgba(255, 255, 255, 0.15);
  vertical-align: middle;
}

/* ─── Tornado Tuning flyout ──────────────────────────────────────── */
#panel-tornado-tuning { top: 56px; right: 300px; width: 280px; }
#panel-tornado-tuning .tune-hint {
  margin: 0 0 8px 0;
  font-size: 11px;
  font-style: italic;
  color: #aab8c8;
  line-height: 1.4;
}
.tune-block {
  margin-bottom: 12px;
  padding: 6px 8px;
  background: rgba(255, 255, 255, 0.03);
  border-radius: 4px;
  border-left: 2px solid rgba(255, 90, 90, 0.5);
}
.tune-h {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: #ffb3b3;
  margin-bottom: 4px;
}
.tune-row {
  display: grid;
  grid-template-columns: 22px 1fr 40px;
  gap: 6px;
  align-items: center;
  margin-bottom: 3px;
}
.tune-row .tune-lbl {
  font-size: 10.5px;
  color: #8aa0bc;
  font-weight: 600;
  text-align: right;
}
.tune-row input[type=range] {
  accent-color: #ff8a3d;
}
.tune-val {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 11px;
  font-weight: 700;
  color: #ffd09a;
  text-align: right;
}
.tune-tip {
  margin-top: 3px;
  font-size: 10.5px;
  color: #8aa0bc;
  font-style: italic;
  line-height: 1.35;
}

/* Make the NROT row stretch to two columns since there's no lo/hi
 * label — keeps the slider as wide as the lo/hi sliders below. */
#tune-nrot-scale { grid-column: 1 / 3; }
#tune-nrot-scale-val { grid-column: 3; }

/* Site-kind badge (TDWR sites get a small tag next to the ICAO in
 * the Info panel so the operator immediately knows it's a TDWR site
 * with 90 km coverage, not a NEXRAD with 230 km). */
.site-kind {
  display: inline-block;
  background: rgba(95, 177, 255, 0.18);
  color: #aedaff;
  border: 1px solid rgba(95, 177, 255, 0.45);
  border-radius: 3px;
  padding: 0 4px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  margin: 0 4px;
  vertical-align: middle;
}
.site-kind-tdwr {
  background: rgba(255, 184, 77, 0.18);
  color: #ffd09a;
  border-color: rgba(255, 184, 77, 0.45);
}

/* ─── Telestrator (operator drawing layer) ───────────────────────── */

/* Default panel position — top-right above the Info panel. Draggable
 * like every other glass-panel. */
#panel-telestrator { top: 56px; right: 12px; width: 260px; }

/* Crosshair cursor whenever drawing mode is active, so the operator
 * gets a clear "you're in draw mode" signal. */
body.telestrator-drawing #radar-map { cursor: crosshair !important; }

/* Tool palette layout — buttons in rows, color/style pickers compact. */
.tlstr-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 6px;
}
.tlstr-row.tlstr-actions { justify-content: space-between; gap: 6px; }
.tlstr-tool {
  flex: 1 1 60px;
  min-width: 50px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.10);
  color: #cdd5dd;
  border-radius: 3px;
  padding: 4px 6px;
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
}
.tlstr-tool:hover { background: rgba(255, 255, 255, 0.10); color: #e7ecf2; }
.tlstr-tool.active {
  background: rgba(95, 177, 255, 0.22);
  border-color: rgba(95, 177, 255, 0.55);
  color: #aee0ff;
}
.tlstr-fronts .tlstr-tool { flex: 1 1 40px; min-width: 38px; font-size: 11px; }
.tlstr-line-opts {
  align-items: center;
  font-size: 11px;
  color: #aab8c8;
}
.tlstr-color, .tlstr-style {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 1;
}
.tlstr-color input[type=color] {
  width: 30px; height: 22px;
  padding: 0; border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 3px;
  background: transparent;
  cursor: pointer;
}
.tlstr-style select {
  background: rgba(255, 255, 255, 0.05);
  color: #cdd5dd;
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 3px;
  padding: 2px 4px;
  font-size: 11px;
  flex: 1;
}
.tlstr-actions button {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.15);
  color: #cdd5dd;
  border-radius: 3px;
  padding: 4px 8px;
  font-size: 11px;
  cursor: pointer;
}
.tlstr-actions button:hover { background: rgba(255, 255, 255, 0.10); color: #fff; }
#btn-tlstr-clear:hover { background: #ff5252; border-color: #ff5252; color: #fff; }
.tlstr-hint {
  margin: 6px 0 0 0;
  color: #8aa0bc;
  font-size: 11px;
  font-style: italic;
  line-height: 1.4;
}

/* Freehand toggle in the Telestrator palette. Checkbox + label inline. */
.tlstr-freehand {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: #d8e0ec;
  cursor: pointer;
  user-select: none;
  flex: 1;
}
.tlstr-freehand input[type=checkbox] {
  accent-color: #5fb1ff;
  cursor: pointer;
}

/* Pressure markers — circle with H / L letter. Color follows surface-
 * analysis convention: blue H (high), red L (low). */
.tlstr-marker > div {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: rgba(20, 28, 40, 0.85);
  display: flex; align-items: center; justify-content: center;
  font-weight: 900;
  font-size: 16px;
  font-family: 'Georgia', serif;
  text-shadow: 0 0 4px rgba(0, 0, 0, 0.8);
  border: 2px solid;
}
.tlstr-press-H { color: #6ec6ff; border-color: #6ec6ff !important;
                 box-shadow: 0 0 10px rgba(110, 198, 255, 0.6); }
.tlstr-press-L { color: #ff5252; border-color: #ff5252 !important;
                 box-shadow: 0 0 10px rgba(255, 82, 82, 0.6); }
.tlstr-marker.tlstr-marker-H > div { border-color: #6ec6ff; }
.tlstr-marker.tlstr-marker-L > div { border-color: #ff5252; }

/* Text labels — operator-typed annotations. */
.tlstr-text .tlstr-text-inner {
  display: inline-block;
  background: rgba(20, 28, 40, 0.78);
  color: #ffeaa3;
  border: 1px solid rgba(255, 234, 163, 0.45);
  padding: 3px 6px;
  border-radius: 3px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
}

/* ─── Resizable panel handle (used by panel-cell-info) ────────────── */

.gp-resize-handle {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 8px;
  cursor: ns-resize;
  background: linear-gradient(
    to bottom,
    transparent 0%,
    rgba(255, 255, 255, 0.04) 50%,
    rgba(255, 255, 255, 0.12) 100%
  );
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.gp-resize-handle:hover {
  background: linear-gradient(
    to bottom,
    transparent 0%,
    rgba(95, 177, 255, 0.10) 50%,
    rgba(95, 177, 255, 0.28) 100%
  );
}
/* Ensure resizable panels can position the handle absolutely + have
 * room for the handle at the bottom. */
#panel-cell-info {
  position: absolute;
  padding-bottom: 8px;
}

/* ─── Error log toggle + panel ────────────────────────────────────── */

#btn-errors {
  background: rgba(255, 90, 90, 0.18);
  border-color: rgba(255, 90, 90, 0.50);
  color: #ffb3b3;
}
#btn-errors.has-errors {
  animation: errors-pulse 1.6s ease-in-out infinite;
}
@keyframes errors-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 90, 90, 0.5); }
  50%      { box-shadow: 0 0 8px 2px rgba(255, 90, 90, 0.6); }
}
#btn-errors #errors-count {
  display: inline-block;
  margin-left: 4px;
  background: rgba(255, 60, 60, 0.55);
  color: #fff;
  border-radius: 8px;
  min-width: 16px;
  padding: 0 4px;
  font-size: 10.5px;
  font-weight: 700;
  text-align: center;
}
#panel-errors { top: 56px; right: 12px; width: 380px; max-height: 50vh; }
#panel-tropical { top: 56px; right: 12px; width: 420px; max-height: 60vh; overflow: auto; }
#panel-profile { top: 56px; left: 220px; width: 380px; }
.errors-list {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 11px;
  max-height: calc(50vh - 70px);
  overflow-y: auto;
}
.errors-empty {
  padding: 8px;
  color: #8aa0bc;
  font-style: italic;
  text-align: center;
}
.errors-row {
  display: grid;
  grid-template-columns: 70px 1fr;
  gap: 8px;
  padding: 4px 6px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  line-height: 1.35;
}
.errors-row:last-child { border-bottom: none; }
.errors-ts {
  color: #8aa0bc;
  font-size: 10.5px;
  font-weight: 600;
}
.errors-msg {
  color: #ffc4c4;
  word-break: break-word;
}

/* ─── Diagnostics panel ─────────────────────────────────────────── */

#panel-diag { top: 56px; right: 400px; width: 360px; max-height: 70vh; }
.diag-body { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11px; }
.diag-state {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 2px 8px;
  padding: 6px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  margin-bottom: 8px;
}
.diag-row { display: contents; }
.diag-k { color: #8aa0bc; }
.diag-v { color: #d8e0ec; }
.diag-v.diag-bad { color: #ff7a7a; font-weight: 700; }
.diag-h {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #ffb84d;
  margin: 8px 0 4px;
}
.diag-frames {
  max-height: 180px;
  overflow-y: auto;
  background: rgba(0, 0, 0, 0.25);
  border-radius: 3px;
  padding: 4px 6px;
}
.diag-frame { color: #aab8c8; line-height: 1.35; }
.diag-frame.diag-frame-cur {
  color: #ffd96b;
  font-weight: 700;
}
.diag-hint {
  margin: 8px 0 0;
  font-size: 10.5px;
  color: #aab8c8;
  font-style: italic;
  line-height: 1.4;
}
.diag-error {
  color: #ff7a7a;
  font-weight: 700;
  padding: 8px;
}

/* ─── Selected cell drill-down panel (Phase 4a.1) ─────────────────── */

#cell-info-stats {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.18rem 0.7rem;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 0.78rem;
}
#cell-info-stats .lbl { color: #9aa6b3; }
#cell-info-stats .val { color: #e7ecf2; font-weight: 600; }
#cell-info-stats .val.rotation-strong  { color: #ff5555; }
#cell-info-stats .val.rotation-tornadic { color: #ff66ff; }
/* SI-01 (Updraft Vigor) class colors mirror the per-cell tooltip
 * palette in cellsLayer.js — same color → same meaning whether the
 * operator reads it on the map or in the drilldown panel. */
#cell-info-stats .val.si-explosive     { color: #ffeb3b; font-weight: 700; }
#cell-info-stats .val.si-intensifying  { color: #7eff7e; }
#cell-info-stats .val.si-steady        { color: #9e9e9e; }
#cell-info-stats .val.si-weakening     { color: #ff9800; }
#cell-info-stats .val.si-collapsing    { color: #ff5555; font-weight: 700; }
#cell-info-stats .val.si-na            { color: #6b7280; }
/* Hail + Bomb classes — match the on-map glyph palette so the panel
 * and overlay read as one signal. */
#cell-info-stats .val.hail-marginal    { color: #c0c8d0; }
#cell-info-stats .val.hail-likely      { color: #ffb74d; font-weight: 700; }
#cell-info-stats .val.hail-large       { color: #ff5555; font-weight: 700; }
#cell-info-stats .val.hail-significant { color: #ff66ff; font-weight: 700; }
#cell-info-stats .val.hail-none        { color: #6b7280; }
#cell-info-stats .val.hail-na          { color: #6b7280; }
#cell-info-stats .val.bomb-imminent    { color: #ff7a3d; font-weight: 700; }
#cell-info-stats .val.bomb-watching    { color: #ffb74d; }
#cell-info-stats .val.bomb-none        { color: #6b7280; }
#cell-info-stats .val.bomb-na          { color: #6b7280; }
/* MESO-01 supercell archetype — green LP (visible/discrete), amber
 * Classic, magenta HP (rain-wrapped/dangerous). */
#cell-info-stats .val.meso-LP          { color: #7eff7e; font-weight: 700; }
#cell-info-stats .val.meso-Classic     { color: #f2c14e; font-weight: 700; }
#cell-info-stats .val.meso-HP          { color: #ff66ff; font-weight: 700; }
#cell-info-stats .val.meso-na          { color: #6b7280; }
/* SI-02 anvil divergence — operational NWS bench (40/60/80 m/s).
 * Color escalates with venting strength so the operator's eye lands
 * on supercell-class updrafts when scanning the panel. */
#cell-info-stats .val.div-routine      { color: #c0c8d0; }
#cell-info-stats .val.div-organized    { color: #7eff7e; font-weight: 700; }
#cell-info-stats .val.div-strong       { color: #ffb74d; font-weight: 700; }
#cell-info-stats .val.div-extreme      { color: #ff66ff; font-weight: 700; }
#cell-info-stats .val.div-collapsing   { color: #ff5555; font-weight: 700; }
#cell-info-stats .val.div-none         { color: #6b7280; }

/* META-02 Storm Personality — color by threat character. Hail Beast
 * and Wind Demon are the "headline damage" classes and get hot
 * colors; Spinner is rotation-aware (magenta to match the rotation
 * palette); Flood Engine reads water-blue; Pulse Goblin reads neutral
 * gray since it's the "nothing dramatic" default. */
#cell-info-stats .val.pers-hail_beast    { color: #ff5555; font-weight: 700; }
#cell-info-stats .val.pers-wind_demon    { color: #ff7a3d; font-weight: 700; }
#cell-info-stats .val.pers-spinner       { color: #ff66ff; font-weight: 700; }
#cell-info-stats .val.pers-flood_engine  { color: #5fb1ff; font-weight: 700; }
#cell-info-stats .val.pers-pulse_goblin  { color: #c0c8d0; }
#cell-info-stats .val.pers-na            { color: #6b7280; }

/* NROT — operator-familiar 0-10 normalized rotation. Colors mirror
 * the rotation palette so NROT and Couplet read the same visual at a
 * glance, just on a different scale. */
#cell-info-stats .val.nrot-background    { color: #9aa6b3; }
#cell-info-stats .val.nrot-notable       { color: #f2c14e; }
#cell-info-stats .val.nrot-strong        { color: #ff7a3d; font-weight: 700; }
#cell-info-stats .val.nrot-tornadic      { color: #ff5555; font-weight: 700; }
#cell-info-stats .val.nrot-tvs           { color: #ff66ff; font-weight: 700; }
#cell-info-stats .val.nrot-na            { color: #6b7280; }

/* PTDS — Probability of Tornado Debris Signature. Pulses on
 * "observed" since a confirmed TDS is the most urgent operator
 * signal we generate. */
#cell-info-stats .val.ptds-none      { color: #9aa6b3; }
#cell-info-stats .val.ptds-possible  { color: #f2c14e; }
#cell-info-stats .val.ptds-likely    { color: #ff5555; font-weight: 700; }
#cell-info-stats .val.ptds-observed  {
  color: #ff66ff;
  font-weight: 700;
  animation: ptds-observed-pulse 1.2s ease-in-out infinite;
}
#cell-info-stats .val.ptds-na        { color: #6b7280; }
@keyframes ptds-observed-pulse {
  0%, 100% { opacity: 0.85; }
  50%      { opacity: 1.0; }
}

/* VIL Density — color escalates with column-mass concentration.
 * Severe (≥4) gets the same magenta as significant hail because
 * that's typically what it correlates with operationally. */
#cell-info-stats .val.vd-low       { color: #9aa6b3; }
#cell-info-stats .val.vd-moderate  { color: #ffb74d; }
#cell-info-stats .val.vd-high      { color: #ff5555; font-weight: 700; }
#cell-info-stats .val.vd-severe    { color: #ff66ff; font-weight: 700; }
#cell-info-stats .val.vd-na        { color: #6b7280; }

/* TOR-03 Tornadogenesis Ladder — state color escalates from inactive
 * through debris. 'debris' state pulses to match the PTDS-observed
 * pulse since both signal the same operational urgency. */
#cell-info-stats .val.ladder-inactive    { color: #6b7280; }
#cell-info-stats .val.ladder-seeded      { color: #9aa6b3; }
#cell-info-stats .val.ladder-organizing  { color: #f2c14e; }
#cell-info-stats .val.ladder-mature      { color: #ff7a3d; font-weight: 700; }
#cell-info-stats .val.ladder-tornadic    { color: #ff5555; font-weight: 700; }
#cell-info-stats .val.ladder-debris      {
  color: #ff66ff;
  font-weight: 700;
  animation: ptds-observed-pulse 1.2s ease-in-out infinite;
}
#cell-info-stats .val.ladder-na          { color: #6b7280; }

/* POSH (Witt 1998) — Probability of Severe Hail tiers. Bench:
 *   < 30%  unlikely      gray
 *   30-50  marginal      yellow
 *   50-70  possible      orange
 *   70-90  likely        red
 *   ≥ 90   extreme       magenta + pulse */
#cell-info-stats .val.posh-low        { color: #9aa6b3; }
#cell-info-stats .val.posh-marginal   { color: #f2c14e; }
#cell-info-stats .val.posh-possible   { color: #ff7a3d; font-weight: 700; }
#cell-info-stats .val.posh-likely     { color: #ff5555; font-weight: 700; }
#cell-info-stats .val.posh-extreme    {
  color: #ff66ff;
  font-weight: 700;
  animation: ptds-observed-pulse 1.2s ease-in-out infinite;
}
#cell-info-stats .val.posh-na         { color: #6b7280; }

/* Warning-popup threat badges. Each hazard rendered as a colored
   pill so the operator's eye lands on tornado / hail / wind tags
   without parsing the description block. */
.radar-warning-popup .rwp-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 6px 0;
}
.radar-warning-popup .rwp-badge {
  display: inline-block;
  padding: 2px 7px;
  font-size: 11px;
  font-weight: 700;
  border-radius: 10px;
  border: 1px solid;
  white-space: nowrap;
  background: rgba(18, 26, 38, 0.85);
}
.radar-warning-popup .rwp-badge-tornado-observed {
  border-color: #ff66ff;
  color: #ff66ff;
  animation: badge-tornado-pulse 1.3s ease-in-out infinite;
}
.radar-warning-popup .rwp-badge-tornado {
  border-color: #ff5555;
  color: #ff5555;
}
.radar-warning-popup .rwp-badge-hail {
  border-color: #ffb74d;
  color: #ffb74d;
}
.radar-warning-popup .rwp-badge-wind {
  border-color: #ff7a3d;
  color: #ff7a3d;
}
.radar-warning-popup .rwp-badge-damage      { border-color: #ffb74d; color: #ffb74d; }
.radar-warning-popup .rwp-badge-damage-dest { border-color: #ff5555; color: #ff5555; }
.radar-warning-popup .rwp-badge-damage-cat  {
  border-color: #ff66ff;
  color: #ff66ff;
  animation: badge-tornado-pulse 1.3s ease-in-out infinite;
}
.radar-warning-popup .rwp-badge-flood {
  border-color: #5fb1ff;
  color: #5fb1ff;
}
@keyframes badge-tornado-pulse {
  0%, 100% { opacity: 0.85; }
  50%      { opacity: 1.0; }
}

/* HAIL-03 forward-toss landing marker. Smaller + slightly faded vs
 * the primary hail glyph at the echo core so the operator can tell
 * "current core" from "projected landing" without confusion. Severity
 * classes reuse the same color tokens as the primary marker. */
.radar-hail-toss-marker {
  pointer-events: none;
}
.radar-hail-toss-marker .hail-toss-glyph {
  font-size: 14px;
  text-align: center;
  text-shadow: 0 0 3px rgba(0, 0, 0, 0.9);
  opacity: 0.85;
}
.radar-hail-toss-marker.hail-likely      .hail-toss-glyph { color: #ffb74d; }
.radar-hail-toss-marker.hail-large       .hail-toss-glyph { color: #ff5555; }
.radar-hail-toss-marker.hail-significant .hail-toss-glyph {
  color: #ff66ff;
  animation: hail-toss-pulse 1.5s ease-in-out infinite;
}
@keyframes hail-toss-pulse {
  0%, 100% { opacity: 0.7; }
  50%      { opacity: 1.0; }
}

/* SI-01 glyphs on cell labels — bright color so they pop above the
 * radar fill, weight to make the arrow legible at small sizes. */
.radar-cell-label .si-explosive    { color: #ffeb3b; font-weight: 900; }
.radar-cell-label .si-intensifying { color: #7eff7e; font-weight: 700; }
.radar-cell-label .si-collapsing   { color: #ff5555; font-weight: 700; }

/* TVS marker — inverted magenta triangle sized to read from a
 * full-screen overview without obscuring the underlying cell.
 * Pulse animation grabs the eye during an active tornado warning;
 * shadow keeps it legible against bright reflectivity. */
.radar-tvs-marker .tvs-glyph {
  color: #ff00ff;
  font-size: 22px;
  line-height: 22px;
  text-align: center;
  text-shadow: 0 0 4px #000, 0 0 2px #000;
  font-weight: 900;
  animation: tvs-pulse 1.2s ease-in-out infinite;
  pointer-events: none;
  user-select: none;
}
@keyframes tvs-pulse {
  0%, 100% { transform: scale(1.00); opacity: 1.0; }
  50%      { transform: scale(1.18); opacity: 0.75; }
}

/* Forecast dots — small filled circle at each +10/+20/+30 min
 * projection point, with the time offset rendered just to the right.
 * Background uses the cell's intensity color (set inline by the JS
 * builder) so a chain of dots reads as belonging to one cell. */
.radar-forecast-dot {
  pointer-events: none;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 10px;
  font-weight: 600;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  white-space: nowrap;
}
.radar-forecast-dot .fc-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.85);
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.7);
}
.radar-forecast-dot .fc-label {
  color: #f2c14e;
  text-shadow: 0 0 3px #000, 0 0 1px #000;
}

/* Hail marker — hex glyph color-coded by class. Anchored below the
 * label position so it doesn't collide with the dBZ text above the
 * cell. Stroke + shadow keep it readable against bright cores. */
.radar-hail-marker .hail-glyph {
  font-size: 20px;
  line-height: 22px;
  font-weight: 900;
  text-align: center;
  text-shadow: 0 0 4px #000, 0 0 2px #000;
  pointer-events: none;
  user-select: none;
}
.radar-hail-marker.hail-likely      .hail-glyph { color: #ffb74d; }
.radar-hail-marker.hail-large       .hail-glyph { color: #ff5555; font-size: 23px; }
.radar-hail-marker.hail-significant .hail-glyph {
  color: #ff66ff; font-size: 26px;
  animation: tvs-pulse 1.6s ease-in-out infinite;
}

/* Follow button in the cell-info header — inactive is the same glassy
 * pill as other mini buttons; active flips to the amber accent so the
 * operator can tell at a glance that auto-pan is engaged. */
#btn-cell-follow.active {
  background: rgba(242, 193, 78, 0.18);
  color: #f2c14e;
  border-color: rgba(242, 193, 78, 0.45);
}

/* Toolbar-pinned cell summary — severity counts at a glance.
 * Inline-flex so chips pack tightly next to the status pill without
 * disturbing the existing toolbar grid. Each chip carries its own
 * severity color so the operator's eye lands on tornadic > meso >
 * hail > explosive > intensifying in priority order. */
.radar-cell-summary {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: 8px;
  font-size: 0.78rem;
  font-family: ui-monospace, Menlo, Consolas, monospace;
}
.radar-cell-summary .cs-total {
  color: #c0c8d0;
  margin-right: 2px;
}
.radar-cell-summary .cs-chip {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 1px 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  font-weight: 700;
  cursor: default;
}
.radar-cell-summary .cs-tornadic     { color: #ff66ff; border-color: rgba(255, 102, 255, 0.55); }
.radar-cell-summary .cs-meso         { color: #ff5555; border-color: rgba(255, 85, 85, 0.45); }
.radar-cell-summary .cs-hail         { color: #ff8c5a; border-color: rgba(255, 140, 90, 0.45); }
.radar-cell-summary .cs-explosive    { color: #ffeb3b; border-color: rgba(255, 235, 59, 0.45); }
.radar-cell-summary .cs-intensifying { color: #7eff7e; border-color: rgba(126, 255, 126, 0.45); }
.radar-cell-summary .cs-bomb         { color: #ff7a3d; border-color: rgba(255, 122, 61, 0.45); }
.radar-cell-summary .cs-hp           { color: #ff66ff; border-color: rgba(255, 102, 255, 0.45); }
.radar-cell-summary .cs-classic      { color: #f2c14e; border-color: rgba(242, 193, 78, 0.45); }
.radar-cell-summary .cs-lp           { color: #7eff7e; border-color: rgba(126, 255, 126, 0.45); }
/* PTDS-observed gets a pulse — radar-confirmed debris is the single
   most urgent signal the system can produce; it should fight for
   attention against everything else in the chip row. */
.radar-cell-summary .cs-ptds-obs     {
  color: #ff66ff;
  border-color: #ff66ff;
  animation: ptds-observed-pulse 1.2s ease-in-out infinite;
}
.radar-cell-summary .cs-ptds-lkl     { color: #ff5555; border-color: rgba(255, 85, 85, 0.55); }
.radar-cell-summary .cs-ladder-debris   {
  color: #ff66ff;
  border-color: #ff66ff;
  animation: ptds-observed-pulse 1.2s ease-in-out infinite;
}
.radar-cell-summary .cs-ladder-tornadic { color: #ff5555; border-color: rgba(255, 85, 85, 0.55); }
.radar-cell-summary .cs-ladder-mature   { color: #ff7a3d; border-color: rgba(255, 122, 61, 0.45); }
.radar-cell-summary .cs-vd-severe    { color: #ff66ff; border-color: rgba(255, 102, 255, 0.55); }
.radar-cell-summary .cs-vd-high      { color: #ff5555; border-color: rgba(255, 85, 85, 0.45); }
/* POSH (Witt 1998) tiers — extreme pulses for "near-certain severe
 * hail." High tier reads alongside cs-hail (heuristic flag) so the
 * operator can see both calibrations at once during marginal events. */
.radar-cell-summary .cs-posh-extreme {
  color: #ff66ff;
  border-color: #ff66ff;
  animation: ptds-observed-pulse 1.2s ease-in-out infinite;
}
.radar-cell-summary .cs-posh-high    { color: #ff5555; border-color: rgba(255, 85, 85, 0.55); }
.radar-cell-summary .cs-mesh-sig     { color: #ff66ff; border-color: rgba(255, 102, 255, 0.45); }

/* On-map cell label — personality + ladder mini-tags below the
   primary dBZ line. Kept small + low-opacity so they don't crowd
   the dBZ readout but read at-a-glance on hover/scan. */
.radar-cell-label .cl-pers {
  display: inline-block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  padding: 0 3px;
  border-radius: 3px;
  background: rgba(18, 26, 38, 0.78);
  margin-top: 1px;
}
.radar-cell-label .cl-pers.pers-hail_beast    { color: #ff5555; }
.radar-cell-label .cl-pers.pers-wind_demon    { color: #ff7a3d; }
.radar-cell-label .cl-pers.pers-spinner       { color: #ff66ff; }
.radar-cell-label .cl-pers.pers-flood_engine  { color: #5fb1ff; }
.radar-cell-label .cl-ladder {
  display: inline-block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  padding: 0 3px;
  border-radius: 3px;
  background: rgba(18, 26, 38, 0.78);
  margin-top: 1px;
}
.radar-cell-label .cl-ladder.ladder-debris   {
  color: #ff66ff;
  animation: ptds-observed-pulse 1.2s ease-in-out infinite;
}
.radar-cell-label .cl-ladder.ladder-tornadic { color: #ff5555; }
/* POSH (Probability of Severe Hail, Witt 1998) — warn-credible
 * threshold tag attached to the cell label. Two tiers:
 *   .posh-severe      POSH ≥ 70%                 (orange-red)
 *   .posh-significant POSH ≥ 70% + MESH ≥ 1.5"   (magenta + pulse)
 * Mirrors the .cl-ladder pattern so the label-decoration band reads
 * consistently across products. */
.radar-cell-label .cl-posh {
  display: inline-block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  padding: 0 3px;
  border-radius: 3px;
  background: rgba(18, 26, 38, 0.78);
  margin-top: 1px;
}
.radar-cell-label .cl-posh.posh-severe      { color: #ff8a3d; }
.radar-cell-label .cl-posh.posh-significant {
  color: #ff66ff;
  animation: ptds-observed-pulse 1.2s ease-in-out infinite;
}

/* MESO-01 supercell archetype tag (LP / Classic / HP). Same label-band
 * styling as the other per-cell decorations; color cues the mode —
 * green LP (visible, low-precip), amber Classic, magenta HP
 * (rain-wrapped, hidden hazard). */
.radar-cell-label .cl-meso {
  display: inline-block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  padding: 0 3px;
  border-radius: 3px;
  background: rgba(18, 26, 38, 0.78);
  margin-top: 1px;
}
.radar-cell-label .cl-meso.meso-lp      { color: #7eff7e; }
.radar-cell-label .cl-meso.meso-classic { color: #f2c14e; }
.radar-cell-label .cl-meso.meso-hp      { color: #ff66ff; }

/* SI-02 storm-top divergence badge — anvil-level updraft horsepower.
 * Three tiers: organized (≥40 m/s), strong (≥60), extreme (≥80). */
.radar-cell-label .cl-div {
  display: inline-block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  padding: 0 3px;
  border-radius: 3px;
  background: rgba(18, 26, 38, 0.78);
  margin-top: 1px;
}
.radar-cell-label .cl-div.div-organized { color: #5fb1ff; }
.radar-cell-label .cl-div.div-strong    { color: #ff8a3d; }
.radar-cell-label .cl-div.div-extreme   {
  color: #ff5555;
  animation: ptds-observed-pulse 1.2s ease-in-out infinite;
}

/* TOR-04 "Hidden by Geometry" — fires when a rotating cell sits at a
 * range where the lowest tilt's beam height puts the low-level
 * tornadogenesis layer below the radar's view. Two tiers: warn at
 * > 3 kft beam AGL, severe at > 6 kft (truly no useful low-level data). */
.radar-cell-label .cl-hidden {
  display: inline-block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  padding: 0 3px;
  border-radius: 3px;
  background: rgba(38, 18, 26, 0.85);
  margin-top: 1px;
}
.radar-cell-label .cl-hidden.hidden-warn   { color: #ffeb3b; }
.radar-cell-label .cl-hidden.hidden-severe {
  color: #ff66ff;
  animation: ptds-observed-pulse 1.2s ease-in-out infinite;
}

/* Warning popup → SRV motion auto-fill button. Renders inside the
 * NWS warning popup when warningsLayer could parse a MOTION block;
 * click swaps to the Storm-Relative Velocity product with the
 * warning's motion vector pre-loaded. */
.radar-warning-popup .rwp-srv-btn {
  display: block;
  width: 100%;
  margin: 6px 0 2px;
  padding: 5px 8px;
  background: #1a2f4a;
  color: #aedaff;
  border: 1px solid #4a78a8;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  letter-spacing: 0.2px;
}
.radar-warning-popup .rwp-srv-btn:hover {
  background: #2a466b;
  color: #ffffff;
  border-color: #7aa7d8;
}

/* META-08 "Why am I alerted?" plain-language summary — sits between
 * the threat badges and the SRV/raw-text section. Reads as a sentence
 * rather than terminology so it's useful to a non-meteorologist. */
.radar-warning-popup .rwp-why {
  margin: 6px 0;
  padding: 6px 8px;
  background: rgba(40, 60, 90, 0.55);
  border-left: 3px solid #ffb84d;
  border-radius: 3px;
  font-size: 12px;
  line-height: 1.4;
  color: #f0e0c0;
}

/* META-06 Personal Threat Bubble — click-anywhere mini-timeline popup. */
.radar-threat-bubble {
  font-size: 12px;
  color: #e8eef8;
  min-width: 220px;
}
.radar-threat-bubble h4 {
  margin: 0 0 4px;
  font-size: 13px;
  font-weight: 700;
  color: #ffd96b;
}
.radar-threat-bubble .ptb-loc {
  color: #aac4e0;
  font-size: 11px;
  margin-bottom: 6px;
}
.radar-threat-bubble .ptb-empty {
  color: #7ea8c8;
  font-style: italic;
  padding: 4px 0;
}
.radar-threat-bubble .ptb-row {
  display: flex;
  gap: 6px;
  align-items: center;
  padding: 3px 0;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.radar-threat-bubble .ptb-eta {
  color: #ffd96b;
  font-weight: 700;
  min-width: 60px;
}
.radar-threat-bubble .ptb-haz { flex: 1; }
.radar-threat-bubble .ptb-haz-tornado  { color: #ff66ff; font-weight: 700; }
.radar-threat-bubble .ptb-haz-wind     { color: #ff8a3d; font-weight: 700; }
.radar-threat-bubble .ptb-haz-hail     { color: #ff5252; font-weight: 700; }
.radar-threat-bubble .ptb-haz-rain     { color: #5fb1ff; }
.radar-threat-bubble .ptb-haz-flood    { color: #22c55e; }

/* META-01 Storm Vital Signs — compact composite bars at the top of the
 * cell drill-down panel. Each bar carries one tier-colored axis. */
.vital-signs {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11.5px;
}
.vs-bar {
  display: grid;
  grid-template-columns: 65px 1fr;
  align-items: center;
  padding: 3px 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.04);
  border-left: 3px solid #4a5568;
}
.vs-bar .vs-lbl { color: #a8b8cc; font-weight: 600; letter-spacing: 0.3px; }
.vs-bar .vs-val { color: #e8eef8; font-weight: 600; }
.vs-bar.vs-si.vs-si-explosive    { border-left-color: #ff5252; }
.vs-bar.vs-si.vs-si-intensifying { border-left-color: #ff9800; }
.vs-bar.vs-si.vs-si-collapsing   { border-left-color: #aa4488; }
.vs-bar.vs-si.vs-si-weakening    { border-left-color: #5fb1ff; }
.vs-bar.vs-rot.vs-rot-tornadic   { border-left-color: #ff44ff; }
.vs-bar.vs-rot.vs-rot-strong     { border-left-color: #ff5252; }
.vs-bar.vs-rot.vs-rot-organized  { border-left-color: #ff9800; }
.vs-bar.vs-ptds.vs-ptds-observed { border-left-color: #ff44ff; }
.vs-bar.vs-ptds.vs-ptds-likely   { border-left-color: #ff5252; }
.vs-bar.vs-ptds.vs-ptds-possible { border-left-color: #ff9800; }
.vs-bar.vs-hail.vs-hail-significant { border-left-color: #ff44ff; }
.vs-bar.vs-hail.vs-hail-severe   { border-left-color: #ff5252; }
.vs-bar.vs-hail.vs-hail-marginal { border-left-color: #ffeb3b; }
.vs-bar.vs-wind.vs-wind-imminent { border-left-color: #ff5252; }
.vs-bar.vs-wind.vs-wind-watch    { border-left-color: #ff8a3d; }
.vs-bar.vs-mode                  { border-left-color: #5fb1ff; }

/* SI-03 SR Hodograph widget — small SVG canvas + side readout. */
.cell-hodograph {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 4px 0;
}
.cell-hodograph svg {
  background: rgba(10, 16, 26, 0.5);
  border-radius: 4px;
  flex-shrink: 0;
}
.cell-hodograph .hod-readout {
  font-size: 11px;
  color: #d8e0ec;
  line-height: 1.5;
}
.cell-hodograph .hod-key {
  color: #8aa0bc;
  display: inline-block;
  min-width: 60px;
  font-weight: 600;
}

/* Cell Triage panel — threat-ranked outbreak management. */
/* Default position — open just right of the Products panel so it
 * doesn't get buried at (0,0) behind the map. Operator can drag it
 * anywhere; this is just where it lives on first open. */
#panel-triage   { top: 12px; left: 220px; min-width: 320px; max-width: 420px;
                  max-height: calc(100% - 24px); }
.triage-filters {
  display: flex;
  gap: 4px;
  padding: 6px 8px 4px;
  flex-wrap: wrap;
}
.tf-chip {
  background: rgba(255, 255, 255, 0.06);
  color: #c8d4e4;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 12px;
  padding: 3px 10px;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  letter-spacing: 0.3px;
}
.tf-chip:hover { background: rgba(255, 255, 255, 0.12); }
.tf-chip.active {
  background: #1e3a5f;
  color: #fff;
  border-color: #4a78a8;
}
.triage-empty {
  padding: 10px;
  color: #8aa0bc;
  font-size: 12px;
  font-style: italic;
  text-align: center;
}
.triage-row {
  display: grid;
  grid-template-columns: 50px 38px 1fr auto;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 5px 8px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 4px;
  margin-bottom: 3px;
  font-size: 11.5px;
  color: #e8eef8;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}
.triage-row:hover { background: rgba(255, 255, 255, 0.08); }
.triage-row.triage-pinned { border-color: #ffd96b; }
.triage-row .tr-id     { font-weight: 700; color: #ffd96b; }
.triage-row .tr-score  {
  font-weight: 800;
  text-align: center;
  padding: 1px 3px;
  border-radius: 3px;
  font-size: 12px;
}
.triage-row .tr-score.sc-extreme { background: #ff44ff; color: #fff; }
.triage-row .tr-score.sc-high    { background: #ff5252; color: #fff; }
.triage-row .tr-score.sc-mod     { background: #ff8a3d; color: #1a1a1a; }
.triage-row .tr-score.sc-low     { background: #5fb1ff; color: #1a1a1a; }
.triage-row .tr-tag    { font-weight: 600; }
.triage-row .tr-tag.tt-tor  { color: #ff66ff; }
.triage-row .tr-tag.tt-hail { color: #ff5252; }
.triage-row .tr-tag.tt-wind { color: #ff8a3d; }
.triage-row .tr-tag.tt-rot  { color: #ffeb3b; }
.triage-row .tr-tag.tt-rain { color: #5fb1ff; }
.triage-row .tr-meta   { color: #8aa0bc; font-size: 10.5px; }

/* Saved Locations panel. */
/* Default position — open in the upper-left area like the Triage panel
 * but offset enough to not overlap when both are open. Draggable
 * after; this is just the first-open spot. */
#panel-locations { top: 12px; left: 560px; min-width: 300px; max-width: 380px;
                   max-height: calc(100% - 24px); }
.loc-add-row {
  display: flex;
  gap: 6px;
  margin-bottom: 8px;
}
.loc-add-row input {
  flex: 1;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 3px;
  padding: 4px 6px;
  font-size: 12px;
  color: #e8eef8;
}
.loc-add-row button {
  background: #1e3a5f;
  color: #d8ebff;
  border: 1px solid #4a78a8;
  border-radius: 3px;
  padding: 4px 8px;
  font-size: 11px;
  cursor: pointer;
  white-space: nowrap;
}
.loc-add-row button:hover { background: #2a4f80; color: #fff; }
.loc-hint {
  background: rgba(255, 184, 77, 0.15);
  border-left: 3px solid #ffb84d;
  padding: 4px 8px;
  margin-bottom: 6px;
  font-size: 11px;
  color: #ffd09a;
  border-radius: 2px;
}
.loc-empty {
  padding: 12px;
  color: #8aa0bc;
  font-size: 12px;
  font-style: italic;
  text-align: center;
  line-height: 1.5;
}
.loc-row {
  padding: 6px 8px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-left: 3px solid #5fb1ff;
  border-radius: 3px;
  margin-bottom: 4px;
  font-size: 11.5px;
}
.loc-row.loc-lvl-watch   { border-left-color: #ffeb3b; }
.loc-row.loc-lvl-severe  { border-left-color: #ff8a3d; background: rgba(255, 138, 61, 0.10); }
.loc-row.loc-lvl-extreme { border-left-color: #ff44ff; background: rgba(255, 68, 255, 0.12);
                           animation: ptds-observed-pulse 1.6s ease-in-out infinite; }
.loc-row .loc-head {
  display: flex;
  align-items: center;
  gap: 6px;
}
.loc-row .loc-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #5fb1ff;
  flex-shrink: 0;
}
.loc-row .loc-dot.loc-lvl-watch   { background: #ffeb3b; }
.loc-row .loc-dot.loc-lvl-severe  { background: #ff8a3d; }
.loc-row .loc-dot.loc-lvl-extreme { background: #ff44ff; }
.loc-row .loc-name { font-weight: 700; color: #e8eef8; flex: 1; }
.loc-row .loc-coords { color: #8aa0bc; font-size: 10.5px; margin-top: 2px; }
.loc-row .loc-haz { color: #ffd09a; font-weight: 600; margin-top: 3px; font-size: 11px; }
.loc-row .loc-act {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.15);
  color: #c8d4e4;
  border-radius: 3px;
  padding: 1px 6px;
  font-size: 11px;
  cursor: pointer;
}
.loc-row .loc-act:hover { background: rgba(255, 255, 255, 0.10); color: #fff; }
.loc-row .loc-remove:hover { background: #ff5252; border-color: #ff5252; color: #fff; }

/* Saved-location map markers — small dot with optional pulse when
 * the location is under severe/extreme threat. */
.radar-loc-marker > div {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.6);
}
/* Home location — larger 🏠 badge with tier-colored border. Sits
 * above any of-interest dots that overlap (zIndexOffset 1000). */
.radar-loc-marker .loc-home-badge {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2.5px solid #5fb1ff;
  background: rgba(18, 26, 38, 0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.7);
}
/* Home row in the panel — subtle highlight + star button accent. */
.loc-row.loc-is-home {
  border-left-width: 4px;
  background: rgba(255, 217, 107, 0.08);
}
.loc-act.loc-home-act {
  font-size: 14px;
  font-weight: 700;
  color: #c8d4e4;
  padding: 0 4px;
}
.loc-act.loc-home-act.loc-home-active {
  color: #ffd96b;
}
.loc-act.loc-home-act:hover {
  color: #ffd96b;
  background: rgba(255, 217, 107, 0.15);
}

/* Toolbar active states for new toggles. */
#btn-triage.active,
#btn-locations.active {
  background: #1e3a5f;
  border-color: #4a78a8;
  color: #fff;
}

/* TOR-05 Debris Lifecycle block — sits under the trend sparklines in
 * the cell drill-down panel. Renders nothing when the cell has never
 * crossed the "likely TDS" threshold; for cells that have, distills
 * the plume into stage + age + continuity + peak. */
.debris-lifecycle {
  margin-top: 10px;
  padding: 8px 10px;
  background: rgba(255, 68, 255, 0.08);
  border-left: 3px solid #ff66ff;
  border-radius: 3px;
  font-size: 11.5px;
}
.debris-lifecycle .dl-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 4px;
}
.debris-lifecycle .dl-title {
  font-weight: 700;
  color: #ffb3ff;
  letter-spacing: 0.3px;
}
.debris-lifecycle .dl-stage {
  font-weight: 700;
  font-size: 10.5px;
  padding: 1px 6px;
  border-radius: 3px;
}
.debris-lifecycle .dl-stage.dl-forming    { background: #ff8a3d; color: #1a1a1a; }
.debris-lifecycle .dl-stage.dl-sustained  { background: #ff44ff; color: #fff;
                                            animation: ptds-observed-pulse 1.4s ease-in-out infinite; }
.debris-lifecycle .dl-stage.dl-dissipated { background: #5a5a6a; color: #d8d8e8; }
.debris-lifecycle .dl-row {
  display: flex;
  justify-content: space-between;
  padding: 2px 0;
}
.debris-lifecycle .dl-lbl { color: #c8d4e4; }
.debris-lifecycle .dl-val { color: #f0e0e8; font-weight: 600; }
.debris-lifecycle .dl-val.dl-cont-high { color: #ff44ff; }
.debris-lifecycle .dl-val.dl-cont-mod  { color: #ffeb3b; }
.debris-lifecycle .dl-val.dl-cont-low  { color: #aab8c8; }

/* Recently-viewed site chips — quick switcher next to the main
 * dropdown. Active chip highlights the current site so the operator
 * can see where they are in their recent stack. */
.radar-recent-sites {
  display: inline-flex;
  gap: 3px;
  margin-left: 4px;
}
.radar-recent-sites .recent-site {
  padding: 3px 7px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: #c0c8d0;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 0.78rem;
  cursor: pointer;
}
.radar-recent-sites .recent-site:hover {
  background: rgba(255, 255, 255, 0.10);
}
.radar-recent-sites .recent-site.active {
  background: rgba(242, 193, 78, 0.18);
  border-color: rgba(242, 193, 78, 0.55);
  color: #f2c14e;
  font-weight: 700;
}

/* Share button flash — brief green confirmation when copy succeeds. */
#btn-share.share-flash {
  background: rgba(126, 255, 126, 0.2);
  border-color: rgba(126, 255, 126, 0.5);
  color: #7eff7e;
}

/* Scan freshness indicator — green/amber/red age tag in the Info
 * panel. Color crosses the operator's mental threshold of "current
 * vs lagging" without needing them to do the math. */
.scan-age          { font-weight: 600; }
.scan-age.age-fresh { color: #7eff7e; }
.scan-age.age-warm  { color: #ffb74d; }
.scan-age.age-stale { color: #ff5555; }

/* Audio mute button — visually distinct when muted so the operator
 * never wonders whether alerts are firing. Reuses the warn-toggle
 * style scheme. */
#btn-audio.muted {
  background: rgba(160, 60, 60, 0.2);
  border-color: rgba(255, 60, 60, 0.45);
  color: #ff8a8a;
}

/* LSR markers — emoji glyph in a circular badge. Severity drives
 * size + ring color so a tornado LSR is unmistakably larger than a
 * wind report. Click opens the popup with full report details. */
.radar-lsr-marker {
  background: rgba(0, 0, 0, 0.72);
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.7);
  cursor: pointer;
}
.radar-lsr-marker .lsr-glyph {
  font-size: 14px;
  line-height: 1;
  pointer-events: none;
  user-select: none;
}
.radar-lsr-marker.lsr-tornado {
  border-color: #ff00ff;
  width: 28px !important; height: 28px !important;
  margin-left: -14px !important; margin-top: -14px !important;
  animation: tvs-pulse 1.6s ease-in-out infinite;
}
.radar-lsr-marker.lsr-tornado .lsr-glyph { font-size: 18px; }
.radar-lsr-marker.lsr-hail        { border-color: #ff5555; }
.radar-lsr-marker.lsr-wind-dmg    { border-color: #ff9800; }
.radar-lsr-marker.lsr-wind        { border-color: #ffeb3b; }
.radar-lsr-marker.lsr-flood       { border-color: #22c55e; }
.radar-lsr-marker.lsr-rain        { border-color: #06b6d4; opacity: 0.7; }
.radar-lsr-marker.lsr-lightning   { border-color: #ffeb3b; }
.radar-lsr-marker.lsr-lsr         { border-color: #9ca3af; opacity: 0.65; }

.radar-lsr-popup .lsr-title {
  margin: 0 0 0.3rem 0;
  font-size: 0.95rem;
  color: #f2c14e;
}
.radar-lsr-popup .lsr-where {
  color: #c0c8d0;
  font-weight: 600;
  margin-bottom: 0.2rem;
}
.radar-lsr-popup .lsr-mag,
.radar-lsr-popup .lsr-when,
.radar-lsr-popup .lsr-by {
  color: #9aa6b3;
  font-size: 0.78rem;
}
.radar-lsr-popup .lsr-details {
  margin: 0.4rem 0 0 0;
  padding: 0.4rem;
  background: rgba(255, 255, 255, 0.04);
  border-radius: 4px;
  white-space: pre-wrap;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 0.74rem;
  color: #c0c8d0;
  max-height: 200px;
  overflow-y: auto;
}

/* LSR toggle button — same active-state pattern as the warn button. */
.radar-btn.lsr-toggle.active {
  background: rgba(126, 255, 126, 0.16);
  border-color: rgba(126, 255, 126, 0.4);
  color: #7eff7e;
}

/* Cell-info panel tab strip — one chip per pinned cell. Active tab
 * gets the amber accent + filled background so the operator knows
 * which cell the stats/trend area is showing. Tabs wrap to a second
 * row if the operator pins more than fits in the panel width. */
.gp-cell-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 6px 10px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  background: rgba(255, 255, 255, 0.02);
}
.gp-cell-tabs .cell-tab {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 4px 2px 8px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 0.74rem;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  cursor: pointer;
  user-select: none;
}
.gp-cell-tabs .cell-tab .tab-label {
  color: #c0c8d0;
}
.gp-cell-tabs .cell-tab.active {
  background: rgba(242, 193, 78, 0.18);
  border-color: rgba(242, 193, 78, 0.55);
}
.gp-cell-tabs .cell-tab.active .tab-label {
  color: #f2c14e;
  font-weight: 700;
}
.gp-cell-tabs .cell-tab .tab-x {
  background: none;
  border: none;
  color: #9aa6b3;
  font-size: 0.85rem;
  line-height: 1;
  padding: 0 3px;
  cursor: pointer;
}
.gp-cell-tabs .cell-tab .tab-x:hover {
  color: #ff8a8a;
}

/* WND-01 Bomb Clock — siren-orange pill, pulsing to grab attention.
 * Offset east+south of the cell centroid so it doesn't collide with
 * the dBZ label above or hail glyph below. */
.radar-bomb-marker .bomb-glyph {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.7);
  color: #ff7a3d;
  font-size: 12px;
  font-weight: 800;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  text-shadow: 0 0 3px #000;
  border: 1px solid rgba(255, 122, 61, 0.7);
  white-space: nowrap;
  pointer-events: none;
  animation: tvs-pulse 1.4s ease-in-out infinite;
}

.cell-trend-row {
  display: grid;
  grid-template-columns: 3.4rem 1fr 3.2rem;
  align-items: center;
  gap: 0.35rem;
  margin-bottom: 0.2rem;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 0.72rem;
}
.cell-trend-row .lbl { color: #9aa6b3; }
.cell-trend-row svg { display: block; }
.cell-trend-row .now { color: #f2c14e; text-align: right; }
.cell-trend-empty {
  font-size: 0.72rem;
  color: #7e8a96;
  font-style: italic;
}

/* ─── Warning overlay popups ─────────────────────────────────────── */

.radar-warning-popup-wrapper .leaflet-popup-content-wrapper {
  background: rgba(12, 22, 34, 0.94);
  color: #e7ecf2;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 0.4rem;
}
.radar-warning-popup-wrapper .leaflet-popup-tip {
  background: rgba(12, 22, 34, 0.94);
}
.radar-warning-popup {
  font-family: ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif;
}
.radar-warning-popup .rwp-title {
  font-size: 0.95rem;
  font-weight: 700;
  margin: 0 0 0.3rem 0;
  color: #f97316;
}
.radar-warning-popup .rwp-area {
  font-size: 0.78rem;
  color: #cdd5dd;
  margin-bottom: 0.2rem;
}
.radar-warning-popup .rwp-expires {
  font-size: 0.74rem;
  color: #f2c14e;
  font-weight: 600;
  margin-bottom: 0.35rem;
}
.radar-warning-popup .rwp-desc {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 0.7rem;
  line-height: 1.3;
  color: #cdd5dd;
  background: rgba(0, 0, 0, 0.3);
  padding: 0.35rem 0.45rem;
  border-radius: 0.3rem;
  max-height: 260px;
  overflow-y: auto;
  white-space: pre-wrap;
  margin: 0;
}

.radar-btn.warn-toggle.active {
  background: rgba(239, 68, 68, 0.22);
  color: #fca5a5;
  border-color: rgba(239, 68, 68, 0.45);
}

/* ─── Storm-cell overlay (Phase 4a) ───────────────────────────────── */

.radar-cell-label {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 11px;
  font-weight: 700;
  color: #ffffff;
  text-shadow: 0 0 3px rgba(0, 0, 0, 0.9), 0 0 6px rgba(0, 0, 0, 0.7);
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
}

.radar-cell-tooltip {
  background: rgba(12, 22, 34, 0.92) !important;
  color: #e7ecf2 !important;
  border: 1px solid rgba(255, 255, 255, 0.18) !important;
  border-radius: 0.4rem !important;
  font-family: ui-monospace, Menlo, Consolas, monospace !important;
  font-size: 11px !important;
  padding: 0.35rem 0.5rem !important;
}
.radar-cell-tooltip::before { display: none !important; }   /* hide leaflet's arrow */

/* Top-bar toggle button — sits next to other top-bar controls. */
.radar-btn.cells-toggle.active {
  background: rgba(242, 193, 78, 0.22);
  color: #f2c14e;
  border-color: rgba(242, 193, 78, 0.45);
}

/* Sum / max-over-frames toggle. Magenta accent (matches the
 * highest-magnitude end of most signed palettes) since the feature is
 * for revealing tracks of severe signatures: tornadic rotation,
 * debris paths, hail cores. */
.radar-btn.sum-mode-toggle.active {
  background: rgba(255, 102, 255, 0.20);
  color: #ff66ff;
  border-color: rgba(255, 102, 255, 0.55);
}

/* Locked chip — operator's tier doesn't entitle them to this product.
 * The chip is still visible (vs hidden) so the upgrade affordance is
 * discoverable. Click handler in radar.js intercepts before
 * applyActiveProduct so the layer never tries to render a locked one. */
.gp-products button.locked {
  position: relative;
  opacity: 0.55;
  cursor: not-allowed;
  border-style: dashed;
  padding-right: 1.5rem;   /* room for the lock glyph */
}
.gp-products button.locked::after {
  content: "🔒";
  position: absolute;
  right: 0.45rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.7rem;
  filter: grayscale(1);
  opacity: 0.85;
}
.gp-products button.locked:hover {
  background: rgba(255, 120, 120, 0.06);
  border-color: rgba(255, 120, 120, 0.3);
  opacity: 0.75;
}
/* When a locked chip is the "active" pick (shouldn't normally happen
 * since the click handler bails — but if persisted state stale-restores
 * a locked id, the visual cue is clear). */
.gp-products button.locked.active {
  background: rgba(255, 120, 120, 0.12);
  border-color: rgba(255, 120, 120, 0.45);
  color: #fca5a5;
}

/* Loop controls (now horizontal) */
.gp-btn-wide {
  appearance: none;
  background: #142536;
  color: #e7ecf2;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.35rem;
  padding: 0.32rem 0.65rem;
  font-size: 0.78rem;
  cursor: pointer;
  flex: 0 0 auto;
}
.gp-btn-wide:hover { background: #1b3047; }
.gp-inline { display: inline-flex; align-items: center; gap: 0.25rem; font-size: 0.72rem; color: #9aa6b3; flex: 0 0 auto; }
.gp-inline select {
  background: #0e1c2a;
  color: #e7ecf2;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.3rem;
  padding: 0.15rem 0.3rem;
  font-size: 0.75rem;
}

.gp-frame-scrubber {
  display: flex;
  gap: 0.18rem;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
}
.gp-frame-scrubber button {
  flex: 1 1 0;
  min-width: 0;
  height: 16px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.2rem;
  background: rgba(255, 255, 255, 0.05);
  cursor: pointer;
  padding: 0;
}
.gp-frame-scrubber button:hover { background: rgba(255, 255, 255, 0.12); }
.gp-frame-scrubber button.active {
  background: #f2c14e;
  border-color: #f2c14e;
}

/* Legend */
.gp-legend-section { flex: 1 1 auto; overflow: hidden; display: flex; flex-direction: column; min-height: 120px; }
.gp-legend-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.4rem; margin-bottom: 0.3rem;
}
.gp-legend-head .gp-heading { margin: 0; }
.gp-mini-btn {
  appearance: none;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: #cdd5dd;
  font-size: 0.65rem;
  padding: 0.1rem 0.4rem;
  border-radius: 0.3rem;
  cursor: pointer;
}
.gp-mini-btn:hover { background: rgba(255, 255, 255, 0.1); }

.gp-legend {
  flex: 1 1 auto;
  overflow-y: auto;
  display: flex;
  flex-direction: column-reverse;
  gap: 1px;
  padding: 1px;
  border-radius: 0.4rem;
  background: rgba(0, 0, 0, 0.35);
}
.gp-legend-cell {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.12rem 0.4rem;
  cursor: pointer;
  user-select: none;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 0.7rem;
  color: #e7ecf2;
  transition: opacity 0.12s;
}
.gp-legend-cell .swatch {
  display: inline-block;
  width: 22px; height: 14px;
  border-radius: 0.2rem;
  border: 1px solid rgba(255, 255, 255, 0.18);
  flex: 0 0 auto;
}
.gp-legend-cell .label { flex: 1 1 auto; }
.gp-legend-cell.disabled { opacity: 0.32; text-decoration: line-through; }
.gp-legend-cell.disabled .swatch { filter: grayscale(0.7); }
.gp-legend-cell:hover { background: rgba(255, 255, 255, 0.05); }

.gp-hint {
  font-size: 0.65rem;
  color: #7e8a96;
  margin: 0.35rem 0 0 0;
  line-height: 1.3;
}

.radar-meta {
  font-size: 0.82rem;
  line-height: 1.35;
  color: #e7ecf2;
  background: rgba(255, 255, 255, 0.04);
  border-radius: 0.4rem;
  padding: 0.4rem 0.5rem;
  margin-bottom: 0.4rem;
}

/* Narrow viewports — stack panels along the top, drag still works. */
@media (max-width: 720px) {
  #panel-products, #panel-loop, #panel-info {
    position: absolute;
    width: calc(100% - 24px);
    left: 12px !important;
    right: auto !important;
    transform: none !important;
  }
  #panel-products { top: 12px; }
  #panel-loop     { top: 12px; }      /* user can drag to taste */
  #panel-info     { top: 12px; }
}

/* ── Derived overlays section (in Products panel) ──────────────────── */

/* Section sits below the PPI product chips and above the legend. The
   heading visually separates the "what's displayed" radio behavior of
   the product chips from the "what's toggled on" checkbox behavior of
   overlays — different mental models, intentionally split. */
.gp-overlays-section { padding-top: 6px; }
.gp-overlays-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}
.gp-overlays {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
/* Each overlay row pairs the toggle button with its gear (when the
   overlay has tunables). Gear is full-height so the row reads as one
   compact control rather than two adjacent buttons. */
.gp-overlay-row {
  display: flex;
  align-items: stretch;
  gap: 0;
}
.gp-paint-row {
  flex-direction: column;
  gap: 4px;
  padding-top: 6px;
  border-top: 1px dashed rgba(255, 255, 255, 0.08);
  margin-top: 4px;
}
.gp-paint-row .sf-label {
  font-size: 11px;
  color: #c2d0db;
}
.cell-paint-select {
  width: 100%;
  padding: 4px 6px;
  background: #0e1a26;
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 3px;
  font-size: 12px;
}
.gp-overlay-row .radar-btn:first-child {
  flex: 1;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  text-align: left;
}
.gp-overlay-row .radar-btn:last-child {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  border-left-width: 0;
}

/* Gear icon button — narrower than a normal radar-btn since it's a
   modifier on the adjacent button, not a primary action. */
.radar-btn-gear {
  padding-left: 6px;
  padding-right: 6px;
  font-size: 13px;
  opacity: 0.75;
}
.radar-btn-gear:hover { opacity: 1; }

/* Boundaries toggle — color picked to read distinctly from cells (red),
   warn (orange/red), and lsr (green). Cyan tracks the cool-blue palette
   used for low-dBZ fine lines in the layer styling. */
.radar-btn.boundaries-toggle.active {
  background: rgba(95, 177, 255, 0.18);
  border-color: rgba(95, 177, 255, 0.45);
  color: #5fb1ff;
}

/* Training toggle — amber, the "flood corridor" color from the
   training layer's mid-severity palette. Distinct from boundaries
   blue + cells red so the operator can scan the panel and read each
   overlay's state at a glance. */
.radar-btn.training-toggle.active {
  background: rgba(255, 180, 84, 0.18);
  border-color: rgba(255, 180, 84, 0.45);
  color: #ffb454;
}

/* Training corridor label — small tag at the forecast endpoint.
   Border + text in the class color, neutral dark background so the
   tag reads on any reflectivity background. */
.radar-training-label .training-tag {
  display: inline-block;
  padding: 2px 6px;
  border: 1px solid;
  border-radius: 4px;
  background: rgba(18, 26, 38, 0.92);
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  text-shadow: 0 0 2px rgba(0, 0, 0, 0.8);
  pointer-events: none;
}
.radar-training-label.training-extreme .training-tag {
  animation: training-pulse 1.4s ease-in-out infinite;
}
@keyframes training-pulse {
  0%, 100% { opacity: 0.85; }
  50%      { opacity: 1.0; }
}

/* Training popup — match the boundary popup chrome, amber title. */
.radar-training-popup .training-title {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 600;
  color: #ffb454;
}
.radar-training-popup .training-stats {
  width: 100%;
  font-size: 12px;
  border-collapse: collapse;
}
.radar-training-popup .training-stats td {
  padding: 2px 6px;
}
.radar-training-popup .training-stats td:first-child {
  color: #9fb5c8;
}
.radar-training-popup .training-hint {
  margin: 8px 0 0;
  font-size: 11px;
  color: #c2d0db;
  line-height: 1.4;
}

/* Settings flyout — fixed-position popover anchored to the right edge
   of the Products panel. Not draggable; closes on Esc or click-outside.
   Lightweight chrome stands apart from the glass panels which are
   persistent. The Products panel default position is top-left so the
   flyout sits just to its right; on mobile the panel can move, but a
   simple fixed-left offset is the right tradeoff here vs a positioning
   library. */
.settings-flyout {
  position: fixed;
  top: 64px;
  left: 240px;          /* clears the default Products panel width */
  width: 280px;
  z-index: 800;         /* above glass panels (600) and Leaflet panes */
  background: rgba(18, 26, 38, 0.96);
  border: 1px solid rgba(95, 177, 255, 0.35);
  border-radius: 8px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
  color: #d6e2ec;
  font-size: 13px;
  display: flex;
  flex-direction: column;
}
.settings-flyout[hidden] { display: none; }

.sf-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid rgba(95, 177, 255, 0.2);
}
.sf-title {
  flex: 1;
  font-weight: 600;
  color: #5fb1ff;
}
.sf-btn {
  background: #1b3047;
  border: 1px solid rgba(255, 255, 255, 0.15);
  color: #d6e2ec;
  border-radius: 4px;
  padding: 4px 10px;
  font-size: 12px;
  cursor: pointer;
}
.sf-btn:hover { background: #243d59; }
.sf-btn-close {
  width: 26px;
  padding: 4px 0;
  font-size: 16px;
  line-height: 1;
}

.sf-body {
  padding: 10px 12px 4px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.sf-status {
  font-size: 12px;
  color: #9fb5c8;
  padding-bottom: 4px;
  border-bottom: 1px dashed rgba(255, 255, 255, 0.08);
  margin-bottom: 4px;
}
.sf-status.bnd-status-active { color: #5fb1ff; }
.sf-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.sf-label {
  flex: 1;
  color: #c2d0db;
}
.sf-row input[type=number] {
  width: 80px;
  padding: 3px 6px;
  background: #0e1a26;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 3px;
  color: #fff;
  font-size: 12px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.sf-footer {
  padding: 8px 12px;
  border-top: 1px solid rgba(95, 177, 255, 0.15);
}
.sf-hint {
  font-size: 11px;
  color: #748899;
}

/* Boundary popup — match the LSR popup chrome but with cool-blue accents. */
.radar-boundary-popup-wrapper .leaflet-popup-content-wrapper {
  background: rgba(18, 26, 38, 0.96);
  color: #d6e2ec;
  border-radius: 6px;
}
.radar-boundary-popup .bnd-title {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 600;
  color: #5fb1ff;
}
.radar-boundary-popup .bnd-stats {
  width: 100%;
  font-size: 12px;
  border-collapse: collapse;
}
.radar-boundary-popup .bnd-stats td {
  padding: 2px 6px;
}
.radar-boundary-popup .bnd-stats td:first-child {
  color: #9fb5c8;
}
.radar-boundary-popup .bnd-confirmed   { color: #7eff7e; font-weight: 700; }
.radar-boundary-popup .bnd-unconfirmed { color: #9aa6b3; }
.radar-boundary-popup .bnd-det-badge {
  display: inline-block;
  padding: 2px 7px;
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 700;
  border: 1px solid;
  border-radius: 10px;
}
.radar-boundary-popup .bnd-det-badge.det-dual         { color: #ff66ff; border-color: #ff66ff; }
.radar-boundary-popup .bnd-det-badge.det-velocity     { color: #5fffe0; border-color: #5fffe0; }
.radar-boundary-popup .bnd-det-badge.det-reflectivity { color: #ffb454; border-color: rgba(255, 180, 84, 0.55); }

/* Boundary-collision markers — glowing dot + countdown tag at the
   forecast intersection. Magenta for high-confidence collisions,
   amber for moderate. The pulse draws the operator's eye to the CI
   hotspot the way a TVS triangle does for tornadic cells. */
.radar-collision-marker .col-dot {
  position: absolute;
  top: 8px; left: 8px;
  width: 16px; height: 16px;
  border-radius: 50%;
  border: 2px solid;
  box-shadow: 0 0 8px;
  animation: collision-pulse 1.4s ease-in-out infinite;
}
.radar-collision-marker.col-high .col-dot {
  background: rgba(255, 102, 255, 0.35);
  border-color: #ff66ff;
  box-shadow: 0 0 12px #ff66ff;
}
.radar-collision-marker.col-moderate .col-dot {
  background: rgba(255, 180, 84, 0.35);
  border-color: #ffb454;
  box-shadow: 0 0 10px #ffb454;
}
.radar-collision-marker .col-tag {
  position: absolute;
  top: 28px; left: 0;
  width: 64px;
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 0 3px #000;
  pointer-events: none;
}
@keyframes collision-pulse {
  0%, 100% { transform: scale(0.85); opacity: 0.7; }
  50%      { transform: scale(1.1);  opacity: 1.0; }
}
.radar-boundary-popup .bnd-params {
  margin-top: 6px;
  font-size: 11px;
  color: #9fb5c8;
}
.radar-boundary-popup .bnd-params summary {
  cursor: pointer;
  color: #c2d0db;
}
.radar-boundary-popup .bnd-params table {
  margin-top: 4px;
  width: 100%;
  border-collapse: collapse;
}
.radar-boundary-popup .bnd-params td {
  padding: 1px 6px;
}

/* AVN-01 runway gust-front arrival markers — anchored at each
   airport's centerpoint with a tower icon + "KDFW +12 min" tag.
   Severity-tiered color; significant + severe pulse to grab the eye
   the way the collision dots do. */
.radar-avn-marker {
  position: relative;
  pointer-events: auto;
}
.radar-avn-marker .avn-tower {
  position: absolute;
  top: -2px; left: 28px;
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px;
  border-radius: 50%;
  background: rgba(18, 26, 38, 0.85);
  border: 2px solid #c2d0db;
  color: #c2d0db;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.6);
}
.radar-avn-marker .avn-tag {
  position: absolute;
  top: 22px; left: 0;
  width: 80px;
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 0 3px #000;
  pointer-events: none;
}
.radar-avn-marker.avn-routine .avn-tower {
  border-color: #9aa6b3;
  color: #cfd6df;
}
.radar-avn-marker.avn-advisory .avn-tower {
  border-color: #ffb454;
  color: #ffb454;
  box-shadow: 0 0 8px #ffb454;
}
.radar-avn-marker.avn-significant .avn-tower {
  border-color: #ff5555;
  color: #ff5555;
  box-shadow: 0 0 10px #ff5555;
  animation: collision-pulse 1.4s ease-in-out infinite;
}
.radar-avn-marker.avn-severe .avn-tower {
  border-color: #ff66ff;
  color: #ff66ff;
  box-shadow: 0 0 12px #ff66ff;
  animation: collision-pulse 1.4s ease-in-out infinite;
}

/* AVN-06 Terminal Wind Shear marker — same anchor pattern as AVN-01,
 * different glyph (⇄ shear) and tier color scheme. Only renders for
 * airports without an AVN-01 marker; otherwise the shear info rides
 * in the AVN-01 popup. */
.radar-avn-shear-marker {
  position: relative;
  pointer-events: auto;
}
.radar-avn-shear-marker .avn-shear-glyph {
  position: absolute;
  top: -2px; left: 28px;
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px;
  font-weight: 700;
  border-radius: 50%;
  background: rgba(18, 26, 38, 0.85);
  border: 2px solid #6ec6ff;
  color: #6ec6ff;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.6);
}
.radar-avn-shear-marker .avn-shear-tag {
  position: absolute;
  top: 22px; left: 0;
  width: 80px;
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 0 3px #000;
  pointer-events: none;
}
.radar-avn-shear-marker.avn-shear-advisory .avn-shear-glyph {
  border-color: #ffb454;
  color: #ffb454;
  box-shadow: 0 0 8px #ffb454;
}
.radar-avn-shear-marker.avn-shear-significant .avn-shear-glyph {
  border-color: #ff5555;
  color: #ff5555;
  box-shadow: 0 0 10px #ff5555;
  animation: collision-pulse 1.4s ease-in-out infinite;
}
.radar-avn-shear-marker.avn-shear-severe .avn-shear-glyph {
  border-color: #ff66ff;
  color: #ff66ff;
  box-shadow: 0 0 12px #ff66ff;
  animation: collision-pulse 1.4s ease-in-out infinite;
}

/* Popup severity tier colors — shared by AVN-01 / AVN-06 / boundary. */
.radar-boundary-popup .bnd-sev {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.radar-boundary-popup .bnd-sev-routine     { color: #9aa6b3; }
.radar-boundary-popup .bnd-sev-advisory    { color: #ffb454; }
.radar-boundary-popup .bnd-sev-significant { color: #ff5555; }
.radar-boundary-popup .bnd-sev-severe      { color: #ff66ff; }
.radar-boundary-popup .bnd-note {
  margin-top: 6px;
  font-size: 11px;
  color: #aab8c8;
  font-style: italic;
  line-height: 1.4;
}

/* BIO-02 Roost-ring marker. Center glyph + faint circle for the
 * actual ring radius. Purple matches biological tag colors. */
.radar-roost-marker .rst-glyph {
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px;
  border-radius: 50%;
  background: rgba(18, 26, 38, 0.85);
  border: 2px solid #b39cff;
  box-shadow: 0 0 6px rgba(124, 92, 255, 0.5);
}

/* AVN-03 Ramp Restart Timer markers — anchored to airport positions
 * for airports in threat / approaching / clearing status. */
.radar-ramp-marker {
  position: relative;
  pointer-events: auto;
}
.radar-ramp-marker .ramp-glyph {
  position: absolute;
  top: -2px; left: 30px;
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px;
  font-weight: 700;
  border-radius: 4px;
  background: rgba(18, 26, 38, 0.85);
  border: 2px solid #6ec6ff;
  color: #6ec6ff;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.6);
}
.radar-ramp-marker .ramp-tag {
  position: absolute;
  top: 22px; left: 0;
  width: 82px;
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 0 3px #000;
  pointer-events: none;
}
.radar-ramp-marker.ramp-approaching .ramp-glyph {
  border-color: #ffeb3b; color: #ffeb3b; box-shadow: 0 0 8px #ffeb3b;
}
.radar-ramp-marker.ramp-threat .ramp-glyph {
  border-color: #ff5252; color: #ff5252; box-shadow: 0 0 10px #ff5252;
  animation: collision-pulse 1.4s ease-in-out infinite;
}
.radar-ramp-marker.ramp-clearing .ramp-glyph {
  border-color: #22c55e; color: #22c55e; box-shadow: 0 0 6px #22c55e;
}
.radar-boundary-popup .ramp-status {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.radar-boundary-popup .ramp-status.ramp-threat      { color: #ff5252; }
.radar-boundary-popup .ramp-status.ramp-approaching { color: #ffeb3b; }
.radar-boundary-popup .ramp-status.ramp-clearing    { color: #22c55e; }

.radar-avn-popup .avn-subtitle {
  font-size: 11px;
  color: #c2d0db;
  margin: 2px 0 6px;
}
.radar-avn-popup .avn-sev {
  display: inline-block;
  padding: 0 4px;
  border: 1px solid;
  border-radius: 8px;
  font-weight: 700;
}
.radar-avn-popup .avn-sev-routine     { color: #9aa6b3; border-color: rgba(154, 166, 179, 0.45); }
.radar-avn-popup .avn-sev-advisory    { color: #ffb454; border-color: rgba(255, 180, 84, 0.55); }
.radar-avn-popup .avn-sev-significant { color: #ff5555; border-color: rgba(255, 85, 85, 0.55); }
.radar-avn-popup .avn-sev-severe      { color: #ff66ff; border-color: rgba(255, 102, 255, 0.55); }
.radar-avn-popup table.avn-stats {
  width: 100%;
  border-collapse: collapse;
  font-size: 11px;
}
.radar-avn-popup table.avn-stats th {
  text-align: left;
  padding: 2px 6px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  color: #9fb5c8;
  font-weight: 600;
}
.radar-avn-popup table.avn-stats td {
  padding: 2px 6px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

/* ─── In-page dialogs (dialogs.js): replace browser prompt/confirm ─────── */
.rd-dialog-backdrop {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(2, 4, 10, 0.6);
}
.rd-dialog {
  width: min(30rem, 100%);
  max-height: calc(100vh - 2rem);
  overflow: auto;
  padding: 1rem 1.1rem;
  border: 1px solid #2a3550;
  border-radius: 10px;
  background: #0f1526;
  color: #e8edf2;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.55);
  font: 14px/1.4 system-ui, sans-serif;
}
.rd-dialog h3 {
  margin: 0 0 0.4rem;
  font-size: 15px;
}
.rd-dialog-msg {
  margin: 0 0 0.6rem;
  color: #a8b7c4;
  white-space: pre-wrap;
}
.rd-dialog input,
.rd-dialog textarea {
  width: 100%;
  box-sizing: border-box;
  padding: 0.45rem 0.6rem;
  border: 1px solid #2a3550;
  border-radius: 6px;
  background: #0a0f1c;
  color: #e8edf2;
  font: inherit;
}
.rd-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.8rem;
}
.rd-btn {
  padding: 0.35rem 0.85rem;
  border: 1px solid #2a3550;
  border-radius: 6px;
  background: #18213a;
  color: #e8edf2;
  font: inherit;
  cursor: pointer;
}
.rd-btn-primary {
  border-color: #f2c14e;
  background: #f2c14e;
  color: #101820;
}
.rd-btn-danger {
  border-color: #d43d3d;
  background: #d43d3d;
  color: #fff;
}
