/* SkyBag v0.1 — base styles */

:root {
  --bg-deep: #0f1620;
  --bg-mid: #131c28;
  --bg-map: #1a2538;
  --border-faint: rgba(255, 255, 255, 0.08);
  --border-soft: rgba(255, 255, 255, 0.12);
  --text-primary: #c2c0b6;
  --text-muted: #888780;
  --text-dim: #5f5e5a;
  --accent-teal: #5dcaa5;
  --accent-teal-dark: #04342c;
  --accent-amber: #fac775;
  --color-hourly: #5dcaa5;
  --color-synoptic: #2f8f5a;   /* dark green — was amber #ef9f27 until 2026-09-07 (Roy) */
  --color-gapfill: #ba7517;
  --color-nexrad-live: #6b7a99;
  /* Historical MRMS detents — light gray (Roy, 2026-07-10; was dark navy),
     distinct from the teal/orange forecast bands. */
  --color-observed: #a9b1ba;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif;
  font-size: 13px;
  color: var(--text-primary);
  background: var(--bg-deep);
}

body {
  display: flex;
  flex-direction: column;
}

/* Top header bar */
.topbar {
  display: flex;
  align-items: center;
  /* row-gap kept tight (was 16px) so wrapped rows on iPhone/iPad don't
     stack with extra vertical air; column-gap unchanged. */
  column-gap: 16px;
  row-gap: 6px;
  padding: 10px 14px;
  background: var(--bg-deep);
  border-bottom: 0.5px solid var(--border-faint);
  flex-shrink: 0;
  flex-wrap: wrap;
  z-index: 1000;
}

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.status-dot {
  width: 8px;
  height: 8px;
  background: var(--accent-teal);
  border-radius: 50%;
}

.brand-name {
  font-weight: 500;
  color: var(--text-primary);
}

.route-input {
  background: #0a1118;
  border: 0.5px solid var(--border-soft);
  color: var(--text-primary);
  padding: 5px 28px 5px 10px;   /* right padding clears the search icon */
  font-size: 13px;
  width: 200px;
  border-radius: 6px;
  font-family: 'SF Mono', Menlo, monospace;
  outline: none;
}

.route-input:focus {
  border-color: var(--accent-teal);
}


/* Wrap the input so the magnifier can sit absolutely inside its right edge
   without changing the input's layout footprint. On iPhone portrait
   (existing .topbar grid rules) .route-input is flex:1 — the wrap inherits
   the same flex slot, keeping header sizing identical. */
.route-input-wrap {
  position: relative;
  display: inline-block;
}

@media (max-width: 600px) {
  .route-input-wrap {
    display: flex;
    flex: 1;
    flex-basis: 0;
    min-width: 0;
  }
  .route-input-wrap .route-input {
    width: 100%;
  }
}

.search-toggle {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  padding: 0;
  border-radius: 4px;
  transition: color 0.12s ease, background 0.12s ease;
}
.search-toggle:hover,
.search-toggle:focus-visible {
  color: var(--accent-teal);
  outline: none;
}
.search-toggle[aria-expanded="true"] {
  color: var(--accent-teal);
}
.search-toggle svg { display: block; }

/* Search panel — desktop / iPad: small dropdown anchored under the route
   input. iPhone portrait: switches to a full-width overlay (see media
   block below) so it doesn't fight the narrow header. */
.search-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  width: 320px;
  max-width: 90vw;
  background: rgba(15, 22, 32, 0.97);
  border: 0.5px solid var(--border-soft);
  border-radius: 8px;
  padding: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.search-panel[hidden] { display: none; }

.search-input {
  background: #0a1118;
  border: 0.5px solid var(--border-soft);
  color: var(--text-primary);
  padding: 6px 10px;
  font-size: 13px;
  border-radius: 6px;
  font-family: inherit;
  outline: none;
}
.search-input:focus {
  border-color: var(--accent-teal);
}

