:root {
  --accent: #0077b6;
  --nav-bg: #03045e;
  --nav-bg-2: #023e8a;
  --bg: #0a1929;
  --text: #e0e7ef;
  --text-muted: #8eafc4;
  --card-bg: #0d2137;
  --border: #1e3a5f;
  --status-active: #4ade80;
  --status-degraded: #facc15;
  --status-silent: #64748b;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
}

#app {
  display: flex;
  flex-direction: column;
  height: 100%;
}

header {
  background: linear-gradient(90deg, var(--nav-bg), var(--nav-bg-2));
  padding: 0.75rem 1.25rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem;
  border-bottom: 1px solid var(--border);
  z-index: 1000;
}

header h1 {
  font-size: 1.25rem;
  margin: 0;
}

header .subtitle {
  color: var(--text-muted);
  font-size: 0.85rem;
  margin-left: 0.5rem;
}

#stats {
  display: flex;
  gap: 1rem;
  font-size: 0.85rem;
  color: var(--text-muted);
  align-items: center;
  flex-wrap: wrap;
}

#stats .stat { display: flex; align-items: center; gap: 0.35rem; }

.dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: inline-block;
}
.dot.active { background: var(--status-active); }
.dot.degraded { background: var(--status-degraded); }
.dot.silent { background: var(--status-silent); }

#map-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
}

#map {
  position: absolute;
  inset: 0;
}

/* Both panels dock to the full right edge — shift Leaflet's own right-side
   controls (basemap/layers up top, legend down below) left by whichever
   panel's own width so they stay reachable instead of disappearing
   underneath it. The simulator used to be a centered overlay covering the
   whole map — reverted (see #sim-panel below): covering the map entirely
   defeated the point of a spatial tool, worse than the cramped-sidebar
   problem it was meant to fix. */
#map-wrap.plan-open .leaflet-top.leaflet-right,
#map-wrap.plan-open .leaflet-bottom.leaflet-right {
  right: 320px;
  transition: right 0.15s ease;
}
#map-wrap.sim-open .leaflet-top.leaflet-right,
#map-wrap.sim-open .leaflet-bottom.leaflet-right {
  right: 480px;
  transition: right 0.15s ease;
}
@media (max-width: 500px) {
  #map-wrap.plan-open .leaflet-top.leaflet-right,
  #map-wrap.plan-open .leaflet-bottom.leaflet-right,
  #map-wrap.sim-open .leaflet-top.leaflet-right,
  #map-wrap.sim-open .leaflet-bottom.leaflet-right {
    right: 90vw;
  }
}

/* A phone-width panel used to dock right at up to 92vw, which put its
   left edge ON TOP of the bottom-left #map-tools cluster — same z-index,
   later in DOM order, so the panel won the overlap and taps that looked
   like they hit the toolbar silently did whatever the panel had in that
   same spot instead (confirmed by hit-testing the visible "Declutter"
   button's own position and getting back a button from inside the panel).
   That whole class of overlap is gone now rather than worked around: at
   these widths the panels are bottom sheets and #map-tools is the
   full-width tab bar beneath them, so the two stack instead of overlapping
   and the nav stays reachable the entire time. See the MOBILE section at
   the end of this file. */

/* #map-tools (Plan / Simulate / Companion pin / Declutter) is absolutely
   positioned in the bottom-left corner at z-index 1100 — above Leaflet's
   own control corners — so anything Leaflet docks along the bottom edge
   sits underneath the buttons unless it clears them. Lifting the corners
   themselves rather than the individual controls means every bottom-docked
   control is covered, however many of them there are and in whatever order
   they were added (the simulator stacks two: the playback panel and the
   "Map key"). app.js measures the real rendered row into
   --map-tools-clearance so a button row that wraps to two lines on a
   narrow viewport pushes the controls up by the right amount instead of a
   hardcoded single-row guess; the value here is the single-row fallback
   used before that first measurement lands. */
#map-wrap { --map-tools-clearance: 3.25rem; --transport-clearance: 0px; }
#map-wrap .leaflet-bottom.leaflet-left,
#map-wrap .leaflet-bottom.leaflet-right {
  bottom: var(--map-tools-clearance);
}

/* Shared replay transport (see setTransportSource): the bottom-most element
   of the map's bottom stack, spanning the visible map width — it shifts
   left with the docked panels exactly like the Leaflet control corners do,
   so the scrubber never runs underneath the simulator panel. */
