/* Trip Planner styles
 * Aesthetic system:
 *   - Light minimal default. Warm off-white land, cool muted sea.
 *   - Inter for UI, JetBrains Mono for codes/times.
 *   - Single accent: oklch(0.55 0.18 25) — warm crimson.
 *   - Solid black for inactive arcs/marks; crimson dashed for active leg.
 *   - Density tweak adjusts paddings only; not sizes.
 */

:root {
  --c-bg: oklch(0.985 0.003 80);
  --c-sea: oklch(0.93 0.022 240);
  --c-land: oklch(0.975 0.012 80);
  --c-land-stroke: oklch(0.78 0.018 80);
  --c-grid: oklch(0.92 0.01 240);
  --c-graticule: oklch(0.9 0.01 240);

  --c-ink: oklch(0.18 0.01 80);
  --c-ink-2: oklch(0.42 0.012 80);
  --c-ink-3: oklch(0.62 0.012 80);
  --c-line: oklch(0.88 0.008 80);
  --c-card: #ffffff;
  --c-card-2: oklch(0.97 0.005 80);

  --c-accent: oklch(0.55 0.18 25);
  --c-accent-soft: oklch(0.94 0.04 25);
  --c-accent-ink: oklch(0.32 0.16 25);

  --c-arc-idle: oklch(0.22 0.01 80);
  --c-arc-active: var(--c-accent);

  --pad: 14px;
  --pad-sm: 10px;
  --pad-xs: 6px;

  --r-1: 4px;
  --r-2: 8px;
  --r-3: 14px;

  --shadow-1: 0 1px 2px rgba(0,0,0,.04), 0 4px 12px rgba(0,0,0,.06);
  --shadow-2: 0 8px 24px rgba(0,0,0,.10), 0 2px 8px rgba(0,0,0,.06);

  --font-ui: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
}

.theme-dark {
  --c-bg: oklch(0.18 0.01 240);
  --c-sea: oklch(0.22 0.02 240);
  --c-land: oklch(0.28 0.02 80);
  --c-land-stroke: oklch(0.36 0.02 80);
  --c-grid: oklch(0.26 0.02 240);
  --c-graticule: oklch(0.3 0.02 240);
  --c-ink: oklch(0.95 0.01 80);
  --c-ink-2: oklch(0.78 0.01 80);
  --c-ink-3: oklch(0.6 0.01 80);
  --c-line: oklch(0.32 0.01 80);
  --c-card: oklch(0.24 0.01 240);
  --c-card-2: oklch(0.27 0.01 240);
  --c-arc-idle: oklch(0.92 0.01 80);
}

.theme-paper {
  --c-bg: oklch(0.965 0.018 80);
  --c-sea: oklch(0.945 0.018 80);
  --c-land: oklch(0.92 0.025 80);
  --c-land-stroke: oklch(0.78 0.03 80);
  --c-grid: oklch(0.88 0.02 80);
  --c-graticule: oklch(0.85 0.02 80);
}

.density-compact { --pad: 10px; --pad-sm: 7px; --pad-xs: 4px; }

* { box-sizing: border-box; }
html, body, #root { height: 100%; margin: 0; }
body { background: var(--c-bg); font: 13px/1.45 var(--font-ui); -webkit-font-smoothing: antialiased; }

/* Set the inherited text colour on .app so theme overrides (which live on the
   .app class) actually flow into descendants. Setting it on body resolves
   --c-ink at body scope, before the theme variables apply. */
.app { height: 100%; display: flex; flex-direction: column; overflow: hidden; color: var(--c-ink); }

/* ── Top bar ─────────────────────────────────────────────────────────────── */
.topbar {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 10px 16px;
  background: var(--c-card); border-bottom: 1px solid var(--c-line);
  /* Topbar is a flex item, so z-index creates a stacking context that traps
     descendants. It must sit above Leaflet's control container (z 800) or
     the Trip dropdown (a descendant) gets painted under the zoom buttons. */
  position: relative;
  z-index: 1000;
}
.tb-left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.tb-title { min-width: 0; }
.tb-icon { width: 28px; height: 28px; border: 1px solid var(--c-line); border-radius: var(--r-1); background: var(--c-card); color: var(--c-ink-2); cursor: pointer; display:inline-flex; align-items:center; justify-content:center; flex-shrink: 0; }
.tb-icon:hover:not(:disabled) { color: var(--c-ink); }
.tb-icon:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }
.tb-icon:disabled { opacity: 0.35; cursor: not-allowed; }
.tb-trip { font-weight: 600; letter-spacing: -0.01em; font-size: 14px; }
.tb-dates { color: var(--c-ink-3); font-size: 11.5px; margin-top: 1px; }
.tb-dates-summary { display: inline-flex; align-items: center; gap: 4px; }
.tb-center { flex: 1 1 auto; }
.tb-right { display: flex; gap: 8px; justify-content: flex-end; }
.tb-btn { font: 12px/1 var(--font-ui); font-weight: 500; padding: 7px 12px; border-radius: var(--r-1); cursor: pointer; border: 1px solid var(--c-line); }
.tb-btn.ghost { background: var(--c-card); color: var(--c-ink); }
.tb-btn.ghost:hover { background: var(--c-card-2); }
.tb-btn.primary { background: var(--c-ink); color: var(--c-bg); border-color: var(--c-ink); }
.tb-btn.primary:hover { background: var(--c-accent); border-color: var(--c-accent); color: white; }

/* Help "?" button. Icon-only square that still reads as part of the .tb-btn
   family — same border, radius, and hover treatment as the ghost text
   buttons next to it, so the trio (help, sign-in, trip) feels uniform. */
.tb-btn.tb-help {
  width: 28px; height: 28px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--c-ink-2);
  text-decoration: none;
}
.tb-btn.tb-help:hover { color: var(--c-ink); background: var(--c-card-2); }
.tb-btn.tb-help:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }

/* Logo wrapper — same visual presence as the bare <img> was, just clickable.
   Border-radius matches .tb-btn so the focus ring fits the rounded form. */
.tb-logo-link {
  display: inline-flex; align-items: center;
  border-radius: var(--r-1);
  flex: 0 0 auto;
}
.tb-logo-link:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }

/* Logo lockup at the leftmost position. width/height attrs in the JSX
   reserve layout space so the topbar doesn't reflow as the SVG paints in. */
.tb-logo {
  display: block; height: 24px; width: auto;
  flex: 0 0 auto; margin-right: 4px;
}

/* Overview-tab "trip meta" row — sits between the stats grid and the
   Itinerary header. Houses the traveler stepper on desktop; on mobile it
   ALSO houses the editable trip name + dates (which are hidden in the
   topbar at narrow widths — see the mobile media query). */
.ov-trip-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--c-line);
}
.ov-trip-name { font-weight: 600; font-size: 13px; }
.ov-trip-dates {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--c-ink-3); font-size: 11.5px;
}
.ov-dates-sep { color: var(--c-ink-3); }
.ov-trip-travelers {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--c-ink-3); font-size: 11.5px;
}
.ov-travelers-label { font-size: 11px; }
/* Desktop: trip name + dates live in the topbar; hide the OverviewTab
   duplicates here. Specificity 0,2,0 to outweigh the `.inline-text` base
   rule that defines `display: inline-block` further down the file. */
.ov-trip-meta .ov-trip-name,
.ov-trip-meta .ov-trip-dates { display: none; }

.ov-intro {
  padding: 12px;
  border-bottom: 1px solid var(--c-line);
}
.ov-intro h1 {
  margin: 0 0 6px;
  font: 600 16px/1.2 var(--font-ui);
  letter-spacing: 0;
  color: var(--c-ink);
}
.ov-intro p {
  margin: 0;
  color: var(--c-ink-2);
  font: 12.5px/1.45 var(--font-ui);
}
.ov-intro-help {
  margin-top: 8px;
  color: var(--c-ink-3);
  font: 11.5px/1.35 var(--font-ui);
}

/* ── Main layout ─────────────────────────────────────────────────────────── */
.main { flex: 1 1 auto; display: flex; min-height: 0; }
.sidebar {
  flex: 0 0 340px; max-width: 340px;
  display: flex; flex-direction: column;
  background: var(--c-card); border-right: 1px solid var(--c-line);
  overflow: hidden;
}
.map-wrap { flex: 1 1 auto; position: relative; min-width: 0; overflow: hidden; }

/* Toolbar at the very top of the sidebar — hosts the sidebar toggle plus
   undo/redo, relocated from the topbar so the topbar reads as pure
   identity + context (logo, trip name, dates, account, trip menu). */
.sb-toolbar {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 6px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--c-line);
}

/* Floating "show sidebar" button shown only when the sidebar is collapsed.
   Inherits .tb-icon styling for visual consistency with the in-sidebar
   buttons, with a soft drop shadow so it lifts off the map tiles. */
.sidebar-fab {
  position: absolute;
  top: 12px; left: 12px;
  z-index: 500;  /* above Leaflet panes (400) and overlay (400), below popovers (1100) */
  background: var(--c-card);
  box-shadow: 0 1px 2px rgba(0,0,0,0.08), 0 2px 6px rgba(0,0,0,0.10);
}
/* The detail sheet anchors at top-left of the map (top:20, left:20) and
   sits exactly where the sidebar-fab lives. Hide the fab while any
   popover is open — Escape / X / outside-click closes the popover and
   the fab returns. (Mobile already had this rule via @media; lifting it
   to a global rule now that desktop has the same overlap.) */
body.popover-open .sidebar-fab { display: none; }

