/* JetAmigo. One stylesheet, no framework.
   Warm cream on a red accent -- a globe-and-flight-paths mark, not the
   default SaaS blue. Amber and a darker brick red are kept for meaning
   (warnings, errors) rather than decoration. --good is the one deliberate
   exception to "red is the brand, not a signal" -- a price drop is good
   news and reading it in the same red as an error is backwards. */

:root {
  /* Which colours the browser's own parts use (scrollbars, date pickers).
     The dark block below says dark; see there for what switches it. */
  color-scheme: light;

  --bg:          #fffdfa;
  --surface:     #fff6ea;
  --surface-2:   #f5e6d0;
  --ink:         #241c12;
  --ink-2:       #6b5a45;
  --ink-3:       #9c8a70;
  --line:        #f2decb;
  --line-strong: #c99a63;
  --accent:      #d81f26;
  --accent-soft: #fbe4e2;
  --accent-ink:  #ffffff;
  --warn:        #9a5b06;
  --warn-soft:   #f9efdf;
  --risk:        #8a2419;
  --risk-soft:   #f6e2de;
  --good:        #1f7d43;
  --good-soft:   #e3f1e6;

  --display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --body:    "Source Serif 4", Georgia, serif;
  --mono:    "JetBrains Mono", ui-monospace, Consolas, monospace;

  /* The globe disc. Cream in light mode (matches --surface, unchanged);
     forced to pure white only in dark mode, below -- see the request that
     added this: light was fine as it was. */
  --globe-fill: var(--surface);

  /* The big globe's meridian/latitude grid lines. Light mode keeps the
     original --line tan, unchanged; dark mode overrides this, below, to
     match the continent stroke color instead of --line's normal dark
     value, which was too faint against the dark background. */
  --globe-line: var(--line);
}

/* Dark. Switched on for the whole site by data-theme="dark" on <html>, which
   base.html, 404.html and 500.html write from SITE_THEME (config/settings.py):
   dark for everyone since 2026-09-26, with the light colours above kept and
   one setting away. It used to follow each visitor's device through a media
   query, which a site cannot overrule; an attribute it can.
   Every page stylesheet keys its dark rules on the same attribute, inside
   :where() so they keep the specificity the media query gave them. */
:root:where([data-theme="dark"]) {
  color-scheme: dark;
  --bg: #1c1712; --surface: #241d16; --surface-2: #2c231a;
  --ink: #f3ebe0; --ink-2: #c7b8a4; --ink-3: #8f8070;
  --line: #3a2f22; --line-strong: #55442f;
  --accent: #ef4a42; --accent-soft: #3a1f1c; --accent-ink: #1c1712;
  --warn: #e0a352; --warn-soft: #35291a;
  --risk: #e8836e; --risk-soft: #38211c;
  --good: #5fcf82; --good-soft: #1b3324;
  --globe-fill: #ffffff;
  --globe-line: #b89a72;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.6 var(--body);
  -webkit-font-smoothing: antialiased;
}

/* ------------------------------------------------------------ a11y */
.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip {
  position: absolute; left: 12px; top: -60px; z-index: 40;
  padding: 10px 16px; background: var(--accent); color: var(--accent-ink);
  font-family: var(--display); font-size: 14px; text-decoration: none;
  border-radius: 0 0 4px 4px; transition: top 0.12s;
}
.skip:focus { top: 0; }

/* ------------------------------------------------------------ chrome */
.topbar {
  position: relative;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 12px 28px;
  border-bottom: 1px solid var(--line); background: var(--surface);
}
.brand {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--display); font-weight: 700; font-size: 19px;
  letter-spacing: -0.02em; color: var(--ink); text-decoration: none;
  /* One line, always. Left to wrap it stacked the mark above the word and
     made the bar twice as tall on a phone. */
  flex: none; white-space: nowrap;
}
.brand-name span { color: var(--accent); }
.globe-mark { width: 32px; height: 32px; display: block; flex: none; }

@keyframes arc-fly { from { stroke-dashoffset: 100; } to { stroke-dashoffset: -100; } }
/* For the dark bands' background routes. arc-cross flies one dash from the
   start of a pathLength="100" route to its end, with a gap longer than the
   route (stroke-dasharray: 12 188) so it never wraps round and nothing sits
   still at either end; arc-march moves the dotted route itself, two
   periods of its stroke-dasharray: 4 10. */
@keyframes arc-cross { from { stroke-dashoffset: 12; } to { stroke-dashoffset: -100; } }
@keyframes arc-march { to { stroke-dashoffset: -28; } }
@keyframes dots-drift { to { background-position: 24px 24px; } }

.topbar nav { display: flex; align-items: center; gap: 20px; }
.topbar nav a, .link {
  font-family: var(--display); font-size: 14px; font-weight: 500;
  color: var(--ink-2); text-decoration: none;
}
.topbar nav a:hover, .link:hover { color: var(--accent); }
.inline { display: inline; margin: 0; }
.link { background: none; border: 0; padding: 0; cursor: pointer; }
.link.danger { color: var(--risk); }

/* The menu button exists only where the row does not fit. Below, at the
   breakpoint, the nav becomes a panel under the bar. */
.menu-btn { display: none; }

@media (max-width: 719px) {
  /* On a phone the bar is the brand and one button. Trips, Add a trip,
     Settings and Log out do not fit beside them and were wrapping into the
     page, so all four live in the menu. */
  /* No tab key on a touch screen, so the skip link has nothing to skip for
     and is one more thing in the way. It stays on desktop, where keyboard
     users are the ones who need it. */
  .skip { display: none; }

  .topbar { padding: 10px 14px; }
  .has-js .topbar { flex-wrap: nowrap; }

  /* No JavaScript: nothing can open a menu, so the links have to stay on the
     page. Given a full row of their own rather than crushed beside the brand,
     which is what wrapped the mark above the word. */
  html:not(.has-js) .topbar { flex-wrap: wrap; }
  html:not(.has-js) .topbar nav {
    width: 100%; flex-wrap: wrap; gap: 8px 16px; padding-top: 6px;
    border-top: 1px solid var(--line); margin-top: 4px;
  }

  .has-js .menu-btn {
    display: flex; align-items: center; justify-content: center;
    flex: none; width: 42px; height: 42px; padding: 0; cursor: pointer;
    background: none; border: 1px solid var(--line-strong); border-radius: 6px;
  }
  .bars { display: grid; gap: 4px; }
  .bars span {
    display: block; width: 18px; height: 2px; border-radius: 2px;
    background: var(--ink-2);
  }
  .topbar[data-open] .menu-btn { border-color: var(--accent); background: var(--accent-soft); }

  /* Without JavaScript nothing can open it, so it stays a plain wrapped row. */
  .has-js .topbar nav {
    display: none;
    position: absolute; right: 12px; top: calc(100% + 6px); z-index: 30;
    flex-direction: column; align-items: stretch; gap: 0;
    min-width: 208px; padding: 6px;
    background: var(--surface); border: 1px solid var(--line-strong);
    border-radius: 8px; box-shadow: 0 14px 34px rgba(0, 0, 0, 0.16);
  }
  .has-js .topbar[data-open] nav { display: flex; }
  .topbar nav a, .topbar nav .link {
    padding: 11px 12px; border-radius: 5px; font-size: 15px; text-align: left;
  }
  .topbar nav a:hover, .topbar nav .link:hover { background: var(--surface-2); }
  .topbar nav .inline { display: block; }
  .topbar nav .link { display: block; width: 100%; }
}