.search-results {
  display: flex;
  flex-direction: column;
  max-height: 360px;
  overflow-y: auto;
}
.search-result {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 7px 8px;
  border-radius: 4px;
  cursor: pointer;
  color: var(--text-primary);
  font-size: 13px;
  line-height: 1.25;
}
.search-result:hover,
.search-result.active {
  background: rgba(93, 202, 165, 0.10);
  color: var(--accent-teal);
}
.search-result-id {
  font-family: 'SF Mono', Menlo, monospace;
  font-size: 12px;
  color: var(--accent-teal);
  flex-shrink: 0;
  min-width: 48px;
}
.search-result-name {
  color: var(--text-primary);
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.search-result:hover .search-result-name,
.search-result.active .search-result-name {
  color: var(--text-primary);
}
.search-empty,
.search-more {
  padding: 6px 8px;
  font-size: 11px;
  color: var(--text-muted);
  font-style: italic;
}

/* iPhone portrait: overlay style — full-width below the header, dismissable
   via outside-tap or the icon. Uses position:fixed so it floats over the
   crowded narrow-viewport header without being clipped. */
@media (max-width: 600px) and (orientation: portrait) {
  .search-panel {
    position: fixed;
    top: auto;
    left: 8px;
    right: 8px;
    width: auto;
    max-width: none;
    /* Anchor near the top below the header — the topbar's actual height
       varies as the user types/expands, so we pin to a sensible offset
       rather than chasing it. */
    top: 56px;
    max-height: calc(100vh - 80px);
  }
  .search-results { max-height: 60vh; }
}

/* Search-result highlight pulse — fades after ~3s via JS removeLayer.
   Pulses a teal ring around the selected airport. divIcon wrapper so the
   keyframe scales the ring, not a Leaflet circleMarker (which would need
   per-frame setStyle to pulse). */
.search-pulse {
  position: relative;
  width: 32px;
  height: 32px;
  pointer-events: none;
}
.search-pulse::before,
.search-pulse::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid var(--accent-teal);
  box-sizing: border-box;
  animation: search-pulse-ring 1.4s ease-out infinite;
}
.search-pulse::after { animation-delay: 0.7s; }

@keyframes search-pulse-ring {
  0%   { transform: scale(0.35); opacity: 0.95; }
  100% { transform: scale(1.0);  opacity: 0;    }
}

.btn {
  background: transparent;
  color: var(--text-primary);
  border: 0.5px solid var(--border-soft);
  padding: 5px 8px;
  font-size: 12px;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.15s, border-color 0.15s;
}

.btn:hover {
  background: rgba(255, 255, 255, 0.04);
}

.btn:active {
  transform: scale(0.98);
}

.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn:disabled:hover {
  background: transparent;
}

.btn-primary {
  background: var(--accent-teal);
  color: var(--accent-teal-dark);
  border: none;
  font-weight: 500;
  padding: 5px 10px;
}

.btn-primary:hover {
  background: #6fd5b3;
}

.btn-cycle {
  padding: 5px 6px;
  font-size: 11px;
}
.btn-cycle[data-state="HRRR"],
.btn-cycle[data-state="NEXRAD"],
.btn-cycle[data-state="Both"],
.btn-cycle[data-state="On"],
.btn-cycle[data-state="VFR"],
.btn-cycle[data-state="IFR"] {
  background: rgba(93, 202, 165, 0.12);
  color: var(--accent-teal);
  border-color: rgba(93, 202, 165, 0.4);
}

.btn-cycle[data-state="None"],
.btn-cycle[data-state="Off"],
.btn-cycle[data-state="Street"] {
  background: transparent;
  color: var(--text-primary);
  border-color: var(--border-soft);
}

.readout {
  display: flex;
  gap: 12px;
  padding-left: 16px;
  border-left: 0.5px solid var(--border-faint);
  font-size: 12px;
}

.readout-label {
  color: var(--text-muted);
  margin-right: 4px;
}

.header-right {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-left: auto;
}

.header-buttons {
  display: flex;
  gap: 6px;
}

.status {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.3;
  padding-left: 12px;
  border-left: 0.5px solid var(--border-faint);
  font-family: 'SF Mono', Menlo, monospace;
}

.status-hrrr {
  color: var(--accent-teal);
}

/* Map area */
#map {
  flex: 1;
  background: var(--bg-map);
  position: relative;
  min-height: 0;
}

/* Leaflet control theming for dark UI */
.leaflet-control-zoom a {
  background: rgba(15, 22, 32, 0.85) !important;
  color: var(--text-primary) !important;
  border: 0.5px solid var(--border-soft) !important;
}

.leaflet-control-zoom a:hover {
  background: rgba(15, 22, 32, 0.95) !important;
  color: var(--accent-teal) !important;
}

.leaflet-control-attribution {
  background: rgba(15, 22, 32, 0.7) !important;
  color: var(--text-muted) !important;
  font-size: 10px !important;
  padding: 2px 6px !important;
}

