/* The landing page's one in-page link travels rather than teleports, so the
   reader can see where they were taken from. Only the root element decides
   this for the viewport, and only on this page. */
html.landing { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html.landing { scroll-behavior: auto; }
}

:root {
  /* Vibrant travel-poster palette on a light beige ground. Saturated but each
     value still clears 4.5:1 against BOTH the page and the ticket, so it can
     be used as text (tags) or as a fill carrying --on-color (codes, badges).

     Light-only by design: no prefers-color-scheme override, so the beige is
     what every visitor sees regardless of their OS theme. */
  --paper: #f6eddc;          /* light beige page */
  --surface: #fffaf0;        /* warm white ticket */
  --ink: #1f2933;
  --muted: #55606b;
  --rule: #e6d9bf;
  --rule-strong: #c1b092;

  --c-azure:   #0a5f96;      /* N. America / city */
  --c-vermil:  #c22d26;      /* Asia       / nightlife */
  --c-emerald: #0a6d43;      /* Oceania    / nature */
  --c-teal:    #00736e;      /* Europe     / beach */
  --c-violet:  #6435b8;      /* S. America / culture */
  --c-amber:   #856300;      /* Africa     / family */

  --on-color: #fffaf0;
  --danger: #c22d26;
  --danger-wash: #fbe3e0;

  /* Structural roles. Trip-type selections and the step badges each use ONE
     colour, so the form reads as a single system rather than a swatch card. */
  --accent: var(--c-azure);        /* header, summary, selected trip type */
  --accent-strong: var(--c-vermil);/* ticket strip, submit, prices, step badges */

  --font: Futura, "Century Gothic", "URW Gothic", "Avant Garde", "Trebuchet MS", sans-serif;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 16px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
  /* The footer sits at the foot of the window, not of the content: a page
     with one trip on it is a short page, and a footer halfway up the screen
     with empty paper beneath reads as something missing. The main column
     takes whatever height the content does not; a long page scrolls just
     as before. dvh where the browser has it, so a phone's toolbars are
     counted; vh for the rest. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}
body > main { flex: 1 0 auto; }

/* Faint horizon stripes, like a 60s airline poster. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background: repeating-linear-gradient(
    180deg,
    transparent 0 38px,
    rgba(10, 95, 150, .04) 38px 39px
  );
}

body > * { position: relative; z-index: 1; }

/* Header / footer ------------------------------------------------------ */

.site-header {
  display: flex;
  /* On a narrow screen the links drop to their own line rather than squeezing
     the name into a box too small for it — flex was shrinking the logo to
     58px and letting "TRAVEL DAY" spill across the buttons. */
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  /* The slogan under the name costs 17px of height, so the bar gives it back
     in padding rather than growing: same 74px header as before it existed. */
  padding: .6rem clamp(1rem, 5vw, 3rem);
  border-bottom: 3px solid var(--ink);
  background: var(--accent);
  color: var(--on-color);
}

/* The name and what it promises, stacked, so the slogan reads as part of the
   mark rather than as one more thing in the bar. */
.site-brand {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  /* Neither line is worth breaking: the name is a mark and the slogan is one
     phrase. Whatever room they need, they take. */
  flex: 0 0 auto;
  white-space: nowrap;
}

.slogan {
  margin: 0;
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .17em;
  text-transform: uppercase;
  /* Against the accent this is the same ink at less weight, rather than a
     second colour to keep in step with the theme. */
  opacity: .82;
}

.logo {
  display: inline-flex;
  /* The plane sits on the same line as the name rather than being centred
     against its line box. */
  align-items: baseline;
  gap: .4rem;
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--on-color);
  text-decoration: none;
}
.logo::before { content: "✈"; font-size: 1.1em; }
.logo-day { font-weight: 400; }

.tagline {
  margin: 0;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.site-footer {
  margin-top: 3rem;
  padding: 1.5rem clamp(1rem, 5vw, 3rem) 3rem;
  border-top: 2px dashed var(--rule-strong);
  color: var(--muted);
  font-size: .78rem;
  letter-spacing: .04em;
  text-align: center;
}
.site-footer p { margin: 0; }

.wrap {
  width: min(820px, 100%);
  margin: 0 auto;
  padding: clamp(1.8rem, 5vw, 3rem) clamp(1rem, 4vw, 2rem) 0;
}

h1 {
  margin: 0 0 .5rem;
  font-size: clamp(2.1rem, 6vw, 3.2rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -.01em;
}

.lede {
  margin: 0 0 2rem;
  max-width: 42ch;
  color: var(--muted);
  font-size: 1rem;
}

/* Ticket --------------------------------------------------------------- */

.card {
  position: relative;
  background: var(--surface);
  border: 3px solid var(--ink);
  border-radius: 18px;
  --pad: clamp(1.1rem, 3.5vw, 2rem);
  padding: 0 var(--pad);
}

/* Ticket header strip */
.card::before {
  content: "Boarding pass · TravelDay · No. 001";
  display: block;
  margin: 0 calc(-1 * var(--pad));
  padding: .55rem 1.1rem;
  border-bottom: 2px dashed var(--rule-strong);
  border-radius: 15px 15px 0 0;
  background: var(--accent-strong);
  color: var(--on-color);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
}

.field {
  border: 0;
  border-bottom: 2px dashed var(--rule);
  margin: 0;
  padding: 1.5rem 0;
}

.field legend {
  display: block;
  float: left;
  width: 100%;
  margin-bottom: .9rem;
  padding: 0;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
}

.field > *:not(legend) { clear: both; }

.step {
  display: inline-block;
  min-width: 1.5rem;
  margin-right: .55rem;
  padding: .1rem .3rem;
  border-radius: 4px;
  background: var(--accent-strong);
  color: var(--on-color);
  text-align: center;
  font-size: .7rem;
  letter-spacing: .06em;
}

.hint {
  margin: .6rem 0 0;
  color: var(--muted);
  font-size: .8rem;
}

input[type="number"], select {
  padding: .7rem .8rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
}
select { width: 100%; font-weight: 700; }

/* The departure day.
   The visible field is text, written dd / mm / yyyy, because a native date
   input renders in the browser's own locale and the page cannot override it.
   The native input is still there, sized to nothing, purely to open the
   calendar picker. */
.date-field {
  position: relative;
  display: block;
  width: 100%;
}

/* Only once the script has run: until then the native input is the field, so
   the form still works with JavaScript switched off. */
.date-field:not(.is-enhanced) .date-text,
.date-field:not(.is-enhanced) .date-open { display: none; }

.date-text {
  width: 100%;
  padding: .7rem 2.4rem .7rem .8rem;   /* room for the calendar button */
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.date-text::placeholder { color: var(--muted); font-weight: 400; }
.date-text.is-wrong { border-color: var(--danger); background: var(--danger-wash); }

/* Present for showPicker(), invisible and unreachable otherwise. The doubled
   class beats the shared `.control input` sizing, which would otherwise give
   this a full-size box sitting invisibly over the field. */
.date-field.is-enhanced .date-picker {
  position: absolute;
  left: .8rem;
  bottom: 0;
  width: 1px;
  min-width: 0;
  height: 1px;
  min-height: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  pointer-events: none;
}

.date-open {
  position: absolute;
  top: 50%;
  right: .45rem;
  transform: translateY(-50%);
  padding: .25rem .3rem;
  border: 0;
  border-radius: 6px;
  background: none;
  font-size: .95rem;
  line-height: 1;
  cursor: pointer;
  opacity: .7;
}
.date-open:hover { opacity: 1; background: var(--rule); }

input:focus-visible, select:focus-visible, button:focus-visible {
  outline: 3px solid var(--accent-strong);
  outline-offset: 2px;
}

/* Choice cards, shared by the traveller count and the trip type */
.options { display: grid; gap: .5rem; }

/* Who is travelling: two-up on wider screens, stacked on mobile. */
.options--party { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }

/* Party size controls. Revealed purely in CSS by what is checked, so they work
   with JavaScript switched off. */
.party-detail {
  display: none;
  gap: 1.2rem;
  margin-top: .8rem;
  padding: .9rem 1rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 10px;
  background: var(--paper);
}
.options--party:has(input[value="friends"]:checked) ~ .party-detail[data-for="friends"],
.options--party:has(input[value="family"]:checked)  ~ .party-detail[data-for="family"] {
  display: flex;
}

.party-detail label {
  display: grid;
  gap: .3rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.party-detail select { width: auto; min-width: 5rem; }

.option {
  position: relative;
  display: block;
  padding: .8rem 1rem .8rem 3rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--paper);
  cursor: pointer;
}
.option:hover { background: var(--surface); }

.option input { position: absolute; opacity: 0; pointer-events: none; }

/* Hand-drawn style checkbox */
.option::before {
  content: "";
  position: absolute;
  left: 1rem;
  top: 50%;
  transform: translateY(-50%);
  width: 1.15rem;
  height: 1.15rem;
  border: 2px solid var(--ink);
  border-radius: 3px;
  background: var(--surface);
}
.option:has(input:checked) { background: var(--accent); color: var(--on-color); }
/* Ticked, the box goes white on the accent — but keeps its dark border. The
   border was being set to the same colour as the fill, so the outline the
   unticked box has simply vanished at the moment of pressing it and the tick
   floated in a white square. The border is what makes it read as a checkbox. */
.option:has(input:checked)::before { background: var(--on-color); }

/* The tick itself: two borders of a rotated box. Hidden until checked, so the
   control reads as ticked on its own, not only via the row colour. */
.option::after {
  content: "";
  position: absolute;
  left: 1.44rem;
  top: 50%;
  width: .28rem;
  height: .6rem;
  border: solid var(--ink);
  border-width: 0 3px 3px 0;
  transform: translateY(-64%) rotate(45deg);
  opacity: 0;
}
.option:has(input:checked)::after { opacity: 1; }
.option:has(input:focus-visible) { outline: 3px solid var(--accent-strong); outline-offset: 2px; }

.option-icon {
  margin-right: .35rem;
  /* Emoji come from the system, not the page's font, so they are sized on
     their own terms rather than inheriting a heading's weight. */
  font-weight: 400;
  font-size: 1.05em;
  line-height: 1;
}

.option-title {
  display: block;
  font-weight: 700;
  font-size: .95rem;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.option-sub { display: block; margin-top: .1rem; color: var(--muted); font-size: .85rem; }
.option:has(input:checked) .option-sub { color: var(--on-color); }

/* Location */

/* Once a place is chosen this line is the only record of it on the page. */
.origin-status.is-ok {
  color: var(--ink);
  font-weight: 700;
}

.origin-label {
  display: block;
  margin-bottom: .4rem;
  color: var(--muted);
  font-size: .78rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}

/* Perforated tear-off before the action */
.perf {
  position: relative;
  margin: 0 calc(-1 * var(--pad));
  border-top: 3px dashed var(--rule-strong);
}
.perf::before, .perf::after {
  content: "";
  position: absolute;
  top: -13px;
  width: 22px;
  height: 22px;
  border: 3px solid var(--ink);
  border-radius: 50%;
  background: var(--paper);
}
.perf::before { left: -14px; }
.perf::after { right: -14px; }

.actions { padding: 1.5rem 0 1.7rem; text-align: center; }

.btn-primary {
  display: inline-block;
  padding: .9rem 2.2rem;
  border: 3px solid var(--ink);
  border-radius: 999px;
  background: var(--accent-strong);
  color: var(--on-color);
  font: inherit;
  font-size: .85rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  box-shadow: 4px 4px 0 var(--ink);
}
.btn-primary:hover { background: var(--c-azure); color: var(--on-color); }
.btn-primary:active { transform: translate(2px, 2px); box-shadow: 2px 2px 0 var(--ink); }
.btn-primary:disabled { opacity: .6; cursor: progress; box-shadow: 4px 4px 0 var(--ink); }

/* Lives in the header, so it sits on the accent fill, not on the page. */
.btn-ghost {
  padding: .4rem .9rem;
  border: 2px solid var(--on-color);
  border-radius: 999px;
  color: var(--on-color);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  text-decoration: none;
}
.btn-ghost:hover { background: var(--on-color); color: var(--accent); }

/* Barcode strip along the bottom of the ticket */
.barcode {
  height: 30px;
  margin: 0 calc(-1 * var(--pad));
  border-top: 2px solid var(--ink);
  border-radius: 0 0 15px 15px;
  background-image: repeating-linear-gradient(
    90deg,
    var(--ink) 0 3px, transparent 3px 6px,
    var(--ink) 6px 7px, transparent 7px 11px,
    var(--ink) 11px 15px, transparent 15px 17px
  );
  opacity: .85;
}

/* Messages ------------------------------------------------------------- */

.error {
  margin: .5rem 0 0;
  color: var(--danger);
  font-size: .82rem;
  font-weight: 700;
}

/* On the sign-in and register cards the notice sits under the title with
   air above it rather than hard against the card's top edge. */
.auth .alert { margin-top: 1.6rem; }

.alert {
  margin: 0 0 1.4rem;
  padding: .85rem 1.1rem;
  border: 2px solid var(--danger);
  border-radius: 10px;
  background: var(--danger-wash);
  color: var(--danger);
  font-size: .88rem;
}
.alert a { color: inherit; }

/* The plan's own loader: a turning ring, centred where the plan is about to
   appear. It used to be a line of words, and words that never change read
   as a page that has stopped; a turn says "still working" and claims
   nothing more. The ring is the same one the redraw buttons show, larger.
   Under reduced motion it pulses, as they do. */
.loading {
  display: flex;
  justify-content: center;
  padding: 5rem 0;
}
.loading-ring {
  width: 2.6rem;
  height: 2.6rem;
  border: 4px solid var(--rule);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: working-turn .8s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .loading-ring { animation: working-pulse 1.4s ease-in-out infinite; }
}

/* Plan page ------------------------------------------------------------ */

.plan-summary {
  position: relative;          /* the link icon sits in its top corner */
  margin-bottom: 2rem;
  padding: 1.2rem 1.4rem;
  border: 3px solid var(--ink);
  border-radius: 14px;
  background: var(--accent);
  color: var(--on-color);
}
.plan-summary h1 { margin-bottom: .6rem; font-size: clamp(1.7rem, 5vw, 2.5rem); }

.chips { display: flex; flex-wrap: wrap; gap: .45rem; }

/*
 * The foot of the blue card: what the trip is, and the one thing you might
 * want to do with the whole of it.
 *
 * The chips take the room they need and printing sits in the far corner,
 * bottom-aligned so the button's baseline meets the last row of chips however
 * many rows they run to.
 */
.summary-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: .8rem 1rem;
}

.summary-foot .chips { flex: 1 1 18rem; }

.summary-print {
  /* The button row, with any message floated into the empty blue above it
     rather than given a line of its own: a line would push the button down
     and wrap the chips, and "the button stays where it is" means in both
     directions. The print button and the link icon sit side by side. */
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  gap: .5rem;
  flex: 0 0 auto;
}
/* The notice in the blue card: a small note hanging below the print
   button, over whatever follows the card — no line reserved for it, so
   the card keeps its height, and nothing drawn over the title or the
   chips, which is what floating it *above* the button did. */
.summary-print .print-upsell--pop {
  position: absolute;
  top: calc(100% + .5rem);
  right: 0;
  z-index: 6;
  width: max-content;
  max-width: min(24rem, calc(100vw - 2rem));
  margin: 0;
  padding: .5rem .8rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--surface);
  color: var(--ink);
  box-shadow: 3px 3px 0 var(--ink);
  text-align: left;
}
@media (max-width: 620px) {
  .summary-print { flex: 1 1 100%; align-items: flex-start; }
  .summary-print .print-upsell--pop { left: 0; right: 0; width: auto; max-width: none; }
}

.print-row { display: inline-flex; align-items: center; gap: .7rem; }
/* At the foot the row is not a box of its own: its button and ticks lay out
   among the other actions exactly as before. */
.plan-actions .print-row { display: contents; }

/* Sized down to sit among the chips rather than tower over them, and dressed
   like them — the card's own light-on-blue vocabulary, not the page's. */
.summary-print .btn-print {
  padding: .32rem .9rem;
  border-width: 2px;
  font-size: .72rem;
}

/*
 * At the foot of the page the two ticks sit side by side, as they always
 * have — there is a whole page width to put them in.
 */
.print-toggles {
  display: inline-flex;
  align-items: center;
  gap: 1rem;
}

/*
 * In the blue card there is not, so they stack. Ranged left against each
 * other rather than centred, so the two boxes line up in a column and read as
 * one control with two switches.
 */
.summary-print .print-toggles {
  flex-direction: column;
  align-items: flex-start;
  gap: .2rem;
}

.summary-print .print-prices,
.summary-print .print-maps {
  color: var(--on-color);
  font-size: .72rem;
}

/* Ink, not the card's cream: mobile Safari draws a checkbox's tick in white
   on the accent colour, and a white tick on a cream box on the blue card
   looked unchecked however often it was tapped. Ink takes a white tick. */
.summary-print .print-prices input,
.summary-print .print-maps input { accent-color: var(--ink); width: 1.05rem; height: 1.05rem; }

@media (max-width: 620px) {
  .summary-foot { justify-content: flex-start; }
}

.chip {
  padding: .2rem .7rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);            /* own surface, so it follows the theme again */
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* Editing the plan ----------------------------------------------------- */

.controls {
  margin-bottom: 1.2rem;
  padding: 1rem 1.2rem;
  border: 2px solid var(--ink);
  border-radius: 12px;
  background: var(--surface);
}
/* The panel folds away once the trip has been worked on; the heading is the
   way back in. */
.controls-title {
  display: flex;
  align-items: baseline;
  gap: .7rem;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.controls-title:hover .controls-hint { color: var(--ink); }

.controls-hint {
  margin-left: auto;
  color: var(--muted);
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .06em;
  white-space: nowrap;
}
/* The − / + at the row's end, level with the title: the row centres its
   items, and the glyph is centred in its circle (it is a span here, inside
   the title button, not a button of its own). */
.controls-title { align-items: center; }
.controls-title .controls-fold {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: center;
  margin-left: .2rem;
}
.controls-title:hover .controls-fold { border-color: var(--ink); }
.controls-title:not(.is-folded) .controls-hint { margin-left: auto; }
.controls-title .controls-fold:only-of-type { margin-left: auto; }
.controls-title .controls-hint + .controls-fold { margin-left: .2rem; }
.controls .controls-title h2 { margin: 0; }   /* beats .controls h2 below */
.controls-body { margin-top: .8rem; }          /* the room the title's margin used to give */

.controls h2 {
  margin: 0 0 .8rem;
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Capped rather than stretched: this row holds one date, and a dd/mm/yyyy box
   drawn the full width of the page reads as somewhere to write an essay. The
   track still shrinks on a narrow screen, and auto-fit still lays out more
   than one should another control ever join it. */
.control-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 16rem));
  gap: .8rem;
}

.control { display: grid; gap: .3rem; }
.control-label {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.control select, .control input {
  width: 100%;
  /* A date field's intrinsic width is wider than a grid cell, which stretched
     its column past the others on a narrow screen. */
  min-width: 0;
  /* One height for all three, rather than three near-misses. */
  min-height: 3.1rem;
}

/* Dim the plan while a change is in flight. */
.is-busy { opacity: .55; pointer-events: none; }

/* Top of the plan, and the end of it. A year-long trip is a very long page. */
.jump {
  position: fixed;
  right: 1rem;
  bottom: 1.4rem;
  z-index: 30;
  display: none;
  flex-direction: column;
  gap: .4rem;
}
.jump.is-on { display: flex; }

.jump-arrow {
  width: 2.6rem;
  height: 2.6rem;
  border: 2px solid var(--ink);
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 4px 14px -6px rgba(31, 41, 51, .6);
  color: var(--ink);
  font: inherit;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}
.jump-arrow:hover:not(:disabled) { background: var(--ink); color: var(--surface); }
.jump-arrow:disabled { opacity: .3; cursor: default; box-shadow: none; }

/* The working pill sits along the bottom; leave it the middle. */
@media (max-width: 620px) {
  .jump { right: .6rem; bottom: .8rem; }
  .jump-arrow { width: 2.3rem; height: 2.3rem; font-size: 1rem; }
}

@media print { .jump { display: none !important; } }

/* …and say what is being done, once it has taken long enough to notice. It is
   fixed to the window because the plan is long and the change might have been
   made anywhere in it. */
.working {
  position: fixed;
  left: 50%;
  bottom: 1.6rem;
  /* Above every other notice: while a change is saving, that is the one
     thing on the page that must not be covered. */
  z-index: 45;
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .6rem 1.1rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--surface);
  box-shadow: 0 8px 24px -10px rgba(31, 41, 51, .6);
  color: var(--ink);
  font-size: .82rem;
  font-weight: 700;
  /* Out of the way until it is wanted: no pointer events, nothing to read. */
  opacity: 0;
  transform: translate(-50%, .6rem);
  pointer-events: none;
  transition: opacity .16s ease, transform .16s ease;
  max-width: calc(100vw - 1.6rem);
  box-sizing: border-box;
}
.working.is-on { opacity: 1; transform: translate(-50%, 0); }

.working-spin {
  /* A fixed-size flex item shrinks in width, not height, when the text
     beside it presses on a phone's width — a circle became an ellipse.
     It may not shrink; the text wraps instead. */
  flex: 0 0 1rem;
  width: 1rem;
  height: 1rem;
  border: 3px solid var(--rule);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: working-turn .8s linear infinite;
}

@keyframes working-turn { to { transform: rotate(360deg); } }

/* Something still has to move, or it reads as a stuck page rather than a busy
   one — so it pulses instead of spinning. */
@media (prefers-reduced-motion: reduce) {
  .working { transition: none; }
  .working-spin {
    border-top-color: var(--accent);
    animation: working-pulse 1.4s ease-in-out infinite;
  }
  @keyframes working-pulse { 50% { opacity: .3; } }
}

@media print { .working { display: none !important; } }

/*
 * The way back, offered for a moment after a change lands.
 *
 * Dressed exactly like the legend's "undo the last move" — the same light
 * pill, the same ink border, the same uppercase button — because they are the
 * same thing said in two places, and a reader who has learnt one should
 * recognise the other. Fixed to the foot of the window, since the change it
 * follows can have happened anywhere on a long page.
 */
.undo-toast {
  position: fixed;
  left: 50%;
  bottom: 1.6rem;
  transform: translateX(-50%);
  z-index: 41;
  display: flex;
  align-items: center;
  gap: .8rem;
  max-width: min(92vw, 34rem);
  padding: .5rem .55rem .5rem 1rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-size: .82rem;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .18);
}