@media (max-width: 400px) {
  .brand-name { font-size: 17px; }
}

.wrap { max-width: 1020px; margin: 0 auto; padding: 42px 28px 90px; }
.wrap.narrow { max-width: 620px; }
.wrap.auth { max-width: 440px; }

.auth-tabs {
  display: flex; gap: 4px; margin-bottom: 28px; border-bottom: 1px solid var(--line);
}
.auth-tabs a {
  padding: 10px 4px; margin-bottom: -1px; font-family: var(--display);
  font-weight: 600; font-size: 15px; text-decoration: none;
  color: var(--ink-3); border-bottom: 2px solid transparent;
}
.auth-tabs a + a { margin-left: 20px; }
.auth-tabs a.on { color: var(--ink); border-bottom-color: var(--accent); }

.foot {
  border-top: 1px solid var(--line); padding: 26px 28px;
  color: var(--ink-3); font-size: 13.5px;
}
.foot p { max-width: 70ch; margin: 0 auto; }

/* ------------------------------------------------------------ type */
h1 {
  font-family: var(--display); font-weight: 700;
  font-size: clamp(27px, 4vw, 36px); letter-spacing: -0.025em;
  line-height: 1.1; margin: 0 0 10px; text-wrap: balance;
}
h2 {
  font-family: var(--display); font-weight: 600; font-size: 17px;
  letter-spacing: -0.01em; margin: 0 0 14px;
}
.lede { color: var(--ink-2); font-size: 17px; max-width: 62ch; margin: 0 0 28px; }
.aside { color: var(--ink-3); font-size: 14.5px; margin-top: 26px; }
.hint { display: block; color: var(--ink-3); font-size: 13px; line-height: 1.45; }
.note { color: var(--ink-2); font-size: 14.5px; margin: -4px 0 16px; }
a { color: var(--accent); text-underline-offset: 2px; }
.quiet { font-family: var(--display); font-size: 14px; color: var(--ink-2); }

/* ------------------------------------------------------------ messages */
.messages { list-style: none; padding: 0; margin: 0 0 26px; display: grid; gap: 8px; }
.msg {
  padding: 12px 16px; border-left: 3px solid var(--accent);
  background: var(--accent-soft); font-size: 15px;
}
.msg.error { border-left-color: var(--risk); background: var(--risk-soft); }
.msg.warning { border-left-color: var(--warn); background: var(--warn-soft); }

.error { color: var(--risk); font-size: 13.5px; display: block; margin-top: 4px; }
.error.big, .ok.big {
  font-size: 15px; padding: 14px 18px; border-left: 3px solid var(--risk);
  background: var(--risk-soft); margin-bottom: 22px;
}
.ok.big { border-left-color: var(--accent); background: var(--accent-soft); color: var(--ink); }

/* ------------------------------------------------------------ forms */
.stack { display: grid; gap: 18px; max-width: 460px; }
.field { display: block; }
/* A length hides the two inner bounds, which are then arithmetic rather than
   questions. Like `.row[hidden]` below: `display: block` is an author rule
   and beats the UA stylesheet's own [hidden], so it has to be said. */
.field[hidden] { display: none; }
/* A grid item will not shrink below the widest thing inside it unless it is
   told it may, and a date box is wide: the browser sizes it around the whole
   date plus its calendar button, and on iOS that measurement is bigger than
   anything a desktop draws. Without this the box keeps its width and runs off
   the right of the tile instead of fitting the column it was given.
   Reported from a phone on 2026-09-25. */
.field { min-width: 0; }
.lbl {
  display: block; font-family: var(--display); font-weight: 600;
  font-size: 13.5px; margin-bottom: 5px; cursor: pointer;
}
input[type=text], input[type=email], input[type=password], input[type=date],
input[type=number], select {
  width: 100%; padding: 9px 11px; font: 15px var(--body);
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: 3px;
  /* Never wider than what is holding it, whatever the browser thinks its
     contents need. A date box on iOS asks for more room than the column it
     is in and takes it, which is what pushed these off the right edge. */
  min-width: 0; max-width: 100%;
}
/* The rules above were not enough for a date box on iOS: it still ran off the
   tile by exactly its padding and border, because Safari draws the native
   control at 100% of the content box and ignores border-box. Dropping the
   native appearance makes it an ordinary box that obeys width. An empty one
   then collapses to no height (iOS draws no placeholder), so the height is
   said outright, and the value is put back on the left where Safari centres
   it. The calendar still opens on tap. Reported from a phone, 2026-09-26. */
input[type=date] {
  -webkit-appearance: none; appearance: none;
  display: block; min-height: 42px; line-height: 1.4;
}
input[type=date]::-webkit-date-and-time-value { text-align: left; margin: 0; }
/* Sixteen pixels on a touch screen, and not a typography choice.
   iOS Safari zooms the whole page in when it focuses a control whose text is
   smaller than 16px, and the page does not zoom back out. Everything is then
   wider than the screen: boxes run past their edges and over each other, and
   the customer is left pinching to read a form they were halfway through.
   Reported on a phone on 2026-09-25 and invisible everywhere else, because no
   desktop browser does it and neither does a headless one.
   By pointer rather than width, so a phone held sideways is still a phone. */
@media (pointer: coarse) {
  input[type=text], input[type=email], input[type=password], input[type=date],
  input[type=number], select, textarea { font-size: 16px; }
}