.leaflet-control-attribution a {
  color: var(--text-primary) !important;
}

/* Bottom timeline */
.timeline {
  display: flex;
  align-items: center;
  /* flex-wrap lets .forecast-quote break to its own row below the slider/readout */
  flex-wrap: wrap;
  gap: 12px;
  /* Extra bottom padding clears the iOS home-indicator gesture zone in
     portrait mode; on desktop it's just a bit of breathing room. */
  padding: 12px 14px 36px;
  background: var(--bg-mid);
  border-top: 0.5px solid var(--border-faint);
  flex-shrink: 0;
  z-index: 1000;
}

/* Made-up aphorism printed below the slider. JS adds either
   .forecast-quote--dimmed (iPad/desktop/iPhone landscape: stays as quiet
   flavor text) or .forecast-quote--collapsed (iPhone portrait: vanishes
   entirely so the tight bottom strip reclaims its vertical space) after
   QUOTE_DISPLAY_MS in app.js. */
.forecast-quote {
  flex-basis: 100%;
  font-style: italic;
  /* Entrance state (Roy, 2026-07-10): double-size bright red for the first
     QUOTE_DISPLAY_MS, then the --dimmed class shrinks it back to the quiet
     12px cranberry flavor text. */
  font-size: 24px;
  text-align: center;
  color: #ff3b30;
  padding: 4px 6px 0;
  max-height: 90px;
  overflow: hidden;
  opacity: 1;
  transition:
    font-size 0.6s ease,
    color 0.8s ease,
    opacity 0.8s ease,
    max-height 0.5s ease 0.3s,
    padding 0.5s ease 0.3s,
    margin 0.5s ease 0.3s;
}

.forecast-quote--dimmed {
  /* Recede to quiet flavor: small again, darker cranberry, faded */
  font-size: 12px;
  color: #a52a3b;
  opacity: 0.55;
}

.forecast-quote--collapsed {
  opacity: 0;
  max-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  margin: 0;
}

.slider-wrapper {
  flex: 1;
  position: relative;
}

#forecast-slider {
  width: 100%;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  cursor: pointer;
}

#forecast-slider::-webkit-slider-runnable-track {
  height: 8px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 4px;
}

#forecast-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--accent-teal);
  border: 2px solid var(--bg-mid);
  /* Centers the thumb over the track: -(thumb - track) / 2 = -(30-8)/2 */
  margin-top: -11px;
  cursor: pointer;
}

#forecast-slider::-moz-range-track {
  height: 8px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 4px;
}

#forecast-slider::-moz-range-thumb {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--accent-teal);
  border: 2px solid var(--bg-mid);
  cursor: pointer;
}

.run-bar {
  display: flex;
  height: 6px;
  gap: 1px;
  margin-top: 4px;
  background: rgba(255, 255, 255, 0.04);
  border-radius: 1px;
}

/* Step 15: run-bar segments */
.run-seg {
  flex: 1;
  height: 100%;
  min-width: 0;
  cursor: default;
}

.run-seg--nexrad-live { background: var(--color-nexrad-live); }
.run-seg--observed    { background: var(--color-observed); }
.run-seg--hourly      { background: var(--color-hourly); }
/* Bands darken with forecast age (Roy, 2026-09-07: bright green -> dark
   green -> brown; the middle band was amber from 2026-07-10). buildRunBar
   assigns these POSITIONALLY — 1st source run bright green, 2nd dark green,
   3rd+ brown — because which run is "synoptic" vs "gap-fill" varies with
   the stitch and had the middle/tail colors trading places. */
.run-seg--mid         { background: var(--color-synoptic); }
.run-seg--far         { background: var(--color-gapfill); }
.run-seg--empty       { background: rgba(255, 255, 255, 0.06); }

/* Red rule at the observed/forecast boundary (historicalRadar). A zero-flex
   run-bar child between the Now and T+0 segments; taller than the 6px bar so
   it reads as a tick rising over the slider track. Aesthetic only. */
.run-boundary {
  flex: 0 0 2px;
  height: 18px;
  margin-top: -12px;
  background: #d93a3a;
  border-radius: 1px;
  pointer-events: none;
}

/* Floating forecast readout pill — anchored to #map (its position:relative
   parent), top-center under the header's input row, so it holds position
   whether the header is expanded or collapsed. pointer-events:none so map
   drag/zoom passes straight through. z-index sits above Leaflet panes/controls
   but below the header + search overlay (z 1000). Frosted style mirrors the
   dBZ legend / info button. No transition: it must snap during fast scrubbing. */
