/* ── Flight Tracker ───────────────────────────────────────────────
   Palette: neutral slate ground, cool glacier-blue for live/active,
   bone for text, muted steel for chrome, signal-red for tight links.
   The brand accent (--brand) is deliberately cool and fairly desaturated —
   an instrument-panel blue, not a saturated "look at me" brand color —
   so it reads as chrome rather than competing with the traveler colors
   (config/palette.js), which stay untouched and are the only saturated
   hues in the UI.
   Dark is the baseline theme below; [data-theme="light"] overrides it.
   The inline script in index.html's <head> always stamps a resolved
   data-theme ("light" or "dark") on <html> — including for "System",
   resolved from prefers-color-scheme at apply time — so these two blocks
   are the only palettes needed. */
:root {
  --ink: #0d1013;
  --panel: #161a1f;
  --panel-2: #1d2229;
  --line: #2a2f37;
  --bone: #e7e9ec;
  --bone-dim: #99a1ab;
  --brand: #7dabc9;
  --brand-soft: #7dabc92a;
  --brand-ink: #0b1a22;
  --green: #5fd08a;
  --red: #e2574c;
  --steel: #6c7681;
  --radius: 4px;
  --mono: "Spline Sans Mono", ui-monospace, monospace;
  --display: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --water: #0d1216;
  --land: #202730;
  --land-line: #2c3541;
  --glow: #17202a;
  --topbar-bg: rgba(13, 16, 19, 0.85);
  --scrim-weak: rgba(255, 255, 255, 0.02);
  --scrim-med: rgba(255, 255, 255, 0.06);
  --on-brand: var(--brand-ink);
}

:root[data-theme="light"] {
  --ink: #f4f5f6;
  --panel: #ffffff;
  --panel-2: #eceef0;
  --line: #d8dce0;
  --bone: #1b1f24;
  --bone-dim: #5c6570;
  --brand: #2c6a86;
  --brand-soft: #2c6a861f;
  --brand-ink: #0b1a22;
  --green: #1f8a52;
  --red: #c53b30;
  --steel: #57626c;
  /* Cool neutral slate, matching the rest of this theme's grays — kept out of the
     saturated-blue "generic basemap" territory so it still reads as chrome. */
  --water: #e3e7ea;
  --land: #c3ccd3;
  --land-line: #a2adb6;
  --glow: transparent;
  --topbar-bg: rgba(255, 255, 255, 0.85);
  --scrim-weak: rgba(0, 0, 0, 0.025);
  --scrim-med: rgba(0, 0, 0, 0.05);
  /* Selected-segment foreground on a --brand-colored fill: --brand is a darker teal
     in this theme (unlike dark mode's light blue), so --brand-ink's navy text loses
     contrast against it — flip to a light foreground here instead. */
  --on-brand: #f4f6f7;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background:
    radial-gradient(1200px 600px at 80% -10%, var(--glow) 0%, transparent 60%),
    var(--ink);
  color: var(--bone);
  font-family: var(--display);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  transition: background-color 0.2s ease, color 0.2s ease;
}

/* ── Top bar ──────────────────────────────────────────────────────── */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--topbar-bg);
  backdrop-filter: blur(8px);
}
.brand { display: flex; align-items: center; gap: 6px; min-width: 0; }
.brand-mark { color: var(--brand); width: 20px; height: 20px; flex: none; }
.topbar h1 {
  font-size: 21px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.topbar-status { display: flex; align-items: center; gap: 12px; flex: none; position: relative; }
.settings-inline { display: contents; }
#settingsBtn { display: none; }

@media (max-width: 639.98px) {
  .settings-inline {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 10px;
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
    z-index: 30;
  }
  .settings-inline.open { display: flex; }
  .settings-inline .hour-format-switch,
  .settings-inline .theme-switch { width: 100%; justify-content: center; }
  #settingsBtn { display: flex; }
}

/* ── Theme switch ─────────────────────────────────────────────────── */
.theme-switch {
  display: flex;
  align-items: center;
  height: 38px;
  box-sizing: border-box;
  gap: 2px;
  padding: 2px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  flex: none;
}
.theme-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: transparent;
  border: none;
  color: var(--bone-dim);
  cursor: pointer;
  transition: all 0.15s;
}
.theme-btn svg { width: 14px; height: 14px; display: block; }
.theme-btn:hover { color: var(--bone); }
.theme-btn.active { background: var(--brand); color: var(--on-brand); }

