/* Kobaso brand palette — sage #7D9A87, brown #8B6E4F, cream #EADCC6,
   peach #F4A98D, off-white #FFF7EF — shared with the artwork in js/art.js */
:root {
  /* surfaces: warm off-white, not white */
  --cream: #FFFCF6;
  --bg: #FFF7EF;
  --surface: #FFFCF6;
  --sunk: #F5EBDC;

  /* ink: warm brown, never black */
  --ink: #5D4A35;
  --muted: #8B6E4F;
  --line: #EADCC6;
  --border: #EADCC6;

  /* soft sage tints, used for gentle fills */
  --mint: #A9C3B2;
  --mint-soft: #D9E6DD;
  --mint-pale: #EEF4EF;

  /* sage: the one action colour */
  --brand: #7D9A87;
  --brand-dark: #5F7B68;
  --accent: #5F7B68;
  --accent-soft: #D9E6DD;

  --cheek: #F4A98D;
  /* peach: the brand's warm accent — carries what gold used to */
  --gold: #F4A98D;
  --gold-soft: #FBE5D8;

  /* one radius scale */
  --r-sm: 12px;
  --r-md: 18px;
  --r-lg: 26px;
  --r-pill: 999px;
  --radius: var(--r-lg);

  --shadow: 0 6px 22px rgba(92, 74, 62, 0.09);
  --shadow-lg: 0 16px 44px rgba(92, 74, 62, 0.16);

  /* Brand type is Nunito Rounded (bold/semibold for display, regular/medium for
     body). Nunito Rounded has no webfont host, so if a visitor has it installed
     locally we use it; everyone else gets Nunito — the same face minus the
     rounded terminals — from Google Fonts. */
  --font-body: "Nunito Rounded", "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-display: var(--font-body);
}

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

/* The whole interface sits on rem, so this is the one dial for its scale.
   16px read small against the roomy layouts; a notch up suits the brand's
   friendly weight without any single screen needing its own numbers.

   `manipulation` drops double-tap-to-zoom, which on a page of big tappable
   cards mostly fired by accident — two quick picks in a row and the phone
   zoomed in on them instead. Panning and pinch-zoom are both untouched, so
   anyone who wants a closer look can still take one; `user-scalable=no` in the
   viewport tag would have taken that away, and iOS ignores it anyway.

   A tap's allowed behaviour is the intersection of touch-action all the way up
   its ancestors, so the root alone would do it — but `body` carries
   overflow-x: hidden and is therefore a scroll container in its own right, and
   it costs nothing to say it on both rather than depend on where a given
   engine decides to stop walking. Leaflet's stricter `none` on the map
   container still wins inside the map, which is what it wants. */
html, body { touch-action: manipulation; }
html { font-size: 17px; }

/* Two things a phone does to a page unless it is told not to.
   Mobile Safari inflates the text of any block it decides is too wide to read,
   independently of the rest of the layout — a paragraph comes back a size and a
   half larger than the heading above it, and only in landscape, and only on
   some screens. `100%` keeps the sizes we set.
   And a tap on anything tappable flashes a grey rectangle over it, squared off
   at the corners of elements that are pills. Every control here already answers
   a press with its own :active state, so the flash is only ever the wrong
   shape in the wrong colour. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
button, a, summary, label, input, select, textarea, [role="button"] {
  -webkit-tap-highlight-color: transparent;
}

/* `clip` on the root, not just hidden on body: hidden still leaves the page a
   scroll container, so anything poking past the right edge could shunt the
   whole site sideways — a focus, a drag, an overeager animation — and on a Mac
   paint a dark overlay scrollbar across the page while it was at it. clip
   forbids the scrolling itself, programmatic or otherwise. body keeps hidden
   as the fallback for engines that don't know clip. */
html { overflow-x: clip; }
body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.6;
  min-height: 100vh;
  overflow-x: hidden;
  font-weight: 500;
}

body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(600px 420px at 85% -10%, rgba(169, 195, 178, 0.30), transparent 60%),
    radial-gradient(520px 420px at -10% 30%, rgba(244, 169, 141, 0.14), transparent 60%),
    radial-gradient(520px 520px at 92% 92%, rgba(244, 169, 141, 0.10), transparent 60%);
}

/* Nunito bold carries display type, per the brand's Nunito Rounded spec */
h1, h2 { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.01em; }
h3 { font-weight: 800; }

#app { max-width: 820px; margin: 0 auto; padding: 24px 20px 80px; position: relative; }
#app.full { max-width: none; padding: 0; }

/* ---------- Animations ---------- */
/* `transform: none` at the end, not `translateY(0)`: the animation is filled
   both ways, so a zero translate is still a transform, and a transformed
   element is the containing block for anything `position: fixed` inside it.
   That is what pinned the phone's map view and its Map/List pill to the top of
   a page-tall section instead of to the screen. */
@keyframes fadeSlideIn {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}
@keyframes popIn {
  0% { transform: scale(1); }
  50% { transform: scale(1.06); }
  100% { transform: scale(1); }
}
@keyframes floatUp {
  0%   { transform: translateY(105vh) rotate(-8deg); opacity: 0; }
  10%  { opacity: 0.5; }
  90%  { opacity: 0.5; }
  100% { transform: translateY(-10vh) rotate(8deg); opacity: 0; }
}
@keyframes planeFly {
  0%   { left: -60px; transform: translateY(0) rotate(0deg); }
  50%  { transform: translateY(-14px) rotate(-6deg); }
  100% { left: calc(100% + 60px); transform: translateY(0) rotate(0deg); }
}
@keyframes dotPulse {
  0%, 80%, 100% { transform: scale(0.6); opacity: 0.4; }
  40% { transform: scale(1); opacity: 1; }
}

.anim-in { animation: fadeSlideIn 0.45s ease both; }
.stagger { animation: fadeSlideIn 0.5s ease both; }
.pop { animation: popIn 0.3s ease; }

/* Scroll-triggered reveals */
.reveal { opacity: 0; transform: translateY(26px); transition: opacity 0.55s ease, transform 0.55s cubic-bezier(0.22, 1, 0.36, 1); }
.reveal.in { opacity: 1; transform: translateY(0); }

/* Ambient motion */
@keyframes kenburns { from { transform: scale(1); } to { transform: scale(1.09); } }
.collage-tile img.loaded { animation: kenburns 16s ease-in-out infinite alternate; }
@keyframes compassRock { 0%, 100% { transform: rotate(-3deg); } 50% { transform: rotate(3deg); } }
.logo-badge { animation: compassRock 5.5s ease-in-out infinite; }
@keyframes blobShift { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
body::before { animation: blobShift 14s ease-in-out infinite; }

/* Button shimmer */
.btn-primary { position: relative; overflow: hidden; }
.btn-primary::after {
  content: ""; position: absolute; top: 0; left: -80%; width: 45%; height: 100%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.35), transparent);
  transform: skewX(-20deg); transition: left 0.55s ease;
}
.btn-primary:hover::after { left: 135%; }




/* Know-before-you-go. Five answers you'd otherwise open five tabs for, on the
   page where you're already planning — so it has to earn its height and not much
   more. No card and no white panel: hairlines top and bottom, a small line-art
   icon, the answer, the label under it. Each one still opens to a sentence.
   Every answer is kept to one line by SHORT_FACT in data.js, which is what lets
   the whole strip sit in about 44px. */
.essentials { margin: 2px 0 30px; }
/* Only a rule underneath. A second one along the top sat right below the page
   heading and read as an underline on the title rather than the top of a strip. */
/* Eight even columns, one row. A grid rather than a wrapping flex row because
   the answers vary from "Korean" to "No meat/dairy", and sizing to content gave
   eight columns of eight different widths. Everything longer than about a dozen
   characters is shortened in SHORT_FACT, with the tail moved to the label line
   ("Plugs · 220V") or the note. */
.ess-row {
  display: grid; grid-template-columns: repeat(8, minmax(0, 1fr));
  border-bottom: 1px solid var(--line);
  padding: 2px 0 4px;
}
.ess {
  font: inherit; cursor: pointer; color: inherit; text-align: left;
  display: flex; flex-direction: column; gap: 1px;
  background: none; border: none; padding: 8px 8px;
  min-width: 0; position: relative;
  transition: background 0.15s ease;
}
/* Hairline between columns rather than a box around each. :nth-of-type counts
   buttons only — the notes between them are <p>, so they don't shift the count
   and the first cell of each row correctly goes without. */
.ess:not(:nth-of-type(8n + 1))::before {
  content: ""; position: absolute; left: 0; top: 22%; bottom: 22%;
  width: 1px; background: var(--line);
}
.ess:hover { background: var(--mint-pale); border-radius: var(--r-sm); }
.ess[aria-expanded="true"] { background: var(--mint-pale); border-radius: var(--r-sm); }
/* The icon leads the cell, on its own line above the answer — four columns give
   it the room five didn't.
   Two-class selector deliberately: the generic `.ico { width: 19px }` further
   down this file would otherwise win on source order. */
.ess .ess-ico { width: 18px; height: 18px; flex: none; margin-bottom: 3px; }
.ess > strong {
  display: block; max-width: 100%;
  font-size: 0.82rem; font-weight: 800; line-height: 1.35; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.ess > em {
  display: flex; align-items: center; gap: 4px; max-width: 100%;
  font-style: normal; font-size: 0.68rem; font-weight: 700; color: var(--muted);
  line-height: 1.3;
}
.ess > em span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Eight across needs the full-width panel. Narrower than that and they'd be
   slivers, so it steps down to four and then two rather than shrinking. */
@media (max-width: 1080px) {
  .ess-row { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .ess:not(:nth-of-type(8n + 1))::before { content: none; }
  .ess:not(:nth-of-type(4n + 1))::before {
    content: ""; position: absolute; left: 0; top: 22%; bottom: 22%;
    width: 1px; background: var(--line);
  }
}
@media (max-width: 640px) {
  .ess-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ess:not(:nth-of-type(4n + 1))::before { content: none; }
  .ess:not(:nth-of-type(2n + 1))::before {
    content: ""; position: absolute; left: 0; top: 22%; bottom: 22%;
    width: 1px; background: var(--line);
  }
}
/* Each note sits next to its button in the DOM — which is right for reading
   order — but a note opening in the middle of the row would shunt the buttons
   after it onto a second line. Ordering it last keeps the five together and
   drops the note underneath them. */
.ess-note {
  order: 1; grid-column: 1 / -1; margin: 2px 0 4px;
  background: var(--mint-pale); border-radius: var(--r-sm); padding: 9px 13px;
  font-size: 0.83rem; line-height: 1.5;
}
/* Getting there sits under the row rather than in it: it's the one fact that
   depends on where they're leaving from, and a sixth column would have broken
   the five into slivers. */
/* The one line here that changes with where you're leaving from, so it gets to
   look like an answer rather than a footnote: a tinted strip, and a plane that
   flies in and lands on it. It replays on every render, which is exactly when
   the sentence has just changed. */
.ess-flight {
  display: flex; align-items: center; gap: 9px;
  font-size: 0.79rem; line-height: 1.45; margin-top: 12px; color: var(--ink);
  background: linear-gradient(90deg, var(--mint-pale), rgba(238, 244, 239, 0) 78%);
  border-left: 3px solid var(--mint);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding: 7px 12px; position: relative; overflow: hidden;
}
.ess-flight .ess-flight-ico {
  width: 16px; height: 16px; flex: none;
  animation: planeIn 1s cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
/* The contrail draws itself out behind the plane and fades, so the eye is led
   left-to-right into the sentence rather than at a decorative glyph. */
.ess-flight::after {
  content: ""; position: absolute; left: 10px; top: 50%; height: 1px; width: 0;
  border-top: 1.5px dashed var(--mint); pointer-events: none;
  animation: planeTrail 1.4s ease-out both;
}
@keyframes planeIn {
  0%   { transform: translate(-28px, 9px) rotate(-14deg); opacity: 0; }
  60%  { opacity: 1; }
  100% { transform: none; opacity: 1; }
}
@keyframes planeTrail {
  0%   { width: 0; opacity: 0; }
  35%  { opacity: 0.9; }
  100% { width: 62%; opacity: 0; }
}
/* Hover gives it a little lift — the whole strip is a hint that this answer came
   from an answer you gave, and can be changed. */
.ess-flight:hover .ess-flight-ico { animation: planeHop 0.8s ease-in-out; }
@keyframes planeHop {
  0%, 100% { transform: none; }
  45%      { transform: translate(5px, -4px) rotate(-10deg); }
}
/* No airport yet, so the prompt is the point — give it a slow pulse rather than
   letting it read as another grey footnote. */
.ess-flight .ess-ask { animation: askPulse 2.6s ease-in-out 1.2s 3; }
@keyframes askPulse {
  0%, 100% { color: var(--brand-dark); transform: none; }
  50%      { color: var(--brand); transform: scale(1.06); }
}
@media (prefers-reduced-motion: reduce) {
  .ess-flight .ess-flight-ico, .ess-flight::after, .ess-flight .ess-ask,
  .ess-flight:hover .ess-flight-ico { animation: none; }
  .ess-flight::after { display: none; }
}
.ess-ask {
  font: inherit; font-weight: 700; color: var(--brand-dark);
  background: none; border: none; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
  /* A link inside a running sentence can't grow to a 44px block without
     breaking the line it sits in, so the tap area grows invisibly instead:
     the padding extends what a finger can hit, the negative margin hands the
     space straight back to the layout. Inline vertical padding doesn't move
     line boxes, so the sentence is none the wiser. */
  padding: 13px 5px; margin: -13px -5px;
}
.ess-ask:hover { color: var(--ink); }
/* Getting there overland, when there's no flight to talk about */
.ess-ground {
  margin-top: 8px; padding: 9px 12px; border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: linear-gradient(90deg, var(--mint-pale), rgba(238, 244, 239, 0) 78%);
  border-left: 3px solid var(--mint);
}
.ess-ground-head { font-size: 0.74rem; font-weight: 800; color: var(--brand-dark); margin-bottom: 6px; }
/* One way per row, labels in a column, so the three notes read as a list */
.ess-ground-ways { display: flex; flex-direction: column; gap: 5px; }
.ess-way { display: flex; align-items: baseline; gap: 10px; font-size: 0.78rem; line-height: 1.4; min-width: 0; }
.ess-way em { flex: none; min-width: 58px; font-style: normal; font-size: 0.7rem; font-weight: 800; color: var(--muted); }
.ess-foot { font-size: 0.72rem; color: var(--muted); margin-top: 9px; }
/* The strip's lower shelf: flight facts and the entry note, full width. What
   used to sit in a column beside them — the one-base savings — is a full-width
   line of its own now, docked after this rather than next to it. */
.ess-lower { display: flex; gap: 22px; align-items: flex-start; }
.ess-lower-main { flex: 1 1 auto; min-width: 0; }
/* Search, and the way in to adding a place we don't have */
.poi-search { position: relative; display: flex; align-items: center; margin: 0 0 8px; }
.poi-search-ico { position: absolute; left: 16px; font-size: 1.05rem; pointer-events: none; }
/* 16px, not a hair under it. Safari zooms the whole page in when you focus an
   input set smaller than that, and the zoom doesn't come back out — you finished
   typing on a page a third too big with the list off the side of the screen. */
.poi-search input {
  font: inherit; font-size: 16px; font-weight: 600; width: 100%; color: inherit;
  padding: 14px 48px 14px 46px; border-radius: var(--r-pill);
  background: var(--surface); border: 1.5px solid var(--border);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.poi-search input::placeholder { font-weight: 500; color: var(--muted); }
.poi-search input:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--mint-pale);
}
.poi-search input::-webkit-search-cancel-button { display: none; }
/* Was a 26px target inside the field's rounded end, which on a phone meant
   aiming at something smaller than a fingertip to undo a search. */
.poi-search-clear {
  position: absolute; right: 8px; width: 34px; height: 34px; border-radius: 50%;
  font: inherit; font-size: 0.85rem; cursor: pointer; color: var(--muted);
  background: var(--sunk); border: none; display: grid; place-items: center;
}
.poi-search-clear:hover { color: var(--ink); background: var(--border); }
/* What the box is for, under it rather than crammed into the placeholder where
   "or add a place we don't list" was the half you couldn't read. */
.poi-search-hint {
  font-size: 0.8rem; color: var(--muted); line-height: 1.5;
  margin: 0 0 18px; padding-left: 16px;
}

/* Results we didn't write: real places, plainly marked as not ours */
.osm-results { margin-top: 18px; }
.poi-chip.osm { border-style: dashed; }
.poi-chip.osm .poi-chip-thumb { background: var(--sunk); }
.poi-chip.osm .poi-check {
  background: var(--mint-pale); color: var(--brand-dark); border-color: var(--mint);
  font-size: 0.9rem;
}
.poi-chip.osm:hover .poi-check { background: var(--brand); color: var(--cream); }

/* "We don't cover that, but here's what's near it" */
.off-map {
  margin-bottom: 14px; padding: 14px 18px; border-radius: var(--r-md);
  background: var(--mint-pale); border: 1.5px solid var(--mint);
}
.off-map-head { font-weight: 800; font-size: 0.95rem; margin-bottom: 5px; }
.off-map p { font-size: 0.87rem; line-height: 1.55; color: var(--ink); margin-bottom: 10px; }

.add-own {
  margin-top: 18px; padding: 18px 20px; border-radius: var(--r-md);
  background: var(--surface); border: 1.5px dashed var(--border);
}
.add-own-head { font-weight: 800; font-size: 0.95rem; margin-bottom: 14px; }
.add-own-fields {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
  gap: 12px 14px; margin-bottom: 14px;
}
.add-own input, .add-own select {
  font: inherit; font-size: 0.88rem; color: inherit; width: 100%;
  padding: 9px 12px; border-radius: var(--r-sm);
  background: var(--bg); border: 1.5px solid var(--border);
}
.add-own input:focus, .add-own select:focus { outline: none; border-color: var(--brand); }
.add-own-note { font-size: 0.78rem; color: var(--muted); margin-top: 10px; line-height: 1.5; }
/* Your own places, marked so they don't look like ours */
.poi-card.own .poi-card-img, .poi-chip.own .poi-chip-thumb {
  background: repeating-linear-gradient(45deg, var(--mint-pale), var(--mint-pale) 8px, var(--sunk) 8px, var(--sunk) 16px);
}

/* Where in the country to look, before anything is listed.
   These are a filter, not the content, and at 0.92rem in a 1.5px-bordered pill
   nine pixels tall they were reading as the heaviest thing on the page — seven
   fat buttons above the photographs they were meant to be filtering. Smaller
   type, a hairline border and less air inside: still a row of taps, no longer
   the loudest row on screen. */
.region-bar { margin: 2px 0 18px; display: flex; flex-direction: column; gap: 7px; }
.region-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.region-chip {
  font: inherit; font-weight: 700; font-size: 0.8rem; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px; min-width: 0;
  background: var(--surface); color: var(--muted);
  border: 1px solid var(--border); border-radius: var(--r-pill);
  padding: 6px 12px; transition: all 0.15s ease;
}
.region-chip:hover { border-color: var(--brand); color: var(--ink); }
/* Emoji fill their whole em box, so at text size they loom — take them down */
.region-chip .region-ico { font-size: 0.85em; line-height: 1; }
.region-chip em {
  font-style: normal; font-size: 0.72rem; font-weight: 700; color: var(--muted);
  white-space: nowrap; opacity: 0.7;
}
.region-chip.on {
  background: var(--brand); border-color: var(--brand); color: var(--cream); font-weight: 800;
}
.region-chip.on em { color: rgba(253, 252, 247, 0.8); opacity: 1; }
/* A first handful, with the rest a tap away */
.poi-grid.must-grid.capped > *:nth-child(n + 11),
.poi-chips.must-grid.capped > *:nth-child(n + 11) { display: none; }
.poi-grid.match-grid.capped > *:nth-child(n + 13) { display: none; }
.show-more {
  font: inherit; font-weight: 800; font-size: 0.88rem; cursor: pointer;
  background: var(--surface); color: var(--brand-dark);
  border: 1.5px dashed var(--brand); border-radius: var(--r-pill);
  padding: 11px 22px; margin: 14px 0 6px; transition: all 0.15s ease;
}
.show-more:hover { background: var(--mint-pale); }
.show-more.wide { display: block; width: 100%; margin-top: 22px; }

/* The wishlist grouped by city — collapsed until wanted, so a country's worth
   of places reads as a handful of places per base. */
.base-group { border: 1.5px solid var(--border); border-radius: var(--r-md); margin-bottom: 10px; background: var(--surface); }
.base-group-head {
  font: inherit; width: 100%; cursor: pointer; text-align: left;
  display: flex; align-items: center; gap: 12px;
  background: none; border: none; padding: 14px 16px; color: inherit;
}
.base-group-head:hover { background: var(--mint-pale); border-radius: var(--r-md); }
.bg-name { font-weight: 800; font-size: 0.98rem; }
.bg-count { color: var(--muted); font-size: 0.8rem; font-weight: 700; margin-left: auto; }
.bg-chev { color: var(--muted); transition: transform 0.2s ease; }
.base-group.open .bg-chev { transform: rotate(180deg); }
/* .poi-grid sets display:grid and is declared further down, so these need the
   same weight or better to close a group at all */
.poi-grid.base-group-body { display: none; padding: 0 16px 16px; }
.base-group.open .poi-grid.base-group-body { display: grid; }
.poi-chips.base-group-body { display: none; padding: 0 14px 14px; }
.base-group.open .poi-chips.base-group-body { display: grid; }
/* Map marker entrances + stay-pin pulse */
@keyframes markerIn { from { opacity: 0; transform: scale(0.25); } }
.poi-dot { animation: markerIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) backwards; }
@keyframes pillIn { from { opacity: 0; transform: translate(-50%, -175%) scale(0.4); } }
.base-pill { animation: pillIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) backwards; }
@keyframes pinPulse {
  0% { box-shadow: 0 4px 16px rgba(95, 123, 104, 0.5), 0 0 0 0 rgba(125, 154, 135, 0.5); }
  100% { box-shadow: 0 4px 16px rgba(95, 123, 104, 0.5), 0 0 0 16px rgba(125, 154, 135, 0); }
}
.base-pill.current { animation: pillIn 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) backwards, pinPulse 2.2s ease-out 1.2s infinite; }

/* Results confetti burst. Anchored across the whole head rather than sitting
   in the flex row after the title: as a flex item its launch point was
   wherever the text happened to end, which on a phone was the right edge —
   and the pieces flying right from there left the page 40-odd pixels wider
   than the screen. From the head's own centre the full ±135px spread stays
   on-screen down to 320px. */
.burst { position: absolute; inset: 0 0 auto 0; height: 0; z-index: 5; pointer-events: none; }
.burst span {
  position: absolute; left: 50%; top: -4px; font-size: 1.1rem; opacity: 0;
  animation: burstFly 1.1s ease-out forwards; animation-delay: calc(var(--i) * 70ms);
}
@keyframes burstFly {
  0% { opacity: 1; transform: translate(-50%, 0) scale(0.5); }
  100% { opacity: 0; transform: translate(calc(-50% + var(--x)), -85px) scale(1.15) rotate(20deg); }
}

/* Question swipe transitions */
@keyframes slideInRight { from { opacity: 0; transform: translateX(70px); } to { opacity: 1; transform: none; } }
@keyframes slideInLeft  { from { opacity: 0; transform: translateX(-70px); } to { opacity: 1; transform: none; } }
@keyframes slideOutLeft  { to { opacity: 0; transform: translateX(-70px); } }
@keyframes slideOutRight { to { opacity: 0; transform: translateX(70px); } }
.qcard.enter-fwd  { animation: slideInRight 0.3s cubic-bezier(0.22, 1, 0.36, 1) both; }
.qcard.enter-back { animation: slideInLeft 0.3s cubic-bezier(0.22, 1, 0.36, 1) both; }
.qcard.exit-left  { animation: slideOutLeft 0.2s ease both; pointer-events: none; }
.qcard.exit-right { animation: slideOutRight 0.2s ease both; pointer-events: none; }

/* ---------- Floating background emoji ---------- */
.floaters { position: fixed; inset: 0; pointer-events: none; z-index: 0; }
.floater {
  position: absolute; bottom: 0; font-size: 1.6rem;
  animation: floatUp linear infinite;
  filter: grayscale(0.2); opacity: 0;
}
.hero-inner { position: relative; z-index: 1; }

/* ---------- Buttons ---------- */
.btn {
  font: inherit; font-weight: 600; border: none; cursor: pointer;
  border-radius: var(--r-pill); padding: 13px 28px; transition: all 0.15s ease;
}
.btn-primary { background: linear-gradient(135deg, var(--brand), var(--mint)); color: #fff; box-shadow: 0 6px 18px rgba(125, 154, 135, 0.30); }
.btn-primary:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 10px 24px rgba(125, 154, 135, 0.38); }
.btn-primary:active:not(:disabled) { transform: scale(0.97); }
.btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-lg { font-size: 1.15rem; padding: 16px 40px; }
.btn-ghost { background: none; color: var(--muted); border: 2px solid var(--border); }
.btn-ghost:hover { color: var(--ink); border-color: var(--muted); }