input:focus-visible, button:focus-visible, a:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
.unit, .euro { color: var(--ink-3); font-size: 14px; }
/* Without this the unit wraps under its own full-width input and reads as a
   stray word rather than as part of the answer. */
.with-unit { display: flex; align-items: center; gap: 8px; }
.with-unit input { flex: 1; min-width: 0; }

button.primary {
  font-family: var(--display); font-weight: 600; font-size: 15px;
  padding: 11px 20px; border: 0; border-radius: 3px; cursor: pointer;
  background: var(--accent); color: var(--accent-ink);
}
button.primary:hover { filter: brightness(1.08); }
button.primary:disabled {
  background: var(--line-strong); color: var(--ink-3);
  cursor: not-allowed; filter: none;
}
a.primary {
  display: inline-block; text-decoration: none; font-family: var(--display);
  font-weight: 600; padding: 11px 20px; border-radius: 3px;
  background: var(--accent); color: var(--accent-ink);
}

/* ------------------------------------------------------------ builder */
.builder {
  display: grid; gap: 22px;
  grid-template-columns: minmax(0, 1fr);
}
.steps { display: grid; gap: 14px; min-width: 0; }

@media (min-width: 900px) {
  .builder { grid-template-columns: minmax(0, 1fr) 268px; align-items: start; }
  .builder .card, .steps { grid-column: 1; }
  .rail { grid-column: 1 / -1; }
  /* Auto-placed rather than pinned to row 2: with no JavaScript the rail is
     display:none and takes no cell, so a pinned row left a gap above the
     quote the height of the steps that were never there. */
  .quote { grid-column: 2; position: sticky; top: 20px; }
}

.card {
  background: var(--surface); border: 1px solid var(--line);
  padding: 22px 24px; display: grid; gap: 16px;
}
.card > h2 { margin-bottom: 0; }
.row { display: grid; gap: 16px; grid-template-columns: 1fr 1fr; }
@media (max-width: 620px) { .row { grid-template-columns: 1fr; } }
.row > [hidden] { display: none; }
/* Without this, `.row[hidden]` (e.g. the return-date row on a one-way trip)
   stays visible: `.row`'s own `display: grid` is an author rule and beats
   the browser's built-in `[hidden] { display: none }`, which only wins on
   specificity ties because it lives in the lower-priority UA stylesheet. */
.row[hidden] { display: none; }

/* Sets of dates. Each is two tiles, Departure and Coming home. With several
   sets a numbered heading and a rule between them tell the sets apart, rather
   than a box around the tiles, which would be a box in a box in a box. */
.windows { display: grid; gap: 18px; }
.window { display: grid; gap: 12px; }
.window-head { display: none; align-items: baseline; justify-content: space-between; gap: 12px; }
.windows.is-several .window-head { display: flex; }
.windows.is-several .window + .window {
  padding-top: 18px; border-top: 1px solid var(--line-strong);
}
.window-name { font-family: var(--display); font-weight: 600; font-size: 14.5px; }

.leg {
  display: grid; gap: 12px; padding: 14px 16px 16px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 3px;
}
/* The dates read back as a sentence, under each set. It is the answer to a
   question the customer did not type -- what the return dates worked out to
   -- so it is quiet, and it only exists once there is something to say. */
.readback {
  margin: 0; font-size: 13px; line-height: 1.5; color: var(--ink-2);
  padding: 9px 12px; background: var(--bg);
  border-left: 2px solid var(--line-strong); border-radius: 0 3px 3px 0;
}
.readback[hidden] { display: none; }

/* Which shape of answer a set is giving. Only the script can act on these, so
   like the Remove button they wait for it. */
.pills[hidden] { display: none; }
.pill-btn {
  font: 13px var(--display); color: var(--ink-2); cursor: pointer;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: 999px; padding: 5px 12px;
}
.pill-btn:hover { border-color: var(--ink-3); }
/* The month shortcut, quieter than the boxes it fills in. */
.month {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font: 13.5px var(--display); color: var(--ink-2);
}
.month[hidden] { display: none; }
.month select { max-width: 15rem; }
.month-or {
  margin: 0; font: 13.5px var(--display); color: var(--ink-2);
}
.month-or[hidden] { display: none; }

.pill-btn[aria-pressed="true"] {
  background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
}
/* `display: grid` above outranks the browser's own [hidden] rule. */
.leg[hidden] { display: none; }
.leg-name {
  margin: 0; font-family: var(--display); font-weight: 600; font-size: 14px;
  letter-spacing: 0; color: var(--ink);
}
@media (max-width: 620px) { .leg { padding: 12px 12px 14px; } }
/* Only the script can take a set away, so the button waits for it. */
.window-remove {
  display: none; font: 13.5px var(--display); color: var(--accent);
  background: none; border: 0; padding: 2px 0; cursor: pointer;
}
.wizard .window-remove { display: inline; }
/* "Add other dates" (.window-more, .window-add) shares the quote tip's box and
   button, further down, so that the two are styled in one place. */

/* ---------------------------------------------------------- step rail */
/* Hidden without JavaScript: every step is open there, so a progress
   indicator would be counting something that is not happening. */
.rail { display: none; }
.wizard .rail {
  display: flex; flex-wrap: wrap; gap: 6px;
  list-style: none; margin: 0 0 4px; padding: 0;
  counter-reset: rail;
}
.rail li {
  display: flex; align-items: center; gap: 7px;
  padding: 6px 13px 6px 7px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
  font-family: var(--display); font-size: 13px; color: var(--ink-3);
  cursor: pointer; counter-increment: rail;
}
.rail li::before {
  content: counter(rail);
  display: grid; place-items: center; width: 20px; height: 20px;
  border-radius: 50%; background: var(--surface-2); color: var(--ink-3);
  font-size: 11.5px; font-weight: 600;
}
.rail li.done { color: var(--ink-2); border-color: var(--line-strong); }
.rail li.done::before { content: "✓"; background: var(--accent); color: var(--accent-ink); }
.rail li.on {
  color: var(--ink); border-color: var(--accent); background: var(--accent-soft);
}
.rail li.on::before { background: var(--accent); color: var(--accent-ink); }
.rail li.locked { cursor: default; opacity: 0.55; }

/* -------------------------------------------------------------- steps */
.step {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 4px;
}
.wizard .step.is-open { border-color: var(--line-strong); box-shadow: 0 1px 0 var(--line); }
.wizard .step.is-todo { background: var(--surface-2); }

