@charset "utf-8";
/* ══════════════════════════════════════════════════════════════════════════
   TRIPFIZZ HOLIDAYS — "NIGHT FLIGHT"

   The subcontinent seen from altitude at the hour the light goes.

   The brand's wings are about lift; this site is about what lift reveals. So:
   a dark world, photography as the only real light source, and chrome that
   floats above the imagery the way a cabin window floats over the ground.

   Three laws, and everything below follows from them.

     1. PHOTOGRAPHY IS THE LIGHT. The page is dark so the pictures can be the
        bright thing. Images run to the edge by default — a boxed photograph
        is a wasted photograph. Where type must sit on one, it gets a
        DIRECTIONAL gradient from the type's side only, never a flat scrim
        across the whole frame.
     2. CHROME IS GLASS. Floating surfaces are translucent, blurred and
        hairline-edged, and they let the image behind them through. They never
        resolve into opaque grey cards.
     3. NOTHING FLOATS WITHOUT REASON. Elevation encodes interactivity. Flat
        is content; lifted and glowing means you can act on it.

   Two structural notes:

   Four steps of night, not one flat black. A single tinted near-black is one
   of the commonest generated-design tells, and layered navies give depth
   without leaning on drop shadows.

   Spacing is non-linear (~x1.55) and the section rhythm is deliberately
   uneven. Even spacing everywhere is precisely what makes a page feel like it
   came out of a CMS.

   Layout convention, so two class families never fight over the same box:
       .band   owns padding-block   (vertical rhythm)   — and nothing else
       .shell  owns max-width + padding-inline           — and nothing else
   ══════════════════════════════════════════════════════════════════════════ */

/* ─── 1. TOKENS ─────────────────────────────────────────────────────────── */
:root {
  /* Ground — four steps of night */
  --void:   #04070F;
  --night:  #080D1A;
  --slate:  #0E1730;
  --steel:  #16223F;

  /* The logo, unchanged. These are the brand. */
  --royal:  #2376B3;
  --azure:  #12C4F0;
  --sky:    #5FE0FF;
  --ice:    #C9F6FF;

  /* Light world — used for a deliberate few sections, never as the default */
  --paper:  #F7F8FA;
  --ink:    #0A1428;

  /* The counterweight. An all-blue dark site reads as a fintech dashboard;
     India is warm. This appears on the end of a route, the active state and
     the signature flag — under 1% of pixels. */
  --ember:  #E8A33C;
  --dawn:   #F4C89A;

  /* Type on dark */
  --on-dark:        #EAF1FB;
  --on-dark-soft:   #9FB3D0;
  --on-dark-faint:  #64789A;
  --rule-dark:      #1B2942;

  /* Type on light */
  --on-light:       #0A1428;
  --on-light-soft:  #40536F;
  --on-light-faint: #74879F;
  --rule-light:     #DFE5EE;

  /* Live surface aliases. Sections flip these two lines and every component
     inside re-skins itself — the same trick the whole system rests on. */
  --fg:        var(--on-dark);
  --fg-soft:   var(--on-dark-soft);
  --fg-faint:  var(--on-dark-faint);
  --rule:      var(--rule-dark);
  --bg:        var(--void);

  /* Type */
  --display: "Fraunces", "Iowan Old Style", Georgia, serif;
  --text: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  /* Fraunces hairlines go fragile on dark, so SOFT is pushed up there and
     pulled back on light. Set per-surface, read by every display class. */
  --soft: 34;

  --t-xs:   0.75rem;
  --t-sm:   0.875rem;
  --t-base: 1.0625rem;
  --t-md:   1.25rem;
  --t-lg:   clamp(1.375rem, 1.1rem  + 1.2vw,  1.875rem);
  --t-xl:   clamp(1.75rem,  1.2rem  + 2.4vw,  2.75rem);
  --d-sm:   clamp(1.75rem,  1.25rem + 2.2vw,  2.75rem);
  --d-md:   clamp(2.5rem,   1.5rem  + 4.2vw,  4.5rem);
  --d-lg:   clamp(2.9rem,   1.8rem  + 5.6vw,  7rem);
  --d-xl:   clamp(4rem,     2rem    + 10vw,   11rem);

  /* Space — non-linear, roughly x1.55 */
  --s1: 4px;   --s2: 8px;    --s3: 12px;  --s4: 18px;
  --s5: 28px;  --s6: 44px;   --s7: 68px;  --s8: 104px;
  --s9: 160px; --s10: 248px;

  --shell: 1440px;
  --gutter: clamp(20px, 5vw, 80px);

  --r-sm: 6px;
  --r-md: 14px;
  --r-lg: 26px;
  --r-pill: 999px;

  --ease:  cubic-bezier(.2, .8, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --dur: 220ms;

  color-scheme: dark;
}

/* Sections that flip to the light world reassign the aliases. Everything
   inside — buttons, rules, cards, route diagrams — follows without knowing. */
.on-light {
  --fg: var(--on-light);
  --fg-soft: var(--on-light-soft);
  --fg-faint: var(--on-light-faint);
  --rule: var(--rule-light);
  --bg: var(--paper);
  --soft: 18;
  background: var(--paper);
  color: var(--on-light);
}

/* ─── 2. RESET ──────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 96px;
  background: var(--void);
}

body {
  margin: 0;
  background: var(--void);
  color: var(--fg);
  font-family: var(--text);
  font-size: var(--t-base);
  line-height: 1.65;
  /* Light-on-dark optically bolds, so the resting weight is under 400 and the
     tracking is opened a hair. */
  font-variation-settings: "wdth" 100, "wght" 350;
  letter-spacing: 0.006em;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

.on-light { letter-spacing: 0; }
.on-light :is(p, li) { font-variation-settings: "wdth" 100, "wght" 400; }

img, svg, video, canvas { display: block; max-width: 100%; }
img { height: auto; }

/* app.js filters the journey index by setting `hidden` on each .jcard. An
   author `display` declaration beats the browser's own [hidden]{display:none},
   and .jcard sets display:block — so without this line a filtered-out card
   stays on screen and the whole filter bar looks broken. */
[hidden] { display: none !important; }

h1, h2, h3, h4 { margin: 0; font-weight: 400; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--azure);
  outline-offset: 3px;
  border-radius: 3px;
}