/* ── Sidebar tabs ────────────────────────────────────────────────────────── */
.sb-tabs { display: flex; border-bottom: 1px solid var(--c-line); padding: 0 var(--pad-sm); gap: 2px; flex: 0 0 auto; }
.sb-tab { background: transparent; border: 0; padding: 12px 10px; font: 12px/1 var(--font-ui); font-weight: 500; color: var(--c-ink-3); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.sb-tab:hover { color: var(--c-ink); }
.sb-tab.active { color: var(--c-ink); border-bottom-color: var(--c-accent); }

.sb-body { flex: 1 1 auto; overflow: auto; padding: var(--pad); }

/* ── Overview tab ────────────────────────────────────────────────────────── */
/* Inventory stats (flight count / hotel nights / booked ratio) and the cash
   subtotal used to live here as a 2x2 grid. They moved to the Budget tab —
   the inventory cells render as .bud-composition, and the cash subtotal is
   already the bud-total headline so it isn't duplicated. */

.ov-section-h { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--c-ink-3); margin: 8px 2px; }
.ov-list { display: flex; flex-direction: column; gap: 1px; }
.ov-item { display: grid; grid-template-columns: 56px 1fr; padding: 10px 8px; border-radius: var(--r-1); cursor: pointer; gap: 4px; }
.ov-item.flight { background: transparent; }
.ov-item.stay { background: var(--c-card-2); }
.ov-item:hover { background: var(--c-accent-soft); }
.ov-item.active { background: var(--c-accent-soft); box-shadow: inset 2px 0 0 var(--c-accent); }
.ov-item.layover { color: var(--c-ink-3); padding: 4px 8px; }
.ov-layover-text { font-size: 11.5px; font-style: italic; }
.ov-date { font: 11px/1 var(--font-mono); color: var(--c-ink-3); padding-top: 3px; grid-row: span 2; }
.ov-row { display: flex; align-items: center; gap: 8px; }
.ov-iata { font: 600 13px/1 var(--font-mono); letter-spacing: 0.02em; }
.ov-iata-edit,
.pop-iata-edit {
  appearance: none;
  border: 0;
  background: transparent;
  color: inherit;
  padding: 0 1px;
  margin: 0;
  cursor: pointer;
  border-radius: 2px;
}
.ov-iata-edit:hover:not(:disabled),
.pop-iata-edit:hover:not(:disabled) {
  color: var(--c-accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.ov-iata-edit:focus-visible,
.pop-iata-edit:focus-visible {
  color: var(--c-accent);
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
}
.ov-iata-edit:disabled,
.pop-iata-edit:disabled {
  color: var(--c-ink-3);
  cursor: default;
  text-decoration: none;
}
.pop-iata-edit[aria-disabled="true"] {
  color: var(--c-ink-3);
  cursor: pointer;
  text-decoration: none;
}
.pop-iata-edit[aria-disabled="true"]:hover {
  color: var(--c-accent-ink);
  text-decoration: none;
}
.ov-arrow { flex: 1; display: flex; align-items: center; gap: 0; height: 1px; }
.ov-arrow-line { flex: 1; height: 1px; background: currentColor; opacity: 0.35; }
.ov-arrow-tip { width: 0; height: 0; border-left: 4px solid currentColor; border-top: 3px solid transparent; border-bottom: 3px solid transparent; opacity: 0.5; }
.ov-stay-name {
  font-weight: 500; flex: 1; min-width: 0;
  /* Cap to 3 lines so the hover state (88px right padding) doesn't push the
     name to a tall, cramped column. Past 3 lines we ellipsize. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden; overflow-wrap: anywhere;
}
.ov-stay-thumb { grid-column: 2; width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--r-1); margin-top: 8px; background: var(--c-card-2); }
.ov-nights { font: 11px/1 var(--font-mono); color: var(--c-ink-3); padding: 2px 5px; border: 1px solid var(--c-line); border-radius: 3px; }
.ov-meta {
  grid-column: 2;
  display: flex; gap: 5px; align-items: center;
  color: var(--c-ink-3); font-size: 11px;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ov-meta > span { white-space: nowrap; flex-shrink: 0; }
/* The neighborhood/address is the long, shrinkable element — not the trailing
   cash figure. Without targeting it specifically, it would push cash out of
   view and the meta line would just clip without an ellipsis. */
.ov-meta > .ov-meta-addr { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ov-meta > span:last-child { min-width: 0; }

/* ── Activities tab ──────────────────────────────────────────────────────── */
.act-city { margin-bottom: 18px; }
.act-city-h { display: flex; align-items: baseline; justify-content: space-between; padding: 0 2px 8px; border-bottom: 1px solid var(--c-line); margin-bottom: 8px; }
.act-city-name { font-weight: 600; font-size: 14px; letter-spacing: -0.01em; }
.act-city-code { font: 11px/1 var(--font-mono); color: var(--c-ink-3); }
.act-item { display: grid; grid-template-columns: 60px 1fr; gap: 10px; padding: 8px 4px; border-bottom: 1px solid var(--c-line); }
.act-item:last-of-type { border-bottom: 0; }
.act-time { color: var(--c-ink-3); }
.act-day { font: 11px/1 var(--font-mono); }
.act-clock { font: 600 12px/1.4 var(--font-mono); color: var(--c-ink); }
.act-tz { font: 9.5px/1 var(--font-ui); color: var(--c-ink-3); margin-top: 2px; letter-spacing: 0.04em; }
.act-title { font-weight: 500; }
.act-meta { display: flex; gap: 6px; align-items: center; color: var(--c-ink-3); font-size: 11.5px; margin-top: 3px; }
.act-status { padding: 1px 6px; border-radius: 3px; font: 10px/1.4 var(--font-ui); text-transform: uppercase; letter-spacing: 0.04em; background: var(--c-card-2); color: var(--c-ink-3); }
.act-status.booked { background: var(--c-accent-soft); color: var(--c-accent-ink); }
.act-add { width: 100%; padding: 8px; border: 1px dashed var(--c-line); background: transparent; color: var(--c-ink-3); border-radius: var(--r-1); cursor: pointer; font: inherit; }
.act-add:hover { border-color: var(--c-accent); color: var(--c-accent); }

/* ── Notes tab ──────────────────────────────────────────────────────────── */
.notes-tab { display: flex; flex-direction: column; gap: 10px; }
.note-block { padding: 10px; border: 1px solid var(--c-line); border-radius: var(--r-2); cursor: pointer; }
.note-block.active { border-color: var(--c-accent); }
.note-h {
  font-size: 11.5px; font-weight: 600; color: var(--c-ink-2); margin-bottom: 6px;
  font-family: var(--font-mono); letter-spacing: 0.01em;
  display: flex; align-items: center; gap: 6px;
}
.note-h > span { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Resize wrapper for RichNote. The user can drag the bottom-right corner to
   make a note taller; height is persisted to trip.tripNoteHeights via a
   ResizeObserver inside the component. */
.note-resize {
  width: 100%;
  resize: vertical;
  overflow: auto;
  min-height: 56px;
  border-radius: var(--r-1);
}

/* The actual editable surface. Single always-rendered contenteditable;
   typing is reflected immediately because the browser owns the DOM here.
   We deliberately don't put a visible border so the wrapper's resize handle
   is the only visible affordance. */
.rich-note {
  width: 100%;
  min-height: 56px;
  font: 12.5px/1.5 var(--font-ui);
  color: var(--c-ink);
  outline: none;
  padding: 0;
  cursor: text;
  word-break: break-word;
}
.rich-note:focus { outline: none; }
/* Standard contenteditable placeholder pattern: ::before drawn off the
   data-placeholder attribute, hidden as soon as the field has content. */
.rich-note.empty::before {
  content: attr(data-placeholder);
  color: var(--c-ink-3);
  pointer-events: none;
  display: block;
}
.rich-note > :first-child { margin-top: 0; }
.rich-note > :last-child { margin-bottom: 0; }
.rich-note p { margin: 0 0 6px 0; }
.rich-note ul, .rich-note ol { margin: 4px 0 6px 18px; padding: 0; }
.rich-note li { margin: 2px 0; }
.rich-note h1 { font-size: 16px; font-weight: 600; margin: 8px 0 4px; }
.rich-note h2 { font-size: 14px; font-weight: 600; margin: 8px 0 4px; }
.rich-note h3 { font-size: 13px; font-weight: 600; margin: 8px 0 4px; }
.rich-note h4 { font-size: 12.5px; font-weight: 600; margin: 6px 0 3px; }
.rich-note code { font: 11.5px/1.4 var(--font-mono); background: var(--c-card-2); padding: 0 4px; border-radius: 3px; }
.rich-note pre { background: var(--c-card-2); padding: 8px 10px; border-radius: var(--r-1); overflow-x: auto; font: 11.5px/1.45 var(--font-mono); }
.rich-note pre code { background: transparent; padding: 0; }
.rich-note a { color: var(--c-accent); text-decoration: underline; }
.rich-note blockquote { margin: 4px 0 6px 0; padding-left: 8px; border-left: 2px solid var(--c-line); color: var(--c-ink-2); }
.rich-note hr { border: 0; border-top: 1px solid var(--c-line); margin: 8px 0; }
.rich-note b, .rich-note strong { font-weight: 600; }

.note-del {
  background: transparent; border: 0; color: var(--c-ink-3); cursor: pointer;
  padding: 0 4px; font-size: 14px; line-height: 1; flex: 0 0 auto;
}
.note-del:hover { color: var(--c-accent); }

.conf-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font: 11px/1.4 var(--font-mono);
  background: var(--c-accent-soft); color: var(--c-accent-ink);
  padding: 2px 8px; border-radius: 999px; margin-bottom: 6px;
}
.conf-chip code { font: inherit; background: transparent; padding: 0; }

.note-add-link {
  background: transparent; border: 1px dashed var(--c-line);
  color: var(--c-ink-3); width: 100%; padding: 8px;
  border-radius: var(--r-1); cursor: pointer; font: inherit;
}
.note-add-link:hover { border-color: var(--c-accent); color: var(--c-accent); }

/* "Open in Notes →" row inside the LegRow expand panel. */
.ov-expand-notes-btn {
  background: transparent; border: 0; color: var(--c-accent);
  cursor: pointer; font: inherit; text-decoration: underline; padding: 0;
}
.ov-expand-notes-btn:hover { opacity: 0.85; }

/* ── Budget tab ──────────────────────────────────────────────────────────── */
.bud-total { padding: 16px; background: var(--c-ink); color: var(--c-bg); border-radius: var(--r-2); margin-bottom: 12px; }
.bud-total-num { font: 700 26px/1 var(--font-ui); letter-spacing: -0.02em; }
.bud-total-lab { font-size: 11px; opacity: 0.7; margin-top: 4px; }
/* Per-currency breakout under the budget tab's USD total — same idea as
   .ov-num-alt. Inherits the dark .bud-total background so the muted ink
   target is the inverse-text variant. */
.bud-total-alt { font: 11.5px/1.4 var(--font-mono); opacity: 0.7; margin-top: 6px; word-break: break-word; }
.bud-miles { display: flex; flex-direction: column; gap: 3px; padding: 10px 12px; background: var(--c-accent-soft); border-radius: var(--r-2); margin-bottom: 12px; font-size: 12px; color: var(--c-accent-ink); font-weight: 500; }
/* Trip-composition strip — small 3-up cells under bud-miles, showing
   flight count / hotel nights / booked ratio. These used to live in the
   Overview tab's stat grid; they're inventory-flavored (not cash), so
   they sit between the cash/miles headline and the per-line budget rows. */
.bud-composition {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  margin-bottom: 14px;
}
.bud-comp-cell {
  display: flex; flex-direction: column; gap: 2px;
  padding: 8px 10px;
  background: var(--c-card-2);
  border: 1px solid var(--c-line);
  border-radius: var(--r-2);
}
.bud-comp-num { font: 600 16px/1.1 var(--font-ui); letter-spacing: -0.02em; color: var(--c-ink); }
.bud-comp-lab { font-size: 11px; color: var(--c-ink-3); }
.bud-rows { display: flex; flex-direction: column; gap: 10px; }
.bud-row-h { display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 4px; }
.bud-label { color: var(--c-ink-2); }
.bud-val { font: 600 12px/1 var(--font-mono); }
.bud-bar { height: 4px; background: var(--c-card-2); border-radius: 2px; overflow: hidden; }
.bud-bar-fill { height: 100%; background: var(--c-ink); }
.bud-bar-fill.muted { background: var(--c-ink-3); }
.bud-bar-fill.primary { background: var(--c-accent); }

/* ── Map ─────────────────────────────────────────────────────────────────── */
.map-canvas { position: absolute; inset: 0; }
.map-leaflet { position: absolute; inset: 0; background: var(--c-sea); }
.map-leaflet.leaflet-container { font: inherit; }
/* SVG is portaled into a Leaflet pane (no intrinsic dimensions). Its
   position is set imperatively via L.DomUtil.setPosition (transform), and
   width/height/viewBox by updateOverlayBounds. Do NOT use `inset: 0` here
   — that would collapse the SVG to the pane's 0×0 size and clip every
   element to invisibility. */
.map-overlay {
  --annotation-scale: 1;
  position: absolute;
  pointer-events: none;
  contain: layout style paint;
}
.map-annotation-scale {
  transform: scale(var(--annotation-scale));
  transform-origin: 0 0;
}
.map-overlay > g > * { pointer-events: auto; }
.map-overlay text { pointer-events: none; }
/* Belt-and-suspenders for pointer-events: the `> g > *` rule depends on
   exact DOM depth and silently kills clicks if an extra wrapper <g> is
   added later. List interactive classes explicitly so the contract survives
   structural refactors. */
.pin-halo, .pin-dot, .arc-hit, .flight-chip, .hotel-tag,
.ground-hit, .ground-chip, .gc-bg { pointer-events: auto; }

/* Screen-aligned tooltip layer (sibling of the Leaflet pane that hosts the
   SVG overlay). Tooltip <div>s portal in here and imperatively position
   themselves via style.transform on every map move/zoom tick — they stay
   screen-aligned and don't scale during the 250ms zoom transition. */
.trippy-tooltip-layer {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 410;     /* above .map-overlay pane (400), below controls (800) */
  contain: layout style paint;
}
.trippy-tooltip-layer > * {
  position: absolute; top: 0; left: 0;
  pointer-events: auto;
  will-change: transform;
}

/* Leaflet attribution + zoom restyle to match aesthetic */
.leaflet-control-attribution {
  background: rgba(255,255,255,.85) !important;
  font: 10px/1.4 var(--font-ui) !important;
  color: var(--c-ink-3) !important;
  padding: 2px 6px !important;
}
.leaflet-control-attribution a { color: var(--c-ink-2) !important; }
.theme-dark .leaflet-control-attribution { background: rgba(40,40,50,.85) !important; color: var(--c-ink-3) !important; }
.theme-dark .leaflet-control-attribution a { color: var(--c-ink-2) !important; }
.leaflet-bar { border: 1px solid var(--c-line) !important; box-shadow: var(--shadow-1) !important; }
.leaflet-bar a { background: var(--c-card) !important; color: var(--c-ink) !important; border-bottom-color: var(--c-line) !important; }
.leaflet-bar a:hover { background: var(--c-card-2) !important; }

/* Arcs */
.arc { fill: none; stroke-linecap: round; }
.arc-hit { fill: none; stroke: transparent; stroke-width: 18; cursor: pointer; }
.arc-idle { stroke: var(--c-arc-idle); stroke-width: 1.2; opacity: 0.55; }
.arc-active { stroke: var(--c-arc-active); stroke-width: 2.2; }
.arc-dashed.arc-active { stroke-dasharray: 6 4; }
.arc-dashed.arc-idle  { stroke-dasharray: 3 3; }
.arrow-active-fill { fill: var(--c-arc-active); }
.arrow-idle-fill { fill: var(--c-arc-idle); opacity: 0.6; }
.arc-arrow-active { fill: var(--c-arc-active); pointer-events: none; }
.arc-arrow-idle   { fill: var(--c-arc-idle); opacity: 0.6; pointer-events: none; }

/* (FlightLabelFull was removed — flight detail now lives in the chip's
   hover tooltip below, matching the hotel-tag pattern.) */

/* City pins */
.city-pin .pin-halo,
.city-pin .pin-dot { cursor: pointer; }
.pin-halo { fill: rgba(255,255,255,0.95); stroke: var(--c-arc-idle); stroke-width: 1; filter: drop-shadow(0 1px 1.5px rgba(0,0,0,.18)); }
.pin-dot  { fill: var(--c-ink); }
.city-pin.active .pin-halo { stroke: var(--c-accent); stroke-width: 1.4; }
.city-pin.active .pin-dot  { fill: var(--c-accent); }
.pin-code  { font: 700 11px/1 var(--font-mono); fill: var(--c-ink);
             paint-order: stroke; stroke: var(--c-card); stroke-width: 3px; stroke-linejoin: round; }
.pin-city  { font: 10.5px/1 var(--font-ui); fill: var(--c-ink-2);
             paint-order: stroke; stroke: var(--c-card); stroke-width: 2.5px; stroke-linejoin: round; }
.pin-nights{ font: 10px/1 var(--font-ui); fill: var(--c-ink-3);
             paint-order: stroke; stroke: var(--c-card); stroke-width: 2.5px; stroke-linejoin: round; }
.theme-dark .pin-code, .theme-dark .pin-city, .theme-dark .pin-nights { stroke: var(--c-bg); }

/* Hotel tags — small inline badge attached to a city pin label */
.hotel-tag { cursor: pointer; }
.ht-bg     { fill: var(--c-card); stroke: var(--c-ink); stroke-width: 1; filter: drop-shadow(0 1px 1.5px rgba(0,0,0,.12)); }
.ht-text   { font: 700 9.5px/1 var(--font-ui); fill: var(--c-ink); letter-spacing: 0.02em; }
.hotel-tag.active .ht-bg   { fill: var(--c-ink); stroke: var(--c-accent); stroke-width: 1.3; }
.hotel-tag.active .ht-text { fill: var(--c-bg); }
/* Tooltips are HTML <div>s portaled into .trippy-tooltip-layer; opacity is
   driven by the .visible class (toggled by React based on hover/active
   state lifted to MapView via hoveredOverlayId). The :hover descendant
   selector is dead because the tooltip is no longer a DOM child of the
   chip/tag. */
.ht-tooltip { opacity: 0; transition: opacity .12s ease; }
.ht-tooltip.visible { opacity: 1; }
/* Inner card is inline-block so it grows to fit short names and wraps long
   ones within the tooltip's max width. */
.ht-tip {
  display: inline-block;
  max-width: 240px;
  padding: 5px 7px;
  background: var(--c-card);
  border: 1px solid var(--c-line);
  border-radius: 3px;
  box-shadow: 0 2px 6px rgba(0,0,0,.1);
}
.ht-tip-name   { font: 600 10.5px/1.25 var(--font-ui); color: var(--c-ink); word-break: break-word; }
.ht-tip-detail { font: 10px/1 var(--font-mono); color: var(--c-ink-3); margin-top: 4px; }

/* Flight chip — compact pill on the arc, plus a hover minicard. */
.flight-chip { cursor: pointer; }
.fc-bg   { fill: var(--c-card); stroke: var(--c-line); stroke-width: 0.7;
           filter: drop-shadow(0 1px 1.5px rgba(0,0,0,.08)); }
.fc-code { font: 600 10px/1 var(--font-mono); fill: var(--c-ink-2); letter-spacing: 0.02em; }
.flight-chip:hover .fc-bg { stroke: var(--c-accent); }
.flight-chip:hover .fc-code { fill: var(--c-accent-ink); }
/* Selected leg + its linked siblings — accent stroke matches the active arc. */
.flight-chip.active .fc-bg   { stroke: var(--c-accent); stroke-width: 1.2; }
.flight-chip.active .fc-code { fill: var(--c-accent-ink); }
/* Hover-only minicard. Lives in .trippy-tooltip-layer (screen-aligned).
   The inner .fc-tip is shifted left by 50% of its own width so it centres
   under the anchor point. Visibility driven by .visible class from React. */
.fc-tooltip { opacity: 0; transition: opacity .12s ease; }
.fc-tooltip.visible { opacity: 1; }
.fc-tip {
  display: inline-block; transform: translateX(-50%);
  max-width: 240px; padding: 6px 8px;
  background: var(--c-card);
  border: 1px solid var(--c-line);
  border-radius: 3px;
  box-shadow: 0 2px 6px rgba(0,0,0,.1);
  font: 11px/1.3 var(--font-ui); color: var(--c-ink);
}
.fc-tip-head { display: flex; gap: 6px; align-items: baseline; }
.fc-tip-code { font: 600 11px/1 var(--font-mono); color: var(--c-ink); }
.fc-tip-air  { color: var(--c-ink-3); font-size: 10.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.fc-tip-times { font: 10.5px/1.3 var(--font-mono); color: var(--c-ink-2); margin-top: 3px; }
.fc-tip-foot  { display: flex; justify-content: space-between; gap: 6px; margin-top: 4px; font-size: 10.5px; }
.fc-tip-stops { color: var(--c-ink-3); }
.fc-tip-price { color: var(--c-accent-ink); font: 600 10.5px/1 var(--font-mono); }

/* Ground legs — straight mode-styled lines between endpoints, plus a chip
   at the midpoint. Each mode picks its own hue + dash so they read distinctly
   from each other and from flight arcs. Stroke width / opacity match the
   idle flight arc so ground transit doesn't dominate the map. */
:root {
  --c-ground-train:  oklch(0.50 0.16 260);
  --c-ground-bus:    oklch(0.55 0.14 60);
  --c-ground-car:    oklch(0.48 0.12 165);
  --c-ground-ferry:  oklch(0.55 0.14 200);
}
.ground-hit { fill: none; stroke: transparent; stroke-width: 14; pointer-events: stroke; cursor: pointer; }
.ground-line {
  fill: none; stroke-width: 1.6; opacity: 0.85;
  stroke-linecap: round;
}
.ground-line.mode-train { stroke: var(--c-ground-train); stroke-dasharray: 8 3 2 3; }
.ground-line.mode-bus   { stroke: var(--c-ground-bus);   stroke-dasharray: 5 4; }
.ground-line.mode-car   { stroke: var(--c-ground-car);   stroke-width: 2.2; }
.ground-line.mode-ferry { stroke: var(--c-ground-ferry); stroke-dasharray: 1 3; stroke-width: 1.8; }
.ground-group:hover .ground-line { opacity: 1; stroke-width: 2.0; }
.ground-group.mode-car:hover .ground-line,
.ground-group.mode-car.active .ground-line { stroke-width: 2.6; opacity: 1; }

/* Ground chip — pill at the midpoint with mode glyph + operator/mode label.
   Uses the same drop-shadow / radius pattern as FlightChip so the visual
   language stays consistent. Per-mode left-edge accent gives a quick read. */
.ground-chip { cursor: pointer; pointer-events: auto; }
.gc-bg {
  fill: var(--c-card); stroke: var(--c-line); stroke-width: 0.7;
  filter: drop-shadow(0 1px 1.5px rgba(0,0,0,.08));
}
.gc-text { font: 600 10px/1 var(--font-ui); fill: var(--c-ink-2); letter-spacing: 0.02em; }
.ground-chip.mode-train .gc-bg { stroke: var(--c-ground-train); }
.ground-chip.mode-bus   .gc-bg { stroke: var(--c-ground-bus); }
.ground-chip.mode-car   .gc-bg { stroke: var(--c-ground-car); }
.ground-chip.mode-ferry .gc-bg { stroke: var(--c-ground-ferry); }
.ground-chip.active .gc-bg { fill: var(--c-accent-soft); stroke: var(--c-accent); }
.gc-tooltip { opacity: 0; transition: opacity .12s ease; }
.gc-tooltip.visible { opacity: 1; }
.gc-tip {
  display: inline-block; transform: translateX(-50%);
  max-width: 220px; padding: 6px 8px;
  background: var(--c-card);
  border: 1px solid var(--c-line);
  border-radius: 3px;
  box-shadow: 0 2px 6px rgba(0,0,0,.1);
  font: 11px/1.3 var(--font-ui); color: var(--c-ink);
}
.gc-tip-head { display: flex; gap: 6px; align-items: baseline; }
.gc-tip-mode { font: 600 11px/1 var(--font-ui); color: var(--c-ink); }
.gc-tip-op { color: var(--c-ink-3); font-size: 10.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.gc-tip-route { font: 10.5px/1.3 var(--font-mono); color: var(--c-ink-2); margin-top: 3px; }
.gc-tip-times { font: 10.5px/1.3 var(--font-mono); color: var(--c-ink-3); margin-top: 2px; }

/* Map legend */
.map-legend {
  position: absolute; left: 16px; top: 16px;
  /* Above Leaflet's control container (z-index 800) and panes (≤700). */
  z-index: 1000;
  background: var(--c-card); border: 1px solid var(--c-line); border-radius: var(--r-2);
  padding: 10px 12px; font-size: 11.5px; box-shadow: var(--shadow-1);
  display: flex; flex-direction: column; gap: 6px;
}
.ml-row { display: flex; align-items: center; gap: 10px; color: var(--c-ink-2); }
.legend-arc.arc-active { stroke: var(--c-accent); stroke-width: 2; }
.legend-arc.arc-idle { stroke: var(--c-arc-idle); stroke-width: 1.2; opacity: 0.6; }
.legend-arc.arc-dashed { stroke-dasharray: 3 2; }
.legend-hotel { fill: var(--c-card); stroke: var(--c-ink); stroke-width: 1.2; }
.legend-ground { stroke-width: 1.6; }
.legend-ground.mode-train { stroke: var(--c-ground-train); stroke-dasharray: 6 2 2 2; }
.legend-ground.mode-car { stroke: var(--c-ground-car); }
.ml-attrib { font-size: 10px; color: var(--c-ink-3); padding-top: 4px; border-top: 1px solid var(--c-line); margin-top: 2px; }

/* ── Timeline (bottom strip) ─────────────────────────────────────────────── */
.timeline {
  position: absolute; left: 16px; right: 16px; bottom: 16px;
  /* Above Leaflet's control container (z-index 800) and panes (≤700). */
  z-index: 1000;
  pointer-events: auto;
  background: var(--c-card); border: 1px solid var(--c-line); border-radius: var(--r-3);
  padding: 14px 18px 10px;
  box-shadow: var(--shadow-2);
}
.tl-track { position: relative; height: 78px; overflow: hidden; touch-action: pan-y; }
.tl-zoom {
  position: absolute; top: 8px; right: 12px; z-index: 2;
  display: inline-flex; gap: 4px; align-items: center;
}
/* Top-left minimize button — mirrors .tl-zoom's positioning on the right
   so the two corner clusters read as a symmetric pair. Uses the same
   .tl-zoom-btn visual styles for consistency. */
.tl-min {
  position: absolute; top: 8px; left: 12px; z-index: 2;
  display: inline-flex; align-items: center;
}
/* Collapsed-state pill. Anchored bottom-right with a 16px gutter so it
   sits clear of the Leaflet attribution control (which pins to bottom: 0,
   right: 0 with ~16px text height). Same z-index (1000) as .timeline so
   it slots cleanly into the established map-chrome layer. */
.tl-pill {
  position: absolute; right: 16px; bottom: 16px;
  z-index: 1000;
  background: var(--c-card); border: 1px solid var(--c-line);
  border-radius: 999px;
  padding: 7px 14px 7px 11px;
  font: 600 12px/1 var(--font-ui); color: var(--c-ink-2);
  cursor: pointer;
  box-shadow: var(--shadow-2);
  display: inline-flex; align-items: center; gap: 6px;
}
.tl-pill:hover {
  background: var(--c-accent-soft); color: var(--c-accent-ink);
  border-color: var(--c-accent);
}
.tl-pill:focus-visible {
  outline: 2px solid var(--c-accent); outline-offset: 2px;
}
.tl-pill-caret { font-size: 10px; color: var(--c-ink-3); }
.tl-pill:hover .tl-pill-caret { color: var(--c-accent-ink); }
.tl-zoom-btn {
  font: 600 11px/1 var(--font-mono);
  width: 20px; height: 20px; padding: 0; border-radius: 99px;
  background: var(--c-card); border: 1px solid var(--c-line); color: var(--c-ink-2);
  cursor: pointer; box-shadow: 0 1px 2px rgba(0,0,0,.06);
  display: inline-flex; align-items: center; justify-content: center;
}
.tl-zoom-btn:hover:not(:disabled) {
  background: var(--c-accent-soft); color: var(--c-accent-ink); border-color: var(--c-accent);
}
.tl-zoom-btn:disabled { opacity: 0.35; cursor: default; }
.tl-zoom-reset {
  width: auto; padding: 0 8px; font-size: 10px;
}
.tl-axis { position: absolute; inset: 0; }
.tl-tick { position: absolute; top: 0; bottom: 0; }
.tl-tick-line { position: absolute; left: 0; top: 0; bottom: 0; width: 1px; background: var(--c-line); }
.tl-tick-label { position: absolute; bottom: -2px; left: 0; transform: translateX(-50%); font: 10px/1 var(--font-mono); color: var(--c-ink-3); white-space: nowrap; }
/* Anchor the leftmost label so it doesn't clip off the timeline frame.
   Default centering (translateX -50%) would push half the label off-canvas. */
.tl-tick:first-child .tl-tick-label { transform: translateX(0); }
.tl-tick-mo { margin-left: 3px; color: var(--c-ink-3); opacity: 0.7; }
.tl-rows {
  position: absolute; inset: 0 0 18px 0;
  display: grid; grid-template-rows: 22px 10px 26px;
  align-content: space-between; row-gap: 1px;
}
.tl-row      { position: relative; }
.tl-stays    { height: 22px; }
.tl-layovers { height: 10px; }
.tl-flights  { height: 26px; }
.tl-stay {
  position: absolute; top: 0; height: 22px;
  background: var(--c-card-2); border: 1px solid var(--c-line); border-radius: var(--r-1);
  padding: 0 8px; display: flex; align-items: center; gap: 6px;
  cursor: pointer; overflow: hidden; min-width: 0;
}
.tl-stay-city  { font: 600 11px/1 var(--font-ui); white-space: nowrap; flex-shrink: 0; }
/* Hotel name is the long, shrinkable element — it ellipsizes around the
   always-visible city (left) and meta (right). */
.tl-stay-hotel { font: 11px/1 var(--font-ui); color: var(--c-ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1 1 auto; min-width: 0; }
.tl-stay-hotel::before { content: "·"; margin-right: 6px; color: var(--c-ink-3); }
.tl-stay-meta  { display: inline-flex; gap: 4px; flex-shrink: 0; color: var(--c-ink-3); font: 10.5px/1 var(--font-mono); white-space: nowrap; }
.tl-stay.active { background: var(--c-accent-soft); border-color: var(--c-accent); }
.tl-activity {
  position: absolute; top: 1px; transform: translateX(-50%);
  width: 24px; height: 16px; padding: 0; border-radius: 99px;
  border: 1px solid var(--c-line); background: var(--c-card);
  color: var(--c-ink-2); display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; box-shadow: 0 1px 2px rgba(0,0,0,.06);
}
.tl-activity:hover {
  border-color: var(--c-accent); color: var(--c-accent-ink); background: var(--c-accent-soft);
}
.tl-activity.booked {
  border-color: var(--c-accent); color: var(--c-accent-ink); background: var(--c-accent-soft);
}
.tl-activity-icon { width: 12px; height: 12px; flex: 0 0 auto; }
.tl-stay.active .tl-stay-city,
.tl-stay.active .tl-stay-hotel,
.tl-stay.active .tl-stay-meta { color: var(--c-accent-ink); }

/* Layover connector — short transit window between two flights. Lives on
   its own thin strip between stays and flights so hour-scale items don't
   compete with day-scale lodging. Renders as a horizontal dashed line with
   a centered airport-code chip floating on top; the duration goes inline
   only when the connector is wide enough (otherwise tooltip). */
.tl-layover {
  position: absolute; top: 4px; height: 2px;
  border-top: 1px dashed var(--c-line);
  cursor: pointer; pointer-events: auto;
}
.tl-layover-code {
  position: absolute; left: 50%; top: -7px; transform: translateX(-50%);
  background: var(--c-card); padding: 0 4px;
  font: 600 9px/1 var(--font-mono);
  color: var(--c-ink-2); letter-spacing: 0.02em;
  white-space: nowrap;
}
.tl-layover-dur { margin-left: 4px; font-weight: 400; color: var(--c-ink-3); }
.tl-layover.active { border-top-color: var(--c-accent); }
.tl-layover.active .tl-layover-code { color: var(--c-accent-ink); }

/* Flight / ground bars. Width is duration on the time axis — long-haul
   flights are visibly longer than short hops. Sits at the bottom of the
   flights row so the airline-code chip floats just above. Ground legs use
   a dashed mode-keyed border so air vs rail/road still reads at a glance. */
.tl-bar {
  position: absolute; bottom: 0; height: 6px;
  background: var(--c-arc-idle); border-radius: 3px; opacity: 0.7;
  pointer-events: none;
}
.tl-bar.active { background: var(--c-accent); opacity: 1; }

/* Airline-code chip at the apex of each arc — replaces the old plane glyph
   and the redundant pill row. The chip IS the click target; hover/active
   states match the arc's. translateX(-50%) so `left:%` positions the chip
   centre on the arc apex. */
.tl-arc-label {
  position: absolute; top: 0; transform: translateX(-50%);
  font: 600 10px/1 var(--font-mono); letter-spacing: 0.02em;
  padding: 3px 6px; border-radius: 99px;
  background: var(--c-card); border: 1px solid var(--c-line); color: var(--c-ink);
  cursor: pointer; user-select: none; white-space: nowrap;
  box-shadow: 0 1px 2px rgba(0,0,0,.06);
}
.tl-arc-label:hover { border-color: var(--c-accent); color: var(--c-accent-ink); background: var(--c-accent-soft); }
.tl-arc-label.active { background: var(--c-accent); color: var(--c-bg); border-color: var(--c-accent); }

/* Compact form for sub-threshold legs (airline code only / mode glyph
   alone). Full info stays in the tooltip. */
.tl-arc-label[data-compact="true"] { padding: 2px 5px; font-size: 9.5px; min-width: 18px; text-align: center; }

/* Ground bars — duration bar like flights, but with a mode-keyed dashed
   pattern so air vs rail/road reads at a glance. Background-image gives
   the dash effect since bars are HTML divs (not SVG strokes). */
.tl-bar-ground {
  background: transparent; opacity: 0.9;
  background-image: repeating-linear-gradient(90deg,
    var(--c-ground-train) 0 4px, transparent 4px 6px);
}
.tl-bar-ground.mode-train { background-image: repeating-linear-gradient(90deg, var(--c-ground-train) 0 4px, transparent 4px 6px); }
.tl-bar-ground.mode-bus   { background-image: repeating-linear-gradient(90deg, var(--c-ground-bus)   0 4px, transparent 4px 6px); }
.tl-bar-ground.mode-car   { background-image: repeating-linear-gradient(90deg, var(--c-ground-car)   0 4px, transparent 4px 6px); }
.tl-bar-ground.mode-ferry { background-image: repeating-linear-gradient(90deg, var(--c-ground-ferry) 0 4px, transparent 4px 6px); }
.tl-bar-ground.active { background-image: repeating-linear-gradient(90deg, var(--c-accent) 0 4px, transparent 4px 6px); opacity: 1; }
.tl-arc-label-ground { font-family: var(--font-ui); font-weight: 500; }
.tl-arc-label-ground.mode-train { border-color: var(--c-ground-train); }
.tl-arc-label-ground.mode-bus   { border-color: var(--c-ground-bus); }
.tl-arc-label-ground.mode-car   { border-color: var(--c-ground-car); }
.tl-arc-label-ground.mode-ferry { border-color: var(--c-ground-ferry); }

/* ── Detail popover ──────────────────────────────────────────────────────── */
/* Single-mode sheet anchored to the top-LEFT corner of the map on desktop
   (rendered inside .map-wrap, which is position:relative — so absolute
   top/left are map-relative). On mobile the @media block below switches
   to position:fixed full-width top-anchored.

   The earlier 5-way smart-placement (above/below/left/right/cover + a
   `wide` flag) put the card in unpredictable positions per leg. Then a
   top-centred sheet still landed on top of whichever leg the user just
   clicked. Top-left consistently leaves the right ~70% of the map clear
   so the pan-to-leg logic (map-view.jsx) can put the anchor over there.

   Geometry:
     • top  = 20px from the map's top edge
     • left = 20px from the map's left edge
     • width: 480px on desktop, full-width-minus-12 on mobile
     • max-height clamps to map-wrap height minus the timeline reservation. */
.popover {
  position: absolute;
  top: 20px; left: 20px;
  width: 480px; max-width: calc(100% - 40px);
  background: var(--c-card); border: 1px solid var(--c-line); border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
  /* Must be above .map-overlay (400), Leaflet controls (800), and the
     legend/timeline (1000). */
  z-index: 1100;
  /* Flex column so the inner search-results list can flex to fill the sheet's
     available height instead of being capped at the .pop-options 360px
     default. Saved/Search lists now grow with the sheet, scroll inside it. */
  display: flex; flex-direction: column;
  /* Cap height so the sheet never collides with the timeline. Percentages
     work here because .map-wrap (the absolute-positioning parent) is a
     flex child with a real resolved height. */
  max-height: calc(100% - 20px /* top offset */
      - 124px           /* timeline footprint reservation */
      - 16px);          /* bottom breathing room */
  /* When content exceeds max-height, the sheet itself scrolls. overflow-x
     hidden keeps the rounded corners clean. */
  overflow-x: hidden; overflow-y: auto;
  /* Keep inner-list scroll from chaining to the page on mobile. */
  overscroll-behavior: contain;
  /* Avoid a flash at full opacity before mount — the JS adds .ready one
     tick after mount, CSS transitions opacity over 120ms. */
  opacity: 0; transition: opacity .12s ease-out;
}
.popover.ready { opacity: 1; }
.popover:focus-within { outline: none; }
/* Search/saved results lists grow to fill the sheet (was an opt-in on the
   old `.popover-cover` mode; now universal because every popover is a sheet). */
.popover .pop-options { max-height: none; flex: 1 1 auto; min-height: 0; }

/* Dim backdrop behind the mobile popover sheet. Same visual treatment
   as .mt-backdrop on the trip-manager modal — fades in with the card,
   fades out as the user drags it closed. Pointer-events: auto so a
   tap on the dimmed area still triggers the popover's outside-click
   close (the doc-level pointerdown handler in chrome.jsx runs on any
   click that isn't inside .popover or .map-overlay). Z-index sits
   just under the popover (1100) and above the timeline / topbar
   (both 1000) so the dim coverage matches "everything behind the
   card" — mirrors the trip-manager full-viewport dim. */
.pop-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.42);
  z-index: 1090;
  opacity: 0;
  transition: opacity 120ms ease-out;
  pointer-events: auto;
}
.pop-backdrop.ready { opacity: 1; }

/* Drag-to-dismiss grip at the BOTTOM of the mobile sheet. Mirrors
   .mt-handle-grip on the trip-menu modal but anchored at the bottom of
   its parent card — the swipe gesture pulls upward to close. Generous
   vertical padding gives a ~32px tap target around the 4px visible bar. */
.pop-handle-grip {
  display: flex; justify-content: center; align-items: center;
  padding: 10px 0 14px;
  touch-action: none;
  cursor: grab;
  -webkit-user-select: none; user-select: none;
  /* Sticks to the bottom of the popover; if the card scrolls internally,
     the grip stays in view as a persistent close affordance. */
  position: sticky; bottom: 0; left: 0; right: 0;
  background: linear-gradient(to bottom,
      rgba(255,255,255,0) 0%,
      var(--c-card) 40%, var(--c-card) 100%);
}
.pop-handle-grip:active { cursor: grabbing; }
.pop-handle {
  width: 42px; height: 4px; border-radius: 2px;
  background: var(--c-ink-3); opacity: 0.4;
}
.pop-close { position: absolute; top: 8px; right: 10px; width: 22px; height: 22px; border: 0; background: transparent; color: var(--c-ink-3); font-size: 18px; line-height: 1; cursor: pointer; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.pop-close:hover { background: var(--c-card-2); color: var(--c-ink); }
.pop-h { padding: 14px 16px 10px; border-bottom: 1px solid var(--c-line); }
.pop-route { display: flex; align-items: baseline; gap: 8px; }
.pop-iata { font: 700 18px/1 var(--font-mono); letter-spacing: 0.01em; }
.pop-arrow { color: var(--c-ink-3); font-size: 16px; }
.pop-route-picker {
  margin-top: 10px;
}
.pop-route-picker .cp-list {
  max-height: 220px;
}
.pop-city { font: 600 16px/1 var(--font-ui); letter-spacing: -0.01em; }
.pop-nights { font: 11px/1 var(--font-mono); color: var(--c-ink-3); padding: 2px 6px; border: 1px solid var(--c-line); border-radius: 3px; }
.pop-sub { font-size: 12px; color: var(--c-ink-2); margin-top: 4px; }
.pop-sub-editable {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.pop-sub-editable .date-display {
  color: var(--c-ink);
}
.pop-source {
  font: 10.5px/1 var(--font-mono); color: var(--c-ink-3);
  margin-top: 6px; padding: 0 16px;
  text-transform: uppercase; letter-spacing: 0.04em;
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
}
.pop-source a { color: inherit; text-decoration: underline; text-decoration-color: var(--c-line); }
.pop-source a:hover { color: var(--c-ink-2); text-decoration-color: var(--c-ink-2); }

.pop-options { display: flex; flex-direction: column; max-height: 360px; overflow: auto; }
.pop-opt { display: grid; grid-template-columns: 1.1fr 1.2fr 0.9fr; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--c-line); cursor: pointer; }
.pop-opt:last-child { border-bottom: 0; }
.pop-opt:hover { background: var(--c-card-2); }
.pop-opt.selected { background: var(--c-accent-soft); }
.pop-opt.selected .pop-opt-code { color: var(--c-accent-ink); }
.pop-opt-code { font: 600 13px/1.2 var(--font-mono); }
.pop-opt-airline { font-size: 12px; color: var(--c-ink-2); margin-top: 2px; }
.pop-opt-eq { font-size: 11px; color: var(--c-ink-3); margin-top: 2px; }
.pop-opt-times { font: 600 13px/1.2 var(--font-mono); }
.pop-opt-dur { font-size: 11px; color: var(--c-ink-3); margin-top: 2px; }
.pop-opt-award { font-size: 10.5px; color: var(--c-accent-ink); margin-top: 4px; text-transform: uppercase; letter-spacing: 0.04em; }
.pop-opt-award.none { color: var(--c-ink-3); }
.pop-opt-r { text-align: right; }
.pop-opt-cash { font: 600 14px/1 var(--font-ui); }
.pop-opt-cash.miles-primary { font: 600 13px/1 var(--font-mono); color: var(--c-accent-ink); }
.pop-opt-cash.none { color: var(--c-ink-3); font-weight: 400; }
.pop-opt-miles { font: 11px/1.4 var(--font-mono); color: var(--c-accent-ink); margin-top: 3px; }
.pop-opt-miles.none { color: var(--c-ink-3); }
.pop-opt-actions { display: flex; gap: 4px; margin-top: 6px; justify-content: flex-end; }
.pop-opt-thumb { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--r-1); margin-top: 8px; background: var(--c-card-2); }
.pop-mini { font: 10px/1 var(--font-mono); padding: 3px 7px; border-radius: 3px; background: var(--c-card); border: 1px solid var(--c-line); color: var(--c-ink-2); cursor: pointer; }
.pop-mini:hover { background: var(--c-card-2); color: var(--c-ink); }
.pop-mini.danger:hover { background: var(--c-accent-soft); color: var(--c-accent-ink); border-color: var(--c-accent); }

.pop-tabs { display: flex; gap: 2px; margin-top: 8px; border-bottom: 1px solid var(--c-line); margin: 8px -16px -10px; padding: 0 16px; }
.pop-tabs button { background: transparent; border: 0; padding: 8px 10px; font: 11.5px/1 var(--font-ui); font-weight: 500; color: var(--c-ink-3); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.pop-tabs button.active { color: var(--c-ink); border-bottom-color: var(--c-accent); }
.pop-tabs button:hover { color: var(--c-ink); }
.pop-search { display: flex; flex-direction: column; }
.pop-search-bar { padding: 10px 16px; border-bottom: 1px solid var(--c-line); display: flex; gap: 8px; align-items: center; }
.pop-search-bar input[type="date"] { flex: 1; padding: 4px 6px; border: 1px solid var(--c-line); border-radius: var(--r-1); font: inherit; color: var(--c-ink); background: var(--c-card-2); }
.pop-empty { padding: 20px 16px; text-align: center; color: var(--c-ink-3); font-size: 12px; }
.pop-link { background: transparent; border: 0; color: var(--c-accent); cursor: pointer; font: inherit; text-decoration: underline; padding: 0; }
.pop-error { margin: 8px 16px 0; padding: 8px 10px; border-radius: var(--r-1); background: var(--c-accent-soft); color: var(--c-accent-ink); font-size: 11.5px; line-height: 1.4; border: 1px solid var(--c-accent); }

/* 4-tab variant: tighter padding so all four labels fit at popover width */
.pop-tabs.pop-tabs-4 button { padding: 8px 6px; font-size: 11px; flex: 1; text-align: center; }

/* Award/Cash source toggle inside the Search tab */
.pop-source-toggle { display: inline-flex; gap: 0; border: 1px solid var(--c-line); border-radius: var(--r-1); overflow: hidden; }
.pop-source-toggle button { background: transparent; border: 0; padding: 4px 8px; font: 11px/1 var(--font-ui); color: var(--c-ink-3); cursor: pointer; }
.pop-source-toggle button.active { background: var(--c-accent-soft); color: var(--c-accent-ink); }
.pop-source-toggle button + button { border-left: 1px solid var(--c-line); }
.pop-source-toggle button:disabled { opacity: 0.4; cursor: not-allowed; }

/* Manual entry + paste-link forms. Scrolling is delegated to the outer
   .popover container (which is already height-clamped to roomAbove/roomBelow);
   a nested overflow region inside .pop-form just creates a confusing extra
   scrollbar that hides most of the form behind a tiny window. */
.pop-form { padding: 12px 16px 14px; display: flex; flex-direction: column; gap: 10px; }
.pop-form-row { display: flex; flex-direction: column; gap: 4px; }
.pop-form-row > label { font: 10.5px/1 var(--font-mono); color: var(--c-ink-3); text-transform: uppercase; letter-spacing: 0.04em; }
.pop-form-row input, .pop-form-row select {
  padding: 6px 8px; border: 1px solid var(--c-line); border-radius: var(--r-1);
  font: 12.5px/1.2 var(--font-ui); color: var(--c-ink); background: var(--c-card);
  width: 100%; box-sizing: border-box;
}
.pop-form-row input:focus, .pop-form-row select:focus { outline: 2px solid var(--c-accent); outline-offset: 1px; border-color: var(--c-accent); }
.pop-form-row.split { flex-direction: row; gap: 8px; }
.pop-form-row.split > div { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
.pop-form-row.split > div > label { font: 10.5px/1 var(--font-mono); color: var(--c-ink-3); text-transform: uppercase; letter-spacing: 0.04em; }
.pop-form-row.split > div.grow { flex: 2; }
.pop-form-actions { display: flex; gap: 8px; justify-content: flex-end; padding-top: 4px; }

/* Segment block in the manual flight form. Each block holds the per-segment
   inputs (carrier, flight#, date, from, to, depart, arrive, aircraft) and is
   visually grouped with a card-style border + header. The "× remove" button
   only appears when there are 2+ segments. */
.pop-form-segment {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px 12px; background: var(--c-card-2);
  border: 1px solid var(--c-line); border-radius: var(--r-1);
}
.pop-form-seg-h {
  display: flex; justify-content: space-between; align-items: center;
  font: 600 11px/1 var(--font-mono); text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--c-ink-2);
}
.pop-form-seg-rm {
  width: 22px; height: 22px; border: 1px solid var(--c-line); background: var(--c-card);
  border-radius: 3px; cursor: pointer; color: var(--c-ink-3); padding: 0;
  font: 14px/1 var(--font-mono);
}
.pop-form-seg-rm:hover { color: var(--c-accent-ink); border-color: var(--c-accent); background: var(--c-accent-soft); }
.pop-form-add-seg { align-self: flex-start; font-size: 11.5px; padding: 6px 10px; }
/* Booking / Segments sections in the manual flight form. The Booking section
   is grouped with a subtle header so users see which fields apply to the whole
   purchase vs. per-segment fields. */
.pop-form-section {
  display: flex; flex-direction: column; gap: 10px;
  padding: 10px 12px;
  background: var(--c-card);
  border: 1px solid var(--c-line); border-radius: var(--r-1);
}
.pop-form-section-h {
  display: flex; justify-content: space-between; align-items: center;
  font: 600 11px/1 var(--font-mono); text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--c-ink-2);
  margin-top: 4px;
}
.pop-form-section-note {
  font: 10px/1.2 var(--font-ui); text-transform: none; letter-spacing: 0;
  color: var(--c-accent-ink); background: var(--c-accent-soft);
  border: 1px solid var(--c-accent); padding: 1px 6px; border-radius: 99px;
}

/* Parsed-link preview */
.pop-parsed { border: 1px solid var(--c-line); border-radius: var(--r-1); padding: 10px 12px; background: var(--c-card-2); display: flex; flex-direction: column; gap: 10px; }
.pop-parsed-h { font: 10.5px/1 var(--font-mono); color: var(--c-ink-3); text-transform: uppercase; letter-spacing: 0.04em; }
.pop-parsed-leg { display: flex; flex-direction: column; gap: 6px; padding-bottom: 8px; border-bottom: 1px solid var(--c-line); }
.pop-parsed-leg:last-of-type { border-bottom: 0; padding-bottom: 0; }
.ppl-route { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-weight: 600; }
.ppl-route .pop-iata { font-size: 13px; }
.ppl-route .pop-arrow { color: var(--c-ink-3); }
.ppl-via { font: 11px/1 var(--font-mono); color: var(--c-ink-2); padding: 1px 4px; border-radius: 3px; background: var(--c-card); font-weight: 500; }
.ppl-meta { color: var(--c-ink-2); font-weight: 400; font-size: 11.5px; margin-left: auto; font-family: var(--font-mono); }
.ppl-segments { display: flex; flex-direction: column; gap: 2px; padding-left: 4px; }
.ppl-seg { display: flex; gap: 8px; font: 11px/1.4 var(--font-mono); color: var(--c-ink-2); flex-wrap: wrap; }
.ppl-seg-route { min-width: 80px; }
.ppl-seg-flt { color: var(--c-ink); font-weight: 500; }
.ppl-seg-time { color: var(--c-ink); }
.ppl-seg-lay { color: var(--c-accent-ink); font-size: 10.5px; }
.ppl-warn { font-size: 11.5px; color: var(--c-accent-ink); background: var(--c-accent-soft); padding: 6px 8px; border-radius: var(--r-1); border: 1px solid var(--c-accent); }
.ppl-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.ppl-hint { font-size: 11px; color: var(--c-ink-3); line-height: 1.4; padding: 6px 8px; background: var(--c-card); border-radius: var(--r-1); border: 1px dashed var(--c-line); }
.ppl-hint b { color: var(--c-ink); font-family: var(--font-mono); }

/* Connect-seats.aero gate: replaces the filters/results when the user must
   sign in or connect their seats.aero Pro account before searching. */
.pop-seats-gate { padding: 16px; display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
.psg-title { font: 600 13px/1.3 var(--font-ui); color: var(--c-ink); }
.psg-body { font: 12px/1.5 var(--font-ui); color: var(--c-ink-2); }

/* Search-tab filter bar (cabin select, direct-only checkbox, date window) */
.pop-search-filters { padding: 6px 16px 10px; border-bottom: 1px solid var(--c-line); display: flex; flex-direction: column; gap: 6px; }
.psf-search { margin-left: auto; padding: 5px 12px; font-size: 11.5px; }
.psf-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.psf-l { font: 10.5px/1 var(--font-mono); color: var(--c-ink-3); text-transform: uppercase; letter-spacing: 0.04em; }
.psf-row input[type="date"], .psf-row select, .psf-row input[type="text"], .psf-row input[type="number"] {
  padding: 4px 6px; border: 1px solid var(--c-line); border-radius: var(--r-1);
  font: 12px/1.2 var(--font-ui); color: var(--c-ink); background: var(--c-card);
}
.psf-row input[type="date"], .psf-row input[type="text"] { flex: 1; min-width: 130px; }
.psf-row input[type="number"] { width: 64px; }
.psf-row input[type="text"]:disabled { background: var(--c-card-2); color: var(--c-ink-2); }
.psf-check { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--c-ink-2); cursor: pointer; user-select: none; }
.psf-check input[type="checkbox"] { width: 14px; height: 14px; cursor: pointer; accent-color: var(--c-accent); }
.psf-check:hover span { color: var(--c-ink); }
.hotel-search-filters { gap: 10px; padding-top: 10px; }
.hsf-grid { display: grid; gap: 8px; }
.hsf-dates, .hsf-filters { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.hsf-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.hsf-field input[type="date"], .hsf-field input[type="text"], .hsf-field input[type="number"], .hsf-field select {
  width: 100%; box-sizing: border-box;
  padding: 5px 7px; border: 1px solid var(--c-line); border-radius: var(--r-1);
  font: 12px/1.2 var(--font-ui); color: var(--c-ink); background: var(--c-card);
}
.hsf-field input[type="number"] { min-width: 0; }
.hsf-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 1px; }
.hsf-search { min-width: 86px; padding: 6px 12px; font-size: 12px; }
.pop-result-meta {
  padding: 8px 16px 0; color: var(--c-ink-3); text-align: right;
  font: 10.5px/1 var(--font-mono); text-transform: uppercase; letter-spacing: 0.04em;
}
.pop-more { padding: 10px 16px 14px; display: flex; justify-content: center; border-top: 1px solid var(--c-line); }

/* Multi-segment summary inside an option row (small chips beneath times+cabin) */
.pop-opt-segs { display: flex; flex-direction: column; gap: 1px; margin-top: 2px; font: 10.5px/1.4 var(--font-mono); color: var(--c-ink-3); }
.pop-opt-seg b { color: var(--c-ink); font-weight: 500; }
.pop-opt-seg span { color: var(--c-ink-2); }

/* "times unset" placeholder */
.pop-opt-times.none { color: var(--c-ink-3); font-weight: 400; font-style: italic; }
/* Hotel paste-link result row preview: shows the link's check-in/check-out
   dates inline so the user sees a date mismatch with the stay leg before
   clicking + add. The "warn" chip appears only when the dates differ. */
.pop-opt-paste-dates {
  font: 10.5px/1.3 var(--font-mono); color: var(--c-ink-2); margin-top: 2px;
}
.pop-opt-paste-warn {
  display: inline-block; margin-top: 4px;
  font: 600 9.5px/1 var(--font-ui); letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--c-accent-ink); background: var(--c-accent-soft);
  border: 1px solid var(--c-accent); padding: 2px 6px; border-radius: 99px;
}
/* Day-shift pill rendered next to "depart → arrive" when arrival lands on a
   later calendar day. Friendlier than the raw "+1" suffix. */
.pop-opt-day {
  display: inline-block; margin-left: 6px;
  font: 600 9.5px/1 var(--font-ui); letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--c-accent-ink);
  background: var(--c-accent-soft); border: 1px solid var(--c-accent);
  padding: 1px 5px; border-radius: 99px;
  vertical-align: 1px;
}

/* Date label rendered on award search-result rows when the option's date is
   not the leg's date. Red, prefixed before the times so the divergence is
   the first thing scanned. Only the search call site passes legDate, so
   saved/paste rows never render this. */
.pop-opt-date {
  display: inline-block; margin-right: 8px;
  font: 600 11.5px/1 var(--font-mono);
  color: var(--c-accent);
}

/* ── TopBar enhancements ─────────────────────────────────────────────────── */
.tb-trip { font-weight: 600; letter-spacing: -0.01em; font-size: 14px; }
.tb-dates { color: var(--c-ink-3); font-size: 11.5px; margin-top: 2px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.tb-dates-sep { color: var(--c-ink-3); opacity: 0.5; }
.tb-right { position: relative; }
.tb-menu {
  position: absolute; right: 0; top: calc(100% + 6px);
  min-width: 240px; background: var(--c-card);
  border: 1px solid var(--c-line); border-radius: var(--r-2);
  box-shadow: var(--shadow-2); overflow: hidden;
  display: flex; flex-direction: column;
  /* Above Leaflet's control container (z-index 800) and panes (≤700). */
  z-index: 1000;
}
.tb-menu-item {
  display: flex; flex-direction: column; gap: 2px;
  padding: 10px 12px; background: transparent; border: 0;
  text-align: left; cursor: pointer;
  border-bottom: 1px solid var(--c-line);
}
.tb-menu-item:last-child { border-bottom: 0; }
.tb-menu-item:hover { background: var(--c-card-2); }
.tb-menu-item b { font-size: 12.5px; font-weight: 600; color: var(--c-ink); }
.tb-menu-item span { font-size: 11px; color: var(--c-ink-3); }
.tb-menu-sep { height: 1px; background: var(--c-line); margin: 0; }
.tb-menu-section { font: 600 10px/1 var(--font-ui); text-transform: uppercase; letter-spacing: 0.06em; color: var(--c-ink-3); padding: 8px 12px 4px; background: var(--c-card-2); border-bottom: 1px solid var(--c-line); }
.tb-menu-item.compact { padding: 7px 12px; }
.tb-menu-item.compact b { font-size: 12px; }
.tb-menu-item.compact span { font-size: 10.5px; }
.tb-menu-item.danger b { color: var(--c-accent-ink); }
.tb-menu-item.danger:hover { background: var(--c-accent-soft); }
/* Active trip in the Switch list — soft accent fill + 2px crimson left bar so
   the user can see at a glance which trip they're currently editing. The 2px
   is absorbed from the left padding so the text stays aligned with siblings. */
.tb-menu-item.active {
  background: var(--c-accent-soft);
  cursor: default;
  border-left: 2px solid var(--c-accent);
  padding-left: 10px;
}
.tb-menu-item.active b { color: var(--c-accent-ink); }
.tb-menu-item.active:hover { background: var(--c-accent-soft); }
/* Disabled state for the "Sign in to share" entry — preserves clickability
   (it dispatches the auth popover) but tones the row down so it reads as a
   gated action. */
.tb-menu-item.muted b { color: var(--c-ink-3); }
.tb-menu-item.muted span { color: var(--c-ink-3); }
.tb-menu-item:disabled b,
.tb-menu-item:disabled span { color: var(--c-ink-3); }
.tb-menu-item.active:disabled b { color: var(--c-accent-ink); }
.tb-menu-item.active:disabled span { color: var(--c-accent-ink); opacity: 0.85; }

/* ── ShareDialog popover ─────────────────────────────────────────────────────
   Anchored under the Trip menu button (.tb-trip-menu is position: relative
   already). Mirrors the .tb-menu visual language — same card bg, same border
   + shadow — but wider and laid out vertically for the URL field + actions. */
.share-dialog {
  position: absolute; right: 0; top: calc(100% + 6px);
  width: 360px; max-width: calc(100vw - 32px);
  background: var(--c-card);
  border: 1px solid var(--c-line); border-radius: var(--r-2);
  box-shadow: var(--shadow-2);
  z-index: 1010;
  padding: 14px 14px 12px;
  display: flex; flex-direction: column; gap: 10px;
}
.share-header {
  font: 600 13px/1.2 var(--font-ui);
  color: var(--c-ink);
}
.share-status {
  font-size: 12px; color: var(--c-ink-3);
  padding: 4px 0;
}
.share-error {
  font-size: 12px; color: var(--c-accent-ink);
  background: var(--c-accent-soft);
  border: 1px solid var(--c-accent);
  border-radius: var(--r-1);
  padding: 8px 10px;
}
.share-input {
  width: 100%;
  font: 12px/1.4 var(--font-mono);
  padding: 8px 10px;
  border: 1px solid var(--c-line);
  border-radius: var(--r-1);
  background: var(--c-card-2);
  color: var(--c-ink);
}
.share-input:focus {
  outline: 2px solid var(--c-accent);
  outline-offset: 1px;
  border-color: var(--c-accent);
}
.share-actions {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
}
.share-actions .tb-btn { padding: 6px 12px; font-size: 12px; }
.share-actions .share-stop {
  margin-left: auto;
  color: var(--c-accent-ink);
  border-color: transparent;
  background: transparent;
}
.share-actions .share-stop:hover {
  background: var(--c-accent-soft);
  border-color: var(--c-accent);
}
.share-foot {
  font: 11px/1.45 var(--font-ui);
  color: var(--c-ink-3);
  padding-top: 4px;
  border-top: 1px solid var(--c-line);
  margin-top: 2px;
}

/* ── Trip switcher trigger + popover + Manage Trips modal ────────────────────
   Replaces the old .tb-menu kitchen-sink dropdown. Three coordinated surfaces:
     • .tb-trip-switcher  — the "● <title> ▾" button in the TopBar's right
                            cluster. Reuses .tb-btn.ghost styling for
                            consistency with the help/account/undo cluster.
     • .ts-*              — compact switcher popover (anchored under the
                            trigger). Search + RECENT/OTHER list + bottom
                            action row (New / Import / Manage trips →).
     • .mt-*              — Manage Trips modal. Centered card on desktop,
                            full-screen sheet on mobile, with per-row
                            inline actions on desktop and a kebab → action
                            sheet on mobile.

   Z-index ladder (so future additions don't collide):
       500   .sidebar-fab
       800   leaflet-control-container (Leaflet defaults — zoom, attribution)
       900   .sidebar (mobile overlay)
      1000   .topbar / .tb-menu / .ts-popover / .timeline
      1010   .share-dialog (anchored variant)
      1100   .popover (DetailPopover)
      1200   .mt-backdrop + .mt-modal              [desktop]
      1210   .mt-kebab-sheet                       [desktop fallback]
      1220   .share-modal-backdrop                 [desktop fallback]
      2000   .mt-backdrop + .mt-modal              [mobile — clears Leaflet
                                                   controls that iOS Safari
                                                   sometimes hoists into
                                                   their own stacking context]
      2010   .mt-kebab-sheet                       [mobile]
      2020   .share-modal-backdrop                 [mobile] */

/* Trigger — "<title> ▾". Ellipsized title + caret. (Accent dot was removed
   after user feedback that it read as a sync/notification indicator.) */
.tb-trip-switcher {
  display: inline-flex; align-items: center; gap: 6px;
  max-width: 220px;
}
.tb-trip-switcher .ts-title {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0;
}
.tb-trip-switcher .ts-caret {
  color: var(--c-ink-3); font-size: 10px; flex-shrink: 0;
}

/* Popover — same anchoring/visual language as .tb-menu, just wider with a
   search input on top and a sticky action row on the bottom. */
.ts-popover {
  position: absolute; right: 0; top: calc(100% + 6px);
  width: 300px; max-width: calc(100vw - 24px);
  background: var(--c-card);
  border: 1px solid var(--c-line); border-radius: var(--r-2);
  box-shadow: var(--shadow-2);
  display: flex; flex-direction: column;
  max-height: min(70vh, 520px);
  overflow: hidden;
  z-index: 1000;
}
.ts-search { padding: 10px 12px 8px; border-bottom: 1px solid var(--c-line); }
.ts-search-input {
  width: 100%;
  font: 12px/1.4 var(--font-ui);
  padding: 7px 10px;
  border: 1px solid var(--c-line); border-radius: var(--r-1);
  background: var(--c-card-2); color: var(--c-ink);
  box-sizing: border-box;
}
.ts-search-input:focus {
  outline: 2px solid var(--c-accent); outline-offset: 1px;
  border-color: var(--c-accent);
}
.ts-list { flex: 1 1 auto; overflow: auto; }
/* Section header inside the switcher — reuse the .tb-menu-section treatment
   (uppercase, small, accent-soft background) for visual continuity. */
.ts-section { font: 600 10px/1 var(--font-ui); text-transform: uppercase; letter-spacing: 0.06em; color: var(--c-ink-3); padding: 8px 12px 4px; background: var(--c-card-2); border-bottom: 1px solid var(--c-line); }
.ts-trip-row {
  display: flex; flex-direction: column; gap: 2px;
  padding: 8px 12px; background: transparent; border: 0;
  text-align: left; cursor: pointer; width: 100%;
  border-bottom: 1px solid var(--c-line);
  color: var(--c-ink);
}
.ts-trip-row:last-child { border-bottom: 0; }
.ts-trip-row:hover { background: var(--c-card-2); }
.ts-trip-row.active {
  background: var(--c-accent-soft);
  cursor: default;
  border-left: 2px solid var(--c-accent);
  padding-left: 10px;
}
.ts-trip-row.active .ts-row-title { color: var(--c-accent-ink); }
.ts-trip-row.active:hover { background: var(--c-accent-soft); }
.ts-row-title {
  font: 600 12.5px/1.2 var(--font-ui); color: var(--c-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: flex; align-items: center; gap: 6px;
}
.ts-row-meta {
  font: 11px/1.2 var(--font-ui); color: var(--c-ink-3);
}
.ts-row-tag {
  font: 10px/1 var(--font-mono); padding: 2px 5px;
  border-radius: 2px; background: var(--c-card);
  color: var(--c-ink-3); border: 1px solid var(--c-line);
}
.ts-empty {
  padding: 24px 16px; text-align: center;
  color: var(--c-ink-3); font-size: 12px;
}
.ts-actions {
  display: flex; gap: 6px; align-items: center;
  padding: 8px 10px; border-top: 1px solid var(--c-line);
  background: var(--c-card-2);
}
.ts-actions .tb-btn { padding: 6px 10px; font-size: 11.5px; }
.ts-action-manage { margin-left: auto; }
/* Crimson resting-state primary used by the bottom-row "+ New" and the
   modal's "+ New" header / "+ New trip" mobile footer. The existing
   .tb-btn.primary is dark-ink with crimson hover; the mockup shows
   crimson as resting state. New variant rather than retheming .primary. */
.tb-btn.accent {
  background: var(--c-accent); color: white; border-color: var(--c-accent);
}
.tb-btn.accent:hover {
  /* Slight darken using ink-mix; falls back gracefully on older Safari. */
  filter: brightness(0.94);
}
.tb-btn.accent:focus-visible {
  outline: 2px solid var(--c-accent); outline-offset: 2px;
}

/* Manage Trips modal — backdrop + shell + rows + footer.
   Backdrop is z-index 1200 (above .popover at 1100) so a stuck-open leg
   popover can't intercept clicks meant for the modal. */
.mt-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.42);
  z-index: 1200;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.mt-modal {
  /* Desktop width — 540px reads as proportional to the single-line trip rows.
     Earlier 720px felt unnaturally wide for the actual content. */
  width: min(540px, 100%);
  max-height: min(80vh, 720px);
  background: var(--c-card);
  border: 1px solid var(--c-line); border-radius: var(--r-2);
  box-shadow: var(--shadow-2);
  display: flex; flex-direction: column;
  overflow: hidden;
}
/* Drag-to-dismiss grip on the mobile sheet. Generous padding so the
   touch target is comfortable (~44px tall) even though the visible bar
   is only 4px. `touch-action: none` prevents the browser from swallowing
   the gesture as a page scroll — also belted by preventDefault in the
   JS pointerdown handler. */
.mt-handle-grip {
  /* Only rendered on mobile (component gates on isNarrow). */
  display: flex; justify-content: center; align-items: center;
  padding: 14px 0 8px;
  touch-action: none;
  cursor: grab;
  -webkit-user-select: none; user-select: none;
}
.mt-handle-grip:active { cursor: grabbing; }
.mt-handle {
  /* Visual bar inside the grip wrapper. The wrapper provides spacing. */
  width: 36px; height: 4px; border-radius: 2px;
  background: var(--c-line);
}
.mt-header {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--c-line);
}
.mt-header-title {
  font: 600 14px/1.2 var(--font-ui); color: var(--c-ink);
  flex: 1 1 auto;
  display: flex; align-items: baseline; gap: 8px;
}
.mt-header-count {
  font: 500 12px/1 var(--font-ui); color: var(--c-ink-3);
}
.mt-header-actions { display: flex; gap: 6px; align-items: center; }
.mt-close { /* uses .tb-icon as the base class */ }

.mt-search { padding: 10px 16px; border-bottom: 1px solid var(--c-line); }
.mt-search-input {
  width: 100%;
  font: 12.5px/1.4 var(--font-ui);
  padding: 8px 12px;
  border: 1px solid var(--c-line); border-radius: var(--r-1);
  background: var(--c-card-2); color: var(--c-ink);
  box-sizing: border-box;
}
.mt-search-input:focus {
  outline: 2px solid var(--c-accent); outline-offset: 1px;
  border-color: var(--c-accent);
}

.mt-import-error {
  padding: 8px 16px;
  background: var(--c-accent-soft); color: var(--c-accent-ink);
  font-size: 12px; line-height: 1.4;
  border-bottom: 1px solid var(--c-accent);
}

.mt-list { flex: 1 1 auto; overflow: auto; }
.mt-empty {
  padding: 28px 16px; text-align: center;
  color: var(--c-ink-3); font-size: 12.5px;
  display: flex; flex-direction: column; gap: 8px; align-items: center;
}
.mt-row {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr) auto;
  align-items: center; gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--c-line);
  cursor: pointer;
  background: transparent;
  /* Plain divs as row containers — bind the click on the dot+body subarea
     so action buttons aren't double-handled. */
}
.mt-row:last-child { border-bottom: 0; }
.mt-row:hover { background: var(--c-card-2); }
.mt-row.active { background: var(--c-accent-soft); cursor: default; }
.mt-row.active:hover { background: var(--c-accent-soft); }
.mt-row.sample .mt-row-title { color: var(--c-ink-2); }
.mt-row.sample { opacity: 0.78; }
.mt-row-dot {
  width: 10px; height: 10px; border-radius: 50%;
  border: 1.5px solid var(--c-ink-3); background: transparent;
  box-sizing: border-box;
}
.mt-row.active .mt-row-dot {
  background: var(--c-accent); border-color: var(--c-accent);
}
.mt-row-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mt-row-title {
  font: 600 13px/1.25 var(--font-ui); color: var(--c-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: flex; align-items: center; gap: 6px;
}
.mt-row.active .mt-row-title { color: var(--c-accent-ink); }
.mt-row-meta {
  font: 11.5px/1.25 var(--font-ui); color: var(--c-ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mt-row-actions {
  display: flex; gap: 2px;
  opacity: 0; transition: opacity .1s;
}
/* Reveal on hover/focus-within. Force visible on the active row so it doesn't
   look dead — the active row otherwise has no hover affordance. */
.mt-row:hover .mt-row-actions,
.mt-row:focus-within .mt-row-actions,
.mt-row.active .mt-row-actions { opacity: 1; }
.mt-row-action {
  width: 28px; height: 28px;
  border: 1px solid transparent; border-radius: var(--r-1);
  background: transparent; color: var(--c-ink-2);
  cursor: pointer; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.mt-row-action:hover {
  background: var(--c-card); border-color: var(--c-line); color: var(--c-ink);
}
.mt-row-action.danger:hover {
  background: var(--c-accent-soft); border-color: var(--c-accent);
  color: var(--c-accent-ink);
}
.mt-row-action:focus-visible {
  outline: 2px solid var(--c-accent); outline-offset: 1px;
}
.mt-row-kebab {
  /* Mobile-only — display: none default, revealed in the @media block. */
  display: none;
  width: 32px; height: 32px;
  border: 1px solid transparent; border-radius: var(--r-1);
  background: transparent; color: var(--c-ink-2);
  cursor: pointer; padding: 0;
  align-items: center; justify-content: center;
}
.mt-row-kebab:hover { background: var(--c-card); border-color: var(--c-line); color: var(--c-ink); }

.mt-footer {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 16px;
  border-top: 1px solid var(--c-line);
  background: var(--c-card-2);
  font: 11.5px/1.2 var(--font-ui); color: var(--c-ink-3);
  flex-wrap: wrap;
}
.mt-footer-left, .mt-footer-right { display: flex; align-items: center; gap: 10px; }
.mt-footer-link {
  background: transparent; border: 0; padding: 0; cursor: pointer;
  color: var(--c-ink-2); font: inherit; text-decoration: underline;
  text-decoration-color: var(--c-line); text-underline-offset: 2px;
}
.mt-footer-link:hover { color: var(--c-ink); text-decoration-color: var(--c-accent); }
.mt-footer-hint { font-family: var(--font-mono); color: var(--c-ink-3); }

/* Mobile-only thin "Load sample trip" link, sitting just above the action
   bar. Hidden on desktop (the desktop footer has its own copy in the
   bottom-right). Quiet styling — small font, muted color — so it doesn't
   compete with the "+ New trip" primary CTA below. */
.mt-mobile-sample {
  display: none;
  text-align: center;
  padding: 8px 16px 4px;
  border-top: 1px solid var(--c-line);
  background: var(--c-card);
  font: 11.5px/1.2 var(--font-ui);
}

/* Mobile-only footer with full-width primary CTA + import icon. Hidden on
   desktop; revealed in the @media block. */
.mt-footer-actions {
  display: none;
  gap: 8px; align-items: center;
  padding: 10px 16px;
  padding-bottom: max(10px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--c-line);
  background: var(--c-card);
}
.mt-footer-actions .tb-btn.accent { flex: 1 1 auto; padding: 10px 14px; font-size: 13px; }
.mt-footer-import { width: 44px; height: 44px; flex-shrink: 0; }

/* Kebab action sheet on mobile — anchored to the bottom, above the modal
   layer (1210 > 1200). Doesn't get its own backdrop; the modal already
   captures outside-clicks. */
.mt-kebab-sheet {
  position: fixed;
  left: 12px; right: 12px;
  bottom: max(12px, env(safe-area-inset-bottom));
  background: var(--c-card);
  border: 1px solid var(--c-line); border-radius: var(--r-2);
  box-shadow: var(--shadow-2);
  z-index: 1210;
  overflow: hidden;
}
.mt-kebab-header {
  padding: 10px 14px;
  font: 600 12.5px/1.2 var(--font-ui); color: var(--c-ink);
  border-bottom: 1px solid var(--c-line);
  background: var(--c-card-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mt-kebab-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 12px 14px;
  background: transparent; border: 0; cursor: pointer;
  text-align: left;
  font: 13px/1.2 var(--font-ui); color: var(--c-ink);
  border-bottom: 1px solid var(--c-line);
}
.mt-kebab-item:last-child { border-bottom: 0; }
.mt-kebab-item:hover { background: var(--c-card-2); }
.mt-kebab-item.danger { color: var(--c-accent-ink); }
.mt-kebab-item.danger:hover { background: var(--c-accent-soft); }

/* ShareDialog modal-on-modal variant — used when Share is invoked from a row
   inside the Manage Trips modal. A separate, slightly darker backdrop gives
   the user a visual handoff from manage→share, and lifts the share dialog
   above the modal layer (1220 > 1200). Anchored ShareDialog (TopBar default)
   keeps its existing positioning rules untouched. */
.share-modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.28);
  z-index: 1220;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.share-dialog--modal {
  position: static;
  top: auto; right: auto;
  width: min(420px, 100%);
  max-width: none;
}

/* ── Inline editing primitives ───────────────────────────────────────────── */
.inline-text {
  cursor: text; border-radius: 3px; padding: 1px 3px; margin: -1px -3px;
  transition: background .12s;
  display: inline-block; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  vertical-align: bottom;
}
.inline-text:hover { background: var(--c-accent-soft); }
.inline-text.editing {
  background: var(--c-card); border: 1px solid var(--c-accent);
  padding: 0 4px; margin: -1px -4px; outline: none; font: inherit; color: inherit;
  min-width: 120px;
}
.inline-placeholder { color: var(--c-ink-3); font-style: italic; }
.inline-text.tb-trip { font-weight: 600; font-size: 14px; max-width: 320px; }
.inline-text.tb-trip.editing { font-size: 14px; min-width: 200px; }

.date-field { position: relative; display: inline-flex; align-items: center; }
.date-display { cursor: pointer; padding: 1px 4px; margin: -1px -4px; border-radius: 3px; transition: background .12s; }
.date-display:hover { background: var(--c-accent-soft); }
.date-popover {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 60;
  padding: 4px 6px; border: 1px solid var(--c-accent); border-radius: var(--r-1);
  background: var(--c-card); font: inherit; color: var(--c-ink);
  box-shadow: var(--shadow-1);
}
.num-stepper { display: inline-flex; align-items: center; gap: 4px; padding: 0 2px; }
.ns-btn { width: 18px; height: 18px; border: 1px solid var(--c-line); border-radius: 3px; background: var(--c-card); cursor: pointer; color: var(--c-ink-2); padding: 0; line-height: 1; font: 12px var(--font-mono); }
.ns-btn:hover:not(:disabled) { background: var(--c-card-2); color: var(--c-ink); }
.ns-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.ns-val { min-width: 18px; text-align: center; font: 600 11.5px/1 var(--font-mono); color: var(--c-ink); }
.ns-suffix { color: var(--c-ink-3); margin-left: 2px; }

.time-field { position: relative; display: inline-flex; align-items: center; }
.time-display { font: 11px/1 var(--font-mono); cursor: pointer; padding: 2px 5px; border-radius: 3px; border: 1px solid var(--c-line); background: var(--c-card-2); }
.time-display:hover { background: var(--c-accent-soft); border-color: var(--c-accent); }
.time-popover {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 60;
  display: flex; align-items: center; gap: 6px; padding: 6px 8px;
  background: var(--c-card); border: 1px solid var(--c-line); border-radius: var(--r-1);
  box-shadow: var(--shadow-1);
}
.time-popover input[type="time"] { padding: 3px 4px; border: 1px solid var(--c-line); border-radius: 3px; font: inherit; }
.time-day { display: inline-flex; align-items: center; gap: 1px; font: 11px var(--font-mono); color: var(--c-ink-3); }
.time-day input { width: 28px; padding: 3px 2px; border: 1px solid var(--c-line); border-radius: 3px; font: inherit; text-align: center; }
.time-done { background: var(--c-ink); color: var(--c-bg); border: 0; border-radius: 3px; padding: 4px 8px; font: 11px var(--font-ui); cursor: pointer; }

/* Duration field — display "4h 23m", click to edit. The "auto" badge marks
   values derived from depart/arrive (or from surrounding flights, for layover
   legs) so the user knows where the number came from. */
.dur-field {
  display: inline-flex; align-items: center; gap: 5px;
  font: 600 11.5px/1 var(--font-mono); color: var(--c-ink);
  padding: 2px 6px; border: 1px solid var(--c-line); border-radius: 3px;
  background: var(--c-card-2); cursor: text;
}
.dur-field:hover { border-color: var(--c-accent); background: var(--c-accent-soft); color: var(--c-accent-ink); }
.dur-field.editing {
  font: 600 11.5px/1 var(--font-mono); padding: 2px 6px;
  border: 1px solid var(--c-accent); border-radius: 3px;
  background: var(--c-card); color: var(--c-ink); outline: none; min-width: 120px;
}
.dur-auto-badge {
  font: 600 9px/1 var(--font-ui); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--c-ink-3); background: var(--c-card); border: 1px solid var(--c-line);
  border-radius: 2px; padding: 1px 4px;
}
.dur-field:hover .dur-auto-badge { color: var(--c-accent-ink); border-color: var(--c-accent); }

/* Confirmation field on the leg expand panel — same visual weight as a date /
   time field but a longer text input since record locators / hotel reservation
   numbers can be 6–20 chars. */
.inline-text.ov-conf { font: 600 11.5px/1 var(--font-mono); letter-spacing: 0.04em; min-width: 80px; }
.inline-text.ov-conf.editing { min-width: 160px; }

/* "Booking" row in the flight expand panel — the actions live to the right
   of the label, and the linked badge sits inline next to them. */
.ov-link-actions { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ov-link-btn { font-size: 11px; padding: 3px 8px; }
.ov-link-badge {
  font: 600 9px/1 var(--font-ui); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--c-accent-ink); background: var(--c-accent-soft);
  border: 1px solid var(--c-accent); border-radius: 2px; padding: 2px 5px;
}

/* Confirmation tag in the sidebar meta line — small mono pill so the user can
   spot it among the other meta bits (code, times, duration, price). */
.ov-meta-conf {
  font: 600 10.5px/1 var(--font-mono); letter-spacing: 0.04em;
  color: var(--c-accent-ink); background: var(--c-accent-soft);
  padding: 1px 5px; border-radius: 2px;
}
.ov-booked-dot {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; border-radius: 50%; font-size: 9px; font-weight: 700;
  background: oklch(0.85 0.13 145); color: oklch(0.28 0.13 145);
  flex-shrink: 0;
}
.theme-dark .ov-booked-dot { background: oklch(0.4 0.12 145); color: oklch(0.95 0.05 145); }
.ov-warn-pill {
  font: 600 9.5px/1 var(--font-ui); text-transform: uppercase; letter-spacing: 0.04em;
  color: oklch(0.4 0.12 60); background: oklch(0.92 0.08 80);
  border: 1px solid oklch(0.78 0.1 80); padding: 1px 6px; border-radius: 99px;
  flex-shrink: 0;
}

/* Popover-header confirmation row — sits between the dates sub-line and the
   tab strip. Subtle until the user hovers / focuses the input. */
.pop-conf {
  display: flex; align-items: center; gap: 8px;
  margin-top: 6px; font-size: 11.5px;
}
.pop-conf label { color: var(--c-ink-3); font-weight: 500; }
.inline-text.pop-conf-val { font: 600 12px/1 var(--font-mono); letter-spacing: 0.04em; min-width: 80px; }
.inline-text.pop-conf-val.editing { min-width: 200px; }
.pop-ground-modes {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 6px; margin-top: 10px;
}
.pop-ground .pop-route {
  display: grid; grid-template-columns: minmax(0, 150px) 16px minmax(0, 150px);
  column-gap: 8px; align-items: center; width: fit-content; max-width: 100%;
}
.pop-ground .pop-iata {
  max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 16px;
}
.pop-route-details {
  display: grid; grid-template-columns: minmax(0, 150px) 16px minmax(0, 150px);
  column-gap: 8px; width: fit-content; max-width: 100%; margin-top: 2px;
  color: var(--c-ink-3); font: 11px/1.25 var(--font-ui);
}
.pop-route-detail {
  min-width: 0; overflow: hidden;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
.pop-time-note {
  margin-top: 6px;
  color: var(--c-ink-3);
  font: 11px/1.25 var(--font-ui);
}
.pop-ground-modes button {
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  border: 1px solid var(--c-line); background: var(--c-card);
  color: var(--c-ink-2); border-radius: var(--r-1);
  padding: 6px 4px; font: 600 11px/1 var(--font-ui); cursor: pointer;
}
.pop-ground-modes button:hover { border-color: var(--c-ink-3); color: var(--c-ink); background: var(--c-card-2); }
.pop-ground-modes button.active { border-color: var(--c-accent); color: var(--c-accent-ink); background: var(--c-accent-soft); }
.pop-ground-modes.mode-needed button {
  animation: ground-mode-needed .8s ease-out;
}
@keyframes ground-mode-needed {
  0% {
    border-color: var(--c-line);
    background: var(--c-card);
    color: var(--c-ink-2);
    box-shadow: 0 0 0 0 color-mix(in oklch, var(--c-accent) 0%, transparent);
  }
  35% {
    border-color: var(--c-accent);
    background: var(--c-accent-soft);
    color: var(--c-accent-ink);
    box-shadow: 0 0 0 3px color-mix(in oklch, var(--c-accent) 18%, transparent);
  }
  100% {
    border-color: var(--c-line);
    background: var(--c-card);
    color: var(--c-ink-2);
    box-shadow: 0 0 0 0 color-mix(in oklch, var(--c-accent) 0%, transparent);
  }
}
.pop-ground-fields {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px; margin-top: 10px;
}
.pop-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.pop-field label { color: var(--c-ink-3); font: 600 10.5px/1 var(--font-ui); }
.pop-ground-routebox {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 10px; padding: 9px 10px;
  border: 1px solid var(--c-line); border-radius: var(--r-1);
  background: var(--c-card-2);
}
.pop-ground-routecopy {
  min-width: 0; display: flex; flex-direction: column; gap: 3px;
  color: var(--c-ink-2); font: 11px/1.25 var(--font-ui);
}
.pop-ground-routecopy span:first-child { color: var(--c-ink); font-weight: 600; }
.pop-ground-routeactions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.pop-ground-routeactions .tb-btn { padding: 5px 8px; font-size: 11px; }
.pop-ground-routeactions .tb-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.pop-note-ta {
  margin-top: 8px; width: 100%; min-height: 56px; resize: vertical;
  border: 1px solid var(--c-line); background: var(--c-card-2); color: var(--c-ink);
  border-radius: var(--r-1); padding: 8px 10px;
  font: 12px/1.45 var(--font-ui); outline: none;
}
.pop-note-ta:focus { border-color: var(--c-accent); background: var(--c-card); }
/* RichNote variant used inside FlightPopover / HotelPopover. The
   .note-resize wrapper takes the bordered look so the resize handle sits
   on the visible edge of the field. */
.note-resize.pop-note-ta {
  margin-top: 8px;
  border: 1px solid var(--c-line);
  background: var(--c-card-2);
  padding: 8px 10px;
}
.note-resize.pop-note-ta:focus-within {
  border-color: var(--c-accent);
  background: var(--c-card);
}

/* ── City picker ─────────────────────────────────────────────────────────── */
.city-picker {
  background: var(--c-card); border: 1px solid var(--c-line); border-radius: var(--r-2);
  box-shadow: var(--shadow-1); overflow: hidden;
}
.cp-header { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; border-bottom: 1px solid var(--c-line); font-size: 12px; font-weight: 600; color: var(--c-ink-2); }
.cp-close { background: transparent; border: 0; font-size: 16px; line-height: 1; cursor: pointer; color: var(--c-ink-3); width: 22px; height: 22px; border-radius: 3px; }
.cp-close:hover { color: var(--c-ink); background: var(--c-card-2); }
.cp-input { display: block; width: 100%; padding: 8px 12px; border: 0; outline: none; font: 12.5px/1 var(--font-ui); background: var(--c-card-2); color: var(--c-ink); border-bottom: 1px solid var(--c-line); }
.cp-input:focus { background: var(--c-card); }
.cp-list { max-height: 240px; overflow-y: auto; }
.cp-section { font: 600 10px/1 var(--font-ui); text-transform: uppercase; letter-spacing: 0.06em; color: var(--c-ink-3); padding: 8px 12px 4px; background: var(--c-card-2); border-bottom: 1px solid var(--c-line); }
.cp-item { display: grid; grid-template-columns: 50px 1fr auto; gap: 8px; align-items: center; width: 100%; padding: 8px 12px; background: transparent; border: 0; cursor: pointer; text-align: left; font: inherit; }
.cp-item:hover { background: var(--c-accent-soft); }
.cp-code { font: 600 12px/1 var(--font-mono); letter-spacing: 0.02em; color: var(--c-ink); }
.cp-name { font: 12px/1 var(--font-ui); color: var(--c-ink); display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cp-name-city { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cp-name-sub { font: 10.5px/1.2 var(--font-ui); color: var(--c-ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cp-meta { font: 11px/1 var(--font-ui); color: var(--c-ink-3); }
.cp-empty { padding: 14px 12px; font-size: 12px; color: var(--c-ink-3); display: flex; flex-direction: column; gap: 8px; }
.cp-empty-hint { color: var(--c-ink-3); font-style: italic; }
.cp-footer { padding: 6px 8px; border-top: 1px solid var(--c-line); }
.cp-section-mapbox { color: var(--c-ground-train); }
.cp-loading { padding: 8px 12px; font-size: 11.5px; color: var(--c-ink-3); font-style: italic; }
.cp-error   { padding: 8px 12px; font-size: 11px;  color: oklch(0.45 0.18 25); background: oklch(0.97 0.04 25); border-top: 1px solid var(--c-line); }
.cp-item-mapbox { color: var(--c-ink); }
.cp-item-mapbox.loading { opacity: 0.6; cursor: progress; }
.cp-item-mapbox:disabled { opacity: 0.5; cursor: progress; }
.cp-add-custom { background: transparent; border: 1px dashed var(--c-line); border-radius: var(--r-1); padding: 6px 10px; font: 11px var(--font-ui); color: var(--c-ink-2); cursor: pointer; width: 100%; }
.cp-add-custom:hover { border-color: var(--c-accent); color: var(--c-accent); }

.cp-custom { padding: 10px 12px; border-top: 1px solid var(--c-line); background: var(--c-card-2); }
.cp-custom-h { font-size: 11px; font-weight: 600; color: var(--c-ink-2); margin-bottom: 8px; }
.cp-custom-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-bottom: 8px; }
.cp-custom-grid input { padding: 6px 8px; border: 1px solid var(--c-line); border-radius: var(--r-1); font: 11.5px/1 var(--font-ui); background: var(--c-card); color: var(--c-ink); outline: none; }
.cp-custom-grid input:focus { border-color: var(--c-accent); }
.cp-custom-actions { display: flex; gap: 6px; justify-content: flex-end; }
.cp-custom-actions .tb-btn { padding: 5px 10px; font-size: 11.5px; }
.cp-custom-kinds { display: flex; gap: 4px; margin-bottom: 8px; }
.cp-kind-tab {
  background: transparent; border: 1px solid var(--c-line); border-radius: 99px;
  padding: 3px 10px; font: 10.5px/1 var(--font-ui); color: var(--c-ink-3);
  text-transform: capitalize; cursor: pointer;
}
.cp-kind-tab:hover { border-color: var(--c-accent); color: var(--c-accent-ink); }
.cp-kind-tab.active { background: var(--c-accent); color: var(--c-bg); border-color: var(--c-accent); }

/* Endpoint kind hint on the code badge — small visual cue so the user can
   tell airports vs stations vs custom places at a glance in the picker. */
.cp-code-station { color: var(--c-ground-train); }
.cp-code-place   { color: var(--c-ink-3); font-style: italic; }

/* Ground inserter — mode picker step. Sits in the same shell as CityPicker. */
.ground-mode-picker {
  background: var(--c-card); border: 1px solid var(--c-line); border-radius: var(--r-2);
  box-shadow: var(--shadow-1); overflow: hidden;
}
.ground-mode-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  padding: 10px 12px;
}
.ground-mode-btn {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 12px 8px; border: 1px solid var(--c-line); border-radius: var(--r-1);
  background: var(--c-card-2); color: var(--c-ink); cursor: pointer;
  font: 600 11.5px/1 var(--font-ui);
}
.ground-mode-btn:hover { border-color: var(--c-accent); color: var(--c-accent-ink); background: var(--c-accent-soft); }
.ground-mode-glyph { font-size: 22px; line-height: 1; }
.ground-mode-label { letter-spacing: 0.02em; }

/* ── Overview tab editing ────────────────────────────────────────────────── */
.ov-section-row { display: flex; justify-content: space-between; align-items: center; }
.ov-section-meta { color: var(--c-ink-3); font-weight: 500; text-transform: none; letter-spacing: 0; }

/* Override the original prototype's grid styles on .ov-item — the new layout
   uses .ov-item-main as the grid and .ov-expand as a sibling block below. */
.ov-item { position: relative; display: block; padding: 0; gap: 0; background: transparent; }
.ov-item:hover { background: transparent; }
.ov-item.active { background: transparent; box-shadow: none; }
.ov-item-main { display: grid; grid-template-columns: 56px 1fr; padding: 10px 12px 10px 8px; border-radius: var(--r-1); cursor: pointer; gap: 4px; }
/* Layovers don't open a popover — drop the click affordance so the row reads
   as passive context, not as something you can interact with. */
.ov-item.layover .ov-item-main { cursor: default; }
.ov-item.layover .ov-item-main:hover { background: transparent; }
.ov-item.flight .ov-item-main { background: transparent; }
.ov-item.ground .ov-item-main {
  background: transparent;
  box-shadow: inset 2px 0 0 var(--c-line);
}
.ov-item.ground.mode-train  .ov-item-main { box-shadow: inset 2px 0 0 var(--c-ground-train); }
.ov-item.ground.mode-bus    .ov-item-main { box-shadow: inset 2px 0 0 var(--c-ground-bus); }
.ov-item.ground.mode-car    .ov-item-main { box-shadow: inset 2px 0 0 var(--c-ground-car); }
.ov-item.ground.mode-ferry  .ov-item-main { box-shadow: inset 2px 0 0 var(--c-ground-ferry); }
.ov-ground-glyph { font-size: 14px; line-height: 1; flex-shrink: 0; }
.ov-item.stay .ov-item-main { background: var(--c-card-2); }
.ov-item .ov-item-main:hover { background: var(--c-accent-soft); color: var(--c-accent-ink); }
/* The accent-soft highlight is a light pink in both themes, so force dark
   crimson text for legible contrast on it (don't inherit the theme's ink). */
.ov-item.active .ov-item-main {
  background: var(--c-accent-soft);
  color: var(--c-accent-ink);
  box-shadow: inset 2px 0 0 var(--c-accent);
}
.ov-item.layover .ov-item-main { color: var(--c-ink-3); padding: 6px 8px; }
.ov-item.layover .ov-item-main:hover { background: var(--c-accent-soft); }
.ov-item.broken { color: var(--c-ink-3); padding: 8px; font-style: italic; font-size: 11.5px; }
.ov-item.broken button { font: inherit; color: var(--c-accent); background: none; border: 0; cursor: pointer; text-decoration: underline; }
.ov-meta-empty { color: var(--c-ink-3); font-style: italic; }

/* Mobile-only ... menu button on each leg row. Rendered by LegRow when
   the viewport is narrow; the button toggles a .ov-actions-bar strip
   that appears below the row with the four action pills. */
.ov-menu-btn {
  position: absolute; top: 6px; right: 6px;
  width: 28px; height: 28px;
  border: 1px solid var(--c-line); background: var(--c-card);
  color: var(--c-ink-2); border-radius: 3px; cursor: pointer;
  padding: 0; line-height: 1;
  display: none; align-items: center; justify-content: center;
  z-index: 2;
}
.ov-menu-btn:hover { background: var(--c-card-2); color: var(--c-ink); border-color: var(--c-ink); }
.ov-menu-btn.active { background: var(--c-accent-soft); color: var(--c-accent-ink); border-color: var(--c-accent); }
.ov-actions-bar {
  display: flex; gap: 6px; padding: 8px;
  background: var(--c-card-2); border-top: 1px solid var(--c-line);
  margin: 0 -8px;
}
.ov-actions-bar .ov-ctl {
  flex: 1; height: 36px; font-size: 14px;
}
.ov-controls { position: absolute; right: 6px; top: 6px; display: none; gap: 1px; z-index: 1; }
.ov-item:hover .ov-controls,
.ov-item.active .ov-controls { display: flex; }
/* Always reserve space for the close (×) + edit (✎) buttons so layout doesn't
   shift on hover; on hover/active we expand to make room for ↑↓ as well. */
/* Reserve right gutter at idle (12px keeps the 3n pill / meta line off the
   row's right edge); expand to 88px on hover/active to make room for the
   move/edit/remove controls without layout shift. */
.ov-item-main { padding-right: 12px; transition: padding-right .12s; }
.ov-item:hover .ov-item-main,
.ov-item.active .ov-item-main { padding-right: 88px; }
.ov-ctl { width: 20px; height: 20px; border: 1px solid var(--c-line); background: var(--c-card); color: var(--c-ink-3); border-radius: 3px; cursor: pointer; padding: 0; line-height: 1; font: 11px var(--font-mono); display: inline-flex; align-items: center; justify-content: center; }
.ov-ctl:hover:not(:disabled) { background: var(--c-card-2); color: var(--c-ink); border-color: var(--c-ink); }
.ov-ctl:disabled { opacity: 0.3; cursor: not-allowed; }
.ov-ctl.danger:hover:not(:disabled) { background: var(--c-accent-soft); color: var(--c-accent-ink); border-color: var(--c-accent); }
/* The inline airport picker (opens when you tap a flight row's IATA code).
   Spans the row's full width — earlier the rule had a 64px left indent to
   align with the row's content column (after the 56px date column + 8px
   gap), which left the picker only ~240px wide in a 340px sidebar and
   truncated airport names + the search placeholder. Full-width gives the
   picker the same breathing room CityPicker gets when used in the Inserter
   flow. */
.ov-route-picker {
  padding: 0 0 10px;
}
.ov-route-picker .city-picker {
  width: 100%;
}

/* Bleed past the row's gutter (margin: 0 -8px), then re-add a comfortable
   inner gutter so labels (CHECK-IN, NIGHTS, …) and value controls don't sit
   flush against the panel edges. */
.ov-expand { padding: 10px 14px 12px; background: var(--c-card-2); border-bottom: 1px solid var(--c-line); display: flex; flex-direction: column; gap: 6px; margin: 0 -8px; }
.ov-expand-row { display: grid; grid-template-columns: 80px 1fr; align-items: center; gap: 8px; font-size: 11.5px; }
.ov-expand-row label { color: var(--c-ink-3); font-weight: 500; text-transform: uppercase; font-size: 10px; letter-spacing: 0.04em; }

/* Inserter at rest is a near-invisible 1-px line; hovering reveals action
   pills. Reduces visual clutter dramatically when there are 10+ legs. */
.ov-inserter {
  position: relative; height: 10px; display: flex; align-items: center;
  gap: 6px; padding: 0 4px; transition: height .15s ease;
}
.ov-inserter-line { flex: 1; height: 1px; background: var(--c-line); opacity: 0.4; transition: opacity .12s; }
.ov-inserter-actions { display: flex; gap: 4px; opacity: 0; transition: opacity .12s; pointer-events: none; }
.ov-inserter:hover { height: 24px; }
.ov-inserter:hover .ov-inserter-line    { opacity: 0; }
.ov-inserter:hover .ov-inserter-actions { opacity: 1; pointer-events: auto; }
.ov-inserter.open  { height: auto; padding: 8px 4px; flex-direction: column; align-items: stretch; }
.ov-inserter.open  .ov-inserter-line    { display: none; }
.ov-inserter.open  .ov-inserter-actions { opacity: 1; pointer-events: auto; }
/* Sparse layout (empty / one-leg trip) — show buttons inline so new users
   don't have to discover the hover-reveal affordance. */
.ov-inserter.sparse { height: auto; padding: 8px 4px; justify-content: center; }
.ov-inserter-actions.visible { opacity: 1; pointer-events: auto; }
.ov-add-btn {
  background: var(--c-card); border: 1px solid var(--c-line); border-radius: 99px;
  padding: 3px 9px; font: 10px/1.4 var(--font-ui); font-weight: 500;
  color: var(--c-ink-2); cursor: pointer; white-space: nowrap;
}
.ov-add-btn:hover  { background: var(--c-accent-soft); color: var(--c-accent-ink); border-color: var(--c-accent); }
.ov-add-btn:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }
.ov-add-btn-cancel { padding: 3px 8px; }
/* Collapsed-pill toggle for the mobile inserter — hidden on desktop where
   the existing hairline + hover reveal is already discoverable. The mobile
   media block below flips display:inline-flex on small screens. */
.ov-inserter-toggle {
  display: none;
  background: var(--c-card); border: 1px solid var(--c-line); border-radius: 99px;
  color: var(--c-ink-2); cursor: pointer;
  font: 600 14px/1 var(--font-mono);
  width: 28px; height: 28px; padding: 0;
  align-items: center; justify-content: center;
}
.ov-inserter-toggle:hover {
  background: var(--c-accent-soft); color: var(--c-accent-ink); border-color: var(--c-accent);
}
.ov-inserter-toggle:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }

.ov-empty { padding: 16px 12px; text-align: center; color: var(--c-ink-3); font-size: 12px; background: var(--c-card-2); border: 1px dashed var(--c-line); border-radius: var(--r-2); }

/* Bordered "forward booking confirmations to add@..." tip. Sits between the
   meta row and the Itinerary section header (moved from below the header
   so it reads in the same scan-zone as the Travelers stepper). The address
   is a click-to-copy button styled with a dashed under-rule to signal
   affordance without looking like a real link. */
.ov-email-tip {
  padding: 8px 10px; margin: 0 2px 8px;
  font: 12px/1.45 var(--font-ui); color: var(--c-ink-3);
  background: var(--c-card-2); border: 1px solid var(--c-line);
  border-radius: var(--r-1);
}
.ov-email-tip-addr {
  background: transparent; border: 0; padding: 0;
  font: 12px/1 var(--font-mono); color: var(--c-ink);
  cursor: pointer; border-bottom: 1px dashed var(--c-ink-3);
}
.ov-email-tip-addr:hover { color: var(--c-accent); border-bottom-color: var(--c-accent); }

.cities-list { display: flex; flex-direction: column; gap: 2px; }
.city-row { display: grid; grid-template-columns: 44px 1fr auto auto; align-items: center; gap: 8px; padding: 6px 8px; border-radius: var(--r-1); }
.city-row:hover { background: var(--c-card-2); }
.city-code { font: 600 11px/1 var(--font-mono); color: var(--c-ink); }
.city-name { font: 12px/1 var(--font-ui); color: var(--c-ink); }
.city-country { font: 11px/1 var(--font-ui); color: var(--c-ink-3); }
.city-remove { width: 20px; height: 20px; border: 0; background: transparent; color: var(--c-ink-3); cursor: pointer; border-radius: 3px; }
.city-remove:hover { background: var(--c-accent-soft); color: var(--c-accent-ink); }
.city-add { margin-top: 8px; padding: 8px; border: 1px dashed var(--c-line); background: transparent; color: var(--c-ink-3); border-radius: var(--r-1); cursor: pointer; font: inherit; }
.city-add:hover { border-color: var(--c-accent); color: var(--c-accent); }
.cities-picker-shell { margin-top: 8px; }

/* ── Activities tab editing ──────────────────────────────────────────────── */
.act-meta-field { font: inherit; }
.act-status-btn { background: var(--c-card-2); color: var(--c-ink-3); border: 1px solid var(--c-line); padding: 1px 6px; border-radius: 3px; font: 10px/1.4 var(--font-ui); text-transform: uppercase; letter-spacing: 0.04em; cursor: pointer; }
.act-status-btn:hover { background: var(--c-card); color: var(--c-ink); }
.act-status-btn.booked { background: var(--c-accent-soft); color: var(--c-accent-ink); border-color: var(--c-accent); }
.act-remove { background: transparent; border: 0; color: var(--c-ink-3); cursor: pointer; padding: 0 4px; font-size: 14px; line-height: 1; }
.act-remove:hover { color: var(--c-accent); }
.act-note-toggle { background: transparent; border: 0; color: var(--c-accent); cursor: pointer; padding: 0 4px; font: inherit; font-size: 11px; text-decoration: underline; margin-left: auto; }
.act-note-toggle:hover { opacity: 0.8; }
/* RichNote variant used inline in an ActivityRow — bordered card style. */
.note-resize.act-note {
  margin-top: 6px;
  padding: 6px 8px;
  border: 1px solid var(--c-line);
  background: var(--c-card-2);
  min-height: 44px;
}

.act-form { padding: 10px; background: var(--c-card-2); border: 1px solid var(--c-line); border-radius: var(--r-1); display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.act-form input { padding: 6px 8px; border: 1px solid var(--c-line); border-radius: var(--r-1); background: var(--c-card); color: var(--c-ink); font: 12px var(--font-ui); outline: none; }
.act-form input:focus { border-color: var(--c-accent); }
.act-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.act-form-checkbox { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--c-ink-2); }
.act-form-actions { display: flex; gap: 6px; justify-content: flex-end; margin-top: 4px; }
.act-form-actions .tb-btn { padding: 5px 12px; font-size: 11.5px; }

/* ── Budget tab editing ──────────────────────────────────────────────────── */
.bud-tag { font: 9px/1.4 var(--font-mono); padding: 1px 5px; border-radius: 3px; background: var(--c-card-2); color: var(--c-ink-3); margin-left: 6px; text-transform: uppercase; letter-spacing: 0.04em; }
.bud-val-edit { display: inline-flex; align-items: center; font: 600 12px var(--font-mono); }
.bud-val-edit input { width: 70px; padding: 2px 4px; border: 1px solid var(--c-line); border-radius: 3px; font: inherit; color: var(--c-ink); background: var(--c-card-2); text-align: right; outline: none; -moz-appearance: textfield; }
.bud-val-edit input::-webkit-inner-spin-button, .bud-val-edit input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.bud-val-edit input:focus { border-color: var(--c-accent); background: var(--c-card); }

/* ── Empty state ─────────────────────────────────────────────────────────── */
/* Overlay on top of the map so the empty state shows tiles in the
   background instead of a flat grey panel. The container is transparent and
   passes pointer events through to the map; the centred card captures clicks
   for its own controls. */
.empty-state {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: transparent;
  pointer-events: none;
  z-index: 1050;  /* above the map overlay (400) and Leaflet controls (800), below the popover (1100) */
}
.es-card {
  position: relative;
  background: var(--c-card); border: 1px solid var(--c-line);
  border-radius: var(--r-3); box-shadow: var(--shadow-2);
  padding: 24px 28px; width: 460px; max-width: calc(100vw - 60px);
  text-align: center;
  pointer-events: auto;
  /* Slight backdrop blur so the card feels like it's floating over the map
     rather than sitting flush on it. Falls back gracefully on browsers that
     don't support backdrop-filter. */
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  backdrop-filter: blur(8px) saturate(140%);
  background: color-mix(in oklch, var(--c-card) 86%, transparent);
}
.es-close { position: absolute; top: 8px; right: 10px; }
.es-h { font: 600 18px/1 var(--font-ui); letter-spacing: -0.02em; color: var(--c-ink); margin-bottom: 8px; }
.es-sub { color: var(--c-ink-2); font-size: 13px; margin-bottom: 18px; }
.es-actions { display: flex; flex-direction: column; gap: 10px; align-items: stretch; }
.es-hint { color: var(--c-ink-3); font-size: 11.5px; text-align: center; }
/* "or" divider between the primary "+ Add your first flight" CTA and the
   paste-link box. */
.es-divider {
  display: flex; align-items: center; gap: 8px;
  color: var(--c-ink-3); font-size: 11px; text-transform: uppercase;
  letter-spacing: 0.06em; margin: 4px 0;
}
.es-divider::before,
.es-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--c-line);
}
.es-paste { display: flex; flex-direction: column; gap: 6px; text-align: left; }
.es-paste-label {
  font: 600 10.5px/1 var(--font-mono); color: var(--c-ink-3);
  text-transform: uppercase; letter-spacing: 0.04em;
}
.es-paste-row { display: flex; gap: 6px; }
.es-paste-input {
  flex: 1; min-width: 0;
  padding: 7px 9px; border: 1px solid var(--c-line); border-radius: var(--r-1);
  font: 12px/1.2 var(--font-ui); color: var(--c-ink); background: var(--c-card);
  outline: none;
}
.es-paste-input:focus { border-color: var(--c-accent); outline: 2px solid var(--c-accent); outline-offset: 1px; }
.es-paste-input:disabled { opacity: 0.6; }
.es-paste-error {
  font-size: 11.5px; color: var(--c-accent-ink); background: var(--c-accent-soft);
  border: 1px solid var(--c-accent); padding: 6px 8px; border-radius: var(--r-1);
}

/* ── Accessibility & focus ───────────────────────────────────────────────── */
/* Use focus-visible so focus rings only show for keyboard nav, not mouse. */
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[role="button"]:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 1px;
  border-radius: 3px;
}
/* Visually-hidden text for screen readers */
.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;
}
/* Reduce motion: respect user preference */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ── Account menu (TopBar) ───────────────────────────────────────────────────
   AccountMenu lives inside .tb-right alongside the existing trip menu. Each
   menu owns its own positioning context so the two popovers don't collide.
   The .acct-pop overrides the base .popover transform/anchor (which assumes
   an absolutely-positioned map anchor) so the popover drops directly below
   the button, right-aligned to the topbar edge. */
.tb-right { display: flex; align-items: center; gap: 8px; position: relative; }
.acct-wrap { position: relative; }
.tb-trip-menu { position: relative; }

.acct-pop {
  width: 320px;
  right: 0; left: auto;
  top: calc(100% + 6px);
  transform: none;
  opacity: 1;
  /* Base .popover's max-height + max-width are both sized against its parent
     (.map-wrap), assuming the wide map area. Inside .acct-wrap (just the
     account button) those % resolve to nearly nothing, collapsing the
     popover to a few px tall and ~50px wide. Override both with sensible
     viewport-anchored caps that fit all three stages (email form, OTP
     form, signed-in panel) without scrolling. */
  max-height: min(70vh, 520px);
  max-width: calc(100vw - 24px);
  overflow: hidden;
}
.acct-pop .pop-h { padding: 12px 16px 8px; }
.acct-pop .pop-form { padding: 10px 16px 14px; }
.acct-email { font: 600 13px/1.2 var(--font-ui); color: var(--c-ink); }
.acct-sync { font: 11px/1.2 var(--font-mono); color: var(--c-ink-3); margin-top: 4px; }
.acct-sub { font: 11.5px/1.4 var(--font-ui); color: var(--c-ink-2); margin-top: 4px; }
.acct-google {
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.acct-divider {
  display: flex; align-items: center; gap: 8px;
  color: var(--c-ink-3); font-size: 11px; margin: 2px 0;
}
.acct-divider::before, .acct-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--c-line);
}