.forecast-readout {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 900;
  pointer-events: none;
  padding: 5px 14px;
  background: rgba(15, 22, 32, 0.78);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 0.5px solid var(--border-soft);
  border-radius: 999px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
  font-family: 'SF Mono', Menlo, monospace;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-primary);
  white-space: nowrap;
  text-align: center;
}

/* Step 19: dBZ legend */
.dbz-legend {
  background: rgba(15, 22, 32, 0.88);
  border: 0.5px solid var(--border-soft);
  border-radius: 6px;
  padding: 7px 9px;
  font-family: 'SF Mono', Menlo, monospace;
  font-size: 10px;
  color: var(--text-muted);
  line-height: 1;
  pointer-events: none;
}

.legend-title {
  text-align: center;
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-dim);
  margin-bottom: 5px;
}

.legend-row {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 3px;
}

.legend-row:last-child {
  margin-bottom: 0;
}

.legend-swatch {
  width: 11px;
  height: 11px;
  border-radius: 2px;
  flex-shrink: 0;
  display: inline-block;
}

/* "How it works" info button — bottom-right floating control. Lives inside
   the Leaflet map, mirrors the dBZ-legend visual style, sized large enough
   for a comfortable tap on iPhone (Apple HIG: 44 px min). */
/* White on a dark backing disc (Roy, 2026-07-10: more prominent — white
   over red, which reads as a warning in this app). The disc keeps it
   legible over the light VFR/IFR chart bases where the old transparent
   teal all but vanished. 44 px base size also satisfies the Apple HIG
   minimum everywhere, so the old iPhone-portrait override is gone. */
/* Scoped under .leaflet-container so the color beats leaflet.css's
   `.leaflet-container a` link-blue (higher specificity than a lone class —
   the old teal was silently losing to it too). */
.leaflet-container .info-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(15, 22, 32, 0.78);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  color: #ffffff;
  text-decoration: none;
  transition: color 0.12s ease, border-color 0.12s ease;
}
.leaflet-container .info-btn:hover,
.leaflet-container .info-btn:focus-visible {
  color: var(--accent-teal);
  border-color: rgba(93, 202, 165, 0.6);
  outline: none;
}
.info-btn svg { display: block; }

/* Step 7b: route input error state — a solid muted-red fill reads as a clearer
   "this needs attention" cue than the original 1px outline. Color chosen to
   stay legible behind the light-gray input text on the dark theme.
   -webkit-appearance: none is required so Safari (desktop + iOS) honors the
   custom background; without it the default text-input chrome wins and only
   the border color comes through, giving the impression of an outline-only style. */
.route-input.error,
input.error {
  -webkit-appearance: none;
  appearance: none;
  background-color: #8a2929 !important;
  border-color: #c25656;
}

/* Forces the topbar's second row: everything after the Dist/ETE readout
   (flight inputs, buttons, status, chevron) wraps below the route line.
   Hidden when collapsed so the single collapsed row stays intact. */
.topbar-break {
  flex-basis: 100%;
  height: 0;
}

.topbar--collapsed .topbar-break {
  display: none;
}

/* Step 18+: speed and departure inputs.
   No left divider — the break above means this always starts its row. */
.flight-inputs {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-wrap: wrap;
  row-gap: 6px;
}

.flight-input-group {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-wrap: nowrap;
}

.flight-input {
  background: #0a1118;
  border: 0.5px solid var(--border-soft);
  color: var(--text-primary);
  padding: 5px 8px;
  font-size: 13px;
  border-radius: 6px;
  font-family: 'SF Mono', Menlo, monospace;
  outline: none;
  width: 54px;
}

.flight-input:focus {
  border-color: var(--accent-teal);
}

.flight-input--dep {
  width: 62px;
}

.flight-input--dep-date {
  width: 115px;
  color-scheme: dark;
}

.flight-input--stop {
  width: 72px;
}

.flight-input--stop-min {
  width: 52px;   /* fits 3 digits with room to spare */
}

/* Remove number-input spin arrows */
.flight-input[type="number"]::-webkit-inner-spin-button,
.flight-input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}

.flight-input[type="number"] {
  -moz-appearance: textfield;
}