::selection { background: color-mix(in oklab, var(--azure) 34%, transparent); color: #fff; }

/* Numbers that mean a quantity line up. This is why the system carries no
   monospace face — Archivo's tabular figures do that job. */
.num, .price, .daynum, .stat-v, time, .jfacts dd { font-variant-numeric: tabular-nums; }

/* ─── 3. GRAIN ──────────────────────────────────────────────────────────── */
/* 2% monochrome noise over the dark ground. Kills gradient banding across
   large navy fields and gives the whole thing a filmic surface. One inline
   SVG — no image request. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: .028;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ─── 4. LAYOUT PRIMITIVES ──────────────────────────────────────────────── */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.shell--tight  { max-width: 1140px; }
.shell--read   { max-width: 780px; }

.band { padding-block: clamp(88px, 11vh, 200px); position: relative; }
.band--tight  { padding-block: clamp(44px, 5vh, 76px); }

/* The breath. Used two or three times a page to let the eye rest — this is
   what breaks the metronome of equal sections. */
.band--breathe { padding-block: clamp(160px, 20vh, 320px); }

.band--night { background: var(--night); }
.band--slate { background: var(--slate); }

/* Editorial ratios. Never 6/6 — equal splits are static and read as template. */
.cols     { display: grid; gap: clamp(32px, 5vw, 96px); align-items: center; }
.cols--75 { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
.cols--57 { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
.cols--84 { grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); }
.cols--48 { grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); }
.cols--top { align-items: start; }

@media (max-width: 900px) {
  .cols { grid-template-columns: minmax(0, 1fr) !important; gap: var(--s6); }
}

/* Offset — content breaks the container on ONE side only. Sections alternate
   which side, which is what gives the page vertical rhythm without repeating
   a layout. */
.bleed-r { margin-right: calc(-1 * var(--gutter)); }
.bleed-l { margin-left: calc(-1 * var(--gutter)); }
@media (min-width: 1441px) {
  .bleed-r { margin-right: calc((100vw - var(--shell)) / -2 - var(--gutter)); }
  .bleed-l { margin-left: calc((100vw - var(--shell)) / -2 - var(--gutter)); }
}
.bleed-full { width: 100vw; margin-left: calc(50% - 50vw); }

/* The signature composition. Adjacent sections overlap, with the upper element
   lifting over the lower on glass. This is what stops a long page reading as a
   stack of bands. */
.lift { position: relative; z-index: 2; margin-top: clamp(-140px, -9vw, -80px); }
@media (max-width: 900px) { .lift { margin-top: calc(-1 * var(--s6)); } }

.stack > * + * { margin-top: var(--s4); }
.stack--lg > * + * { margin-top: var(--s6); }
.stack--xl > * + * { margin-top: var(--s7); }
.stack--sm > * + * { margin-top: var(--s2); }

hr, .rule { height: 1px; background: var(--rule); border: 0; margin: 0; }

/* ─── 5. TYPE ───────────────────────────────────────────────────────────── */
.display, .h1, .h2, .h3 {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.028em;
}

.display {
  font-size: var(--d-lg);
  font-variation-settings: "opsz" 144, "SOFT" var(--soft), "WONK" 1;
  line-height: 0.92;
  letter-spacing: -0.038em;
}
/* The one oversized moment per page. Used once, never twice. */
.display--xl { font-size: var(--d-xl); line-height: 0.88; letter-spacing: -0.045em; }

.h1 {
  font-size: var(--d-md);
  font-variation-settings: "opsz" 144, "SOFT" var(--soft), "WONK" 1;
  line-height: 0.96;
  letter-spacing: -0.034em;
}
.h2 {
  font-size: var(--d-sm);
  font-variation-settings: "opsz" 96, "SOFT" var(--soft), "WONK" 0;
  line-height: 1.04;
}
.h3 {
  font-size: var(--t-xl);
  font-variation-settings: "opsz" 48, "SOFT" var(--soft), "WONK" 0;
  line-height: 1.12;
  letter-spacing: -0.02em;
}
.h4 {
  font-family: var(--text);
  font-size: var(--t-md);
  font-variation-settings: "wght" 550;
  line-height: 1.32;
  letter-spacing: -0.01em;
}

.lede {
  font-size: var(--t-lg);
  line-height: 1.48;
  color: var(--fg-soft);
  max-width: 46ch;
  font-variation-settings: "wght" 300;
}

.prose { max-width: 58ch; }
.on-light .prose { max-width: 62ch; }
.prose > * + * { margin-top: 1.15em; }
.prose p { color: var(--fg-soft); }
.prose strong { color: var(--fg); font-variation-settings: "wght" 600; }

/* An italic Fraunces label in sentence case. Deliberately not a tracked
   ALL-CAPS eyebrow — those sit above every heading on every generated page. */
.label {
  font-family: var(--display);
  font-style: italic;
  font-size: var(--t-md);
  font-variation-settings: "opsz" 24, "SOFT" 40;
  color: var(--sky);
  line-height: 1.2;
}
.on-light .label { color: var(--royal); }

.meta { font-size: var(--t-sm); color: var(--fg-faint); line-height: 1.5; }
.muted { color: var(--fg-faint); }
.measure { max-width: 58ch; }

/* ─── 6. SURFACES ───────────────────────────────────────────────────────── */
/* Glass. The inset top highlight is what makes it read as glass rather than
   as a grey box — without it the whole effect collapses. */
.glass {
  background: color-mix(in oklab, var(--slate) 62%, transparent);
  backdrop-filter: blur(20px) saturate(1.4);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  border: 1px solid color-mix(in oklab, #fff 10%, transparent);
  border-radius: var(--r-lg);
  box-shadow:
    inset 0 1px 0 0 color-mix(in oklab, #fff 9%, transparent),
    0 24px 60px -20px rgb(0 0 0 / .7);
}

.glow {
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--azure) 40%, transparent),
    0 8px 40px -8px color-mix(in oklab, var(--azure) 45%, transparent);
}

/* ─── 7. PHOTOGRAPHY ────────────────────────────────────────────────────── */
.shot { position: relative; overflow: hidden; background: var(--slate); }
.shot > img { width: 100%; height: 100%; object-fit: cover; }
.shot--r  { border-radius: var(--r-lg); }
.shot--32 { aspect-ratio: 3 / 2; }
.shot--45 { aspect-ratio: 4 / 5; }
.shot--169{ aspect-ratio: 16 / 9; }
.shot--34 { aspect-ratio: 3 / 4; }

/* Directional scrim. Only from the side the type sits on, so the top two
   thirds of the photograph survive intact. Never a flat wash. */
.scrim-b::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    rgb(4 7 15 / .95) 0%,
    rgb(4 7 15 / .78) 26%,
    rgb(4 7 15 / .42) 50%,
    rgb(4 7 15 / .1) 74%,
    transparent 92%);
}
.scrim-l::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to right,
    rgb(4 7 15 / .88) 0%,
    rgb(4 7 15 / .45) 42%,
    transparent 74%);
}
.shot > .over { position: absolute; inset: auto 0 0 0; z-index: 2; padding: clamp(20px, 3vw, 40px); }