/* ── Hour format switch ───────────────────────────────────────────── */
.hour-format-switch {
  display: flex;
  align-items: center;
  height: 38px;
  box-sizing: border-box;
  gap: 2px;
  padding: 2px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  flex: none;
}
.hour-format-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 0 10px;
  border-radius: 999px;
  background: transparent;
  border: none;
  color: var(--bone-dim);
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: all 0.15s;
}
.hour-format-btn:hover { color: var(--bone); }
.hour-format-btn.active { background: var(--brand); color: var(--on-brand); }

/* ── Buttons ──────────────────────────────────────────────────────── */
.btn-ghost, .btn-solid {
  font-family: var(--mono);
  font-size: 18px;
  border-radius: var(--radius);
  cursor: pointer;
  border: 1px solid var(--line);
  transition: all 0.15s;
  letter-spacing: 0.03em;
}
.btn-ghost {
  background: transparent;
  color: var(--bone-dim);
  padding: 6px 10px;
}
.btn-ghost:hover { color: var(--bone); border-color: var(--steel); }
.btn-solid {
  background: var(--brand);
  color: var(--brand-ink);
  border-color: var(--brand);
  font-weight: 700;
  padding: 9px 16px;
}
.btn-solid:hover { filter: brightness(1.08); }

.btn-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px; height: 38px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--bone-dim);
  cursor: pointer;
  transition: all 0.15s;
  flex: none;
}
.btn-icon svg { width: 22px; height: 22px; display: block; }
.btn-icon:hover { color: var(--bone); border-color: var(--steel); background: var(--scrim-med); }
.btn-icon:active svg { transform: rotate(75deg); transition: transform 0.3s ease; }

/* ── Page shell ───────────────────────────────────────────────────── */
main {
  max-width: 1200px;
  margin: 0 auto;
  padding: 16px;
}

/* ── Map ──────────────────────────────────────────────────────────── */
/* Aspect ratio isn't fixed — map.js sizes the SVG's height to whatever the airports'
   bounding box naturally crops to, so there's never blank letterboxing. Capped to a
   max-width so it doesn't sprawl edge-to-edge on very wide viewports. */
.map-wrap {
  max-width: 57.6rem;
  margin: 0 auto;
  border: 1px solid var(--line);
  border-bottom: none;
  border-radius: var(--radius) var(--radius) 0 0;
  overflow: hidden;
  background: var(--water);
}
.map {
  display: block;
  width: 100%;
  min-height: 180px;
  background: var(--water);
}
.map-land .land { fill: var(--land); stroke: var(--land-line); stroke-width: 0.5; }
/* Route/trail opacities are set inline from ROUTE.* in map.js — keep them off here so
   they stay centrally adjustable. */
.map-routes .route { stroke-linecap: round; }
.map-dynamic .route-trail { stroke-linecap: round; }
.map-dynamic .label-leader,
.map-airports .label-leader { stroke: var(--bone-dim); stroke-width: 0.75; stroke-opacity: 0.5; }
.map-airports .airport-dot { fill: var(--bone); stroke: var(--ink); stroke-width: 1; }
.map-airports .airport-label {
  fill: var(--bone-dim);
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 500;
  paint-order: stroke;
  stroke: var(--ink);
  stroke-width: 3px;
  transition: opacity 0.2s ease;
}
/* Airports outside the active traveller's own itinerary — faded, not hidden. */
.map-airports .label-leader.dim { opacity: 0.35; }
.map-airports .airport-label.dim { opacity: 0.35; }
.map-dynamic .traveler-marker { transition: cx 0.6s ease, cy 0.6s ease; }
.map-dynamic .traveler-marker.live { animation: markerPulse 1.8s ease-in-out infinite; }
@keyframes markerPulse {
  0%, 100% { stroke-opacity: 1; }
  50% { stroke-opacity: 0.3; }
}

/* ── View controls (Live View / Preview Flights) ─────────────────────
   Sits flush beneath the map, sharing its border, so the two read as one
   connected unit. The scrub/play row only appears in preview mode. */
.view-controls {
  max-width: 57.6rem;
  margin: 0 auto 20px;
  border: 1px solid var(--line);
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--panel);
  overflow: hidden;
}
/* The colored highlight is a single ::before "thumb", sized to a segment's width once
   (segments are flex:1, so width is uniform and only ever changes on resize) and then
   slid purely with `transform: translateX()`. That's a compositor-only property — no
   layout/paint per frame — which is what keeps the slide smooth; animating `left` (as
   this used to) forces a reflow on every frame and reads as janky under load.
   `overflow: hidden` keeps the thumb clipped to the pill shape at the ends of the bar,
   where the container's own corner radius otherwise lets it poke past the curve. */