.step-head {
  display: grid; align-items: center; gap: 2px 12px;
  grid-template-columns: 26px 1fr auto;
  padding: 16px 22px;
}
.wizard .step.is-done .step-head, .wizard .step.is-todo .step-head {
  cursor: pointer; padding: 13px 22px;
}
.step-n {
  display: none; place-items: center; width: 24px; height: 24px;
  border-radius: 50%; background: var(--surface-2); color: var(--ink-3);
  font-family: var(--display); font-size: 12.5px; font-weight: 700;
}
.wizard .step-n { display: grid; }
.wizard .step.is-open .step-n { background: var(--accent); color: var(--accent-ink); }
.wizard .step.is-done .step-n { background: var(--accent-soft); color: var(--accent); }
.step-head h2 { grid-column: 2; margin: 0; }
.wizard .step:not(.is-open) .step-head h2 { font-size: 15px; color: var(--ink-2); }

.step-sum {
  grid-column: 2; font-size: 14px; color: var(--ink);
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}
.step-sum:empty { display: none; }

.step-edit {
  display: none; grid-column: 3; grid-row: 1 / span 2;
  background: none; border: 0; padding: 4px; cursor: pointer;
  font-family: var(--display); font-size: 13.5px; color: var(--accent);
}
.wizard .step.is-done .step-edit { display: block; }

.step-body { display: grid; gap: 16px; padding: 0 22px 20px; }
.wizard .step:not(.is-open) .step-body { display: none; }

.step-go { display: none; }
.wizard .step-go { display: block; }
.step-warn {
  margin: 0; padding: 10px 14px; font-size: 14px;
  background: var(--risk-soft); border-left: 3px solid var(--risk);
}

@media (max-width: 620px) {
  .step-head, .step-body { padding-left: 16px; padding-right: 16px; }
}

fieldset { border: 0; padding: 0; margin: 0; display: grid; gap: 10px; }
legend {
  font-family: var(--display); font-weight: 600; font-size: 13.5px;
  padding: 0; margin-bottom: 2px;
}

.kinds { gap: 8px; }
.kind {
  display: grid; grid-template-columns: 20px 1fr; gap: 4px 10px;
  align-items: start; padding: 11px 13px; cursor: pointer;
  border: 1px solid var(--line-strong); border-radius: 3px;
}
.kind:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }

/* The open-jaw option. Indented and joined to the Return card above it so it
   reads as a detail of that answer rather than as a fourth kind of trip. */
.kind-extra {
  margin: -4px 0 0 22px; padding: 12px 14px 13px 16px;
  border-left: 2px solid var(--accent);
  background: var(--surface-2); border-radius: 0 3px 3px 0;
}
.kind-extra[hidden] { display: none; }
.kind-extra .check { align-items: start; }
.kind-extra strong {
  font-family: var(--display); font-size: 14px; font-weight: 600;
}
.kind-extra .hint { margin-top: 3px; max-width: 58ch; }
.kind input { grid-row: 1 / span 2; margin-top: 3px; }
.kind-name { font-family: var(--display); font-weight: 600; font-size: 14.5px; }
.kind-why { color: var(--ink-3); font-size: 13px; line-height: 1.45; }

.stops, .groups { gap: 8px; }
/* The two "avoid" questions, kept together so a direct trip hides both. Same
   spacing the step body would have given them. */
.avoid { display: grid; gap: 16px; }
.avoid[hidden] { display: none; }
.pills { display: flex; flex-wrap: wrap; gap: 8px; }
.pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px; border: 1px solid var(--line-strong); border-radius: 999px;
  font-family: var(--display); font-size: 13.5px; cursor: pointer;
}
.pill:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }

/* ------------------------------------------------- airport picker */
/* The real field. Kept in the DOM and kept posting; only taken off screen,
   so with the script blocked it is the plain text box it always was. */