.sim-transport {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 1100;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.85rem;
  background: var(--card-bg);
  border-top: 1px solid var(--border);
  box-shadow: 0 -4px 16px rgba(0,0,0,0.4);
  font-size: 0.78rem;
  transition: right 0.15s ease;
}
.sim-transport.hidden { display: none; }
#map-wrap.plan-open .sim-transport { right: 320px; }
#map-wrap.sim-open .sim-transport { right: 480px; }
@media (max-width: 500px) {
  #map-wrap.plan-open .sim-transport,
  #map-wrap.sim-open .sim-transport { right: 90vw; }
}
#sim-transport-play {
  flex-shrink: 0;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--accent);
  color: #fff;
  font-size: 0.85rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
#sim-transport-play:hover { filter: brightness(1.1); }
#sim-transport-seek {
  flex: 1;
  min-width: 80px;
  accent-color: var(--accent);
  cursor: pointer;
}
.sim-transport-time {
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  min-width: 9ch;
  text-align: right;
}
.sim-transport-speed-label { flex-shrink: 0; display: flex; }
#sim-transport-speed {
  background: var(--surface1, #0a1929);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.15rem 0.3rem;
  font-size: 0.72rem;
  cursor: pointer;
}
.sim-transport-label {
  flex-shrink: 0;
  color: var(--text-muted);
  font-size: 0.72rem;
  white-space: nowrap;
}
/* Below the label's breakpoint the bar keeps only the controls that matter
   for driving playback. */
@media (max-width: 700px) {
  .sim-transport-label { display: none; }
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.leaflet-popup-content-wrapper {
  background: var(--card-bg);
  color: var(--text);
  border: 1px solid var(--border);
}
.leaflet-popup-tip { background: var(--card-bg); }

.popup-title {
  font-weight: 700;
  font-size: 1rem;
  margin-bottom: 0.25rem;
}
.popup-row {
  font-size: 0.8rem;
  color: var(--text-muted);
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}
.popup-hint {
  margin-top: 0.35rem;
  font-size: 0.68rem;
  font-style: italic;
  color: var(--text-muted);
  opacity: 0.8;
}
.popup-neighbors {
  margin-top: 0.5rem;
  padding-top: 0.4rem;
  border-top: 1px solid var(--border);
}
.popup-neighbors-title {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 0.25rem;
}
.popup-neighbors ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  max-height: 160px;
  overflow-y: auto;
  font-size: 0.72rem;
}
.popup-neighbors li {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}
.popup-status {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  margin-bottom: 0.4rem;
}
.popup-status.active { background: rgba(74,222,128,0.15); color: var(--status-active); }
.popup-status.degraded { background: rgba(250,204,21,0.15); color: var(--status-degraded); }
.popup-status.silent { background: rgba(100,116,139,0.2); color: var(--status-silent); }