/* ---------- Cinematic landing ---------- */
.hero-cinema {
  /* transparent, not cream: the fade at the bottom hands over to the page's
     own fixed wash, which must be the same one visible below the seam */
  position: relative; overflow: hidden;
  /* Fills the screen — it is the whole landing page, so anything short of that
     leaves cream below the fold. Capping the hero itself did exactly that. */
  display: flex; align-items: center;
  height: 100svh; min-height: 560px;
}
/* The filter also makes the stage a stacking context, which is what keeps the
   slides' z-index below the scrim and the copy rather than fighting them. */
.cine-stage { position: absolute; inset: 0; filter: saturate(1.05); }
/* A true cross-fade, with nothing showing through the seam. Only the arriving
   slide animates: it is lifted above the one it replaces and fades in over it,
   while the outgoing slide holds at full opacity and is cut once it is covered.
   Fading both at once left them each half-transparent mid-way, and the page
   behind showed through as a dip in brightness on every change. */
.cine-slide { position: absolute; inset: 0; opacity: 0; transition: opacity 0s 1.7s; }
.cine-slide.on {
  opacity: 1; z-index: 1;
  /* Eased, not linear — a linear fade spends its whole length half-done and
     reads as a dissolve glitch; easing gives it an arrival and a landing. */
  transition: opacity 1.5s cubic-bezier(0.4, 0, 0.2, 1);
  /* The photo also settles as it fades in: a touch larger on arrival, easing
     back to rest. Only the incoming slide runs it, and the keyframe ends at
     the identity, so when .on moves elsewhere nothing snaps. */
  animation: cineArrive 2.2s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes cineArrive { from { transform: scale(1.05); } }
.cine-slide img {
  width: 100%; height: 100%; object-fit: cover;
  /* The photographs are fetched from Wikipedia after the page is up, so each
     one has to arrive rather than appear — without this the first thing you
     see is the picture landing in a single frame. */
  opacity: 0; transition: opacity 0.9s ease;
  /* The pan runs on every slide and is only ever paused, never restarted.
     Hanging it off .on meant the outgoing photo snapped from 1.09 back to 1
     the instant the class came off, part-way through its own fade — the jump.
     Pausing freezes the transform where it stands, so between countries
     nothing moves but the opacity. */
  animation: kenburns 26s ease-in-out infinite alternate;
  animation-play-state: paused;
}
.cine-slide img.loaded { opacity: 1; }
.cine-slide.on img { animation-play-state: running; }
.cine-scrim {
  /* The photograph is the point of this page, so it gets to be a photograph.
     This used to be a cream wash at 99% opacity across the left two-thirds,
     which kept the warm brown type readable by hiding almost all of the
     picture. Now it's a dark gradient weighted to the bottom and left — enough
     to carry light type, little enough to leave the image vivid. Its dark is
     the brand ink's own brown rather than neutral black, so any photo reads
     as lit by the same warm palette as the rest of the page. */
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(96deg, rgba(58, 44, 30, 0.74) 0%, rgba(58, 44, 30, 0.5) 34%,
                    rgba(58, 44, 30, 0.16) 62%, rgba(58, 44, 30, 0) 82%),
    linear-gradient(to top, rgba(48, 37, 25, 0.74) 0%, rgba(48, 37, 25, 0.24) 32%, transparent 58%),
    linear-gradient(to bottom, rgba(48, 37, 25, 0.45), transparent 22%);
}
/* The hand-off to the cream page below. A soft fade was tried twice here —
   painted cream, then a mask — and both read as fog with a hairline at the
   end of it. The photo now tucks under a drawn cream wave instead: a crisp,
   deliberate edge in the brand's own hand, with a pale sage wave peeking out
   behind it, and the corner Kobo standing on it like a hill. */
.cine-wave {
  position: absolute; left: 0; right: 0; bottom: -1px; z-index: 2;
  display: block; width: 100%; height: clamp(44px, 7vw, 96px);
}
.cine-wave .w-back { fill: var(--mint); opacity: 0.5; }
.cine-wave .w-front { fill: var(--bg); }
/* The hero is the landing's first screen, exactly one screen tall, with the
   two explainer sections following below the fold. */
.hero-cinema { max-height: 100svh; }
.cine-top {
  position: absolute; top: 0; left: 0; right: 0; z-index: 3;
  display: flex; align-items: center; justify-content: space-between;
  padding: 24px clamp(22px, 6vw, 84px); color: #fff;
}
.cine-mark { font-family: var(--font-display); font-weight: 800; font-size: 1.3rem; display: flex; align-items: center; gap: 9px; color: var(--cream); text-shadow: 0 2px 14px rgba(24,16,12,0.5); }
/* The brand-sheet wordmark: peach pin, lowercase two-tone. Over the dark hero
   photo it runs all-white, as the reversed logo on the sheet does; on light
   pages "ko" takes the sage. */
.cine-mark .nav-pin { width: 21px; height: 21px; flex: none; color: var(--gold); stroke-width: 2.4; }
.cine-mark .mark-word { text-transform: lowercase; letter-spacing: 0.01em; }
.cine-mark .mark-word b { font-weight: 800; }
.cine-mark.dark .mark-word b { color: var(--brand); }
.cine-compass { display: inline-block; animation: compassRock 5.5s ease-in-out infinite; }
.btn-outline { background: var(--cream); color: var(--ink); border: 1.5px solid var(--line); }
.btn-outline:hover { background: var(--mint-soft); border-color: var(--brand); }

.cine-inner {
  position: relative; z-index: 2; width: 100%;
  max-width: 1240px; margin: 0 auto; padding: 0 clamp(22px, 6vw, 84px); color: var(--cream);
  /* One group, anchored low: the copy and its Explore button sit together in
     the bottom-left, where the scrim is darkest, leaving the photograph clear
     above. Pinning the copy high left it floating in the middle of the frame. */
  display: flex; flex-direction: column; justify-content: flex-end;
  height: 100%;
  padding-top: clamp(90px, 13vh, 150px);
  /* Clears the cream wave along the bottom edge, and then some: sitting right
     on the wave the copy read as having slid off the photo. */
  padding-bottom: clamp(96px, 17vh, 200px);
  align-self: end;
}
/* One sentence that lands on a place: the promise set small and in sentence
   case, the country given the display size the photograph can carry. Big
   enough to be the picture's title rather than a caption on it — Nunito is a
   wide face, so the cap is lower than the old handwritten one needed. */
.cine-headline { display: flex; flex-direction: column; gap: 4px; color: var(--cream); }
.cine-lede {
  font-size: clamp(1.1rem, 2.5vw, 1.85rem); font-weight: 700; line-height: 1.15;
  letter-spacing: 0; text-shadow: 0 2px 18px rgba(24, 16, 12, 0.6);
}
.cine-country {
  font-size: clamp(2.6rem, 7.4vw, 5.6rem); line-height: 0.98;
  text-transform: uppercase; text-shadow: 0 6px 40px rgba(24, 16, 12, 0.5);
}
.cine-sub {
  max-width: 34rem; margin: 18px 0 26px;
  color: rgba(253, 252, 247, 0.9); font-size: 1.05rem;
  text-shadow: 0 2px 18px rgba(24, 16, 12, 0.6);
}

.cine-cta { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.cine-link { color: var(--brand-dark); font-weight: 800; text-decoration: none; border-bottom: 1.5px solid var(--mint); padding-bottom: 2px; }
.cine-link:hover { border-color: var(--brand); }

.below-hero { max-width: 980px; margin: 0 auto; padding: 8px 22px 44px; }
.below-hero .section-label { text-align: center; margin-bottom: 18px; }
.below-hero .hero-features { margin-top: 26px; }

/* ---------- Hero (legacy inner-page bits) ---------- */
.hero { text-align: center; padding: 48px 0 20px; }
.hero-grid {
  display: grid; grid-template-columns: 1.05fr 1fr; gap: 48px;
  align-items: center; text-align: left; margin-bottom: 26px;
}
.hero-grid .hero-inner { text-align: left; }
.hero-grid .logo-badge { margin: 0 0 22px; }
.hero-grid .hero-sub { margin: 0 0 30px; }
.hero-collage { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.collage-tile {
  position: relative; aspect-ratio: 4 / 3.4; border-radius: var(--r-md); overflow: hidden;
  background: linear-gradient(135deg, var(--mint-pale), var(--mint-soft));
  display: flex; align-items: center; justify-content: center; font-size: 2rem;
  box-shadow: var(--shadow);
}
.collage-tile:nth-child(even) { transform: translateY(22px); }
.collage-tile img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0; transition: opacity 0.6s ease;
}
.collage-tile img.loaded { opacity: 1; }
.logo-badge {
  font-size: 2.6rem; width: 84px; height: 84px; margin: 0 auto 20px;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--brand), var(--mint));
  border-radius: var(--r-lg); box-shadow: var(--shadow);
  transition: transform 0.3s ease;
}
.logo-badge:hover { transform: rotate(-8deg) scale(1.05); }
.hero h1 { font-size: 3rem; letter-spacing: -0.02em; }
.hero h1 span { color: var(--brand); }
.tagline { font-size: 1.3rem; font-weight: 600; color: var(--accent); margin: 4px 0 16px; }
.hero-sub { max-width: 560px; margin: 0 auto 32px; color: var(--muted); font-size: 1.05rem; }

.hero-features {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
  margin-top: 56px; text-align: center;
  list-style: none; padding: 0;
}
.feat {
  position: relative;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 30px 20px 26px;
  display: flex; flex-direction: column; gap: 6px; align-items: center;
  animation: fadeSlideIn 0.6s ease both;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.feat:hover { transform: translateY(-4px); box-shadow: var(--shadow); }
.feat span { font-size: 1.8rem; }
.feat small { color: var(--muted); line-height: 1.5; }
/* The number, so three cards read as three steps in order rather than three
   unrelated boasts */
.feat .feat-step {
  position: absolute; top: -15px; left: 50%; transform: translateX(-50%);
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--brand); color: var(--cream);
  font-size: 0.9rem; font-weight: 800; line-height: 30px;
}
.feat strong { font-size: 1.05rem; }

.how-strip-foot { display: flex; justify-content: center; margin-top: 34px; }
/* .explore-arrow is a flex disc, so it stacks under the label unless the button
   it sits in is a flex row too — which is why it looks right on .planner-go */
.how-strip-foot .btn {
  display: inline-flex; align-items: center; gap: 14px;
  padding: 9px 9px 9px 28px; font-size: 1rem;
}

/* ---------- Progress ---------- */
.progress-wrap { display: flex; align-items: center; gap: 14px; margin-bottom: 36px; }
.back-link {
  background: var(--surface); border: 1.5px solid var(--border); color: var(--muted);
  font: inherit; font-weight: 700; cursor: pointer; white-space: nowrap;
  border-radius: var(--r-pill); padding: 7px 16px;
  transition: all 0.15s ease;
}
.back-link:hover { color: var(--ink); border-color: var(--muted); transform: translateX(-2px); }
.progress { flex: 1; height: 9px; background: var(--border); border-radius: var(--r-pill); }
.progress-fill { height: 100%; background: linear-gradient(90deg, var(--brand), var(--mint)); border-radius: var(--r-pill); transition: width 0.5s cubic-bezier(0.22, 1, 0.36, 1); position: relative; }
.progress-plane {
  position: absolute; right: 0; top: 50%; transform: translate(55%, -58%);
  font-size: 1.1rem; filter: drop-shadow(0 2px 4px rgba(92, 74, 62, 0.25));
}
.progress-label { color: var(--muted); font-size: 0.85rem; white-space: nowrap; }

/* ---------- Questions ---------- */
.question h2 { font-size: 1.9rem; letter-spacing: -0.01em; }
.question-sub { color: var(--muted); margin: 6px 0 28px; }

/* One-page quiz sections: select → scroll down */
.quiz-sec {
  padding: 34px 0;
  border-bottom: 1px dashed var(--border);
  scroll-margin-top: 18px;
  transition: opacity 0.45s ease, filter 0.45s ease;
}
.quiz-sec:last-child { border-bottom: none; }
.quiz-sec.locked {
  opacity: 0.3; filter: saturate(0.4);
  pointer-events: none; user-select: none;
}
.quiz-sec h2 { font-size: 1.7rem; }
.quiz-sec .question-sub { margin-bottom: 22px; }

.options { display: grid; gap: 14px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }

.card {
  background: var(--surface); border: 2px solid var(--border);
  border-radius: var(--radius); padding: 20px;
  display: flex; flex-direction: column; gap: 4px; text-align: left;
  position: relative;
}
.option { cursor: pointer; font: inherit; color: inherit; transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease; }
.option:hover:not(.disabled) { border-color: var(--brand); transform: translateY(-2px); box-shadow: var(--shadow); }
.option:active:not(.disabled) { transform: scale(0.98); }
.option.selected { border-color: var(--brand); background: var(--mint-pale); box-shadow: var(--shadow); }
.option.disabled { opacity: 0.5; cursor: default; }
.card-icon { font-size: 1.9rem; }
.card-title { font-weight: 700; font-size: 1.05rem; }
.card-title em { font-style: normal; color: var(--accent); font-size: 0.9rem; }
.card-sub { color: var(--muted); font-size: 0.9rem; }
.card.compact { flex-direction: row; align-items: center; gap: 14px; }

.tick {
  position: absolute; right: 16px; top: 50%; transform: translateY(-50%) scale(0);
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--brand); color: #fff; font-size: 0.85rem; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.option.selected .tick { transform: translateY(-50%) scale(1); }

.step-footer { margin-top: 28px; display: flex; gap: 12px; }
.step-footer.center { justify-content: center; }

/* ---------- Loading ---------- */
.loading { text-align: center; padding: 100px 0; }
.plane-track { position: relative; height: 70px; margin-bottom: 24px; overflow: hidden; }
.plane { position: absolute; top: 20px; font-size: 2.4rem; animation: planeFly 2.4s ease-in-out infinite; }
.loading h2 { font-size: 1.7rem; }
.loading-msg { color: var(--muted); margin-top: 10px; min-height: 1.6em; transition: opacity 0.3s; }
.loading-dots { display: flex; gap: 8px; justify-content: center; margin-top: 24px; }
.loading-dots span {
  width: 10px; height: 10px; border-radius: 50%; background: var(--brand);
  animation: dotPulse 1.2s ease-in-out infinite;
}
.loading-dots span:nth-child(2) { animation-delay: 0.2s; }
.loading-dots span:nth-child(3) { animation-delay: 0.4s; }

/* ---------- Results ---------- */
.results-head { text-align: center; margin: 20px 0 28px; }
.results-kicker { color: var(--muted); font-weight: 600; text-transform: uppercase; font-size: 0.8rem; letter-spacing: 0.06em; }
.pick-badge {
  display: inline-block; margin-top: 10px; padding: 6px 16px; border-radius: var(--r-pill);
  background: linear-gradient(135deg, var(--mint-pale), var(--mint-soft)); color: var(--brand-dark);
  font-weight: 700; font-size: 0.85rem;
}
.pick-badge.alt { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.pick-badge.alt a { text-decoration: underline; cursor: pointer; font-weight: 700; }
.results-head h2 { font-size: 2.4rem; margin: 8px 0 4px; letter-spacing: -0.02em; }
.highlight { color: var(--brand); }
.results-area { color: var(--muted); margin-bottom: 14px; }

.match-ring { display: inline-flex; align-items: baseline; gap: 10px; background: var(--accent-soft); padding: 10px 22px; border-radius: var(--r-pill); }
.match-num { font-size: 1.6rem; font-weight: 800; color: var(--accent); font-variant-numeric: tabular-nums; }
.match-sub { color: var(--accent); font-weight: 600; font-size: 0.92rem; }

.winner-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 28px; box-shadow: var(--shadow);
  text-align: center;
}
.winner-emoji { font-size: 3rem; margin-bottom: 10px; }
.winner-blurb { font-size: 1.05rem; max-width: 620px; margin: 0 auto 20px; }

/* score bars */
.score-grid { display: flex; flex-direction: column; gap: 10px; max-width: 560px; margin: 0 auto 20px; }
.score-row { display: grid; grid-template-columns: 150px 1fr 44px; align-items: center; gap: 12px; text-align: left; }
.score-label { font-size: 0.88rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* where the bars came from, when we inferred them from the wishlist */
.score-note { font-size: 0.82rem; opacity: 0.7; margin: -8px 0 18px; text-align: center; }
.score-bar { height: 10px; background: var(--border); border-radius: var(--r-pill); overflow: hidden; }
.score-fill {
  height: 100%; width: 0; border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--brand), var(--mint));
  transition: width 0.9s cubic-bezier(0.22, 1, 0.36, 1) 0.3s;
}
.score-fill.good { background: linear-gradient(90deg, var(--brand-dark), var(--mint)); }
.score-fill.poor { background: var(--line); }
.score-num { font-size: 0.85rem; color: var(--muted); font-variant-numeric: tabular-nums; text-align: right; }

.tip-box {
  text-align: left; font-size: 0.9rem; line-height: 1.5;
  background: linear-gradient(90deg, var(--mint-pale), rgba(238, 244, 239, 0) 82%);
  border-left: 3px solid var(--mint);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding: 9px 14px;
}
.caveat { margin-top: 14px; font-size: 0.9rem; color: var(--muted); text-align: left; }

.daytrips { margin-top: 24px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px 28px; }
.daytrips h3 { margin-bottom: 14px; font-size: 1.15rem; }
.daytrips ul { list-style: none; }
.daytrips li {
  display: flex; justify-content: space-between; gap: 16px;
  padding: 10px 0; border-bottom: 1px solid var(--border);
  transition: background 0.15s ease, padding-left 0.15s ease;
}
.daytrips li:hover { background: var(--bg); padding-left: 8px; }
.daytrips li:last-child { border-bottom: none; }
.trip-time { color: var(--muted); font-size: 0.9rem; white-space: nowrap; }

.split-card {
  margin-top: 24px; border-radius: var(--radius); padding: 24px 28px;
  background: linear-gradient(135deg, var(--mint-pale), var(--mint-pale)); border: 1px solid var(--mint);
}
.split-card.good { background: var(--mint-pale); border-color: var(--mint); }
.leg-area { font-size: 0.82rem; color: var(--muted); font-weight: 700; margin-top: 2px; }
.leg-covers { font-size: 0.76rem; color: var(--muted); line-height: 1.45; margin-top: 6px; }
.leg-link { margin-top: auto; }

/* Share, costs, transport hops, booking links */
a.btn { text-decoration: none; display: inline-block; text-align: center; }
/* Two columns while both labels fit on one line each, and stacked the moment
   they don't — side by side in a 230px bubble the hotel button was three lines
   of wrapped text next to a one-word Airbnb, which read as a mistake. */
.stay-links { display: flex; flex-wrap: wrap; gap: 8px; align-items: stretch; }
.stay-links .btn {
  display: flex; align-items: center; justify-content: center;
  flex: 1 1 auto; min-width: 0; white-space: nowrap;
  padding-left: 14px; padding-right: 14px;
}
.stay-links .btn-ghost { flex: 0 1 auto; }

/* Kobo sees you off to the booking sites: mascot beside a speech bubble that
   holds the buttons */
.stay-book { display: flex; gap: 8px; align-items: flex-end; margin-top: 16px; }
/* doubled selector: the generic .kobo { width: 100% } is declared later in
   the sheet and would otherwise blow the mascot up to column width */
.stay-book .book-kobo { width: 74px; height: 74px; flex: none; object-fit: contain; }
.book-bubble {
  position: relative; flex: 1; min-width: 0;
  background: var(--surface); border: 1.5px solid var(--line);
  border-radius: var(--r-md); padding: 12px 14px 14px;
  box-shadow: var(--shadow);
}
/* the tail, pointing down-left at Kobo */
.book-bubble::before {
  content: ""; position: absolute; left: -7px; bottom: 22px;
  width: 13px; height: 13px; background: var(--surface);
  border-left: 1.5px solid var(--line); border-bottom: 1.5px solid var(--line);
  transform: rotate(45deg);
}
.book-line { font-size: 0.84rem; font-weight: 700; margin-bottom: 10px; }

/* The flight facts again, small, at the foot of the booking column — in the
   same tip language as the ess-flight strip it echoes */
.fly-reminder {
  display: flex; gap: 10px; align-items: flex-start;
  margin-top: 14px; padding: 8px 12px;
  background: linear-gradient(90deg, var(--mint-pale), rgba(238, 244, 239, 0) 82%);
  border-left: 3px solid var(--mint);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  font-size: 0.8rem; line-height: 1.5; color: var(--ink);
}
.fly-reminder .fly-rem-ico { width: 16px; height: 16px; flex: none; margin-top: 2px; color: var(--brand-dark); }
.fly-reminder em { display: block; margin-top: 2px; font-style: normal; font-size: 0.72rem; color: var(--muted); }
.fpill.share { border-color: var(--brand); color: var(--brand); }
.fpill.share:hover { background: var(--accent-soft); }
.cost-line {
  background: var(--accent-soft); border-radius: var(--r-sm); padding: 10px 16px;
  font-size: 0.92rem; margin: 8px 0 10px;
}
.season-adj { margin-top: 12px; font-size: 0.85rem; font-weight: 700; color: var(--accent); }
.split-hop { flex: 0 0 130px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; text-align: center; }
.split-hop small { font-size: 0.74rem; color: var(--muted); font-weight: 700; line-height: 1.35; }
.leg-link {
  margin-top: 8px; font-size: 0.8rem; font-weight: 800; color: var(--brand);
  text-decoration: none;
}
.leg-link:hover { text-decoration: underline; }

/* Photo thumbs replacing emoji (map dots, compare cards, legs, itinerary) */
.wthumb {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: var(--r-sm); overflow: hidden; flex-shrink: 0;
  background: linear-gradient(135deg, var(--mint-pale), var(--mint-soft)); vertical-align: middle;
}
.wthumb em { font-style: normal; font-size: 1.2rem; }
.wthumb img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0; transition: opacity 0.4s ease;
}
.wthumb img.loaded { opacity: 1; }
.wthumb.alt-thumb { width: 52px; height: 52px; }
.wthumb.mini { width: 26px; height: 26px; border-radius: 50%; margin-right: 7px; }
.wthumb.mini em { font-size: 0.85rem; }
/* The base-name row only — the bolds inside the beds line stay inline */
.split-leg > strong { display: flex; align-items: center; }
.itin-base { display: flex; align-items: center; }
.itin-base .wthumb.mini { width: 20px; height: 20px; margin-right: 6px; }
.itin-base .wthumb.mini em { font-size: 0.7rem; }
.wl-img { position: relative; }
.wl-img .wl-emoji { font-style: normal; }
.wl-img img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0; transition: opacity 0.35s ease;
}
.wl-img img.loaded { opacity: 1; }