.picker-source {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); border: 0; opacity: 0;
}
.picker {
  position: relative;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 6px; min-height: 42px;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: 3px;
}
.picker:focus-within { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.picker-chips { display: contents; }

.chip-air {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 4px 4px 10px; border-radius: 999px;
  background: var(--accent-soft); border: 1px solid transparent;
  font-size: 13.5px; line-height: 1.2; max-width: 100%;
}
.chip-city { font-family: var(--display); font-weight: 600; }
.chip-code {
  font-family: var(--mono); font-size: 11px; color: var(--accent);
  letter-spacing: 0.04em;
}
.chip-x {
  display: grid; place-items: center; width: 19px; height: 19px; padding: 0;
  border: 0; border-radius: 50%; cursor: pointer; font-size: 14px;
  line-height: 1; background: transparent; color: var(--ink-3);
}
.chip-x:hover { background: var(--risk-soft); color: var(--risk); }

.picker-search {
  flex: 1 1 130px; min-width: 110px;
  padding: 5px 4px; border: 0; background: none;
  font: 15px var(--body); color: var(--ink);
}
/* The box around it already shows focus. Letting the global input outline
   through as well drew a second ring inside the first. */
.picker-search:focus, .picker-search:focus-visible { outline: none; }
.picker-search[hidden] { display: none; }

.picker-list {
  position: absolute; left: -1px; right: -1px; top: calc(100% + 4px);
  z-index: 20; max-height: 302px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: 4px; box-shadow: 0 16px 36px rgba(0, 0, 0, 0.17);
}
.picker-opt {
  display: grid; grid-template-columns: 42px 1fr; align-items: center;
  gap: 10px; padding: 9px 12px; cursor: pointer;
  border-bottom: 1px solid var(--line);
}
.picker-opt:last-child { border-bottom: 0; }
.picker-opt.active, .picker-opt:hover { background: var(--accent-soft); }
.picker-opt.on { opacity: 0.5; }
.picker-opt.on .opt-city::after { content: " · added"; color: var(--accent); font-weight: 400; }
.opt-code {
  font-family: var(--mono); font-size: 12px; font-weight: 500;
  text-align: center; padding: 3px 0; border-radius: 3px;
  background: var(--surface-2); color: var(--ink-2);
}
.opt-body { display: grid; min-width: 0; }
.opt-city { font-family: var(--display); font-weight: 600; font-size: 14.5px; }
.opt-sub {
  font-size: 12.5px; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.picker-none, .picker-note {
  padding: 11px 13px; font-size: 13px; color: var(--ink-3); line-height: 1.45;
}
.picker-note { padding: 2px 4px 0; flex-basis: 100%; }

/* The euro belongs against the number, not floating beside the box. */
.with-euro {
  display: flex; align-items: stretch;
  border: 1px solid var(--line-strong); border-radius: 3px;
  background: var(--surface); overflow: hidden; max-width: 220px;
}
.with-euro:focus-within { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.with-euro .euro {
  display: grid; place-items: center; padding: 0 11px;
  background: var(--surface-2); border-right: 1px solid var(--line);
  font-size: 15px; color: var(--ink-2);
}
.with-euro input { flex: 1; min-width: 0; border: 0; border-radius: 0; }
.with-euro input:focus, .with-euro input:focus-visible { outline: none; }
.check {
  display: grid; grid-template-columns: 18px 1fr; gap: 10px;
  align-items: start; cursor: pointer; font-size: 14.5px;
}
.check input { margin-top: 4px; }
/* `display: grid` above outranks the browser's own [hidden] rule. */
.check[hidden] { display: none; }

.quote {
  background: var(--surface); border: 1px solid var(--line-strong);
  border-top: 3px solid var(--accent); padding: 20px 22px;
  display: grid; gap: 10px; align-content: start;
}
.quote.over { border-top-color: var(--risk); }
/* Before there are dates there is nothing to quote, and a big em-dash where a
   price will be reads as a broken number rather than as one not asked for. */
.wizard .quote:not(.ready) .quote-n,
.wizard .quote:not(.ready) .quote-p { opacity: 0.4; }
.quote-n { font-size: 14.5px; color: var(--ink-2); }
.quote-n strong, .quote-p strong {
  font-family: var(--display); font-weight: 700; font-size: 30px;
  letter-spacing: -0.02em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.quote-p { font-size: 14.5px; color: var(--ink-2); }
.quote-p span { display: block; }
.quote-note { font-size: 13px; color: var(--ink-3); margin: 0; line-height: 1.45; }
.quote.over .quote-note { color: var(--risk); }
/* The cheaper trip, offered beside a price that has just jumped. Green because
   it is money back, not a warning: the point is that they stay.
   "Add other dates" wears the same box and button, always, so it stands out
   the same way. A dashed outline and grey text under it were easy to miss. */
.quote-tip, .window-more {
  display: grid; gap: 9px; justify-items: start;
  background: var(--good-soft); border-left: 3px solid var(--good);
  padding: 11px 13px; font-size: 13.5px; line-height: 1.45; color: var(--ink-2);
}
.quote-tip[hidden], .window-more[hidden] { display: none; }
.quote-tip p { margin: 0; }
.quote-tip strong { font-family: var(--display); font-weight: 700; color: var(--good); }
.quote-tip-go, .window-add {
  font-family: var(--display); font-weight: 600; font-size: 13.5px;
  padding: 7px 12px; border: 1px solid var(--good); border-radius: 3px;
  background: none; color: var(--good); cursor: pointer;
}
.quote-tip-go:hover, .window-add:hover { background: var(--surface); }
.window-add[hidden] { display: none; }

/* What the route lists say about the airports just chosen. Amber where one may
   have nothing direct: it is a "probably", not an error, so not red. Green for
   the nearby airports that do fly there, like the cheaper-trip offer. */
.route-hints {
  display: grid; gap: 10px; margin: 2px 0 16px;
  font-size: 14px; line-height: 1.45; color: var(--ink-2);
}
.route-hints[hidden] { display: none; }
/* Through .step-body, or the landing page's `.step p` (15px) wins: it comes
   later in this file and the builder's steps share the class name. */
.step-body .route-hints p, .step-body .route-hints li {
  margin: 0; font-size: 14px; color: var(--ink-2);
}
.route-warn, .route-also {
  display: grid; gap: 8px; justify-items: start;
  padding: 11px 13px; border-left: 3px solid;
}
.route-warn { background: var(--warn-soft); border-left-color: var(--warn); }
.route-also { background: var(--good-soft); border-left-color: var(--good); }
.route-also ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.route-also li { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.route-hints button {
  font-family: var(--display); font-weight: 600; font-size: 13px;
  padding: 5px 10px; border: 1px solid currentColor; border-radius: 3px;
  background: none; cursor: pointer;
}
.route-warn button { color: var(--warn); }
.route-also button { color: var(--good); }
.route-hints button:hover { background: var(--surface); }
.step-body .route-hints .route-source { font-size: 12.5px; color: var(--ink-3); }

/* ------------------------------------------------------------ receipt */
.receipt {
  background: var(--surface); border: 1px solid var(--line);
  padding: 6px 20px; margin-bottom: 26px;
}
.line {
  display: flex; justify-content: space-between; gap: 20px;
  padding: 11px 0; border-bottom: 1px dotted var(--line); font-size: 15px;
}
.line:last-child { border-bottom: 0; }
.line.total {
  border-top: 1px solid var(--line-strong); border-bottom: 0;
  font-family: var(--display); font-weight: 600;
}
.line.discount .amt { color: var(--accent); }
.amt { font-family: var(--mono); font-variant-numeric: tabular-nums; }

.soon {
  border: 1px dashed var(--line-strong); padding: 18px 20px;
  margin-top: 26px; color: var(--ink-2); font-size: 14.5px;
}
.soon h2 { margin-bottom: 6px; }
.code-form { max-width: 380px; }

/* ------------------------------------------------------------ dashboard */
.first-night-globe { display: flex; justify-content: center; margin: 4px 0 32px; }
.first-night-globe .hero-globe { flex: none; width: 220px; height: 200px; }

.trip-switch { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 24px; }
.trip-switch a {
  font-family: var(--display); font-size: 13.5px; text-decoration: none;
  padding: 6px 13px; border: 1px solid var(--line-strong); border-radius: 999px;
  color: var(--ink-2);
}
.trip-switch a.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

/* ------------------------------------------------- destination hero */
.trip-hero {
  position: relative; isolation: isolate; overflow: hidden;
  border-radius: 5px; margin-bottom: 26px;
  min-height: 168px; display: flex; flex-direction: column;
  justify-content: flex-end;
  /* The fallback colour, from the airport code. A destination nobody has
     fetched a photograph for still gets its own hero rather than a hole. */
  background: linear-gradient(135deg, var(--dest-from, var(--accent)),
                                      var(--dest-to, #123));
}
.trip-hero-img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* The scrim. A photograph can be any brightness anywhere, so white text on
   one is only safe with a guaranteed dark floor under it -- pale sky over
   Cape Town would otherwise swallow the trip name entirely. */
.trip-hero.has-photo::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top,
      rgba(0, 0, 0, 0.82) 0%, rgba(0, 0, 0, 0.55) 38%,
      rgba(0, 0, 0, 0.22) 70%, rgba(0, 0, 0, 0.30) 100%);
}

.trip-hero-body {
  display: flex; flex-wrap: wrap; gap: 12px 20px;
  align-items: flex-end; justify-content: space-between;
  padding: 26px 24px 20px;
}
.trip-hero-body > div:first-child { min-width: 0; }
.trip-hero h1 {
  color: #fff; margin: 0 0 5px;
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.5);
}
.trip-place {
  font-family: var(--display); font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.1em;
  color: rgba(255, 255, 255, 0.82); margin: 0 0 4px;
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.6);
}
.trip-route {
  margin: 0; font-size: 15.5px; color: rgba(255, 255, 255, 0.92);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.6);
}

.trip-meta { display: flex; align-items: center; gap: 14px; flex: none; }
.trip-hero .chip {
  background: rgba(255, 255, 255, 0.16); border-color: rgba(255, 255, 255, 0.3);
  color: #fff; backdrop-filter: blur(3px);
}
.trip-hero .quiet { color: #fff; text-decoration: underline; }

/* Attribution. CC BY and CC BY-SA both require the photographer to be named,
   so this is not decoration and must not be removed to tidy the corner --
   toned down to a quiet watermark instead, full contrast on hover/focus. */
.trip-credit {
  position: absolute; right: 0; top: 0; margin: 0;
  padding: 3px 7px 4px; border-radius: 0 0 0 7px;
  font-size: 9px; line-height: 1.3; max-width: 62%; text-align: right;
  color: rgba(255, 255, 255, 0.5);
  /* Its own backdrop rather than only a text shadow: the top of the hero is
     wherever the sky is, so it is the brightest part of most of these
     photographs and white-on-white was unreadable over Cape Town. */
  background: rgba(0, 0, 0, 0.22);
  backdrop-filter: blur(1.5px);
  transition: color 0.15s, background-color 0.15s;
}
.trip-credit:hover, .trip-credit:focus-within {
  color: rgba(255, 255, 255, 0.85); background: rgba(0, 0, 0, 0.42);
}
.trip-credit a { color: inherit; text-decoration: none; }
.trip-credit a:hover, .trip-credit a:focus { color: #fff; text-decoration: underline; }

.chip {
  font-family: var(--mono); font-size: 12px; padding: 4px 10px;
  background: var(--surface-2); border: 1px solid var(--line);
}

@media (max-width: 620px) {
  .trip-hero { min-height: 150px; }
  .trip-hero-body { padding: 20px 16px 16px; }
  .trip-credit { max-width: 52%; }
}

/* The graph shows the shape; these say the number in words. */
.stats {
  display: grid; gap: 1px; margin-bottom: 22px;
  grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
  background: var(--line); border: 1px solid var(--line);
}
.stat { background: var(--surface); padding: 14px 18px; display: grid; gap: 3px; }
.stat-k {
  font-family: var(--display); font-size: 11.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-3);
}
.stat-v {
  font-family: var(--display); font-weight: 700; font-size: 26px;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums; line-height: 1.1;
}
.stat-v.down { color: var(--good); }
.stat-v.up { color: var(--risk); }
.stat-v.flat { color: var(--ink-3); font-size: 20px; }
.stat-s { font-size: 12.5px; color: var(--ink-3); }

.chartbox {
  position: relative;
  background: var(--surface); border: 1px solid var(--line);
  padding: 18px 20px; margin-bottom: 32px;
}
/* The scrolling lives here, not on .chartbox itself, so .chart-axis-mobile
   below can sit outside it as a plain sibling -- an absolutely positioned
   box is placed against .chartbox's own padding edge regardless of how far
   this inner box has been scrolled, which is what keeps it in place. */
.chart-scroll {
  overflow-x: auto; overscroll-behavior-x: contain;
  /* Opens scrolled to the END of the chart (today's price, the point anyone
     actually opens this page to see) instead of the start, with no
     JavaScript: a well-supported trick where the scroll container reads
     right-to-left, so its resting position is its right edge, and the
     content inside is flipped straight back to ltr so nothing about the
     chart itself reads backwards. */
  direction: rtl;
}
.chart { width: 100%; height: auto; display: block; min-width: 520px; direction: ltr; }
/* Hidden by default; only takes over from the SVG's own axis text below
   520px, where .chart's min-width above guarantees it is wider than the
   screen and therefore scrolls. */
.chart-axis-mobile { display: none; }
@media (max-width: 520px) {
  /* The SVG is pinned to exactly 520px wide by .chart's min-width whenever
     the viewport can't fit that, so its rendered height is a known constant
     (520 * 260/720) rather than something this overlay has to measure. */
  .chart-axis-mobile {
    display: block; position: absolute; left: 20px; top: 18px;
    width: 46px; height: 187.78px;
    background: var(--surface);
    pointer-events: none;
  }
  .chart-axis-mobile span {
    position: absolute; right: 6px; transform: translateY(-50%);
    font-family: var(--mono); font-size: 10.5px; color: var(--ink-3);
    white-space: nowrap;
  }
  /* Replaced by the overlay above; left in without this it would scroll back
     into view, doubled up, the moment someone drags the chart leftward. */
  .chart .ylab { display: none; }
}
.chart .grid { stroke: var(--line); stroke-width: 1; }
.chart .series {
  fill: none; stroke: var(--accent);
  stroke-width: 2; stroke-linejoin: round;
}
.chart .dot { fill: var(--accent); stroke: var(--surface); stroke-width: 1.5; }
.chart .dot.partial { opacity: 0.45; }
/* The night whose options are on screen, so the graph and the table agree. */
.chart .dot.on { stroke: var(--ink); stroke-width: 2.5; }
/* An invisible disc doing the catching. The visible dot is 3.5px, which is
   not a target anyone can hit with a finger, and growing it would bury the
   line it sits on. */
.chart .hit { fill: transparent; stroke: none; }
.chart .dotlink { cursor: pointer; }
.chart .dotlink:hover .dot { r: 5.5; fill: var(--ink); }
.chart .dotlink:focus-visible { outline: none; }
.chart .dotlink:focus-visible .dot { stroke: var(--ink); stroke-width: 2.5; }
.chart .best { fill: none; stroke: var(--ink); stroke-width: 1.5; }
.chart .threshold {
  stroke: var(--warn); stroke-width: 1.5; stroke-dasharray: 4 4;
}
.chart .ylab, .chart .xlab, .chart .tlab {
  font-family: var(--mono); font-size: 10.5px; fill: var(--ink-3);
}
.chart .ylab { text-anchor: end; }
.chart .tlab { fill: var(--warn); }
.chart .blab {
  font-family: var(--display); font-size: 12px; font-weight: 600; fill: var(--ink);
}
.chart-empty { color: var(--ink-3); text-align: center; padding: 40px 0; margin: 0; }

/* Something that is switched on but silently not working. Warm rather than
   red: nothing is broken and nothing is lost, there is just a step left. */
.warnbox {
  background: var(--warn-soft); border: 1px solid var(--warn);
  border-left-width: 3px; border-radius: 3px;
  padding: 13px 16px; margin: 0 0 22px; font-size: 14.5px;
}
.warnbox p { margin: 0 0 8px; }
.warnbox p:last-child, .warnbox form:last-child { margin-bottom: 0; }

.days-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 14px;
}
.pager { display: flex; gap: 14px; font-family: var(--display); font-size: 14px; }

/* A sideways strip: five nights at a time, the rest a scroll away. A grid of
   every night checked buries the graph under three weeks of cards. */
.daystrip {
  display: grid; gap: 10px;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - 4 * 10px) / 5);
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-bottom: 6px;
}
.daystrip > .day { scroll-snap-align: start; }
.daystrip:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Narrow screens cannot show five of anything legibly. */
@media (max-width: 900px) {
  .daystrip { grid-auto-columns: calc((100% - 2 * 10px) / 3); }
}
@media (max-width: 620px) {
  .daystrip { grid-auto-columns: 74%; }
}