/* ── Guest banner ───────────────────────────────────────────────────────────
   Sits between the TopBar and the main pane. Uses accent-soft background so
   it reads as informational, not alarming, and matches the existing
   .pop-error palette. The banner is dismissed for 7 days at a time via
   localStorage. */
.guest-banner {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 8px 16px;
  background: var(--c-accent-soft);
  color: var(--c-accent-ink);
  border-bottom: 1px solid var(--c-accent);
  font: 12px/1.4 var(--font-ui);
}
.gb-text { flex: 1 1 auto; min-width: 0; }
.gb-actions { display: flex; gap: 8px; align-items: center; flex: 0 0 auto; }
.gb-btn { padding: 5px 10px; font-size: 11.5px; }
.gb-x {
  width: 22px; height: 22px;
  border: 0; background: transparent;
  color: var(--c-accent-ink);
  font-size: 18px; line-height: 1;
  cursor: pointer; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.gb-x:hover { background: rgba(0, 0, 0, 0.06); }

/* ── ShareViewerBanner ───────────────────────────────────────────────────────
   Shown when the page boots from /t/<token>. Same shape as the GuestBanner
   so the layout space below the topbar is consistent. The "forked" variant
   appears for ~4s after the viewer makes their first edit, replacing the
   "you're viewing a shared trip" copy with a confirmation. */
.share-banner {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 8px 16px;
  background: var(--c-accent-soft);
  color: var(--c-accent-ink);
  border-bottom: 1px solid var(--c-accent);
  font: 12px/1.4 var(--font-ui);
}
.share-banner .sb-text { flex: 1 1 auto; min-width: 0; }
.share-banner .sb-x {
  width: 22px; height: 22px;
  border: 0; background: transparent;
  color: var(--c-accent-ink);
  font-size: 18px; line-height: 1;
  cursor: pointer; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.share-banner .sb-x:hover { background: rgba(0, 0, 0, 0.06); }
.share-banner.forked {
  background: var(--c-card-2);
  color: var(--c-ink);
  border-bottom-color: var(--c-line);
}

/* The traveler stepper relocates to the Overview tab's "Itinerary" header on
   mobile (.ov-travelers-mobile is rendered there but hidden on desktop). */
.ov-travelers-mobile { display: none; }

/* ── Touch devices ───────────────────────────────────────────────────────── */
/* Hover tooltips on map chips (FlightChip / HotelTag / GroundChip) can't be
   triggered without a mouse, and at the corners of the viewport they clip
   off-screen anyway. The chip's onClick already opens the full DetailPopover
   with the same information, so we suppress these HTML tooltips (portaled
   into .trippy-tooltip-layer) on touch devices entirely. */
@media (hover: none) {
  .fc-tooltip,
  .ht-tooltip,
  .gc-tooltip { display: none; }
}

/* ── Mobile ──────────────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  /* Disable browser pinch-zoom on the page; .map-leaflet still pinches.
     Belt-and-suspenders alongside the JS gesture handler in app.jsx. */
  body { touch-action: pan-x pan-y; }
  /* Lift the timeline (and its collapsed-state pill) above iOS Safari's
     bottom URL bar / home indicator. */
  .timeline { bottom: max(16px, env(safe-area-inset-bottom)); }
  .tl-pill { bottom: max(16px, env(safe-area-inset-bottom)); }
  .topbar { padding: 8px 10px; gap: 8px; padding-top: max(8px, env(safe-area-inset-top)); }
  .tb-left { gap: 6px; }
  .tb-btn { white-space: nowrap; }
  /* Trip name + dates move out of the topbar on mobile (now in the
     Overview tab's .ov-trip-meta row). The logo, ☰, undo, redo, account,
     and Trip menu buttons all stay visible. */
  .topbar .tb-trip, .topbar .tb-dates { display: none; }
  /* Logo shrinks slightly on narrow viewports to leave room for icon
     buttons + the right-side account/Trip menu. */
  .tb-logo { height: 20px; }
  /* Sidebar overlays the map on mobile rather than pushing it. The map
     itself stays full-width (avoiding the squeezed-and-clipped state seen
     when sidebar takes 340px of a ~390px viewport), and a tap on the map
     auto-dismisses the overlay (wired in map-view.jsx). */
  .main { position: relative; }
  .sidebar {
    position: absolute; top: 0; left: 0; bottom: 0;
    width: min(85vw, 340px); max-width: 85vw;
    z-index: 900;
    box-shadow: 2px 0 12px rgba(0, 0, 0, 0.18);
  }
  /* Mobile: trip name + dates show in the .ov-trip-meta row above the
     Itinerary header (they're hidden by default — see desktop rules).
     Specificity 0,2,0 to outweigh the desktop hide rule. */
  .ov-trip-meta .ov-trip-name { display: inline-block; }
  .ov-trip-meta .ov-trip-dates { display: inline-flex; }

  /* Inserter on mobile: hide the hairline reveal pattern, show a single
     "+" pill that expands to the four kind buttons. The :hover height
     change at the desktop rule still fires but is overridden here. */
  .ov-inserter:not(.sparse):not(.open):not(.expanded) {
    height: auto; padding: 4px 4px;
    flex-direction: row; align-items: center; justify-content: center;
  }
  .ov-inserter:not(.sparse):not(.open):not(.expanded) .ov-inserter-line {
    display: none;
  }
  .ov-inserter:not(.sparse):not(.open):not(.expanded) .ov-inserter-actions {
    display: none;
  }
  .ov-inserter:not(.sparse):not(.open) .ov-inserter-toggle {
    display: inline-flex;
  }
  /* Expanded shows the four kind pills inline with a cancel button. */
  .ov-inserter.expanded {
    height: auto; padding: 6px 4px;
    flex-direction: column; align-items: stretch;
  }
  .ov-inserter.expanded .ov-inserter-toggle { display: none; }
  .ov-inserter.expanded .ov-inserter-line { display: none; }
  .ov-inserter.expanded .ov-inserter-actions {
    flex-wrap: wrap; justify-content: center;
  }
  .ov-add-btn { padding: 6px 12px; font-size: 11.5px; }

  /* LegRowControls on mobile: hide the always-visible cluster and surface
     a single overflow (...) button instead. The button toggles an action
     row that renders below the leg (see .ov-actions-bar). */
  .ov-controls { display: none; }
  .ov-item:hover .ov-controls,
  .ov-item.active .ov-controls { display: none; }
  .ov-menu-btn { display: inline-flex; }
  /* Reserve room for just the 28px ... button + 8px gutter. */
  .ov-item-main { padding-right: 44px; }
  .ov-item:hover .ov-item-main,
  .ov-item.active .ov-item-main { padding-right: 44px; }

  /* iOS Safari auto-zooms the page when a focused input has font-size < 16px,
     and that zoom doesn't return to 1.0 on blur. Bump form inputs to 16px
     on mobile so the auto-zoom never fires. Targets the form controls in the
     DetailPopover, the city picker search, the notes textarea, and the
     EmptyState paste-link input — every text/number/email/date control in
     the app. Buttons and labels are excluded so visual density elsewhere
     (mono price chips, mono date fields) isn't disrupted. */
  .pop-form-row input,
  .pop-form-row select,
  .es-paste-input,
  .cp-input,
  .note-ta,
  input[type="email"],
  input[type="text"],
  input[type="number"],
  input[type="date"],
  input[type="time"],
  input[type="search"],
  input[type="tel"],
  input[type="url"],
  textarea,
  select {
    font-size: 16px;
  }

  /* Sign-in popover: bypass the right:0 anchoring (which lands the popover
     anywhere from mid-right to off-screen depending on .acct-wrap's flow
     position) and stretch a fixed sheet across the viewport with a small
     gutter. The signed-in state uses the same layout for consistency. */
  .acct-pop {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 50px);
    left: 12px; right: 12px; bottom: auto;
    width: auto; max-width: none;
  }

  /* Icon-only Sign-in button (guest state on mobile). Same height as the
     other tb-btn pills so the topbar's vertical rhythm doesn't shift. */
  .acct-icon-only {
    width: 32px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
  }

  /* Tighter title cap so even long titles ellipsize before colliding with
     the right-side buttons. Replaces the 160px declared earlier. */
  .inline-text.tb-trip { max-width: 130px; }

  /* Reduce horizontal weight of .tb-right so it doesn't crowd the title. */
  .tb-right { gap: 4px; }
  .tb-btn { padding: 5px 8px; font-size: 11.5px; }
  .pop-ground-fields { grid-template-columns: 1fr; }
  .pop-ground-routebox { align-items: stretch; flex-direction: column; }
  .pop-ground-routeactions { justify-content: flex-start; }
  .pop-ground .pop-iata { max-width: 118px; }
  .pop-ground .pop-route,
  .pop-route-details { grid-template-columns: minmax(0, 118px) 16px minmax(0, 118px); }

  /* Trip switcher trigger on mobile — tighter title cap so the title
     ellipsizes before colliding with the help/account icons. */
  .tb-trip-switcher { max-width: 140px; }

  /* Switcher popover on mobile — pin it to a 12px gutter and let it grow up
     to most of the viewport. Matches the .acct-pop treatment above. */
  .ts-popover {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 50px);
    left: 12px; right: 12px; bottom: auto;
    width: auto; max-width: none;
    max-height: 70vh;
  }

  /* Manage Trips modal on mobile — bottom sheet that takes ~90% of the
     viewport so a thin strip of dim backdrop shows above (gives the drag
     handle a reason to exist, and reads as a sheet rather than a full-screen
     takeover). The dim backdrop also reassures the user the page is still
     "there" behind it.
     z-index bump: timeline sits at 1000 and the Leaflet attribution + zoom
     controls live in the leaflet-control-container (z-index 800). Bumping
     to 2000 puts the sheet unambiguously above all map chrome — the earlier
     1200 was already above those numerically but Leaflet sometimes promotes
     its controls into their own stacking context on iOS Safari, leaving the
     attribution bar painting through. 2000 keeps us safely clear. */
  .mt-backdrop {
    padding: 0;
    align-items: flex-end; justify-content: stretch;
    background: rgba(0, 0, 0, 0.42);
    z-index: 2000;
  }
  .mt-modal {
    width: 100%;
    height: 90vh; height: 90dvh;
    max-width: none; max-height: none;
    /* Rounded only at top — bottom meets the viewport edge. */
    border-radius: 16px 16px 0 0;
    border: 0; border-top: 1px solid var(--c-line);
    /* Safe-area handled at the footer; padding-top reserved for the drag
       handle's breathing room (.mt-handle's own margin tops it off). */
  }
  /* Kebab sheet + share-modal-on-modal both bump to match the new mobile
     ladder (2000 base → 2010 kebab → 2020 share). Without these, sharing
     a row or opening the kebab on mobile would render the sub-layer
     underneath the manage sheet. */
  .mt-kebab-sheet { z-index: 2010; }
  .share-modal-backdrop { z-index: 2020; }
  /* Slightly more prominent handle so it reads as the draggable affordance
     it actually is (pointer handlers live on .mt-handle-grip). The grip
     wrapper provides vertical spacing — no margin here. */
  .mt-handle {
    width: 42px; height: 4px;
    background: var(--c-ink-3); opacity: 0.4;
  }
  /* Hide the desktop inline action cluster; reveal the kebab. */
  .mt-row-actions { display: none; }
  .mt-row-kebab { display: inline-flex; }
  /* Bigger tap targets — 44px minimum vertical via 14px padding × 2 + ~17px
     content. */
  .mt-row { padding: 14px 16px; }
  /* Swap the desktop footer for the mobile action bar. The text footer is
     redundant on mobile (the modal IS the screen, the sync hint can wait).
     The .mt-mobile-sample row sits just above the action bar as a quiet
     entry to the demo. */
  .mt-footer { display: none; }
  .mt-mobile-sample { display: block; }
  .mt-footer-actions { display: flex; }

  /* ── DetailPopover at mobile width — positioning override + polish ──
     Desktop anchors the sheet at top-left (20px in) so the right side of
     the map stays clear for the leg's anchor. Mobile keeps the original
     full-width-minus-12 sheet — there's no "side" to reserve on a 390px
     viewport, so the sheet spans top edge-to-edge. */

  /* Hide the Leaflet zoom while ANY popover is open on mobile — the
     pinch-zoom gesture replaces it on touch, and the controls compete
     with the sheet's top corners. document.body gets the .popover-open
     class from a useEffect in app.jsx keyed on popover state. */
  body.popover-open .leaflet-control-zoom { display: none; }

  .popover {
    left: 12px; right: 12px;
    top: 12px;
    width: auto; max-width: none;
    /* Square top corners + rounded bottom corners per mockup. */
    border-radius: 0 0 16px 16px;
    /* Tighter timeline reservation on mobile (timeline is narrower).
       Percentages relative to .map-wrap, which already sits below the
       topbar — no need to subtract topbar height here. */
    max-height: calc(100% - 12px
        - 124px
        - env(safe-area-inset-bottom, 0px)
        - 12px);
    /* Drop the heavy box-shadow on the mobile sheet — the card sits at the
       top of the viewport with no negative space above to drop a shadow
       into, and the soft top border alone reads cleaner. */
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.10);
    /* Padding-bottom reserves room for the bottom-anchored drag handle so
       it doesn't sit on top of the card's last interactive row. */
    padding-bottom: 0;
  }

  /* Airier header — original desktop padding felt cramped vs. the (now
     bigger) close button. */
  .popover .pop-h {
    padding: 18px 18px 12px;
  }
  /* Bigger close button so a thumb actually lands on it. Pull farther
     into the corner so it clears the .pop-iata headline. */
  .popover .pop-close {
    top: 12px; right: 12px;
    width: 32px; height: 32px;
    font-size: 22px;
  }
  /* Anchor info should read first — bump IATA codes by 2px on mobile. */
  .popover .pop-iata { font: 700 20px/1 var(--font-mono); }
  .popover .pop-route { gap: 10px; }
  .popover .pop-arrow { font-size: 18px; }

  /* Form labels — 10.5px reads as visual noise; 11.5px stays small but
     legible at touch distance. */
  .popover .pop-form-row > label,
  .popover .pop-form-row.split > div > label {
    font-size: 11.5px;
  }

  /* Stack multi-column form rows on mobile. The desktop split layout
     packs 3-4 fields per row, which crams date/time/select inputs (each
     needs ~120px at 16px font + native picker icon) into <110px columns
     and truncates their values ("02/06/:", "Airbus A38", "Econo>"). The
     popover is internally scrollable so vertical growth is cheap; better
     to make every field full-width and readable than to preserve a
     density that hides data. */
  .popover .pop-form-row.split {
    flex-direction: column;
    gap: 10px;
  }
  .popover .pop-form-row.split > div.grow {
    flex: 1 1 auto;
  }

  /* Tabs: enable horizontal scroll for forward-compatibility (5th tab
     would crowd at the desktop's flex-equally layout), and give each
     tab more room. */
  .popover .pop-tabs {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* Hide the scrollbar — chrome/firefox lay out a slim bar that
       fights the tab underline. Users can swipe instead. */
    scrollbar-width: none;
  }
  .popover .pop-tabs::-webkit-scrollbar { display: none; }
  .popover .pop-tabs button,
  .popover .pop-tabs.pop-tabs-4 button {
    padding: 10px 14px;
    font-size: 12.5px;
    flex: 0 0 auto;
  }
}