.undo-toast[hidden] { display: none; }   /* display:flex would otherwise win over [hidden] */

/* A passing word at the foot of the screen: "Link copied". The undo pill's
   shape, eased in and out, raised clear of the undo pill when both show. */
.note-toast {
  position: fixed;
  left: 50%;
  bottom: 1.6rem;
  z-index: 42;
  display: flex;
  align-items: center;
  gap: .5rem;
  max-width: min(92vw, 30rem);
  padding: .55rem 1.1rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-size: .82rem;
  font-weight: 700;
  box-shadow: 0 8px 24px -10px rgba(31, 41, 51, .6);
  opacity: 0;
  transform: translate(-50%, .6rem);
  pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
}
.note-toast.is-on { opacity: 1; transform: translate(-50%, 0); }
.note-toast.is-raised { bottom: 5rem; }
.note-toast { white-space: nowrap; }
.note-toast-tick {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 1.2rem;
  height: 1.2rem;
  border-radius: 50%;
  background: var(--c-emerald);
  color: var(--on-color);
  font-size: .7rem;
}

.undo-said { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* The same button as .btn-shorten, sized to sit inside the pill. */
.undo-btn {
  flex: none;
  padding: .4rem .8rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  cursor: pointer;
}
.undo-btn:hover { background: var(--ink); color: var(--surface); }

.undo-close {
  flex: none;
  width: 1.6rem;
  height: 1.6rem;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  opacity: .55;
}
.undo-close:hover { opacity: 1; }

@media print { .undo-toast { display: none !important; } }

/* What a stop costs a day, under its subtotal: an aside on the figure above
   it, not another row of the bill. */
.cost-perday {
  margin-top: .1rem;
  text-align: right;
  font-size: .78rem;
  color: var(--muted);
}

/* Reroll: same answers, a different plan. */
.reroll {
  margin-top: 1rem;
  padding-top: .9rem;
  border-top: 2px dashed var(--rule);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4rem .9rem;
}

.btn-reroll {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .6rem 1.1rem;
  border: 2px solid var(--c-violet);
  border-radius: 999px;
  background: var(--c-violet);
  color: var(--on-color);
  font: inherit;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
}
.btn-reroll:hover { filter: brightness(1.12); }

/*
 * The same slot, once the trip is yours and there is no redrawing it.
 *
 * Deliberately the shape of the button it replaces — one control lives here
 * and it does not move or resize as the trip changes under it — and just as
 * deliberately not its colour. Violet invites a press; this one should be
 * findable without being inviting.
 */
.btn-remove-trip {
  border-color: var(--danger);
  background: var(--danger);
  text-decoration: none;
}

.btn-quiet-inline {
  padding: .6rem 1rem;
  border: 2px solid var(--rule-strong);
  border-radius: 999px;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: .78rem;
  font-weight: 700;
  cursor: pointer;
}
.btn-quiet-inline:hover { border-color: var(--ink); }

.reroll-note {
  margin: 0;
  flex: 1 1 14rem;
  font-size: .74rem;
  line-height: 1.45;
  color: var(--muted);
}

.notice {
  margin: 0 0 1.2rem;
  padding: .8rem 1rem;
  border: 2px solid var(--c-amber);
  border-radius: 10px;
  background: var(--surface);
  color: var(--c-amber);
  font-size: .86rem;
}

/*
 * Somebody else's plan, opened from a shared link.
 *
 * Stated plainly rather than warned about: nothing is wrong, this is simply
 * not your trip. So it borrows the notice shape and drops the amber, which on
 * this page means "something needs your attention".
 */
.notice--shared {
  border-color: var(--rule-strong);
  color: var(--muted);
}

/* The choices are still shown — they are what the plan says — but they are
   settled, so they stop looking like something to press. */
.plan--shared input:disabled,
.plan--shared select:disabled {
  cursor: default;
  opacity: .85;
}

.plan--shared label {
  cursor: default;
}

/* Where you stay */
.lodging {
  margin-top: 1rem;
  padding-top: .8rem;
  border-top: 2px dashed var(--rule);
}
.lodging h4 {
  margin: 0 0 .5rem;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}

.lodging-list {
  display: grid;
  /* auto-fill, not auto-fit: a stop with two places to stay was collapsing its
     empty third column and sharing the room between the two, so those cards
     came out half as wide again as every other card on the page. An empty
     track left empty keeps them all the same size. */
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: .5rem;
}

.lodging-option {
  display: grid;
  /* Content at the top. A card stretched to match a taller neighbour used to
     spread its three rows down the whole box, leaving the price floating on
     its own at the bottom. */
  align-content: start;
  gap: .15rem;
  /* Right padding leaves room for the Site/Map badge in the corner. */
  padding: .6rem 3.4rem .6rem .7rem;
  border: 2px solid var(--rule-strong);
  border-radius: 10px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.lodging-option:hover { border-color: var(--ink); }
.lodging-option.is-on {
  border-color: var(--accent);
  background: var(--surface);
  cursor: default;
}

/* An invitation rather than an offer: dashed until it is filled in. */
.lodging-option--own {
  border-style: dashed;
  border-color: var(--c-violet);
  padding-right: .7rem;
}
.lodging-option--own:hover { border-color: var(--c-violet); }
.lodging-option--own.is-open { border-style: solid; background: var(--surface); }
.lodging-option--own strong,
.lodging-option--own .lodging-rate { color: var(--c-violet); }
.lodging-option--own.is-on {
  border-style: solid;
  border-color: var(--accent);
}
.lodging-option--own.is-on strong { color: var(--ink); }
.lodging-option--own.is-on .lodging-rate { color: var(--accent-strong); }

/* The name gets the whole width; the stars and the price band go under it.
   Sharing one line meant the name was a flex item competing with them for
   room, so it shrank to its longest word and "Hilton Mumbai International
   Airport" came out as four lines of one word each — which then set the
   height of every card in the row. */
.lodging-name {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .15rem .4rem;
}
.lodging-name strong {
  flex: 1 0 100%;
  min-width: 0;
  font-size: .9rem;
  /* A single unbroken word longer than the card still has to fit inside it. */
  overflow-wrap: anywhere;
}
.lodging-stars { color: var(--c-amber); font-size: .72rem; letter-spacing: .02em; }
/* What it costs against the rest of this city, not against the world.
   Sits with the stars rather than pushed to the far edge: on a place with no
   star rating it was the only thing on its line and floated out there on its
   own, looking like it belonged to the card next door. */
.lodging-band {
  padding: .05rem .35rem;
  border: 1px solid currentColor;
  border-radius: 5px;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--muted);
}
.lodging-band--1 { color: var(--c-emerald); }
.lodging-band--3 { color: var(--c-vermil); }
.lodging-meta { color: var(--muted); font-size: .72rem; }
.lodging-rate { font-size: .8rem; font-weight: 700; color: var(--accent-strong); }
.lodging-note { margin: .5rem 0 0; color: var(--muted); font-size: .74rem; }

/* Activity picker */
.doing-option {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: .6rem;
  padding: .35rem .5rem;
  border-radius: 8px;
  cursor: pointer;
  font-size: .88rem;
}
.doing-option:hover { background: var(--paper); }
.doing-option input { width: 1rem; height: 1rem; accent-color: var(--accent); }
.doing-option .doing-name { color: var(--muted); }
.doing-option.is-on .doing-title { color: var(--ink); }
.doing-option strong { color: var(--muted); font-weight: 700; }
.doing-option.is-on strong { color: var(--ink); }
/* An invitation rather than an offer: dashed, and quoting nothing, until it
   is ticked and filled in. */
.doing-option--ask { border: 2px dashed var(--c-violet); }
.doing-option--ask .doing-title,
.doing-option--ask .doing-kind,
.doing-option--ask strong { color: var(--c-violet); }
.doing-option--ask.is-on { border-style: solid; background: var(--paper); }
.doing-option--ask.is-on .doing-title { color: var(--c-violet); }

.doing-empty { margin: 0; color: var(--muted); font-size: .84rem; }

/* Itinerary ------------------------------------------------------------ */

.itinerary {
  display: grid;
  gap: .9rem;
  margin-bottom: 2rem;
}

/* Where another way of travelling can be put into a journey.
   A thin line with the button on it, sitting exactly where the card it adds
   would appear — so "before" and "after" are read off the page rather than
   out of a label. */
.leg-insert {
  display: grid;
  grid-template-columns: 3rem 1fr;
  align-items: center;
  gap: 1rem;
  margin: -.35rem 0;
  padding: 0 1.1rem;
}
.leg-insert::before {
  content: '';
  grid-column: 1;
  height: 100%;
  min-height: 1.4rem;
  margin: 0 auto;
  border-left: 2px dashed var(--rule);
}
.leg-insert-btn {
  grid-column: 2;
  justify-self: start;
  padding: .25rem .7rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 999px;
  background: var(--bg);
  color: var(--muted);
  font: inherit;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .02em;
  cursor: pointer;
  opacity: .55;
  transition: opacity .12s ease, border-color .12s ease, color .12s ease;
}
.leg-insert-btn:hover,
.leg-insert-btn:focus-visible {
  opacity: 1;
  border-color: var(--ink);
  color: var(--ink);
}
/* Opened here, the form has no card around it, so it makes its own. */
.leg-insert .flight-form {
  grid-column: 2;
  margin: .5rem 0 .3rem;
  padding: .8rem .9rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 14px;
  background: var(--surface);
}

/* A journey between two places */
.leg {
  position: relative;          /* the fold button sits in its corner */
  display: grid;
  grid-template-columns: 3rem 1fr auto;
  align-items: center;
  gap: 1rem;
  padding: .9rem 1.1rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 12px;
  background: var(--surface);
  /* Home has no card of its own, so a jump to it lands here; same air. */
  scroll-margin-top: 10px;
}

.leg-glyph {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--ink);
  font-size: 1.3rem;
  line-height: 1;
}

.leg--flight .leg-glyph { border-color: var(--c-vermil); }
.leg--train .leg-glyph  { border-color: var(--c-azure); }
.leg--bus .leg-glyph    { border-color: var(--c-emerald); }
.leg--car .leg-glyph    { border-color: var(--c-amber); }
/* A way of the traveller's own: not one of ours, and coloured to say so. */
.leg--custom .leg-glyph { border-color: var(--c-violet); }
/* And a journey with nothing planned for it, which is a question rather than
   a way of travelling: drawn open, so a glance down the trip finds the gap. */
.leg--none {
  border-style: dashed;
  background: none;
}
.leg--none .leg-glyph {
  border-style: dashed;
  border-color: var(--muted);
  color: var(--muted);
  font-size: 1.1rem;
}
.leg--none .leg-price { display: none; }
.leg--none .leg-mode { color: var(--muted); }

.leg-day {
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}

.leg-route {
  margin: .1rem 0 .25rem;
  font-size: 1.05rem;
  font-weight: 700;
}

.leg-meta {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem .9rem;
  color: var(--muted);
  font-size: .78rem;
}

.leg-mode {
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink);
}

.leg-note { margin: .35rem 0 0; color: var(--muted); font-size: .78rem; }

/* Fold / unfold a journey: the same button as a stop's, in the card's top
   corner. Only the price beside it keeps clear; everything below — the
   other ways, the timetable — runs the card's full width. */
.leg-fold { position: absolute; top: .8rem; right: .9rem; margin: 0; }
/* At the card's right edge, directly under the fold button rather than
   beside it: starts below the button's row, whatever the card's height. */
.leg-price { text-align: right; align-self: start; padding-top: 2.4rem; }
.leg-price strong { display: block; font-size: 1.1rem; color: var(--accent-strong); }
.leg-price .leg-per { font-size: .72rem; color: var(--muted); }

/* A place you stay */
.stay {
  /* The sticky header changes height when it pins, and letting the browser
     re-anchor the scroll for that fights with the pinning. */
  overflow-anchor: none;
  /* Jumping here from the map should not butt the card against the very top
     of the window; leave it a little air. */
  scroll-margin-top: 10px;
  padding: 1.2rem 1.3rem 1.3rem;
  border: 3px solid var(--ink);
  border-radius: 14px;
  background: var(--surface);
}

/* A stay card is tall — hotel, three meals a day, things to do — so its
   header stays at the top of the screen while you are inside it. Otherwise you
   scroll into a list of restaurants with no idea which town they are in. */
.stay-head {
  position: sticky;
  top: 0;
  z-index: 3;
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  flex-wrap: wrap;
  /* Spans the card's padding so nothing slides through beside it, then puts
     that padding back on its own. */
  margin: -1.2rem -1.3rem 0;
  padding: 1.2rem 1.3rem .6rem;
  background: var(--surface);
  border-radius: 11px 11px 0 0;
  /* Padding and gap carry the height change, so it eases into the thinner bar
     instead of snapping. */
  transition: padding .18s ease, box-shadow .18s ease;
}

@media (prefers-reduced-motion: reduce) {
  .stay-head { transition: none; }
}

/* Restoring the pinned state after a re-render is not a transition — it is
   where the header already was. Animating it makes the card's contents jump
   and settle every time a selection changes. */
.is-restoring .stay-head { transition: none; }

/* Holding position: a line and a shadow so it reads as a header over the
   content, and tighter padding so it takes less of the screen. Every piece of
   text stays, at the size it already was — only the space around it closes
   up. */
.stay-head.is-stuck {
  /* The gap stays: shrinking it moved the name, country and "change"
     chip a few pixels left at the moment of pinning. Only the vertical
     padding closes up. */
  padding-top: .55rem;
  padding-bottom: .45rem;
  border-bottom: 2px solid var(--rule);
  box-shadow: 0 6px 12px -8px rgba(31, 41, 51, .45);
}

/* On a phone the header wraps to three rows, which is most of what a bar
   should cost. Pinned, the nights sit beside the city instead of below it —
   same words, fewer rows. */
@media (max-width: 620px) {
  .stay-head.is-stuck { flex-wrap: nowrap; align-items: flex-start; }
  .stay-head.is-stuck .stay-titles { min-width: 0; }
  .stay-head.is-stuck .stay-nights { flex: none; margin-left: auto; }
}

/* Nothing sticks on paper. */
@media print {
  .stay-head { position: static; margin: 0; padding: 0; box-shadow: none; }
  .meal-days { position: static; }
}
.stay-titles { flex: 1 1 12rem; }

/* Fold / unfold, at the end of the header's first line — level with the
   city, its "change" chip and the nights, not floating above them. */