.stepper {
  font: inherit; font-family: var(--display); font-size: 14px;
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--accent);
}
.stepper:hover { text-decoration: underline; }
/* A link, not a card: picking a night is what switches the options table. */
.day {
  background: var(--surface); border: 1px solid var(--line);
  padding: 14px 16px; display: grid; gap: 5px; align-content: start;
  color: inherit; text-decoration: none; cursor: pointer;
  border-left: 3px solid transparent;
}
.day:hover { border-color: var(--line-strong); border-left-color: var(--line-strong); }
.day.on { border-color: var(--accent); border-left-color: var(--accent); background: var(--accent-soft); }
.day.partial { border-style: dashed; }
.day-date {
  font-family: var(--mono); font-size: 11.5px; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.day-price {
  font-family: var(--display); font-weight: 700; font-size: 25px;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.day-price.none { font-size: 16px; color: var(--ink-3); font-weight: 500; }
.day-card { font-size: 12.5px; color: var(--ink-2); line-height: 1.4; }
.day-checks { font-family: var(--mono); font-size: 11px; color: var(--ink-3); }

/* ----------------------------------------------------- what was asked for */
/* Chips rather than prose: these are read by scanning for the one constraint
   that explains a thin list, not sentence by sentence. */
.asked {
  margin: 18px 0 22px; padding: 14px 18px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 3px;
}
.asked h3 {
  margin: 0 0 9px;
  font-family: var(--display); font-size: 11.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-3);
}
.asked ul {
  display: flex; flex-wrap: wrap; gap: 6px 8px;
  list-style: none; margin: 0; padding: 0; font-size: 13.5px;
}
.asked li {
  padding: 3px 11px; background: var(--surface);
  border: 1px solid var(--line); border-radius: 999px;
}
.asked .hint { margin-top: 10px; }

/* -------------------------------------------------- every option table */
.options { margin-top: 38px; }
.scroll {
  /* Positioned so it is the containing block for anything absolute inside it.
     Without this the visually-hidden `.sr` label in the last column escaped
     the clip, sat at x=818 of the wide table and stretched the whole document
     to 819px -- so every page on a phone scrolled sideways. */
  position: relative;
  overflow-x: auto; background: var(--surface);
  border: 1px solid var(--line); border-radius: 3px;
}
.opts { width: 100%; border-collapse: collapse; font-size: 14px; }
/* Not sticky: `overflow-x: auto` on .scroll makes it the scroll container in
   both axes, so a sticky header would have nothing to stick to and the whole
   table is meant to scroll with the page anyway. */
.opts th {
  padding: 9px 12px; text-align: left; white-space: nowrap;
  font-family: var(--display); font-size: 11.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-3);
  background: var(--surface-2); border-bottom: 1px solid var(--line);
}
.opts td {
  padding: 10px 12px; border-bottom: 1px solid var(--line);
  vertical-align: top; white-space: nowrap;
}
.opts tbody tr:last-child td { border-bottom: 0; }
.opts tbody tr:hover { background: var(--surface-2); }
.opts tr.best td { background: var(--accent-soft); }
.opts tr.best:hover td { background: var(--accent-soft); filter: brightness(0.98); }