.view-toggle {
  position: relative;
  display: flex;
  gap: 4px;
  padding: 6px;
  overflow: hidden;
}
.view-toggle::before {
  content: '';
  position: absolute;
  top: 6px; bottom: 6px;
  left: 0;
  width: var(--thumb-w, 0px);
  transform: translateX(var(--thumb-x, 0px));
  opacity: var(--thumb-opacity, 0);
  background: var(--thumb-color, var(--brand));
  border-radius: var(--radius);
  transition: transform 0.22s cubic-bezier(.4,0,.2,1), background-color 0.22s ease, opacity 0.15s ease;
  will-change: transform;
}
.view-btn {
  -webkit-tap-highlight-color: transparent;
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex: 1;
  padding: 8px 12px;
  border-radius: var(--radius);
  background: transparent;
  border: 1px solid transparent;
  cursor: pointer;
  font-family: var(--display);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--bone-dim);
  opacity: 0.85;
  transition: opacity 0.15s, color 0.25s ease;
}
.view-btn svg { width: 15px; height: 15px; flex: none; display: block; }
.view-btn:hover { opacity: 1; }
.view-btn:not(.active):hover { background: color-mix(in srgb, var(--bone-dim) 12%, transparent); }
.view-btn.active { opacity: 1; color: var(--on-brand); }
.preview-inline {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px;
  border-top: 1px solid var(--line);
}
.play-btn {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  border-radius: 50%;
  border: 1px solid var(--brand);
  background: var(--brand-soft);
  color: var(--brand);
  cursor: pointer;
  transition: all 0.15s;
}
.play-btn svg { width: 19px; height: 19px; display: block; }
.play-btn:hover { background: var(--brand); color: var(--brand-ink); }
.preview-body { flex: 1; min-width: 0; }
.preview-labels {
  display: flex;
  justify-content: flex-end;
  align-items: baseline;
  gap: 5px;
  margin-bottom: 6px;
}
.preview-date { font-family: var(--mono); font-size: 15px; color: var(--brand); }
.preview-time { font-family: var(--mono); font-size: 15px; color: var(--brand); }
/* Wide enough for the time label to sit beside the scrubber instead of above it —
   line them both up in a row so they read as level with the play button. Once the
   date and time aren't crammed above a narrow scrub track, give the time its own
   line instead of running it into the date. */
@media (min-width: 640px) {
  .preview-body { display: flex; align-items: center; gap: 14px; }
  .preview-labels { flex-direction: column; align-items: center; gap: 1px; margin-bottom: 0; flex: none; order: 2; }
  .scrub { order: 1; }
}
.scrub {
  width: 100%;
  -webkit-appearance: none;
  appearance: none;
  height: 4px;
  border-radius: 3px;
  background: var(--line);
  cursor: pointer;
}
.scrub::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--brand);
  border: 2px solid var(--ink);
  box-shadow: none;
}
.scrub::-moz-range-thumb {
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--brand);
  border: 2px solid var(--ink);
  box-shadow: none;
}
/* When previewing a simulated moment, tint the map frame so it's clear it isn't live. */
body.previewing .map-wrap { box-shadow: inset 0 0 0 1px var(--brand); }

/* ── Itinerary panels ─────────────────────────────────────────────
   Mobile-first: one column of full-width traveller cards. On wide
   viewports, cards flow into a multi-column grid. Each card is its own
   container-query context so its internal leg layout (row vs. stacked)
   adapts to the card's own width, not just the viewport. */
.panels {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding-bottom: 40px;
}
.panels-body {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
}
@media (min-width: 860px) {
  .panels-body { grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); }
}

.traveler-card {
  container-type: inline-size;
  width: 100%;
  max-width: 48em; /* ~624px */
  margin-inline: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--panel) 88%, var(--panel-2));
  overflow: hidden;
  /*border-top: 3px solid var(--accent, var(--brand));*/
}
.traveler-legs { display: flex; flex-direction: column; }

/* ── Highlighted next/current flight ─────────────────────────────
   Sits above the full itinerary, set off with an accent-tinted frame so it
   reads as the answer to "what's next" without scanning the whole list. */