/* Input fill-state classes — toggled by JS */
.input-empty {
  background: rgba(250, 199, 117, 0.15) !important;
}

.input-filled {
  background: #2a3340 !important;
}

/* Step 18+: aircraft icon — reset Leaflet divIcon defaults */
.aircraft-icon {
  background: transparent !important;
  border: none !important;
}

/* Narrow viewports (iPhone portrait + small landscapes): push .flight-inputs
   onto its own topbar row so the Stop airport + min-input never get clipped
   off-screen. flex-basis: 100% in a flex-wrap container is the canonical
   "break to a new line" trick.

   This block also carries the iPhone-only polish for v0.3:
   - Inputs at 16px so Mobile Safari doesn't auto-zoom on focus.
   - Bigger tap targets on buttons + inputs (Apple HIG min is 44px; we
     compromise at ~36px to keep the topbar from blowing up vertically).
   - Safe-area insets on the topbar (status bar) and timeline (home
     indicator + landscape notch) so standalone mode doesn't clip. */
@media (max-width: 600px) {
  .flight-inputs {
    flex-basis: 100%;
  }

  .route-input,
  .flight-input {
    font-size: 16px;
  }

  .status {
    align-items: center;
    text-align: center;
  }

  .topbar {
    padding-top: max(10px, env(safe-area-inset-top));
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }

  .timeline {
    padding-bottom: max(36px, env(safe-area-inset-bottom));
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }
}

/* iPhone portrait only: tighten the topbar — hide brand, compact the
   Dist/ETE readout to "1,252 nm, 7h 31m" form, drop the forecast readout
   to its own row so the slider gets full width. */
@media (max-width: 600px) and (orientation: portrait) {
  .brand {
    display: none;
  }

  /* Stretch route input to fill row 1, leaving the Dist/ETE readout sized
     to its content. flex-basis: 0 so the readout's intrinsic width wins
     the row-1 sizing; route-input takes the rest. */
  .route-input {
    flex: 1;
    flex-basis: 0;
    min-width: 0;
    width: auto;
  }

  /* Stop input narrowed to fit the "stop" placeholder (and a typical
     4-char ICAO like KAXQ). 5-char IDs may clip slightly. */
  .flight-input--stop {
    width: 56px;
  }

  /* Min input at its 3-digit floor for 16px mono (3×9.6 + 10px padding
     + border ≈ 40; 44 keeps a hair of air). The 52px base would push
     the flight-input row past ~390px viewports and wrap it. */
  .flight-input--stop-min {
    width: 44px;
  }

  /* Date input widened to give iOS Safari's native control room to
     render the full date on one line (was wrapping to 2 lines inside
     the field at 115px). */
  .flight-input--dep-date {
    width: 140px;
  }

  /* Speed input at its 3-digit floor (same math as the min input above;
     kt label is hidden via .readout-label rule, so the input stands
     alone and the "Kts" placeholder covers the empty state). */
  #speed-input {
    width: 40px;
  }

  /* Tighter horizontal padding on flight inputs to free row width so
     Stop+Min stays inline with the dep date+time. */
  .flight-input {
    padding: 5px 5px;
  }

  .readout {
    gap: 4px;
  }
  .readout-label {
    display: none;
  }
  .readout-item:first-child::after {
    content: ",";
  }

  /* Action-button row: Plot/Layer/Airspace/Refresh + status pinned left,
     chevron pinned right. Requires .header-right to take a full row so
     the auto margin has space to push against. */
  .header-right {
    flex-basis: 100%;
    margin-left: 0;
  }
  #collapse-btn {
    margin-left: auto;
  }

  .timeline {
    flex-wrap: wrap;
    row-gap: 6px;
  }
  /* Compact the floating pill on iPhone portrait; it stays anchored to the
     map (it's no longer a flex child of the timeline footer). Always visible. */
  .forecast-readout {
    top: 8px;
    padding: 4px 12px;
    font-size: 13px;
  }

  /* Reclaim vertical space below the slider. The 36px floor inherited
     from the iPhone block above was sized for PWA home-indicator
     clearance; in Safari browser mode env(safe-area-inset-bottom)
     reports ~0 and the OS already reserves the URL-bar strip, so the
     36px sat unused. 8px keeps a small breathing room and lets
     standalone mode get the real home-indicator inset from env(). */
  .timeline {
    padding-bottom: max(8px, env(safe-area-inset-bottom));
  }
}