/* Gallery: a tall frame beside two shorter ones. Three identical boxes is
   what makes a grid read as a CMS; an uneven pair reads as art direction. */
.gal { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(14px, 1.6vw, 24px); }
.gal-col { display: grid; gap: clamp(14px, 1.6vw, 24px); align-content: stretch; }
.gal-col .shot { height: 100%; }
@media (max-width: 760px) { .gal { grid-template-columns: minmax(0, 1fr); } }

/* Parallax on imagery only, native CSS, no JS and no scroll listener. The
   single biggest "expensive" cue in the system and it costs nothing. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .par > img {
      animation: par linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
      will-change: transform;
    }
    @keyframes par {
      from { transform: translate3d(0, -6%, 0) scale(1.14); }
      to   { transform: translate3d(0, 6%, 0)  scale(1.14); }
    }
  }
}

/* ─── 8. HEADER ─────────────────────────────────────────────────────────── */
.hdr {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 200;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
  border-bottom: 1px solid transparent;
}
.hdr.is-stuck {
  background: color-mix(in oklab, var(--void) 82%, transparent);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  border-bottom-color: var(--rule-dark);
}
.hdr-in { display: flex; align-items: center; gap: var(--s6); height: 84px; }
.hdr-logo img { height: 50px; width: auto; }
/* The client's lockup is wide and its wordmark small inside it, so it needs
   more height than a compact mark would to read at nav-text size. */
@media (max-width: 1080px) { .hdr-logo img { height: 42px; } }