.card-heading {
  font-size: 16.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--bone-dim);
  padding: 14px 16px 8px;
  text-align: center;
}
.highlight-section { padding-bottom: 4px; }
.highlight-card {
  margin: 0 0 4px;
  border-top: 1px solid color-mix(in srgb, var(--accent, var(--brand)) 45%, var(--line));
  border-bottom: 1px solid color-mix(in srgb, var(--accent, var(--brand)) 45%, var(--line));
  background: color-mix(in srgb, var(--accent, var(--brand)) 7%, var(--panel));
  overflow: hidden;
}
.highlight-card .leg-card { border-bottom: none; }
.highlight-card .layover-row { border-bottom: 1px solid color-mix(in srgb, var(--accent, var(--brand)) 30%, var(--line)); }
.itinerary-heading { border-top: 1px solid var(--line); margin-top: 4px; }

/* Placeholder cards: before/after the trip */
.placeholder-card {
  margin: 12px 16px;
  padding: 12px 14px;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background: var(--scrim-weak);
}
.placeholder-card.done { border-color: var(--green); background: color-mix(in srgb, var(--green) 10%, transparent); }
.placeholder-title { font-size: 18px; font-weight: 700; letter-spacing: 0.04em; }
.placeholder-sub { font-family: var(--mono); font-size: 16.5px; color: var(--bone-dim); margin-top: 3px; }

/* Leg card */
.leg-card {
  padding: 20px 18px;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 55%, var(--panel));
}
.traveler-legs > .leg-card:last-child { border-bottom: none; }