/* iPhone portrait, PWA standalone only: the home-indicator safe-area
   inset (~34px) added above leaves a dead band of dark space below the
   slider. Reclaim it — the slider can sit close to the bottom edge; the
   home-indicator gesture still works. Browser mode unchanged. */
@media (display-mode: standalone) and (max-width: 600px) and (orientation: portrait) {
  .timeline {
    padding-bottom: 4px;
  }
}

/* iPhone landscape only. Targets iPhone landscape via short viewport +
   landscape orientation — doesn't catch iPad or desktop. */
@media (max-height: 500px) and (orientation: landscape) {
  /* Inputs at 16px to suppress Mobile Safari's auto-zoom on focus
     (same fix as portrait, was scoped to max-width:600px so missed
     landscape). */
  .route-input,
  .flight-input {
    font-size: 16px;
  }

  /* Tighter horizontal padding offsets the larger font so total row
     width usage actually drops vs the prior 13px/8px layout. */
  .flight-input {
    padding: 5px 5px;
  }

  /* Speed input: fits "180" at 16px (~29px text) + 10px padding. */
  #speed-input {
    width: 42px;
  }

  /* Date input: same width as portrait so iOS Safari's native date
     control has room to render the full date on one line at 16px font. */
  .flight-input--dep-date {
    width: 140px;
  }

  /* Departure time, Stop, and Stop-min sized to their text floors at
     16px font + 5px padding. Frees ~24px to offset the date widening. */
  .flight-input--dep {
    width: 58px;
  }
  .flight-input--stop {
    width: 50px;
  }
  .flight-input--stop-min {
    width: 48px;
  }
}

/* iPad portrait, both Safari and PWA. Tightens the three numeric/short
   inputs whose base widths are sized for desktop so row 1 of the topbar
   has a chance of not wrapping. iPhone portrait is excluded by
   min-width: 600px (it has its own tighter values in the max-width:600
   block). iPad landscape is excluded by orientation: portrait. May not
   fully un-wrap row 1 on iPad Mini (768px) or 11" Pro (834px) — those
   may need additional levers (hide brand, hide readout labels, etc.)
   per the planning note. */
@media (orientation: portrait) and (min-width: 600px) {
  #speed-input              { width: 40px; }  /* was 54; fits "180"/"999" at 13px */
  .flight-input--stop       { width: 56px; }  /* was 72; fits "Stop ID" placeholder */
  .flight-input--stop-min   { width: 44px; }  /* fits "min" + 3-digit max; row-width pressure eased now that flight inputs live on topbar row 2 */
}

/* iPad PWA standalone (both orientations).
   Browser mode is excluded by display-mode: standalone — Safari's URL
   bar already provides top clearance, so iPad-in-browser is fine.
   iPhone is excluded by min-width: 600px + min-height: 500px (iPhone
   Pro Max landscape is 932×430, so the min-height floor knocks it out;
   iPhone portrait is ≤430 wide, so min-width knocks it out). All iPad
   models satisfy both floors in both orientations. */
@media (display-mode: standalone) and (min-width: 600px) and (min-height: 500px) {
  .topbar {
    /* Without this, the topbar sits flush under the OS status bar /
       camera-cutout zone and the inputs land in dead tap area.
       env(safe-area-inset-top) reports the real inset on devices with
       a cutout; the 20px floor covers older iPads where env() is 0. */
    padding-top: max(20px, env(safe-area-inset-top));
  }

  .timeline {
    /* Trim the 36px bottom floor (sized for iPhone portrait home
       indicator). env(safe-area-inset-bottom) gives iPad's real
       indicator clearance; the 16px floor keeps a small breathing
       room when env() is 0. */
    padding-bottom: max(16px, env(safe-area-inset-bottom));
  }
}

/* Collapse toggle: user taps the chevron to hide the entire input area
   (route, dist/ETE readout, flight inputs). State persisted in localStorage.
   Tinted in the slider's middle-band color (matches the run-bar segments)
   so it visually ties to the timeline strip. Glyph stays at 32px. */
.btn-icon {
  padding: 0 8px;
  font-size: 32px;
  line-height: 1;
  background: rgba(47, 143, 90, 0.12);
  color: var(--color-synoptic);
  border-color: rgba(47, 143, 90, 0.4);
}

.topbar--collapsed .route-input,
.topbar--collapsed #plot-btn,
.topbar--collapsed .readout,
.topbar--collapsed .flight-inputs {
  display: none;
}