.nav { display: flex; align-items: center; gap: var(--s5); margin-left: auto; list-style: none; }
.nav a {
  font-size: var(--t-sm);
  color: var(--on-dark-soft);
  position: relative;
  padding-block: 8px;
  transition: color var(--dur) var(--ease);
}
.nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 2px;
  height: 1px;
  background: var(--azure);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 260ms var(--ease);
}
.nav a:hover { color: #fff; }
.nav a:hover::after, .nav a[aria-current="page"]::after { transform: scaleX(1); }
.nav a[aria-current="page"] { color: #fff; }

.burger {
  display: none;
  width: 46px; height: 46px;
  align-items: center; justify-content: center;
  border: 1px solid color-mix(in oklab, #fff 16%, transparent);
  border-radius: var(--r-pill);
  background: color-mix(in oklab, var(--slate) 50%, transparent);
  backdrop-filter: blur(12px);
  cursor: pointer;
}
.burger span { display: block; width: 16px; height: 1.25px; background: currentColor; position: relative; }
.burger span::before, .burger span::after {
  content: ""; position: absolute; left: 0; width: 16px; height: 1.25px; background: currentColor;
}
.burger span::before { top: -5px; }
.burger span::after { top: 5px; }

@media (max-width: 1080px) {
  .nav, .nav-tail .btn { display: none; }
  .burger { display: flex; margin-left: auto; }
  .hdr-in { height: 70px; }
}

.drawer {
  position: fixed; inset: 0; z-index: 300;
  background: color-mix(in oklab, var(--void) 96%, transparent);
  backdrop-filter: blur(28px);
  padding: 0 var(--gutter) var(--s8);
  overflow-y: auto;
  opacity: 0; visibility: hidden;
  transition: opacity 300ms var(--ease), visibility 300ms;
}
.drawer.is-open { opacity: 1; visibility: visible; }
.drawer-top { display: flex; align-items: center; justify-content: space-between; height: 70px; }
.drawer-nav { list-style: none; margin-top: var(--s6); }
.drawer-nav li + li { border-top: 1px solid var(--rule-dark); }
.drawer-nav a {
  display: flex; align-items: baseline; gap: var(--s3);
  padding: 20px 0;
  font-family: var(--display);
  font-size: clamp(2rem, 9vw, 3rem);
  font-variation-settings: "opsz" 96, "SOFT" 34;
  line-height: 1;
  letter-spacing: -0.03em;
}
.drawer-nav .n { font-family: var(--text); font-size: var(--t-xs); color: var(--sky); }

/* ─── 9. BUTTONS ────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s2);
  min-height: 52px;
  padding: 15px 30px;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-size: var(--t-sm);
  font-variation-settings: "wght" 560;
  letter-spacing: 0.01em;
  cursor: pointer;
  background: none;
  transition: transform 180ms var(--ease), background var(--dur) var(--ease),
              border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.btn:active { transform: translateY(1px); }

.btn--primary {
  background: linear-gradient(180deg, var(--royal), #1A5A8C);
  color: #fff;
  box-shadow: 0 8px 30px -8px color-mix(in oklab, var(--azure) 55%, transparent);
}
.btn--primary:hover {
  box-shadow: 0 12px 44px -8px color-mix(in oklab, var(--azure) 75%, transparent);
}

.btn--ghost {
  border-color: color-mix(in oklab, currentColor 26%, transparent);
  color: var(--fg);
}
.btn--ghost:hover {
  border-color: currentColor;
  background: color-mix(in oklab, currentColor 8%, transparent);
}

.btn--sm { min-height: 42px; padding: 10px 20px; font-size: var(--t-xs); }

/* A quiet text action. No trailing arrow — the "→ suffix" is a tell. */
.btn--quiet {
  min-height: 0; padding: 0 0 3px;
  border-radius: 0;
  color: var(--fg);
  border-bottom: 1px solid color-mix(in oklab, currentColor 34%, transparent);
}
.btn--quiet:hover { border-bottom-color: currentColor; }

.link {
  color: var(--sky);
  border-bottom: 1px solid color-mix(in oklab, var(--sky) 34%, transparent);
  transition: border-color var(--dur) var(--ease);
}
.link:hover { border-bottom-color: var(--sky); }
.on-light .link { color: var(--royal); border-bottom-color: color-mix(in oklab, var(--royal) 34%, transparent); }

/* ─── 10. ROUTE DIAGRAM ─────────────────────────────────────────────────── */
/* The icon system. Stops drawn as nodes on a rule — a diagram, not a string of
   place names joined with middots. An inbound operator's credibility comes
   from specificity, and this says "we know the road" where a suitcase icon
   says "template". */
.route {
  --node: 5px;
  display: flex; flex-wrap: wrap; row-gap: 10px;
  list-style: none;
  font-size: var(--t-sm);
  color: var(--fg-soft);
  line-height: 1.3;
}
.route > li { position: relative; padding: 0 var(--s4) 0 13px; white-space: nowrap; }
.route > li::before {
  content: "";
  position: absolute; left: 0; top: .52em;
  width: var(--node); height: var(--node);
  border-radius: 50%;
  background: var(--azure);
}
/* The connector spans only the gap AFTER the label. A rule drawn through a
   place name is a strikethrough, not a diagram. */
.route > li:not(:last-child)::after {
  content: "";
  position: absolute; right: 3px; width: 10px;
  top: calc(.52em + var(--node) / 2 - .5px);
  height: 1px;
  background: color-mix(in oklab, var(--fg) 26%, transparent);
}
.route > li:last-child::before {
  background: var(--ember);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--ember) 22%, transparent);
}
.route--sm { font-size: var(--t-xs); --node: 4px; }

/* ─── 11. JOURNEY CARD ──────────────────────────────────────────────────── */
/* Image-led and text-over-image, so there is no empty half. The whole card is
   one target with the title as its accessible name. */
.jcard {
  position: relative;
  display: block;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--slate);
  isolation: isolate;
  transition: transform 420ms var(--ease-out), box-shadow 420ms var(--ease-out);
}
.jcard::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  border: 1px solid color-mix(in oklab, #fff 9%, transparent);
  pointer-events: none;
  z-index: 3;
  transition: border-color var(--dur) var(--ease);
}
.jcard:hover { transform: translateY(-5px); box-shadow: 0 34px 70px -30px rgb(0 0 0 / .85); }
.jcard:hover::after { border-color: color-mix(in oklab, var(--azure) 44%, transparent); }

.jcard .shot { aspect-ratio: 4 / 5; }
.jcard .shot > img { transition: transform 900ms var(--ease-out); }
.jcard:hover .shot > img { transform: scale(1.05); }