/* Day-by-day itinerary */
.itinerary {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 24px 28px;
}
.itin-day { display: flex; gap: 16px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.itin-day:last-child { border-bottom: none; }
.itin-num {
  flex-shrink: 0; width: 64px; text-align: center; height: fit-content;
  font-weight: 800; font-size: 0.82rem; color: var(--brand);
  background: var(--accent-soft); border-radius: var(--r-sm); padding: 4px 0;
}
.itin-base {
  font-size: 0.75rem; font-weight: 800; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.05em;
}
.itin-body ul { list-style: none; margin-top: 2px; }
.itin-body li { font-size: 0.93rem; padding: 2px 0; line-height: 1.5; }
/* A pick's row is draggable and has to look it: a dashed border and grip make
   it read as a loose card, not a printed line. The days that can take it
   light up while it's in the air. */
.itin-body li.itin-pick {
  display: flex; align-items: center; gap: 8px;
  cursor: grab; border-radius: var(--r-sm); padding: 4px 9px; margin: 3px 0 3px -9px;
  background: var(--surface); border: 1.5px dashed var(--mint);
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.itin-body li.itin-pick:hover {
  background: var(--mint-pale); border-color: var(--brand); border-style: solid;
  box-shadow: var(--shadow);
}
.itin-body li.itin-pick:active { cursor: grabbing; }
.itin-body li.itin-pick.dragging { opacity: 0.35; }
.itin-pick-label { flex: 1; min-width: 0; }
.itin-grip { flex: none; color: var(--brand-dark); opacity: 0.75; font-size: 0.8rem; }
/* Rows wrap so a note can sit as a second line under its visit */
.itin-body li.itin-pick { flex-wrap: wrap; }
.itin-seq {
  flex: none; width: 19px; height: 19px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--mint-pale); color: var(--brand-dark);
  font-size: 0.72rem; font-weight: 800;
}
.itin-note-btn {
  flex: none; font: inherit; font-size: 0.74rem; font-weight: 800; cursor: pointer;
  background: none; border: none; color: var(--brand-dark);
  opacity: 0; transition: opacity 0.15s ease; padding: 2px 4px;
}
.itin-body li.itin-pick:hover .itin-note-btn, .itin-note-btn:focus-visible { opacity: 0.85; }
.itin-note {
  flex-basis: 100%; margin-left: 26px; font-size: 0.8rem; color: var(--accent);
  line-height: 1.45;
}
.itin-note::before { content: "📝 "; }
.itin-note-edit { flex-basis: 100%; margin-left: 26px; }
.itin-note-edit input {
  width: 100%; font: inherit; font-size: 0.8rem; color: var(--ink);
  background: var(--surface); border: 1.5px solid var(--brand); border-radius: var(--r-sm);
  padding: 5px 9px; outline: none;
}
/* The wishlist's out-of-reach picks, said plainly at the foot of the plan
   rather than quietly missing from it — in the house tip language (gold edge,
   fading wash), same as the pace and access caveats */
.itin-leftover {
  margin-top: 16px; padding: 11px 16px;
  background: linear-gradient(90deg, var(--gold-soft), rgba(251, 229, 216, 0) 88%);
  border-left: 3px solid var(--gold);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
.itin-leftover-head { font-size: 0.85rem; font-weight: 800; color: var(--ink); margin-bottom: 7px; }
.itin-leftover ul { list-style: none; display: flex; flex-direction: column; gap: 4px; }
.itin-leftover li { font-size: 0.85rem; line-height: 1.45; }
.itin-leftover li span { color: var(--muted); }
.itin-leftover li span::before { content: " · "; }
.itin-leftover-note { margin-top: 8px; font-size: 0.8rem; color: var(--muted); }

.itin-actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 18px; }
.itin-save-hint { font-size: 0.78rem; color: var(--muted); }
/* The days a drag may land on, and the one it's currently over */
.itin-day { transition: background 0.15s ease, box-shadow 0.15s ease; border-radius: var(--r-sm); }
.itin-day.can-drop { box-shadow: inset 0 0 0 1.5px var(--mint); }
.itin-day.drop-ok { background: var(--mint-pale); box-shadow: inset 0 0 0 2px var(--brand); }

/* Must-visit bar + plan-for-me */
.must-bar { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.must-bar .section-label { margin: 22px 0 0; }
.btn-sm { padding: 8px 18px; font-size: 0.88rem; }
.must-grid { margin-bottom: 8px; }
.split-card h3 { font-size: 1.15rem; margin-bottom: 6px; }
.split-plan { display: flex; align-items: stretch; gap: 14px; margin: 16px 0; flex-wrap: wrap; }
.split-leg { flex: 1 1 240px; background: var(--surface); border-radius: var(--r-sm); padding: 14px 18px; display: flex; flex-direction: column; box-shadow: var(--shadow); }
.split-days { font-size: 0.8rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.split-arrow { font-size: 1.4rem; color: var(--brand); }
.split-note { color: var(--muted); font-size: 0.92rem; }

.runners-up { margin-top: 32px; }
.runners-up h3 { margin-bottom: 14px; }
.alt-card { box-shadow: none; }

/* ---------- Activity picker (step 5) ---------- */
.section-label {
  font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--brand); margin: 22px 0 12px;
}
.section-label.muted { color: var(--muted); }
.cat-group { margin-bottom: 30px; }
.cat-group.dim { opacity: 0.9; }
.cat-head { font-weight: 800; margin-bottom: 14px; font-size: 1.15rem; }
.chip-wrap { display: flex; flex-wrap: wrap; gap: 10px; }
.chip {
  display: inline-flex; align-items: center; gap: 7px;
  font: inherit; font-weight: 600; font-size: 0.9rem; color: inherit;
  background: var(--surface); border: 2px solid var(--border); border-radius: var(--r-pill);
  padding: 8px 16px; cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.chip:hover { border-color: var(--brand); transform: translateY(-1px); box-shadow: var(--shadow); }
.chip:active { transform: scale(0.96); }
.chip.selected { border-color: var(--brand); background: var(--mint-pale); box-shadow: var(--shadow); }
.sticky-footer {
  position: sticky; bottom: 12px; z-index: 600;
  background: var(--bg); padding: 12px 0;
  border-top: 1px solid var(--border);
}

/* Suggestion tiles — Airbnb listing style, compact.
   182px put three across the results panel and stopped a hair short of four, so
   every card was 270px wide: a photograph the size of a postcard for a place you
   are only deciding yes or no about, and nine of them to a screen. 150 fits four
   with room to spare, and four smaller cards show more of the country per screen
   than three big ones ever did. */
.poi-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 18px 14px;
}
/* The name is its own control inside the card: tapping the card adds the place,
   tapping the name asks what it is. Underlined on hover so it reads as one. */
.poi-open { cursor: pointer; text-decoration-color: transparent; }
.poi-open:hover, .poi-open:focus-visible {
  text-decoration: underline; text-underline-offset: 3px; text-decoration-color: currentColor;
}
.poi-open:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: 4px; }

/* ---------- A place, in full ---------- */
.poi-modal { position: fixed; inset: 0; z-index: 2000; display: grid; place-items: center; padding: 20px; }
.pm-backdrop { position: absolute; inset: 0; background: rgba(41, 33, 28, 0.55); backdrop-filter: blur(2px); }
.pm-card {
  position: relative; width: min(460px, 100%); max-height: min(88vh, 780px); overflow-y: auto;
  background: var(--surface); border-radius: 26px; box-shadow: 0 24px 60px rgba(41, 33, 28, 0.3);
  animation: pmIn 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes pmIn { from { opacity: 0; transform: translateY(16px) scale(0.98); } }
.pm-photo {
  position: relative; height: 250px; border-radius: 26px 26px 20px 20px; overflow: hidden;
  background: linear-gradient(135deg, var(--mint-pale), var(--mint-soft));
  display: grid; place-items: center;
  /* The photo is tappable — it steps the gallery (see bindShotNav) */
  cursor: pointer; user-select: none; -webkit-user-select: none;
}
.pm-fallback { font-size: 3rem; }
/* The gallery is a stack that cross-fades: only the slide that is both loaded
   and current shows, so a slow-loading photo never flashes an empty frame. */
.pm-photo img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 0.6s ease;
}
.pm-photo img.loaded.on { opacity: 1; }
/* Top centre, not under the title: a two-line name reaches most of the way up
   the photo and the dots landed on top of it. */
.pm-dots {
  position: absolute; left: 62px; right: 62px; top: 24px; z-index: 3;
  display: flex; justify-content: center; gap: 6px;
}
.pm-dot {
  width: 7px; height: 7px; padding: 0; border: none; border-radius: 50%; cursor: pointer;
  background: rgba(253, 252, 247, 0.45); transition: all 0.25s ease;
}
.pm-dot.on { background: var(--cream); width: 18px; border-radius: 4px; }
/* A wash under the title, so white text holds on any photo */
.pm-photo::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, rgba(41, 33, 28, 0.92) 0%, rgba(41, 33, 28, 0.55) 32%, rgba(41, 33, 28, 0.1) 62%, transparent 80%);
}
.pm-round {
  position: absolute; top: 14px; z-index: 2; width: 38px; height: 38px; border-radius: 50%;
  font: inherit; font-size: 1.15rem; line-height: 1; cursor: pointer;
  background: rgba(253, 252, 247, 0.9); border: none; color: var(--ink);
  display: grid; place-items: center; transition: transform 0.15s ease, background 0.15s ease;
}
.pm-round:hover { transform: scale(1.08); }
.pm-back { left: 14px; }
.pm-fav { right: 14px; }
.pm-fav.on { background: var(--brand); color: var(--cream); }
.pm-title { position: absolute; left: 20px; right: 20px; bottom: 16px; z-index: 2; color: var(--cream); }
.pm-where { font-size: 0.78rem; font-weight: 700; opacity: 0.92; }
.pm-title h2 { font-size: 1.7rem; line-height: 1.15; margin-top: 2px; }
.pm-stats {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px; padding: 16px 18px 4px;
}
.pm-stat { display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center; min-width: 0; }
.pm-stat b { font-size: 0.86rem; font-weight: 800; line-height: 1.3; }
/* "Recommended time" is longer than the column, so labels wrap centred rather
   than forcing the three stats out of alignment. */
.pm-stat em {
  font-style: normal; font-size: 0.68rem; font-weight: 700; color: var(--muted);
  line-height: 1.3; max-width: 100%;
}
.pm-card .pm-ico { width: 18px; height: 18px; margin-bottom: 3px; }
.pm-body { padding: 12px 22px 22px; }
.pm-body h3 { font-size: 1.05rem; margin: 14px 0 5px; }
.pm-body p { font-size: 0.9rem; line-height: 1.6; color: var(--muted); }
.pm-body p + p { margin-top: 9px; }
.pm-tag { font-size: 0.78rem !important; font-weight: 700; margin-top: 12px; }
.pm-tips { list-style: none; display: flex; flex-direction: column; gap: 7px; margin-top: 4px; }
.pm-tips li {
  display: flex; gap: 8px; align-items: flex-start;
  font-size: 0.85rem; line-height: 1.55; color: var(--ink);
  background: linear-gradient(90deg, var(--mint-pale), rgba(238, 244, 239, 0) 82%);
  border-left: 3px solid var(--mint);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding: 6px 11px;
}
.pm-tips li::before { content: "💡"; flex: none; font-size: 0.85rem; }
.pm-actions { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 18px; }
.pm-actions .btn { flex: 1 1 auto; }
@media (max-width: 520px) {
  .poi-modal { padding: 0; align-items: end; }
  .pm-card { width: 100%; max-height: 92vh; border-radius: 22px 22px 0 0; }
  .pm-photo { height: 210px; border-radius: 22px 22px 20px 20px; }
}

/* The suggestion list: a round photo, a name, a line, and the facts as icons.
   A quarter the height of a poi-card, so a long tail of places reads as a list
   to skim rather than a second shop window. */
.poi-chips {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
  gap: 8px;
}
.poi-chip {
  position: relative; font: inherit; color: inherit; text-align: left; cursor: pointer;
  display: flex; align-items: center; gap: 12px;
  background: var(--surface); border: 1.5px solid var(--border); border-radius: var(--r-md);
  padding: 9px 12px; min-width: 0;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}
.poi-chip:hover { border-color: var(--brand); transform: translateY(-1px); }
.poi-chip.selected { border-color: var(--brand); background: var(--mint-pale); }
.poi-chip-thumb {
  position: relative; flex: none; width: 52px; height: 52px; border-radius: 50%;
  overflow: hidden; background: var(--mint-pale);
  display: grid; place-items: center; font-size: 1.25rem;
}
.poi-chip-thumb img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 0.3s ease;
}
.poi-chip-thumb img.loaded { opacity: 1; }
.poi-chip-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.poi-chip-body strong { font-size: 0.9rem; line-height: 1.3; }
.poi-chip-desc {
  font-size: 0.78rem; color: var(--muted); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.poi-chip-meta { display: flex; flex-wrap: wrap; gap: 4px 8px; margin-top: 2px; }
.poi-chip-meta em {
  font-style: normal; font-size: 0.7rem; font-weight: 700; color: var(--muted);
  white-space: nowrap;
}
.poi-chip .poi-check {
  position: static; margin-left: auto; flex: none;
  width: 22px; height: 22px; border-radius: 50%; font-size: 0.72rem;
  display: grid; place-items: center;
  background: var(--sunk); color: transparent; border: 1.5px solid var(--border);
}
.poi-chip.selected .poi-check {
  background: var(--brand); border-color: var(--brand); color: var(--cream);
}
.poi-card {
  position: relative; font: inherit; color: inherit; text-align: left;
  background: none; border: none; padding: 0; cursor: pointer;
  display: flex; flex-direction: column; gap: 7px;
}
.poi-card-img {
  position: relative; aspect-ratio: 4 / 3; width: 100%;
  border-radius: var(--r-sm); overflow: hidden;
  background: linear-gradient(135deg, var(--mint-pale), var(--mint-soft));
  display: flex; align-items: center; justify-content: center;
  transition: box-shadow 0.2s ease;
}
.poi-card:hover .poi-card-img { box-shadow: 0 8px 24px rgba(92, 74, 62, 0.18); }
.poi-card:active .poi-card-img { transform: scale(0.98); }
.poi-fallback { font-size: 2rem; }
.poi-card-img img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0;
  transition: opacity 0.4s ease, transform 0.35s ease;
}
.poi-card-img img.loaded { opacity: 1; }
.poi-card:hover .poi-card-img img { transform: scale(1.05); }
.poi-card.selected .poi-card-img {
  outline: 3px solid var(--brand); outline-offset: 2px;
}
.badge-first {
  position: absolute; top: 7px; left: 7px; z-index: 2;
  background: rgba(255, 255, 255, 0.95); color: var(--ink);
  font-size: 0.68rem; font-weight: 800;
  padding: 2px 8px; border-radius: var(--r-pill);
  box-shadow: 0 2px 8px rgba(92, 74, 62, 0.2);
}
.poi-card-body { display: flex; flex-direction: column; gap: 1px; padding: 0 2px; }
/* which part of the country a place is in */
.poi-card-where {
  display: block; font-size: 0.66rem; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--brand-dark); margin-bottom: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.poi-card-title { font-size: 0.88rem; font-weight: 800; line-height: 1.3; }
/* The two facts left on the card: what kind of thing it is, and how much of a
   day it takes. Everything else moved into the detail card behind the name.
   `nowrap` on a 150px card would push "Overnight ryokan stay" out past its own
   edge, so a long tag is allowed to take a second line instead. */
.poi-card-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.poi-card-tag {
  font-size: 0.7rem; font-weight: 700; color: var(--muted); min-width: 0;
  background: var(--sunk); border-radius: var(--r-pill); padding: 2px 8px;
}
.poi-card-tag.cat { background: var(--mint-pale); color: var(--brand-dark); }
/* Not in the base you'd be staying in, so it costs a day rather than an hour */
.poi-card-tag.trip { background: var(--gold-soft); color: var(--ink); }
.poi-check {
  position: absolute; top: 7px; right: 7px; z-index: 2;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--brand); color: #fff; font-weight: 800; font-size: 0.78rem;
  display: flex; align-items: center; justify-content: center;
  border: 2px solid #fff; box-shadow: 0 2px 8px rgba(95, 123, 104, 0.4);
  transform: scale(0); transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.poi-card.selected .poi-check { transform: scale(1); }

/* ---------- Map ---------- */
.map-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow);
}
#map { height: 420px; width: 100%; z-index: 0; background: var(--mint-pale); }
.map-fallback {
  height: 100%; display: flex; align-items: center; justify-content: center;
  color: var(--muted); font-weight: 600;
}
.map-legend {
  display: flex; flex-wrap: wrap; gap: 18px; padding: 12px 18px;
  font-size: 0.85rem; color: var(--muted); border-top: 1px solid var(--border);
}
.map-legend > span { display: inline-flex; align-items: center; gap: 7px; }
.legend-dot { width: 13px; height: 13px; border-radius: 50%; display: inline-block; }
.legend-dot.stay { background: var(--brand); }
.legend-dot.near { background: #fff; border: 3px solid var(--brand); }
.legend-dot.far { background: #fff; border: 3px solid var(--line); }

.poi-dot {
  width: 34px; height: 34px; border-radius: 50%; position: relative;
  background: #fff; border: 3px solid var(--brand);
  background-size: cover; background-position: center;
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; box-shadow: 0 2px 8px rgba(92, 74, 62, 0.25);
  cursor: pointer; transition: transform 0.12s ease;
}
.poi-dot:hover { transform: scale(1.12); }
.poi-dot.poi-far { border-color: var(--line); opacity: 0.8; }
.poi-dot.poi-off { border-color: var(--line); opacity: 0.85; }
.poi-dot.poi-on { border-color: var(--brand); transform: scale(1.08); }
.poi-dot.poi-on::after {
  content: "✓"; position: absolute; top: -6px; right: -6px;
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--brand); color: #fff;
  font-size: 10px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
  border: 2px solid #fff;
}
.legend-dot.sel { background: #fff; border: 3px solid var(--brand); }
.legend-dot.unsel { background: #fff; border: 3px solid var(--line); }
.stay-pin {
  background: var(--brand); color: #fff; font-weight: 700; font-size: 0.85rem;
  padding: 7px 14px; border-radius: var(--r-pill); white-space: nowrap; text-align: center;
  box-shadow: 0 4px 14px rgba(95, 123, 104, 0.45);
  border: 2px solid #fff;
}

/* ---------- Results split view (list left, map right) ---------- */
.results-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(360px, 42vw, 900px);
  align-items: start;
  min-height: 100vh;
}
/* centred in its column — margin-left:auto pinned it to the map and left the
   whole surplus as a void on the left at wide viewports */
.results-panel { padding: 32px 40px 80px; max-width: 980px; margin: 0 auto; width: 100%; }

/* ---- The results as one screen, turned by its tabs ----
   The map has always been a fixed pane you don't scroll; the answer beside it
   was a page you did, and the tabs went off the top of it the moment you
   started reading, so getting from the itinerary back to the overview meant
   scrolling up to find them. Now the frame — who, where, what it saves you and
   the tabs — is pinned, and the tab's own page is the only thing that moves.
   Below the split (see the 960px block) the map is a view behind a pill and the
   panel is the whole screen, where an ordinary scroll is the right answer. */
@media (min-width: 961px) {
  .results-split { height: 100svh; overflow: hidden; align-items: stretch; }
  .results-panel {
    display: flex; flex-direction: column;
    height: 100svh; min-height: 0; padding: 22px 34px 0;
  }
  .results-panel > .rp-head,
  .results-panel > .savings-mini,
  .results-panel > .rp-tabs,
  .results-panel > .rp-pager { flex: none; }
  .rp-tabs { margin: 14px 0 12px; }
  /* The negative margin pairs with the padding: the scrollbar gutter would
     otherwise crop the right-hand edge of every card in here. */
  .rp-page {
    flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    padding-right: 6px; margin-right: -6px;
  }
  /* A rule above it, so the last card reads as continuing behind the pager
     rather than as a page that stopped */
  .results-panel > .rp-pager {
    margin-top: 0; padding: 10px 0 14px; border-top: 1px solid var(--line);
  }
  .results-map { height: 100svh; }
}
/* The wishlist page's one heading, so it carries the page the way "Stay in
   Kyoto" carries the results */
.wishlist-title { font-size: 2.2rem; letter-spacing: -0.02em; margin: 6px 0 14px; }
/* Kobo lines up with the baseline of the title rather than the middle of it:
   the themed illustrations all stand on a painted patch of ground, and sitting
   that on the type's baseline is what stops him looking like he's floating.
   The width itself lives with the other mascot sizes, after `.kobo`. */
.wishlist-head { display: flex; align-items: flex-end; gap: 12px; }
@media (max-width: 900px) { .wishlist-title { font-size: 1.7rem; } }
/* Kobo was 104px of a 390px phone, which left "Thailand wishlist 🇹🇭" about a
   hundred and sixty pixels to live in: the words took two lines and dropped the
   flag onto a third, on its own, reading as a stray. He shrinks, and the title
   balances its own line breaks rather than leaving one word stranded. */
@media (max-width: 560px) {
  .wishlist-kobo { width: 74px; }
  .wishlist-head { gap: 10px; }
  .wishlist-title { font-size: 1.5rem; margin: 4px 0 12px; text-wrap: balance; }
}
.results-map { position: sticky; top: 0; height: 100vh; }
.results-map #map { height: 100%; width: 100%; z-index: 0; background: var(--mint-pale); }
.map-overlay-legend {
  position: absolute; bottom: 18px; left: 18px; z-index: 500;
  background: rgba(255, 255, 255, 0.95); border-radius: var(--r-sm); padding: 10px 16px;
  display: flex; flex-direction: column; gap: 5px;
  font-size: 0.82rem; font-weight: 600; color: var(--ink);
  box-shadow: var(--shadow);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.map-overlay-legend > span { display: inline-flex; align-items: center; gap: 8px; }
/* Out of the way of an open place card — see the popupopen handler */
.map-overlay-legend.hushed { opacity: 0; transform: translateY(6px); pointer-events: none; }

/* ---------- The place, opened from its dot on the map ---------- */
/* Leaflet's own popup is a white box with a serif-ish shadow and a close cross
   in the corner; this is the same card as the list, shrunk to fit over a map. */
.poi-map-popup .leaflet-popup-content-wrapper {
  padding: 0; overflow: hidden; border-radius: var(--r-md);
  background: var(--surface); color: var(--ink);
  box-shadow: 0 10px 30px rgba(20, 32, 28, 0.28);
}
/* Leaflet measures the content to size the popup, so the card can't be given a
   width here — it gets one from minWidth/maxWidth on bindPopup. Only the
   default 13px/19px margin goes, so the photo can reach the edges. */
.poi-map-popup .leaflet-popup-content { margin: 0; line-height: inherit; }
.poi-map-popup .leaflet-popup-tip { background: var(--surface); }
/* The close cross lands on the photo, so it needs its own disc to be legible
   against whatever the photo happens to be, and a finger-sized one at that. */
/* `a.` matters: Leaflet's own rule is `.leaflet-container a.leaflet-popup-close-
   button`, and a class-only selector loses to it however far down the file. */
.poi-map-popup a.leaflet-popup-close-button {
  top: 8px; right: 8px; width: 30px; height: 30px; padding: 0;
  border-radius: 50%; text-align: center;
  font-weight: 800; font-size: 1.2rem; line-height: 28px;
  color: var(--ink); background: rgba(255, 255, 255, 0.94);
  box-shadow: 0 2px 8px rgba(20, 32, 28, 0.28);
}
.poi-map-popup a.leaflet-popup-close-button:hover { color: var(--ink); background: #fff; }
.mp-photo {
  position: relative; height: 108px; background: var(--sunk);
  display: grid; place-items: center; overflow: hidden;
}
.mp-fallback { font-size: 1.9rem; opacity: 0.45; }
.mp-photo img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 0.35s ease;
}
.mp-photo img.loaded { opacity: 1; }
.mp-body { padding: 11px 13px 13px; display: flex; flex-direction: column; gap: 3px; }
.mp-where {
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--brand-dark);
}
.mp-name { font-size: 1rem; font-weight: 800; line-height: 1.25; }
.mp-desc {
  font-size: 0.82rem; line-height: 1.45; color: var(--muted); margin: 3px 0 1px;
  /* Two lines of what it is, then Read more — the write-up is a tap away and
     doesn't need to push the buttons off the bottom of a phone screen. */
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.mp-meta { display: flex; flex-wrap: wrap; gap: 4px 10px; margin-top: 4px; }
.mp-meta em { font-style: normal; font-size: 0.74rem; font-weight: 700; color: var(--muted); }
.mp-actions { display: flex; flex-direction: column; gap: 6px; margin-top: 11px; }
.mp-actions .btn { width: 100%; padding: 9px 12px; font-size: 0.85rem; }
/* The itinerary, drawn on the map: which day each pick belongs to, and the
   order you'd travel between them. */
.poi-day {
  position: absolute; top: -9px; left: 50%; transform: translateX(-50%);
  height: 17px; padding: 0 7px; border-radius: var(--r-pill); white-space: nowrap;
  background: var(--brand-dark); color: var(--cream);
  font-size: 0.64rem; font-weight: 800; line-height: 17px; text-align: center;
  box-shadow: 0 2px 6px rgba(20, 32, 28, 0.35);
}
.route-arrow {
  color: var(--brand-dark); font-size: 0.9rem; line-height: 18px; text-align: center;
  text-shadow: 0 0 4px rgba(253, 252, 247, 0.9);
}

/* A base too far off the winner's match: shown for orientation, not clickable */
.base-pill.dim { opacity: 0.55; cursor: default; }

/* "Perhaps you'd like to visit…" — the far-off bases, offered as their own
   trip rather than as a comparison that could never win. */
.maybe-card {
  background: var(--gold-soft); border: 1.5px solid var(--cheek);
  border-radius: var(--r-md); padding: 14px 16px;
}
.maybe-head { font-weight: 800; font-size: 0.95rem; margin-bottom: 4px; }
.maybe-note { font-size: 0.85rem; color: var(--muted); line-height: 1.5; margin-bottom: 10px; }
.maybe-row { display: flex; flex-wrap: wrap; gap: 8px; }
.maybe-base {
  font: inherit; font-weight: 700; font-size: 0.86rem; cursor: pointer; color: inherit;
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--surface); border: 1.5px solid var(--border); border-radius: var(--r-pill);
  padding: 6px 14px 6px 8px; transition: all 0.15s ease;
}
.maybe-base:hover { border-color: var(--brand); transform: translateY(-1px); box-shadow: var(--shadow); }
.maybe-base .wthumb.mini { margin-right: 3px; }
.maybe-nights { font-style: normal; font-size: 0.74rem; font-weight: 800; color: var(--muted); }

/* What they asked to be near, echoed on the stay card */
.stay-asks { font-size: 0.82rem; font-weight: 700; color: var(--brand-dark); margin-top: 8px; }

/* Brand line icons inline with text: sized by the font, coloured by the text */
.cico { width: 1em; height: 1em; display: inline-block; vertical-align: -0.12em; flex: none; }
.poi-dot .cico { width: 17px; height: 17px; vertical-align: middle; color: var(--brand-dark); }

/* Only true where the map actually needs two fingers — see mapOptions() */
.legend-touch { display: none; }
@media (pointer: coarse) {
  .legend-touch { display: inline-flex; color: var(--muted); }
}

/* The name of the place on the left, everything you can change about it on the
   right — so the answer reads first and the controls don't push it down. */
.rp-head {
  margin-bottom: 24px; display: grid; gap: 14px 26px;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr); align-items: start;
}
.rp-head-main { min-width: 0; display: flex; align-items: center; gap: 14px; position: relative; }
.rp-head-text { min-width: 0; }
.rp-kobo { flex: none; align-self: center; }
.rp-kobo .found-kobo { width: 64px; height: 64px; }
.rp-head-side { min-width: 0; display: flex; flex-direction: column; align-items: flex-end; gap: 12px; }
.rp-head > .filter-row { grid-column: 1 / -1; margin-top: -2px; }
.rp-head-actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }
/* The way onward once a trip is saved — appears beside the ✓ and stays */
@keyframes afterSaveIn { from { opacity: 0; transform: translateY(6px); } }
.rp-after-save { display: inline-flex; gap: 10px; animation: afterSaveIn 0.35s ease both; }
.rp-restart, .rp-share, .rp-itin { white-space: nowrap; }
/* The itinerary's front door needs the section not to land flush with the
   viewport edge when jumped to. */