/* VFR base state: map backdrop matches the FAA sectional ocean tint
   (sampled from the charts: rgb(173,210,222)) so tile-load gaps and any
   area beyond OSM read as continuous water. Toggled by applyBaseState. */
.map--vfr {
  background: #add2de;
}

/* METAR/TAF station popup (SPEC-metar-taf-v0.1). Leaflet's default white
   popup chrome is kept; these just format the decoded rows and raw text. */
.wx-popup {
  font: 12px/1.5 -apple-system, "Helvetica Neue", Arial, system-ui, sans-serif;
  color: #1a2538;
}
.wx-popup-head {
  font-weight: 700;
  font-size: 13px;
  margin-bottom: 5px;
}
.wx-popup .wx-k {
  display: inline-block;
  min-width: 74px;
  color: #667;
}
.wx-popup-sub {
  font-weight: 700;
  font-size: 12px;
  margin-top: 8px;
  padding-top: 6px;
  border-top: 1px solid #dde;
}
.wx-raw {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  margin-top: 6px;
  padding-top: 5px;
  border-top: 1px solid #dde;
  color: #445;
  word-break: break-word;
  max-width: 300px;
}

/* Tap-to-add nearby-points popup (SPEC-tap-to-add-fixes-v0.1). Rides the
   default Leaflet popup chrome like the wx popup does. */