.legend {
  background: var(--card-bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.6rem 0.75rem;
  font-size: 0.75rem;
  max-width: 220px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
}
.legend-title { font-weight: 600; margin-bottom: 0.4rem; }
.legend-bar {
  height: 10px;
  border-radius: 5px;
  background: linear-gradient(90deg, #f97316, #22c55e);
  margin-bottom: 0.25rem;
}
.legend-labels {
  display: flex;
  justify-content: space-between;
  color: var(--text-muted);
  font-size: 0.68rem;
}
.legend-note {
  margin-top: 0.4rem;
  color: var(--text-muted);
  font-size: 0.65rem;
  line-height: 1.3;
}

.legend-opacity {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.45rem;
  font-size: 0.68rem;
  color: var(--text-muted);
}
.legend-opacity input[type="range"] {
  flex: 1;
  accent-color: var(--accent);
}

.scope-filter-control {
  background: var(--card-bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.65rem;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.scope-filter-control label {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  cursor: pointer;
}
.scope-filter-control input[type="checkbox"] {
  accent-color: var(--accent);
}

.position-mode-control {
  background: var(--card-bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.65rem;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.position-mode-control select {
  background: var(--card-bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.2rem 0.3rem;
  font-size: 0.75rem;
}

.map-display-control {
  background: var(--card-bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.65rem;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.map-display-control label {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  cursor: pointer;
  white-space: nowrap;
}
.map-display-control input[type="checkbox"] {
  accent-color: var(--accent);
}

/* Shared collapsible-header pattern — see app.js's window.HopReachMapControls. */
.map-control-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.68rem;
  color: var(--text-muted);
  margin-bottom: 0.15rem;
  cursor: pointer;
  user-select: none;
}
.map-control-header:hover { color: var(--text); }
.map-control-chevron { font-size: 0.6rem; flex-shrink: 0; }
/* At its bare font-size-driven height this measured ~16px tall live — a
   real miss target on a touchscreen, not a near-miss (the ~44px
   guideline). Desktop density is fine as-is and stays untouched; this
   only adds padding below the same narrow-viewport breakpoint used
   elsewhere on this page. */
@media (max-width: 700px) {
  .map-control-header { padding: 0.65rem 0; margin-bottom: 0; min-height: 44px; }
}
.map-control-body.hidden { display: none; }

.sim-playback-control {
  background: var(--card-bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.65rem;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
  width: 240px;
  /* Clearance from #map-tools is handled once for the whole bottom-left
     corner (see --map-tools-clearance above) rather than per-control — a
     margin here only ever lifted whichever control happened to be last in
     the corner, leaving the other one (the "Map key") sitting under the
     buttons. */
}
/* A smaller sim-stat-strip for the map-docked corner — the modal's own
   full-size version (min-width: 4.5rem, larger padding) is comfortable in
   a 560px modal but cramped in a 240px map card; same shared component
   (renderStatStrip), just denser. */
.sim-stat-strip-compact { gap: 0.4rem; margin-bottom: 0; }
.sim-stat-strip-compact .sim-stat { min-width: 3.6rem; padding: 0.25rem 0.5rem; }
.sim-stat-strip-compact .sim-stat-value { font-size: 0.95rem; }

/* Still used by the real-packet replay's own map-docked transport controls
   (ensureBottleneckLegendControl) — NOT dead, unlike the simulated-flood
   playback buttons that used to share this class (see
   ensureSimPlaybackControl, now a live-stats card instead). */
.sim-playback-buttons { margin-bottom: 0.4rem; }
.sim-playback-buttons button {
  flex: 1;
  background: var(--surface1, #0a1929);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.3rem 0.4rem;
  font-size: 0.72rem;
  cursor: pointer;
}
.sim-playback-buttons button:hover { border-color: var(--accent); }

/* The real-packet replay's map-docked control (see
   ensureBottleneckLegendControl): transport buttons, live status, and the
   key for the line colours. Sized to match .sim-playback-control so the two
   stack tidily in the same corner. */
.sim-bottleneck-legend {
  background: var(--card-bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.65rem;
  font-size: 0.72rem;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
  width: 240px;
}
.sim-real-replay-controls { margin-bottom: 0.5rem; }
.sim-real-replay-controls .plan-hint { margin: 0; font-size: 0.68rem; }
.sim-flood-reach-toggle {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0.35rem 0;
  font-size: 0.7rem;
  color: var(--text-muted);
  cursor: pointer;
}
.sim-flood-reach-toggle input[type="checkbox"] { accent-color: var(--accent); }
.sim-map-open-analysis {
  display: block;
  width: 100%;
  margin-top: 0.5rem;
  background: var(--surface1, #0a1929);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.3rem 0.4rem;
  font-size: 0.72rem;
  cursor: pointer;
}
.sim-map-open-analysis:hover { border-color: var(--accent); }
.map-control-header-static {
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--text-muted);
  margin-bottom: 0.3rem;
}
.sim-legend-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.1rem 0;
  white-space: nowrap;
}
.sim-legend-swatch {
  display: inline-block;
  width: 18px;
  height: 3px;
  border-radius: 2px;
  flex-shrink: 0;
}
.sim-legend-swatch.sim-legend-dashed {
  background: none;
  border-top: 3px dashed;
  height: 0;
}

.leaflet-control-layers {
  background: var(--card-bg) !important;
  color: var(--text) !important;
  border: 1px solid var(--border) !important;
}

/* Precision/Calibrated Precision coverage overlay: nearest-neighbour
   scaling instead of the browser's default smooth (bilinear) upscaling,
   so zooming in reveals the raster's real per-pixel detail as crisp
   squares rather than blurring it into a soft gradient. */
.coverage-crisp {
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
}
.leaflet-control-layers-expanded { padding: 0.5rem 0.75rem !important; }

#error-banner {
  display: none;
  background: #7f1d1d;
  color: #fecaca;
  padding: 0.5rem 1.25rem;
  font-size: 0.85rem;
}

#progress-banner {
  background: var(--card-bg);
  border-bottom: 1px solid var(--border);
  padding: 0.5rem 1.25rem;
  display: flex;
  align-items: center;
  gap: 1rem;
}
#progress-banner.hidden { display: none; }
#progress-text {
  font-size: 0.8rem;
  color: var(--text-muted);
  white-space: nowrap;
  flex-shrink: 0;
}
.progress-track {
  flex: 1;
  height: 8px;
  border-radius: 4px;
  background: rgba(255,255,255,0.08);
  overflow: hidden;
}
#progress-fill {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, #f97316, #22c55e);
  transition: width 0.4s ease;
}