.rp-section.itinerary { scroll-margin-top: 18px; }

@media (max-width: 900px) {
  /* Stacked, and the buttons go back to reading left-to-right. They also go
     last: in one column they'd otherwise land between the title and the answers
     that belong to it. */
  .rp-head { grid-template-columns: 1fr; }
  .rp-head-side { align-items: stretch; order: 1; }
  .rp-head-actions { justify-content: flex-start; }
}
.found-line { font-weight: 800; color: var(--accent); font-size: 0.95rem; display: flex; align-items: center; gap: 6px; }
/* Kobo is the way into the passport — a picture of you, so to speak */
.kobo-link {
  background: none; border: none; padding: 0; cursor: pointer; line-height: 0;
  border-radius: 50%; transition: transform 0.15s ease;
}
.kobo-link:hover { transform: scale(1.08); }
.kobo-link:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }
.found-line.alt a { text-decoration: underline; cursor: pointer; }
.rp-head h2 { font-size: 2.2rem; letter-spacing: -0.02em; }
.rp-sub { color: var(--muted); margin-bottom: 14px; }
.filter-row { display: flex; flex-wrap: wrap; gap: 7px; align-items: flex-start; }
.fpill-edit { color: var(--ink); }
.fpill {
  font: inherit; font-weight: 700; font-size: 0.8rem; color: var(--muted);
  background: var(--surface); border: 1.5px solid var(--border); border-radius: var(--r-pill);
  padding: 6px 12px; cursor: pointer; transition: all 0.15s ease; white-space: nowrap;
}
.fpill:hover { color: var(--ink); }
.fpill:hover { border-color: var(--ink); }


.hero-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow);
}
.hero-banner {
  background: linear-gradient(135deg, var(--mint-pale), var(--mint-soft), var(--mint-soft));
  font-size: 3.4rem; text-align: center; padding: 22px 0;
}
.hero-photo {
  position: relative; height: 270px;
  background: linear-gradient(135deg, var(--mint-pale), var(--mint-soft));
  display: flex; align-items: center; justify-content: center;
}
.hero-photo .poi-fallback { font-size: 3.2rem; }
.hero-photo img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0; transition: opacity 0.5s ease;
}
.hero-photo img.loaded { opacity: 1; }
.hero-photo::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(20, 26, 34, 0.55), transparent 45%);
}
.hero-photo-label {
  position: absolute; bottom: 14px; left: 18px; z-index: 2;
  color: #fff; font-weight: 800; font-size: 1.05rem;

}

/* Photo option tiles (country picker) */
.photo-opt { padding: 0; overflow: hidden; }
.photo-opt-img {
  position: relative; aspect-ratio: 16 / 8.5; width: 100%;
  background: linear-gradient(135deg, var(--mint-pale), var(--mint-soft));
  display: flex; align-items: center; justify-content: center;
}
.photo-opt-img .poi-fallback { font-size: 2.4rem; }
.photo-opt-img img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0; transition: opacity 0.5s ease, transform 0.35s ease;
}
.photo-opt-img img.loaded { opacity: 1; }
.photo-opt:hover .photo-opt-img img { transform: scale(1.05); }
.photo-opt-body { padding: 13px 17px 15px; display: flex; flex-direction: column; gap: 2px; }
.photo-opt .poi-check { top: 12px; right: 12px; }
.hero-body { padding: 22px 26px 26px; }
.match-line { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
.match-line .match-num { font-size: 1.7rem; font-weight: 900; color: var(--accent); }
.match-line .match-sub { color: var(--accent); font-weight: 700; font-size: 0.92rem; }
.hero-body .winner-blurb { text-align: left; margin: 0 0 18px; }
.hero-body .score-grid { margin: 0 0 18px; max-width: none; }

/* Season timing card */
/* A tip rather than a panel: it's a caveat on the answer above it, so it's sized
   like one — no shadow, tighter padding, smaller type. */
.season-card {
  margin-top: 22px; border-radius: var(--r-md); padding: 14px 18px 16px;
  background: var(--surface); border: 1px solid var(--border);
}
/* Kobo beside the season the way he stands beside the base at the top of the
   page, so the card is announced rather than just labelled */
.season-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.season-card .season-kobo { width: 62px; height: 62px; flex: none; object-fit: contain; }
.season-naming { min-width: 0; }
.season-card h3 { font-size: 0.98rem; margin-bottom: 2px; }
.season-summary {
  color: var(--muted); margin-top: 12px; font-size: 0.87rem; line-height: 1.5;
}
/* Read as a tip, the way the flight line does: a coloured edge and a wash that
   fades out, rather than a fully filled and outlined yellow box. Two of those
   stacked looked like error messages on a form. */
.warn-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.warn-list li {
  display: flex; gap: 8px; align-items: center;
  background: linear-gradient(90deg, var(--gold-soft), rgba(251, 229, 216, 0) 82%);
  border-left: 3px solid var(--gold);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding: 6px 11px; font-size: 0.82rem; line-height: 1.45;
}
/* Two across where the card has the width for it — stacked, a pair of these
   was the tallest thing on the overview and pushed the summary out of sight.
   The fade in the background runs left-to-right, so a column narrower than
   about 250px starts eating its own text; below that they go back to a stack. */
.warn-list.cols-2 {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 8px; align-items: stretch;
}
.warn-list.cols-2 li { align-items: flex-start; }
.warn-ico { flex-shrink: 0; font-size: 0.88rem; }

.rp-section { margin-top: 28px; }
.rp-section h3 { font-size: 1.15rem; margin-bottom: 4px; }
.rp-hint { color: var(--muted); font-size: 0.88rem; margin-bottom: 12px; }

.wl-row {
  display: flex; align-items: center; gap: 14px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 12px 16px; margin-bottom: 10px; cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.wl-row:hover { transform: translateY(-2px); box-shadow: var(--shadow); border-color: var(--brand); }
.wl-row.slim { cursor: default; }
.wl-row.slim:hover { transform: none; box-shadow: none; border-color: var(--border); }
.wl-img {
  width: 64px; height: 64px; border-radius: var(--r-sm); flex-shrink: 0;
  background: linear-gradient(135deg, var(--mint-pale), var(--mint-soft));
  display: flex; align-items: center; justify-content: center; font-size: 1.4rem;
  overflow: hidden;
}
.wl-img img { width: 100%; height: 100%; object-fit: cover; }
.wl-info { display: flex; flex-direction: column; min-width: 0; }
.wl-info strong { font-size: 0.98rem; }
.wl-info span { font-size: 0.83rem; color: var(--muted); }
/* The guide's own rating on a recommended row — same voice as browse's Must go */
.wl-must {
  display: inline-block; vertical-align: 2px; margin-left: 2px;
  font-size: 0.66rem; font-weight: 800; letter-spacing: 0.02em; color: var(--ink);
  background: var(--gold-soft); border: 1px solid var(--gold);
  border-radius: var(--r-pill); padding: 1px 8px; white-space: nowrap;
}
.wl-far { opacity: 0.75; }
.wl-status {
  margin-left: auto; width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 0.85rem; color: #fff;
}
.wl-status.ok { background: var(--brand-dark); }
.wl-status.no { background: var(--line); }
.wl-row .trip-time { margin-left: auto; }

/* Day-trip rows on the scores page: same anatomy as a wishlist row, with an
   add button where the coverage tick would be */
.trip-add {
  margin-left: auto; flex: none; font: inherit; font-size: 0.85rem; font-weight: 800;
  background: var(--cream); color: var(--brand-dark); border: 1.5px solid var(--brand);
  border-radius: var(--r-pill); padding: 7px 16px; cursor: pointer;
  white-space: nowrap; transition: all 0.15s ease;
}
.trip-add:hover { background: var(--mint-pale); transform: translateY(-1px); }
.trip-add.on { background: var(--brand); border-color: var(--brand); color: #fff; }

.base-pill {
  /* sits above its city point rather than on it, so the wishlist dots stay visible */
  transform: translate(-50%, -175%);
  background: #fff; color: var(--ink);
  font-family: "Nunito", sans-serif; font-weight: 800; font-size: 0.85rem;
  padding: 7px 14px; border-radius: var(--r-pill); white-space: nowrap;
  box-shadow: 0 3px 12px rgba(92, 74, 62, 0.28);
  border: 1px solid rgba(92, 74, 62, 0.08);
  cursor: pointer; transition: transform 0.12s ease;
  display: inline-block; width: max-content;
}
.base-pill:hover { transform: translate(-50%, -175%) scale(1.07); }
.base-pill.current {
  background: linear-gradient(135deg, var(--brand), var(--mint)); color: #fff;
  box-shadow: 0 4px 16px rgba(95, 123, 104, 0.5); border: 2px solid #fff;
  font-size: 0.9rem;
}

/* ---------- Wishlist checklist ---------- */
.checklist {
  margin-top: 24px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 24px 28px;
}
.checklist h3 { margin-bottom: 14px; font-size: 1.15rem; }
.checklist ul { list-style: none; }
.checklist li {
  display: flex; align-items: center; gap: 10px; padding: 8px 0;
  border-bottom: 1px solid var(--border); font-size: 0.97rem;
}
.checklist li:last-child { border-bottom: none; }
.cl-icon {
  width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.8rem; font-weight: 800; color: #fff;
}
.cover-yes .cl-icon { background: var(--brand-dark); }
.cover-no .cl-icon { background: var(--line); }
.cover-no { color: var(--muted); }
.cl-note { margin-left: auto; font-size: 0.82rem; color: var(--muted); font-style: italic; white-space: nowrap; }

/* ---------- Where exactly to stay ---------- */
.stay-card {
  margin-top: 18px; padding: 20px 22px; border-radius: var(--r-md);
  background: var(--accent-soft); border: 1px solid rgba(125, 154, 135, 0.28);
}
.stay-label { display: block; font-size: 0.78rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent); }
.stay-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; justify-content: space-between; margin-top: 4px; }
.stay-area { font-family: var(--font-display); font-weight: 800; font-size: 1.4rem; line-height: 1.2; }
.stay-nights {
  flex: none; background: var(--brand); color: #fff; font-weight: 800; font-size: 0.85rem;
  padding: 6px 14px; border-radius: var(--r-pill); white-space: nowrap;
}
.stay-note { margin-top: 8px; font-size: 0.95rem; }
.stay-alts { margin-top: 12px; }
.stay-alts-label {
  display: block; font-size: 0.72rem; font-weight: 800; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 6px;
}
.stay-alts-row { display: flex; flex-wrap: wrap; gap: 6px; }
.stay-alt-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--cream); border: 1px solid var(--border);
  border-radius: var(--r-pill); padding: 4px 12px; font-weight: 700; color: var(--ink);
  font: inherit; font-size: 0.85rem; cursor: pointer; transition: all 0.15s ease;
}
/* Its own pill inside the chip, so "cheaper" reads as a tag on Asakusa rather
   than as the second half of the word before it */