.jcard-body { position: absolute; inset: auto 0 0 0; z-index: 2; padding: clamp(20px, 2.4vw, 32px); }
.jcard h3 {
  font-size: clamp(1.25rem, 1rem + .85vw, 1.7rem);
  color: #fff;
  letter-spacing: -0.024em;
  line-height: 1.06;
  max-width: 16ch;
}
.jcard .route { margin-top: var(--s3); color: color-mix(in oklab, #fff 78%, transparent); }
.jcard .route > li:not(:last-child)::after { background: color-mix(in oklab, #fff 34%, transparent); }

.jcard-foot {
  display: flex; align-items: baseline; gap: var(--s4);
  flex-wrap: wrap;
  margin-top: var(--s4);
  padding-top: var(--s3);
  border-top: 1px solid color-mix(in oklab, #fff 15%, transparent);
  font-size: var(--t-sm);
  color: color-mix(in oklab, #fff 72%, transparent);
}
.jcard-foot .price { color: #fff; font-variation-settings: "wght" 600; margin-left: auto; }
.jcard-foot .price small { font-variation-settings: "wght" 350; opacity: .66; }

/* The wide variant — one per row, used to break a grid's regularity. */
.jcard--wide { grid-column: 1 / -1; }
.jcard--wide .shot { aspect-ratio: 21 / 9; }
.jcard--wide h3 { font-size: clamp(1.55rem, 1.1rem + 1.6vw, 2.45rem); max-width: 20ch; }
.jcard--wide .jcard-body { max-width: 780px; }

@media (max-width: 700px) {
  .jcard .shot, .jcard--wide .shot { aspect-ratio: 4 / 5; }
  .jcard--wide h3 { font-size: var(--d-sm); max-width: none; }
}

.flag {
  display: inline-block;
  padding: 4px 12px 5px;
  border-radius: var(--r-pill);
  font-size: .7rem;
  font-variation-settings: "wght" 600;
  letter-spacing: .05em;
  background: color-mix(in oklab, var(--ember) 90%, #000);
  color: #1B1206;
}
.flag--new { background: var(--sky); color: #04142B; }

/* ─── 12. TILE ──────────────────────────────────────────────────────────── */
.tile {
  position: relative;
  display: block;
  border-radius: var(--r-md);
  overflow: hidden;
  isolation: isolate;
  transition: transform 420ms var(--ease-out);
}
.tile:hover { transform: translateY(-4px); }
.tile .shot { aspect-ratio: 3 / 4; }
.tile .shot > img { transition: transform 900ms var(--ease-out); }
.tile:hover .shot > img { transform: scale(1.06); }
.tile-body { position: absolute; inset: auto 0 0 0; z-index: 2; padding: var(--s4) var(--s4) var(--s5); }
.tile h3 {
  font-size: clamp(1.15rem, .95rem + .7vw, 1.55rem);
  color: #fff;
  letter-spacing: -0.018em;
  line-height: 1.12;
}
.tile .meta { color: color-mix(in oklab, #fff 70%, transparent); margin-top: 2px; }

/* ─── 13. STATS ─────────────────────────────────────────────────────────── */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s6) var(--s5); }
.stat { border-top: 1px solid var(--rule); padding-top: var(--s4); }
.stat-v {
  display: block;
  font-family: var(--display);
  font-size: clamp(2.5rem, 1.4rem + 4vw, 4.25rem);
  font-variation-settings: "opsz" 144, "SOFT" var(--soft), "WONK" 1;
  line-height: .9;
  letter-spacing: -.04em;
  background: linear-gradient(170deg, var(--ice), var(--azure) 72%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.on-light .stat-v { background: linear-gradient(170deg, var(--royal), var(--azure)); -webkit-background-clip: text; background-clip: text; }
.stat-l { font-size: var(--t-sm); color: var(--fg-faint); margin-top: var(--s3); }

/* ─── 14. QUOTE ─────────────────────────────────────────────────────────── */
.quote { display: flex; flex-direction: column; gap: var(--s5); height: 100%; padding: clamp(26px, 3vw, 44px); }
.quote blockquote {
  margin: 0;
  font-family: var(--display);
  font-size: clamp(1.0625rem, .95rem + .42vw, 1.3rem);
  font-variation-settings: "opsz" 30, "SOFT" 44, "WONK" 0;
  line-height: 1.5;
  letter-spacing: -.006em;
  color: var(--fg);
}
.quote-by { margin-top: auto; font-size: var(--t-sm); color: var(--fg-faint); }
.quote-by strong { display: block; color: var(--fg); font-variation-settings: "wght" 600; }

/* ─── 15. ITINERARY DAYS ────────────────────────────────────────────────── */
.days { list-style: none; }
.day {
  display: grid;
  grid-template-columns: minmax(0, 104px) minmax(0, 1fr);
  gap: clamp(18px, 3vw, 52px);
  padding-block: var(--s6);
  border-top: 1px solid var(--rule);
}
.daynum {
  font-family: var(--display);
  font-size: clamp(1.75rem, 1.2rem + 1.6vw, 2.75rem);
  font-variation-settings: "opsz" 96, "SOFT" var(--soft), "WONK" 1;
  color: var(--fg-faint);
  line-height: .9;
  letter-spacing: -.03em;
}
.daynum small { display: block; font-family: var(--text); font-size: var(--t-xs); margin-top: 8px; letter-spacing: .04em; }
.day-place { color: var(--sky); font-size: var(--t-sm); font-variation-settings: "wght" 560; margin-bottom: 4px; }
.day-body { color: var(--fg-soft); margin-top: var(--s3); max-width: 58ch; }
.day-foot { margin-top: var(--s4); font-size: var(--t-sm); color: var(--fg-faint); }

@media (max-width: 640px) {
  .day { grid-template-columns: minmax(0, 1fr); gap: var(--s2); }
  .daynum { display: flex; align-items: baseline; gap: var(--s3); font-size: var(--t-xl); }
  .daynum small { margin-top: 0; }
}

/* ─── 16. FACTS ─────────────────────────────────────────────────────────── */
.jfacts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: var(--s5);
  margin: 0;
}
.jfacts dt { font-size: var(--t-xs); color: var(--fg-faint); margin-bottom: 5px; }
.jfacts dd { margin: 0; font-size: var(--t-md); font-variation-settings: "wght" 500; color: var(--fg); }

/* ─── 17. TICKS ─────────────────────────────────────────────────────────── */
/* The mark is a short rule, not a tick glyph, so it sits in the same drawing
   language as the route diagram. */
.ticks { list-style: none; display: grid; gap: var(--s3); }
.ticks > li { position: relative; padding-left: 28px; color: var(--fg-soft); font-size: var(--t-sm); }
.ticks > li::before {
  content: ""; position: absolute; left: 0; top: .75em;
  width: 15px; height: 1px; background: var(--azure);
}
.ticks--off > li::before { width: 8px; background: var(--fg-faint); }
.plain { list-style: none; display: grid; gap: var(--s2); font-size: var(--t-sm); color: var(--fg-soft); }

/* ─── 18. STEPS ─────────────────────────────────────────────────────────── */
/* Numbered only because this content genuinely is a sequence. */
.steps { list-style: none; display: grid; gap: var(--s6); }
.steps > li {
  display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: var(--s5);
  align-items: start; padding-top: var(--s5); border-top: 1px solid var(--rule);
}
.steps-n {
  font-family: var(--display);
  font-size: var(--t-xl);
  font-variation-settings: "opsz" 72, "SOFT" var(--soft), "WONK" 1;
  color: var(--sky);
  line-height: .9;
}
@media (max-width: 560px) { .steps > li { grid-template-columns: minmax(0, 1fr); gap: var(--s2); } }

/* ─── 19. ACCORDION ─────────────────────────────────────────────────────── */
.acc { border-top: 1px solid var(--rule); }
.acc summary {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s5);
  padding: var(--s5) 0;
  cursor: pointer; list-style: none;
  font-size: var(--t-md);
  font-variation-settings: "wght" 480;
  transition: color var(--dur) var(--ease);
}
.acc summary::-webkit-details-marker { display: none; }
.acc summary:hover { color: var(--sky); }
.acc summary::after {
  content: ""; flex: none; width: 11px; height: 11px; margin-top: 9px;
  border-right: 1.25px solid currentColor; border-bottom: 1.25px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--dur) var(--ease);
}
.acc[open] summary::after { transform: rotate(-135deg); }
.acc-body { padding-bottom: var(--s5); color: var(--fg-soft); max-width: 62ch; }

/* ─── 20. FILTERS ───────────────────────────────────────────────────────── */
.chip {
  display: inline-flex; align-items: center;
  min-height: 44px;
  padding: 9px 18px;
  border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent);
  border-radius: var(--r-pill);
  font-size: var(--t-sm);
  color: var(--fg-soft);
  background: none;
  cursor: pointer;
  white-space: nowrap;
  transition: all var(--dur) var(--ease);
}
.chip:hover { color: var(--fg); border-color: color-mix(in oklab, var(--fg) 44%, transparent); }
.chip[aria-pressed="true"] {
  background: var(--fg); border-color: var(--fg);
  color: var(--bg);
}
.checks { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* ─── 21. FORMS ─────────────────────────────────────────────────────────── */
.form { display: grid; gap: var(--s5); }
.form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--s5); }
.field { display: grid; gap: 8px; }
.field > span { font-size: var(--t-sm); font-variation-settings: "wght" 500; }
.field > span em { font-style: normal; color: var(--fg-faint); font-variation-settings: "wght" 350; }
.field :is(input, select, textarea) {
  width: 100%;
  min-height: 52px;
  padding: 14px 17px;
  background: color-mix(in oklab, var(--void) 55%, transparent);
  border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent);
  border-radius: var(--r-sm);
  color: var(--fg);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.field :is(input, select, textarea)::placeholder { color: var(--fg-faint); }
.field :is(input, select, textarea):focus {
  outline: none;
  border-color: var(--azure);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--azure) 22%, transparent);
}
.field textarea { min-height: 140px; resize: vertical; }
.field-note { font-size: var(--t-xs); color: var(--fg-faint); }

.check { position: relative; }
.check input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.check span {
  display: inline-block; min-height: 44px; padding: 10px 18px;
  border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent);
  border-radius: var(--r-pill);
  font-size: var(--t-sm);
  transition: all var(--dur) var(--ease);
}
.check input:checked + span { background: var(--azure); border-color: var(--azure); color: #04142B; }
.check input:focus-visible + span { outline: 2px solid var(--azure); outline-offset: 2px; }

/* ─── 23. HERO ──────────────────────────────────────────────────────────── */
.hero {
  position: relative;
  min-height: min(100svh, 900px);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}
.hero-bg { position: absolute; inset: 0; z-index: 0; }
.hero-bg img { width: 100%; height: 100%; object-fit: cover; }
/* Three stacked gradients, each doing one job: seat the type at the bottom,
   keep the nav legible against a bright sky at the top, and pull the left
   edge down so the headline never fights the picture behind it. */
.hero-bg::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(to top, var(--void) 1%, rgb(4 7 15 / .82) 22%, rgb(4 7 15 / .34) 54%, transparent 76%),
    linear-gradient(to bottom, rgb(4 7 15 / .72) 0%, rgb(4 7 15 / .18) 16%, transparent 30%),
    linear-gradient(to right, rgb(4 7 15 / .66) 0%, rgb(4 7 15 / .2) 44%, transparent 70%);
}
/* The header is fixed and 84px tall, so the hero content needs real air under
   it — not just clearance. At 132px the label sat directly beneath the nav. */
.hero-in {
  position: relative; z-index: 2; width: 100%;
  padding-block: clamp(160px, 20vh, 232px) clamp(64px, 9vh, 120px);
}
.hero .label { margin-bottom: var(--s4); }
.hero .display { max-width: 15ch; }
.hero .lede { margin-top: var(--s5); max-width: 44ch; }
.hero-cta { display: flex; align-items: center; gap: var(--s5); flex-wrap: wrap; margin-top: var(--s6); }

/* No scroll cue. There was one — a hairline that drifted down and faded —
   and it was cut: the proposition panel already lifts over the bottom of the
   hero, so a slice of the next section is visible at every viewport height.
   That IS the affordance, and a second one was just noise on top of it. */


/* ─── 24. SECTION HEAD ──────────────────────────────────────────────────── */
.hd { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s5); flex-wrap: wrap; margin-bottom: var(--s7); }
.hd .h2 { max-width: 18ch; }
.hd .label + .h2 { margin-top: var(--s3); }

/* Sticky heading — holds while its content scrolls past, then releases. */
@media (min-width: 901px) {
  .hd--sticky { position: sticky; top: 120px; align-self: start; margin-bottom: 0; }
}

/* ─── 25. FOOTER ────────────────────────────────────────────────────────── */
.ftr {
  background: var(--night);
  border-top: 1px solid var(--rule-dark);
  padding-block: clamp(64px, 9vw, 160px) var(--s6);
}
/* A fixed first column beside repeat(auto-fit,...) collapses badly on the way
   down — the brand block squeezes while the link columns keep their width, and
   somewhere around 900px they overlap. Explicit breakpoints instead. */
.ftr-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) repeat(4, minmax(0, 1fr));
  gap: clamp(32px, 4vw, 72px);
}
@media (max-width: 1180px) {
  .ftr-grid { grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr)); row-gap: var(--s7); }
}
@media (max-width: 820px) {
  .ftr-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* The brand block spans the full width above the link columns rather than
     being squashed into a half it cannot fill. */
  .ftr-grid > :first-child { grid-column: 1 / -1; }
}
@media (max-width: 460px) {
  .ftr-grid { grid-template-columns: minmax(0, 1fr); gap: var(--s6); }
  .ftr-grid > div:not(:first-child) { border-top: 1px solid var(--rule-dark); padding-top: var(--s5); }
}
.ftr h4 { color: var(--on-dark); font-size: var(--t-sm); font-variation-settings: "wght" 600; margin-bottom: var(--s4); }
.ftr ul { list-style: none; display: grid; gap: 11px; font-size: var(--t-sm); }
.ftr a { color: var(--on-dark-soft); transition: color var(--dur) var(--ease); }
.ftr a:hover { color: #fff; }
.ftr-logo img { height: 58px; width: auto; margin-bottom: var(--s4); }
.ftr-btm {
  display: flex; flex-wrap: wrap; gap: var(--s3) var(--s5);
  justify-content: space-between;
  margin-top: clamp(44px, 6vw, 104px); padding-top: var(--s5);
  border-top: 1px solid var(--rule-dark);
  font-size: var(--t-xs); color: var(--on-dark-faint);
}
/* height:auto here let the logo scale to the full column width on a phone.
   The height is the constraint; the width follows it. */
.ftr-logo img { height: 58px; width: auto; max-width: 100%; }
@media (max-width: 460px) { .ftr-logo img { height: 46px; } }

/* ─── 26. GRIDS + UTILITIES ─────────────────────────────────────────────── */
.g2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); gap: clamp(20px, 2.4vw, 40px); }
.g3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: clamp(18px, 2vw, 32px); }