.stay-fold {
  flex: none;
  align-self: flex-start;
  margin: 0 0 0 .2rem;          /* the same 1.5rem as the − / + beside it */
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 2px solid var(--rule-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 1.1rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}
.stay-fold:hover { border-color: var(--ink); }

/* The folded stop: what was chosen, in a short ledger, then the bill. */
.stay-folded { margin-top: .8rem; }
.stay-folded-row {
  display: grid;
  grid-template-columns: 6rem minmax(0, 1fr);
  gap: .2rem .8rem;
  padding: .45rem 0;
  border-top: 1px dashed var(--rule);
  font-size: .86rem;
}
.stay-folded-row:first-child { border-top: 0; }
.stay-folded-label {
  color: var(--muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  padding-top: .15rem;
}
.stay-folded-mark {
  display: block;
  color: var(--danger);
  font-size: .6rem;
  letter-spacing: .08em;
}
.stay-folded-body { display: grid; gap: .15rem; min-width: 0; }
.stay-folded-line { overflow-wrap: break-word; }
.stay-folded-when {
  color: var(--muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.stay-folded-quiet { color: var(--muted); }
/* The folded card ends with the same cost lines as the open one. */
.stay-folded .costs { margin-top: .8rem; }

/* Line-height 1, so the name's line box is the badge's height and its
   centre sits level with the badge, the nights and the buttons beside it,
   rather than a line-and-a-half box that hung the name below them. */
.stay-head h2 { margin: 0; font-size: 1.5rem; font-weight: 700; letter-spacing: -.01em; line-height: 1; }

.stay-nights { text-align: right; }

/* Nights on and off, either side of the count they change. */
.stay-nights-count {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .35rem;
  /* The − / + buttons' height, kept even where a read-only plan has no
     buttons, so "3 nights" stays centred on the badge's line either way. */
  min-height: 1.5rem;
}

.stay-night-step {
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 2px solid var(--rule-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .95rem;
  line-height: 1;
  cursor: pointer;
}
.stay-night-step:hover:not(:disabled) {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--surface);
}
.stay-night-step:disabled { opacity: .35; cursor: default; }

@media print { .stay-night-step { display: none !important; } }
.stay-nights strong { display: block; font-size: 1rem; line-height: 1; }
.stay-nights span {
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}

.dest-code {
  padding: .1rem .45rem;
  border-radius: 5px;
  background: var(--c-azure);
  color: var(--on-color);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .12em;
}

.dest-code--europe        { background: var(--c-teal); }
.dest-code--asia          { background: var(--c-vermil); }
.dest-code--africa        { background: var(--c-amber); }
.dest-code--north-america { background: var(--c-azure); }
.dest-code--south-america { background: var(--c-violet); }
.dest-code--oceania       { background: var(--c-emerald); }

.dest-country {
  margin: .15rem 0 0;
  color: var(--muted);
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.dest-blurb { margin: .8rem 0 0; max-width: 54ch; font-size: .92rem; }

.tags { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .7rem; }

.tag {
  padding: .1rem .5rem;
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  color: var(--muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.tag--beach     { color: var(--c-teal);    border-color: var(--c-teal); }
.tag--city      { color: var(--c-azure);   border-color: var(--c-azure); }
.tag--nature    { color: var(--c-emerald); border-color: var(--c-emerald); }
.tag--culture   { color: var(--c-violet);  border-color: var(--c-violet); }
.tag--nightlife { color: var(--c-vermil);  border-color: var(--c-vermil); }
.tag--family    { color: var(--c-amber);   border-color: var(--c-amber); }

/* What you do there */
.doing {
  margin-top: 1rem;
  padding-top: .8rem;
  border-top: 2px dashed var(--rule);
}
.doing h4 {
  margin: 0 0 .5rem;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}
.doing-list { margin: 0; padding: 0; list-style: none; }
.doing-list li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: .2rem 0;
  font-size: .88rem;
}
.doing-list strong { font-weight: 700; }

.costs {
  margin-top: 1rem;
  padding-top: .7rem;
  border-top: 2px dashed var(--rule);
}

.cost-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: .15rem 0;
  color: var(--muted);
  font-size: .84rem;
}
.cost-row strong { color: var(--ink); font-weight: 700; }

.cost-subtotal {
  margin-top: .35rem;
  padding-top: .4rem;
  border-top: 1px solid var(--rule);
  color: var(--ink);
  font-weight: 700;
}

/* Grand total, styled as the tear-off stub */
.totals {
  padding: 1.3rem 1.4rem;
  border: 3px solid var(--ink);
  border-radius: 14px;
  background: var(--surface);
}
.totals h2 {
  margin: 0;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
}
.totals .costs { margin-top: .8rem; border-top: 0; padding-top: 0; }

.grand {
  margin-top: 1rem;
  padding-top: .9rem;
  border-top: 3px dashed var(--ink);
  text-align: right;
}

.stub-label {
  display: block;
  color: var(--muted);
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.stub-price {
  display: block;
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.15;
  color: var(--accent-strong);
}

.stub-note { display: block; color: var(--muted); font-size: .78rem; }

.plan-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: .5rem 1rem;             /* the notice line sits close under the buttons */
  margin-top: 1.4rem;
}
/* The footer follows the buttons closely on the plan page: the reserved
   notice line already keeps them apart. */
#plan-root + .site-footer { margin-top: 1.4rem; }

@media (max-width: 620px) {
  .leg { grid-template-columns: 2.4rem 1fr; }
  .leg-glyph { width: 2.4rem; height: 2.4rem; font-size: 1.05rem; }
  .leg-price { grid-column: 2; text-align: left; }
  .stay-nights { text-align: left; }

}

/* -------------------------------------------------------------- route map */

/* The plan page carries a map beside the itinerary, so it gets more room than
   the form page. */
#plan-root { width: min(1120px, 100%); }

.plan-body {
  display: grid;
  gap: 1.2rem;
  align-items: start;
  margin-bottom: 2rem;
}

/* Narrow: the map comes first, as an overview of what follows. */
.map-panel { order: -1; }

@media (min-width: 900px) {
  .plan-body { grid-template-columns: minmax(0, 1fr) 21rem; }
  .map-panel {
    order: 0;
    position: sticky;
    top: 1rem;
    /* A long trip makes this panel taller than the window, and a pinned
       element cannot be scrolled past — the end of the stop list and the
       button under it would simply be unreachable. So it scrolls itself. */
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

.map-panel h2 {
  margin: 0 0 .6rem;
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
}

.map-frame { position: relative; }

.map-box {
  position: relative;
  height: 20rem;
  overflow: hidden;
  border: 2px solid var(--ink);
  border-radius: 12px;
  background: var(--paper);
  cursor: grab;
  /* Drag pans the map; a vertical swipe still scrolls the page, so the map
     cannot trap a reader on a phone. */
  touch-action: pan-y;
  user-select: none;
}
.map-box.is-dragging { cursor: grabbing; }

@media (min-width: 900px) {
  .map-box { height: 26rem; }
}

/* Zoom controls, over the top-right corner of the map. */
.map-tools {
  position: absolute;
  top: .5rem;
  right: .5rem;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .3rem;
}

.map-tool {
  min-width: 2rem;
  height: 2rem;
  padding: 0 .5rem;
  border: 2px solid var(--ink);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}
.map-tool:hover:not(:disabled) { background: var(--accent); color: var(--on-color); border-color: var(--accent); }
.map-tool:disabled { opacity: .45; cursor: default; }

.map-tool--refit {
  height: auto;
  padding: .35rem .6rem;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.map-tiles { position: absolute; inset: 0; }

.map-tile {
  position: absolute;
  width: 256px;
  height: 256px;
  /* Tone the map down so the route stays the loudest thing on it. */
  opacity: .78;
  filter: saturate(.72);
}

.map-overlay {
  position: absolute;
  inset: 0;
  /* A white halo keeps the route and its labels legible over any terrain. */
  filter: drop-shadow(0 0 2px var(--surface)) drop-shadow(0 0 2px var(--surface));
}

.map-leg {
  fill: none;
  stroke: var(--c-vermil);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* A flight is a straight line because that is what it is. */
.map-leg--flight { stroke-dasharray: 8 7; }
/* So is a way of one's own, but we do not even know the route it takes. */
.map-leg--custom { stroke: var(--c-violet); stroke-dasharray: 2 6; }
/* Real roads and track are thinner: they carry their own detail. */
.map-leg--real { stroke-width: 2.6; }
/* Nothing planned for this one yet — the two places are still joined on the
   map, because the trip still goes between them; how is the open question. */
.map-leg--none { stroke: var(--muted); stroke-dasharray: 1 8; opacity: .7; }

/* The route lines are a way in to their journeys, like the pins to their
   stops. The hit line is the ink's invisible fat twin: a stroke's clickable
   area is exactly its width, and three pixels is not a target. */
.map-route { cursor: pointer; }
.map-leg-hit { fill: none; stroke: transparent; stroke-width: 16; pointer-events: stroke; }
.map-route:hover .map-leg { stroke-width: 4.4; }
.map-route:hover .map-leg--real { stroke-width: 3.8; }
.map-route:focus-visible { outline: 3px solid var(--accent-strong); outline-offset: 2px; }

/* The pins are a way in to the itinerary, not decoration. */
.map-pin { cursor: pointer; }
.map-pin:hover circle { stroke: var(--accent-strong); }
.map-pin:focus-visible { outline: 3px solid var(--accent-strong); outline-offset: 2px; }

.map-pin circle {
  fill: var(--accent);
  stroke: var(--surface);
  stroke-width: 3;
}
.map-pin--home circle { fill: var(--ink); }

.map-pin-num {
  fill: var(--on-color);
  font-family: inherit;
  font-size: .72rem;
  font-weight: 700;
}

.map-legend {
  list-style: none;
  margin: .7rem 0 0;
  padding: 0;
  display: grid;
  /* No gap: a country's box has to be one unbroken block of colour, and a gap
     between its rows would show the page through it in stripes. The rows carry
     their own breathing room in their padding. */
  gap: 0;
}

.map-legend li { display: block; }

/* The row and its remove button sit side by side, so the row can stay a button
   in its own right — one button cannot be nested in another. Qualified by the
   list because `.map-legend li` sets display on the same items and would
   otherwise win on specificity, dropping the button onto its own line. */
.map-legend .map-key-item { display: flex; align-items: center; }
.map-legend .map-key-item > .map-key-row { flex: 1 1 auto; min-width: 0; width: auto; }

.map-key-drop {
  flex: none;
  padding: .15rem .4rem;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: .9rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity .12s ease;
}
.map-key-item:hover .map-key-drop,
.map-key-drop:focus-visible { opacity: 1; }
.map-key-drop:hover { color: var(--danger); }

/* Asked before it acts, so the two answers are always visible. */
.map-key-drop-ask { display: flex; gap: .2rem; flex: none; }
.map-key-drop-ask .map-key-drop {
  opacity: 1;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.map-key-drop--yes { color: var(--danger); }
.map-key-drop--yes:hover { background: var(--danger); color: var(--surface); }

@media (hover: none) { .map-key-drop { opacity: 1; } }

.map-key-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  padding: .32rem .4rem;
  border: 0;
  border-radius: 8px;
  background: none;
  color: inherit;
  font: inherit;
  font-size: .8rem;
  text-align: left;
  cursor: pointer;
}
/* Stops that sit next to each other in the same country, boxed together with
   the country's name above them — the trip reads as its legs rather than as a
   list of seventeen cities. */
.map-country-head {
  margin-top: .45rem;
  padding: .32rem .5rem .2rem;
  border: 2px solid rgba(var(--tint), .3);
  border-bottom: 0;
  border-radius: 10px 10px 0 0;
  background: rgba(var(--tint), .1);
  color: rgb(var(--tint-ink));
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.map-key-item.in-country {
  padding: 0 .35rem;
  border-left: 2px solid rgba(var(--tint), .3);
  border-right: 2px solid rgba(var(--tint), .3);
  background: rgba(var(--tint), .1);
}
.map-key-item.country-last { padding-bottom: .25rem; }

/* The box closes under the "another place" row, not under the last city. */
.map-country-add {
  margin-bottom: .45rem;
  padding: .1rem .35rem .35rem;
  border-left: 2px solid rgba(var(--tint), .3);
  border-right: 2px solid rgba(var(--tint), .3);
  border-bottom: 2px solid rgba(var(--tint), .3);
  border-radius: 0 0 10px 10px;
  background: rgba(var(--tint), .1);
}

.map-country-add-btn {
  width: 100%;
  padding: .25rem .4rem;
  border: 2px dashed rgba(var(--tint), .35);
  border-radius: 8px;
  background: none;
  color: rgb(var(--tint-ink));
  font: inherit;
  font-size: .7rem;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
}
.map-country-add-btn:hover,
.map-country-add-btn.is-open {
  border-style: solid;
  background: var(--surface);
}

/* Below the last box: somewhere the trip does not go yet. Outside every
   country's colour, because it belongs to none of them. */
.map-country-new {
  margin: .2rem 0 .45rem;
  list-style: none;
}
.map-country-new-btn {
  width: 100%;
  padding: .3rem .5rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 10px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: .7rem;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
}
.map-country-new-btn:hover,
.map-country-new-btn.is-open {
  border-style: solid;
  background: var(--surface);
  color: var(--ink);
}

.map-country-form {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  margin-top: .4rem;
}
.map-country-form[hidden] { display: none; }
.map-country-field {
  flex: 1 1 8rem;
  min-width: 0;
  padding: .35rem .55rem;
  border: 2px solid var(--rule-strong);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .78rem;
}
.map-country-field.is-wrong { border-color: var(--danger); background: var(--danger-wash); }
/* Focus is said by the field's own border, not the page's red ring: red on
   a box you have only clicked into read as an error before anything was
   typed. */
.map-country-field:focus-visible {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(31, 41, 51, .14);
}
.map-country-form .btn-own,
.map-country-form .btn-quiet-inline { padding: .3rem .65rem; font-size: .72rem; }

/* The correction, offered as one press instead of retyping the name. */
.map-country-fix {
  margin-top: .3rem;
  padding: .3rem .7rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--ink);
  color: var(--surface);
  font: inherit;
  font-size: .74rem;
  font-weight: 700;
  cursor: pointer;
}
.map-country-fix:hover { background: var(--surface); color: var(--ink); }

/* Said in the box it is about, beside the button that was pressed, rather
   than at the top of a page the reader has scrolled a long way down. */
.map-country-error {
  margin: .35rem 0 .1rem;
  padding: .45rem .6rem;
  font-size: .74rem;
  line-height: 1.35;
}
.map-country-error:focus-visible { outline: 3px solid var(--danger); outline-offset: 2px; }

/* The number keeps the country's colour too, so a glance down the list reads
   as legs of a trip rather than seventeen unrelated dots. */
.map-key-item.in-country .map-key { background: rgb(var(--tint)); }

/* The rows hover to a lighter shade, so inside a box they need their own. */
.map-key-item.in-country .map-key-row:hover { background: rgba(255, 250, 240, .75); }

/* A stop can be dragged to a different point in the trip. */
.map-key-item.is-movable > .map-key-row { cursor: grab; }
.map-key-item.is-movable > .map-key-row:active { cursor: grabbing; }

.map-key-grip {
  /* The nights already push to the right edge; this just follows them. */
  padding-left: .4rem;
  /* The handle a finger drags by. Only here, so a swipe anywhere else on the
     row still scrolls the page. */
  touch-action: none;
  color: var(--muted);
  font-size: .9rem;
  line-height: 1;
  opacity: 0;
  transition: opacity .12s ease;
}
.map-key-row:hover .map-key-grip,
.map-key-row:focus-visible .map-key-grip { opacity: 1; }

/* Nothing hovers on a touchscreen, and a handle you cannot see is no handle. */
@media (hover: none) {
  .map-key-grip { opacity: 1; padding: .1rem .35rem; }
}

/* The one in your hand, and the gap it will drop into. */
.map-key-item.is-lifted > .map-key-row {
  background: var(--paper);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .18);
  cursor: grabbing;
}

/* Its number changes colour while it is held. The numbers renumber themselves
   as the row travels, so without this there is nothing on the badge to say
   which of them is the one you are actually moving. */
.map-key-item.is-lifted .map-key {
  background: var(--c-violet);
  box-shadow: 0 0 0 3px rgba(100, 53, 184, .3);
}
.map-key-item.is-lifted .map-key-city { color: var(--c-violet); }
.map-legend.is-reordering .map-key-item:not(.is-lifted) {
  transition: transform .12s ease;
}
.map-legend.is-reordering .map-key-row { cursor: grabbing; }

.map-legend-status {
  margin: .4rem 0 0;
  font-size: .7rem;
  line-height: 1.45;
  color: var(--muted);
}
.map-legend-status:empty { margin: 0; }

.map-legend-help {
  margin: .35rem 0 0;
  font-size: .7rem;
  line-height: 1.5;
  color: var(--muted);
}
.map-legend-help strong { color: var(--ink); font-weight: 700; }

/* Under the list of stops, because it is about the list of stops. */
.map-shorten {
  margin-top: .7rem;
  padding-top: .7rem;
  border-top: 1px dashed var(--rule);
}

.btn-shorten {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  width: 100%;
  justify-content: center;
  padding: .55rem .8rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-align: center;
  cursor: pointer;
}
.btn-shorten:hover { background: var(--ink); color: var(--surface); }

.map-shorten-note {
  margin: .45rem 0 0;
  font-size: .72rem;
  line-height: 1.45;
  color: var(--muted);
}

.map-key-row:hover { background: var(--paper); }
.map-key-row:hover .map-key-city { color: var(--accent); }

.map-key {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-color);
  font-size: .7rem;
  font-weight: 700;
}
.map-key--home { background: var(--ink); }

.map-key-city { font-weight: 700; }

/* When you are there, beside how long for. The dates take the free space so
   the two sit together at the end of the row. */
.map-key-when {
  margin-left: auto;
  color: var(--muted);
  font-size: .72rem;
  white-space: nowrap;
}

.map-key-nights {
  margin-left: auto;
  color: var(--muted);
  font-size: .72rem;
  white-space: nowrap;
}
.map-key-when + .map-key-nights { margin-left: .5rem; }

.map-credit {
  margin: .45rem 0 0;
  font-size: .68rem;
  color: var(--muted);
}
.map-credit a { color: inherit; }

/* ---------------------------------------------------------- landing page */

.wrap--wide { width: min(1080px, 100%); padding-bottom: clamp(2rem, 5vw, 3.5rem); }

.hero {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
  width: min(1080px, 100%);
  margin: 0 auto;
  padding: clamp(2.5rem, 7vw, 4.5rem) clamp(1rem, 4vw, 2rem) clamp(2rem, 6vw, 4rem);
}

@media (min-width: 880px) {
  .hero { grid-template-columns: 1.15fr .85fr; }
}

.eyebrow {
  margin: 0 0 1rem;
  color: var(--c-vermil);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
}

.hero-title {
  margin: 0 0 1rem;
  font-size: clamp(2.4rem, 7vw, 4rem);
  font-weight: 700;
  line-height: .98;
  letter-spacing: -.02em;
}

.hero-lede {
  margin: 0 0 1.8rem;
  max-width: 44ch;
  color: var(--muted);
  font-size: clamp(1rem, 2.2vw, 1.12rem);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .8rem 1.4rem;
  margin-bottom: 1rem;
}

.btn-large { padding: .95rem 2rem; font-size: .84rem; }

.btn-quiet {
  color: var(--ink);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-decoration: none;
  border-bottom: 2px solid var(--rule-strong);
  padding-bottom: .15rem;
}
.btn-quiet:hover { border-color: var(--ink); }

.hero-note { margin: 0; color: var(--muted); font-size: .8rem; }

/* The map beside the pass, a little below it, like a photo pinned next to
   a ticket. The aside leaves room at its right and foot for the overlap. */
.hero-ticket { position: relative; padding: 0 2.6rem clamp(6rem, 12vw, 7.5rem) 0; }
.hero-map {
  /* Over the pass's lower corner and hanging below it, like a photo laid
     on a ticket. */
  position: absolute;
  right: 0;
  bottom: 0;
  width: 60%;
  margin: 0;
  padding: .3rem .3rem .4rem;
  border: 3px solid var(--ink);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 6px 6px 0 var(--ink);
  transform: rotate(4deg);
}
.hero-map img { display: block; width: 100%; height: auto; border-radius: 4px; }

.hero-map figcaption {
  margin-top: .25rem;
  color: var(--muted);
  font-size: .56rem;
  letter-spacing: .04em;
  text-align: right;
}
/* The line under the pass keeps clear of the photo. */
.hero-ticket .pass-why { max-width: 38%; }

/* On a wide screen the photo sits to the right of the pass, laid a little
   over its edge, level with its middle — the aside keeps a strip free on
   its right for it, so nothing reaches past the column. */
@media (min-width: 880px) {
  /* Room for a full-width pass and a photo beside it: the hero is a little
     wider and its right column a little larger than the text's, and the
     title steps down one notch so "Get one planned." still fits its line. */
  .hero { width: min(1160px, 100%); grid-template-columns: 1fr 1.1fr; }
  /* The whole hero — words, pass and map — sits a touch right of centre:
     up to 2rem, and never more than the margin the screen leaves, so the
     map's corner stays inside the window. */
  .hero { transform: translateX(clamp(0px, calc((100vw - 1160px) / 2 - 10px), 3.5rem)); }
  .hero-title { font-size: clamp(2.2rem, 4.9vw, 3.6rem); }
  .hero-ticket { padding: 20px 35% 0 0; }
  .hero-map { right: 0; bottom: auto; top: calc(24% + 20px); width: 40%; transform: rotate(5deg); }
  .hero-ticket .pass-why { max-width: 100%; }
}

/* The boarding pass, as the product shot */
.pass {
  --pad: 1.3rem;
  border: 3px solid var(--ink);
  border-radius: 18px;
  background: var(--surface);
  padding: 0 var(--pad);
  transform: rotate(-1.4deg);
  box-shadow: 10px 12px 0 rgba(31, 41, 51, .12);
}

.pass-head {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin: 0 calc(-1 * var(--pad));
  padding: .55rem 1.1rem;
  border-bottom: 2px dashed var(--rule-strong);
  border-radius: 15px 15px 0 0;
  background: var(--accent-strong);
  color: var(--on-color);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.pass-route {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .8rem;
  padding: 1.4rem 0 1.1rem;
}
.pass-code { font-size: 2.1rem; font-weight: 700; letter-spacing: .04em; }
/* Whole names rather than three-letter codes: a size down, so "Lisbon →
   Rome" keeps to one line on the pass. */
.pass-route--names .pass-code { font-size: 1.55rem; letter-spacing: .02em; text-transform: uppercase; }
.pass-route--names .pass-arrow { font-size: 1.2rem; }
.pass-arrow { color: var(--c-vermil); font-size: 1.5rem; }

.pass-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .9rem;
  margin: 0;
  padding: 1rem 0;
  border-top: 2px dashed var(--rule);
  border-bottom: 2px dashed var(--rule);
}
.pass-grid dt {
  color: var(--muted);
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.pass-grid dd { margin: .2rem 0 0; font-weight: 700; }

/* Why this particular trip is on the pass. Quiet, but not hidden. */
.pass-why {
  margin: .6rem .2rem 0;
  color: var(--muted);
  font-size: .72rem;
  line-height: 1.45;
  text-align: center;
}

.pass-total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 0;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}
.pass-total strong {
  color: var(--c-vermil);
  font-size: 1.7rem;
  letter-spacing: 0;
  text-transform: none;
}

.pass .barcode { margin: 0 calc(-1 * var(--pad)); }

/* Sections */
.band { padding: clamp(2rem, 5vw, 3rem) 0; }
.band--tint { background: var(--surface); border-block: 3px solid var(--ink); }

.section-title {
  margin: 0 0 1.6rem;
  font-size: clamp(1.5rem, 3.5vw, 2.1rem);
  font-weight: 700;
  letter-spacing: -.01em;
}

.cards {
  display: grid;
  gap: 1rem;
  /* Wide enough that six cards land as two rows of three rather than four and
     a ragged two. */
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
}

.feature {
  padding: 1.4rem 1.3rem;
  border: 2px solid var(--ink);
  border-radius: 14px;
  background: var(--surface);
}
.band--tint .feature { background: var(--paper); }

.feature-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.6rem;
  height: 2.6rem;
  margin-bottom: .9rem;
  border-radius: 10px;
  background: var(--accent);
  color: var(--on-color);
  font-size: 1.2rem;
}
.feature-icon--stay  { background: var(--c-emerald); }
.feature-icon--map   { background: var(--c-teal); }
.feature-icon--money { background: var(--c-vermil); font-weight: 700; }

.feature h3 { margin: 0 0 .5rem; font-size: 1.05rem; }
.feature p { margin: 0; color: var(--muted); font-size: .88rem; }

/* Steps */
.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  /* Four steps, two by two — three and a lonely fourth reads as a mistake. */
  grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
  counter-reset: none;
}
.steps li {
  padding: 1.4rem 1.3rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 14px;
  background: var(--paper);
}
.steps .step { margin-bottom: .9rem; }
.steps h3 { margin: 0 0 .5rem; font-size: 1.05rem; }
.steps p { margin: 0; color: var(--muted); font-size: .88rem; }

/* On a phone the two grids are one column, and a column that can shrink:
   the desk-side minimums above (19rem, 22rem) are wider than a 360px
   phone, and a grid cell that will not shrink pushes the whole page out
   sideways — the one thing a phone page must never do. The cards give a
   little padding and type back, so a screen shows more than one of them. */
@media (max-width: 620px) {
  .cards, .steps { grid-template-columns: minmax(0, 1fr); gap: .8rem; }
  .feature, .steps li { padding: 1.1rem 1rem; }
  .feature h3, .steps h3 { font-size: .98rem; }
  .feature p, .steps p { font-size: .84rem; }
  .feature-icon { width: 2.2rem; height: 2.2rem; margin-bottom: .7rem; font-size: 1.05rem; }

  /* The "evening's work" piece: two paragraphs and a list of claims that
     read as an essay on a desk and as a wall on a phone. A step down in
     size, and the section titles across the page with it. */
  /* The sign-in and register pages: a form that should fit a phone screen
     without a scroll, which on the login page means the whole thing —
     header, title, two fields, two buttons, footer — inside 640px. Every
     band gives a little: the title, the ticket strip, the field padding,
     the buttons' row (the Google button says just "Google" here, so both
     buttons share one line), the barcode, the footer. */
  .auth { padding-top: .7rem; }
  .auth h1 { font-size: 1.6rem; margin-bottom: .1rem; }
  .auth .lede { margin-bottom: .7rem; font-size: .85rem; }
  .auth .card::before { padding: .3rem .9rem; font-size: .56rem; }
  .auth .field { padding: .6rem 0; }
  .auth .field legend { margin-bottom: .35rem; font-size: .66rem; }
  .auth .field legend .step { font-size: .6rem; padding: .1rem .35rem; }
  .auth .card input[type="email"],
  .auth .card input[type="password"] { padding: .45rem .7rem; font-size: .92rem; }
  .auth .field .hint { margin-top: .25rem; font-size: .7rem; }
  .auth .hint--wide { display: none; }
  .auth .agree-row { font-size: .8rem; gap: .5rem; }
  .auth .actions { padding: .6rem 0 .5rem; }
  .auth .btn-primary { padding: .6rem 1.4rem; font-size: .74rem; }
  .auth .btn-google--small { padding: .5rem .8rem; font-size: .64rem; }
  .auth .auth-alt { margin-top: .2rem; font-size: .8rem; }
  .auth .barcode { height: 14px; }
  .auth .when-wide { display: none; }
  .auth .when-narrow { display: inline; }

  /* Register has twice the fields of login and the same screen to fit:
     the sentence under the title goes (the title says it), the hints under
     the password boxes go (the browser holds the minimum length itself),
     the terms sentence is its short form, and each band is a little
     tighter than login's. */
  .auth-register .lede { display: none; }
  .auth-register h1 { margin-bottom: .5rem; }
  .auth-register .field { padding: .45rem 0; }
  .auth-register .card input[type="email"],
  .auth-register .card input[type="password"] { padding: .4rem .7rem; }
  .auth-register .actions { padding: .5rem 0 .4rem; }

  /* Settings on a phone: the same step down as the sign-in pages, card by
     card. The account facts go two abreast instead of one under another,
     the notes and hints a size smaller, every field and button tighter,
     the ticket strips and barcodes thinner. Nothing is removed: the page
     is the same page at two thirds the height. */
  .settings h1 { font-size: 1.45rem; margin-bottom: .1rem; }
  .settings .lede { font-size: .82rem; margin-bottom: .8rem; }
  .settings .account { margin-bottom: .9rem; padding: .75rem .9rem; }
  .settings .account-head h2 { font-size: .98rem; }
  .settings .tier-badge { padding: .18rem .55rem; font-size: .56rem; }
  /* One fact per line, the label on the left and the value on the right,
     so nothing has a column to overflow: two columns put "Member since"
     and "Signing in" over the card's edge on a 360px phone, and the
     "not confirmed — resend the link" line, which may not break, needs
     the whole width. */
  .settings .account-facts { grid-template-columns: 1fr; gap: .3rem; margin-bottom: .5rem; }
  .settings .account-facts > div { display: flex; justify-content: space-between; align-items: baseline; gap: .8rem; min-width: 0; }
  .settings .account-facts dt { flex: 0 0 auto; font-size: .58rem; }
  .settings .account-facts dd { margin: 0; min-width: 0; text-align: right; font-size: .8rem; overflow-wrap: anywhere; }
  .settings .account-unverified { white-space: normal; font-size: .74rem; }
  .settings .account-sub { font-size: .74rem; }
  .settings .account-note { padding-top: .5rem; font-size: .72rem; line-height: 1.45; }
  .settings .settings-card { margin-top: .7rem; }
  .settings .card::before { padding: .28rem .85rem; font-size: .54rem; }
  .settings .card-lead, .settings .card h2 { font-size: 1rem; margin-bottom: .25rem; }
  .settings .card .lede, .settings .card > p { font-size: .8rem; margin-bottom: .6rem; }
  .settings .field { padding: .6rem 0; }
  .settings .field legend { margin-bottom: .35rem; font-size: .66rem; }
  .settings .field legend .step { font-size: .58rem; padding: .1rem .32rem; }
  .settings .control-label { font-size: .66rem; }
  .settings .card input[type="email"],
  .settings .card input[type="password"],
  .settings .control input,
  .settings .control select { padding: .42rem .65rem; font-size: .88rem; }
  .settings .hint { margin-top: .25rem; font-size: .7rem; }
  .settings .agree-row { font-size: .78rem; }
  .settings .actions { padding: .55rem 0 .4rem; }
  .settings .btn-primary, .settings .btn-danger { padding: .55rem 1.2rem; font-size: .68rem; box-shadow: 3px 3px 0 var(--ink); }
  .settings .barcode { height: 12px; }

  /* Premium on a phone: three plan cards in a column, each tight enough
     that a card and a half show at once — the reader compares by
     scrolling, so the less each card costs in height the easier the
     comparison. The price stays the biggest thing on the card; the list
     of what it buys and the notes step down; the buy button spans the
     card, which is where a thumb expects it. */
  .premium-page h1 { font-size: 1.45rem; margin-bottom: .1rem; }
  .premium-page .lede { font-size: .82rem; margin-bottom: .6rem; }
  .premium-page .alert { padding: .6rem .8rem; font-size: .8rem; }
  .premium-page .plans { gap: .7rem; margin: .9rem 0; }
  .premium-page .plan { gap: .35rem; padding: .85rem .95rem; box-shadow: 3px 3px 0 var(--ink); }
  .premium-page .plan--best { box-shadow: 3px 3px 0 var(--c-amber); }
  .premium-page .plan-head h2 { font-size: .98rem; }
  .premium-page .plan-tag { padding: .12rem .5rem; font-size: .56rem; }
  .premium-page .plan-price { margin-top: .1rem; }
  .premium-page .plan-amount { font-size: 1.6rem; }
  .premium-page .plan-cadence { font-size: .72rem; }
  .premium-page .plan-per { font-size: .72rem; }
  .premium-page .plan-list { margin-top: .4rem; gap: .25rem; }
  .premium-page .plan-list li { font-size: .78rem; padding-left: 1.2rem; }
  .premium-page .plan-note { font-size: .72rem; }
  .premium-page .plan-buy { width: 100%; margin-top: .6rem; padding: .65rem 1rem; font-size: .72rem; box-shadow: 3px 3px 0 var(--ink); }
  .premium-page .plan-keep { margin: 1rem 0 .7rem; padding: .75rem .85rem; font-size: .78rem; line-height: 1.45; }
  .premium-page .plan-footnote { margin-bottom: .9rem; font-size: .72rem; line-height: 1.45; }

  /* The reading pages — FAQ, privacy, terms, contact — on a phone: the
     title on one line, prose a size down, and the contents row as chips a
     thumb can hit, in one row that scrolls sideways within itself (the
     page never does). The FAQ's folded questions get a row height a
     finger expects and answers at reading size. */
  .legal h1 { font-size: 1.45rem; margin-bottom: .1rem; }
  .legal .lede { font-size: .85rem; margin-bottom: .8rem; }
  .legal section { margin-top: 1.3rem; }
  /* main.legal, not .legal: the page's own h2 rule is further down the
     file and would otherwise win the tie. */
  main.legal h2 { font-size: 1rem; margin-bottom: .4rem; }
  .legal p, .legal li { font-size: .86rem; line-height: 1.55; }
  /* Contact: the two cards tighter, and the addresses kept as the biggest
     thing on them — the phone-size prose rule above would otherwise pull
     them down to body size. */
  .legal .contact-cards { gap: .7rem; margin-top: .9rem; }
  .legal .contact-card { padding: .8rem .9rem; }
  .legal .contact-card h2 { font-size: 1rem; }
  .legal .contact-address { font-size: 1.02rem; font-weight: 700; }
  /* Written as .legal .legal-toc: the page's own rules for the box and
     for links are further down the file and would otherwise win the tie. */
  .legal .legal-toc { flex-wrap: wrap; gap: .35rem; margin-top: .6rem; padding: .55rem .6rem; }
  .legal .legal-toc a {
    flex: 0 0 auto;
    min-height: 36px;
    display: inline-flex;
    align-items: center;
    padding: 0 .65rem;
    border: 2px solid var(--rule-strong);
    border-radius: 999px;
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
  }
  .faq-item { margin: .4rem 0; }
  .faq-item summary { min-height: 44px; padding: .55rem .8rem; font-size: .9rem; line-height: 1.3; }
  .faq-item p { padding: 0 .8rem .7rem; font-size: .84rem; }

  /* The start form on a phone. Seven questions in one column: every band
     steps down a size, the sixteen interests go two abreast so that
     question is half as tall, and the actions bar sticks to the foot of
     the screen while the form scrolls past — with the button always in
     reach and a line above it saying what has been chosen so far. */
  .start-page h1 { font-size: 1.45rem; margin-bottom: .1rem; }
  .start-page .lede { font-size: .85rem; margin-bottom: .8rem; }
  .start-page .card::before { padding: .3rem .9rem; font-size: .56rem; }
  .start-page .field { padding: .9rem 0; }
  .start-page .field legend { margin-bottom: .55rem; font-size: .7rem; }
  .start-page .field legend .step { font-size: .6rem; padding: .1rem .35rem; }
  .start-page .hint { margin-top: .4rem; font-size: .72rem; }
  .start-page .hint--tight { font-size: .7rem; }
  .start-page .options { gap: .4rem; }
  .start-page .option { padding: .6rem .8rem .6rem 2.6rem; }
  .start-page .option::before { left: .8rem; }
  .start-page .option::after { left: 1.24rem; }
  .start-page .option-title { font-size: .84rem; }
  .start-page .option-sub { font-size: .76rem; }
  .start-page .options--interests { grid-template-columns: 1fr 1fr; gap: .35rem; }
  .start-page .option--interest { padding: .5rem .5rem .5rem 2.2rem; min-height: 42px; display: flex; align-items: center; }
  .start-page .option--interest::before { left: .6rem; }
  .start-page .option--interest::after { left: 1.04rem; }
  .start-page .option--interest .option-title { font-size: .72rem; letter-spacing: .03em; }
  .start-page .option-icon { font-size: 1em; margin-right: .25rem; }
  /* Three of the questions as rows of plain chips rather than stacked
     cards: "how far" as a pair, "how" as two by two with only the four
     names, "how much" as three across saying Cheap, Mid-range, Expensive.
     No tick box drawn on these — the blue fill is the answer, and the
     room the box took is what lets three fit a 360px screen. */
  .start-page .options--reach { grid-template-columns: 1fr 1fr; }
  .start-page .options--transport { grid-template-columns: 1fr 1fr; }
  .start-page .options--price { grid-template-columns: 1fr 1fr 1fr; }
  .start-page .options--reach .option,
  .start-page .options--transport .option,
  .start-page .options--price .option {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 46px;
    padding: .5rem .4rem;
    text-align: center;
  }
  .start-page .options--reach .option::before,
  .start-page .options--reach .option::after,
  .start-page .options--transport .option::before,
  .start-page .options--transport .option::after,
  .start-page .options--price .option::before,
  .start-page .options--price .option::after { display: none; }
  .start-page .options--reach .option-sub,
  .start-page .options--transport .option-sub,
  .start-page .options--price .price-mark,
  .start-page .options--price .price-blurb { display: none; }
  .start-page .options--reach .option-title,
  .start-page .options--transport .option-title { font-size: .76rem; line-height: 1.2; }
  .start-page .options--transport .option-icon { display: none; }
  .start-page .options--price .option-sub { margin: 0; color: inherit; }
  .start-page .options--price .price-name {
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
  }
  .start-page .follow-up, .start-page .party-detail { margin-top: .6rem; padding: .7rem .8rem; }
  .start-page .origin-search-row input,
  .start-page input[type="number"],
  .start-page input[type="date"] { padding: .5rem .7rem; font-size: .95rem; }
  .start-page .want-chip { font-size: .78rem; }
  /* The ticket's tear line (dashed rule, two punched holes) sits right
     above the button — which on a phone rides at the foot of the screen,
     so the tear would ride mid-form with it. The bar's own top edge and
     shadow do the separating here. */
  .start-page .perf { display: none; }
  /* And the last question's dashed underline, for the same reason: the
     bar's edge is right beneath it, and two rules is one too many. */
  .start-page .field:last-of-type { border-bottom: 0; padding-bottom: .5rem; }
  .start-page .actions {
    position: sticky;
    bottom: 0;
    z-index: 3;
    margin: .4rem calc(-1 * var(--pad)) 0;
    padding: .5rem var(--pad) .6rem;
    background: var(--surface);
    border-top: 2px solid var(--rule);
    box-shadow: 0 -10px 18px -14px rgba(0, 0, 0, .45);
  }
  .start-page .actions .btn-primary { width: 100%; padding: .75rem 1rem; font-size: .78rem; }
  .start-page .form-summary {
    display: block;
    margin: 0 0 .4rem;
    color: var(--muted);
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .start-page .form-summary:empty { display: none; }

  /* The plan on a phone (mobile.md, step 2). The shortlists already fold
     to three; what costs the height is the bands around them — a 147 px
     stay header that pins to the top, a 545 px map, option rows whose
     small print wraps to three lines because the price sits beside it
     in a column of its own. So: the pinned header a third the height and
     shedding its region line and chips while pinned; the map shorter;
     prices stacked under their own estimate so the name column has the
     width; every band a size down; the small controls up to a thumb.
     Every rule carries #plan-root: the page's own rules for these classes
     are written further down the file and would otherwise win the tie. */
  #plan-root .plan-summary { margin-bottom: 1rem; padding: .9rem .95rem; }
  #plan-root .plan-summary h1 { margin-bottom: .4rem; font-size: 1.2rem; }
  #plan-root .chips { gap: .25rem; }
  #plan-root .chip { padding: .08rem .42rem; border-width: 1.5px; font-size: .56rem; letter-spacing: .06em; }
  /* "rename" is a pencil on a phone: the word cost a line of the title. */
  #plan-root .plan-title-name .stay-swap-hint { padding: .1rem .4rem; font-size: .95rem; line-height: 1.1; }
  #plan-root .plan-title-sub { font-size: .68rem; }
  #plan-root .plan-title-name .when-wide { display: none; }
  #plan-root .plan-title-name .when-narrow { display: inline; }
  #plan-root .summary-print .btn-print { padding: .35rem .8rem; font-size: .64rem; }
  #plan-root .notice { margin-bottom: .8rem; padding: .6rem .8rem; font-size: .8rem; }

  #plan-root .map-box { height: 15rem; }
  #plan-root .map-key-row { padding: .25rem .3rem; }
  #plan-root .map-key-city { font-size: .9rem; }

  #plan-root .stay { padding: .9rem .9rem 1rem; }
  /* One layout for the stop header on a phone, pinned or not: a small grid
     — the code and the city on the first row, the country and continent
     together on the second row under the code, the nights, the − / + and
     the days in their own column on the right spanning both rows. Same
     padding and type in both states, so pinning changes nothing but the
     shadow line beneath: a header that re-arranged itself as it pinned
     changed height, and the card jumped with it. The titles wrapper is
     dissolved (display: contents) so its two children can take grid
     areas; the name may break, and a long one-word name may break inside
     the word, so the header can never grow wider than the card. */
  #plan-root .stay { min-width: 0; }
  #plan-root .stay-head,
  #plan-root .stay-head.is-stuck {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "code name nights" "country country nights";
    align-items: center;
    column-gap: .6rem;
    row-gap: .1rem;
    margin: -.9rem -.9rem 0;
    max-width: calc(100% + 1.8rem);
    padding: .55rem .9rem .45rem;
    /* The pinned state's underline, drawn transparent at rest: the last
       two pixels of height difference between the two states. */
    border-bottom: 2px solid transparent;
  }
  #plan-root .stay-head.is-stuck { border-bottom-color: var(--rule); }
  #plan-root .stay-head .stay-titles { display: contents; }
  #plan-root .stay-head .dest-code { grid-area: code; }
  #plan-root .stay-head .stay-name { grid-area: name; min-width: 0; }
  /* break-word, never anywhere: "anywhere" makes a word's minimum width
     one letter, and the name sits in a flex row beside the "change" pill,
     so a squeezed row could — and on a real phone did — shrink the name
     to a column of single letters. break-word only breaks a word that is
     actually overflowing, and the name takes the row's spare width. */
  #plan-root .stay-head .stay-name { flex-wrap: wrap; align-items: baseline; gap: .2rem .5rem; }
  #plan-root .stay-head h2 { flex: 1 1 auto; min-width: 0; font-size: 1.1rem; overflow-wrap: break-word; }

  #plan-root .stay-head .dest-country {
    grid-area: country;
    display: block;
    margin: 0;
    font-size: .58rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  #plan-root .stay-head .stay-nights { grid-area: nights; align-self: start; margin-left: 0; flex: none; }
  #plan-root .stay-nights strong { font-size: .9rem; }
  #plan-root .stay-nights span { font-size: .62rem; }
  #plan-root .stay-night-step { width: 1.5rem; height: 1.5rem; font-size: .85rem; }
  #plan-root .stay-nights-count { gap: .25rem; }
  #plan-root .stay-head .chips { display: none; }
  /* The phone header is a grid; the button takes the corner, level with
     the first line. */
  #plan-root .stay-head,
  #plan-root .stay-head.is-stuck { padding-right: 2.6rem; }   /* pinned too: the grid above resets the shorthand */
  #plan-root .stay-fold { position: absolute; top: .55rem; right: .5rem; margin: 0; width: 1.5rem; height: 1.5rem; font-size: 1rem; }
  #plan-root .stay-folded-row { grid-template-columns: 4.6rem minmax(0, 1fr); font-size: .8rem; }
  /* The "change" pill is a hint, not the control — the name itself opens
     the change panel — and on a phone it wrapped under the name at rest
     and was hidden when pinned, which was the last of the height
     difference between the two states. Off in both, and the name has the
     row's width. */
  #plan-root .stay-head .stay-swap-hint { display: none; }
  #plan-root .stay h3 { font-size: .68rem; }

  /* The day tabs (meals, things to do) and the hotel's night tabs: one
     row that scrolls sideways within itself rather than wrapping into
     two or three pinned rows. Swipe left for the first days of the stay,
     right for the later ones; the chosen day is scrolled into view by
     plan.js after every render. The scrollbar is hidden — the row is the
     affordance — and the bar's edges fade into the card. */
  #plan-root .meal-days {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    padding: .25rem 0;
    gap: .25rem;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  #plan-root .meal-days::-webkit-scrollbar { display: none; }
/* …and the sections that hold a row may shrink below their contents. */
.meals, .doing, .lodging, .stay, .stay-body { min-width: 0; }
  #plan-root .meal-days--marked { padding-bottom: 1.1rem; }
  #plan-root .meal-day { flex: 0 0 auto; scroll-snap-align: start; }
  #plan-root .lodging-nights .meal-day { max-width: 9rem; }
  #plan-root .meal-day { padding: .3rem .5rem; }
  #plan-root .meal-day-num, #plan-root .meal-day-cost { font-size: .68rem; }
  #plan-root .meal-label { font-size: .64rem; }
  /* The meal toggles — Breakfast, Lunch, Dinner, any meal of your own and
     "+ Add a meal" — as one row that scrolls sideways, like the day tabs,
     rather than wrapping into two or three. */
  #plan-root .meal-slots {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    gap: .35rem;
    padding-bottom: .2rem;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  #plan-root .meal-slots::-webkit-scrollbar { display: none; }
  #plan-root .meal-slots > * { flex: 0 0 auto; scroll-snap-align: start; white-space: nowrap; }
  #plan-root .meal-slot-add .meal-own-name { flex-basis: 9rem; }
  /* A restaurant or a thing to do as two tight lines, never five: the
     name and the price on the first, the kind and distance and the
     estimate on the second, each cut with an ellipsis rather than wrapped
     — a name that does not fit is still recognisable from its start, and
     the row stays a row. The link to the place's site is a small square at
     the end, still 32 px to tap. Hotels keep their card: they carry more
     to read and there are only a few of them. */
  #plan-root .meal-option,
  #plan-root .doing-option {
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    align-items: center;
    gap: .25rem .4rem;
    padding: .28rem .15rem;
    font-size: .82rem;
  }
  #plan-root .meal-name, #plan-root .doing-name { gap: 0; }
  #plan-root .meal-title, #plan-root .doing-title {
    font-size: .82rem;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  #plan-root .meal-kind, #plan-root .doing-kind {
    font-size: .58rem;
    line-height: 1.25;
    letter-spacing: .02em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  #plan-root .meal-price, #plan-root .doing-price {
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: baseline;
    gap: 0 .2rem;
    text-align: right;
    font-size: .86rem;
    line-height: 1.2;
  }
  #plan-root .meal-price > :first-child, #plan-root .doing-price > :first-child { flex-basis: 100%; }
  #plan-root .meal-each, #plan-root .doing-est { font-size: .56rem; white-space: nowrap; }
  #plan-root .meal-own-name, #plan-root .meal-own-price { font-size: .82rem; }

  /* A hotel card as three rows rather than four: the name (stars beside
     it), then the kind and distance with the $-band at the end of that
     line — under the Site/Map badge, not on a row of its own — then the
     rate. The name block is dissolved (display: contents) so its pieces
     can take grid areas. The "somewhere of your own" card is a form and
     keeps its own shape. */
  #plan-root .lodging-option:not(.lodging-option--own) {
    position: relative;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "name stars" "meta meta" "rate rate";
    align-items: center;
    gap: .1rem .4rem;
    padding: .5rem 3.7rem .5rem .6rem;
  }
  #plan-root .lodging-option:not(.lodging-option--own) .lodging-name { display: contents; }
  #plan-root .lodging-option:not(.lodging-option--own) .lodging-name strong { grid-area: name; flex: none; }
  #plan-root .lodging-option:not(.lodging-option--own) .lodging-stars { grid-area: stars; justify-self: end; }
  #plan-root .lodging-option:not(.lodging-option--own) .lodging-meta { grid-area: meta; }
  /* The band's placement under the badge is in the base rules; the phone
     badge is taller (30 px), so the band sits a little lower here. */
  #plan-root .lodging-slot:has(.lodging-look) .lodging-option:not(.lodging-option--own) .lodging-band { top: 2.75rem; }
  #plan-root .lodging-option:not(.lodging-option--own) .lodging-rate { grid-area: rate; }
  #plan-root .lodging-option--own { padding: .5rem .6rem; }
  #plan-root .lodging-name strong { font-size: .88rem; }
  #plan-root .lodging-meta { font-size: .7rem; }
  #plan-root .lodging-rate { font-size: .78rem; }
  #plan-root .lodging-look { min-height: 30px; padding: .3rem .5rem; font-size: .6rem; }
  #plan-root .doing-link {
    width: 32px;
    height: 32px;
    margin-left: 0;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .8rem;
  }

  #plan-root .leg { grid-template-columns: 2.2rem 1fr; gap: .5rem .7rem; padding: .7rem .8rem; }
  #plan-root .leg-day, #plan-root .leg-route { padding-right: 1.9rem; }
  #plan-root .leg-price { padding-top: 0; align-self: auto; }
  /* Folded on a phone, the price stands under the fold button in the
     card's corner rather than below the description; the body keeps
     clear of it on the right. */
  #plan-root .leg.is-folded .leg-price { position: absolute; top: 2.5rem; right: .8rem; text-align: right; }
  #plan-root .leg.is-folded .leg-body { padding-right: 4.8rem; }
  #plan-root .leg.is-folded .leg-day, #plan-root .leg.is-folded .leg-route { padding-right: 0; }
  #plan-root .leg-fold { top: .6rem; right: .55rem; width: 1.5rem; height: 1.5rem; font-size: 1rem; }
  /* The sentence wraps to two lines on a phone: both are reserved. */
  #plan-root .plan-actions .print-upsell { min-height: 3em; }
  #plan-root .plan-actions { row-gap: .7rem; }
  #plan-root + .site-footer { margin-top: 1rem; }
  /* "Or travel by": the ways of doing a leg as a two-by-two grid of small
     boxes — the glyph, the name and the price, no journey time and no "you
     say what" under "Some other way" — so four ways fit two rows instead of
     four. The time is still on the leg card above once a way is chosen. */
  #plan-root .leg-options-row { display: grid; grid-template-columns: 1fr 1fr; gap: .35rem; }
  #plan-root .leg-option {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: .35rem;
    min-height: 40px;
    padding: .4rem .55rem;
    font-size: .74rem;
  }
  #plan-root .leg-option-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  #plan-root .leg-option-time, #plan-root .leg-option-note { display: none; }

  #plan-root .btn-more { min-height: 40px; padding: .4rem .8rem; font-size: .68rem; }
  #plan-root .departure-link { min-height: 32px; display: inline-flex; align-items: center; }
  #plan-root .map-key-row { min-height: 36px; }
  #plan-root .summary-print .btn-print { min-height: 34px; }
  #plan-root .btn-share--icon { width: 34px; height: 34px; }
  #plan-root .plan-summary > .btn-share--icon { top: .8rem; right: .8rem; }
  /* The drawer's − / + stays in its title row on a phone: the stop header's
     corner positioning is not for it. */
  #plan-root .controls-fold { position: static; width: 1.5rem; height: 1.5rem; margin: 0 0 0 .2rem; }
  #plan-root .controls-title .controls-fold:only-of-type { margin-left: auto; }
  /* Folded on a phone: the title and the − / + on the first row, the
     nights · places · countries line under them, in smaller type. */
  #plan-root .controls-title { flex-wrap: wrap; row-gap: .15rem; }
  #plan-root .controls .controls-title h2 { flex: 1 1 auto; }
  #plan-root .controls-title .controls-fold { order: 2; margin-left: auto; }
  #plan-root .controls-title .controls-hint { order: 3; flex: 1 1 100%; margin-left: 0; font-size: .66rem; white-space: normal; }
  #plan-root .plan-title { padding-right: 2.6rem; }
  #plan-root .price-basis-btn { min-height: 32px; }
  #plan-root .totals { padding: .9rem .95rem; }
  #plan-root .cost-row { font-size: .8rem; gap: .6rem; }
  #plan-root .check { margin-top: 1rem; padding: .8rem .9rem; }
  #plan-root .check-item { font-size: .82rem; }

  /* The footer, on every phone page: the links are the point. The
     estimates sentence is said on the plan itself, beside the figures;
     the 3rem of air above and below was a desk's. */
  .site-footer { margin-top: 1rem; padding: .8rem 1rem 1rem; }
  .footer-note { display: none; }

  .section-title { font-size: 1.35rem; line-height: 1.2; }
  .split p { font-size: .9rem; }
  .split .split-lede { font-size: .95rem; }
  .claims { padding: 1rem .9rem; }
  /* ul.claims, not .claims: the list's own rule is written further down the
     file and would otherwise win the tie. */
  ul.claims li { font-size: .84rem; }
}