.stay-alt-chip em {
  font-style: normal; font-size: 0.66rem; font-weight: 800; letter-spacing: 0.03em;
  text-transform: uppercase; color: var(--brand-dark);
  background: var(--mint-pale); border-radius: var(--r-pill); padding: 1px 7px;
}
.stay-alt-chip:hover { border-color: var(--brand); background: var(--mint-pale); }
.stay-alt-chip.on { background: var(--brand); border-color: var(--brand); color: #fff; }
.stay-alt-chip.on em { color: var(--brand-dark); background: rgba(255, 255, 255, 0.9); }
/* What the runner-up neighbourhood would save, and cost — under its chip */
.alt-stay {
  margin-top: 10px; padding: 12px 14px; border-radius: var(--r-sm);
  background: var(--cream); border: 1px dashed var(--brand);
}
.alt-stay-head { font-size: 0.92rem; }
.alt-stay-price { margin-top: 6px; font-size: 0.85rem; color: var(--accent); }
.alt-stay-trade {
  margin-top: 8px; padding: 6px 10px; font-size: 0.82rem; line-height: 1.5;
  background: linear-gradient(90deg, var(--gold-soft), rgba(251, 229, 216, 0) 82%);
  border-left: 3px solid var(--gold);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
.alt-stay-note { margin-top: 6px; font-size: 0.82rem; color: var(--muted); }
.alt-stay-link { display: inline-block; margin-top: 8px; font-size: 0.85rem; font-weight: 800; color: var(--brand-dark); }
/* A tip in the house style: coloured edge, a wash that fades out rightward,
   small icon — the same language as the flight line and the season caveats. */
.stay-tips {
  margin-top: 12px; font-size: 0.84rem; line-height: 1.5; color: var(--ink);
  display: flex; gap: 8px; align-items: flex-start;
  background: linear-gradient(90deg, var(--cream), rgba(255, 252, 246, 0) 85%);
  border-left: 3px solid var(--brand);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding: 7px 12px;
}
.stay-tips::before { content: "💡"; flex: none; font-size: 0.88rem; }
.leg-why { font-size: 0.8rem; color: var(--muted); margin-top: 2px; }

/* ---------- What staying put saves (compact, header top-right) ---------- */
/* One line across the page, not a tower in a side column. Stacked in a 330px
   column this was a dark block half again as tall as the note beside it, and
   the mismatch left a hole above the tabs. Across the full width the three
   figures line up as what they are: one sentence of arithmetic. */
.savings-mini {
  background: linear-gradient(100deg, var(--brand-dark), var(--brand)); color: var(--cream);
  border-radius: var(--r-md); padding: 10px 16px; cursor: help; margin-top: 14px;
  box-shadow: 0 6px 18px rgba(92, 74, 62, 0.18);
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 18px;
}
.sm-title { font-family: var(--font-display); font-weight: 800; font-size: 0.85rem; flex: none; }
.sm-row { display: flex; flex: 1 1 420px; gap: 8px; min-width: 0; }
.sm-stat {
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: baseline; gap: 8px;
  background: rgba(253, 252, 247, 0.14); border: 1px solid rgba(253, 252, 247, 0.22);
  border-radius: var(--r-sm); padding: 5px 11px;
}
.sm-stat b {
  font-family: var(--font-display); font-weight: 800; font-size: 1rem; line-height: 1.2;
  flex: none; white-space: nowrap;
}
.sm-stat em {
  font-style: normal; font-size: 0.74rem; line-height: 1.3;
  color: rgba(253, 252, 247, 0.88);
}
/* Below a phone's width three across become three slivers, so they stack — the
   layout the card had everywhere before, kept for where it was right. */
@media (max-width: 700px) {
  .savings-mini { flex-direction: column; align-items: stretch; gap: 8px; padding: 12px 14px; }
  .sm-row { flex-direction: column; flex: none; gap: 5px; }
  .sm-stat b { min-width: 3.4em; }
}

/* ---------- Mobile ---------- */
@media (max-width: 760px) {
  /* The hero at phone size: the country name a title, not a poster — 2.6rem
     was most of the viewport's width, and with the big Explore pill under it
     the first screen read as three massive things stacked. */
  .cine-country { line-height: 1; font-size: clamp(2.1rem, 9.5vw, 2.6rem); }
  .cine-sub { font-size: 0.95rem; margin: 12px 0 20px; }
  .cine-inner { padding-bottom: clamp(64px, 11vh, 120px); }
  .btn-lg { font-size: 1.02rem; padding: 13px 28px; }
  .explore-arrow { width: 30px; height: 30px; font-size: 1rem; }
  .cine-cta { gap: 14px; }
}

@media (max-width: 600px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  /* One button per row in the booking bubble — two columns in ~230px of
     bubble turns the pills into balled-up circles */
  .stay-links { grid-template-columns: 1fr; }
  .stay-book { align-items: flex-end; }
  /* Day label above its day, not beside it — a side column steals a third
     of a phone's width from the activities */
  .itin-day { flex-direction: column; gap: 8px; }
  .hero h1 { font-size: 2.2rem; }
  .hero-features { grid-template-columns: 1fr; }
  .hero-grid { grid-template-columns: 1fr; gap: 26px; }
  .collage-tile:nth-child(even) { transform: none; }
  .hero-photo { height: 200px; }
  .results-head h2 { font-size: 1.8rem; }
  .split-plan { flex-direction: column; align-items: stretch; }
  .split-arrow { text-align: center; transform: rotate(90deg); }
  .score-row { grid-template-columns: 110px 1fr 40px; }
  .step-footer { flex-direction: column; }
  #map { height: 320px; }
  .cl-note { display: none; }
  .rp-head h2 { font-size: 1.7rem; }
}

/* ---------- The wishlist picker: a map, with the list on a sheet ----------
   This screen used to be a page of cards with the map behind a toggle, which
   meant the two halves of the same question — what do I fancy, and where is it
   — were never on screen at once, and the map was somewhere you visited rather
   than the thing you were choosing on. Now the map is the screen and the list
   rides on a sheet you pull up over it: shut is the map, half is both, full is
   the list. Same gesture on a phone and on a desktop; only the edge the sheet
   is docked to changes. */
.picker {
  height: 100svh; overflow: hidden;
  display: flex; flex-direction: column;
}

/* The header, and the country's basics, above the map rather than floating on
   it: who this trip is for and the eight facts about the place, in the order
   you'd want them, before the picking starts. It keeps its own height and the
   map takes the rest — and it scrolls inside itself once the basics are open,
   so unfolding them can never squeeze the map off the screen. */
.picker-head {
  flex: none; max-height: 58svh; overflow-y: auto; overscroll-behavior: contain;
  padding: 16px 20px 12px; background: var(--bg);
  border-bottom: 1px solid var(--line);
  transition: max-height 0.3s cubic-bezier(0.22, 1, 0.36, 1),
              padding 0.3s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.2s ease;
}
/* Pulled all the way up, the sheet is the screen — you've stopped looking at
   the map and at which country this is, and on a phone the header is 270px the
   list could be reading with. It comes back the moment you pull the sheet
   down, which is also the moment you want it again. */
.picker[data-sheet="full"] .picker-head {
  max-height: 0; padding-top: 0; padding-bottom: 0; opacity: 0;
  border-bottom-color: transparent;
}
.picker-head-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.picker-head .wishlist-head { margin-top: 10px; }
.picker-head .wishlist-title { margin: 4px 0 0; }
/* The basics are the last thing before the map and they're on the page, not
   behind a chevron: eight facts across, running the header's full width, handing
   straight over to the map beneath. Tapping one still opens the whole answer
   under it — that's the strip's own behaviour everywhere — but you can read all
   eight without opening anything. Negative side margins take the rule under it
   out to the header's own edges. */
.picker-head .essentials { margin: 10px -20px 0; padding: 0 20px; }
.picker-head .ess-row {
  border-top: 1px solid var(--line); border-bottom: none; padding: 5px 0 2px;
}
/* On a phone every row the header keeps comes off the map underneath it, so
   the header is as short as it can be and still say what it says — and the
   facts, which are two columns at this width, are the biggest part of it. */
@media (max-width: 620px) {
  .picker-head { padding: 10px 16px 0; }
  .picker-head .wishlist-head { margin-top: 4px; gap: 8px; }
  .picker-head .wishlist-kobo { width: 44px; }
  .picker-head .wishlist-title { font-size: 1.2rem; margin: 0; }
  .picker-head .essentials { margin: 6px -16px 0; padding: 0 16px; }
  /* Three across, not the two the strip uses elsewhere: at two, the eight facts
     were four rows and 245px, and the map underneath came out shorter than the
     sheet's own head. Four across would be two rows and shorter still, but at
     390px it puts "K-ETA maybe" and "No fresh food" into an ellipsis, and a
     fact you can't read is worse than a row you can't spare. */
  .picker-head .ess-row { grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 3px 0 1px; }
  /* The hairlines are keyed to a two-column count; at three they'd land inside
     the cells. The rows are short enough to read without them. */
  .picker-head .ess::before { content: none; }
  /* The icon rides beside the words rather than on its own line above them —
     stacked, each cell was ~55px and the eight facts ~170px of a screen the
     map and the sheet are also fighting for. Side-on the strip is about 100px
     and reads the same. */
  .picker-head .ess {
    padding: 3px 5px;
    display: grid; grid-template-columns: auto minmax(0, 1fr);
    column-gap: 6px; align-items: center;
  }
  .picker-head .ess .ess-ico { width: 14px; height: 14px; margin: 0; grid-row: 1 / 3; }
  .picker-head .ess > strong { font-size: 0.72rem; line-height: 1.3; }
  .picker-head .ess > em { font-size: 0.58rem; }
}

/* Everything the sheet measures itself against, and the map's own box */
.picker-stage { flex: 1; min-height: 0; position: relative; }
.picker-stage #map { width: 100%; height: 100%; background: var(--mint-pale); }

/* With a header above the map and a sheet below it, the band left on a phone is
   about 220px tall, and there is no corner of that a legend can sit in without
   covering pins. It doesn't have much to say that the map doesn't — tap a dot
   and it turns green, and the card that opens explains itself — so on a phone
   it stands down, and on a wide screen, where the map is most of the window, it
   keeps its corner. Bottom-right there, because bottom-left is the sheet. */
.picker .map-overlay-legend { display: none; }
/* Two lines, not three: there is a zoom control in the opposite corner and the
   map moves when you drag it, so the third line was telling people something
   the screen had already told them — at the cost of covering the coast. */
.picker .legend-touch { display: none; }

.sheet {
  --sheet-covers: bottom;
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 700;
  display: flex; flex-direction: column; min-height: 0;
  height: 62%;
  background: var(--bg);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  box-shadow: 0 -10px 40px rgba(30, 22, 15, 0.2);
  transition: height 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}
/* Following a finger has to be instant; snapping back afterwards is the part
   worth animating. */
.sheet.dragging { transition: none; }
/* Percentages of the stage, not of the window — the header above the map has
   its own height, and a sheet measured against the viewport was taller than
   the box it lives in. Keep these in step with SHEET_DETENTS in app.js.
   Shut is the exception: it's the head measured by syncSheetShut(), because
   26% of the stage cut the button off the bottom on a short phone. */
.sheet[data-detent="shut"] { height: var(--sheet-shut, 172px); }
.sheet[data-detent="half"] { height: 62%; }
.sheet[data-detent="full"] { height: 97%; }

/* The head is the drag surface, so the browser mustn't claim the gesture first
   — without `touch-action: none` a downward drag here scrolls the page behind
   and the sheet never moves. */
.sheet-head {
  flex: none; touch-action: none; cursor: grab;
  padding: 0 16px 12px; display: flex; flex-direction: column; gap: 8px;
  border-bottom: 1px solid var(--line);
}
/* Tighter still on a phone, where every pixel the head keeps is a pixel of map
   — and the head is 176px of an 844px screen before anything else happens. */
@media (max-width: 620px) {
  .sheet-head { padding: 0 12px 8px; gap: 6px; }
  /* Font stays 16px — see the Safari-zoom note on .poi-search input — so the
     slimming is all padding. The search pill and the button under it were
     each ~52px; at ~40px the pair gives roughly a fact-row's height back to
     the map. */
  .sheet-head .poi-search input { padding-top: 8px; padding-bottom: 8px; }
  .sheet-head .poi-next { padding-top: 9px; padding-bottom: 9px; font-size: 0.95rem; }
  .sheet-body { padding: 12px 14px 24px; }
}
.sheet-head:active { cursor: grabbing; }
/* The bar you see is 44×5; the button around it is a thumb's worth in both
   directions, because this is the control the whole screen turns on. The
   negative margins let that 44px target overlap the padding either side of it
   rather than adding 44px of its own to the head — on a phone the head is
   competing with the map for the same pixels. */
.sheet-grab {
  align-self: center; margin: -6px auto -10px; padding: 0 44px;
  min-height: 44px; display: flex; align-items: center; justify-content: center;
  background: none; border: none; cursor: pointer;
}
.sheet-grab span {
  display: block; width: 44px; height: 5px; border-radius: 3px;
  background: var(--border); transition: background 0.15s ease;
}
.sheet-grab:hover span { background: var(--brand); }
.sheet-head .poi-search { margin: 0; }
.sheet-head .poi-next { width: 100%; }
/* A disabled control swallows pointer events without dispatching them in some
   browsers, which made the big grey button a dead zone for the sheet drag.
   Letting touches fall through it turns it back into head — there's nothing
   to click on it while it's disabled anyway. */
.sheet-head .poi-next:disabled { pointer-events: none; }

.sheet-body {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch; padding: 14px 16px 24px;
}
/* Shut, the body is a sliver of nothing worth showing — hide it so the head
   sits on a clean edge rather than on two cropped chips. */
.sheet[data-detent="shut"] .sheet-body { visibility: hidden; }
.sheet-body .region-bar { margin-top: 0; }
.sheet-body .ess-fold { margin: 22px 0 6px; }
/* The fold's summary is a phone rule elsewhere; in the sheet it's the only way
   in to the basics at every width. */
.sheet-body .ess-summary {
  display: flex; align-items: center; gap: 12px; cursor: pointer;
  list-style: none; padding: 12px 15px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
}
.sheet-body .ess-summary::-webkit-details-marker { display: none; }
.sheet-body .ess-summary::after {
  content: "⌄"; margin-left: auto; font-weight: 900; color: var(--muted);
  transform: translateY(-3px); transition: transform 0.2s ease;
}
.sheet-body .ess-fold[open] .ess-summary::after { transform: rotate(180deg) translateY(-1px); }
.sheet-body .ess-summary span { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.sheet-body .ess-summary strong { font-size: 0.95rem; font-weight: 800; }
.sheet-body .ess-summary small { font-size: 0.76rem; color: var(--muted); }
.sheet-body .ess-summary-ico { width: 22px; height: 22px; flex: none; }

/* Wide screens: same sheet, same gesture, docked to a column at the side
   instead of a band across the foot — a full-width sheet on a 1440px screen
   would put seven place cards on a row and the map behind a letterbox. */
@media (min-width: 961px) {
  .sheet {
    --sheet-covers: side;
    left: 22px; right: auto; bottom: 22px; width: min(500px, 38vw);
    border-radius: var(--r-lg);
  }
  .sheet[data-detent="half"] { height: 68%; }
  .sheet[data-detent="full"] { height: calc(100% - 44px); }
  .picker-head { padding: 14px 26px 0; }
  .picker-head .wishlist-head { margin-top: 6px; }
  .picker-head .essentials { margin: 12px -26px 0; padding: 0 26px; }
  /* The header folding away at "full" is a phone rule — there the sheet IS
     the screen. Here the sheet is a column beside a map that stays visible,
     and folding the header took Back, Edit answers and the country's name off
     a page that was still very much on show. */
  .picker[data-sheet="full"] .picker-head {
    max-height: 58svh; opacity: 1;
    padding: 14px 26px 0; border-bottom-color: var(--line);
  }
  .picker .map-overlay-legend {
    display: flex; bottom: 16px; right: 16px; top: auto; left: auto;
    font-size: 0.76rem; padding: 9px 13px; gap: 4px;
  }
}

/* The pill that swaps the two, and the map view it opens. Desktop shows both
   panels at once and has no use for either. */
.map-toggle { display: none; }

/* ---------- The wishlist picker on a phone ---------- */
/* The country's basics, folded. Open and headless on a wide screen, where the
   strip has always simply been part of the page. */
.ess-fold { margin-bottom: 6px; }
.ess-summary { display: none; }
.pick-bar, .pick-escape { display: none; }

@media (max-width: 700px) {
  .ess-summary {
    display: flex; align-items: center; gap: 12px; cursor: pointer;
    list-style: none; padding: 12px 15px; margin-bottom: 10px;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
  }
  .ess-summary::-webkit-details-marker { display: none; }
  /* The chevron is the affordance, so it turns with the fold */
  .ess-summary::after {
    content: "⌄"; margin-left: auto; font-weight: 900; color: var(--muted);
    transform: translateY(-3px); transition: transform 0.2s ease;
  }
  .ess-fold[open] .ess-summary::after { transform: rotate(180deg) translateY(-1px); }
  .ess-summary span { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
  .ess-summary strong { font-size: 0.95rem; font-weight: 800; }
  .ess-summary small { font-size: 0.76rem; color: var(--muted); }
  .ess-summary-ico { width: 22px; height: 22px; flex: none; }
}

@media (max-width: 960px) {
  /* minmax(0, …) rather than a bare 1fr, which floors at the min-content of
     whatever is inside — the folded country-basics strip alone was 918px of it,
     and the column grew to match while the phone stayed 390. */
  .results-split { grid-template-columns: minmax(0, 1fr); }
  /* Room at the foot for the pill to float over nothing in particular, so the
     end of the list is never the thing it covers */
  .results-panel { padding: 24px 20px 104px; margin: 0 auto; min-width: 0; }

  /* One view at a time. The list is the screen you land on; the map is behind
     the pill, full-bleed when you open it, because half a phone of map is
     neither a map nor a list. */
  .results-map { display: none; }
  .results-split.map-open .results-panel { display: none; }
  .results-split.map-open .results-map {
    display: block; position: fixed; inset: 0; height: 100svh; z-index: 700;
  }
  .results-split.map-open .results-map #map { height: 100%; }
  /* Clear of the pill, which sits over the bottom of the map */
  .results-split.map-open .map-overlay-legend { bottom: 84px; }

  .map-toggle {
    display: inline-flex; align-items: center; gap: 9px;
    position: fixed; left: 50%; transform: translateX(-50%); bottom: 18px; z-index: 750;
    font: inherit; font-weight: 800; font-size: 0.92rem; cursor: pointer;
    padding: 12px 22px; border-radius: var(--r-pill);
    background: var(--brand); color: var(--cream); border: none;
    box-shadow: 0 10px 26px rgba(30, 22, 15, 0.28);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }
  .map-toggle:active { transform: translateX(-50%) scale(0.97); }
  /* A solid pill floating dead centre over a page of prose cut a hole through
     whatever line it was over — half a sentence gone, and the half still
     showing reading as a bug. The foot of the list fades out under it now, so
     text runs out rather than stopping dead. 740 puts the fade under the pill
     (750) and over the page. It hangs off the panel, which the map view hides,
     so no fade is left lying across the map. */
  .results-panel::after {
    content: ""; position: fixed; left: 0; right: 0; bottom: 0; height: 88px;
    z-index: 740; pointer-events: none;
    background: linear-gradient(to top, var(--bg) 32%, rgba(255, 247, 239, 0));
  }
  .map-toggle .cico { width: 19px; height: 19px; }
  /* The pill says where tapping it takes you, so it shows one label at a time */
  .map-toggle .mt-to-map, .map-toggle .mt-to-list { display: inline-flex; align-items: center; gap: 9px; }
  .map-toggle .mt-to-list { display: none; }
  .map-open .map-toggle .mt-to-map { display: none; }
  .map-open .map-toggle .mt-to-list { display: inline-flex; }
  /* ---- The wishlist picker's one bar ----
     Browsing places is a two-question screen — which view am I in, and how many
     have I picked — and both answers belong in the same place at the foot of
     the phone, permanently, rather than as a floating pill over a footer you
     have to scroll to the end of the list to reach. The bar sits outside the
     list panel, so switching to the map doesn't take it away. */
  .wide-only { display: none; }
  .pick-bar {
    display: flex; align-items: center; gap: 10px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 760;
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
    background: var(--surface); border-top: 1px solid var(--border);
    box-shadow: 0 -8px 24px rgba(30, 22, 15, 0.1);
  }
  /* In the bar the toggle is a control among controls, not a floating pill */
  .pick-bar .map-toggle {
    position: static; transform: none; flex: none;
    background: var(--bg); color: var(--ink); border: 1.5px solid var(--line);
    box-shadow: none; padding: 11px 16px;
  }
  .pick-bar .map-toggle:active { transform: scale(0.97); }
  .pick-bar .poi-next { flex: 1; min-width: 0; padding: 13px 14px; font-size: 0.92rem; }
  /* Clear of the bar: the last card, and the map's legend */
  .results-split:has(.pick-bar) .results-panel { padding-bottom: 92px; }
  .map-open .map-overlay-legend { bottom: 96px; }
  /* The escape hatch leaves the bar to the two controls that matter and sits at
     the end of the list, where someone who has scrolled the lot and picked
     nothing will actually be. */
  .pick-escape { display: block; text-align: center; font-size: 0.86rem; color: var(--muted); margin-top: 24px; }

  /* ---- The places themselves ----
     One card per row meant a 4:3 photograph, a place, a name and two tags for
     every single suggestion: one and a half of them on screen at a time, and
     twenty places to get through. Two up shows four, which is the difference
     between browsing and scrolling. */
  .poi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 12px; }
  .poi-card-where { font-size: 0.68rem; }
  .poi-card-title { font-size: 0.88rem; }
  .poi-card-tag { font-size: 0.68rem; padding: 2px 8px; }
  .badge-first { font-size: 0.62rem; padding: 2px 6px; }

  /* The add control, always there. It used to be a tick that appeared only
     once you'd added something — which told you what you had done, and never
     what you could do. Now every card carries a + you can see, and adding
     fills it in. The whole card still adds; this is what says so. */
  .poi-card .poi-check {
    transform: scale(1); width: 30px; height: 30px;
    background: rgba(255, 253, 250, 0.94); color: var(--brand-dark);
    border-color: rgba(255, 255, 255, 0.9); box-shadow: 0 2px 10px rgba(60, 48, 40, 0.28);
    font-size: 0; /* hides the ✓ in the markup; the glyph is set below */
  }
  .poi-card .poi-check::before { content: "+"; font-size: 1.25rem; line-height: 1; font-weight: 800; }
  .poi-card.selected .poi-check { background: var(--brand); color: #fff; }
  .poi-card.selected .poi-check::before { content: "✓"; font-size: 0.85rem; }
  /* The classics below the matches are the same choice in a smaller row, so
     they say it the same way: an empty + until it's on your list. */
  /* `transform: scale(1)` because the shared .poi-check hides itself at scale(0)
     and only the card version was ever scaled back up — which is why these rows
     showed nothing at all, picked or not. */
  .poi-chip .poi-check {
    transform: scale(1); width: 28px; height: 28px; color: var(--brand-dark);
    background: var(--surface); border-color: var(--line); font-size: 0;
  }
  .poi-chip .poi-check::before { content: "+"; font-size: 1.15rem; line-height: 1; font-weight: 800; }
  .poi-chip.selected .poi-check::before { content: "✓"; font-size: 0.8rem; }

  /* This was a one-row scrolling rail, and the fade at its right-hand edge read
     as a chopped-off chip rather than "there's more this way" — the fourth city
     was sliced through the middle of its name and nobody swiped. Every region is
     on screen again, wrapped; the chips are shrunk so seven of them come to
     three short rows rather than the four tall ones that caused the rail. */
  .region-bar { margin: 2px 0 16px; gap: 7px; }
  /* Wrapped chips of seven different widths left a ragged edge with a chip's
     worth of dead space on every row — four rows to show what fits in three.
     A grid of even columns packs them instead, and lines the counts up so the
     column reads as "how much is in each of these" rather than as noise. */
  .region-chips {
    /* 132px: two columns still fit the narrowest phone in circulation, where
       138 tipped over into a single column and seven full-width rows. */
    display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
    gap: 6px;
  }
  /* 44px because these are now the page's main navigation on a phone rather
     than a rail you flicked past, and they were 31px tall. */
  .region-chip {
    justify-content: flex-start; text-align: left; min-height: 44px;
    font-size: 0.82rem; padding: 7px 11px; gap: 5px;
  }
  .region-chip em { margin-left: auto; font-size: 0.7rem; }
}

/* ---------- Extra questionnaire answers in the results ---------- */
.beds-line { margin-top: 10px; font-size: 0.86rem; color: var(--accent); }
.split-leg .beds-line { font-size: 0.76rem; margin-top: 6px; }
/* Caveats in the same tip language as the season card's warnings: gold edge
   and a wash, not a filled-and-outlined yellow box */
.access-warn, .pace-warn {
  padding: 8px 12px; font-size: 0.85rem; line-height: 1.5; color: var(--ink);
  background: linear-gradient(90deg, var(--gold-soft), rgba(251, 229, 216, 0) 82%);
  border-left: 3px solid var(--gold);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
.access-warn { margin-top: 12px; }
.pace-warn { margin: 10px 0 4px; }

/* Travel-style questions: icon beside a stacked title + description */
.card.compact.stacked { align-items: flex-start; }
.card.compact.stacked .card-icon { font-size: 1.6rem; line-height: 1.2; }
.card-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.card-text .card-title { font-weight: 800; }
.card-text .card-sub { color: var(--muted); font-size: 0.85rem; line-height: 1.4; }

/* ---------- Hero itinerary planner ---------- */
.planner {
  background: var(--surface); color: var(--ink);
  border-radius: var(--r-lg); padding: 26px 24px 22px;
  box-shadow: 0 24px 60px rgba(92, 74, 62, 0.4);
  display: flex; flex-direction: column; gap: 14px;
}
.planner-title { font-size: 1.5rem; text-align: center; margin-bottom: 2px; }
.planner-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.planner-label {
  font-size: 0.72rem; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--muted); display: flex; align-items: center; gap: 5px;
}
.planner-hint { font-style: normal; cursor: help; color: var(--brand); }
.planner select, .wiz-selects select {
  font: inherit; font-weight: 600; font-size: 0.95rem; color: var(--ink);
  width: 100%; padding: 11px 34px 11px 13px; border-radius: var(--r-sm);
  border: 1.5px solid var(--border); background: var(--surface); cursor: pointer;
  appearance: none; text-overflow: ellipsis;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
  transition: border-color 0.15s ease;
}
.planner select:hover, .planner select:focus,
.wiz-selects select:hover, .wiz-selects select:focus { border-color: var(--brand); outline: none; }

/* The no-flight answer on the flying-from step: a real button above the
   selects, not a footnote after them */
.wiz-domestic {
  display: block; width: 100%; padding: 13px 18px; margin-bottom: 12px;
  font: inherit; font-weight: 800; font-size: 0.95rem; text-align: center;
  background: var(--mint-pale); color: var(--brand-dark);
  border: 1.5px dashed var(--brand); border-radius: var(--r-sm);
  cursor: pointer; transition: all 0.15s ease;
}
.wiz-domestic:hover { background: var(--mint-soft); transform: translateY(-1px); }
.wiz-domestic.on { background: var(--brand); border-style: solid; color: #fff; }
.wiz-or {
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 10px; text-align: center;
}

.planner-toggle {
  font: inherit; font-weight: 700; font-size: 0.9rem; text-align: left;
  background: none; border: none; cursor: pointer; color: var(--ink);
  padding: 4px 0; display: flex; align-items: center; gap: 6px;
}
.planner-toggle span { color: var(--muted); font-weight: 600; }
.planner-toggle em { font-style: normal; margin-left: auto; color: var(--muted); transition: transform 0.2s ease; }
.planner-toggle.open em { transform: rotate(180deg); }

.planner-acts { display: flex; flex-wrap: wrap; gap: 7px; }
/* author display beats the UA [hidden] rule, so restate it */
.planner-acts[hidden] { display: none; }
.act-chip {
  font: inherit; font-size: 0.8rem; font-weight: 700; cursor: pointer;
  background: var(--bg); color: var(--ink);
  border: 1.5px solid var(--border); border-radius: var(--r-pill); padding: 6px 12px;
  transition: all 0.15s ease;
}
.act-chip:hover { border-color: var(--brand); }
.act-chip.on { background: var(--accent-soft); border-color: var(--brand); }

.planner-go {
  font: inherit; font-weight: 800; font-size: 1rem; cursor: pointer;
  background: var(--brand); color: var(--cream); border: none;
  border-radius: var(--r-pill); padding: 15px; margin-top: 4px;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.planner-go:hover:not(:disabled) { transform: translateY(-2px); }
.planner-go:disabled { opacity: 0.35; cursor: not-allowed; }
.planner-note { font-size: 0.78rem; color: var(--muted); text-align: center; }
.planner-note a { color: var(--brand); font-weight: 800; cursor: pointer; text-decoration: underline; }

@media (max-width: 900px) {
  /* Column, not row: with the controls gone static they'd otherwise sit as a
     second flex item BESIDE the copy, floating over the middle of the photo */
  .hero-cinema {
    height: auto; min-height: 100svh; padding: 84px 0 96px;
    flex-direction: column; justify-content: flex-end;
  }
  .cine-inner { grid-template-columns: 1fr; gap: 30px; padding-bottom: 0; }
  .cine-foot { position: static; padding-top: 26px; }
  .planner { max-width: 420px; }
}
.fpill.refine { border-style: dashed; border-color: var(--brand); color: var(--brand); }
.fpill.refine:hover { background: var(--accent-soft); }
/* our assumption, not their answer — tap it to say what they actually want */
.fpill.assumed { border-style: dashed; opacity: 0.8; }

/* ---------- Hero: top nav ---------- */
.topnav {
  position: absolute; top: 0; left: 0; right: 0; z-index: 4;
  display: flex; align-items: center; gap: 24px;
  padding: 22px clamp(20px, 5vw, 64px); color: var(--ink);
}
.topnav-links { display: flex; gap: 28px; margin: 0 auto; }
.topnav-links a {
  color: var(--muted); font-weight: 700; font-size: 0.92rem;
  text-decoration: none; cursor: pointer; padding-bottom: 3px;
  border-bottom: 2px solid transparent; transition: all 0.15s ease;
}
.topnav-links a:hover { color: var(--ink); border-color: var(--brand); }
.topnav-right { flex: none; }

/* Everything in the hero now sits over a photograph rather than a cream wash,
   so it has to carry its own contrast. Scoped to .hero-cinema — the same nav
   markup on the passport and browse pages still sits on cream. */
.hero-cinema .topnav-links a { color: rgba(253, 252, 247, 0.82); }
.hero-cinema .topnav-links a:hover { color: var(--cream); border-color: var(--cream); }

.greet {
  font: inherit; font-weight: 700; font-size: 0.88rem; color: var(--ink); cursor: pointer;
  display: flex; align-items: center; gap: 9px;
  background: var(--cream); border: 1.5px solid var(--line);
  border-radius: var(--r-pill); padding: 6px 16px 6px 6px; backdrop-filter: blur(6px);
}
.greet:hover { background: var(--mint-soft); }
.greet-avatar {
  width: 28px; height: 28px; border-radius: 50%; background: var(--mint-soft);
  display: flex; align-items: center; justify-content: center; font-size: 0.85rem;
}
/* Signed in, the chip is just the avatar — a round badge, no greeting text */
.greet.greet-solo { padding: 4px; }

/* Over the hero photograph the cream pill reads as a stray light-theme control,
   so there it dresses like the other overlay chrome (the Explore arrow):
   frosted glass, white text. Passport and browse keep the cream version. */
.hero-cinema .greet {
  background: rgba(253, 252, 247, 0.18); border-color: rgba(253, 252, 247, 0.35);
  color: var(--cream);
}
.hero-cinema .greet:hover { background: rgba(253, 252, 247, 0.3); }
.hero-cinema .greet-avatar { background: rgba(253, 252, 247, 0.25); }

@media (max-width: 900px) {
  .greet { font-size: 0.82rem; gap: 7px; padding: 4px 13px 4px 4px; }
  .greet-avatar { width: 24px; height: 24px; font-size: 0.75rem; }
}

/* ---------- Hero: title + explore ---------- */
/* The words change with the photograph, in step but not in lockstep: the
   country name rises out of a slight blur first, its tagline follows a beat
   later. `both` holds the sub invisible through its delay, so the two never
   flash their new text before their own entrance. */
@keyframes titleSwap { from { opacity: 0; transform: translateY(24px); filter: blur(6px); } }
.cine-country.swap { animation: titleSwap 0.7s cubic-bezier(0.22, 1, 0.36, 1) both; }
@keyframes subSwap { from { opacity: 0; transform: translateY(12px); } }
.cine-sub.swap { animation: subSwap 0.6s 0.15s cubic-bezier(0.22, 1, 0.36, 1) both; }
@media (prefers-reduced-motion: reduce) {
  .cine-slide.on, .cine-country.swap, .cine-sub.swap { animation: none; }
  .cine-slide.on { transition-duration: 0.6s; }
}
.explore-arrow {
  width: 38px; height: 38px; border-radius: 50%; background: rgba(253, 252, 247, 0.28);
  display: flex; align-items: center; justify-content: center; font-size: 1.15rem;
  transition: transform 0.2s ease;
}
.explore-btn:hover .explore-arrow { transform: translateX(3px); }

/* ---------- Planner docked under the hero ---------- */
.planner-dock {
  position: relative; z-index: 5; max-width: 1160px; margin: -118px auto 0;
}


@media (max-width: 900px) {
  .topnav-links { display: none; }
  /* The links carried the `margin: 0 auto` that held the avatar out at the far
     edge; with them hidden the chip fell back against the wordmark. It takes
     the auto margin itself, so it stays where a profile button belongs — the
     top right corner, thumb side. */
  .topnav-right { margin-left: auto; }
  .planner-dock { margin-top: -40px; }
}

/* ---------- Sign up (local passport) ---------- */
.cine-mark.dark { color: var(--ink); }
.signup-wrap { min-height: 100svh; display: flex; align-items: center; justify-content: center; padding: 40px 20px; }
.signup-card {
  width: min(100%, 440px); background: var(--surface); border-radius: var(--r-lg);
  padding: 32px 30px 26px; box-shadow: 0 20px 50px rgba(92, 74, 62, 0.14);
  display: flex; flex-direction: column; gap: 14px;
}
.signup-card h1 { font-size: 1.9rem; line-height: 1.1; margin-top: 6px; }
.signup-sub { color: var(--muted); font-size: 0.95rem; }
.signup-input {
  font: inherit; font-weight: 600; width: 100%; padding: 12px 14px;
  border: 1.5px solid var(--border); border-radius: var(--r-sm); background: var(--surface); color: var(--ink);
}
.signup-input:focus { outline: none; border-color: var(--brand); }
/* Told in the same peach the season warnings and the access caveats use — this
   is a "mind this one" rather than a failure, and the palette has no red in it */
.signup-input.invalid { border-color: var(--gold); background: var(--gold-soft); }
.field-error {
  font-size: 0.83rem; font-weight: 700; color: var(--ink); margin-top: 4px;
  padding: 6px 11px; border-left: 3px solid var(--gold);
  background: linear-gradient(90deg, var(--gold-soft), rgba(251, 229, 216, 0) 88%);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
.field-error[hidden] { display: none; }
.avatar-row { display: flex; flex-wrap: wrap; gap: 8px; }
.avatar-pick {
  width: 46px; height: 46px; font-size: 1.4rem; cursor: pointer;
  background: var(--bg); border: 2px solid var(--border); border-radius: var(--r-sm);
  transition: all 0.15s ease;
}
.avatar-pick:hover { border-color: var(--brand); }
.avatar-pick.on { border-color: var(--brand); background: var(--accent-soft); transform: scale(1.06); }
/* The Google button only exists when js/firebase-config.js names a project */
.google-btn {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  font: inherit; font-weight: 800; font-size: 0.95rem; color: var(--ink);
  background: var(--surface); border: 1.5px solid var(--border); border-radius: var(--r-sm);
  padding: 12px 14px; cursor: pointer; transition: all 0.15s ease;
}
.google-btn:hover:not(:disabled) { border-color: var(--brand); background: var(--bg); }
.google-btn:disabled { opacity: 0.55; cursor: wait; }
.google-done { display: flex; align-items: center; justify-content: center; gap: 10px; font-size: 0.9rem; color: var(--muted); padding: 2px 0; }
.google-done b { color: var(--ink); }
.google-done .g-logo { width: 16px; height: 16px; }
.g-logo { width: 20px; height: 20px; flex: none; }
.signup-or { display: flex; align-items: center; gap: 12px; color: var(--muted); font-size: 0.78rem; font-weight: 700; }
.signup-or::before, .signup-or::after { content: ""; flex: 1; height: 1px; background: var(--border); }

/* ---------- Profile shell ---------- */
.profile-shell { display: grid; grid-template-columns: 236px 1fr; min-height: 100svh; }
.profile-side {
  background: var(--surface); border-right: 1px solid var(--border);
  padding: 26px 20px; display: flex; flex-direction: column; gap: 26px;
  position: sticky; top: 0; height: 100svh;
}
.side-nav { display: flex; flex-direction: column; gap: 4px; }
.side-nav a {
  color: var(--muted); font-weight: 700; font-size: 0.92rem; text-decoration: none;
  padding: 10px 12px; border-radius: var(--r-sm); transition: all 0.15s ease;
}
.side-nav a:hover { background: var(--accent-soft); color: var(--ink); }
.side-foot { margin-top: auto; display: flex; flex-direction: column; gap: 8px; }
.side-user { display: flex; align-items: center; gap: 9px; font-weight: 800; font-size: 0.92rem; }
.side-user em { font-style: normal; font-size: 1.3rem; }
.side-cloud { font-size: 0.78rem; font-weight: 700; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.link-btn { background: none; border: none; font: inherit; font-size: 0.82rem; color: var(--muted); cursor: pointer; text-align: left; text-decoration: underline; }
.link-btn:hover { color: var(--ink); }

/* The whole passport aims to sit on one screen: badges render only when
   earned, stamps only where visited, and the trips list scrolls inside its
   own panel rather than growing the page. */
.profile-main { padding: 16px clamp(20px, 4vw, 44px) 20px; max-width: 1060px; }
.profile-top { display: flex; justify-content: space-between; gap: 12px; margin-bottom: 14px; }

.profile-hero {
  background: var(--surface); border-radius: var(--r-lg); padding: 20px;
  box-shadow: var(--shadow); display: grid;
  grid-template-columns: auto 1fr; gap: 14px 22px; align-items: center;
}
.pf-avatar {
  position: relative; width: 104px; height: 104px; border-radius: var(--r-lg); font-size: 3rem;
  background: linear-gradient(135deg, var(--accent-soft), var(--mint-soft));
  display: flex; align-items: center; justify-content: center;
}
.pf-flame {
  position: absolute; top: -8px; right: -8px; width: 32px; height: 32px; border-radius: 50%;
  background: #fff; box-shadow: var(--shadow); font-size: 0.95rem;
  display: flex; align-items: center; justify-content: center;
}
.pf-id h1 { font-size: 2rem; line-height: 1.1; }
.pf-role { color: var(--muted); font-size: 0.9rem; font-weight: 700; margin-bottom: 12px; }
.xp-wrap { display: flex; align-items: center; gap: 12px; max-width: 420px; }
.xp-bar { flex: 1; height: 9px; border-radius: var(--r-pill); background: var(--border); overflow: hidden; }
.xp-fill { height: 100%; border-radius: var(--r-pill); background: linear-gradient(90deg, var(--brand), var(--mint)); transition: width 0.8s cubic-bezier(0.22,1,0.36,1); }
.xp-num { font-size: 0.76rem; font-weight: 800; color: var(--muted); white-space: nowrap; }

.pf-stats { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
/* Buttons, not ornaments: each tile jumps to the panel it counts */
.pf-stat {
  display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto;
  gap: 0 12px; align-items: center; font: inherit; color: var(--ink);
  text-align: left; cursor: pointer; transition: all 0.15s ease;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-md); padding: 12px 16px;
}
.pf-stat:hover { border-color: var(--brand); transform: translateY(-1px); }
.pf-ico {
  grid-row: 1 / 3; width: 40px; height: 40px; border-radius: 50%; background: var(--surface);
  display: flex; align-items: center; justify-content: center; font-size: 1.1rem; box-shadow: var(--shadow);
}
.pf-stat strong { font-family: var(--font-display); font-weight: 800; font-size: 1.4rem; line-height: 1.1; }
.pf-stat small { color: var(--muted); font-size: 0.76rem; }

.profile-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 14px; }
.panel { background: var(--surface); border-radius: var(--r-lg); padding: 18px; box-shadow: var(--shadow); }
.panel + .panel, .profile-grid + .panel { margin-top: 14px; }
.panel.flash { box-shadow: 0 0 0 3px var(--brand), var(--shadow); transition: box-shadow 0.25s ease; }
.panel-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.panel-head h2 { font-size: 1.25rem; display: flex; align-items: center; gap: 8px; }
.panel-head h2 em {
  font-style: normal; font-family: var(--font-body); font-size: 0.72rem; font-weight: 800;
  background: var(--bg); border-radius: var(--r-sm); padding: 2px 8px; color: var(--muted);
}
.panel-meter { flex: 1; height: 7px; border-radius: var(--r-pill); background: var(--border); overflow: hidden; min-width: 40px; }
.panel-meter span { display: block; height: 100%; border-radius: var(--r-pill); background: linear-gradient(90deg, var(--brand), var(--mint)); }
.panel-count { font-size: 0.74rem; font-weight: 800; color: var(--muted); }
.panel-hint { color: var(--muted); font-size: 0.85rem; margin-bottom: 12px; }

.badge-grid, .stamp-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
/* While picking, the full country list scrolls inside the panel — the page
   itself stays one screen */
.stamp-grid { max-height: 32vh; overflow-y: auto; }
.badge-tile {
  text-align: center; padding: 16px 10px; border-radius: var(--r-md);
  background: var(--bg); border: 1px solid var(--border);
  display: flex; flex-direction: column; align-items: center; gap: 4px;
}
.badge-tile strong { font-size: 0.82rem; }
.badge-tile small { font-size: 0.68rem; color: var(--muted); line-height: 1.35; }
.badge-tile.earned { background: var(--accent-soft); border-color: rgba(125, 154, 135, 0.35); }
.badge-tile.earned small { color: var(--brand-dark); font-weight: 800; }
.badge-tile.locked { opacity: 0.62; }
.stamp {
  font: inherit; cursor: pointer; text-align: center; padding: 14px 8px; border-radius: var(--r-md);
  background: var(--bg); border: 2px dashed var(--border); color: var(--ink);
  display: flex; flex-direction: column; align-items: center; gap: 3px; transition: all 0.15s ease;
}
.stamp:hover { border-color: var(--brand); }
.stamp-flag { font-size: 1.7rem; filter: grayscale(1); opacity: 0.5; transition: all 0.2s ease; }
.stamp-name { font-size: 0.8rem; font-weight: 800; }
.stamp-mark { font-size: 0.62rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.stamp.on { border-style: solid; border-color: var(--brand); background: var(--accent-soft); }
.stamp.on .stamp-flag { filter: none; opacity: 1; }
.stamp.on .stamp-mark { color: var(--brand-dark); }

.trip-list { display: flex; flex-direction: column; gap: 8px; max-height: 30vh; overflow-y: auto; }
.stamp-add { margin-top: 10px; font-weight: 800; text-decoration: none; color: var(--brand-dark); }
.stamp-add:hover { text-decoration: underline; }
/* A row is the trip, and clicking it reopens it — so it's a button, and it has
   to look like one you can press without turning the list into a wall of chrome:
   the arrow only arrives on hover. */
.trip-row {
  font: inherit; color: inherit; text-align: left; cursor: pointer; width: 100%;
  display: flex; align-items: center; gap: 14px; padding: 12px 14px;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-sm);
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}
.trip-row:hover { background: var(--mint-pale); border-color: var(--mint); transform: translateX(2px); }
.trip-row:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.trip-flag { font-size: 1.4rem; }
.trip-info { display: flex; flex-direction: column; min-width: 0; }
.trip-info strong { font-size: 0.95rem; }
.trip-info span { font-size: 0.78rem; color: var(--muted); }
.trip-season { margin-left: auto; font-size: 1.1rem; }
.trip-go {
  font-size: 1rem; color: var(--brand-dark); opacity: 0;
  transition: opacity 0.15s ease;
}
.trip-season + .trip-go { margin-left: 0; }
.trip-row:hover .trip-go, .trip-row:focus-visible .trip-go { opacity: 1; }

@media (max-width: 900px) {
  /* minmax(0, …) rather than a bare 1fr, for the reason .results-split needs
     it too: a 1fr track never goes below the min-content of what's in it, so on
     a 320px phone the column settled at 336 and took the passport page sideways
     with it. */
  .profile-shell { grid-template-columns: minmax(0, 1fr); }
  .profile-side {
    position: static; height: auto; flex-direction: row; align-items: center;
    gap: 16px; border-right: none; border-bottom: 1px solid var(--border);
    padding: 14px 16px; min-width: 0;
  }
  /* A flex child won't shrink below its own content unless it's told it may, so
     the nav ignored its overflow-x and stretched this bar to twice the width of
     a phone — taking the whole passport page sideways with it. */
  .side-nav { flex-direction: row; overflow-x: auto; flex: 1; min-width: 0; -webkit-overflow-scrolling: touch; }
  .side-nav a { white-space: nowrap; }
  .side-foot { margin-top: 0; margin-left: auto; flex: none; flex-direction: row; align-items: center; gap: 12px; }
  .profile-grid { grid-template-columns: 1fr; }
  .profile-hero { grid-template-columns: 1fr; text-align: center; justify-items: center; }
  /* Three counts, one under the other, was most of a screen spent on three
     numbers. They keep their row on a phone and stack instead: icon, number,
     what it counts. */
  .pf-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
  .pf-stat {
    grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto auto;
    justify-items: center; text-align: center; gap: 3px 0; padding: 12px 6px;
  }
  .pf-stat .pf-ico { grid-row: auto; width: 32px; height: 32px; font-size: 1rem; }
  .pf-stat strong { font-size: 1.25rem; }
  .pf-stat small { font-size: 0.68rem; line-height: 1.25; }
}

@media (max-width: 620px) {
  /* No room for a name and a nav on one line — the nav is what you came for */
  .profile-side { flex-wrap: wrap; gap: 10px 14px; }
  .side-nav { order: 3; flex-basis: 100%; }
  .badge-grid, .stamp-grid { grid-template-columns: repeat(2, 1fr); }

  /* Four tabs on one row meant "Achievements" sliced through the middle at the
     right-hand edge and "Trips planned" off the screen entirely, behind a
     sideways scroll nobody knew was there. They are the whole navigation of
     this page, so all four get to be visible: two by two, each one a full
     tappable row-half. */
  .side-nav {
    overflow-x: visible; gap: 4px;
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .side-nav a {
    justify-content: flex-start; min-width: 0; padding: 10px 10px; gap: 8px;
    font-size: 0.86rem; white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis;
  }
  .side-nav a .ico { width: 18px; height: 18px; flex: none; }
}

/* ---------- Kobo the mascot + spot illustrations ---------- */
.kobo { width: 100%; height: auto; display: block; }
.kobo-head { width: 34px; height: auto; flex: none; }
.kobo-head.nav { width: 48px; }
.cine-mark { display: flex; align-items: center; gap: 8px; }

@keyframes koboBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }

.how-head { display: flex; align-items: center; gap: 26px; margin-bottom: 34px; }
.below-hero .hero-features { margin-top: 26px; }
.how-kobo { width: 150px; flex: none; animation: koboBob 4s ease-in-out infinite; }
.how-title { font-size: 1.9rem; line-height: 1.15; margin: 2px 0 8px; }
.how-sub { color: var(--muted); max-width: 46ch; }
.below-hero .section-label { text-align: left; margin-bottom: 2px; }

.spot { width: 68px; height: 68px; }
.feat .spot { margin-bottom: 6px; }

.wishlist-kobo { width: 104px; flex: none; margin-bottom: 2px; }
.signup-kobo { width: 120px; margin: -6px auto 0; animation: koboBob 4s ease-in-out infinite; }
.loading-kobo { width: 160px; margin: 0 auto 18px; animation: koboBob 2.4s ease-in-out infinite; }
/* a white bunny on cream disappears below ~56px, so small placements sit on a
   mint disc — the same trick the medals use */
.found-kobo, .kobo-chip {
  width: 46px; height: 46px; flex: none; object-fit: contain; object-position: center bottom;
  background: var(--mint-soft); border-radius: 50%; padding: 4px 4px 0;
}
.found-line { display: flex; align-items: center; gap: 6px; }
.empty-state { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 10px 0 4px; }
.empty-kobo { width: 120px; opacity: 0.95; }
.empty-state p { color: var(--muted); font-size: 0.9rem; }

/* medals, drawn rather than emoji */
.medal { width: 62px; height: 62px; margin-bottom: 2px; }
.badge-tile.earned .medal { filter: drop-shadow(0 5px 12px rgba(228, 138, 102, 0.35)); }
.badge-tile.locked .medal { opacity: 0.7; }

@media (max-width: 700px) {
  .how-head { flex-direction: column; text-align: center; gap: 14px; }
  .how-sub { margin: 0 auto; }
  .below-hero .section-label { text-align: center; }
}
.ico { width: 19px; height: 19px; flex: none; }
.side-nav a { display: flex; align-items: center; gap: 10px; }
.pf-ico .ico { width: 20px; height: 20px; }
.pf-flame { padding: 3px; }
.pf-flame .kobo-head { width: 26px; height: 26px; object-fit: contain; object-position: center bottom; }
.side-user .kobo-head { width: 30px; height: 30px; object-fit: contain; object-position: center bottom; }

/* ---------- Planner panel: the whole questionnaire, in one card ---------- */
.planner {
  background: var(--surface); color: var(--ink);
  border-radius: var(--r-lg); padding: 26px 26px 22px;
  box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; gap: 18px;
}
.planner-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.planner-title { font-size: 1.6rem; text-align: left; margin: 0; }
.planner-lead { color: var(--muted); font-size: 0.9rem; margin-top: 2px; }
.planner-close {
  flex: none; width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  background: var(--bg); border: 1.5px solid var(--line); color: var(--muted); font-size: 0.9rem;
}
.planner-close:hover { background: var(--mint-soft); color: var(--ink); }

.planner-fields { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px 16px; }
.pf-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
/* What the chosen option means, in the space the select hasn't got. Reserved
   whether or not anything is chosen, so the fields stay on the same baseline. */
.pf-hint { font-size: 0.78rem; color: var(--muted); min-height: 1.1em; line-height: 1.35; padding-left: 2px; }

/* Stage one: where to, and nothing else */
.country-choices {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
  gap: 12px; margin: 4px 0 8px;
}
.country-choice {
  font: inherit; color: inherit; cursor: pointer; text-align: left;
  display: grid; grid-template-columns: auto 1fr; gap: 2px 12px;
  background: var(--bg); border: 1.5px solid var(--border); border-radius: var(--r-md);
  padding: 14px 16px; transition: all 0.15s ease;
}
.country-choice:hover { border-color: var(--brand); background: var(--mint-pale); transform: translateY(-2px); }
.country-choice em { grid-row: 1 / 3; font-style: normal; font-size: 1.7rem; align-self: center; }
.country-choice strong { font-size: 1rem; }
.country-choice small { color: var(--muted); font-size: 0.82rem; line-height: 1.35; }

/* The same choice, compact, sat in the hero under the Explore button */
.cine-naming { max-width: 40rem; }
.cine-acting { display: flex; flex-direction: column; gap: 22px; margin-top: 6px; }
/* The picker is the one control in the app that sat naked on a photograph.
   It docks in a frosted cream card instead — the same card language as every
   other screen — which also lets the continent labels read in the brand brown
   rather than as faint white caps fighting whatever the photo is doing. */
.cine-cta { align-self: flex-start; }
/* Centred on a phone, where the copy above it already fills the width and a
   left-hung button read as having slipped off the end of the line. Sits here
   rather than up with the rest of the mobile hero rules because it has to come
   after the flex-start it overrides. */
@media (max-width: 760px) {
  .cine-acting { align-items: center; }
  .cine-cta { align-self: center; }
  /* The whole hero group centres with it. On a wide screen the copy is a
     column hung off the left of a photograph; on a phone it IS the width, and
     anything left-hung reads as sitting off to one side of its own picture. */
  .cine-copy, .cine-naming { text-align: center; }
  .cine-naming { margin: 0 auto; }
  .cine-sub { margin-left: auto; margin-right: auto; }
}
.cine-pick {
  max-width: 640px;
  background: rgba(255, 250, 242, 0.88);
  -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  border: 1.5px solid rgba(255, 252, 246, 0.65);
  border-radius: var(--r-lg);
  padding: 16px 20px 20px;
  box-shadow: 0 18px 44px rgba(30, 22, 15, 0.22);
}
.cine-pick-title {
  display: block; font-family: var(--font-display); font-weight: 800;
  font-size: 0.95rem; color: var(--ink); margin-bottom: 12px;
}
.cine-pick .country-group-label { color: var(--muted); }
/* white on the frost, not cream on cream — the chips need their own edge */
.cine-pick .country-choice.compact {
  background: #fff; backdrop-filter: none;
  box-shadow: 0 2px 10px rgba(93, 74, 53, 0.10);
}
.cine-pick .country-choice.compact:hover { background: var(--mint-pale); }
.cine-pick-row { display: flex; flex-wrap: wrap; gap: 14px 22px; align-items: flex-start; }

/* The picker again at the foot of the front page, as a third slide in the
   same voice as the two above it — the card sits in the copy column, solid
   rather than frosted because the ground here is cream, not a photo */
.front-pick-end .cine-pick {
  margin-top: 34px; max-width: none;
  background: var(--surface); border: 1.5px solid var(--border);
  -webkit-backdrop-filter: none; backdrop-filter: none;
  box-shadow: var(--shadow);
}
/* Kobo waving goodbye, straight on the page — no polaroid frame here */
.pick-kobo {
  position: absolute; top: 8%; left: 24%; width: 42%; z-index: 2;
  animation: koboBob 4s ease-in-out infinite;
}
.pick-art .tag-1 { top: 8%; right: 4%; }
.country-group { display: flex; flex-direction: column; gap: 7px; }
.country-group-label {
  font-size: 0.66rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
  color: rgba(253, 252, 247, 0.6);
}
.country-group-row { display: flex; flex-wrap: wrap; gap: 8px; }
/* in the modal, where the cards are on cream rather than a photograph */
.country-choices .country-group-label { color: var(--muted); }
.country-choices { display: flex; flex-direction: column; gap: 14px; }
.country-choices .country-group-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); gap: 12px;
}
.country-choice.compact {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 15px; border-radius: var(--r-pill);
  /* it sits on a photograph, so it needs its own ground to stand on — and its
     own ink, since the hero around it now sets a cream text colour */
  background: rgba(253, 252, 247, 0.92); backdrop-filter: blur(6px);
  color: var(--ink); border-color: transparent;
}
.country-choice.compact em { font-size: 1.05rem; }
.country-choice.compact strong { font-size: 0.88rem; }
.country-choice.compact.on {
  background: var(--brand); border-color: var(--brand); color: var(--cream);
}
.country-choice.compact.on:hover { background: var(--brand-dark); }

/* The questions, on their own page */
.questions-page { max-width: 1160px; margin: 0 auto; padding: 26px clamp(18px, 4vw, 40px) 80px; }
.qp-top { display: flex; align-items: center; gap: 14px; margin-bottom: 20px; }
.qp-crumb { font-weight: 800; font-size: 0.95rem; }
.planner-dock.standalone { margin-top: 0; }


/* Step 2: the explainer on its own, before anything is asked. Wider than it was,
   because the three cards now share the row with Kobo rather than having it. */
.intro-page { max-width: 1240px; }
/* One screen with one job gets to fill it: the band and its button centre in
   the viewport rather than huddling small in the top-left corner. */
.intro-page { display: flex; flex-direction: column; min-height: calc(100svh - 130px); }
.intro-page .intro-head { margin-top: auto; }
.intro-page .how-strip-foot { margin-bottom: auto; }
/* Kobo on the left, the three steps on the right of him — one band rather than
   a mascot with a paragraph, then a separate row of cards underneath. */
.intro-head { display: flex; align-items: center; gap: 40px; margin: 10px 0 6px; }
.intro-head .how-kobo { width: 215px; flex: none; }
.intro-steps { flex: 1; min-width: 0; }
.intro-steps .section-label { font-size: 1rem; }
/* howItWorks() is also used on its own, where it centres itself in the page.
   Beside Kobo it's a column of the band, so it gives that up. */
.intro-steps .below-hero { max-width: none; margin: 0; padding: 0; }
.intro-steps .hero-features { margin-top: 26px; gap: 20px; }
/* The cards carry the whole screen here, so they're a size up from the landing
   version of the same strip. */
.intro-steps .feat { padding: 42px 26px 34px; gap: 8px; }
.intro-steps .feat .spot { width: 96px; height: 96px; margin-bottom: 10px; }
.intro-steps .feat strong { font-size: 1.25rem; }
.intro-steps .feat small { font-size: 0.98rem; }
.intro-steps .feat .feat-step {
  width: 36px; height: 36px; line-height: 36px; font-size: 1.05rem; top: -18px;
}
.intro-page .how-strip-foot { margin-top: 40px; }
.intro-page .how-strip-foot .btn { font-size: 1.15rem; padding: 12px 12px 12px 34px; }
@media (max-width: 700px) {
  .intro-head { flex-direction: column; text-align: center; gap: 16px; }
}
/* The passport, sat where the questions used to be on the landing page */
.dock-passport { display: flex; flex-direction: column; gap: 14px; }
.dock-pp-head { display: flex; align-items: center; gap: 12px; }
.dock-pp-avatar {
  width: 46px; height: 46px; border-radius: var(--r-md); flex: none;
  display: flex; align-items: center; justify-content: center; font-size: 1.5rem;
  background: linear-gradient(135deg, var(--accent-soft), var(--mint-soft));
}
.dock-pp-head strong { display: block; font-size: 1rem; }
.dock-pp-role { color: var(--muted); font-size: 0.82rem; font-weight: 700; }
.dock-pp-head .planner-change { margin-left: auto; }

.dock-pp-stats { display: flex; flex-wrap: wrap; gap: 10px; }
.dock-pp-stats span {
  display: flex; flex-direction: column; gap: 1px; flex: 1 1 120px;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 10px 12px; font-size: 0.78rem; color: var(--muted); font-weight: 700;
}
.dock-pp-stats b { font-size: 1.25rem; color: var(--ink); }

.dock-pp-stamps { display: flex; flex-wrap: wrap; gap: 6px; font-size: 1.4rem; }
.dock-pp-none { color: var(--muted); font-size: 0.84rem; }

.dock-passport.empty { flex-direction: row; align-items: flex-start; gap: 16px; }
.dock-kobo { width: 96px; flex: none; }
.dock-passport-copy { display: flex; flex-direction: column; gap: 6px; }
.dock-passport-copy strong { font-size: 1rem; }
.dock-passport-copy span { color: var(--muted); font-size: 0.88rem; }
.dock-passport-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; align-items: center; }

@media (max-width: 620px) {
  .dock-passport.empty { flex-direction: column; align-items: center; text-align: center; }
  .dock-passport-actions { justify-content: center; }
}

/* When the hero holds the choice, the panel below only points back to it */
.planner-uplink {
  font: inherit; font-weight: 800; font-size: 0.95rem; cursor: pointer;
  background: var(--mint-pale); color: var(--brand-dark);
  border: 1.5px dashed var(--brand); border-radius: var(--r-pill);
  padding: 12px 24px; align-self: flex-start; transition: all 0.15s ease;
}
.planner-uplink:hover { background: var(--accent-soft); }

/* Stage two: the country already answered, sat above the rest */
.planner-where {
  display: flex; align-items: center; gap: 10px;
  font-weight: 800; font-size: 1.05rem; margin-bottom: 2px;
}
.planner-change {
  font: inherit; font-size: 0.78rem; font-weight: 700; cursor: pointer;
  background: none; border: none; color: var(--brand); text-decoration: underline;
  padding: 2px 4px;
}
.planner-change:hover { color: var(--brand-dark); }


/* Months or exact dates — dates also answer "how long", so that field goes
   quiet rather than sitting there able to contradict them. */
.when-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.when-modes { display: inline-flex; gap: 4px; }
.when-mode {
  font: inherit; font-size: 0.68rem; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase; cursor: pointer; padding: 3px 9px;
  border-radius: var(--r-pill); border: 1.5px solid var(--border);
  background: transparent; color: var(--muted);
}
.when-mode.on { background: var(--brand); border-color: var(--brand); color: var(--cream); }

.pf-dates { display: flex; flex-wrap: wrap; gap: 10px; }
.pf-dates label {
  display: flex; flex-direction: column; gap: 4px; flex: 1 1 150px; min-width: 0;
  font-size: 0.7rem; font-weight: 800; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--muted);
}
.pf-dates input {
  font: inherit; font-weight: 600; font-size: 0.95rem; color: var(--ink);
  padding: 10px 12px; border-radius: var(--r-sm);
  border: 1.5px solid var(--border); background: var(--surface); width: 100%;
}
.pf-dates input:focus { outline: none; border-color: var(--brand); }
.planner select:disabled, .wiz-selects select:disabled { opacity: 0.55; cursor: not-allowed; }
/* Questions that take more than one answer */
/* Four short season chips need less room than three wordy transport ones */
.planner-multi { display: grid; grid-template-columns: 1fr 1.15fr; gap: 14px 22px; margin-top: 14px; }
.pf-multi { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.pf-chips { display: flex; flex-wrap: wrap; gap: 8px; }
/* twelve months read as a calendar, not a ragged wrap */
.pf-chips.months { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 7px; }
.pf-chips.months .act-chip { padding: 6px 4px; text-align: center; }
@media (max-width: 620px) { .pf-chips.months { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.planner-acts-block { display: flex; flex-direction: column; gap: 8px; }
.planner-label .opt, .planner-label em { font-style: normal; font-weight: 700; color: var(--muted); text-transform: none; letter-spacing: 0; }

.planner-go {
  font: inherit; font-weight: 800; font-size: 1rem; cursor: pointer;
  background: var(--brand); color: var(--cream); border: none;
  border-radius: var(--r-pill); padding: 9px 9px 9px 28px; margin-top: 2px;
  display: inline-flex; align-items: center; justify-content: center; gap: 14px;
  align-self: flex-start; transition: transform 0.15s ease, opacity 0.15s ease;
}
.planner-go .explore-arrow { width: 34px; height: 34px; font-size: 1.05rem; }
.planner-go:hover:not(:disabled) { transform: translateY(-2px); }
.planner-go:disabled { opacity: 0.4; cursor: not-allowed; }
.planner-note { font-size: 0.8rem; color: var(--muted); }

/* docked under the hero, overlapping it. The whole dock is one card — Kobo
   introduces on the left, the form sits on the right, both on the same white. */
.planner-dock {
  display: grid; grid-template-columns: minmax(230px, 290px) minmax(0, 1fr);
  gap: clamp(20px, 3vw, 38px); align-items: center;
  background: var(--surface); border-radius: var(--r-lg);
  padding: 28px clamp(22px, 3vw, 34px);
  box-shadow: var(--shadow-lg);
}
/* the form is already inside the card, so it drops its own chrome */
.planner-dock .planner {
  width: 100%; background: none; box-shadow: none; padding: 0; border-radius: 0;
}
.planner-dock .how-head {
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center;
  gap: 10px; margin: 0; height: 100%; text-align: left;
  border-right: 1px solid var(--line); padding-right: clamp(16px, 2vw, 30px);
}
.planner-dock .how-kobo { width: 150px; margin-left: -10px; }
.planner-dock .how-title { font-size: 1.6rem; }
.planner-dock .how-sub { font-size: 0.92rem; }
.planner-dock .section-label { margin: 0; }
@keyframes dockFlash { 0%, 100% { box-shadow: var(--shadow-lg); } 40% { box-shadow: 0 0 0 5px var(--mint), var(--shadow-lg); } }
.planner-dock.flash { animation: dockFlash 0.9s ease; }

/* floated over the results when you change an answer */
.planner-modal { position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center; padding: 24px; }
.planner-backdrop { position: absolute; inset: 0; background: rgba(92, 74, 62, 0.42); animation: fadeIn 0.2s ease; }
@keyframes fadeIn { from { opacity: 0; } }
.planner-modal-inner {
  position: relative; width: min(100%, 940px); max-height: 90svh; overflow-y: auto;
  animation: fadeSlideIn 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* wishlist header, replacing the old step counter */
.wl-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 28px; }

@media (max-width: 1100px) {
  .planner-dock { grid-template-columns: 1fr; }
  .planner-dock .how-head {
    flex-direction: row; align-items: center; gap: 20px; height: auto;
    border-right: none; border-bottom: 1px solid var(--line);
    padding: 0 0 18px;
  }
  .planner-dock .how-kobo { margin-left: 0; }
}
@media (max-width: 900px) {
  /* Two columns need about 620px to hold "Same bed all trip · 1 hotel" without
     cutting it off; below that it's one field per row. */
  .planner { max-width: 620px; }
  .planner-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .planner-multi { grid-template-columns: 1fr; }
  .planner-dock { margin-top: -50px; }
  .planner-go { align-self: stretch; }
}
@media (max-width: 640px) {
  .planner-dock .how-head { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 680px) {
  .planner { max-width: 420px; }
  .planner-fields { grid-template-columns: 1fr; }
}

/* ---------- Touch ----------
   Everything here is about fingers rather than screen width, so it keys off
   pointer: coarse. A phone in landscape is still a phone, and a 1280px tablet
   still has no cursor — width alone would miss both. */
@media (pointer: coarse) {
  /* iOS Safari zooms the whole page in when you focus a control smaller than
     16px and never zooms back out, stranding you mid-questionnaire at 1.3×. */
  .planner select, .xsearch, .signup-input, .pf-dates input { font-size: 16px; }

  /* A thumb needs about 44px. These all measured between 20px and 43px. */
  .fpill, .act-chip, .xpill, .xchip, .xadd, .btn-sm, .back-link,
  .greet, .leg-link, .link-btn, .tab-btn, .planner-change, .when-mode, .region-chip,
  .topnav-links a, .side-nav a,
  .rp-tab, .maybe-base, .stay-alt-chip {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  /* Links that read as sentences keep their left edge; only the pills centre */
  .leg-link, .link-btn, .planner-change { justify-content: flex-start; }
  /* Turning these into flex containers drops the whitespace between their words
     — a flex parent throws away text nodes that are only spaces — so a chip
     written as `Kyoto Station <em>cheaper</em>` came out "Kyoto Stationcheaper".
     Anything with two children in here needs the space put back as a gap. */
  .fpill, .act-chip, .xpill, .xchip, .xadd, .btn-sm, .back-link,
  .greet, .leg-link, .link-btn, .tab-btn, .planner-change, .when-mode,
  .topnav-links a, .rp-tab, .stay-alt-chip { gap: 6px; }

  /* Hover styling sticks after a tap on touch, leaving buttons looking pressed */
  .fpill:hover, .act-chip:hover, .xpill:hover, .xchip:hover, .xadd:hover,
  .back-link:hover { transform: none; }

  /* Nothing flashes grey under a finger any more — see the tap-highlight rule
     at the top — so a press has to be answered by the thing being pressed.
     One behaviour everywhere: it gives a little, and comes back.
     `.map-toggle` is out because its resting state is already a transform
     (translateX(-50%)) and a bare scale here would throw it half a pill
     sideways on every tap; it has its own :active for that reason. Text links
     are out too — a sentence that shrinks reads as a glitch, not a press, and
     `.poi-card` already answers by scaling its photograph. No transition is set
     here on purpose: most of these carry `transition: all`, which covers it,
     and an `#app button` rule strong enough to add one would also overwrite the
     colour fades those chips are relying on. */
  #app button:active:not(:disabled):not(.map-toggle):not(.link-btn):not(.leg-link):not(.poi-card),
  #app summary:active {
    transform: scale(0.97);
  }
}

/* ---------- Results: winner card and wishlist side by side ---------- */
.rp-top {
  /* min(340px, 100%), not a bare 340px: on a 375px phone the column is 335px
     wide, and a hard 340px minimum took the whole page sideways by five. */
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
  gap: 18px; align-items: start;
}
.rp-top .hero-card, .rp-top .rp-section { margin-top: 0; }
/* Asides on the second grid row start level with each other */
.rp-top > .season-card, .rp-top > .maybe-card { margin-top: 0; align-self: start; }
/* The season card runs the full width so its warnings can sit two across —
   penned into one 340px column they stacked, and a pair of them was the
   tallest thing on the overview. */
.rp-top > .season-card { grid-column: 1 / -1; }
/* The split plan needs elbow room its column never had: full width, so the
   legs sit side by side with the hop between them */
.rp-top > .split-card { grid-column: 1 / -1; margin-top: 0; }
.rp-top .rp-section { align-self: stretch; }
.rp-left { display: flex; flex-direction: column; min-width: 0; }
/* Right-hand column: where to stay, how to book it, and how the base scored. */
.rp-right { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.rp-right > * { margin-top: 0; }
.score-card {
  margin-top: 12px; padding: 20px 22px; border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--border);
}
.score-head {
  font-size: 0.78rem; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 14px;
  line-height: 1.4;
}
/* The grid's bottom margin and the note's matching negative one cancel out where
   these sit in the hero body. Pulled apart here, the negative margin has nothing
   to cancel and the note lands on top of the last row. */
.rp-right .score-grid { margin: 0; max-width: none; gap: 12px; }
.rp-right .score-note {
  margin: 16px 0 0; padding-top: 14px; text-align: left; line-height: 1.5;
  border-top: 1px solid var(--line);
}
/* A narrower column than the hero body's 150px, and the labels wrap into it
   rather than being cut off with an ellipsis — "Adventure & adrenaline" was
   losing its second word. */
.rp-right .score-row { grid-template-columns: minmax(0, 108px) 1fr 42px; align-items: center; }
.rp-right .score-label { white-space: normal; overflow: visible; line-height: 1.3; font-size: 0.84rem; }
/* The picks, two abreast across the full width — one column made a list of
   seven into a long thin ribbon with an empty half-page beside it. */
.wl-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr));
  gap: 10px; align-items: stretch;
}
/* The rows carry their own bottom margin for the stacked lists elsewhere; in the
   grid the gap does that job. */
.wl-grid .wl-row { margin-bottom: 0; height: 100%; }

/* three outcomes, not two: on the doorstep, a long day out, or worth a night */
.wl-row.wl-stretch { border-color: var(--gold); background: var(--gold-soft); }
.wl-status.stretch { background: var(--gold); color: var(--ink); }
.wl-status.ok { background: var(--brand); color: var(--cream); }
.wl-status.no, .wl-status.far { background: var(--line); color: var(--muted); }

/* ---------- Explore ---------- */
.explore-page { max-width: 1060px; margin: 0 auto; padding: 24px clamp(20px, 4vw, 44px) 90px; }
.explore-top { display: flex; justify-content: space-between; gap: 12px; margin-bottom: 26px; }
/* Kobo, the heading, and the line under it: a grid rather than a row, so the
   line can sit beside Kobo on a wide screen and run the full width beneath him
   on a phone without either arrangement being the odd one out. */
.explore-head {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  align-items: center; column-gap: 26px; row-gap: 6px; margin-bottom: 26px;
}
.explore-kobo { width: 128px; flex: none; grid-row: 1 / span 2; }
.explore-naming { min-width: 0; }
.explore-sub { grid-column: 2; }

.explore-filters {
  display: flex; flex-direction: column; gap: 12px; margin-bottom: 24px;
  padding-bottom: 20px; border-bottom: 1px solid var(--line);
}
.xcountries, .xcats { display: flex; flex-wrap: wrap; gap: 8px; }
.xpill, .xchip {
  font: inherit; font-weight: 700; font-size: 0.84rem; cursor: pointer;
  background: var(--surface); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: var(--r-pill); padding: 7px 14px;
  transition: all 0.15s ease;
}
.xpill:hover, .xchip:hover { border-color: var(--brand); }
.xpill.on { background: var(--brand); border-color: var(--brand); color: var(--cream); }
.xchip.on { background: var(--mint-soft); border-color: var(--brand); }
/* Wide screens fit all fifteen, so the cap and its button are a phone rule only
   — see the max-width block below, which is where .capped actually bites. */
.xcats-more { display: none; }
.xsearch {
  font: inherit; font-weight: 600; width: 100%; max-width: 420px;
  padding: 11px 16px; border-radius: var(--r-pill);
  border: 1.5px solid var(--line); background: var(--surface); color: var(--ink);
}
.xsearch:focus { outline: none; border-color: var(--brand); }

.explore-list { display: flex; flex-direction: column; gap: 14px; }
.xrow {
  display: grid; grid-template-columns: auto minmax(0, 1fr) 168px; gap: 18px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 18px 20px; transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.xrow:hover { box-shadow: var(--shadow); transform: translateY(-2px); }
.xnum {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  background: var(--mint-soft); border: 1.5px solid var(--brand); color: var(--brand-dark);
  display: flex; align-items: center; justify-content: center;
  font-size: 0.8rem; font-weight: 800;
}
.xtitle { font-family: var(--font-display); font-weight: 800; font-size: 1.2rem; line-height: 1.2; }
.xtags { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.xtag {
  font-size: 0.72rem; font-weight: 700; color: var(--muted);
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-pill); padding: 3px 9px;
}
.xtag.must { background: var(--gold-soft); border-color: var(--gold); color: var(--ink); }
.xdesc { font-size: 0.92rem; line-height: 1.55; }
.xaccess { font-size: 0.78rem; color: var(--muted); margin-top: 6px; }

.xside { display: flex; flex-direction: column; gap: 10px; }
.xthumb {
  position: relative; height: 106px; border-radius: var(--r-sm); overflow: hidden;
  background: var(--mint-pale); display: flex; align-items: center; justify-content: center;
}
.xthumb em { font-style: normal; font-size: 1.6rem; }
.xthumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 0.5s ease; }
.xthumb img.loaded { opacity: 1; }
.xadd {
  font: inherit; font-weight: 800; font-size: 0.84rem; cursor: pointer;
  background: var(--surface); color: var(--ink);
  border: 1.5px solid var(--line); border-radius: var(--r-pill); padding: 9px 14px;
  transition: all 0.15s ease;
}
.xadd:hover { border-color: var(--brand); background: var(--mint-pale); }
.xadd.on { background: var(--brand); border-color: var(--brand); color: var(--cream); }

@media (max-width: 760px) {
  .xrow { grid-template-columns: auto minmax(0, 1fr); }
  .xside { grid-column: 1 / -1; flex-direction: row; align-items: center; }
  .xthumb { flex: 1; height: 90px; }
  .xadd { flex: none; }
}

/* On a phone the whole first section — Kobo stacked over an eyebrow, a
   two-line heading, a three-line paragraph, then seven country pills over
   three rows — was a screen and a half before a single thing to do appeared.
   Kobo keeps his full size, as the paintings do everywhere outside the
   questionnaire; what changes is that he stands beside the heading rather than
   above it, and everything around him tightens. */
@media (max-width: 560px) {
  .explore-page { padding: 16px 16px 76px; }
  .explore-top { margin-bottom: 14px; }
  .explore-head { column-gap: 14px; row-gap: 4px; margin-bottom: 16px; }
  .explore-page .how-title { font-size: 1.3rem; }
  /* Full width under both, where it has room to be read in two lines rather
     than six down a column narrowed by the painting beside it. */
  .explore-sub { grid-column: 1 / -1; font-size: 0.88rem; }
  .explore-filters { gap: 10px; margin-bottom: 18px; padding-bottom: 14px; }
  .xcountries, .xcats { gap: 6px; }
  .xpill, .xchip { font-size: 0.78rem; padding: 7px 11px; }
  .xsearch { padding: 10px 14px; }

  /* Fifteen categories wrapped to eight rows here, which put the first thing
     you could actually do below two screens of filters. The first five wrap
     into two, and the button under them says how many more there are — the
     sideways rail this replaced sliced its last chip through the middle of a
     word, and read as broken rather than as "there's more this way". */
  /* Child 1 is the "All 35" chip, so the five categories run to child 6 —
     keep this in step with XCATS_SHOWN in app.js. */
  .xcats.capped > .xchip:nth-child(n + 7) { display: none; }
  /* Seven countries wrapped to three rows of chips; as one swipeable rail
     they're a single row, and the list of places starts a screen earlier. */
  .xcountries {
    flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; margin-left: -16px; margin-right: -16px;
    padding: 0 16px 4px;
  }
  .xcountries::-webkit-scrollbar { display: none; }
  .xcountries > * { flex: none; }
  .xcats-more {
    display: inline-flex; align-items: center; align-self: flex-start;
    min-height: 44px; padding: 8px 15px;
    font: inherit; font-weight: 800; font-size: 0.78rem; cursor: pointer;
    color: var(--brand-dark); background: none;
    border: 1.5px dashed var(--border); border-radius: var(--r-pill);
  }

}

/* ---------- The questionnaire, one card at a time ---------- */
/* The old nine-dropdown form, dealt as a deck: one question, big tappable
   answers, and a way past every one of them. Same controls vocabulary as the
   rest of the site — chips tick, cards pick — just one decision per screen. */
.wiz { max-width: 780px; margin: 0 auto; }
.wiz-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 28px clamp(20px, 4vw, 36px) 26px;
  box-shadow: var(--shadow);
}
@keyframes wizIn     { from { opacity: 0; transform: translateX(26px); }  to { opacity: 1; transform: none; } }
@keyframes wizInBack { from { opacity: 0; transform: translateX(-26px); } to { opacity: 1; transform: none; } }
.wiz-card.wiz-in      { animation: wizIn 0.32s cubic-bezier(0.22, 1, 0.36, 1); }
.wiz-card.wiz-in-back { animation: wizInBack 0.32s cubic-bezier(0.22, 1, 0.36, 1); }

.wiz-progress { display: flex; align-items: center; gap: 14px; margin-bottom: 20px; }
.wiz-count {
  flex: none; font-size: 0.78rem; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--muted);
}
.wiz-bar { flex: 1; height: 7px; background: var(--sunk); border-radius: var(--r-pill); overflow: hidden; }
.wiz-bar-fill {
  height: 100%; border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--brand), var(--mint));
  transition: width 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.wiz-head { display: flex; align-items: center; gap: 16px; margin-bottom: 18px; }
.wiz-kobo { width: 92px; flex: none; }
.wiz-title { font-size: 1.55rem; font-weight: 900; line-height: 1.2; }
.wiz-sub { font-size: 0.92rem; color: var(--muted); margin-top: 4px; line-height: 1.5; }

.wiz-choices {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
}
.wiz-choices.dense { grid-template-columns: repeat(auto-fill, minmax(min(160px, 100%), 1fr)); }
/* Cards whose sub carries a real sentence (the passport visa notes) need room
   to wrap at the comma, not inside "Visa-free" */
.wiz-choices.wide { grid-template-columns: repeat(auto-fill, minmax(min(215px, 100%), 1fr)); }
/* …and the idle tick shouldn't tax that room — park it in the corner as on mobile */
.wiz-choices.wide .wiz-chip { position: relative; }
.wiz-choices.wide .wiz-tick { position: absolute; top: 8px; right: 8px; margin: 0; }
.wiz-choices.wide .wiz-chip-text { padding-right: 14px; }
.wiz-chip {
  display: flex; align-items: center; gap: 12px; text-align: left;
  font: inherit; cursor: pointer; padding: 13px 14px;
  background: var(--cream); border: 1.5px solid var(--line); border-radius: var(--r-md);
  transition: all 0.15s ease;
  /* A grid item is min-content wide by default, so the longest label in the
     hand ("Comfortable" alongside its icon) set a floor the column couldn't go
     under — and the card, being a flex item, grew past the screen to honour it.
     Nothing in here is allowed to widen the card: the label wraps instead, and
     breaks mid-word only if the word alone can't fit. */
  min-width: 0; overflow-wrap: break-word;
}
/* The answers deal themselves in, in reading order, each one a beat behind the
   last — so a new question arrives as a hand of cards rather than as a block of
   markup that was simply already there. `backwards` rather than `both` on
   purpose: it holds the from-state through the delay but hands the element
   back to its own rules the moment it lands, so the hover lift and the picked
   state still work afterwards. The delay is set per chip in wizChoices. */
@keyframes wizChipIn { from { opacity: 0; transform: translateY(12px) scale(0.97); } }
.wiz-chip { animation: wizChipIn 0.34s cubic-bezier(0.22, 1, 0.36, 1) backwards; }
.wiz-chip:hover { border-color: var(--brand); transform: translateY(-1px); box-shadow: var(--shadow); }
.wiz-chip.on { background: var(--accent-soft); border-color: var(--brand); }
.wiz-ico { font-style: normal; font-size: 1.35rem; flex: none; line-height: 1; }
.wiz-chip-text { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.wiz-chip-text strong { font-size: 0.94rem; font-weight: 800; color: var(--ink); }
.wiz-chip-text small { font-size: 0.77rem; color: var(--muted); line-height: 1.35; }
.wiz-tick {
  margin-left: auto; flex: none; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center; font-size: 0.72rem; font-weight: 900;
  background: var(--brand); color: var(--cream);
  opacity: 0; transform: scale(0.5); transition: all 0.18s ease;
}
.wiz-chip.on .wiz-tick { opacity: 1; transform: none; }
/* The month grid doesn't need card-sized answers */
.wiz-choices.dense .wiz-chip { padding: 10px 12px; }

.wiz-modes { margin-bottom: 14px; }
.wiz-dates { margin-top: 4px; }
.wiz-note { font-size: 0.85rem; color: var(--muted); margin-top: 12px; line-height: 1.5; }
.wiz-selects {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
}

.wiz-foot { display: flex; justify-content: flex-end; align-items: center; gap: 16px; margin-top: 22px; }
/* .explore-arrow is a flex disc — the button must be a flex row or it stacks */
.wiz-next {
  display: inline-flex; align-items: center; gap: 12px;
  padding: 8px 8px 8px 24px; font-size: 0.95rem;
}
.wiz-next .explore-arrow { width: 32px; height: 32px; font-size: 1rem; }
.wiz-skip {
  font: inherit; font-weight: 800; font-size: 0.9rem; cursor: pointer;
  background: none; border: none; color: var(--muted); padding: 10px 14px;
  border-radius: var(--r-pill); transition: all 0.15s ease;
}
.wiz-skip:hover { color: var(--ink); background: var(--mint-pale); }

/* The recap card at the end: every question, its answer or its honest blank,
   each row a way back to change it. */
.wiz-recap { display: flex; flex-direction: column; gap: 6px; margin-bottom: 22px; }
.wiz-recap-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  font: inherit; text-align: left; cursor: pointer; padding: 9px 14px;
  background: var(--cream); border: 1px solid var(--line); border-radius: var(--r-sm);
  transition: all 0.15s ease;
}
.wiz-recap-row:hover { border-color: var(--brand); background: var(--mint-pale); }
.wiz-recap-row span { font-size: 0.88rem; font-weight: 700; color: var(--muted); }
.wiz-recap-row b { font-size: 0.88rem; font-weight: 800; color: var(--brand-dark); text-align: right; }
.wiz-recap-row.open b { color: var(--muted); font-weight: 600; font-style: italic; }
.wiz-go { width: 100%; }
/* The finish card's foot stacks the button over its note, unlike the question
   cards' right-aligned Skip/Next row. On a phone the recap now rides in
   .wiz-body, so it scrolls under this foot rather than pushing it off-screen. */
.wiz-finish .wiz-foot { flex-direction: column; align-items: stretch; gap: 8px; }
.wiz-finish .wiz-recap { margin-bottom: 0; }

/* No phone-size art: the paintings keep their desktop size everywhere — the
   layouts flex around them, not the other way round. (Same rule as the
   activity icons; the user asked for it twice.) */
@media (max-width: 560px) {
  .wiz-title { font-size: 1.3rem; }
  /* minmax(0, …), not 1fr: a bare 1fr floors at the column's min-content, which
     is how a long answer used to make the card wider than the phone. */
  .wiz-choices, .wiz-choices.dense { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .wiz-choices .wiz-chip { flex-direction: column; align-items: flex-start; gap: 6px; }
  .wiz-tick { position: absolute; } /* keep the tick from stretching the column */
  .wiz-chip { position: relative; }
  .wiz-chip .wiz-tick { top: 8px; right: 8px; margin: 0; }
}

/* ---------- The questionnaire as one screen per question ----------
   On a phone this was a long page you scrolled: the answers ran off the bottom
   and the button that moves you on ran off with them, so every question began
   by scrolling to find out what the question was. The card is now the screen
   itself — the progress bar and Kobo pinned at the top, the onward button
   pinned at the foot, and the answers in between. The page never scrolls; on
   the two longest questions only the answers do, and only on a short phone.
   Everything here is tuned to buy that middle band as much height as possible,
   which is why the paddings are so much tighter than the desktop card's. */
@media (max-width: 700px) {
  /* A definite height, not a minimum. `min-height` still lets the section grow
     to whatever its contents want, so the flex children never had to shrink and
     the two long questions simply pushed the page taller — which is the scroll
     this is here to remove. Pinned to the small viewport height so it still
     fits with iOS Safari's chrome showing. */
  .wiz-page.questions-page {
    height: 100svh; max-height: 100svh; overflow: hidden;
    padding: 12px; display: flex; flex-direction: column;
    /* Nothing on this screen scrolls, so nothing should bounce either — the
       rubber-band drag reads as "there is more down there" when there isn't. */
    overscroll-behavior: none;
  }
  .wiz-page .qp-top { margin-bottom: 10px; flex: none; }
  .wiz-page .wiz-progress, .wiz-page .wiz-head, .wiz-page .wiz-foot { flex: none; }
  /* `min-width: 0` on both, for the same reason `min-height: 0` is on them: a
     flex item defaults to min-content in that axis, so one long answer inside
     grew the card past the right edge of the phone and the whole page went
     with it. Nothing in the questionnaire may move sideways. */
  .wiz-page .wiz { flex: 1; display: flex; min-height: 0; min-width: 0; width: 100%; }
  .wiz-page .wiz-card {
    flex: 1; display: flex; flex-direction: column; min-height: 0; min-width: 0;
    padding: 16px 15px 14px;
  }
  .wiz-page .wiz-progress { margin-bottom: 9px; }
  .wiz-page .wiz-head { margin-bottom: 9px; gap: 10px; }
  /* The one part that gives: it scrolls only when the answers genuinely can't
     fit, and the question above it and the button below it stay put while it
     does. `min-height: 0` is what lets a flex child shrink far enough to
     scroll at all — without it the body just pushes the foot off-screen. */
  /* Centred, not top-aligned: the twelve months filled half the card and left
     the other half empty between the last answer and the button, which put the
     shortest questions furthest from the thumb. `safe` is doing real work — a
     plain `center` on an overflowing flex column pushes the first answers off
     the top where they can't be scrolled back to, and the two long questions do
     overflow on a short phone. */
  .wiz-page .wiz-body {
    flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    display: flex; flex-direction: column; justify-content: safe center;
  }
  /* A rule under the answers, so a list that runs on reads as continuing behind
     the button rather than as a card that got cut off */
  .wiz-page .wiz-foot { margin-top: 0; padding-top: 12px; border-top: 1px solid var(--line); }
  .wiz-page .wiz-choices { gap: 8px; }
  /* Tighter padding buys rows, but the single-line answers — the twelve months
     — landed at 42px, and a thumb wants 44. */
  .wiz-page .wiz-chip { padding: 10px 12px; min-height: 44px; }
  .wiz-page .wiz-sub { font-size: 0.86rem; }
  /* The body's 1.6 is set for paragraphs; on a two-word label stacked under a
     painting it just costs rows. */
  .wiz-page .wiz-chip-text strong { line-height: 1.25; }
  .wiz-page .wiz-chip-text small { line-height: 1.3; }

  /* The twelve months came to ten pixels over the body's height, which bought a
     scrollbar for one row's worth of nothing. */
  .wiz-page .wiz-choices { gap: 7px; }
  .wiz-page .wiz-modes { margin-bottom: 10px; }

  /* Six answers or fewer take the full width, one to a row. Two columns left a
     phone-width label about seventy pixels to work in, which is not enough for
     "Restaurants close by" — it wrapped after "Restauran". These questions are
     short enough that a column each costs nothing and every label reads whole. */
  .wiz-page .wiz-choices:not(.dense):not(.wide) { grid-template-columns: minmax(0, 1fr); }

  /* Twelve months in two columns is six rows, and on a short phone the last of
     them — December, the one people scroll for — sat under the fold. They are
     three-letter answers with no painting to hold, so they take a third column
     and the whole year fits in four rows with room to spare. */
  .wiz-page .wiz-choices.months { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .wiz-page .wiz-choices.months .wiz-chip {
    justify-content: center; text-align: center; padding: 8px 6px;
  }
  .wiz-page .wiz-choices.months .wiz-chip-text { align-items: center; }
  /* A three-letter month leaves the corner free, so the tick keeps its place
     there rather than taking a column of the row and pushing the label off
     centre. */
  .wiz-page .wiz-choices.months .wiz-tick {
    top: 4px; right: 5px; width: 16px; height: 16px; font-size: 0.58rem;
  }

  /* The finish card has no paintings on it, so it can simply be tighter: eleven
     questions, each one row, all on the screen at once. The question is the
     thing you scan for, so it keeps the width and its answer takes what's left
     rather than wrapping the row onto a second line. */
  .wiz-page .wiz-finish .wiz-recap { gap: 4px; }
  .wiz-page .wiz-recap-row { padding: 5px 11px; gap: 10px; align-items: center; }
  .wiz-page .wiz-recap-row span,
  .wiz-page .wiz-recap-row b {
    font-size: 0.78rem; line-height: 1.25;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .wiz-page .wiz-recap-row span { flex: 1 1 auto; min-width: 0; }
  .wiz-page .wiz-recap-row b { flex: 0 1 auto; min-width: 0; }
  /* The line under the button explains the next screen, which the next screen
     also explains. On a phone that costs a recap row. */
  .wiz-page .wiz-finish .planner-note { display: none; }
  .wiz-page .wiz-finish .wiz-head { margin-bottom: 8px; }

  /* ---- The answers, sized to fit the screen rather than the sheet ----
     Everywhere else the paintings hold their full size. Here they can't: a
     stacked 52px painting over a label and a sub-line makes a 132px answer, and
     fourteen of those is three screens of scrolling on the one question people
     most need to see whole. So on phones only, inside the questionnaire, the
     painting shrinks and moves alongside its label. */
  .wiz-page .wiz-choices .wiz-chip {
    flex-direction: row; align-items: center; text-align: left;
    gap: 10px; padding: 8px 34px 8px 10px;
  }
  .wiz-page .wiz-body .act-art,
  .wiz-page .wiz-body .quiz-art { width: 34px; height: 34px; }
  .wiz-page .wiz-body .quiz-art.flag { width: 32px; height: 24px; }
  .wiz-page .wiz-ico { flex: none; }
  /* The sub-line is the first thing to go: it's the elaboration, and the label
     above it already carries the answer. */
  .wiz-page .wiz-chip-text small { display: none; }
  /* Nine passports in one column was the tallest screen in the whole flow */
  .wiz-page .wiz-choices.wide { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .wiz-page .wiz-choices.wide .wiz-chip-text { padding-right: 0; }
  /* Two columns leaves each label about ninety pixels, and "Somewhere" wanted
     more than that — it wrapped after "Somewhe". The tick shrinks into the
     corner as it does on the activities, and the padding it was reserving goes
     back to the label. */
  .wiz-page .wiz-choices.wide .wiz-chip { padding-right: 24px; }
  .wiz-page .wiz-choices.wide .wiz-tick {
    top: 4px; right: 4px; width: 17px; height: 17px; font-size: 0.6rem;
  }
  /* "Somewhere" is the longest single word in the flow and it was still four
     pixels over the column. A slightly smaller flag and label clear it. */
  .wiz-page .wiz-body .wide .quiz-art.flag { width: 28px; height: 21px; }
  .wiz-page .wiz-choices.wide .wiz-chip-text strong { font-size: 0.88rem; }
  /* An odd number of passports leaves the last one — "Somewhere else", the
     longest label of the nine — alone on its row anyway, so it takes the whole
     width and reads on one line even on a 360px phone. */
  .wiz-page .wiz-choices.wide .wiz-chip:last-child:nth-child(odd) { grid-column: 1 / -1; }
  /* Fourteen activities is the tallest question in the flow: seven rows have to
     fit where five would sit comfortably, so this one screen takes a smaller
     label, a tighter gap between rows, and lets its tick sit over the corner
     instead of reserving a column of its own. Two-line labels still fit. */
  .wiz-page .wiz-choices.acts { gap: 5px; }
  .wiz-page .wiz-choices.acts .wiz-chip { padding: 5px 8px; gap: 7px; min-height: 44px; }
  .wiz-page .wiz-choices.acts .act-art { width: 30px; height: 30px; }
  .wiz-page .wiz-choices.acts .wiz-chip-text strong { font-size: 0.78rem; }
  .wiz-page .wiz-choices.acts .wiz-tick {
    top: 2px; right: 2px; width: 17px; height: 17px; font-size: 0.6rem;
  }
  /* The flying-from screen carries a button, an "or", two selects and a note —
     the one question built out of paragraphs rather than a grid, and the last
     few pixels it needs come off the space between them. */
  .wiz-page .wiz-domestic { margin-bottom: 9px; }
  .wiz-page .wiz-or { margin-bottom: 8px; }
  .wiz-page .wiz-note { margin-top: 9px; }

  /* Kobo introduces the question; at this size he can do it smaller */
  .wiz-page .wiz-kobo img, .wiz-page .wiz-kobo { max-width: 74px; }
}

/* Small phones held upright — an SE with the address bar showing is barely 560px
   tall, a hundred short of the screens above. The question and its answers keep
   their place; what goes is the decoration around them, in the order we'd miss
   it least: Kobo, then the line under the question. */
@media (max-width: 700px) and (max-height: 620px) {
  .wiz-page .wiz-kobo { display: none; }
  .wiz-page .wiz-sub { display: none; }
  .wiz-page .wiz-title { font-size: 1.15rem; }
  .wiz-page .wiz-card { padding: 12px 12px 10px; }
  .wiz-page .wiz-progress { margin-bottom: 7px; }
  .wiz-page .wiz-head { margin-bottom: 7px; }
  .wiz-page .wiz-foot { padding-top: 9px; }
  .wiz-page .wiz-choices { gap: 6px; }
  /* The 44px thumb target holds even here: what shrinks is the padding around
     the label, never the height of the thing you have to hit. */
  .wiz-page .wiz-choices .wiz-chip { padding: 6px 30px 6px 8px; }
  .wiz-page .wiz-body .act-art, .wiz-page .wiz-body .quiz-art { width: 28px; height: 28px; }
  .wiz-page .wiz-choices.acts .act-art { width: 26px; height: 26px; }
  .wiz-page .wiz-recap-row { padding: 4px 10px; }
  .wiz-page .wiz-recap-row span, .wiz-page .wiz-recap-row b { font-size: 0.74rem; }
  /* The two that still ran over at this height: fourteen activities, and the
     flying-from screen's button, its "or…" line and its two dropdowns. */
  .wiz-page .wiz-choices.acts { gap: 4px; }
  .wiz-page .wiz-choices.acts .wiz-chip { padding: 4px 22px 4px 6px; gap: 6px; }
  .wiz-page .wiz-choices.acts .wiz-chip-text strong { font-size: 0.72rem; }
  .wiz-page .wiz-or { margin: 7px 0; font-size: 0.8rem; }
  .wiz-page .wiz-domestic { padding: 9px 12px; }
  .wiz-page .wiz-selects { gap: 9px; }
  .wiz-page .wiz-note { margin-top: 8px; font-size: 0.8rem; }
}

/* ---------- Results as pages ---------- */
/* The long scroll became a short deck: tabs say what the pages are, the pager
   at the foot turns them, and the map keeps its half of the screen throughout. */
.rp-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 20px 0 22px; }
.rp-tab {
  font: inherit; font-weight: 800; font-size: 0.86rem; cursor: pointer;
  padding: 8px 16px; border-radius: var(--r-pill);
  background: var(--surface); color: var(--muted); border: 1.5px solid var(--line);
  transition: all 0.15s ease;
}
.rp-tab:hover { border-color: var(--brand); color: var(--ink); }
.rp-tab.on { background: var(--brand); border-color: var(--brand); color: var(--cream); }

.rp-pager {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 30px; padding-top: 18px; border-top: 1px solid var(--border);
}
.rp-pager-count { flex: none; font-size: 0.8rem; font-weight: 800; color: var(--muted); }

/* The day-by-day in the overview's right column: scrolls inside its card on
   tall trips, so the page itself stays one screen. */
.rp-itin-col .itinerary { max-height: 76vh; overflow-y: auto; }
@media (max-width: 900px) { .rp-itin-col .itinerary { max-height: none; } }

/* The score bars, two abreast now the card has the panel's full width */
.score-grid.cols-2 {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px 34px;
  max-width: none; margin: 0 0 16px;
}
@media (max-width: 720px) { .score-grid.cols-2 { grid-template-columns: 1fr; } }

/* The painted activity icons: big enough to read as pictures, like the sheet
   they were sliced from, and the grid loosens up to give them room. */
.wiz-ico .act-art, .act-art { width: 52px; height: 52px; object-fit: contain; display: block; }
/* The passport flags are landscape, and near their cut size so they stay crisp */
.wiz-ico .quiz-art.flag { width: 46px; height: 34px; }
.wiz-choices.acts { grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr)); }
.wiz-choices.acts .wiz-chip { padding: 14px 16px; gap: 14px; }
/* The paintings stay the size they were painted, phone or desktop — they were
   being shrunk to 42px to buy back vertical room, which is exactly the job the
   one-screen layout above now does properly. */
@media (max-width: 560px) {
  .wiz-choices.acts { grid-template-columns: 1fr 1fr; }
}

/* ---------- Front door: two explainer screens before the country picker ----------
   In the manner of komoot's homepage — copy on one side, a playful collage on
   the other, one full screen each. Every collage piece floats gently; the float
   keyframe re-states the piece's tilt via --tilt because transform is one
   property, and a translateY-only keyframe would wipe the rotation out. */
/* Sized by what's in them, not by the screen. Each of these was a full 100svh
   with its content centred, which on anything taller than the copy — every
   desktop, and the phone too once the collage was fixed — left a third of the
   section as empty cream above and below. The padding still gives each screen
   its own air; it just no longer pads out to a height nothing needs. */
.front {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: clamp(52px, 7vh, 84px) clamp(22px, 6vw, 84px) clamp(52px, 7vh, 84px);
}
/* The first screen keeps a little more, so the scroll cue has somewhere to sit
   below the copy rather than on top of it. */
.front-hero { padding-bottom: clamp(84px, 11vh, 116px); }
.front-grid {
  width: 100%; max-width: 1180px;
  display: grid; grid-template-columns: 1.02fr 0.98fr; align-items: center;
  gap: clamp(40px, 6vw, 92px);
}
.front-grid.rev { grid-template-columns: 0.98fr 1.02fr; }

/* The primary lockup, per the brand sheet: peach pin, lowercase, ko in sage */
.front-wordmark {
  display: flex; align-items: center; margin-bottom: 16px;
  font-family: var(--font-display); font-weight: 800; font-size: 1.3rem;
  color: var(--muted); letter-spacing: 0.01em;
}
.front-wordmark b { color: var(--brand); }
.front-wordmark .front-pin { width: 24px; height: 24px; margin-right: 5px; color: var(--gold); stroke-width: 2.4; }

.front-title {
  font-size: clamp(2.5rem, 5.2vw, 4.3rem); line-height: 1.04;
  letter-spacing: -0.015em; color: var(--ink);
}
/* No nowrap here. The coloured half is a whole sentence now rather than the two
   words it used to be, and refusing to break it made its typeset width the
   minimum the grid track had to honour — which on a 320px phone pushed the
   entire column of copy past the right-hand edge. Left to wrap it still falls
   as the two lines it's written as on anything from a 375px phone up, and
   simply takes a third line on the narrowest screens instead of overflowing. */
.front-title span { color: var(--brand); }
.front-title.sm { font-size: clamp(2rem, 3.8vw, 3.1rem); }
.front-sub { max-width: 33rem; margin: 20px 0 30px; font-size: 1.08rem; color: var(--muted); }
.front-eyebrow {
  font-family: var(--font-display); font-weight: 800; text-transform: uppercase;
  letter-spacing: 0.28em; font-size: 0.8rem; color: var(--brand-dark); margin-bottom: 10px;
}
.front-cta { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.front-or { color: var(--muted); font-weight: 600; }
/* the text link reaches a 44px tap target on touch, not a 30px sliver */
.front-cta .cine-link { display: inline-block; padding: 8px 2px; }

/* The collage frame: pieces are laid out in % of it, so the whole arrangement
   scales as one picture */
.front-art { position: relative; aspect-ratio: 10 / 9; width: 100%; max-width: 560px; justify-self: center; }

@keyframes frontFloat {
  0%, 100% { transform: rotate(var(--tilt, 0deg)) translateY(0); }
  50%      { transform: rotate(var(--tilt, 0deg)) translateY(-9px); }
}

/* A photograph of Kobo, printed and tossed on the table */
.front-photo {
  position: absolute; top: 2%; left: 10%; width: 52%; z-index: 2;
  background: #fff; padding: 3.5% 3.5% 9%; border-radius: 10px;
  box-shadow: var(--shadow-lg);
  --tilt: -4deg; animation: frontFloat 7s ease-in-out infinite;
}
.front-photo img { width: 100%; display: block; border-radius: 6px; }

/* The map card, with the route drawing itself from A to B on arrival */
.front-map {
  position: absolute; right: 0; bottom: 4%; width: 62%; z-index: 1;
  --tilt: 3deg; animation: frontFloat 8s 0.8s ease-in-out infinite;
  filter: drop-shadow(0 16px 34px rgba(92, 74, 62, 0.18));
}
.front-map svg {
  width: 100%; height: auto; display: block;
  border-radius: 22px; border: 6px solid #fff; background: var(--mint-pale);
}
.route-path {
  stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: routeDraw 1.8s 0.9s cubic-bezier(0.5, 0, 0.3, 1) forwards;
}
@keyframes routeDraw { to { stroke-dashoffset: 0; } }
.route-a, .route-a-label {
  transform-box: fill-box; transform-origin: center;
  opacity: 0; transform: scale(0.3);
  animation: markerPop 0.4s 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
.route-b {
  position: absolute; top: -7%; right: 9%;
  width: 42px; height: 42px; border-radius: 50%;
  background: var(--gold); color: #fff;
  font-family: var(--font-display); font-weight: 800; font-size: 1.15rem;
  display: flex; align-items: center; justify-content: center;
  border: 3px solid #fff; box-shadow: var(--shadow);
  opacity: 0; transform: scale(0.3);
  animation: markerPop 0.45s 2.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes markerPop { to { opacity: 1; transform: scale(1); } }

/* Hand-lettered place tags, in the sheet's sticker spirit */
.front-tag {
  position: absolute; z-index: 3;
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--cream); border: 2.5px solid var(--ink); border-radius: var(--r-pill);
  padding: 9px 20px;
  font-family: var(--font-display); font-weight: 800;
  letter-spacing: 0.12em; text-transform: uppercase; font-size: 0.82rem;
  box-shadow: 3px 4px 0 rgba(93, 74, 53, 0.16);
}
.front-tag .cico { width: 19px; height: 19px; color: var(--brand-dark); }
.tag-1 { top: -3%; right: 3%; --tilt: 2deg; animation: frontFloat 6s 0.4s ease-in-out infinite; }
.tag-2 { left: -2%; bottom: 27%; --tilt: -3deg; animation: frontFloat 6.5s 1.2s ease-in-out infinite; }

/* Doodles, including the brand sheet's own: a heart that flies off as a plane */
.doodle { position: absolute; z-index: 3; }
.doodle-waves { width: 88px; top: 5%; left: -3%; }
.doodle-flight { width: 158px; left: 4%; bottom: -1%; }
.doodle-burst { width: 74px; right: 3%; top: 0; transform: rotate(16deg); }
.flight-trail { animation: trailMarch 1.4s linear infinite; }
@keyframes trailMarch { to { stroke-dashoffset: -10; } }
.flight-plane {
  transform-box: fill-box; transform-origin: center;
  animation: planeBob 3s ease-in-out infinite;
}
@keyframes planeBob {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  50%      { transform: translate(3px, -5px) rotate(4deg); }
}

/* Screen two: the product's promise as two mock cards and the explorer Kobo */
.mock-card {
  position: absolute; z-index: 2;
  background: var(--surface); border: 1.5px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg); padding: 20px 22px;
}
.mock-wishlist { top: 5%; left: 5%; width: 58%; --tilt: -2.5deg; animation: frontFloat 7.5s ease-in-out infinite; }
.mock-wishlist > b { font-size: 1rem; }
.mock-wishlist ul { list-style: none; margin-top: 12px; display: grid; gap: 11px; }
.mock-wishlist li { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 0.92rem; }
.mock-wishlist .cico { width: 20px; height: 20px; flex: none; color: var(--brand-dark); }
.mock-tick {
  width: 21px; height: 21px; flex: none; border-radius: 50%;
  background: var(--brand); color: #fff; font-style: normal; font-weight: 800; font-size: 0.7rem;
  display: flex; align-items: center; justify-content: center;
}
.mock-match { right: 0; bottom: 13%; width: 57%; z-index: 3; --tilt: 2deg; animation: frontFloat 8s 1s ease-in-out infinite; }
.mock-eyebrow {
  display: block; font-weight: 800; text-transform: uppercase;
  letter-spacing: 0.14em; font-size: 0.68rem; color: var(--muted);
}
.mock-match > b { display: block; font-size: 1.25rem; line-height: 1.2; margin-top: 2px; }
.mock-meter { height: 10px; border-radius: var(--r-pill); background: var(--sunk); margin: 12px 0 8px; overflow: hidden; }
.mock-meter i {
  display: block; height: 100%; border-radius: inherit;
  background: linear-gradient(90deg, var(--brand), var(--mint));
  transform: scaleX(0); transform-origin: left;
  transition: transform 1.1s 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.front-art.in .mock-meter i { transform: scaleX(1); }
.mock-match small { color: var(--muted); font-size: 0.85rem; }
.mock-match small b { color: var(--ink); }
/* Kobo strides through the empty lower-left corner, clear of both cards'
   text — overlapping the match card hid the very numbers it exists to show */
.front-kobo { position: absolute; left: 2%; bottom: 0; width: 33%; z-index: 4; animation: koboBob 4s ease-in-out infinite; }

/* The three steps, beside the collage rather than under it */
.front-steps { list-style: none; display: grid; gap: 18px; margin: 26px 0 30px; }
.front-steps li { display: flex; gap: 16px; align-items: flex-start; }
.front-steps .spot { width: 56px; height: 56px; flex: none; }
.front-steps strong { display: block; font-size: 1.02rem; }
.front-steps small { color: var(--muted); line-height: 1.5; }

/* The nudge that there is more below the first screen */
.front-scroll {
  position: absolute; left: 50%; bottom: 24px; z-index: 5;
  width: 46px; height: 46px; border-radius: 50%; cursor: pointer;
  font-size: 1.15rem; line-height: 1; color: var(--ink);
  background: var(--cream); border: 1.5px solid var(--line); box-shadow: var(--shadow);
  animation: cueBounce 2.2s ease-in-out infinite;
}
.front-scroll:hover { background: var(--mint-soft); border-color: var(--brand); }
@keyframes cueBounce {
  0%, 100% { transform: translate(-50%, 0); }
  50%      { transform: translate(-50%, 7px); }
}

@media (max-width: 900px) {
  /* Tighter still in one column, and the first screen gives back the extra it
     was holding for the scroll cue — which is hidden at this width anyway, so
     all it bought was a band of cream between the collage and the next line. */
  .front, .front-hero { padding-top: 44px; padding-bottom: 44px; }
  .front-grid, .front-grid.rev { grid-template-columns: 1fr; gap: 34px; }
  /* copy first on a phone, both screens — the collage is the garnish */
  .front-grid.rev .front-art { order: 2; }
  .front-art { max-width: 460px; }
  .front-scroll { display: none; }

  /* The collage pins its pieces at percentages of the frame, which scales the
     arrangement but not the words inside the cards. In one column the frame
     loses a third of its width while "Arashiyama bamboo" stays the size it
     was, so the cards grow past their slots and end up sitting on top of each
     other — the wishlist unreadable under the score. Here they come off their
     pins and simply stack, keeping their tilts and their left/right offsets so
     it still reads as three things dropped on a table rather than a list. */
  .front-how .front-art { aspect-ratio: auto; display: grid; padding-top: 40px; }
  .front-how .mock-card { position: static; width: 86%; }
  .front-how .mock-wishlist { justify-self: start; }
  .front-how .mock-match { justify-self: end; margin-top: 14px; }
  .front-how .front-kobo { position: static; width: 38%; max-width: 148px; margin: 6px 0 0 4%; }
  .front-how .doodle-burst { top: 0; right: 2%; width: 56px; }

  /* In one column every copy block is the full width of the phone, so a
     left-hung eyebrow, heading and paragraph read as three things pushed to
     one side of an empty half. They centre instead — heading, line under it
     and the button below. The three numbered steps keep their icon-then-text
     rows: they are a list, and centring a wrapped paragraph beside a fixed
     icon only makes it harder to read. */
  .front-copy { text-align: center; }
  .front-wordmark, .front-cta { justify-content: center; }
  .front-sub { margin-left: auto; margin-right: auto; }
  .front-steps li { text-align: left; }
  .cine-pick { margin-left: auto; margin-right: auto; }
  .cine-pick-row { justify-content: center; }
  .cine-pick-row .country-group-label { text-align: center; }
  .cine-pick-row .country-group-row { justify-content: center; }
}

/* Phone size proper: everything one notch down again. The 900px rules solve
   the one-column layout; these solve the scale — at 390px the desktop-clamped
   titles, 56px step icons and full-width art each read as "massive" on their
   own, and stacked they were the whole page. */
@media (max-width: 600px) {
  .front, .front-hero { padding-top: 36px; padding-bottom: 36px; }
  .front-title { font-size: 2.1rem; }
  .front-title.sm { font-size: 1.6rem; }
  .front-sub { font-size: 0.96rem; margin: 14px 0 22px; }
  .front-eyebrow { font-size: 0.72rem; }
  .front-grid, .front-grid.rev { gap: 26px; }
  .front-steps { gap: 13px; margin: 20px 0 24px; }
  .front-steps .spot { width: 42px; height: 42px; }
  .front-art { max-width: 380px; }
  .pick-art { max-width: 300px; }
  .front-tag { padding: 7px 14px; font-size: 0.72rem; border-width: 2px; }
  .front-tag .cico { width: 16px; height: 16px; }
  .doodle-flight { width: 110px; }
  .doodle-waves { width: 64px; }
  .mock-card { padding: 15px 17px; }
  .mock-match > b { font-size: 1.1rem; }
  .front-how .front-kobo { max-width: 110px; }
}

@media (prefers-reduced-motion: reduce) {
  .front-photo, .front-map, .front-tag, .mock-card, .front-kobo,
  .flight-trail, .flight-plane, .front-scroll { animation: none; }
  .route-path { animation: none; stroke-dashoffset: 0; }
  .route-a, .route-a-label, .route-b { animation: none; opacity: 1; transform: none; }
  .mock-meter i { transition: none; transform: scaleX(1); }
}

/* On a phone the trip's chips, its actions and its tabs each become one
   thumb-swipe row, bled to the screen edges — left to wrap, they stacked four
   rows of pills between the top of the screen and the actual answer. */
@media (max-width: 600px) {
  .filter-row, .rp-head-actions, .rp-tabs {
    flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    margin-left: -20px; margin-right: -20px;
    padding-left: 20px; padding-right: 20px;
  }
  .filter-row::-webkit-scrollbar, .rp-head-actions::-webkit-scrollbar,
  .rp-tabs::-webkit-scrollbar { display: none; }
  /* A nowrap row shrinks its items to min-content — buttons folding their own
     labels into towers. They keep their size; the row is what scrolls. */
  .filter-row > *, .rp-head-actions > *, .rp-after-save > *, .rp-tabs > * {
    flex: none; white-space: nowrap;
  }
  .rp-head { gap: 10px; margin-bottom: 16px; }
  .rp-head-side { gap: 8px; }
  .rp-tabs { margin: 12px -20px 14px; }
}