.leg-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 4px;
  margin-bottom: 14px;
}
.leg-flight { display: flex; align-items: baseline; justify-content: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.leg-num {
  font-weight: 700;
  font-size: 16.5px;
  letter-spacing: 0.03em;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.leg-depdate { font-size: 16.5px; color: var(--bone-dim); white-space: nowrap; }
.leg-airline { font-size: 15px; color: var(--bone-dim); }

/* Route: dep and arr ALWAYS side-by-side; progress track between them (wide) or below
   them at full width (narrow), via a container-query grid re-flow. */
.leg-route {
  display: grid;
  align-items: center;
  gap: 10px 20px;
  grid-template-columns: auto 1fr auto;
  grid-template-areas: "dep prog arr";
}
.endpoint { min-width: 0; }
.endpoint.dep { grid-area: dep; }
.endpoint.arr { grid-area: arr; text-align: right; }
.leg-progress { grid-area: prog; min-width: 0; }
.endpoint .code {
  font-size: 30px;
  font-weight: 700;
  letter-spacing: 0.05em;
  line-height: 1.2;
}
.endpoint .city { font-size: 15px; color: var(--bone-dim); margin-top: 1px; }
.endpoint .time-pair {
  display: flex;
  flex-direction: column;
  font-size: 15px;
  margin-top: 4px;
  gap: 1px;
}
.endpoint.arr .time-pair { align-items: flex-end; }
.endpoint .t-airport { color: var(--bone); }
.endpoint .t-viewer { color: var(--bone-dim); font-size: 14px; }
.endpoint .revised-dot { color: var(--brand); font-size: 12px; margin-left: 5px; vertical-align: middle; }
.endpoint .tz { color: var(--bone-dim); font-size: 13px; letter-spacing: 0.03em; }
.endpoint .meta {
  font-size: 15px;
  color: var(--steel);
  margin-top: 3px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Progress track: a filled trail + a plane at the current fraction, status centered below */
.leg-progress { align-self: flex-start; padding-top: 12px; }
.track {
  position: relative;
  height: 4px;
  border-radius: 2px;
  background: var(--line);
}
.trail {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  border-radius: 2px;
  background: var(--accent, var(--brand));
  transition: width 0.6s ease;
}
.leg-progress .plane {
  position: absolute;
  top: 50%;
  display: flex;
  color: var(--accent, var(--brand));
  transform: translate(-50%, -50%); /* icon renders pointing right by default — no rotation needed */
  transition: left 0.6s ease;
}
.leg-progress .plane svg { display: block; filter: drop-shadow(0 0 3px var(--panel)); }
.leg-progress.upcoming .plane { color: var(--bone-dim); }
.leg-progress.complete .plane {
  color: color-mix(in srgb, var(--bone-dim) 70%, var(--panel));
}
.leg-progress.complete .trail {
  background: color-mix(in srgb, var(--bone-dim) 70%, var(--panel));
}
.leg-progress-time {
  font-size: 14px;
  color: var(--bone-dim);
  margin-bottom: 7px;
  text-align: center;
}
.leg-progress-sub {
  font-size: 14px;
  color: var(--bone-dim);
  margin-top: 7px;
  text-align: center;
}

/* Narrow card: keep dep/arr in a row, drop the progress track full-width beneath them. */
@container (max-width: 440px) {
  .leg-route {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "dep arr"
      "prog prog";
  }
  .leg-progress { padding-top: 4px; }
}

/* Status pill */
.pill {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: 0.02em;
  padding: 3px 8px;
  border-radius: 2px;
  display: inline-block;
  white-space: nowrap;
}
.pill.scheduled { background: var(--line); color: var(--bone-dim); }
.pill.enroute   { background: var(--brand-soft); color: var(--brand); border: 1px solid var(--brand); }
.pill.arrived   { background: color-mix(in srgb, var(--green) 10%, transparent); color: var(--green); border: 1px solid var(--green); }
.pill.delayed   { background: color-mix(in srgb, var(--red) 10%, transparent); color: var(--red); border: 1px solid var(--red); }
.pill.canceled  { background: color-mix(in srgb, var(--red) 10%, transparent); color: var(--red); border: 1px solid var(--red); }
.pill.unknown   { background: var(--line); color: var(--steel); }

/* Layover row — centered, "30h 5m layover at IST" */
.layover-row {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 16px 16px;
  background: repeating-linear-gradient(
    90deg, transparent, transparent 6px, var(--scrim-weak) 6px, var(--scrim-weak) 12px);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 55%, var(--panel));
  font-family: var(--mono);
  font-size: 14px;
  color: var(--bone-dim);
  letter-spacing: 0.02em;
}
.layover-fill {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  opacity: 0.14;
  pointer-events: none;
  transition: width 0.6s ease;
}
.layover-row.tight { background: color-mix(in srgb, var(--red) 6%, transparent); color: var(--red); }
.layover-row.stay  { background: var(--scrim-med); color: var(--bone); }

.leg-pending { color: var(--steel); font-family: var(--mono); font-size: 18px; }

/* Loading skeleton */
.panels-inner { display: contents; }
.traveler-card.skeleton { pointer-events: none; }
.sk { display: block; background: var(--line); border-radius: 4px; animation: skPulse 1.4s ease-in-out infinite; }
.sk-line { height: 40px; margin: 14px 16px; }
.sk-line.short { width: 60%; height: 28px; }
@keyframes skPulse { 0%, 100% { opacity: 0.4; } 50% { opacity: 0.8; } }

/* Empty / error state */
.empty-state { grid-column: 1 / -1; text-align: center; padding: 60px 20px; color: var(--bone-dim); }
.empty-big { font-size: 27px; font-weight: 700; margin-bottom: 8px; }
.empty-small { font-family: var(--mono); font-size: 19.5px; }

/* Offline banner — connectivity, distinct from .stale-banner's server-reported staleness. */
.offline-banner {
  background: var(--steel);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 14px;
  text-align: center;
  padding: 7px 16px;
  letter-spacing: 0.02em;
}

/* Stale-data banner */
.stale-banner {
  background: var(--brand-soft);
  border-bottom: 1px solid var(--brand);
  color: var(--bone);
  font-family: var(--mono);
  font-size: 18px;
  text-align: center;
  padding: 8px 16px;
  letter-spacing: 0.02em;
}

/* Usage footer — a quiet, easy-to-miss line of API credit counts. Low opacity by
   default, sharpens slightly on hover; collapses entirely while empty (before the
   fetch resolves, or if it fails) so it never causes layout shift. */
.usage-footer {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.03em;
  text-align: center;
  color: var(--steel);
  opacity: 0.4;
  padding: 4px 16px 20px;
  transition: opacity 0.15s;
}
.usage-footer:hover { opacity: 0.85; }
.usage-footer:empty { display: none; }

/* Toast */
.toast {
  position: fixed;
  bottom: 20px; left: 50%;
  transform: translateX(-50%);
  background: var(--panel-2);
  border: 1px solid var(--red);
  color: var(--bone);
  font-family: var(--mono);
  font-size: 18px;
  padding: 12px 18px;
  border-radius: var(--radius);
  z-index: 50;
  max-width: 90vw;
}
.hidden { display: none !important; }

/* ── Traveler tabs ─────────────────────────────────────────────────
   Segmented-control bar: each button carries its traveller's color as --tc.
   The selected pill gets a solid fill in that color for strong contrast.
   Capped to the same width as the leg cards below and fused to the card
   directly beneath it (squared shared edge, no gap) so the two read as one
   connected unit. */
/* The colored highlight is a single ::before "thumb", sized to a tab's width once (tabs
   are flex:1, so width is uniform and only ever changes on resize) and then slid purely
   with `transform: translateX()` — a compositor-only property, so the browser can animate
   it without recomputing layout/paint each frame. `overflow: hidden` keeps the thumb
   clipped to the bar's pill shape at the ends, where the container's own corner radius
   would otherwise let it poke past the curve. */
.sticky-head {
  position: sticky;
  top: var(--topbar-h, 0px);
  z-index: 15;
}
.preview-banner {
  margin: 4px 16px 0;
  padding: 8px 14px;
  text-align: center;
  font-family: var(--mono);
  font-size: 14px;
  letter-spacing: 0.02em;
  color: var(--brand);
  background: var(--brand-soft);
  border: 1px solid var(--brand);
  border-radius: var(--radius);
}
.traveler-tabs {
  position: relative;
  display: flex;
  gap: 4px;
  padding: 4px;
  margin: 12px 16px 4px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  overflow: hidden;
}
.traveler-tabs::before {
  content: '';
  position: absolute;
  top: 4px; bottom: 4px;
  left: 0;
  width: var(--thumb-w, 0px);
  transform: translateX(var(--thumb-x, 0px));
  opacity: var(--thumb-opacity, 0);
  background: var(--thumb-color, var(--brand));
  border-radius: 999px;
  transition: transform 0.22s cubic-bezier(.4,0,.2,1), background-color 0.22s ease, opacity 0.15s ease;
  will-change: transform;
}
.tab {
  --tc: var(--bone-dim);
  -webkit-tap-highlight-color: transparent;
  position: relative;
  z-index: 1;
  flex: 1;
  padding: 9px 14px;
  border-radius: 999px;
  background: transparent;
  border: 1px solid transparent;
  cursor: pointer;
  font-family: var(--display);
  font-size: 19.5px;
  font-weight: 700;
  color: var(--tc);
  opacity: 0.85;
  transition: opacity 0.15s, color 0.25s ease;
  white-space: nowrap;
}
/* Each tab's --tc is set inline per-traveler (see app.js), which beats any stylesheet
   override of that custom property — so to raise contrast here we override `color`
   itself, darkening the traveler's own hue toward --bone rather than replacing it.
   Light theme's colors read lighter-weight than dark's, washing inactive names out;
   this also drops the opacity fade that would dim them further. */
:root[data-theme="light"] .tab:not(.active) {
  color: color-mix(in srgb, var(--tc) 65%, var(--bone));
  opacity: 1;
}
.tab:hover { opacity: 1; }
.tab:not(.active):hover { background: color-mix(in srgb, var(--bone-dim) 12%, transparent); }
.tab:not(.active) + .tab:not(.active)::before {
  content: '';
  position: absolute;
  left: -3.5px;
  top: 20%;
  bottom: 20%;
  width: 1px;
  background: var(--line);
}
.tab.active {
  opacity: 1;
  color: var(--brand-ink);
}

/* ── Breakpoints ──────────────────────────────────────────────────
   Base styles above are mobile-first. Tablet/desktop only need small
   nudges to spacing — the grid/container-query rules already do the
   structural work. */
@media (min-width: 640px) {
  main { padding: 24px; }
  .topbar { padding: 16px 24px; }
  .topbar h1 { font-size: 24px; }
}
@media (min-width: 1024px) {
  main { padding: 28px; }
}

@media (prefers-reduced-motion: reduce) {
  .progress-fill { transition: none; }
  .map-dynamic .traveler-marker { transition: none; }
  .map-dynamic .traveler-marker.live { animation: none; }
}

/* ── Keyboard focus ───────────────────────────────────────────────
   Every interactive control gets a visible brand-colored ring. Controls that live
   inside an `overflow: hidden` segmented-control track (.tab, .view-btn)
   use an inset box-shadow instead of outline+offset, since an outset
   outline would get clipped by the track at the edges. */
:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}
.tab:focus-visible, .view-btn:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--brand);
}
.scrub:focus-visible { outline-offset: 4px; }