/* Split feature */
.split {
  display: grid;
  gap: clamp(1.4rem, 4vw, 2.6rem);
  align-items: start;
}
@media (min-width: 820px) {
  .split { grid-template-columns: 1.1fr .9fr; }
}
.split-lede { margin: 0 0 1rem; font-size: 1.05rem; }
.split p { color: var(--muted); }
.split .split-lede { color: var(--ink); }

.claims {
  list-style: none;
  margin: 0;
  padding: 1.2rem 1.3rem;
  border: 2px solid var(--ink);
  border-radius: 14px;
  background: var(--surface);
  display: grid;
  gap: .8rem;
}
.claims li {
  padding-left: 1.6rem;
  position: relative;
  font-size: .88rem;
  color: var(--muted);
}
.claims li::before {
  content: "✓";
  position: absolute;
  left: 0;
  top: 0;
  color: var(--c-emerald);
  font-weight: 700;
}
.claims strong { color: var(--ink); }

/* Closing call to action */
.band--cta { background: var(--accent); border-top: 3px solid var(--ink); color: var(--on-color); }
.cta { text-align: center; padding-top: clamp(1.5rem, 4vw, 2.5rem); }
.cta h2 { margin: 0 0 .5rem; font-size: clamp(1.7rem, 4.5vw, 2.6rem); }
.cta p { margin: 0 0 1.6rem; opacity: .9; }
.band--cta .btn-primary {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--ink);
  transition: background-color .15s ease, color .15s ease;
}
/* Same specificity as the generic hover and later in the file, so without
   this the cream override would win and the button would never react. */