/* Quotes are set in the display face, so they need a far wider column than a
   generic card does — below about 340px they break to four words a line and
   read as a ransom note. Three across is the most this type will take. */
.quotes { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); gap: clamp(18px, 2vw, 32px); }
@media (min-width: 1100px) { .quotes { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.g4 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); gap: clamp(16px, 1.8vw, 28px); }

.row { display: flex; gap: var(--s4); flex-wrap: wrap; align-items: center; }
.row--between { justify-content: space-between; }

.sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.skip { position: absolute; left: var(--s4); top: -70px; z-index: 400; background: var(--azure); color: #04142B; padding: 14px 22px; border-radius: var(--r-pill); transition: top var(--dur) var(--ease); }
.skip:focus { top: var(--s4); }

/* The wing watermark. Appears once per page, behind the section that matters
   most — brand presence without a logo salad. */
.wing {
  position: absolute;
  inset: 50% auto auto 50%;
  translate: -50% -50%;
  width: min(88vw, 1180px);
  opacity: .05;
  z-index: 0;
  pointer-events: none;
  filter: blur(.4px);
}
.wing + * { position: relative; z-index: 1; }

/* ─── 27. MOTION ────────────────────────────────────────────────────────── */
/* Arrival: the hero composes itself once, then the page is still. Everything
   else in the system responds to something the visitor did. */
@keyframes rise { from { opacity: 0; transform: translate3d(0, 26px, 0); } to { opacity: 1; transform: none; } }
@keyframes settle { from { transform: scale(1.06); } to { transform: scale(1); } }

@media (prefers-reduced-motion: no-preference) {
  .hero-bg img { animation: settle 1.8s var(--ease-out) both; }
  .arrive > * { animation: rise .9s var(--ease-out) both; }
  .arrive > *:nth-child(1) { animation-delay: .10s; }
  .arrive > *:nth-child(2) { animation-delay: .18s; }
  .arrive > *:nth-child(3) { animation-delay: .26s; }
  .arrive > *:nth-child(4) { animation-delay: .34s; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

@view-transition { navigation: auto; }
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) { animation: vt-out 120ms var(--ease) both; }
  ::view-transition-new(root) { animation: vt-in 260ms var(--ease-out) both; }
}
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; } }