/* ------------------------------------------------- sorting and filtering */
/* Built by trip-tools.js, so none of it appears when the script has not run
   and nothing on the page is furniture that does nothing. */
.opts th.sortable { cursor: pointer; user-select: none; }
.opts th.sortable:hover { color: var(--ink); }
.opts th.sortable::after {
  content: "↕"; margin-left: 6px; opacity: 0.35; font-size: 10px;
}
.opts th[aria-sort="ascending"]::after { content: "↑"; opacity: 1; }
.opts th[aria-sort="descending"]::after { content: "↓"; opacity: 1; }
.opts th[aria-sort="ascending"], .opts th[aria-sort="descending"] {
  color: var(--accent);
}

.opts tr.filters th { padding: 6px 8px; background: var(--surface-2); }
.colfilter {
  width: 100%; min-width: 72px; box-sizing: border-box;
  font: inherit; font-size: 12px; font-family: var(--body);
  /* 5px, not 7: at min-width that is what lets "e.g. <600" fit whole in a
     narrow column such as Stops. */
  padding: 4px 5px; border: 1px solid var(--line-strong);
  border-radius: 3px; background: var(--surface); color: var(--ink);
}
.colfilter:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

.tablestatus {
  display: flex; gap: 14px; align-items: baseline;
  margin: 8px 0 0; font-family: var(--mono); font-size: 11.5px;
  color: var(--ink-3);
}
.linky {
  font: inherit; background: none; border: 0; padding: 0;
  color: var(--accent); cursor: pointer; text-decoration: underline;
}
/* The top row is only "cheapest" while the whole table is showing. */
.opts.is-filtered tr.best td { background: var(--surface); }
.opts.is-filtered tr.best .price .tag { display: none; }