.band--cta .btn-primary:hover,
.band--cta .btn-primary:focus-visible {
  background: var(--ink);
  color: var(--surface);
}

/* --------------------------------------------- real departures on a leg --
   The operators' own timetable, shown under the leg it belongs to. Visually
   distinct from our estimates, because one is a fact and the other is not. */

.leg--has-departures {
  /* A row per thing, and never two things sharing one: the flight editor had
     been given the same "opts" area as the ways-to-travel row, so the two were
     laid one on top of the other and the buttons came out above the options
     they belong under. */
  grid-template-areas:
    "glyph body price"
    "opts  opts opts"
    "air   air  air"
    "find  find find"
    "dep   dep  dep";
}
.leg--has-departures > .leg-glyph { grid-area: glyph; }
.leg--has-departures > .leg-body  { grid-area: body; }
.leg--has-departures > .leg-price { grid-area: price; }

/* The way out to real fares, on every flight card. */
.leg-search {
  grid-area: find;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: .8rem;
  padding-top: .8rem;
  border-top: 2px dashed var(--rule);
}
.leg-search-when {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .72rem;
  font-weight: 700;
  color: var(--muted);
}

.departures {
  grid-area: dep;
  margin-top: .9rem;
  padding-top: .8rem;
  border-top: 2px dashed var(--rule);
}

.departures-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin: 0 0 .6rem;
}

.departures-live {
  padding: .16rem .5rem;
  border-radius: 4px;
  background: var(--c-emerald);
  color: var(--on-color);
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* Looked, found nothing: stated plainly, not dressed up as live data. */
.departures-live--none {
  background: none;
  border: 2px solid var(--rule-strong);
  color: var(--muted);
  padding: .1rem .45rem;
}
.departures--none .departures-note { margin-top: 0; }
.departures--none .btn-quiet-inline { margin-top: .5rem; }

.departures-date {
  color: var(--muted);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.departures-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .4rem;
}

.departures-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .3rem .7rem;
  padding: .45rem .6rem;
  border: 2px solid var(--rule);
  border-radius: 8px;
  background: var(--paper);
  font-size: .82rem;
}

.departure-time { font-weight: 700; font-variant-numeric: tabular-nums; }
.departure-who { color: var(--muted); }