/* ─── 28. PRINT ─────────────────────────────────────────────────────────── */
/* Travellers print itineraries. They should get something readable. */
@media print {
  .hdr, .ftr, .burger, .drawer, .btn, body::after, .wing { display: none !important; }
  body, .band, .hero { background: #fff !important; color: #000 !important; }
  .band { padding-block: 12pt; }
  :is(h1, h2, h3, h4, .display, .h1, .h2, .h3, .lede, p, li) { color: #000 !important; }
  .day { break-inside: avoid; }
  .shot, .hero-bg { display: none; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }
}

/* ══════════════════════════════════════════════════════════════════════════
   29. SCROLL CHOREOGRAPHY

   Scroll-LINKED, not scroll-triggered. Nothing here fires an entrance when a
   section crosses a threshold — that is the fade-up-on-every-section pattern
   and it reads as generated. Instead the page is tied to scroll position, so
   movement is continuous, reversible, and feels like the page has depth
   rather than like it is performing.

   All native CSS scroll-driven animation: no listener, no observer, no jank,
   and it degrades to a still page where unsupported.
   ══════════════════════════════════════════════════════════════════════════ */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* Photographs settle as they arrive — the frame opens rather than the
       picture sliding in. Image treatment, not decoration. */
    .reveal {
      animation: reveal linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 78%;
    }
    @keyframes reveal {
      from { clip-path: inset(13% 7% 13% 7% round var(--r-lg)); opacity: .5; }
      to   { clip-path: inset(0 0 0 0 round var(--r-lg));       opacity: 1; }
    }

    /* Cards rise a few pixels and stop. Small enough to read as depth rather
       than as an effect. */
    .jcard, .tile {
      animation: lift-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 60%;
    }
    @keyframes lift-in {
      from { opacity: .3; transform: translate3d(0, 36px, 0); }
      to   { opacity: 1; transform: none; }
    }

    /* The sticky heading eases back as its content scrolls past, which marks
       the handover instead of it just vanishing. */
    .hd--sticky {
      animation: hold linear both;
      animation-timeline: view();
      animation-range: exit 0% exit 100%;
    }
    @keyframes hold { to { opacity: .22; transform: translate3d(0, -14px, 0); } }

    /* A hairline that draws itself down the day list as you read it. The one
       piece of scroll motion reporting progress rather than arrival. */
    .days::before {
      content: "";
      position: absolute;
      left: 0; top: 0; bottom: 0;
      width: 1px;
      background: linear-gradient(to bottom, var(--azure), color-mix(in oklab, var(--azure) 6%, transparent));
      transform-origin: top;
      animation: draw linear both;
      animation-timeline: view();
      animation-range: cover 6% cover 86%;
    }
    @keyframes draw { from { transform: scaleY(0); } to { transform: scaleY(1); } }
  }
}
.days { position: relative; }
@media (min-width: 641px) { .days { padding-left: var(--s5); } }