.nearby-popup {
  font: 13px/1.4 -apple-system, "Helvetica Neue", Arial, system-ui, sans-serif;
  color: #1a2538;
  min-width: 210px;
}
.nearby-row {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 7px 4px;
  border-radius: 6px;
  cursor: pointer;
}
.nearby-row:hover { background: rgba(93, 202, 165, 0.18); }
.nearby-row + .nearby-row { border-top: 1px solid #e6e9ef; }
.nearby-sym { display: inline-flex; width: 14px; }
.nearby-id { font-weight: 700; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
.nearby-name {
  flex: 1;
  color: #667;
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nearby-dist { color: #445; font-variant-numeric: tabular-nums; }

/* Long-press must not pop the iOS callout / text selection on the map. */
.leaflet-container { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }

/* Route reorder dialog (spec §5): dark-theme modal with draggable pills. */
/* display:flex on the class would beat the UA's [hidden]{display:none} —
   same trap .search-panel[hidden] already guards against. */
.reorder-overlay[hidden] { display: none; }
.reorder-overlay {
  position: fixed;
  inset: 0;
  z-index: 3000;
  background: rgba(6, 10, 16, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px;
}
.reorder-dialog {
  /* No text selection anywhere in the dialog: a long-press on a pill was
     popping the iOS copy/find callout mid-drag (Roy, 2026-07-10). */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  background: #16202e;
  border: 1px solid var(--border-soft, #2a3a50);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
  width: min(420px, 92vw);
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  padding: 14px;
  color: var(--text-primary, #d7dde6);
}
.reorder-head {
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 10px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}
.reorder-hint { font-weight: 400; font-size: 11px; color: #8b98a9; }
.reorder-list { overflow-y: auto; display: flex; flex-direction: column; gap: 6px; }
.reorder-pill {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 8px;
  background: rgba(93, 202, 165, 0.08);
  border: 1px solid rgba(93, 202, 165, 0.3);
  border-radius: 9px;
}
/* The lifted ghost that follows the finger while dragging. left/top/width
   are set inline from the grab point. */
.reorder-pill.dragging {
  position: fixed;
  z-index: 3200;
  margin: 0;
  background: #1b2a3d;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.55);
  opacity: 0.95;
  pointer-events: none;   /* the captured grip keeps streaming events */
}
/* Dashed slot showing where the lifted pill will land. */
.reorder-placeholder {
  border: 1.5px dashed rgba(93, 202, 165, 0.55);
  border-radius: 9px;
  background: rgba(93, 202, 165, 0.06);
  flex-shrink: 0;
}
/* The grip is THE drag handle — big, obvious, and the only drag surface. */
.reorder-grip {
  width: 42px;
  height: 42px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  color: var(--accent-teal);
  background: rgba(93, 202, 165, 0.12);
  border: 1px solid rgba(93, 202, 165, 0.35);
  border-radius: 8px;
  cursor: grab;
  touch-action: none;     /* pointer-drag on touch needs this on the handle */
}
.reorder-pill.dragging .reorder-grip { cursor: grabbing; }
.reorder-id { font-weight: 700; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
.reorder-name {
  flex: 1;
  font-size: 11px;
  color: #8b98a9;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.reorder-remove {
  background: transparent;
  border: none;
  color: #c25656;
  font-size: 17px;
  cursor: pointer;
  padding: 10px 12px;     /* comfortable iPhone touch target */
  flex-shrink: 0;
}
.reorder-actions { display: flex; gap: 8px; margin-top: 12px; align-items: center; }
.reorder-spacer { flex: 1; }

/* Current-location dot (SPEC-user-location-v0.1). pointer-events off so
   the marker never blocks taps/long-press on symbols beneath it. Standard
   blue location dot: white ring over #007aff. */
.loc-icon { pointer-events: none; }
.loc-dot {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #007aff;
  border: 3px solid #ffffff;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.45);
}

/* Lift the dBZ legend clear of Leaflet's attribution strip, which spans
   under the control corner on narrow screens (Roy, 2026-07-10). Scoped
   under .leaflet-bottom to outrank leaflet.css's own margin rule. */
.leaflet-bottom .dbz-legend {
  margin-bottom: 26px;
}

/* Fly-in hotels (SPEC-flyin-hotels-v0.1): the Nav button's third state
   shows a bed icon and stays teal like an active state; the long-press
   nearby list marks lodging airports with the same glyph in gold. */
.btn-cycle[data-state="Hotels"] {
  background: rgba(93, 202, 165, 0.12);
  color: var(--accent-teal);
  border-color: rgba(93, 202, 165, 0.4);
}
#airspace-btn svg { display: block; margin: 1px 2px; }
.nearby-bedicon {
  display: inline-flex;
  color: #d4a017;
  flex-shrink: 0;
}
.nearby-bedicon svg { width: 14px; height: 11px; }

/* Clear-route: destructive action, bottom-left of the reorder dialog
   (Roy, 2026-07-11) — same muted red family as input error states. */
.reorder-clear {
  background: #8a2929;
  border-color: #c25656;
  color: #f3dede;
}
.reorder-clear:hover { background: #a03030; }

/* Lodging booking link inside popups — chart-blue, clearly tappable. */
.wx-popup .wx-book {
  color: #1d5c8f;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Route text input inside the reorder dialog — same dark styling as the
   header input. user-select must be re-enabled: the dialog disables it
   globally (iOS callout suppression), which would break the caret here. */
.reorder-input {
  -webkit-user-select: text;
  user-select: text;
  background: #0a1118;
  border: 1px solid var(--border-soft);
  color: var(--text-primary);
  padding: 9px 10px;
  font-family: 'SF Mono', Menlo, monospace;
  font-size: 13px;
  border-radius: 8px;
  margin-bottom: 10px;
  outline: none;
  width: 100%;
}
.reorder-input:focus { border-color: var(--accent-teal); }
.reorder-pill--unknown {
  border-color: #c25656;
  background: rgba(138, 41, 41, 0.18);
}
.reorder-pill--unknown .reorder-name { color: #c25656; }

/* ---------------------------------------------------------------------------
   iOS focus zoom (Roy, 2026-09-12)
   ---------------------------------------------------------------------------
   iOS Safari zooms the whole page whenever a focused input's computed
   font-size is under 16px, and leaves the map zoomed afterwards. Every text
   input here was 13px: .route-input, the .search-input inside the search
   dialog, the five .flight-input fields, and .reorder-input — the one in the
   "Reorder route" dialog, which is the popup Roy was actually tapping. It is
   built in JS (app.js), not in index.html, which is why the first two passes
   at this missed it.

   16px is the OS threshold, so raising it is the fix, not a workaround. The
   viewport's maximum-scale=5.0 does not suppress this, and maximum-scale=1
   would disable pinch-zoom on the map — the wrong trade for a chart app.

   This block lives at the END of the file deliberately: .search-input (line
   ~170) and .flight-input (line ~706) declare 13px at equal specificity, so
   an earlier block loses to them on source order.

   iPhone only, both orientations — portrait matches max-width:600px, landscape
   matches the max-height:500px idiom used above. Desktop keeps the 13px
   design. type=range is excluded: sliders do not take focus zoom.
   --------------------------------------------------------------------------- */
@media (max-width: 600px), (max-height: 500px) and (orientation: landscape) {
  .route-input,
  .search-input,
  .flight-input,
  .reorder-input {
    font-size: 16px;
  }
}