.opts .price {
  font-family: var(--display); font-weight: 700; font-size: 16.5px;
  font-variant-numeric: tabular-nums;
}
.opts .price.muted { font-size: 14px; font-weight: 600; color: var(--ink-3); }
.opts .route { font-family: var(--mono); font-size: 12.5px; }
.opts .times { font-variant-numeric: tabular-nums; }
.back-times { display: block; font-size: 12px; color: var(--ink-3); }
/* The share of a party's price one traveller works out at, under the price
   they actually pay. Same weight as the return times: a second line that
   answers a question about the first, never one competing with it. */
.each { display: block; font-size: 12px; color: var(--ink-3); font-weight: 400; }
.opts .why {
  display: block; font-size: 12px; color: var(--ink-3);
  white-space: normal; max-width: 42ch; margin-top: 3px;
}
/* The "Open" pill is gone: the whole row is the target now. See .rowlink. */

/* A real anchor kept inside the row so it works with no JavaScript and can
   be tabbed to -- a <tr> cannot be a link. Styled as the text it wraps,
   because the affordance is the row, not this. */
.rowlink { color: inherit; text-decoration: none; }
.rowlink:hover { text-decoration: underline; }
tr[data-href] { cursor: pointer; }
tr[data-href]:focus-within { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Only on rows that leave the site, and only where the row is clickable at
   all -- a failed check must not look like it leads somewhere. */
.has-js tr[data-href][data-external] td:last-child::after {
  content: "↗"; float: right; margin-left: 10px;
  color: var(--ink-3); font-size: 11px;
}

.tag {
  display: inline-block; font-family: var(--mono); font-size: 10.5px;
  text-transform: uppercase; letter-spacing: 0.05em;
  padding: 2px 7px; border-radius: 3px; vertical-align: middle;
  background: var(--surface-2); color: var(--ink-3);
}
.opts tr.best .price .tag { background: var(--accent); color: var(--accent-ink); }
.tag.warn { background: var(--warn-soft); color: var(--warn); }

.rest { margin-top: 18px; }
.rest > summary {
  cursor: pointer; font-family: var(--display); font-size: 14px;
  color: var(--ink-2); padding: 8px 0;
}
.rest > summary:hover { color: var(--accent); }
.rest .note { margin: 8px 0 14px; max-width: 74ch; }
.foot-note { margin-top: 18px; max-width: 74ch; }

/* ------------------------------------------------------------ landing */
.hero {
  display: flex; flex-wrap: wrap; align-items: center; gap: 40px;
  padding: 26px 0 44px; border-bottom: 1px solid var(--line); margin-bottom: 44px;
}
.hero-copy { flex: 1 1 320px; min-width: 0; }
.hero h1 { font-size: clamp(30px, 5.5vw, 46px); max-width: 16ch; }
.hero .lede { font-size: 19px; max-width: 56ch; }
.hero-globe {
  flex: 1 1 240px; max-width: 300px; width: 100%; height: 260px;
  display: block; margin: 0 auto;
}
@media (max-width: 620px) { .hero-globe { max-width: 220px; height: 200px; } }

/* How it works: three numbered steps, a row on a wide screen and a column on
   a phone. Its own classes, not the builder's .step. */
.how { margin-bottom: 52px; }
.how-steps {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 22px;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.how-step {
  display: grid; gap: 10px; align-content: start;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 4px; padding: 20px 22px 22px;
}
.how-n {
  display: grid; place-items: center; width: 32px; height: 32px;
  border-radius: 50%; background: var(--accent); color: var(--accent-ink);
  font-family: var(--display); font-size: 15px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.how-step h3 {
  font-family: var(--display); font-weight: 600; font-size: 17px;
  letter-spacing: -0.01em; line-height: 1.25; margin: 0; text-wrap: balance;
}
.how-step p { font-size: 15px; color: var(--ink-2); margin: 0; }
.step h2 { font-size: 16px; margin-bottom: 8px; }
.step p { font-size: 15px; color: var(--ink-2); margin: 0; }

.pricing { margin-bottom: 52px; }
.price-card {
  background: var(--surface); border: 1px solid var(--line);
  border-top: 3px solid var(--accent); padding: 26px 28px; max-width: 460px;
}
.price-big {
  font-family: var(--display); font-weight: 700; font-size: 44px;
  letter-spacing: -0.03em; line-height: 1;
}
.price-per { color: var(--ink-3); font-size: 14px; margin-bottom: 18px; }
.price-card ul { margin: 0 0 16px; padding-left: 20px; font-size: 15px; }
.price-card li { margin-bottom: 6px; }
.price-note { font-size: 13.5px; color: var(--ink-3); margin: 0; }

.honest {
  border-top: 1px solid var(--line); padding-top: 26px;
  color: var(--ink-2); font-size: 15px;
}
.honest h2 { margin-bottom: 12px; }
.honest p { max-width: 68ch; }

/* ------------------------------------------------------------ settings */
.trip-row {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  justify-content: space-between; padding: 13px 0;
  border-bottom: 1px solid var(--line);
}
.trip-row:last-of-type { border-bottom: 0; }
.trip-actions { display: flex; gap: 14px; align-items: center; }
.quiet-card { background: var(--surface-2); }

/* ------------------------------------------------------------ error pages */
.error-page { min-height: 100vh; display: flex; flex-direction: column; }
.error-topbar { justify-content: center; }
.error-content {
  flex: 1; display: flex; align-items: center; justify-content: center;
  padding: 56px 28px;
}
.error-card { max-width: 420px; text-align: center; }
.error-globe {
  width: 220px; height: 220px; display: block; margin: 0 auto 28px;
}
.error-code {
  font-family: var(--mono); font-size: 13px; color: var(--ink-3);
  letter-spacing: 0.08em; text-transform: uppercase; margin: 0 0 10px;
}
.error-card h1 { font-size: 28px; }
.error-card .lede { font-size: 16px; margin: 0 auto 24px; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}