.departure-platform {
  color: var(--muted);
  font-size: .72rem;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.departure-fare { font-weight: 700; color: var(--c-emerald); }

.departure-link {
  margin-left: auto;
  padding: .2rem .6rem;
  border: 2px solid var(--accent);
  border-radius: 999px;
  color: var(--accent);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}
.departure-link:hover { background: var(--accent); color: var(--on-color); }

.departures-note {
  margin: .6rem 0 0;
  color: var(--muted);
  font-size: .72rem;
  line-height: 1.45;
}

.departure-direct {
  color: var(--c-emerald);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.departure-change {
  color: var(--c-amber);
  font-size: .72rem;
  font-weight: 700;
}

/* A flight leg: the airports, and a search when nobody will sell us a fare. */
.flight-route {
  margin: 0 0 .7rem;
  font-size: .84rem;
  color: var(--muted);
}
.flight-route strong {
  color: var(--ink);
  font-size: .95rem;
  letter-spacing: .04em;
}

.btn-search {
  display: inline-block;
  padding: .5rem 1rem;
  border: 2px solid var(--accent);
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-color);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-decoration: none;
}
.btn-search:hover { filter: brightness(1.1); }

/* The run to an airport gets no styling of its own. It was drawn quieter than
   the flight it serves — paler ground, smaller name — on the reasoning that
   nobody chose it. But it is a journey with a ticket, a departure time and a
   choice of how to make it, and two cards side by side in different colours
   read as two kinds of thing rather than as one trip. It is a leg; it looks
   like a leg. */

/* Who actually flies this, or that nobody does. */
.leg-service {
  margin: .45rem 0 0;
  color: var(--muted);
  font-size: .76rem;
  line-height: 1.45;
}

.leg-service-badge {
  display: inline-block;
  margin-right: .35rem;
  padding: .12rem .45rem;
  border-radius: 4px;
  background: var(--c-emerald);
  color: var(--on-color);
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.leg-service--change .leg-service-badge { background: var(--c-amber); }

/* Saying what a hop really is: how it is made, where it goes, what it cost. */
.flight-edit {
  grid-area: air;
  margin-top: .8rem;
  padding-top: .8rem;
  border-top: 2px dashed var(--rule);
}

.flight-edit-row { display: flex; flex-wrap: wrap; gap: .45rem; }
.flight-edit .btn-quiet-inline { padding: .4rem .8rem; font-size: .72rem; }

.flight-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: .5rem;
  margin-top: .6rem;
}

.flight-field { display: grid; gap: .2rem; font-size: .66rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.flight-field input {
  padding: .45rem .6rem;
  border: 2px solid var(--rule-strong);
  border-radius: 10px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .82rem;
  letter-spacing: normal;
  text-transform: none;
}
.flight-code { width: 5rem; text-transform: uppercase; }
.flight-fare { width: 7rem; }
.flight-mins { width: 5rem; }
.flight-place { width: 11rem; }
.flight-field input.is-wrong { border-color: var(--danger); background: var(--danger-wash); }

/* Which way this part of the journey is made. */
.flight-field--wide { flex: 1 0 100%; }
.flight-modes { display: flex; flex-wrap: wrap; gap: .35rem; }
.flight-mode {
  padding: .35rem .7rem;
  border: 2px solid var(--rule-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: normal;
  text-transform: none;
  cursor: pointer;
}
.flight-mode:hover { border-color: var(--ink); }
.flight-mode.is-on { border-color: var(--ink); background: var(--ink); color: var(--surface); }

/* A place we could look up is optional to time and price; a way of their
   own is not, so the fields that carry it are shown as wanted. */
.flight-form--own .flight-mins,
.flight-form--own .flight-fare { border-color: var(--ink); }

/* Asked before an airport nobody has heard of goes on the plan. */
.flight-unknown {
  flex: 1 0 100%;
  margin: .2rem 0 0;
  padding: .55rem .7rem;
  border: 2px solid var(--c-amber);
  border-radius: 10px;
  background: var(--paper);
  color: var(--ink);
  font-size: .78rem;
  line-height: 1.45;
}
.flight-unknown strong { display: block; }

/* ------------------------------------------------ other ways to do a leg */

.leg-options {
  grid-area: opts;
  margin-top: .9rem;
  padding-top: .8rem;
  border-top: 2px dashed var(--rule);
}

.leg-options-label {
  display: block;
  margin-bottom: .5rem;
  color: var(--muted);
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.leg-options-row {
  display: flex;
  flex-wrap: wrap;
  gap: .45rem;
}

.leg-option {
  display: flex;
  align-items: baseline;
  gap: .45rem;
  padding: .5rem .8rem;
  border: 2px solid var(--rule-strong);
  border-radius: 10px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-size: .8rem;
  cursor: pointer;
  text-align: left;
}
.leg-option:hover:not(:disabled) { border-color: var(--accent); }

.leg-option.is-on {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--on-color);
  cursor: default;
}

.leg-option-name { font-weight: 700; }
.leg-option-price { font-weight: 700; color: var(--accent-strong); }
.leg-option.is-on .leg-option-price { color: var(--on-color); }
.leg-option-time { color: var(--muted); font-size: .72rem; }
.leg-option.is-on .leg-option-time { color: var(--on-color); opacity: .85; }

/* An invitation rather than a priced option: dashed until it is filled in. */
.leg-option--own {
  border-style: dashed;
  border-color: var(--c-violet);
  color: var(--c-violet);
}
.leg-option--own:hover:not(:disabled) { border-color: var(--c-violet); }
.leg-option--own.is-open {
  border-style: solid;
  background: var(--paper);
}
.leg-option--own .leg-option-note { color: var(--c-violet); }

.leg-option-note {
  color: var(--c-amber);
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* Departures shown for a date the traveller has not actually chosen. */
.departures-guess {
  padding: .1rem .45rem;
  border: 2px solid var(--rule-strong);
  border-radius: 4px;
  color: var(--muted);
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}

/* ------------------------------------------- waiting on a real timetable */

.departures--loading { opacity: .95; }

.departures-live--loading {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  background: var(--muted);
}

.spinner {
  width: .7rem;
  height: .7rem;
  border: 2px solid var(--on-color);
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin .7s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

.departures-skeleton {
  display: grid;
  gap: .4rem;
}

.skeleton-row {
  height: 2.4rem;
  border-radius: 8px;
  background: linear-gradient(
    90deg,
    var(--paper) 0%,
    var(--rule) 40%,
    var(--paper) 80%
  );
  background-size: 300% 100%;
  animation: sweep 1.4s ease-in-out infinite;
}
.skeleton-row:nth-child(2) { animation-delay: .12s; opacity: .8; }
.skeleton-row:nth-child(3) { animation-delay: .24s; opacity: .6; }

@keyframes sweep {
  from { background-position: 120% 0; }
  to   { background-position: -20% 0; }
}

/* Movement is decoration here; the words carry the message. */
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; border-right-color: var(--on-color); opacity: .6; }
  .skeleton-row { animation: none; background: var(--rule); }
}

/* Real, named things to do */
.doing-source {
  margin-left: .5rem;
  padding: .12rem .45rem;
  border-radius: 4px;
  background: var(--c-emerald);
  color: var(--on-color);
  font-size: .58rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  vertical-align: middle;
}

.doing-name { display: grid; gap: .1rem; }
.doing-title { font-weight: 700; }
.doing-kind {
  color: var(--muted);
  font-size: .68rem;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.doing-price { display: inline-flex; align-items: baseline; gap: .3rem; }
.doing-est { color: var(--muted); font-size: .62rem; letter-spacing: .06em; text-transform: uppercase; }

.doing-link {
  margin-left: .4rem;
  padding: .1rem .35rem;
  border: 2px solid var(--rule-strong);
  border-radius: 6px;
  color: var(--muted);
  font-size: .7rem;
  text-decoration: none;
}
.doing-link:hover { border-color: var(--accent); color: var(--accent); }

/* ------------------------------------------------------- where you eat -- */

.meals { margin-top: 1rem; }

.meals h4 {
  margin: 0 0 .7rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Which meals the day showing plans, under its tab and above the meals
   themselves. */
.meal-slots {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4rem;
  margin: .1rem 0 .5rem;
}

.meal-slots-label {
  color: var(--muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.meal-slot {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .25rem .6rem;
  border: 2px solid var(--rule);
  border-radius: 999px;
  color: var(--muted);
  font-size: .78rem;
  cursor: pointer;
}
.meal-slot:hover { border-color: var(--rule-strong); }
.meal-slot input { width: .9rem; height: .9rem; accent-color: var(--accent); }
.meal-slot.is-on { border-color: var(--accent); color: var(--ink); font-weight: 700; }

.meal-none { margin: 0; color: var(--muted); font-size: .84rem; }

/* Adding a sitting of your own, beside the three switches. */
.meal-slot-more {
  padding: .25rem .6rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: .74rem;
  font-weight: 700;
  cursor: pointer;
}
.meal-slot-more:hover { border-color: var(--ink); color: var(--ink); }

.meal-slot-add { display: inline-flex; align-items: center; gap: .35rem; }
.meal-slot-add .meal-own-name {
  flex: 0 1 12rem;
  padding: .25rem .5rem;
  border: 2px solid var(--rule-strong);
  border-radius: 999px;
  background: var(--surface);
  font: inherit;
  font-size: .78rem;
}
.meal-slot-add .btn-own { padding: .3rem .7rem; font-size: .64rem; }

.meal-slot-cancel {
  margin-left: .4rem;
  padding: 0 .3rem;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: .9rem;
  line-height: 1;
  cursor: pointer;
}
.meal-slot-cancel:hover { color: var(--danger); }

/* A sitting of the traveller's own reads like the three, minus the shortlist
   nobody can supply for it. */
.meal--extra .meal-label { display: flex; align-items: center; }
.meal--extra .meal-none { padding: .3rem .4rem; }

/* Your own place, listed among the shortlist it is standing in for. */
.meal-option--own .meal-kind {
  color: var(--accent);
  font-weight: 700;
}

/* An invitation rather than an offer: dashed, and quoting nothing, until it
   is picked and filled in. */
.meal-option--ask { border: 2px dashed var(--c-violet); }
.meal-option--ask .meal-title,
.meal-option--ask .meal-price strong { color: var(--c-violet); }
.meal-option--ask .meal-kind { color: var(--c-violet); }
.meal-option--ask .meal-price strong { font-weight: 700; }
.meal-option--ask.is-on { border-style: solid; background: var(--paper); }

/* The fields the invitation opens. .meal-own sets display, which a bare
   [hidden] would lose to. */
.meal-own[hidden] { display: none; }

/* When a control could not be honoured, said under the row it is in. */
.print-prices,
.print-maps {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  color: var(--muted);
  font-size: .78rem;
  cursor: pointer;
}
.print-prices input,
.print-maps input { width: 1rem; height: 1rem; accent-color: var(--accent); }

.control-note {
  margin: .6rem 0 0;
  color: var(--muted);
  font-size: .78rem;
  line-height: 1.5;
}

/* Somewhere of your own, under the shortlist for that meal. */
.meal-own {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin-top: .35rem;
  padding: .35rem .5rem .1rem;
}
.meal-own.is-on {
  border-radius: 8px;
  background: var(--paper);
}

.meal-own input {
  padding: .45rem .6rem;
  border: 2px solid var(--rule-strong);
  border-radius: 10px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .82rem;
}
.meal-own-name { flex: 1 1 10rem; min-width: 0; }
.meal-own-price { flex: 0 1 7rem; min-width: 0; }
.meal-own input::placeholder { color: var(--muted); }
.meal-own input.is-wrong { border-color: var(--danger); background: var(--danger-wash); }
.meal-own .btn-own { padding: .45rem .8rem; font-size: .66rem; }

/*
 * "each / total" — what the number beside it covers.
 *
 * Two words in one outline rather than a dropdown: there are only ever two
 * answers, and which one is in force has to be readable at a glance, because
 * getting it wrong is wrong by the size of the party. Deliberately quiet — it
 * is a qualifier on the box next to it, not a thing to press on the way past.
 */
.own-price { display: contents; }

.price-basis {
  display: inline-flex;
  flex: none;
  border: 2px solid var(--rule-strong);
  border-radius: 999px;
  overflow: hidden;
}

.price-basis-btn {
  padding: .3rem .6rem;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  cursor: pointer;
}

.price-basis-btn.is-on {
  background: var(--ink);
  color: var(--on-color);
}

.price-basis-btn:not(.is-on):hover { color: var(--ink); }

/* Same control under a leg: name it, time it, price one seat. Hidden until
   asked for — and .meal-own sets display, which plain [hidden] would lose to. */
.leg-own { margin-top: .5rem; padding-left: 0; padding-right: 0; }
.leg-own[hidden] { display: none; }
.leg-own-time { flex: 0 1 4.5rem; min-width: 0; }

/* Same control under the things to do. */
.doing-own { margin-top: .5rem; }

.meal {
  display: grid;
  gap: .35rem;
  margin-bottom: .8rem;
}

.meal-label {
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c-amber);
}

/* The same compact rows as the things-to-do list beside it. */
.meal-options { display: grid; gap: .1rem; }

.meal-option {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: .6rem;
  padding: .3rem .5rem;
  border-radius: 8px;
  cursor: pointer;
  font-size: .88rem;
}
.meal-option:hover { background: var(--paper); }
.meal-option input { width: 1rem; height: 1rem; accent-color: var(--accent); }

.meal-name { display: grid; gap: .05rem; min-width: 0; }
.meal-title {
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.meal-option.is-on .meal-title { color: var(--ink); font-weight: 700; }

.meal-kind {
  font-size: .64rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}

.meal-price {
  display: inline-flex;
  align-items: baseline;
  gap: .25rem;
  white-space: nowrap;
}

/* What that is each, next to what it is for everybody. */
.meal-each {
  color: var(--muted);
  font-size: .68rem;
}

.meals-note {
  margin: .2rem 0 0;
  color: var(--muted);
  font-size: .72rem;
  line-height: 1.45;
}

/* ------------------------------------------- who, what for, how much ---- */

.headcount {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;   /* or the number boxes stretch to the tallest column */
  gap: 1.2rem;
}
.headcount label {
  display: grid;
  gap: .3rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.headcount select { width: auto; min-width: 5.5rem; }
.headcount input[type="number"] { width: 5.5rem; }

/* Each column carries its own note, so the nights hint sits under the nights
   box rather than trailing beneath the date field's. */
.headcount-nights { flex: 0 1 14rem; }
.headcount-nights .hint--tight { max-width: 13rem; }

/* The departure day sits beside the nights box and needs more room. */
.headcount-date { flex: 1 1 13rem; max-width: 16rem; }
.headcount-date .date-text { width: 100%; }
.hint--tight {
  margin: 0;
  font-size: .7rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}

/* What the trip is for: several small choices rather than one big one. */
.options--interests {
  /* Wide enough for "Events & Festivals" on one line; narrower and the label
     was quietly clipped rather than wrapping. */
  grid-template-columns: repeat(auto-fit, minmax(11.5rem, 1fr));
  /* Each box its own height. Stretched to match its row, a one-word answer
     stood half empty beside "Beach & Relaxation" — and the three answers that
     need two lines are listed first, so they share the top row between them
     instead of inflating three separate rows. */
  align-items: start;
}
.option--interest { padding: .6rem .8rem .6rem 2.6rem; }
.option--interest .option-title { white-space: normal; }
.option--interest::before { left: .8rem; }
.option--interest::after { left: 1.24rem; }

.options--price { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }

/* Four ways to travel, each with a line saying what it is like. */
.options--transport { grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }

/* A question that only exists because of the answer above it. */
.follow-up {
  margin-top: .9rem;
  padding: .9rem 1rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 12px;
  background: var(--surface);
}
.follow-up[hidden] { display: none; }
.follow-up .control { max-width: 14rem; }
.follow-up .hint { margin: .5rem 0 0; }
.follow-up--regions .control-label { display: block; margin-bottom: .6rem; }
.follow-up--regions .options { margin-top: 0; }

/* Anywhere in particular: a search, and what has been named so far. */
.follow-up--wants .control-label { display: block; margin-bottom: .6rem; }
.follow-up--wants .origin-hits { grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr)); }

.want-list {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin: .6rem 0 0;
  padding: 0;
  list-style: none;
}
.want-list:empty { margin: 0; }

.want-chip {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem .5rem .35rem .7rem;
  border: 2px solid var(--accent);
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-color);
  font-size: .8rem;
  font-weight: 700;
}

.want-drop {
  padding: 0 .2rem;
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  opacity: .8;
}
.want-drop:hover { opacity: 1; }

.price-mark {
  font-size: 1.1rem;
  letter-spacing: .12em;
}

/* ------------------------------------------- more places, and your own -- */

.btn-more {
  margin-top: .6rem;
  padding: .45rem .9rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  cursor: pointer;
}
.btn-more:hover { border-color: var(--ink); color: var(--ink); }

/*
 * Room around "…of your own".
 *
 * It is the last row in both the food and the things-to-do lists, and it is
 * the one row that is not one of our suggestions — a box you fill in rather
 * than a choice you tick. Sitting flush against the list above it, it read as
 * one more option; a little air says it is a different kind of thing.
 */
.meal-option--own,
.meal-option--ask,
.doing-option--own,
.doing-option--ask {
  margin-top: .55rem;
}

/* And the button that opens the rest of the restaurants keeps its distance
   from the staples underneath it, so the three groups stay legible as three.
   The list is a grid, which would stretch the button to the full width the
   hotel and activity lists never give it — it takes its own width there too. */
.meal-options .btn-more,
.meal-options .btn-more-row {
  justify-self: start;
  margin-bottom: .5rem;
}

/* "Show different…" and "Show fewer" side by side at the foot of an open
   list. */
.btn-more-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: .6rem;
}
.btn-more-row .btn-more { margin-top: 0; }

.lodging-custom {
  margin-top: .8rem;
  padding-top: .8rem;
  border-top: 2px dashed var(--rule);
}

.lodging-custom-row {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}

.lodging-custom-name {
  flex: 1 1 11rem;
  min-width: 0;
}
.lodging-custom-rate { flex: 0 1 7rem; min-width: 0; }

.lodging-custom-row input {
  padding: .55rem .7rem;
  border: 2px solid var(--rule-strong);
  border-radius: 10px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-size: .85rem;
}
.lodging-custom-row input::placeholder { color: var(--muted); }
.lodging-custom-row input.is-wrong { border-color: var(--danger); background: var(--danger-wash); }

.btn-own {
  padding: .55rem 1rem;
  border: 2px solid var(--accent);
  border-radius: 10px;
  background: var(--accent);
  color: var(--on-color);
  font: inherit;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  cursor: pointer;
}
.btn-own:hover { filter: brightness(1.1); }

/* A look at the place before you choose it. The link sits over the card
   rather than inside it, because the card is a button. */
.lodging-slot { position: relative; display: flex; }
.lodging-slot > .lodging-option { flex: 1 1 auto; }

.lodging-look {
  position: absolute;
  top: .5rem;
  right: .5rem;
  padding: .18rem .5rem;
  border: 2px solid var(--rule-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-decoration: none;
}
.lodging-look:hover { border-color: var(--accent); color: var(--accent); }
/* The $-band in the badge's column, directly under the Site/Map badge —
   or at the top of that column when a hotel has no badge — at every width,
   so the name and the kind-and-distance line have the card's full width.
   The badge and the band share a minimum width, so the one centres under
   the other. The "somewhere of your own" card is a form and keeps its
   own shape. */
/* Right padding wide enough for the badge column: badge and band are 3rem
   wide and sit .5rem in, so the text column ends 3.7rem from the edge. */
.lodging-option:not(.lodging-option--own) { min-height: 4.4rem; padding-right: 3.7rem; }
.lodging-option:not(.lodging-option--own) .lodging-band {
  position: absolute;
  top: .55rem;
  /* Its natural width — the box hugging the $ signs — centred under the
     badge: the right edge is put at the badge's centre line (.5rem in, half
     the badge's 3rem width), and the band shifted right by half its own
     width from there. */
  right: 2rem;
  transform: translateX(50%);
}
.lodging-look { min-width: 3rem; box-sizing: border-box; text-align: center; }
.lodging-slot:has(.lodging-look) .lodging-option:not(.lodging-option--own) .lodging-band { top: 2.45rem; }

.lodging-option.is-on ~ .lodging-look {
  border-color: var(--on-color);
  background: var(--accent);
  color: var(--on-color);
}
.lodging-option.is-on ~ .lodging-look:hover { background: var(--on-color); color: var(--accent); }

/* Which day of the stay you are choosing meals for. */
/* Which day (or night) you are choosing for pins just beneath the stuck
   stay header while its own section is under the reader — deep in a
   redrawn restaurant list the tabs would otherwise be long gone — and
   scrolls away with its section, handing over to the next section's tabs.
   --stay-head-h is kept up to date by the same code that pins the header. */
.meal-days {
  display: flex;
  /* One line at every width, scrolling sideways — swipe, drag with the
     mouse, or the arrows at either end when there is more than fits. A
     fortnight wrapped into three pinned rows was a third of the screen. */
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  /* No snapping with a mouse: a dragged row that then settled on a tab
     edge was the row moving on its own. Phones keep their proximity snap
     for a flick; see the phone block. */
  scroll-snap-type: none;
  /* A tab scrolled into view stops inside the arrow, not under it. */
  scroll-padding: 0 2rem;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* The row's width is its container's, never its contents': without this
     a fortnight of tabs pushed the card — and the page — wider instead of
     scrolling inside it. */
  contain: inline-size;
  width: 100%;
  min-width: 0;
  max-width: 100%;
  gap: .3rem;
  position: sticky;
  top: var(--stay-head-h, 3.4rem);
  z-index: 2;                  /* under the stay header (3), over the lists */
  background: var(--surface);
  padding: .35rem 0;
  margin-top: -.35rem;
  margin-bottom: .45rem;
  transition: opacity .15s ease;
}
.meal-days::-webkit-scrollbar { display: none; }
.meal-days > .meal-day { flex: 0 0 auto; scroll-snap-align: start; }
.meal-days.is-dragging { cursor: grabbing; user-select: none; scroll-snap-type: none; }
.meal-days.is-dragging .meal-day { pointer-events: none; }

/* The arrows: stuck to the row's own edges, so they stay put while the
   tabs scroll beneath them, and only there when the row overflows. */
.meal-days-arrow {
  display: none;
  position: sticky;
  flex: none;
  align-self: center;
  z-index: 1;
  width: 1.7rem;
  height: 1.7rem;
  padding: 0 0 .15rem;
  border: 2px solid var(--rule-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 0 0 4px var(--surface);
}
.meal-days-arrow--left { left: 0; }
.meal-days-arrow--right { right: 0; }
.meal-days-arrow:hover { border-color: var(--ink); }
.meal-days.is-overflowing .meal-days-arrow { display: inline-flex; align-items: center; justify-content: center; }
.meal-days.is-overflowing.at-start .meal-days-arrow--left,
.meal-days.is-overflowing.at-end .meal-days-arrow--right { opacity: .35; cursor: default; }

/* Sliding out at the end of its section: the reader has moved on. */
.meal-days.is-leaving { opacity: 0; }

.meal-day {
  display: grid;
  gap: .05rem;
  padding: .35rem .6rem;
  border: 2px solid var(--rule);
  border-radius: 8px;
  background: var(--paper);
  color: var(--muted);
  font: inherit;
  cursor: pointer;
  text-align: left;
}
.meal-day:hover { border-color: var(--accent); }
.meal-day.is-on {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--on-color);
}

.meal-day-num {
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.meal-day-cost { font-size: .68rem; opacity: .85; }
/* The day you arrive and the morning you leave, said in red under the
   tab rather than in it, so every box keeps the same two lines. The mark
   hangs below the button; the row leaves room for it, and being inside
   the sticky row it is covered and uncovered with the tabs. */
.meal-day { position: relative; }
.meal-day-leaving {
  position: absolute;
  top: calc(100% + .12rem);
  left: 0;
  right: 0;
  text-align: center;
  color: var(--danger);
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}
.meal-days--marked { padding-bottom: 1.2rem; }

.meals-foot { margin-top: .6rem; }

/* How far the next change reaches — under the meal switches, since it
   governs them as much as the picks below. */
.meal-every {
  display: flex;
  align-items: center;
  gap: .45rem;
  margin: 0 0 .8rem;
  font-size: .78rem;
  color: var(--muted);
  cursor: pointer;
}
.meal-every input { width: 1rem; height: 1rem; accent-color: var(--accent); }

/* ------------------------------------------------------------- printing --
   The screen page is full of controls that mean nothing on paper. Printing
   swaps it for a plain day-by-day itinerary, built into the page so Ctrl-P
   works as well as the button does. */

.printable { display: none; }

/* The same shape as the primary button beside it, in the quieter colour: it
   is the second thing you would do on this page, not a different species of
   control. Sharing .btn-primary's geometry keeps the pair aligned. */
.btn-print {
  display: inline-block;
  padding: .9rem 2.2rem;
  border: 3px solid var(--ink);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .85rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 4px 4px 0 var(--ink);
}
a.btn-print { text-decoration: none; }        /* a link dressed as the button */
.btn-print:hover { background: var(--accent); color: var(--on-color); }
.btn-print:active { transform: translate(2px, 2px); box-shadow: 2px 2px 0 var(--ink); }

/* The plan's link onto the clipboard. At the foot it is the red primary
   button; in the summary card a chain-link icon the size of the print
   button beside it. "Copied" is said in green for a moment either way. */
.btn-share.is-copied { background: var(--c-emerald); border-color: var(--ink); color: var(--on-color); }
.btn-share--icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;                 /* the print button beside it is 32 px */
  height: 2rem;
  margin-left: 0;
  padding: 0;
  border: 2px solid var(--ink);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  vertical-align: middle;
  cursor: pointer;
  box-shadow: 3px 3px 0 var(--ink);
}
.btn-share--icon:hover { background: var(--accent); color: var(--on-color); }
.btn-share--icon:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--ink); }
.btn-share--icon.is-copied { background: var(--c-emerald); color: var(--on-color); }

/*
 * "Before you book" — the caveats, at the end where they are read last and
 * remembered.
 *
 * Deliberately quiet: amber and a border would make it a warning, and nothing
 * has gone wrong. It is the small print, and small print earns its place by
 * being legible rather than by shouting.
 */
.check {
  margin: 1.6rem 0 0;
  padding: 1.1rem 1.3rem;
  border-top: 2px dashed var(--rule-strong);
}

.check-title {
  margin: 0 0 .3rem;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}

.check-lead {
  margin: 0 0 .8rem;
  max-width: 46rem;
  font-size: .92rem;
  color: var(--ink);
}

.check-list {
  margin: 0;
  padding: 0;
  max-width: 46rem;
  list-style: none;
  display: grid;
  gap: .55rem;
}

.check-item {
  font-size: .88rem;
  line-height: 1.5;
  color: var(--muted);
}

.check-item strong { color: var(--ink); }

@media print {
  /* Ink is expensive and paper is white. */
  /* 12pt body and everything scaled with it: 11pt was fine at a desk and
     small in a moving train, which is where this sheet gets read. */
  body { background: #fff; color: #000; font-size: 12pt; }
  body::before { display: none; }

  .site-header,
  .site-footer,
  .controls,
  .plan-actions,
  .itinerary,
  .map-panel,
  .notice,
  .check,
  .totals,
  .alert,
  .loading { display: none !important; }

  #plan-root, .wrap { width: auto; max-width: none; padding: 0; }

  .plan-summary { display: none; }

  .printable { display: block; }

  /* The route map, borrowed from the page for the duration of the print. */
  .printable-map {
    /* A column so the credit sits under the map, whichever order they were
       put into the sheet in. */
    display: flex;
    flex-direction: column;
    margin-bottom: 1rem;
    break-inside: avoid;
    page-break-inside: avoid;
  }
  .printable-map .map-frame { position: static; }
  /* Sized in pixels by the script, which is what the map is drawn in; the
     page scales it to the paper from there. */
  .printable-map .map-box {
    max-width: 100%;
    border: 1px solid #999;
    border-radius: 0;
  }
  /* Zoom buttons are no use on paper. */
  .printable-map .map-tools { display: none !important; }

  .printable-mapnote {
    order: 2;
    margin: .15rem 0 0;
    font-size: 9pt;
    color: #555;
  }

  /* One small map per country or state, each standing where that part of the
     trip begins, so a border crossing is legible on paper instead of being
     three dots on a continent. */
  .printable-inset {
    margin: .6rem 0 .2rem;
    break-inside: avoid;
    page-break-inside: avoid;
  }

  .printable-inset .map-frame { position: static; }

  .printable-inset .map-box {
    max-width: 100%;
    border: 1px solid #999;
    border-radius: 0;
  }

  .printable-inset figcaption {
    margin-top: .12rem;
    font-size: 10pt;
    font-weight: 700;
  }

  .printable-inset-stops { font-weight: 400; color: #555; }

  /* Maps left out on purpose, for a printout that is the list and nothing
     else — or for anybody who would rather not spend the ink. */
  .printable--no-maps .printable-map,
  .printable--no-maps .printable-inset { display: none !important; }

  /* Prices left out on purpose: the itinerary is the point, and not every
     printout is for the person paying. */
  .printable--no-prices .printable-cost { display: none !important; }

  .printable-head { margin-bottom: 1rem; border-bottom: 2px solid #000; padding-bottom: .5rem; }
  .printable-head h2 { margin: 0 0 .2rem; font-size: 20pt; }
  .printable-facts { margin: 0; font-size: 12pt; }

  .printable-day,
  .printable-stay {
    margin-bottom: .9rem;
    /* Never split a day across two sheets. */
    break-inside: avoid;
    page-break-inside: avoid;
  }

  .printable-day h3,
  .printable-stay h3 {
    margin: 0 0 .2rem;
    font-size: 14pt;
    border-bottom: 1px solid #999;
  }
  .printable-day p,
  .printable-stay p { margin: .15rem 0; }

  .printable-day--travel h3 { border-bottom-style: dashed; }
  .printable-note { font-size: 10.5pt; color: #444; }

  /* A ruled blank to write the confirmation number on. Ink-thin: it is a
     line to write on, not a box to look at. */
  .printable-refline { margin: .15rem 0 0; font-size: 10.5pt; color: #444; }
  .printable-refblank {
    display: inline-block;
    width: 42mm;
    border-bottom: 1px solid #999;
  }

  /* Phone, hours and website for the places on the sheet. Quieter than the
     plan itself — reference matter, not itinerary. */
  .printable-contact { margin: .1rem 0 0 1rem; font-size: 10.5pt; color: #444; }
  .printable-contact strong { font-weight: 700; color: #000; }
  .printable-link { color: #444; text-decoration: underline; }

  /* A stay split across a page turn is read twice and understood once. Kept
     whole where it fits; a block taller than the page still splits, which is
     the only honest thing left for it to do. */
  .printable-day,
  .printable-stay {
    break-inside: avoid;
    page-break-inside: avoid;
  }
  .printable-meals tr { break-inside: avoid; }
  .printable-night { margin-left: 1rem !important; font-size: 12pt; }

  .printable-meals,
  .printable-totals {
    width: 100%;
    margin-top: .35rem;
    border-collapse: collapse;
    font-size: 11pt;
  }
  .printable-meals th,
  .printable-meals td,
  .printable-totals th,
  .printable-totals td {
    padding: .15rem .3rem;
    border: 1px solid #bbb;
    text-align: left;
  }
  .printable-meals th { font-weight: 700; white-space: nowrap; }
  .printable-cost, .printable-totals td { text-align: right; white-space: nowrap; }

  .printable-totals { margin-top: 1rem; width: auto; min-width: 40%; }
  .printable-totals tr:last-child th,
  .printable-totals tr:last-child td { font-weight: 700; border-top: 2px solid #000; }

  a { color: #000; text-decoration: none; }
}

/* ------------------------------------------------ swapping a destination */

.stay-name {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.stay-name h2 { margin: 0; }
.stay-name:hover h2 { color: var(--accent); }

.stay-swap-hint {
  padding: .1rem .45rem;
  border: 2px solid var(--rule-strong);
  border-radius: 999px;
  color: var(--muted);
  font-size: .58rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
}
.stay-name:hover .stay-swap-hint { border-color: var(--accent); color: var(--accent); }
.stay-name[aria-expanded="true"] .stay-swap-hint {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--on-color);
}

.stay-swap {
  margin: .8rem 0;
  padding: .9rem 1rem;
  border: 2px dashed var(--accent);
  border-radius: 12px;
  background: var(--paper);
}

.stay-swap-label {
  margin: 0 0 .6rem;
  color: var(--muted);
  font-size: .78rem;
}

.stay-swap-input {
  width: 100%;
  padding: .6rem .8rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-weight: 700;
}

.stay-swap-results {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: .35rem;
  margin-top: .6rem;
}

.stay-swap-hit {
  display: grid;
  gap: .1rem;
  padding: .45rem .7rem;
  border: 2px solid var(--rule);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .82rem;
  text-align: left;
  cursor: pointer;
}
.stay-swap-hit:hover { border-color: var(--accent); }
.stay-swap-hit span { color: var(--muted); font-size: .7rem; }

.stay-swap-empty { margin: 0; color: var(--muted); font-size: .8rem; }

@media print { .stay-swap, .stay-swap-hint { display: none !important; } }

/* Night tabs reuse the meal-day chips; the name is longer than a price. */
.lodging-nights .meal-day { max-width: 12rem; }
.lodging-nights .meal-day-cost {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* One hotel for the whole stay is the default; this opts out of it. */
.lodging-mode {
  display: flex;
  align-items: center;
  gap: .45rem;
  margin-bottom: .7rem;
  color: var(--muted);
  font-size: .78rem;
  cursor: pointer;
}
.lodging-mode input { width: 1rem; height: 1rem; accent-color: var(--accent); }

/* Starting from anywhere, not only the catalogue. */
.origin-search { margin-bottom: 1rem; }

.origin-search-row {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}

.origin-search-row input {
  flex: 1 1 12rem;
  min-width: 0;
  padding: .7rem .8rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
}

.btn-find {
  padding: .7rem 1.3rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--ink);
  color: var(--surface);
  font: inherit;
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  cursor: pointer;
}
.btn-find:hover:not(:disabled) { background: var(--accent); border-color: var(--accent); }
.btn-find:disabled { opacity: .5; cursor: progress; }

.origin-status {
  margin: .5rem 0 0;
  color: var(--muted);
  font-size: .78rem;
}

.origin-hits {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: .35rem;
  margin-top: .5rem;
}

.origin-hit {
  display: grid;
  gap: .1rem;
  padding: .5rem .7rem;
  border: 2px solid var(--rule-strong);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .82rem;
  text-align: left;
  cursor: pointer;
}
.origin-hit:hover { border-color: var(--accent); }
.origin-hit span { color: var(--muted); font-size: .72rem; }

/* An activity already booked on another day of the same stay. */
.doing-kind--elsewhere { color: var(--c-amber); }

/* The trip's own name */
.plan-title { margin-bottom: .4rem; padding-right: 3rem; }   /* clear of the link icon */
.plan-summary > .btn-share--icon { position: absolute; top: 1.1rem; right: 1.2rem; margin: 0; }
.plan-title h1 { margin: 0; }

.plan-title-name {
  display: inline-flex;
  align-items: baseline;
  gap: .6rem;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
/* No underline: the Rename tag beside it lights up on hover, and that is
   signal enough without dressing the title itself. */
.plan-title-name:hover { color: var(--on-color); }

/* These sit on the accent panel, not on the page, so the page's greys would
   be close to unreadable on it. */
.plan-title-sub {
  margin: .2rem 0 0;
  color: var(--on-color);
  opacity: .85;
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.plan-title-name .stay-swap-hint {
  border-color: var(--on-color);
  color: var(--on-color);
  opacity: .8;
}
.plan-title-name:hover .stay-swap-hint {
  background: var(--on-color);
  color: var(--accent);
  opacity: 1;
}

.plan-title-edit {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
}

.plan-title-input {
  flex: 1 1 16rem;
  min-width: 0;
  padding: .6rem .8rem;
  border: 3px solid var(--ink);
  border-radius: 12px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 1.3rem;
  font-weight: 700;
}

@media print { .stay-swap-hint, .plan-title-sub { display: none !important; } }

.feature-icon--clock { background: var(--c-violet); }
.feature-icon--food  { background: var(--c-vermil); }

.pass-name {
  margin: 0 0 .2rem;
  text-align: center;
  color: var(--muted);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* ------------------------------------------------------------ accounts -- */

.site-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6rem 1rem;
}

.site-signout {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: 0;
}

.site-who {
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  opacity: .9;
}

.site-signout .btn-ghost {
  border-width: 2px;
  background: none;
  cursor: pointer;
  font: inherit;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--on-color);
}

/* The account forms reuse the ticket, so they only need field widths. */
.card input[type="email"],
.card input[type="password"] {
  width: 100%;
  padding: .7rem .8rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
}

.auth-alt { margin-top: 1rem; text-align: center; }
.auth-alt a { color: var(--accent); font-weight: 700; }

@media (max-width: 620px) {
  .site-who { max-width: 8rem; }
}

/* The two-word label and the one-word label: only one of them shows. */
.when-narrow { display: none; }

/* The running summary above the form's button is for a phone, where the
   form scrolls past the button; on a desk the answers are in view. */
.form-summary { display: none; }

/* Signed out on a phone: the mark on the left, "Log in" and "Register" on
   the right, one row, the header the height of a toolbar. The pills are
   drawn smaller than on a desk — they are the second thing on the page,
   not the first — but stay tall enough for a thumb. Signed in, the header
   keeps wrapping its row of pills for now (mobile.md, step 1, is the
   menu that replaces that). */
@media (max-width: 620px) {
  .site-header--out {
    flex-wrap: nowrap;
    gap: .6rem;
    padding: .5rem 1rem;
  }
  .site-header--out .slogan { display: none; }
  .site-header--out .logo { font-size: 1.1rem; }
  .site-header--out .site-nav {
    flex: 0 0 auto;
    flex-wrap: nowrap;
    gap: .4rem;
    margin-left: auto;
  }
  .site-header--out .btn-ghost {
    padding: .5rem .7rem;
    font-size: .58rem;
    letter-spacing: .08em;
    white-space: nowrap;
  }
  .site-header--out .when-wide { display: none; }
  .site-header--out .when-narrow { display: inline; }
}

/* Signed in on a phone: the mark and one Menu button on a row the height
   of a toolbar; the pills are hidden and the sheet under the header holds
   them as rows a thumb can hit. The sheet lies over the page rather than
   pushing it down, so opening it does not move what was being read; the
   header is raised above the page's own sticky bands for that. */
.site-menu { display: none; }

@media (max-width: 620px) {
  .site-header--in {
    position: relative;
    z-index: 5;
    flex-wrap: nowrap;
    gap: .6rem;
    padding: .5rem 1rem;
  }
  .site-header--in .slogan { display: none; }
  .site-header--in .logo { font-size: 1.1rem; }
  .site-header--in .site-nav { display: none; }

  .site-menu { display: block; margin-left: auto; }
  .site-menu-button {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .5rem .8rem;
    border: 2px solid var(--on-color);
    border-radius: 999px;
    color: var(--on-color);
    font-size: .6rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    cursor: pointer;
    list-style: none;
    -webkit-tap-highlight-color: transparent;
  }
  .site-menu-button::-webkit-details-marker { display: none; }
  .site-menu[open] .site-menu-button { background: var(--on-color); color: var(--accent); }

  /* Three bars, drawn rather than fetched. */
  .site-menu-bars {
    width: .9rem;
    height: .6rem;
    border-top: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    position: relative;
  }
  .site-menu-bars::after {
    content: "";
    position: absolute;
    left: 0; right: 0; top: 50%;
    border-top: 2px solid currentColor;
    transform: translateY(-1px);
  }

  .site-menu-sheet {
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    display: flex;
    flex-direction: column;
    padding: .3rem 0 .5rem;
    background: var(--accent);
    border-bottom: 3px solid var(--ink);
    box-shadow: 0 14px 28px -14px rgba(0, 0, 0, .55);
  }
  .site-menu-row {
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: 0 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, .18);
    color: var(--on-color);
    font-size: .8rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    text-decoration: none;
  }
  .site-menu-row:first-child { border-top: 0; }
  .site-menu-row:active { background: rgba(255, 255, 255, .12); }
  /* The same amber pill as on a desk, drawn as a row: amber text on the
     blue was hard to read. */
  .site-menu-row--premium { background: var(--c-amber); color: var(--on-color); }
  .site-menu-who {
    min-height: 40px;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    opacity: .85;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: block;
    line-height: 40px;
  }
  .site-menu-signout { margin: 0; display: flex; flex-direction: column; }
  .site-menu-row--button {
    width: 100%;
    background: none;
    border-left: 0; border-right: 0; border-bottom: 0;
    font: inherit;
    font-size: .8rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    text-align: left;
    cursor: pointer;
  }
}

/* --------------------------------------------------------- saved trips -- */

.trip-list {
  display: grid;
  gap: .8rem;
  margin-bottom: 2rem;
}

.trip-card {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .2rem 1rem;
  padding: 1rem 1.2rem;
  border: 3px solid var(--ink);
  border-radius: 14px;
  background: var(--surface);
  color: var(--ink);
  text-decoration: none;
  box-shadow: 4px 4px 0 var(--ink);
}
.trip-card:hover { background: var(--paper); }
.trip-card:active { transform: translate(2px, 2px); box-shadow: 2px 2px 0 var(--ink); }

.trip-card-name {
  grid-column: 1;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: -.01em;
}

.trip-card-route {
  grid-column: 1;
  color: var(--muted);
  font-size: .84rem;
}

.trip-card-facts {
  grid-column: 1;
  color: var(--muted);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.trip-card-total {
  grid-column: 2;
  grid-row: 1 / span 3;
  align-self: center;
  color: var(--accent-strong);
  font-size: 1.4rem;
  font-weight: 700;
  white-space: nowrap;
}

@media (max-width: 620px) {
  /* A ledger line rather than a poster: the name on the first row with
     room kept for Remove in the corner, the route under it, and on the
     last row the facts on the left and the total on the right — the same
     corners the desk card uses, in half the height. */
  .trips h1 { font-size: 1.6rem; margin-bottom: .2rem; }
  .trips .lede { font-size: .88rem; margin-bottom: 1rem; }
  .trips-head { margin-bottom: 1rem; }
  .trips-head .lede { margin-bottom: 0; }
  .trips-new { padding: .5rem .9rem; font-size: .66rem; letter-spacing: .12em; box-shadow: 3px 3px 0 var(--ink); }
  .trip-list { gap: .6rem; }
  .trip-card {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: .1rem .7rem;
    padding: .65rem .85rem .6rem;
    border-width: 2px;
    box-shadow: 3px 3px 0 var(--ink);
  }
  .trip-card-name { grid-column: 1 / -1; padding-right: 4.6rem; font-size: .95rem; line-height: 1.25; }
  .trip-card-route { grid-column: 1 / -1; font-size: .78rem; }
  .trip-card-facts { grid-column: 1; align-self: end; font-size: .72rem; letter-spacing: .06em; }
  .trip-card-total { grid-column: 2; grid-row: auto; align-self: end; font-size: 1.05rem; }
  .trip-card-lock { grid-column: 1 / -1; }
}

/* How much the thing has been used. */
.hero-stat {
  display: inline-flex;
  align-items: baseline;
  gap: .4rem;
  margin: 0 0 .6rem;
  padding: .4rem .9rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 999px;
  color: var(--muted);
  font-size: .8rem;
}
.hero-stat strong { color: var(--accent-strong); font-size: 1rem; }

.cta-stat {
  margin: 1rem 0 0;
  font-size: .82rem;
  opacity: .9;
}
.cta-stat strong { font-size: 1rem; }

/* ------------------------------------------------------------ settings -- */

.account {
  margin-bottom: 1.6rem;
  padding: 1.2rem 1.4rem;
  border: 3px solid var(--ink);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: 4px 4px 0 var(--ink);
}

.account-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .6rem;
  margin-bottom: .9rem;
}
.account-head h2 { margin: 0; font-size: 1.2rem; }

.tier-badge {
  padding: .25rem .8rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--paper);
  color: var(--muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.tier-badge--premium {
  border-color: var(--c-amber);
  background: var(--c-amber);
  color: var(--on-color);
}

.account-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: .8rem;
  margin: 0 0 .9rem;
}
.account-facts dt {
  color: var(--muted);
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.account-facts dd { margin: .15rem 0 0; font-weight: 700; }

.account-note {
  margin: 0;
  padding-top: .8rem;
  border-top: 2px dashed var(--rule);
  color: var(--muted);
  font-size: .82rem;
  line-height: 1.5;
}

.settings-card { margin-top: 1.2rem; }

/* A refusal that is about the tier, not the typing: the sentence carries one
   link, in the refusal's own colour, and nothing else changes. */
.alert-error .alert-upgrade,
.hint--limit a,
.print-upsell a { color: inherit; font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }

.hint--limit { color: var(--muted); }

.print-upsell {
  flex: 1 1 100%;
  order: -1;                 /* at the foot: the line above the buttons */
  max-width: 26rem;
  margin: 0;
  font-size: .8rem;
  color: var(--muted);
}
/* The hanging note is a cream box on the page, so it keeps ink, not the
   card's cream-on-blue. */
.summary-print .print-upsell:not(.print-upsell--pop) { color: var(--on-color); text-align: right; }
/* At the foot: a line of its own under the buttons, centred like them —
   not a line above that the buttons wrapped around. */
.plan-actions .print-upsell {
  flex: 1 1 100%;
  order: 1;
  text-align: center;
  max-width: none;
  /* The line is reserved empty and filled on demand, so the page does not
     grow when the answer appears. */
  min-height: 1.5em;
}

/* A trip that can be read but not changed, said on its card so nobody opens
   one expecting to edit and finds the controls gone. */
.trip-card-lock {
  display: block;
  margin-top: .3rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--c-amber);
}

/* Links inside the landing page's own prose: the page's ink, underlined,
   never the browser's default blue on a beige ground. */
.hero-note a,
.claims a { color: var(--accent); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }

/* ---------------------------------------------------------- the terms --
   Prose, set for reading: a comfortable measure, numbered sections with room
   between them, and a contents line at the top so a reader after one answer
   can go straight to it. */
.legal { max-width: 46rem; }
.legal .lede { max-width: none; }   /* the prose below it runs the full measure; so should the lede */
.legal section { margin-top: 2rem; }
.legal h2 { margin: 0 0 .6rem; font-size: 1.15rem; }
.legal p, .legal li { line-height: 1.6; }
.legal ul { padding-left: 1.2rem; }
.legal li { margin: .4rem 0; }
.legal a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.legal-toc {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem .9rem;
  margin: 1rem 0 0;
  padding: .8rem 1rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 12px;
  font-size: .82rem;
}
.site-footer a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.auth-terms { margin: 0 0 .8rem; }
.auth-terms a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }

.alert-ok {
  border: 2px solid var(--c-emerald);
  border-radius: 10px;
  padding: .7rem 1rem;
  background: var(--surface);
  color: var(--c-emerald);
  font-weight: 700;
}

/* ------------------------------------------------- signing in with Google */

.oauth { margin-top: 1.2rem; }

.oauth-or {
  display: flex;
  align-items: center;
  gap: .8rem;
  margin: 0 0 .8rem;
  color: var(--muted);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.oauth-or::before,
.oauth-or::after {
  content: "";
  flex: 1;
  height: 2px;
  background: var(--rule);
}

.btn-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .7rem;
  padding: .8rem 1.2rem;
  border: 3px solid var(--ink);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-decoration: none;
  box-shadow: 4px 4px 0 var(--ink);
}
.btn-google:hover { background: var(--paper); }
.btn-google:active { transform: translate(2px, 2px); box-shadow: 2px 2px 0 var(--ink); }

/* Beside the main button rather than under an "or": the compact form, on
   the login and register pages, where it is the second way in and not a
   rival to the first. A <button> on the register page (it sends the form
   to the Google door, terms box and all), a link on the login page — so
   both inherit the page's face and get a pointer. */
.actions--row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  /* Stretched, not centred: the two buttons stand the same height, the
     main one setting it, and the Google one is smaller only in its width
     and its type. */
  align-items: stretch;
  gap: .8rem 1rem;
}
.btn-google--small {
  display: inline-flex;
  gap: .5rem;
  padding: .55rem .95rem;
  font: inherit;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  box-shadow: 3px 3px 0 var(--ink);
  cursor: pointer;
}
.btn-google--small .btn-google-mark { width: 1.3rem; height: 1.3rem; font-size: .75rem; }

.btn-google-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  background: var(--c-azure);
  color: var(--on-color);
  font-size: .9rem;
  line-height: 1;
}

/* ------------------------------------------------------------- premium -- */

.btn-ghost--premium {
  border-color: var(--c-amber);
  background: var(--c-amber);
  color: var(--on-color);
}
.btn-ghost--premium:hover { background: var(--on-color); color: var(--c-amber); }

.alert-warn {
  padding: .9rem 1.1rem;
  border: 2px solid var(--c-amber);
  border-radius: 12px;
  background: var(--surface);
  color: var(--ink);
  font-size: .88rem;
  line-height: 1.5;
}

.plans {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 1rem;
  margin: 1.4rem 0 1.4rem;
  align-items: start;
}

.plan {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: 1.3rem 1.4rem;
  border: 3px solid var(--ink);
  border-radius: 16px;
  background: var(--surface);
  box-shadow: 4px 4px 0 var(--ink);
}
.plan--best { border-color: var(--c-amber); box-shadow: 4px 4px 0 var(--c-amber); }
.plan--current { background: var(--paper); }

.plan-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
}
.plan-head h2 { margin: 0; font-size: 1.1rem; }

.plan-tag {
  padding: .15rem .6rem;
  border: 2px solid var(--rule-strong);
  border-radius: 999px;
  color: var(--muted);
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.plan-tag--best {
  border-color: var(--c-amber);
  background: var(--c-amber);
  color: var(--on-color);
}

.plan-price { margin: .3rem 0 0; display: flex; align-items: baseline; gap: .3rem; }
.plan-amount { font-size: 2.1rem; font-weight: 700; letter-spacing: -.02em; }
.plan-cadence { color: var(--muted); font-size: .8rem; font-weight: 700; }

.plan-per { margin: 0; color: var(--muted); font-size: .78rem; }

.plan-list {
  list-style: none;
  margin: .6rem 0 0;
  padding: 0;
  display: grid;
  gap: .4rem;
  flex: 1;
}
.plan-list li {
  position: relative;
  padding-left: 1.4rem;
  font-size: .86rem;
}
.plan-list li::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--c-emerald);
  font-weight: 700;
}

.plan-note { margin: .4rem 0 0; color: var(--muted); font-size: .78rem; }

.plan-buy {
  margin-top: .8rem;
  text-align: center;
  font-size: .78rem;
  padding: .8rem 1.2rem;
}
.plan-buy:disabled { opacity: .55; cursor: not-allowed; }

/* What happens to your trips when premium ends — the question anyone weighing
   a subscription asks, so it gets its own box rather than a footnote. */
.plan-keep {
  margin: 1.6rem 0 1rem;
  padding: 1rem 1.2rem;
  border: 2px solid var(--rule-strong);
  border-radius: 12px;
  background: var(--surface);
  color: var(--ink);
  font-size: .86rem;
  line-height: 1.6;
}
.plan-keep strong { display: block; margin-bottom: .2rem; }

.plan-footnote {
  margin: 0 0 2rem;
  color: var(--muted);
  font-size: .8rem;
  line-height: 1.5;
}

/* Deleting a saved trip */
/* The line under the title with "Plan a new trip" on its right, so the
   page that lists your trips is also where the next one starts. The row
   takes over the lede's bottom margin. */
.trips-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 2rem;
}
.trips-head .lede { flex: 1 1 10rem; min-width: 0; margin-bottom: 0; }
.trips-new { flex: none; padding: .65rem 1.4rem; font-size: .74rem; white-space: nowrap; }

.trip-row {
  position: relative;
  display: flex;
}
.trip-row > .trip-card { flex: 1 1 auto; }

.trip-delete {
  position: absolute;
  top: .7rem;
  right: .8rem;
  padding: .2rem .6rem;
  border: 2px solid var(--rule-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  text-decoration: none;
}
.trip-delete:hover { border-color: var(--danger); background: var(--danger); color: var(--on-color); }

.confirm {
  margin-bottom: 1.4rem;
  padding: 1.1rem 1.3rem;
  border: 3px solid var(--danger);
  border-radius: 14px;
  background: var(--danger-wash);
}
.confirm-question { margin: 0 0 .9rem; font-size: .92rem; line-height: 1.5; }

.confirm-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .8rem;
  justify-content: center;
}

.btn-danger {
  padding: .8rem 1.6rem;
  border: 3px solid var(--ink);
  border-radius: 999px;
  background: var(--danger);
  color: var(--on-color);
  font: inherit;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 4px 4px 0 var(--ink);
}
.btn-danger:hover { filter: brightness(1.08); }
.btn-danger:active { transform: translate(2px, 2px); box-shadow: 2px 2px 0 var(--ink); }

/* The total sits under the delete pill on a narrow card. */
@media (max-width: 620px) {
  /* Remove keeps the top-right corner; the name's right padding is the
     room it stands in, so the two never overlap. */
  .trip-delete {
    /* Small enough to sit inside the title line: a taller pill reached
       down over the second line, the list of places, on a phone. */
    top: .5rem;
    right: .7rem;
    padding: .2rem .55rem;
    font-size: .58rem;
    line-height: 1.2;
  }
  .confirm-actions { flex-wrap: wrap; }
}

/* Where you just landed, for a moment. */
.is-arrived {
  animation: arrived 1.4s ease-out;
}
@keyframes arrived {
  0%   { box-shadow: 0 0 0 4px var(--accent); }
  70%  { box-shadow: 0 0 0 4px var(--accent); }
  100% { box-shadow: 0 0 0 4px rgba(10, 95, 150, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .is-arrived { animation: none; }
}

/* What a stop costs beyond a bed, a meal and a ticket. */
.extras .doing-empty { margin-bottom: .6rem; }
.extra-row {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  padding: .4rem 0;
  border-bottom: 1px dashed var(--rule);
}
.extra-what { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; flex: 1 1 auto; }
.extra-what strong { font-size: .86rem; }
.extra-each { color: var(--muted); font-size: .72rem; }
.extra-total { font-weight: 700; font-size: .86rem; color: var(--accent-strong); }
.extra-row .want-drop { flex: 0 0 auto; }

.extra-form { margin-top: .7rem; }
.extra-ideas { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .5rem; }
.extra-idea {
  padding: .25rem .6rem;
  border: 2px dashed var(--rule-strong);
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: .7rem;
  font-weight: 700;
  cursor: pointer;
}
.extra-idea:hover { border-style: solid; color: var(--ink); background: var(--surface); }
.extra-daily {
  display: flex;
  align-items: center;
  gap: .3rem;
  font-size: .74rem;
  font-weight: 700;
  color: var(--muted);
}

/* A form that has to sit in a sentence, and a button that has to read as the
   link it replaced: the action needs a token, the copy does not change. */
.inline-form { display: inline; }
.btn-as-link {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.btn-as-link:hover { color: var(--accent-strong); }
.btn-as-link:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.plan-form { display: contents; }

/* Contact: the two addresses as two cards, so the choice is made by eye
   before it is made by reading. */
.contact-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
  margin-top: 1.5rem;
}
.contact-card {
  margin: 0;
  padding: 1.1rem 1.2rem;
  border: 2px solid var(--ink);
  border-radius: 12px;
  background: var(--surface);
  box-shadow: 4px 4px 0 var(--ink);
}
.legal .contact-card { margin-top: 0; }
.contact-card h2 { margin-bottom: .3rem; }
.contact-address { margin: 0 0 .6rem; font-size: 1.15rem; font-weight: 700; overflow-wrap: anywhere; }

/* FAQ: native disclosure widgets, one per question — no script, keyboard
   friendly, and the browser remembers nothing, which is right for a page
   read once. */
.faq-item {
  margin: .5rem 0;
  border: 2px solid var(--rule-strong);
  border-radius: 10px;
  background: var(--surface);
}
.faq-item[open] { border-color: var(--ink); }
.faq-item summary {
  padding: .7rem .9rem;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: .8rem;
  align-items: baseline;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: '+';
  flex: 0 0 auto;
  font-weight: 700;
  color: var(--muted);
}
.faq-item[open] summary::after { content: '−'; color: var(--ink); }
.faq-item summary:hover { color: var(--accent-strong); }
.faq-item summary:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; border-radius: 8px; }
.faq-item p { margin: 0; padding: 0 .9rem .8rem; }

/* The landing page's closing band carries the site links at its foot, in
   place of the footer the other pages have. Quiet: the band's own colour,
   a little transparent, and the same size as the footer text. */
.band--cta { position: relative; }
.cta-links {
  /* Laid over the band's own bottom padding rather than added below it, so
     the band is exactly the height it was before the links existed. */
  position: absolute;
  left: 0;
  right: 0;
  bottom: .7rem;
  margin: 0;
  text-align: center;
  font-size: .82rem;
  color: var(--on-color);
  opacity: .85;
}
.cta-links a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.cta-links a:hover { opacity: 1; text-decoration-thickness: 2px; }

/* The subscription line under the plan: what it costs and when it renews. */
.account-sub { display: block; margin-top: .25rem; font-size: .9rem; color: var(--muted); }
.account-sub small { font-size: .8rem; }

/* The consent box on the register form: one row, the box first, the words
   wrapping beside it rather than under it. */
.agree-row {
  display: flex;
  align-items: flex-start;
  gap: .65rem;
  cursor: pointer;
  line-height: 1.45;
}
/* Under an input rather than under a heading (the delete-account card): a
   breath of room, so the box does not read as part of the field above. */
.agree-row--spaced { margin-top: 1.1rem; }
.agree-row input {
  flex: 0 0 auto;
  width: 1.25rem;
  height: 1.25rem;
  margin: .15rem 0 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.agree-row a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }

/* "not confirmed — resend the link", beside the address on the account card */
.account-unverified { color: var(--c-vermil, #b3382b); font-size: .9rem; white-space: nowrap; }