/* ══════════════════════════════════════════════════════════════════════════
   30. VISUAL RHYTHM

   A grid where every cell sits on the same baseline reads as a CMS dump. These
   rules break the metronome without breaking the grid: alternate cards drop
   half a step, and tiles take three different frame heights across a row.
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 901px) {
  .g3 > .jcard:nth-child(even),
  .g2 > .jcard:nth-child(3n) { transform: translateY(38px); }
  .g3 > .jcard:nth-child(even):hover,
  .g2 > .jcard:nth-child(3n):hover { transform: translateY(32px); }

  .g4 > .tile:nth-child(4n + 2) .shot { aspect-ratio: 3 / 4.6; }
  .g4 > .tile:nth-child(4n + 3) .shot { aspect-ratio: 3 / 3.5; }
}

/* ══════════════════════════════════════════════════════════════════════════
   31. MOBILE — RECOMPOSED, NOT STACKED

   Every section below is laid out differently on a phone, not merely narrowed.
   The desktop page is built from wide two-column relationships; a phone has no
   width to spend, so it gets depth and edge instead — photography goes fully
   edge-to-edge, glass loses its inset, meta moves inline, and the filter bar
   becomes one swipeable rail rather than four wrapped rows.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 700px) {

  /* Desktop breathing room is dead space on a screen you scroll with a thumb. */
  .band { padding-block: clamp(56px, 9vh, 84px); }
  .band--tight { padding-block: clamp(36px, 6vh, 56px); }
  .band--breathe { padding-block: clamp(72px, 12vh, 120px); }

  /* Section headings and their action stack rather than sharing a line. */
  .hd { flex-direction: column; align-items: flex-start; gap: var(--s4); margin-bottom: var(--s5); }

  /* Hero. The lede is the first thing to go: six lines of body copy under a
     display headline is a desktop habit. Three places the company and lets
     the photograph do the rest. */
  .hero { min-height: 100svh; }
  .hero-in { padding-block: clamp(128px, 17vh, 168px) var(--s7); }
  .hero .display { max-width: 12ch; }
  .hero .lede {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: var(--t-md);
    max-width: 34ch;
  }
  .hero-cta { gap: var(--s4); width: 100%; }
  .hero-cta .btn--primary { flex: 1 1 auto; }

  /* Photography runs to the screen edge. The gutter is a far bigger share of
     the width on a phone, so an inset photograph loses much more here than it
     does on a desktop — and a full-bleed one gains much more. */
  .g2, .g3, .g4 { gap: var(--s4); }
  .g2 > .jcard, .g3 > .jcard {
    width: 100vw;
    margin-left: calc(50% - 50vw);
    border-radius: 0;
  }
  .g2 > .jcard::after, .g3 > .jcard::after { border-inline: 0; border-radius: 0; }
  .jcard .shot, .jcard--wide .shot { aspect-ratio: 5 / 6; }
  .jcard-body { padding: var(--s5) var(--gutter) var(--s6); }
  .jcard h3, .jcard--wide h3 { font-size: 1.7rem; max-width: none; }

  /* Tiles go two-up. Three across is unreadable, one across wastes the scroll. */
  .g4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .g4 > .tile .shot { aspect-ratio: 3 / 4 !important; }
  .tile h3 { font-size: 1.05rem; }
  .tile-body { padding: var(--s3); }

  /* Glass loses its inset and most of its blur — a 20px backdrop-filter over a
     scrolling page is the single most expensive thing on the site for a
     mid-range Android. */
  .glass {
    border-radius: var(--r-md);
    backdrop-filter: blur(11px) saturate(1.2);
    -webkit-backdrop-filter: blur(11px) saturate(1.2);
  }
  .lift { margin-top: calc(-1 * var(--s5)); }

  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s5) var(--s4); }
  .stat-v { font-size: 2.5rem; }

  /* The filter bar becomes one swipeable rail. Wrapping twenty chips over four
     rows costs a third of the screen before a single journey is visible. */
  [data-filters] .checks {
    flex-wrap: nowrap;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
    padding-bottom: 2px;
  }
  [data-filters] .checks::-webkit-scrollbar { display: none; }
  [data-filters] .chip { scroll-snap-align: start; flex: none; }

  /* The route loses its connectors. CSS cannot tell which item is last on a
     WRAPPED line, so on a narrow screen the rule after the final stop of each
     line dangles into empty space and reads as broken. The nodes alone still
     say "sequence", and they say it cleanly. */
  .route > li:not(:last-child)::after { display: none; }
  .route > li { padding-right: var(--s3); }

  /* The day number stops being a column and becomes a badge on the line the
     eye is already reading. */
  .day { padding-block: var(--s5); }
  .daynum {
    font-family: var(--text);
    font-size: 1rem;
    font-variation-settings: "wght" 600;
    color: var(--sky);
    letter-spacing: .04em;
  }
  .daynum::before { content: "Day "; }
  /* Only draw the separator when there are meals to separate — an arrival day
     carries no meal codes and was rendering a dangling middot. */
  .daynum small:not(:empty)::before { content: " · "; }

  /* The progress hairline is drawn at the left edge of .days, and on a phone
     the day text starts there too. Indent the content rather than dropping the
     line: it is the only thing on the page reporting how far through an
     itinerary you have read. */
  .days { padding-left: var(--s4); }
  .day-body { font-size: var(--t-base); }

  .hd--sticky { position: static; }
  .quote { padding: var(--s5); }
  .gal { gap: var(--s3); }

  /* A full-width primary action reads as a button on a phone; an inline one
     reads as text a thumb will miss. */
  .band > .shell > .btn--primary,
  .band p > .btn--primary { width: 100%; }
}

@media (max-width: 380px) {
  .g4 { grid-template-columns: minmax(0, 1fr); }
  .stats { grid-template-columns: minmax(0, 1fr); }
  .hero .display { font-size: 2.6rem; }
}

/* Landscape phones: the hero must not demand a viewport height it cannot fill. */
@media (max-height: 540px) and (orientation: landscape) {
  .hero { min-height: 560px; }
  .hero-in { padding-block: 104px var(--s6); }
  .hero .lede { -webkit-line-clamp: 2; }
}
