/* =========================================================
   Bora Bora Bound — global styles
   Palette, typography and logo per the official brand guide
   (Drive: "BBB Brand Guidelines.pdf" / Canva brand kit "Bora Bora Bound").
   ========================================================= */

:root {
  /* --- Brand palette (exact values from the brand guide) --- */
  --purple:      #4622a2;   /* primary */
  --rose:        #d0356a;   /* secondary — primary CTA */
  --orange:      #f09839;   /* accent */
  --teal:        #4aa4a6;   /* supporting */
  --pink:        #f6cfee;   /* soft */
  --aqua:        #76efe1;   /* bright accent */

  /* --- Brand secondary neutrals --- */
  --black:       #000000;
  --ink:         #2b2b2b;
  --off-white:   #fdfefb;
  --grey:        #ababab;
  --grey-light:  #d9d9d9;

  /* --- Brand tints (Canva "Color palette" row) --- */
  --purple-soft: #6a4fb3;
  --rose-soft:   #e07a95;
  --aqua-soft:   #8edad3;
  --pink-soft:   #ead4e2;

  /* --- Derived, used for depth. Not new hues, just darker/lighter brand. --- */
  --purple-deep: #34197a;
  --purple-ink:  #1e0e46;
  --rose-deep:   #b02a59;
  --blush:       #f8f0f7;   /* very light tint of --pink, for section grounds */
  /* Three more of the same kind, added for the dark appearance. Still not new
     hues — the brand purple lifted and lightened. --purple-raised and
     --purple-veil are the "elevated" and "tinted" surfaces that sit above the
     --purple-ink page ground; --purple-light is the brand purple taken up far
     enough to be read as text on those grounds. */
  --purple-raised: #2b1560;
  --purple-veil:   #241150;
  --purple-light:  #c4b0ff;

  /* --- Semantic aliases. The rest of the sheet is written against these. ---
     Named for the ROLE each one plays, never for the colour it currently holds.
     These were previously nautical — --navy, --gold, --sand, --lagoon — mapped
     onto a purple/rose palette, so --gold painted pink and --navy painted
     purple. A name that states a hue is a name that goes stale the moment the
     palette moves, and it misleads whoever edits this sheet next. Role names
     stay true through a re-theme. tools/audit's token-truth detector fails the
     build if one of these ever starts lying again. */
  --ground-deep:   var(--purple-deep); /* dark section grounds and the footer */
  --brand:         var(--purple);      /* brand grounds and heading text */
  --link:          var(--purple);      /* links, focus rings, interactive text */
  /* --brand and --link deliberately hold the same purple today. They stay two
     names so either can move without dragging the other with it. */
  --accent-bright: var(--aqua);        /* bright accent on dark grounds */
  --cta:           var(--rose);        /* the primary call to action */
  --surface-tint:  var(--blush);       /* the tinted section ground */
  --paper:         var(--off-white);   /* card, panel and control surfaces — the raised plane */
  --ground:        var(--off-white);   /* the page itself — the plane everything sits on */
  /* --ground and --paper hold one colour in the light appearance and two in
     the dark one. Apple's dark palettes separate a base plane from an elevated
     one so a card reads as sitting above the page rather than merged into it;
     on paper a single off-white does that job by itself. */

  /* --brand is a GROUND. Heading text that happened to be the same purple was
     reading from it too, which is fine until the ground goes dark and the
     heading has to go light — one token cannot do both. */
  --heading:       var(--brand);       /* heading text */
  --link-contrast: #ffffff;            /* text and glyphs ON a --link fill */
  --ink-on-brand:  var(--blush);       /* text on the brand purple, which is a dark ground in BOTH appearances */
  --glass-tint:      #ffffff;          /* what the floating nav pill's material is made of */
  --glass-edge-tint: #ffffff;          /* the light catch along that pill's edge */
  --icon-tile:     linear-gradient(135deg, var(--aqua-soft), var(--blush)); /* the tile behind a feature card's glyph */
  --icon-tile-ink: var(--link);        /* the glyph drawn on that tile */
  --shadow-color:  30, 14, 70;         /* what a shadow is made of — brand ink on paper, true black on a dark ground */
  --muted:     #6b6b73;
  --line:      rgba(70, 34, 162, 0.14);

  /* --- Roles for a DARK ground. -------------------------------------------
     The greys above are tuned for paper. Reused on the footer's purple they
     measure 2.5:1, which is how the footer blurb came to be unreadable while
     --muted itself was fine everywhere else. Text on a dark ground takes
     these instead, and tools/audit/contrast.mjs fails the build if either
     side of that pairing stops holding WCAG AA. */
  --ink-on-dark:      #ffffff;                /* primary text on a dark ground */
  --ink-on-dark-soft: rgba(255, 255, 255, 0.88); /* the same, one step back — subtitles and ledes */
  --muted-on-dark: rgba(255, 255, 255, 0.7);  /* secondary text on a dark ground — 7.2:1 on --ground-deep */
  --line-on-dark:  rgba(255, 255, 255, 0.22); /* hairlines and outlines on a dark ground */

  /* A form control's boundary is the only thing that says the control is
     there, so WCAG 1.4.11 asks 3:1 of it. --line is a card outline at 1.3:1
     and cannot do that job. */
  --field-border:  var(--muted);       /* the edge of an input, select or textarea — 5.2:1 on paper */

  /* The keyboard focus ring. Two names because the site has both grounds and
     one ring cannot serve both: --link is 10.3:1 on paper and 1.3:1 on the
     footer. */
  --focus-ring:         var(--link);   /* focus outline on a light ground */
  --focus-ring-on-dark: #ffffff;       /* focus outline where the ground is dark */

  /* Type — Bebas Neue + Evolve Sans per the brand guide.
     Evolve Sans is a commercial face and is not on Google Fonts; Poppins is
     the closest geometric substitute. Swap the stack here if it gets licensed
     and self-hosted into assets/fonts/. */
  --display: "Bebas Neue", "Oswald", Impact, "Haettenschweiler", sans-serif;
  --serif:   var(--display);
  --sans:    "Poppins", "Evolve Sans", "Helvetica Neue", Arial, sans-serif;
  --script:  "Sacramento", "Great Vibes", "Brush Script MT", cursive;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* =========================================================
     CONTROL BLOCK — every measurement the homepage renders
     ---------------------------------------------------------
     LOCKED 24 August 2026. These numbers are the design, not a
     draft: treat them as fixed. Work that needs a measurement
     adds a new knob here rather than retuning a locked one, and
     a new element gets its own knob even when an existing value
     looks close. One change since the lock, the same day and at
     the author's request: three identical card-title knobs
     merged into one. No value moved.

     Change a number here, save, refresh. Nothing below this
     block carries a raw measurement for anything the homepage
     draws: frame, header, hero, trust strip, sections, cards,
     process, portrait split, quotes, CTA band, referral band,
     footer, buttons and motion.

     Inner-page-only components (forms, FAQ, contact cards,
     legal prose, journal cards, modal, stats, badges) still
     carry literal values further down — say the word and they
     get lifted too.

     Fluid type reads as clamp(MIN, BASE + VW, MAX): MIN is the
     phone size, MAX the size it stops growing at, BASE + VW the
     rate in between.
     ========================================================= */

  /* PAGE FRAME ---------------------------------------------------- */
  --maxw:                    1180px; /* how wide content gets before it stops growing */
  --page-pad-min:           1.25rem; /* side gutter on the narrowest phone */
  --page-pad-vw:                5vw; /* how fast the side gutter grows with the window */
  --page-pad-max:              3rem; /* widest the side gutter ever gets */

  /* BODY TYPE ----------------------------------------------------- */
  /* Apple's typography guidance is direct about this: avoid Ultralight, Thin
     and Light weights, which are hard to see, especially at small sizes. Every
     paragraph, form field and hero lede on this site was set in Poppins Light.
     Nothing about that shows up in a contrast ratio — the colours were already
     passing — which is exactly why it needed saying out loud. */
  --body-weight:                400; /* weight of body text, form fields and ledes */
  --body-size-min:             1rem; /* paragraph size on a phone */
  --body-size-base:         0.96rem; /* fixed part of the in-between paragraph size */
  --body-size-vw:             0.2vw; /* how fast paragraphs grow with the window */
  --body-size-max:         1.075rem; /* paragraph size once the window is wide */
  --body-leading:              1.65; /* line spacing in paragraphs — bigger = airier */
  --para-gap:                 1.1em; /* space under each paragraph */
  --heading-gap:              0.5em; /* space under a heading before its text */
  --heading-leading:           1.04; /* line spacing inside big headings — bigger = looser */
  --subhead-leading:           1.12; /* line spacing inside h3 / h4 */
  --heading-tracking:       0.015em; /* letter spacing in headings — bigger = wider caps */
  --h1-tracking:             0.01em; /* letter spacing in the page headline */
  --h3-tracking:             0.03em; /* letter spacing in small headings */
  --eyebrow-size:           0.72rem; /* the small label above a heading */
  --eyebrow-tracking:        0.18em; /* how spread out that small label reads */
  --eyebrow-gap:               1rem; /* space under the small label */

  /* FLOATING HEADER ----------------------------------------------- */
  --header-top:             0.85rem; /* how far the nav pill floats below the top */
  --header-top-scrolled:     0.6rem; /* where the pill settles once you scroll */
  --header-side-inset:       1.6rem; /* air between the pill and the window edges */
  --header-radius:             22px; /* corner rounding on the nav pill */
  --header-blur:               20px; /* how frosted the glass behind the nav is */
  --header-saturate:           180%; /* how much colour the frosted glass pulls through */
  --header-highlight-width:     1px; /* thickness of the light catch along the pill's edge */
  --header-border-width:        1px; /* hairline around the nav pill */
  --header-shadow-y:           12px; /* how far the nav pill's shadow drops */
  --header-shadow-blur:        36px; /* how soft that shadow is */
  --header-shadow-spread:     -16px; /* negative pulls the shadow in tighter */
  --header-shadow-y-scrolled:  14px; /* shadow drop once the pill is scrolled */
  --header-shadow-blur-scrolled: 32px; /* shadow softness once scrolled */
  --header-shadow-spread-scrolled: -14px; /* how tight that scrolled shadow sits */
  --nav-pad-y:              0.42rem; /* height of the pill above and below the links */
  --nav-pad-left:            1.2rem; /* space before the logo inside the pill */
  --nav-pad-right:           0.5rem; /* space after the pinned CTA inside the pill */
  --nav-gap:                 1.5rem; /* gap between logo, links and CTA */
  --nav-link-gap:            1.9rem; /* space between nav links */
  --nav-link-size:          0.82rem; /* nav link text size */
  --nav-link-tracking:       0.16em; /* how spread out the nav links read */
  --nav-underline-gap:          3px; /* drop from a nav link to its hover underline */
  --nav-underline-height:       2px; /* thickness of that underline */
  --nav-cta-gap:               1rem; /* space between the CTA and the links */
  --nav-cta-pad-y:           0.7rem; /* height of the pinned CTA at tight widths */
  --nav-cta-pad-x:           1.1rem; /* width of the pinned CTA at tight widths */
  --nav-cta-size:           0.74rem; /* its label size at tight widths */
  --brand-gap:               0.7rem; /* space between the logo mark and the wordmark */
  --brand-lockup-size:      1.15rem; /* text size the lockup's letter spacing is measured from */
  --brand-size:             1.22rem; /* wordmark size in the nav and footer */
  --brand-leading:             1.05; /* line spacing if the wordmark wraps */
  --brand-tracking:          0.05em; /* letter spacing in the wordmark */
  --brand-mark-width:          27px; /* logo mark width — the art is 240x373 */
  --brand-mark-height:         42px; /* logo mark height — keep the 0.64:1 ratio */
  --brand-sub-size:         0.72rem; /* the small line under the wordmark — footer only now; see below */
  --brand-sub-tracking:      0.12em; /* how spread out that small line reads */
  --brand-sub-gap:              2px; /* space between wordmark and that small line */
  --nav-toggle-width:          30px; /* width of the hamburger button */
  --nav-toggle-height:         24px; /* height of the hamburger button */
  --nav-toggle-bar:             2px; /* thickness of each hamburger bar */
  --nav-toggle-bar-top:         2px; /* where the top bar sits */
  --nav-toggle-bar-mid:        11px; /* where the middle bar sits — also the X pivot */
  --nav-toggle-bar-bottom:     20px; /* where the bottom bar sits */

  /* HERO ---------------------------------------------------------- */
  --hero-min-height:         100svh; /* how much of the screen the hero fills */
  --hero-pad-top:              7rem; /* clearance under the floating nav */
  --hero-pad-x:                1rem; /* side air around the hero text */
  --hero-pad-bottom:           4rem; /* space under the hero buttons */
  --hero-width:               860px; /* how wide the hero text block gets */
  --hero-tagline-size-min:   0.7rem; /* "Cruises · All-Inclusives" line on a phone */
  --hero-tagline-size-base:  0.6rem; /* fixed part of its in-between size */
  --hero-tagline-size-vw:     0.4vw; /* how fast that line grows with the window */
  --hero-tagline-size-max:   0.9rem; /* its size once the window is wide */
  --hero-tagline-tracking:    0.3em; /* how spread out that line reads */
  --hero-tagline-gap:        1.4rem; /* space between that line and the headline */
  --hero-title-size-min:     2.7rem; /* headline size on a phone */
  --hero-title-size-base:    1.9rem; /* fixed part of the in-between headline size */
  --hero-title-size-vw:         4vw; /* how fast the headline grows with the window */
  --hero-title-size-max:       5rem; /* headline size once the window is wide */
  --hero-title-gap:           0.3em; /* space under the headline */
  --hero-title-shadow-y:        2px; /* how far the headline's soft shadow drops */
  --hero-title-shadow-blur:    30px; /* how soft that shadow is — keeps text legible */
  --hero-script-size-min:    3.1rem; /* the script word "guesswork" on a phone */
  --hero-script-size-base:     2rem; /* fixed part of its in-between size */
  --hero-script-size-vw:        6vw; /* how fast the script word grows */
  --hero-script-size-max:    6.2rem; /* script word size once the window is wide */
  --hero-script-leading:       0.85; /* line spacing on the script word — bigger = looser */
  --hero-script-gap:         0.06em; /* lift of the script word toward the line above */
  --script-inline-size:       1.2em; /* size of a script word inside a smaller heading */
  --script-inline-leading:      0.9; /* line spacing around that inline script word */
  --script-inline-lift:      0.07em; /* nudge that levels it against the caps */
  --hero-lede-size-min:     1.05rem; /* hero paragraph size on a phone */
  --hero-lede-size-base:       1rem; /* fixed part of its in-between size */
  --hero-lede-size-vw:        0.4vw; /* how fast the hero paragraph grows */
  --hero-lede-size-max:      1.3rem; /* hero paragraph size once wide */
  --hero-lede-width:          620px; /* how wide the hero paragraph gets before wrapping */
  --hero-lede-gap:           2.2rem; /* space between that paragraph and the buttons */
  --hero-actions-gap:          1rem; /* space between the two hero buttons */
  --cue-bottom:              1.8rem; /* how far "Three ways to travel" sits off the bottom */
  --cue-size:               0.65rem; /* size of that scroll cue text */
  --cue-tracking:             0.3em; /* how spread out the scroll cue reads */
  --cue-gap:                 0.5rem; /* space between cue text and its line */
  --cue-line-width:             1px; /* thickness of the animated cue line */
  --cue-line-height:           38px; /* length of the animated cue line */
  --cue-cycle:                 2.2s; /* how long one sweep of that line takes */

  /* SECTION RHYTHM ------------------------------------------------ */
  --section-pad-min:           4rem; /* vertical air inside a section on a phone */
  --section-pad-base:          3rem; /* fixed part of the in-between section air */
  --section-pad-vw:             6vw; /* how fast section air grows with the window */
  --section-pad-max:         7.5rem; /* section air once the window is wide */
  --section-head-width:       680px; /* how wide a centred section intro gets */
  --section-head-gap:        3.2rem; /* gap from a section intro to its content */
  --h2-size-min:             2.1rem; /* section heading size on a phone */
  --h2-size-base:            1.6rem; /* fixed part of the in-between heading size */
  --h2-size-vw:               2.4vw; /* how fast section headings grow */
  --h2-size-max:             3.3rem; /* section heading size once the window is wide */
  --page-hero-title-min:     2.6rem; /* inner-page headline size on a phone */
  --page-hero-title-base:    1.8rem; /* fixed part of its in-between size */
  --page-hero-title-vw:       3.6vw; /* how fast that headline grows with the window */
  --page-hero-title-max:     4.6rem; /* inner-page headline size once the window is wide */
  --page-hero-title-gap:     0.25em; /* space under the inner-page headline */
  --section-lede-size:      1.08rem; /* the paragraph under a section heading */
  --section-cta-gap:         2.5rem; /* space above a section's closing button */

  /* BUTTONS ------------------------------------------------------- */
  --btn-size:               0.78rem; /* button label size */
  --btn-tracking:             0.1em; /* how spread out button labels read */
  --btn-pad-y:               0.95em; /* button height above and below the label */
  --btn-pad-x:                  2em; /* button width left and right of the label */
  --btn-radius:               100px; /* corner rounding — 100px keeps them pill-shaped */
  --btn-border-width:           1px; /* outline thickness on ghost and outline buttons */
  --btn-gap:                  0.6em; /* space between a button label and its icon */
  --btn-lift:                   3px; /* how far a button rises on hover */
  --btn-press:                  1px; /* how far it settles back when clicked */
  --btn-sm-pad-y:           0.55rem; /* height of the small referral button */
  --btn-sm-pad-x:            1.1rem; /* width of the small referral button */
  --btn-sm-size:            0.84rem; /* label size on the small button */

  /* CARD SURFACES (shared by every card on the page) --------------- */
  --card-title-size:         1.35rem; /* title on any card — trip, feature, step */
  --card-title-tracking:     0.035em; /* letter spacing on those titles */
  --radius:                    14px; /* corner rounding on cards and media — bigger = softer */
  --border-width:               1px; /* thickness of card outlines */
  --shadow-y:                  18px; /* how far a raised card's shadow drops */
  --shadow-blur:               50px; /* how soft that shadow is */
  --shadow-spread:            -22px; /* negative keeps the shadow under the card */
  --shadow-sm-y:                8px; /* how far a resting card's shadow drops */
  --shadow-sm-blur:            24px; /* how soft the resting shadow is */
  --shadow-sm-spread:         -14px; /* negative keeps the resting shadow tight */
  --shadow:    0 var(--shadow-y) var(--shadow-blur) var(--shadow-spread) rgba(var(--shadow-color), 0.45);
  --shadow-sm: 0 var(--shadow-sm-y) var(--shadow-sm-blur) var(--shadow-sm-spread) rgba(var(--shadow-color), 0.4);

  /* TRUST STRIP --------------------------------------------------- */
  --trust-pad-y:             1.4rem; /* height of the purple credentials bar */
  --trust-gap-x:            2.75rem; /* space between credentials across the bar */
  --trust-gap-y:               1rem; /* space between credential rows when they wrap */
  --trust-item-gap:         0.15rem; /* gap between a credential name and its note */
  --trust-name-size:         1.3rem; /* "CLIA", "ASTA" — the bold names */
  --trust-name-tracking:     0.05em; /* letter spacing on those names */
  --trust-note-size:        0.78rem; /* the small line under each name */

  /* SERVICE CARDS (the five "what I plan" tiles) ------------------- */
  --service-cols:                 3; /* service cards per row — 5 cards read as 3 then 2 */
  --service-pair-cols:            2; /* cards per row in the two-card row */
  --service-cols-half:            6; /* the same row counted in half-columns, so a pair can centre under three */
  --service-gap:             1.5rem; /* space between service cards */
  --service-row-gap:         1.5rem; /* space between the three-card and two-card rows */
  --service-pad-top:         1.4rem; /* space above the card title */
  --service-pad-x:           1.5rem; /* left/right padding inside a service card */
  --service-pad-bottom:      1.5rem; /* space below the card link */
  --service-body-gap:       0.55rem; /* space between title, text and link */
  --service-text-size:      0.94rem; /* service card paragraph size */
  --service-arrow-gap:       0.5rem; /* space above the "Plan a cruise →" link */
  --service-arrow-size:      0.9rem; /* size of that link */
  --service-arrow-tracking:  0.02em; /* letter spacing on that link */
  --service-arrow-nudge:    0.25rem; /* how far the arrow slides on hover */
  --service-lift:               4px; /* how far a service card rises on hover */

  /* FEATURE CARDS (the three "a booking site can't do" cards) ------ */
  --cards-cols:                   3; /* feature cards per row — 5 cards read as 3 then 2 */
  --cards-cols-half:              6; /* the same row counted in half-columns, so the last two can centre under the first three */
  --card-gap:                1.5rem; /* space between feature cards, both directions */
  --card-pad-y:              2.2rem; /* top/bottom padding inside a feature card */
  --card-pad-x:              1.8rem; /* left/right padding inside a feature card */
  --card-lift:                  6px; /* how far a feature card rises on hover */
  --card-icon-size:            54px; /* size of the icon tile */
  --card-icon-radius:          14px; /* corner rounding on the icon tile */
  --card-icon-gap:           1.2rem; /* space under the icon tile */
  --card-icon-glyph:           26px; /* size of the drawn icon inside that tile */
  --card-title-gap:          0.4rem; /* space under a feature card title */
  --card-text-size:         0.98rem; /* feature card paragraph size */

  /* PROCESS STEPS ------------------------------------------------- */
  --process-cols:                 4; /* steps per row on the four-step version */
  --process-detailed-cols:        3; /* steps per row on the five-step version — 3 then 2 */
  --process-gap:             1.5rem; /* space between the four steps */
  --process-number-size:     2.3rem; /* diameter of the numbered circle */
  --process-number-text:    1.05rem; /* size of the digit inside it */
  --process-step-gap:        3.1rem; /* space the circle reserves above each step */
  --process-title-gap:       0.4rem; /* space under a step title */
  --process-text-size:      0.94rem; /* step paragraph size */

  /* PORTRAIT SPLIT (meet your advisor) ----------------------------- */
  --split-gap-min:             2rem; /* space between portrait and text on a phone */
  --split-gap-base:            1rem; /* fixed part of the in-between gap */
  --split-gap-vw:               4vw; /* how fast that gap grows with the window */
  --split-gap-max:             5rem; /* that gap once the window is wide */
  --split-media-ratio:       4 / 5; /* shape of a split image — bigger = shorter */
  --split-media-ratio-tall:  3 / 4; /* shape when the image is marked tall */
  --split-portrait-pad:      0.5rem; /* breathing room above and below the headshot */
  --split-portrait-ratio:    1 / 1; /* shape of the headshot's box — bigger = shorter */

  /* QUOTES -------------------------------------------------------- */
  --quotes-cols:                  3; /* quote cards per row */
  --quote-gap:               1.6rem; /* space between quote cards */
  --quote-pad-top:           2.4rem; /* space above the stars, under the quote mark */
  --quote-pad-x:               2rem; /* left/right padding inside a quote card */
  --quote-pad-bottom:          2rem; /* space under the traveler's name */
  --quote-mark-size:         4.5rem; /* size of the decorative opening quote */
  --quote-mark-leading:         0.5; /* how far that mark sits into the card */
  --quote-mark-top:          1.2rem; /* how far the mark sits from the card top */
  --quote-mark-left:         1.3rem; /* how far the mark sits from the card edge */
  --quote-text-size:         1.3rem; /* the quoted sentence */
  --quote-text-leading:        1.35; /* line spacing in the quote — bigger = looser */
  --quote-text-gap-top:      1.3rem; /* space between the stars and the quote */
  --quote-text-gap-bottom:   1.4rem; /* space between the quote and the name */
  --quote-stars-tracking:    0.15em; /* how spread out the five stars read */
  --quote-stars-gap:         0.4rem; /* space under the stars */
  --quote-cite-size:        0.82rem; /* the traveler's name */
  --quote-cite-tracking:      0.1em; /* letter spacing on that name */

  /* CTA BAND ------------------------------------------------------ */
  --cta-pad-min:               4rem; /* vertical air in the closing band on a phone */
  --cta-pad-base:              3rem; /* fixed part of the in-between band air */
  --cta-pad-vw:                 5vw; /* how fast the band's air grows */
  --cta-pad-max:             6.5rem; /* the band's air once the window is wide */
  --cta-pad-x:                 1rem; /* side air inside the band */
  --cta-title-gap:            0.4em; /* space under "Ready when you are" */
  --cta-text-width:           560px; /* how wide the band's paragraph gets */
  --cta-text-gap:              2rem; /* space between that paragraph and the buttons */
  --cta-actions-gap:        0.75rem; /* space between the two band buttons */
  --cta-direct-gap:         1.25rem; /* space above the email and phone line */
  --cta-direct-size:        0.92rem; /* size of that email and phone line */
  --cta-direct-underline:       3px; /* drop from those links to their underline */
  --cta-direct-dot-space:    0.5rem; /* air either side of the dot separator */
  --cta-direct-stack-gap:    0.35rem; /* space between address and phone once they stack */
  --contact-cols:                 4; /* contact cards per row (inner pages) */

  /* REFERRAL BAND ------------------------------------------------- */
  --referral-pad-y:          1.1rem; /* height of the bottom referral bar */
  --referral-gap:           1.25rem; /* space between its sentence and its button */
  --referral-text-size:     0.96rem; /* size of that sentence */

  /* FOOTER -------------------------------------------------------- */
  --footer-pad-top:            4rem; /* space above the footer columns */
  --footer-pad-bottom:         2rem; /* space under the fine print */
  --footer-size:            0.92rem; /* footer text size */
  --footer-grid-gap:         2.5rem; /* space between footer columns */
  --footer-grid-gap-bottom:  2.5rem; /* space under the columns, above the fine print */
  --footer-brand-gap:          1rem; /* space under the footer wordmark */
  --footer-head-size:       0.74rem; /* the column headings */
  --footer-head-tracking:     0.2em; /* how spread out those headings read */
  --footer-head-gap:           1rem; /* space under a column heading */
  --footer-link-gap:        0.55rem; /* space between footer links */
  --social-size:               40px; /* diameter of a social icon button */
  --social-gap:              0.8rem; /* space between social buttons */
  --social-row-gap:          0.4rem; /* space above the row of social buttons */
  --footer-licence-tracking: 0.04em; /* letter spacing on the licence numbers */
  --social-glyph:              18px; /* size of the drawn icon inside them */
  --social-lift:                3px; /* how far a social button rises on hover */
  --footer-rule-width:          1px; /* thickness of the line above the fine print */
  --footer-bottom-pad:       1.6rem; /* space between that line and the fine print */
  --footer-bottom-gap-y:     0.8rem; /* space between fine-print rows when they wrap */
  --footer-bottom-gap-x:     1.5rem; /* space between fine-print items across */
  --footer-bottom-size:      0.8rem; /* fine-print size */
  --footer-underline-offset:    2px; /* drop from a fine-print link to its underline */
  /* Added 2 September 2026, per the lock rule: new knobs for the phone
     footer, nothing retuned. Above --bp-mobile none of these draw. */
  --footer-brand-social-gap:   1rem; /* phone: space between the wordmark and the social buttons on their shared row */
  --footer-blurb-gap:        0.9rem; /* phone: space between that row and the one-line blurb under it */
  --fold-chevron:               9px; /* size of the open/close chevron on a folded footer column */
  --fold-chevron-stroke:        2px; /* thickness of that chevron */
  --fold-chevron-inset:      0.5rem; /* how far the chevron sits in from the right edge */
  --fold-pad-top:            0.3rem; /* space between a fold's heading row and its links */
  --fold-pad-bottom:           1rem; /* space under a fold's links */
  --chip-gap:                0.5rem; /* space between link chips in an open fold */
  --chip-pad-x:              0.9rem; /* width of a link chip either side of its label */
  --chip-min-width:         4.75rem; /* narrowest a chip gets — a pill this round needs the width for a finger to own a 44px square inside it */
  --touch-cols: minmax(0, 1.4fr) minmax(0, 1fr); /* phone: how the contact links share a row — the wider track holds the email */
  --touch-col-gap:          0.75rem; /* space between the two contact tracks */

  /* TAP TARGETS ---------------------------------------------------
     Added after the 24 August lock, per the rule above: new knobs rather than
     retuned ones. Nothing here moves a visible pixel on a desktop window —
     these grow the area a finger can hit, not the area the design draws. The
     small controls keep their drawn size and gain an invisible overlay; the
     footer link rows grow their height, but only under --bp-tap. */
  --tap-min:                   44px; /* smallest touch target, every side (WCAG 2.5.5) */
  --tap-comfort:               48px; /* height of the phone footer's chips and fold headings — over --tap-min so a half-pixel offset can never round one under it */
  --bp-tap:                  1000px; /* width below which rows grow to --tap-min */
  /* --bp-tap holds the same number as --bp-nav-menu and stays a separate knob.
     They answer different questions — where the nav runs out of room, versus
     where a target has to be finger-sized — so moving one should not drag the
     other with it. */

  /* CONTRAST GUARDS -----------------------------------------------
     Added 3 September 2026, per the lock rule above: new knobs, nothing
     existing retuned by taste. Every number here was set by a measurement
     and is held by tools/audit/contrast.mjs, which fails the build if one
     of them stops carrying WCAG AA.

     The scrims and the nav glass are the load-bearing ones. Text over a
     photo is only as legible as the layer between them, and these photos
     are hotlinked from a third party — so the layer has to carry the worst
     photo that could ever land there, not the one that happens to be there
     today. The detector proves that by measuring each of these against a
     pure white and a pure black ground and taking the worse answer. That is
     why the numbers look heavier than the photos currently need. */
  /* The pill is a MATERIAL, not a tint. Apple's regular glass does not buy
     legibility by piling on opacity — it blurs the backdrop AND flattens its
     luminosity, so what shows through can no longer be dark enough to swallow
     the text. Doing only the first and paying for the rest with opacity is how
     this pill ended up at 0.72 white, which is barely glass at all.
     --header-flatten pulls the backdrop's blacks and whites toward each other;
     --header-lift then moves that compressed band to where the pill's own text
     can live on it. Together they hold 8:1 for the nav's ink at 0.55 opacity,
     where opacity alone needed 0.72 to reach the same place. */
  --header-flatten:              0.5; /* how far the backdrop's own light and dark are squeezed together — lower is flatter */
  --header-lift:                 1.3; /* where that flattened band sits — above 1 pushes it light, for dark text */
  --header-glass:               0.55; /* how much of the pill's own tint sits over that backdrop */
  --header-glass-scrolled:      0.70; /* how much of it sits there once the pill is scrolled */
  --header-glass-edge:          0.85; /* how bright the hairline around the pill reads — keeps the light catch above the fill */
  --hero-scrim-top:             0.56; /* darkening over the hero photo at the top */
  --hero-scrim-mid:             0.48; /* darkening across the middle, where the headline and lede sit — the shallowest point of the gradient, so this is the number that decides the hero */
  --hero-scrim-mid-at:           40%; /* how far down that middle stop sits */
  --hero-scrim-bottom:          0.76; /* darkening at the foot, under the buttons */
  /* A second scrim, anchored to the words rather than to the picture. The
     headline sits over the brightest part of this photograph — sky — and the
     script word is a mid-toned aqua, so darkening the WHOLE image enough to
     carry that one word costs the coastline and the sea, which is the half of
     the picture worth looking at. Apple's guidance for text over media is a
     legibility layer behind the text, not a heavier wash over everything. So
     the gradient above stays light and this ellipse does the work where the
     text actually is. */
  --hero-text-scrim:            0.36; /* how dark it gets directly behind the hero text */
  --hero-text-scrim-hold:        58%; /* how far out it stays at full strength before it starts to fade */
  --hero-text-scrim-pad:        5rem; /* how far past the text the shade reaches before it is fully gone */
  /* The radii are fixed at 50% and are not a knob: 50% is exactly the half-box,
     so the fade finishes precisely at the edge. Anything larger gets clipped by
     the box and draws a hard rectangle across the photo, which is what the
     first attempt at this did. Tune --hero-text-scrim-pad to change the size. */
  --page-hero-scrim-top:        0.74; /* darkening over an inner page's photo, at the top */
  --page-hero-scrim-bottom:     0.70; /* the same, at the foot */

  /* MEDIA CARDS ---------------------------------------------------
     Added after the 24 August lock, per the rule above: new knobs, nothing
     existing retuned. These size the square brand graphics — the five BOUND
     promise cards and the three testimonial cards. The artwork carries its own
     type, so these cards take none of the padding a text card needs; they
     reuse --cards-cols and --quotes-cols, so they stack at --bp-cards with
     everything else. */
  --media-card-ratio:           1 / 1; /* the graphics are square — holds the box before the image lands */
  --media-card-radius:  var(--radius); /* corner rounding, matched to the text cards alongside */
  /* The brand hexagon: flat top and bottom, a point at either side. Taken from
     the shape of the previous hexagon-cropped headshot rather than invented, so
     the headshot matches the hexagons inside the testimonial artwork. */
  --hex-clip: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);

  /* LIGHTBOX -----------------------------------------------------
     Added after the 24 August lock, per the rule above: new knobs, nothing
     existing retuned. The review cards are 1080px squares drawn at about
     340px, so the wording inside the artwork is small until it is opened. */
  --lightbox-max:             1080px; /* cap: the artwork's own pixel size, so it is never upscaled soft */
  --lightbox-pad:               1rem; /* breathing room between the card and the window edge */
  --lightbox-radius: var(--radius); /* corner rounding on the opened card */
  --lightbox-backdrop: rgba(26, 12, 46, 0.82); /* dimming behind the opened card */
  --lightbox-close-gap:       0.5rem; /* inset of the close button from the card's corner */
  --lightbox-fade:              0.2s; /* how fast the lightbox fades in */

  /* FOCUS AND SKIP LINK ------------------------------------------- */
  --focus-ring-width:           2px; /* thickness of the keyboard focus outline */
  --focus-ring-offset:          2px; /* gap between the element and that outline */
  --skip-pad-y:             0.75rem; /* height of the skip-to-content chip */
  --skip-pad-x:             1.25rem; /* width of the skip-to-content chip */

  /* MOTION -------------------------------------------------------- */
  --hover-fast:               0.25s; /* quickest hover fades — arrows, small hints */
  --nav-underline-ms:         0.35s; /* how fast a nav link's underline sweeps across */
  --hover-ms:                  0.3s; /* standard colour fade on hover */
  --lift-ms:                   0.4s; /* how long a button or the nav takes to move */
  --card-hover-ms:            0.35s; /* how long a service card takes to rise */
  --feature-hover-ms:         0.45s; /* how long a feature card takes to rise */
  --reveal-ms:                 0.8s; /* how long a section takes to fade in on scroll */
  --reveal-rise:               28px; /* how far it travels up while fading in */
  --reveal-step:              0.08s; /* stagger between cards in the same row */
  --reveal-trigger:            0.12; /* how much of a section shows before it fades in */
  --reveal-margin:            -40px; /* extra scroll past the fold before that starts */
  --header-scrolled-at:        40px; /* how far you scroll before the nav pill tightens */

  /* MOBILE MENU (dropdown under the nav pill) ---------------------- */
  --menu-width:               420px; /* how wide the dropdown gets before it stops growing */
  --menu-offset:            0.45rem; /* gap between the nav pill and the open menu */
  --menu-radius:               18px; /* corner rounding on the menu panel */
  --menu-pad-top:            0.9rem; /* space above the first menu item */
  --menu-pad-x:              1.2rem; /* side padding inside the menu */
  --menu-pad-bottom:         1.1rem; /* space under the last menu item */
  --menu-item-gap:          0.15rem; /* space between menu items */
  --menu-link-pad-y:         0.7rem; /* height of each menu row */
  --menu-link-size:          0.9rem; /* menu link size */
  --menu-rise:                 10px; /* how far the menu drops in when opening */
  --menu-shadow-y:             24px; /* how far the menu's shadow falls */
  --menu-shadow-blur:          48px; /* how soft that shadow is */
  --menu-shadow-spread:       -20px; /* negative keeps it under the panel */
  --menu-cta-gap:            0.9rem; /* space above the CTA inside the menu panel */
  --menu-cta-gap-top:        0.6rem; /* space between the last link and that CTA */

  /* PHONE-ONLY KNOBS (the rest are re-set inside the breakpoints) -- */
  --process-indent:          3.2rem; /* how far step text sits right of its number on phones */
  --process-number-rise:   -0.15rem; /* fine vertical nudge of that number on phones */
  /* Added 2 September 2026, per the lock rule: a new knob, nothing retuned.
     Below --bp-cards the trip cards stack one per row, and each drew its photo
     at the full 533px the markup reserves — a whole phone screen per card,
     five cards deep. Once they stack the photo follows this shape instead. The
     desktop cards are untouched: there the height attribute still sets the box. */
  --service-image-ratio:      3 / 2; /* photo shape once trip cards stack — bigger = shorter */

  /* SCROLL FOCUS (review cards and BOUND promise cards) ------------
     Added 2 September 2026, per the lock rule: new knobs, nothing retuned.
     The brand graphics carry their own wording, drawn small. As a card
     scrolls toward the middle of the window the artwork behind it blurs and
     dims, and the same words lift off it as real text — larger, sharp and
     selectable. main.js measures where each card is and writes --focus
     (0 away from the middle, 1 centred); a hovered or keyboard-focused card
     counts as centred. Everything visible is derived from these. */
  --focus-scale-rest:               1; /* how big a card sits away from the middle */
  --focus-scale-peak:            1.02; /* how big it grows once it is centred */
  --focus-hold:                  0.18; /* how far from the middle a card stays fully lifted, as a share of window height */
  --focus-band:                  0.45; /* how far from the middle a card is fully at rest, as a share of window height */
  --focus-centre:                 0.5; /* where in the window a card counts as centred — 0.5 = halfway down */
  --focus-ms:                    0.2s; /* how quickly a card catches up with the scroll */
  /* Added 3 September 2026, per the lock rule: a new knob, nothing retuned.
     The words used to lift the moment a card crossed the middle of the window,
     which meant the artwork was covered for most of the time it was on screen
     — and the artwork is the thing Zac drew. Now the lift waits for the page
     to stop moving. Scroll past and you see the cards; stop on one and its
     words come up. Hovering or tabbing to a card still lifts it immediately,
     because that is already a deliberate act. */
  --focus-settle:               240ms; /* how long the page must be still before a centred card lifts its words */

  /* TEXT OVERLAY (the words that lift off a focused card) -----------
     Sizes that read cqw are measured against the card's own width, so a
     review fits a 345px desktop card and grows on a 690px tablet card. */
  --overlay-blur:                 8px; /* how soft the artwork goes behind the lifted text */
  --overlay-grey:                 0.5; /* how much colour drains from the artwork behind the text — 1 = fully grey */
  --overlay-zoom:                0.06; /* how much the artwork grows as it blurs, so its softened edges never show */
  --overlay-scrim:               0.74; /* darkness of the brand tint over the artwork once the text has lifted — 1 = opaque */
  --overlay-pad-min:           0.9rem; /* least breathing room around the lifted text, on a narrow card */
  --overlay-pad-cqw:             5cqw; /* how that breathing room grows with the card's width */
  --overlay-pad-max:           1.6rem; /* most breathing room, on a wide card */
  --overlay-rise:                24px; /* how far the text travels up as it lifts */
  --overlay-scale-rest:          0.88; /* text size before it lifts, relative to its full size */
  --overlay-quote-min:        0.72rem; /* smallest a review or promise body gets, on a narrow card */
  --overlay-quote-cqw:         3.7cqw; /* how that body grows with the card's width */
  --overlay-quote-max:         1.05rem; /* largest that body gets, on a wide card */
  --overlay-quote-leading:        1.4; /* line spacing in that body */
  --overlay-title-min:         1.3rem; /* smallest a promise title gets */
  --overlay-title-cqw:           8cqw; /* how a promise title grows with the card's width */
  --overlay-title-max:         2.2rem; /* largest a promise title gets */
  --overlay-title-gap:         0.5rem; /* space under a promise title */
  --overlay-kicker-size:      0.68rem; /* the small line above a review that has one */
  --overlay-kicker-tracking:   0.16em; /* how spread out that line reads */
  --overlay-kicker-gap:        0.6rem; /* space under it */
  --overlay-cite-size:        0.72rem; /* the reviewer's name */
  --overlay-cite-tracking:     0.12em; /* how spread out the name reads */
  --overlay-cite-gap:          0.9rem; /* space above the name */

  /* PARALLAX (the closing band's photo) ----------------------------
     Added 2 September 2026, per the lock rule: new knobs, nothing retuned.
     main.js slides the photo against the scroll while the band is on screen. */
  --parallax-depth:             400px; /* how far the band's photo drifts as the page scrolls past — 0 turns it off */
  --parallax-overscan: var(--parallax-depth); /* extra photo drawn above and below the band so the drift never shows an edge — tracks depth */

  /* BREAKPOINTS — the numbers are repeated in the @media conditions
     further down, because @media cannot read a custom property.
     Change both. ------------------------------------------------- */
  --bp-nav-tight:            1180px; /* width where the nav starts packing tighter */
  --bp-desktop:               900px; /* width where the portrait split stacks */
  --bp-mobile:                720px; /* width where content columns stack to one */
  --bp-nav-menu:             1000px; /* width where the nav becomes a dropdown menu */
  --bp-cards:                 900px; /* width below which card rows stack to one column */
  --bp-process:              1100px; /* width below which the four steps go two by two */
  --bp-contact:              1100px; /* width below which the contact cards go two by two */
  --bp-phone-narrow:          400px; /* width below which the wordmark drops its sub-line */
  --bp-phone:                 480px; /* width below which headlines shrink to fit long words */
  --bp-short:                 900px; /* window HEIGHT below which the scroll cue hides */

  /* Tell the browser the site renders in both appearances, so the controls it
     draws itself — scrollbars, the date picker, a default form control before
     our own rules land — follow the reader rather than staying stuck light. */
  color-scheme: light dark;
}

/* =========================================================
   DARK APPEARANCE
   ---------------------------------------------------------
   Follows the reader's system setting and nothing else. There
   is deliberately no toggle: Apple's guidance is blunt about
   it — an app-specific appearance switch makes people set the
   same preference twice, and a site that ignores the one they
   already set reads as broken. Their OS already knows.

   Only the semantic layer moves. Everything below this block
   is written against those names, so the whole re-theme is
   this one screenful — which was the entire point of the
   naming discipline at the top of this file.

   Two things do NOT move, and both are deliberate:

   - The scrims over photographs, and the dark section bands.
     They are dark in both appearances already, and the text
     on them is white in both. Flipping them would mean
     re-solving contrast that is already solved.
   - --brand and --cta. The brand purple and the rose stay the
     brand purple and the rose. A dark appearance is not a
     licence to restate the palette.

   Every pair below is measured by tools/audit/contrast.mjs in
   this appearance as well as the light one. Apple asks for
   7:1 on small text rather than the 4.5:1 floor where you can
   get it, and the body pairs here clear that.
   ========================================================= */
@media (prefers-color-scheme: dark) {
  :root {
    /* Surfaces: a base plane, and a raised one for anything that reads as a
       card, panel or control sitting above it. */
    --ground:       var(--purple-ink);
    --paper:        var(--purple-raised);
    --surface-tint: var(--purple-veil);

    /* Text. --ink is 15.7:1 on the page ground; --muted is 7.6:1 on a card,
       which clears the 7:1 Apple asks for on small text rather than only the
       4.5:1 WCAG floor. */
    --ink:          #f4f2fb;
    --muted:        #b9b1d8;

    /* Interactive text is the brand purple lifted until it can be read on a
       dark ground: the original is 1.7:1 there. --link-contrast follows it,
       because white on a pale purple fill is the same mistake in reverse. */
    --link:          var(--purple-light);
    --link-contrast: var(--purple-ink);

    /* Headings stop borrowing the brand ground's purple and take the body
       colour. This is the pairing that could not be expressed before the
       --heading role existed. */
    --heading:      var(--ink);

    /* Lines, edges and rings. --field-border stays a real 5.4:1 against the
       control it outlines; --line is decorative and does not need to. */
    --line:         rgba(255, 255, 255, 0.14);
    --field-border: #9b93bd;
    --focus-ring:   var(--focus-ring-on-dark);

    /* The nav pill is a material, not a colour: in the light appearance it is
       white frosted over the page, and here it is the page's own ink frosted
       over itself. The blur and the opacity knobs are shared, so the pill
       reads the same way in both. */
    --glass-tint:      var(--purple-ink);
    --glass-edge-tint: #ffffff;
    /* The flattened band moves the other way here: pushed down, so the pill's
       light text has something dark to sit on whatever is behind it. */
    --header-lift:     0.5;

    /* The feature-card glyph tile. The light version is a pale aqua-to-blush
       wash with purple ink on it — on a dark ground that tile becomes a bright
       patch and the ink on it fails, so it inverts to a faint wash with the
       aqua glyph, matching what .section--deep already did on dark bands. */
    --icon-tile:     linear-gradient(135deg, rgba(118, 239, 225, 0.20), rgba(196, 176, 255, 0.16));
    --icon-tile-ink: var(--aqua);

    /* A purple shadow is invisible on a purple ground. */
    --shadow-color: 0, 0, 0;
  }

  /* The colour monogram is drawn in brand purple, which disappears into a
     dark pill. build.py serves the white mark here through a <picture>; this
     lets the <img> stay the grid item the lockup sizes. */
  .brand .mark picture { display: contents; }
}

/* ----------------------------- Reset ---------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--sans);
  font-weight: var(--body-weight);
  color: var(--ink);
  background: var(--ground);
  line-height: var(--body-leading);
  font-size: clamp(var(--body-size-min), var(--body-size-base) + var(--body-size-vw), var(--body-size-max));
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }

a { color: inherit; text-decoration: none; }

/* Face, weight, leading and tracking for headings are set once in the brand
   typography block further down — this rule only owns the space beneath.
   overflow-wrap is the backstop: the phone sizes below are picked so real
   headlines fit whole, but a longer word one day breaks rather than pushing
   the whole page sideways. */
h1, h2, h3, h4 {
  margin: 0 0 var(--heading-gap);
  overflow-wrap: break-word;
}

p { margin: 0 0 var(--para-gap); }

.script { font-family: var(--script); font-weight: 400; }

.eyebrow {
  font-family: var(--sans);
  font-weight: 500;
  text-transform: uppercase;
  font-size: var(--eyebrow-size);
  color: var(--link);
  margin: 0 0 var(--eyebrow-gap);
  display: inline-block;
}

.shell {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: clamp(var(--page-pad-min), var(--page-pad-vw), var(--page-pad-max));
}

.center { text-align: center; }

/* --------------------------- Buttons ---------------------------- */
.btn {
  --btn-bg: var(--link);
  --btn-fg: #fff;
  display: inline-flex;
  align-items: center;
  gap: var(--btn-gap);
  font-family: var(--sans);
  font-weight: 500;
  text-transform: uppercase;
  font-size: var(--btn-size);
  padding: var(--btn-pad-y) var(--btn-pad-x);
  border: var(--btn-border-width) solid transparent;
  border-radius: var(--btn-radius);
  background: var(--btn-bg);
  color: var(--btn-fg);
  cursor: pointer;
  transition: transform var(--lift-ms) var(--ease), box-shadow var(--lift-ms) var(--ease),
    background var(--hover-ms) ease, color var(--hover-ms) ease;
}
.btn:hover { transform: translateY(calc(-1 * var(--btn-lift))); box-shadow: var(--shadow-sm); }
.btn:active { transform: translateY(calc(-1 * var(--btn-press))); }

.btn--primary { --btn-bg: linear-gradient(135deg, var(--accent-bright), var(--cta)); --btn-fg: #ffffff; }
.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: #fff;
  border-color: rgba(255, 255, 255, 0.6);
}
.btn--ghost:hover { background: rgba(255, 255, 255, 0.12); }
.btn--outline {
  --btn-bg: transparent;
  --btn-fg: var(--link);
  border-color: var(--link);
}
.btn--outline:hover { background: var(--link); color: var(--link-contrast); }

/* ----------------------------- Nav ------------------------------ */
/* Floating "liquid glass" nav bar — always frosted so it reads on any background */
.site-header {
  position: fixed;
  top: var(--header-top);
  /* Centred with auto margins rather than left:50% + translateX(-50%): a
     transform would make this header the containing block for its own
     position:fixed children, which collapses the mobile slide-in menu to the
     header's own 60px box instead of the full viewport. */
  left: 0;
  right: 0;
  margin-inline: auto;
  z-index: 60;
  width: min(var(--maxw), calc(100% - var(--header-side-inset)));
  border-radius: var(--header-radius);
  background: rgb(from var(--glass-tint) r g b / var(--header-glass));
  /* Order matters: blur, then colour, then flatten the luminosity, then place
     the flattened band. Saturate stays ahead of the flatten so the backdrop
     keeps its colour rather than going grey. */
  -webkit-backdrop-filter: blur(var(--header-blur)) saturate(var(--header-saturate))
    contrast(var(--header-flatten)) brightness(var(--header-lift));
  backdrop-filter: blur(var(--header-blur)) saturate(var(--header-saturate))
    contrast(var(--header-flatten)) brightness(var(--header-lift));
  border: var(--header-border-width) solid rgb(from var(--glass-edge-tint) r g b / var(--header-glass-edge));
  box-shadow:
    0 var(--header-shadow-y) var(--header-shadow-blur) var(--header-shadow-spread) rgba(52, 25, 122, 0.45),
    inset 0 var(--header-highlight-width) 0 rgba(255, 255, 255, 0.6),
    inset 0 calc(-1 * var(--header-highlight-width)) 0 rgba(255, 255, 255, 0.12);
  transition: background var(--lift-ms) var(--ease), box-shadow var(--lift-ms) var(--ease),
    top var(--lift-ms) var(--ease), border-color var(--lift-ms) var(--ease);
}
.site-header.is-scrolled {
  top: var(--header-top-scrolled);
  background: rgb(from var(--glass-tint) r g b / var(--header-glass-scrolled));
  border-color: rgb(from var(--glass-edge-tint) r g b / var(--header-glass-edge));
  box-shadow:
    0 var(--header-shadow-y-scrolled) var(--header-shadow-blur-scrolled) var(--header-shadow-spread-scrolled) rgba(52, 25, 122, 0.5),
    inset 0 var(--header-highlight-width) 0 rgba(255, 255, 255, 0.7);
}
.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nav-gap);
  max-width: none;
  margin: 0;
  padding: var(--nav-pad-y) var(--nav-pad-right) var(--nav-pad-y) var(--nav-pad-left);
}
/* Gap, wordmark size and tracking are set once in the brand lockup block
   further down; the size here is the box the lockup's tracking measures against. */
.brand {
  display: flex;
  align-items: center;
  font-size: var(--brand-lockup-size);
  font-family: var(--serif);
  color: var(--ink);
  transition: color var(--lift-ms) ease;
}
/* Box, size and art are set once in the brand lockup block further down. */
.brand .mark { flex: none; color: #fff; }
.brand small {
  display: block;
  font-family: var(--sans);
  font-weight: 400;
  font-size: var(--brand-sub-size);
  text-transform: uppercase;
  opacity: 0.85;
  margin-top: var(--brand-sub-gap);
}
.is-scrolled .brand,
.inner-page .brand { color: var(--ink); }

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--nav-link-gap);
  list-style: none;
  margin: 0; padding: 0;
}
.nav-links a {
  font-weight: 400;
  font-size: var(--nav-link-size);
  letter-spacing: var(--nav-link-tracking);
  text-transform: uppercase;
  color: var(--ink);
  position: relative;
  padding-bottom: var(--nav-underline-gap);
  transition: color var(--hover-ms) ease;
}
/* Colour and thickness of the underline are set in the brand block below. */
.nav-links a::after {
  content: "";
  position: absolute; left: 0; bottom: 0;
  width: 0;
  transition: width var(--nav-underline-ms) var(--ease);
}
.nav-links a:hover::after,
.nav-links a.active::after { width: 100%; }
.is-scrolled .nav-links a,
.inner-page .nav-links a { color: var(--ink); }
.nav-links a.active { color: var(--link); }

.nav-cta { display: flex; align-items: center; gap: var(--nav-cta-gap); }

.nav-toggle {
  display: none;
  background: none; border: 0; cursor: pointer;
  width: var(--nav-toggle-width); height: var(--nav-toggle-height); position: relative;
}
.nav-toggle span {
  position: absolute; left: 0; height: var(--nav-toggle-bar); width: 100%;
  background: var(--ink); border-radius: var(--nav-toggle-bar); transition: var(--hover-ms) var(--ease);
}
.is-scrolled .nav-toggle span,
.inner-page .nav-toggle span { background: var(--ink); }
.nav-toggle span:nth-child(1) { top: var(--nav-toggle-bar-top); }
.nav-toggle span:nth-child(2) { top: var(--nav-toggle-bar-mid); }
.nav-toggle span:nth-child(3) { top: var(--nav-toggle-bar-bottom); }
body.nav-open .nav-toggle span:nth-child(1) { top: var(--nav-toggle-bar-mid); transform: rotate(45deg); }
body.nav-open .nav-toggle span:nth-child(2) { opacity: 0; }
body.nav-open .nav-toggle span:nth-child(3) { top: var(--nav-toggle-bar-mid); transform: rotate(-45deg); }

/* --------------------------- Hero ------------------------------- */
.hero {
  position: relative;
  min-height: var(--hero-min-height);
  display: grid;
  place-items: center;
  text-align: center;
  color: #fff;
  isolation: isolate;
  padding: var(--hero-pad-top) var(--hero-pad-x) var(--hero-pad-bottom);
}
.hero__bg {
  position: absolute; inset: 0; z-index: -2;
  background:
    linear-gradient(180deg,
      rgba(30, 14, 70, var(--hero-scrim-top)),
      rgba(30, 14, 70, var(--hero-scrim-mid)) var(--hero-scrim-mid-at),
      rgba(30, 14, 70, var(--hero-scrim-bottom))),
    radial-gradient(120% 80% at 50% 0%, rgba(118, 239, 225,0.25), transparent 60%),
    var(--brand);
  background-size: cover;
  background-position: center;
}
.hero__bg.has-img {
  background-image:
    linear-gradient(180deg,
      rgba(30, 14, 70, var(--hero-scrim-top)),
      rgba(30, 14, 70, var(--hero-scrim-mid)) var(--hero-scrim-mid-at),
      rgba(30, 14, 70, var(--hero-scrim-bottom))),
    var(--hero-img);
}
.hero__inner { max-width: var(--hero-width); position: relative; }
/* Sits above .hero__bg (z-index -2) and below the words. */
.hero__inner::before {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--hero-text-scrim-pad));
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    ellipse 50% 50% at 50% 50%,
    rgb(from var(--purple-ink) r g b / var(--hero-text-scrim)) var(--hero-text-scrim-hold),
    rgb(from var(--purple-ink) r g b / 0) 100%);
}
.hero .tagline {
  font-family: var(--sans);
  font-weight: var(--body-weight);
  letter-spacing: var(--hero-tagline-tracking);
  text-transform: uppercase;
  font-size: clamp(var(--hero-tagline-size-min),
                   var(--hero-tagline-size-base) + var(--hero-tagline-size-vw),
                   var(--hero-tagline-size-max));
  margin-bottom: var(--hero-tagline-gap);
  opacity: 0.95;
}
/* Bebas Neue plus the script line makes this headline tall. The sizes below are
   the only ones that apply to it — trimming them is what keeps the CTAs clear of
   the scroll cue on a 13" laptop. */
.hero h1 {
  font-size: clamp(var(--hero-title-size-min),
                   var(--hero-title-size-base) + var(--hero-title-size-vw),
                   var(--hero-title-size-max));
  margin-bottom: var(--hero-title-gap);
  text-shadow: 0 var(--hero-title-shadow-y) var(--hero-title-shadow-blur) rgba(0,0,0,0.3);
}
.hero h1 .script {
  display: block;
  font-size: clamp(var(--hero-script-size-min),
                   var(--hero-script-size-base) + var(--hero-script-size-vw),
                   var(--hero-script-size-max));
  color: var(--aqua-soft);
  line-height: var(--hero-script-leading);
  margin-top: var(--hero-script-gap);
}
.hero p.lede {
  font-size: clamp(var(--hero-lede-size-min),
                   var(--hero-lede-size-base) + var(--hero-lede-size-vw),
                   var(--hero-lede-size-max));
  font-weight: var(--body-weight);
  max-width: var(--hero-lede-width);
  margin: 0 auto var(--hero-lede-gap);
  color: rgba(255,255,255,0.92);
}
.hero__actions { display: flex; gap: var(--hero-actions-gap); justify-content: center; flex-wrap: wrap; }

.scroll-cue {
  position: absolute; bottom: var(--cue-bottom); left: 50%; transform: translateX(-50%);
  font-size: var(--cue-size); letter-spacing: var(--cue-tracking); text-transform: uppercase;
  opacity: 0.8; display: flex; flex-direction: column; align-items: center; gap: var(--cue-gap);
}
.scroll-cue::after {
  content: ""; width: var(--cue-line-width); height: var(--cue-line-height);
  background: linear-gradient(rgba(255,255,255,0.9), transparent);
  animation: cue var(--cue-cycle) var(--ease) infinite;
}
@keyframes cue { 0% { transform: scaleY(0); transform-origin: top; } 50% { transform: scaleY(1);} 100% { transform: scaleY(0); transform-origin: bottom; } }

/* ----------------------- Inner page header ---------------------- */
.page-hero {
  position: relative;
  color: #fff;
  text-align: center;
  padding: 11rem 1rem 5rem;
  isolation: isolate;
}
.page-hero__bg {
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(180deg,
      rgba(30, 14, 70, var(--page-hero-scrim-top)),
      rgba(30, 14, 70, var(--page-hero-scrim-bottom))),
    var(--page-img, none), var(--brand);
  background-size: cover; background-position: center;
}
/* Size is set once in the brand typography block below. */
.page-hero h1 { margin-bottom: var(--page-hero-title-gap); }
.page-hero p { max-width: 600px; margin: 0 auto; opacity: 0.94; font-weight: var(--body-weight); }
.page-hero .eyebrow { color: var(--aqua); }

/* ---------------------------- Sections -------------------------- */
.section { padding: clamp(var(--section-pad-min), var(--section-pad-base) + var(--section-pad-vw), var(--section-pad-max)) 0; }
.section--tint { background: var(--surface-tint); }
.section--deep { background: var(--ground-deep); color: #fff; }
.section--deep .eyebrow { color: var(--aqua); }
.section--deep .muted { color: var(--muted-on-dark); }

.section-head { max-width: var(--section-head-width); margin: 0 auto var(--section-head-gap); text-align: center; }
/* Section heading sizes are set once in the brand typography block below. */
.section-head p { color: var(--muted); font-size: var(--section-lede-size); }
.section--deep .section-head p { color: rgba(255,255,255,0.78); }

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

/* The button that closes a section — "Read more reviews", "Fees, process…". */
.section-cta { margin-top: var(--section-cta-gap); }

/* Split / intro layout */
.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(var(--split-gap-min), var(--split-gap-base) + var(--split-gap-vw), var(--split-gap-max));
  align-items: center;
}
.split__media {
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
  aspect-ratio: var(--split-media-ratio);
  background: var(--aqua-soft) var(--media-img) center/cover no-repeat;
  position: relative;
}
.split__media.tall { aspect-ratio: var(--split-media-ratio-tall); }

/* ------------------------- Feature cards ------------------------ */
.cards {
  display: grid;
  grid-template-columns: repeat(var(--cards-cols), minmax(0, 1fr));
  gap: var(--card-gap);
}
.card {
  background: var(--paper);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius);
  padding: var(--card-pad-y) var(--card-pad-x);
  transition: transform var(--feature-hover-ms) var(--ease), box-shadow var(--feature-hover-ms) var(--ease);
}
.card:hover { transform: translateY(calc(-1 * var(--card-lift))); box-shadow: var(--shadow); }
.card .icon {
  width: var(--card-icon-size); height: var(--card-icon-size); border-radius: var(--card-icon-radius);
  display: grid; place-items: center; margin-bottom: var(--card-icon-gap);
  background: var(--icon-tile);
  color: var(--icon-tile-ink);
}
.card .icon svg { width: var(--card-icon-glyph); height: var(--card-icon-glyph); }
/* Card title size is set once in the brand typography block below. */
.card h3 { margin-bottom: var(--card-title-gap); }
.card p { color: var(--muted); margin: 0; font-size: var(--card-text-size); }
.section--deep .card { background: rgba(255,255,255,0.04); border-color: rgba(255,255,255,0.12); }
.section--deep .card p { color: rgba(255,255,255,0.72); }
.section--deep .card .icon { background: rgba(118, 239, 225,0.18); color: var(--aqua); }

/* numbered promise list */
.promise-grid { counter-reset: promise; }
.card[data-num]::before {
  counter-increment: promise;
  content: "0" counter(promise);
  font-family: var(--serif);
  font-size: 0.95rem;
  color: var(--accent-bright);
  letter-spacing: 0.1em;
  display: block;
  margin-bottom: 0.6rem;
}

/* --------------------------- Media cards ------------------------ */
/* A card that is wholly a brand graphic. The artwork already carries its
   heading and body, so the card draws no type of its own — the real words sit
   next to the image inside .visually-hidden, which is what a screen reader and
   a crawler read. Nobody is shown them twice. */
.media-card {
  /* figure carries a 40px side margin from the browser's own stylesheet, the
     same one that was eating 80px out of every .quote track. */
  margin: 0;
  border-radius: var(--media-card-radius);
  /* No overflow: hidden here. The lifted text panel is allowed to grow past
     the card when a long review needs more height than a narrow card offers,
     so the artwork clips itself inside .media-card__art instead. */
  box-shadow: var(--shadow-sm);
  border: var(--border-width) solid var(--line);
  background: var(--paper);
}
.media-card__art {
  display: block;
  overflow: hidden;
  border-radius: var(--media-card-radius);
}
.media-card img {
  display: block;
  width: 100%;
  /* height:auto is load-bearing, not tidiness. The markup carries width="1080"
     height="1080" so the browser can hold the box before the file lands, but
     those attributes are PRESENTATIONAL HINTS: without a CSS height they win
     over aspect-ratio, and the box became 1080px tall inside a ~380px column.
     object-fit:cover then cropped a square graphic to a tall slot and sliced
     the wording in half — "BESPOKE JOURNEYS" rendered as "SPOKE URNEYS".
     The same attribute-over-aspect-ratio trap grew the honeymoon card by 130px
     in August. */
  height: auto;
  aspect-ratio: var(--media-card-ratio);
  object-fit: cover;
}

/* The review cards open full size. The link is a real link to the image file,
   so it still does something useful with JavaScript off; main.js intercepts it
   and opens the dialog instead. */
.zoom {
  display: block;
  cursor: zoom-in;
}
.zoom:focus-visible {
  outline: var(--focus-ring-width) solid var(--link);
  outline-offset: var(--focus-ring-offset);
}

/* A native <dialog>, not a hand-rolled overlay: showModal() gives the focus
   trap, the Escape key, inertness of the page behind and focus restore on
   close, all of which are easy to implement badly. */
.lightbox {
  border: 0;
  padding: var(--lightbox-pad);
  background: transparent;
  max-width: 100%;
  max-height: 100%;
  overflow: visible;
}
.lightbox::backdrop { background: var(--lightbox-backdrop); }
.lightbox__inner { position: relative; }
/* The cards are square, so the smaller of the two viewport axes decides how big
   they can get; height is usually the binding one on a desktop window and width
   on a phone. Sizing off whichever actually constrains beats a single vmin
   figure, which left ~40px of desktop height unused. Capped at the artwork's own
   1080px so a large monitor gets it sharp rather than upscaled. */
.lightbox img {
  display: block;
  width: min(
    calc(100vw - var(--lightbox-pad) * 2),
    calc(100vh - var(--lightbox-pad) * 2),
    var(--lightbox-max)
  );
  height: auto;
  border-radius: var(--lightbox-radius);
}
.lightbox__close {
  position: absolute;
  top: var(--lightbox-close-gap);
  right: var(--lightbox-close-gap);
  /* --tap-min on both axes: this is the one control in the lightbox, and it
     sits over artwork, so it has to be findable by a thumb. */
  width: var(--tap-min);
  height: var(--tap-min);
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: var(--paper);
  color: var(--heading);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
}
.lightbox__close:focus-visible {
  outline: var(--focus-ring-width) solid var(--link);
  outline-offset: var(--focus-ring-offset);
}
.lightbox[open] { animation: lightbox-in var(--lightbox-fade) ease-out; }
@keyframes lightbox-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .lightbox[open] { animation: none; }
}

/* Present to assistive technology and to search, absent from the page. The
   1px box and negative margin are the standard clipping idiom rather than
   design measurements, so they stay here instead of becoming knobs — there is
   no value a person would ever want to tune. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------- Scroll focus ----------------------- */
/* main.js writes --focus-scroll on every .media-card as the page scrolls: 0
   when the card is a band's width from the middle of the window, 1 when it is
   centred. --focus is that number, or 1 while the card is hovered or holds
   keyboard focus. Everything visible derives from --focus here, so the look is
   tuned in the control block and the script only measures.

   The artwork carries its own wording, drawn small. At rest it shows as it is.
   As --focus rises the artwork blurs, dims and grows a little (so its softened
   edges never show), a brand tint comes up over it, and the figcaption — the
   same words as real text — lifts up into place. It is real text at every
   focus, so a screen reader and a crawler read it regardless; only the sighted
   presentation moves. pointer-events: none keeps a click falling through to
   the review card's link beneath. Scoped to .in so this and the reveal never
   fight over the card's transform. */
.media-card {
  --focus-scroll: 0;
  --focus: var(--focus-scroll);
  position: relative;
  container-type: inline-size;
}
@media (hover: hover) {
  .media-card:hover { --focus: 1; }
}
.media-card:focus-within { --focus: 1; }
/* No rise on entry for these: the scale below is their entrance. */
.js .media-card.reveal { transform: none; }
.media-card.reveal.in {
  transform: scale(calc(var(--focus-scale-rest) + (var(--focus-scale-peak) - var(--focus-scale-rest)) * var(--focus)));
  transition: opacity var(--reveal-ms) var(--ease), transform var(--focus-ms) linear;
  will-change: transform;
}
.media-card img {
  filter:
    blur(calc(var(--overlay-blur) * var(--focus)))
    grayscale(calc(var(--overlay-grey) * var(--focus)));
  transform: scale(calc(1 + var(--overlay-zoom) * var(--focus)));
  transition: filter var(--focus-ms) linear, transform var(--focus-ms) linear;
  will-change: filter, transform;
}
/* Centred on the card and at least as tall as it. Between roughly 900px and
   1060px wide the three-column row leaves a review card under 300px, and the
   two longest reviews need more height than that, so the panel is free to
   grow past the card's top and bottom edges rather than clip a sentence. */
.media-card__text {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  min-height: 100%;
  margin: 0;
  padding: clamp(var(--overlay-pad-min), var(--overlay-pad-cqw), var(--overlay-pad-max));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: #fff;
  border-radius: var(--media-card-radius);
  background: rgb(from var(--purple-ink) r g b / calc(var(--overlay-scrim) * var(--focus)));
  opacity: var(--focus);
  transform:
    translateY(-50%)
    translateY(calc(var(--overlay-rise) * (1 - var(--focus))))
    scale(calc(var(--overlay-scale-rest) + (1 - var(--overlay-scale-rest)) * var(--focus)));
  transition: opacity var(--focus-ms) linear, transform var(--focus-ms) linear, background-color var(--focus-ms) linear;
  pointer-events: none;
  z-index: 1;
}
.media-card__text blockquote,
.media-card__text p { margin: 0; }
.media-card__text blockquote p,
.media-card__text > p:not(.media-card__kicker) {
  font-size: clamp(var(--overlay-quote-min), var(--overlay-quote-cqw), var(--overlay-quote-max));
  line-height: var(--overlay-quote-leading);
}
.media-card__kicker {
  font-family: var(--sans);
  font-weight: 500;
  text-transform: uppercase;
  font-size: var(--overlay-kicker-size);
  letter-spacing: var(--overlay-kicker-tracking);
  color: var(--accent-bright);
  margin-bottom: var(--overlay-kicker-gap);
}
.media-card__text cite {
  font-style: normal;
  font-weight: 500;
  text-transform: uppercase;
  font-size: var(--overlay-cite-size);
  letter-spacing: var(--overlay-cite-tracking);
  color: var(--accent-bright);
  margin-top: var(--overlay-cite-gap);
}
.media-card__text h3 {
  font-size: clamp(var(--overlay-title-min), var(--overlay-title-cqw), var(--overlay-title-max));
  color: var(--accent-bright);
  margin: 0 0 var(--overlay-title-gap);
}
@media (prefers-reduced-motion: reduce) {
  .media-card.reveal.in,
  .media-card img,
  .media-card__text { transition: none; }
}

/* --------------------------- Testimonials ----------------------- */
.quotes {
  display: grid;
  grid-template-columns: repeat(var(--quotes-cols), minmax(0, 1fr));
  gap: var(--quote-gap);
}
.quote {
  /* figure carries a 40px side margin from the browser's own stylesheet, which
     was eating 80px out of every quote card's grid track. */
  margin: 0;
  background: var(--paper);
  border-radius: var(--radius);
  padding: var(--quote-pad-top) var(--quote-pad-x) var(--quote-pad-bottom);
  box-shadow: var(--shadow-sm);
  border: var(--border-width) solid var(--line);
  position: relative;
}
.quote::before {
  content: "\201C";
  font-family: var(--serif);
  font-size: var(--quote-mark-size);
  line-height: var(--quote-mark-leading);
  color: var(--aqua-soft);
  position: absolute; top: var(--quote-mark-top); left: var(--quote-mark-left);
}
.quote blockquote {
  margin: var(--quote-text-gap-top) 0 var(--quote-text-gap-bottom);
  font-family: var(--serif);
  font-size: var(--quote-text-size);
  font-weight: 500;
  line-height: var(--quote-text-leading);
  color: var(--heading);
}
.quote .stars { color: var(--accent-bright); letter-spacing: var(--quote-stars-tracking); margin-bottom: var(--quote-stars-gap); }
.quote cite {
  font-style: normal;
  font-weight: 500;
  letter-spacing: var(--quote-cite-tracking);
  text-transform: uppercase;
  font-size: var(--quote-cite-size);
  color: var(--link);
}

/* ---------------------------- Stats ----------------------------- */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr));
  gap: 1.5rem;
  text-align: center;
}
.stat .num {
  font-family: var(--serif);
  font-size: clamp(2.2rem, 1.6rem + 2.4vw, 3.4rem);
  color: var(--accent-bright);
  line-height: 1;
}
.stat .label {
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 0.74rem;
  color: rgba(255,255,255,0.75);
  margin-top: 0.6rem;
}

/* ------------------------ Badges / creds ------------------------ */
.badges {
  display: flex; flex-wrap: wrap; gap: 0.8rem; justify-content: center;
}
.badge {
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: 0.6em 1.3em;
  font-size: 0.82rem;
  letter-spacing: 0.05em;
  background: var(--paper);
  color: var(--heading);
}
.badge strong { font-weight: 600; }

/* ----------------------------- CTA band ------------------------- */
.cta-band {
  position: relative;
  text-align: center;
  color: #fff;
  padding: clamp(var(--cta-pad-min), var(--cta-pad-base) + var(--cta-pad-vw), var(--cta-pad-max)) var(--cta-pad-x);
  isolation: isolate;
  /* The photo is drawn taller than the band so it can drift; the overhang
     must not paint over the sections either side of it. */
  overflow: hidden;
}
/* The photo overhangs the band by half the overscan top and bottom. main.js
   slides it by up to half --parallax-depth either way as the band crosses the
   window, so the overhang is exactly what keeps an edge from ever showing. */
.cta-band__bg {
  position: absolute; z-index: -1;
  inset: calc(-1 * var(--parallax-overscan) / 2) 0;
  will-change: transform;
  background:
    linear-gradient(135deg, rgba(52, 25, 122,0.82), rgba(70, 34, 162,0.78)),
    var(--cta-img, none), var(--link);
  background-size: cover; background-position: center;
}
/* The band's heading size is set once in the brand typography block below. */
.cta-band h2 { margin-bottom: var(--cta-title-gap); }
.cta-band p { max-width: var(--cta-text-width); margin: 0 auto var(--cta-text-gap); opacity: 0.92; }

/* ---------------------------- Footer ---------------------------- */
/* Two footer columns are <details> so they can fold shut on a phone. Above
   --bp-mobile the fold is inert: the summary takes no pointer and draws no
   marker, and main.js keeps the details open and its summary out of the tab
   order. The phone rules are in the --bp-mobile block further down. */
.footer-col__fold > summary {
  display: block;
  list-style: none;
  pointer-events: none;
}
.footer-col__fold > summary::-webkit-details-marker { display: none; }

.site-footer {
  background: var(--ground-deep);
  color: rgba(255,255,255,0.8);
  padding: var(--footer-pad-top) 0 var(--footer-pad-bottom);
  font-size: var(--footer-size);
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr;
  gap: var(--footer-grid-gap);
  margin-bottom: var(--footer-grid-gap-bottom);
}
/* The footer is a dark ground, so --muted (a paper grey) does not belong here:
   it measured 2.5:1 on the purple. */
.site-footer .muted { color: var(--muted-on-dark); }
.site-footer .brand { color: #fff; margin-bottom: var(--footer-brand-gap); }
.footer-col__title {
  font-family: var(--sans);
  /* These are h2s so the heading order does not skip a level, but they used to
     be h4s and must still draw identically. h1/h2 and h3/h4 carry different
     leading, so pin the h4 value or the swap quietly tightens the footer. */
  line-height: var(--subhead-leading);
  text-transform: uppercase;
  letter-spacing: var(--footer-head-tracking);
  font-size: var(--footer-head-size);
  color: var(--aqua);
  margin-bottom: var(--footer-head-gap);
  font-weight: 500;
}
.footer-links { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--footer-link-gap); }
.footer-links a:hover { color: var(--aqua); }
.socials { display: flex; gap: var(--social-gap); margin-top: var(--social-row-gap); }
.socials a {
  width: var(--social-size); height: var(--social-size); border-radius: 50%;
  display: grid; place-items: center;
  border: var(--border-width) solid rgba(255,255,255,0.2);
  transition: var(--hover-ms) var(--ease);
}
.socials a:hover { background: var(--aqua); border-color: var(--aqua); color: var(--ground-deep); transform: translateY(calc(-1 * var(--social-lift))); }
.socials svg { width: var(--social-glyph); height: var(--social-glyph); }
.footer-bottom {
  border-top: var(--footer-rule-width) solid rgba(255,255,255,0.12);
  padding-top: var(--footer-bottom-pad);
  display: flex; flex-wrap: wrap; gap: var(--footer-bottom-gap-y) var(--footer-bottom-gap-x);
  justify-content: space-between; align-items: center;
  font-size: var(--footer-bottom-size); color: rgba(255,255,255,0.6);
}
.licenses { letter-spacing: var(--footer-licence-tracking); }
.footer-bottom a { color: rgba(255,255,255,0.82); text-decoration: underline; text-underline-offset: var(--footer-underline-offset); }
.footer-bottom a:hover { color: var(--aqua); }

/* ------------------------- Legal / prose ----------------------- */
.legal { max-width: 820px; margin: 0 auto; }
.legal > .updated { color: var(--muted); font-size: 0.9rem; letter-spacing: 0.04em; margin-bottom: 2.2rem; }
.legal h2 {
  font-size: clamp(1.35rem, 1.1rem + 1.1vw, 1.85rem);
  color: var(--heading);
  margin-top: 2.6rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--line);
}
.legal h2:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
.legal h3 { font-family: var(--sans); font-weight: 600; font-size: 1.05rem; margin: 1.4rem 0 0.4rem; }
.legal p, .legal li { color: var(--ink); }
.legal ul { padding-left: 1.2rem; margin: 0 0 1.1em; }
.legal li { margin-bottom: 0.45rem; }
.legal a { color: var(--link); text-decoration: underline; text-underline-offset: 2px; }
.legal .callout {
  background: var(--surface-tint);
  border-left: 3px solid var(--accent-bright);
  padding: 1rem 1.3rem;
  border-radius: 8px;
  margin: 1.6rem 0;
  font-size: 0.95rem;
}

/* ----------------------------- Modal ---------------------------- */
.modal {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  padding: 1.5rem;
  background: rgba(30, 14, 70,0.6);
  backdrop-filter: blur(6px);
  opacity: 0; visibility: hidden;
  transition: opacity 0.35s ease, visibility 0.35s ease;
}
.modal.is-open { opacity: 1; visibility: visible; }
.modal__panel {
  background: var(--paper);
  border-radius: var(--radius);
  max-width: 520px; width: 100%;
  padding: clamp(1.8rem, 1rem + 3vw, 2.8rem);
  box-shadow: var(--shadow);
  transform: translateY(20px) scale(0.98);
  transition: transform 0.4s var(--ease);
  max-height: 90vh; overflow-y: auto;
}
.modal.is-open .modal__panel { transform: none; }
.modal__close {
  position: absolute; top: 1.2rem; right: 1.4rem;
  background: none; border: 0; font-size: 1.6rem; line-height: 1;
  cursor: pointer; color: var(--muted);
}
.modal__panel h3 { font-size: 1.7rem; margin-bottom: 0.2em; }
.modal__panel .sub { color: var(--muted); margin-bottom: 1.6rem; }

/* ----------------------------- Forms ---------------------------- */
.field { margin-bottom: 1.1rem; }
.field label {
  display: block;
  font-size: 0.74rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--link); margin-bottom: 0.45rem; font-weight: 500;
}
.field input,
.field textarea,
.field select {
  width: 100%;
  font-family: var(--sans); font-size: 1rem; font-weight: var(--body-weight);
  color: var(--ink);
  padding: 0.85em 1em;
  /* --line is a card outline at 1.3:1. A control's edge is what says the
     control is there, and WCAG 1.4.11 asks 3:1 of it. */
  border: 1px solid var(--field-border);
  border-radius: 10px;
  background: var(--paper);
  transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
/* The old focus state removed the outline and leaned on an aqua border at
   1.4:1 plus a 3px aqua halo at 1.1:1 — visible on a bright screen, invisible
   on a dim one, and nothing at all to a keyboard user who needs the ring. */
.field input:focus-visible,
.field textarea:focus-visible,
.field select:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
  border-color: var(--link);
}
.field textarea { resize: vertical; min-height: 120px; }
.form-actions { display: flex; gap: 0.8rem; margin-top: 1.4rem; }
.form-note {
  font-size: 0.78rem; color: var(--muted); margin-top: 1rem; text-align: center;
}
.form-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }

/* embedded (non-modal) form card */
.form-card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(1.8rem, 1rem + 3vw, 3rem);
  box-shadow: var(--shadow-sm);
  max-width: 640px; margin: 0 auto;
}

/* --------------------------- Reveal anim ------------------------ */
/* Hidden only once <html> carries .js, which a one-line script in the head
   adds before anything paints. Without that gate a visitor with scripts off,
   or a main.js that fails to run, gets a page of invisible sections. */
.js .reveal { opacity: 0; transform: translateY(var(--reveal-rise)); transition: opacity var(--reveal-ms) var(--ease), transform var(--reveal-ms) var(--ease); }
.reveal.in { opacity: 1; transform: none; }
.reveal.d1 { transition-delay: var(--reveal-step); }                    /* one stagger step */
.reveal.d2 { transition-delay: calc(var(--reveal-step) * 2); }          /* two steps behind */
.reveal.d3 { transition-delay: calc(var(--reveal-step) * 3); }          /* three steps behind */
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
  .scroll-cue::after { animation: none; }
}

/* ---------------------------- Responsive ------------------------ */
@media (max-width: 900px) { /* --bp-desktop */
  :root {
    --split-media-ratio:   16 / 11; /* the portrait goes landscape once it stacks */
  }
  .split { grid-template-columns: 1fr; }
  .split__media { order: -1; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 720px) { /* --bp-mobile */
  :root {
    --footer-pad-top:          2.5rem; /* space above the footer on a phone */
    --footer-pad-bottom:       1.5rem; /* space under the fine print on a phone */
    --footer-grid-gap:           1rem; /* space between footer blocks once they stack */
    --footer-grid-gap-bottom:  1.6rem; /* space under the blocks, above the fine print, on a phone */
    --footer-brand-gap:             0; /* the wordmark shares a row with the social buttons, so no space under it */
    --footer-head-gap:         0.4rem; /* space under a column heading on a phone */
    --footer-link-gap:         0.2rem; /* rows are already finger-height on a phone; a hairline keeps two taps apart */
    /* The sub-line is legible now rather than 9.3px, which costs it width: at
       the desktop tracking it wraps to two lines under the wordmark on a
       phone. Tightened here rather than shrunk back, because the size is the
       point and the letter spacing is not. */
    --brand-sub-tracking:     0.055em; /* how spread out that line reads on a phone */
  }
  /* Four blocks stacked one under another ran to two phone screens. The
     wordmark and the social buttons share one row; the two link columns fold
     shut behind their headings and open into rows of chips; the contact links
     share two-column rows. */
  .footer-grid { grid-template-columns: 1fr; }
  .footer-grid > :first-child {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: var(--footer-brand-social-gap);
  }
  .footer-grid > :first-child .socials { margin-top: 0; }
  .footer-grid > :first-child p {
    grid-column: 1 / -1;
    margin: var(--footer-blurb-gap) 0 0;
  }
  .footer-col__fold { border-top: var(--footer-rule-width) solid rgba(255,255,255,0.12); }
  .footer-col__fold > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: var(--tap-comfort);
    pointer-events: auto;
    cursor: pointer;
  }
  .footer-col__fold > summary .footer-col__title { margin: 0; }
  .footer-col__fold > summary::after {
    content: "";
    width: var(--fold-chevron);
    height: var(--fold-chevron);
    margin-right: var(--fold-chevron-inset);
    border-right: var(--fold-chevron-stroke) solid var(--aqua);
    border-bottom: var(--fold-chevron-stroke) solid var(--aqua);
    transform: translateY(-25%) rotate(45deg);
    transition: transform var(--hover-ms) var(--ease);
  }
  .footer-col__fold[open] > summary::after { transform: translateY(25%) rotate(-135deg); }
  .footer-col__fold > nav { padding: var(--fold-pad-top) 0 var(--fold-pad-bottom); }
  .footer-col__fold .footer-links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--chip-gap);
  }
  .footer-col__fold .footer-links a {
    min-height: var(--tap-comfort);
    min-width: var(--chip-min-width);
    justify-content: center;
    border: var(--border-width) solid rgba(255,255,255,0.18);
    border-radius: var(--btn-radius);
    padding: 0 var(--chip-pad-x);
  }
  .footer-grid > :last-child .footer-links {
    grid-template-columns: var(--touch-cols);
    column-gap: var(--touch-col-gap);
  }
  .form-grid-2 { grid-template-columns: 1fr; }
}

/* =================================================================
   Phase 2–4 components
   Added for the cruise / all-inclusive / small-group rebuild.
   ================================================================= */

/* ------------------------- Skip link ---------------------------- */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--paper);
  color: var(--ink);
  padding: var(--skip-pad-y) var(--skip-pad-x);
  border-radius: 0 0 var(--radius) 0;
  font-weight: 500;
}
.skip-link:focus {
  left: 0;
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
}

/* ------------------------- Focus ring --------------------------- */
/* Every interactive thing on the site had been leaning on the browser's own
   focus ring. That ring is drawn in the UA's colour, not the site's, and the
   site puts controls on two very different grounds — links in the footer and
   the CTA band sit on deep purple, where a dark ring is close to invisible.
   So the ring is declared here, once, and flipped to white wherever the
   ground is dark.

   :where() holds this at zero specificity on purpose: the components that
   already draw their own ring (.zoom, .lightbox__close, .service-card,
   .faq__item summary) keep winning, and this only fills the gaps.

   :focus-visible, not :focus — a mouse click on a link should not leave a
   ring behind it. */
:where(a, button, summary, [tabindex], input, select, textarea):focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
}
:where(.site-footer, .section--deep, .hero, .page-hero, .post-hero, .cta-band,
       .trust-strip, .referral-banner)
  :where(a, button, summary, [tabindex]):focus-visible {
  outline-color: var(--focus-ring-on-dark);
}

/* ------------------------- Narrow measure ----------------------- */
.shell.narrow,
.narrow { max-width: 74ch; margin-inline: auto; }
.shell.narrow h2 { margin-top: 2.6rem; }
.shell.narrow h3 { margin-top: 1.8rem; }
.shell.narrow > .lede { font-size: 1.12rem; color: var(--muted); }

/* ------------------------- Trust strip -------------------------- */
.trust-strip {
  background: var(--brand);
  color: var(--ink-on-brand);
  padding: var(--trust-pad-y) 0;
}
.trust-strip ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--trust-gap-y) var(--trust-gap-x);
}
.trust-strip li {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--trust-item-gap);
}
/* Face, size and tracking for the credential names are set once in the brand
   typography block below. */
.trust-strip strong { color: var(--accent-bright); }
.trust-strip span { font-size: var(--trust-note-size); opacity: 0.85; }

/* ------------------------- Service cards ------------------------ */
.service-cards {
  display: grid;
  grid-template-columns: repeat(var(--service-cols), minmax(0, 1fr));
  gap: var(--service-gap);
}
.service-cards--pair {
  margin-top: var(--service-row-gap);
  grid-template-columns: repeat(var(--service-pair-cols), minmax(0, 1fr));
}

/* ways-to-travel puts all five trip types in a single grid. Five into three
   leaves two cards on the last row, hard against the left edge with a hole
   where the third would be. Counting the row in half-columns and giving every
   card a span of two lets the last row start one half-column in, which centres
   the pair under the three above at exactly the same card width — unlike
   .service-cards--pair, which makes its two cards wider.

   Only above --bp-cards. Below it --service-cols is 1 and there is nothing to
   centre, so the plain .service-cards rule takes over. */
@media (min-width: 901px) { /* just above --bp-cards */
  .service-cards--centered {
    grid-template-columns: repeat(var(--service-cols-half), minmax(0, 1fr));
  }
  .service-cards--centered > .service-card { grid-column: span 2; }
  .service-cards--centered > .service-card:nth-child(4) { grid-column: 2 / span 2; }

  /* The same trick for a .cards row, used by the five BOUND promise cards so
     they hang together the way the five trip cards do: three across, then two
     centred beneath rather than pushed to the left. The child selector is
     deliberately loose — .cards carries feature cards on some pages and
     media cards on others, and the centring does not care which. */
  .cards--centered {
    grid-template-columns: repeat(var(--cards-cols-half), minmax(0, 1fr));
  }
  .cards--centered > * { grid-column: span 2; }
  .cards--centered > :nth-child(4) { grid-column: 2 / span 2; }
}

.service-card {
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  box-shadow: var(--shadow-sm);
  transition: transform var(--card-hover-ms) var(--ease), box-shadow var(--card-hover-ms) var(--ease);
}
.service-card:hover,
.service-card:focus-visible {
  transform: translateY(calc(-1 * var(--service-lift)));
  box-shadow: var(--shadow);
}
/* No aspect-ratio here, deliberately. The width/height attributes on these
   <img> tags are presentational hints, and with no height declared in CSS the
   height hint wins over an aspect-ratio — so `aspect-ratio: 3/2` sat in this
   rule doing nothing while the cards rendered portrait at 0.64. A knob that
   moves no pixels is worse than no knob, so --service-image-ratio is gone too.
   The height attribute in pages/*.html is what sets the box; object-fit crops
   the photo into it. Giving the CSS the ratio back means adding `height: auto`,
   which shortens every card by ~300px — a redesign, not a fix. */
.service-card img {
  width: 100%;
  object-fit: cover;
  display: block;
}
.service-card__body {
  padding: var(--service-pad-top) var(--service-pad-x) var(--service-pad-bottom);
  display: flex;
  flex-direction: column;
  gap: var(--service-body-gap);
  flex: 1;
}
/* Card title size is set once in the brand typography block below. */
.service-card__body h3 { margin: 0; }
.service-card__body p { margin: 0; color: var(--muted); font-size: var(--service-text-size); }
.service-card .arrow {
  margin-top: auto;
  padding-top: var(--service-arrow-gap);
  color: var(--link);
  font-weight: 500;
  font-size: var(--service-arrow-size);
  letter-spacing: var(--service-arrow-tracking);
}
.service-card .arrow::after {
  content: " →";
  transition: margin-left var(--hover-fast) var(--ease);
  display: inline-block;
}
.service-card:hover .arrow::after { margin-left: var(--service-arrow-nudge); }

/* ------------------------- Real images in split ----------------- */
.split__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ------------------------- Process steps ------------------------ */
.process {
  list-style: none;
  counter-reset: step;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(var(--process-cols), minmax(0, 1fr));
  gap: var(--process-gap);
}
.process--detailed { grid-template-columns: repeat(var(--process-detailed-cols), minmax(0, 1fr)); }
.process li {
  counter-increment: step;
  position: relative;
  padding-top: var(--process-step-gap);
}
.process li::before {
  content: counter(step);
  position: absolute;
  top: 0;
  left: 0;
  width: var(--process-number-size);
  height: var(--process-number-size);
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--link);
  color: var(--link-contrast);
  font-family: var(--serif);
  font-size: var(--process-number-text);
  line-height: 1;
}
/* Step title size is set once in the brand typography block below. */
.process h3 { margin: 0 0 var(--process-title-gap); }
.process p { margin: 0; color: var(--muted); font-size: var(--process-text-size); }

/* ------------------------- Tick lists --------------------------- */
.tick-list { list-style: none; padding: 0; margin: 1.2rem 0; }
.tick-list li {
  position: relative;
  padding-left: 1.75rem;
  margin-bottom: 0.7rem;
}
.tick-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: var(--aqua);
}

/* ------------------------- Callout box -------------------------- */
.callout-box {
  background: var(--surface-tint);
  border-left: 3px solid var(--accent-bright);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: 1.3rem 1.6rem;
  margin: 2rem 0;
}
.callout-box h3 { margin: 0 0 0.5rem; font-size: 1.05rem; }
.callout-box p:last-child,
.callout-box ul:last-child { margin-bottom: 0; }
.callout-box ul { padding-left: 1.1rem; }
.callout-box li { margin-bottom: 0.5rem; }
.section--tint .callout-box { background: var(--paper); }

/* ------------------------- Credentials -------------------------- */
.credential-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: 1.5rem;
}
.credential {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.5rem 1.6rem;
}
.credential h3 { margin: 0 0 0.4rem; font-size: 1.15rem; color: var(--heading); }
.credential__what {
  font-size: 0.88rem;
  color: var(--muted);
  font-style: italic;
  margin: 0 0 0.8rem;
  padding-bottom: 0.8rem;
  border-bottom: 1px solid var(--line);
}
.credential p:last-child { margin-bottom: 0; font-size: 0.95rem; }

/* ------------------------- FAQ ---------------------------------- */
.faq { border-top: 1px solid var(--line); }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__item summary {
  cursor: pointer;
  padding: 1.1rem 2.5rem 1.1rem 0;
  font-weight: 500;
  font-size: 1.02rem;
  position: relative;
  list-style: none;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after {
  content: "+";
  position: absolute;
  right: 0.4rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 1.4rem;
  color: var(--link);
  line-height: 1;
  transition: transform 0.25s var(--ease);
}
.faq__item[open] summary::after { content: "−"; }
.faq__item summary:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 2px;
}
.faq__body { padding: 0 2.5rem 1.3rem 0; }
.faq__body p { margin: 0 0 0.7rem; color: var(--muted); font-size: 0.96rem; }
.faq__body p:last-child { margin-bottom: 0; }

/* ------------------------- Contact ------------------------------ */
.contact-methods {
  display: grid;
  grid-template-columns: repeat(var(--contact-cols), minmax(0, 1fr));
  gap: 1.5rem;
}
.contact-method {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.contact-method .icon {
  width: 2.4rem;
  height: 2.4rem;
  color: var(--link);
  margin-bottom: 0.3rem;
}
.contact-method .icon svg { width: 100%; height: 100%; }
.contact-method h2 { margin: 0; font-size: 1.2rem; }
.contact-method p { margin: 0; color: var(--muted); font-size: 0.93rem; }
.contact-method__link {
  margin-top: auto;
  padding-top: 0.6rem;
  font-weight: 500;
  color: var(--link);
  word-break: break-word;
}
.socials--lg { justify-content: center; }
.socials--lg a { width: 2.9rem; height: 2.9rem; }

/* ------------------------- CTA band extras ---------------------- */
.cta-band__actions {
  display: flex;
  gap: var(--cta-actions-gap);
  flex-wrap: wrap;
  justify-content: center;
}
.cta-band__direct {
  margin-top: var(--cta-direct-gap);
  font-size: var(--cta-direct-size);
  opacity: 0.9;
}
/* nowrap so a phone number never splits across two lines on a narrow screen —
   the line breaks between the address and the number instead. */
.cta-band__direct a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: var(--cta-direct-underline);
  white-space: nowrap;
}
.cta-band__direct span { margin: 0 var(--cta-direct-dot-space); }

/* ------------------------- Referral ----------------------------- */
.referral-banner {
  background: var(--brand);
  color: var(--ink-on-brand);
  padding: var(--referral-pad-y) 0;
}
.referral-banner .shell {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--referral-gap);
  flex-wrap: wrap;
  text-align: center;
}
.referral-banner p { margin: 0; font-size: var(--referral-text-size); }
.referral-banner strong { color: var(--accent-bright); }
.referral-banner .btn--outline { border-color: rgba(255,255,255,0.5); color: var(--ink-on-brand); }
.referral-banner .btn--outline:hover { background: rgba(255,255,255,0.12); }

.referral-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: 1.5rem;
}
.referral-action {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.referral-action h3 { margin: 0; font-size: 1.12rem; }
.referral-action p { margin: 0; color: var(--muted); font-size: 0.94rem; flex: 1; }
.referral-action .btn { align-self: flex-start; }

.btn--sm { padding: var(--btn-sm-pad-y) var(--btn-sm-pad-x); font-size: var(--btn-sm-size); }

/* ------------------------- Journal ------------------------------ */
.journal-planned { list-style: none; padding: 0; margin: 1.5rem 0 0; }
.journal-planned li {
  padding: 1.2rem 0;
  border-bottom: 1px solid var(--line);
}
.journal-planned li:first-child { border-top: 1px solid var(--line); }
.journal-planned h3 { margin: 0 0 0.35rem; font-size: 1.08rem; }
.journal-planned p { margin: 0; color: var(--muted); font-size: 0.94rem; }

/* ------------------------- Mobile CTA in menu ------------------- */
.nav-cta-mobile { display: none; }

@media (max-width: 720px) { /* --bp-mobile */
  :root {
    --trust-gap-x:          1.5rem; /* credentials pack tighter across a phone */
    --referral-gap:        0.85rem; /* space between referral text and its button */
    --process-step-gap:          0; /* the number moves beside the step, not above it */
  }
  .process li { padding-left: var(--process-indent); }
  .process li::before { top: var(--process-number-rise); }
  .referral-banner .shell { flex-direction: column; }
}

/* ------------------------- Card rows ---------------------------- */
/* These grids used auto-fit with a pixel floor, which lets the space available
   decide the column count — and at mid widths that left a row of one: three
   trip cards came out two-and-one, four steps three-and-one. The counts are
   explicit now, and step down at the widths where the cards would otherwise be
   too narrow to read. The rule throughout: a row never holds a single card. */
@media (max-width: 1100px) { /* --bp-process, --bp-contact */
  :root {
    --process-cols:                 2; /* four steps go two by two */
    --contact-cols:                 2; /* contact cards go two by two */
  }
}
@media (max-width: 900px) { /* --bp-cards */
  :root {
    --service-cols:                 1; /* trip cards stack rather than orphan one */
    --service-pair-cols:            1; /* the two-card row stacks with them */
    --cards-cols:                   1; /* feature cards stack */
    --quotes-cols:                  1; /* quotes stack */
    --process-cols:                 1; /* steps stack */
    --process-detailed-cols:        1; /* the five-step version stacks */
    --contact-cols:                 1; /* contact cards stack */
  }
  /* Stacked cards take their photo shape from --service-image-ratio. height:auto
     is what lets the ratio apply at all: the height attribute on the <img> is a
     presentational hint that otherwise wins, which is how these cards came to
     draw a 533px portrait photo in a 350px column. */
  .service-card img { height: auto; aspect-ratio: var(--service-image-ratio); }
}

/* ------------------------- Nav fit ------------------------------ */
/* Six nav items plus a pinned CTA is tight at mid widths: without this
   "Ways to Travel" and "How I Work" wrap onto two lines. */
.nav-links a { white-space: nowrap; }
.nav-cta .btn { white-space: nowrap; }
.nav .brand > span { white-space: nowrap; }
.nav .brand { flex-shrink: 0; }
/* Bebas is a condensed caps face, so one long word — CONGRATULATIONS,
   HONEYMOONS — comes out wider than a phone column at the sizes the desktop
   curve asks for, and it was pushing pages sideways. Below --bp-phone the
   headlines follow a lower, steeper curve that meets the desktop one exactly
   at 480px, so nothing jumps as the window crosses the breakpoint. */
@media (max-width: 480px) { /* --bp-phone */
  /* Scoped to the stand-in face: main.js adds .display-face-ready once Bebas is
     confirmed loaded, and these sizes drop away because Bebas is narrow enough
     not to need them. Without JS, or with the webfont blocked, the smaller
     sizes stay — which is exactly the case that needs them. */
  :root:not(.display-face-ready) {
    --h2-size-min:            1.2rem; /* floor, low enough that the curve below governs */
    --h2-size-base:          -0.2rem; /* negative: the width term carries the size here */
    --h2-size-vw:              8.4vw; /* how fast section headings grow across phones */
    --page-hero-title-min:    1.5rem; /* floor, low enough that the curve below governs */
    --page-hero-title-base:   0.1rem; /* fixed part of the phone headline size */
    --page-hero-title-vw:     9.25vw; /* how fast that headline grows across phones */
  }
  /* Address and phone get a line each on a phone, so the dot between them has
     nothing left to separate. */
  .cta-band__direct {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--cta-direct-stack-gap);
  }
  .cta-band__direct span { display: none; }
}

/* The nav lockup no longer carries a sub-line at any width — build.py stopped
   emitting one. It drew at 9.3px, the smallest text on the site by a wide
   margin and well under Apple's 10pt desktop floor, and the nav could not
   afford to grow it: six links, a wordmark and a pinned CTA already need about
   970px of pill. It was also already being hidden in two of the four width
   bands it could appear in, which is its own argument. The footer keeps it,
   at a size the footer has room for. */
@media (max-width: 400px) { /* --bp-phone-narrow */
  :root {
    --brand-size:            1.05rem; /* wordmark size on a small phone */
  }
}
@media (max-width: 1180px) and (min-width: 1001px) { /* --bp-nav-tight down to --bp-nav-menu */
  :root {
    --nav-link-gap:       1.05rem; /* links pack tighter before the menu appears */
    --nav-link-size:      0.74rem; /* nav link size at that tight width */
    --nav-link-tracking:   0.09em; /* how spread out the links read there */
  }
  .nav-cta .btn {
    padding: var(--nav-cta-pad-y) var(--nav-cta-pad-x);
    font-size: var(--nav-cta-size);
  }
}

/* =================================================================
   Brand typography — Bebas Neue display face
   Bebas is caps-only, single-weight and condensed, so headings need
   more size, tighter leading and a little tracking to sit correctly.
   ================================================================= */
h1, h2, h3, h4,
.brand,
.stat .num {
  font-family: var(--display);
  font-weight: 400;
  letter-spacing: var(--heading-tracking);
  line-height: var(--heading-leading);
}
h1 { letter-spacing: var(--h1-tracking); }
h3, h4 { letter-spacing: var(--h3-tracking); line-height: var(--subhead-leading); }

/* Bebas runs ~15% narrower than the serif it replaces — size up to keep
   the same optical weight in the layout. The hero headline is sized in the
   hero rule above; everything else that carries a heading is sized here. */
.section-head h2,
.split h2,
.cta-band h2 {
  font-size: clamp(var(--h2-size-min), var(--h2-size-base) + var(--h2-size-vw), var(--h2-size-max));
}
/* Trip cards, feature cards and process steps share one title step. Merged
   from three identical knobs on 24 August 2026, at the author's request. */
.card h3,
.service-card__body h3,
.process h3 { font-size: var(--card-title-size); letter-spacing: var(--card-title-tracking); }
.page-hero h1 {
  font-size: clamp(var(--page-hero-title-min),
                   var(--page-hero-title-base) + var(--page-hero-title-vw),
                   var(--page-hero-title-max));
}
/* Inner pages only — these components do not appear on the homepage. */
.shell.narrow h2 { font-size: clamp(1.9rem, 1.5rem + 1.6vw, 2.6rem); }
.shell.narrow h3 { font-size: 1.45rem; }
.credential h3,
.contact-method h2,
.referral-action h3,
.journal-planned h3 { font-size: 1.35rem; letter-spacing: 0.035em; }
.stat .num      { font-size: clamp(2.6rem, 2rem + 2vw, 3.6rem); letter-spacing: 0.01em; }

/* Script accent. Bebas has no lowercase, so the script word carries the only
   lowercase on the page — keep it obviously different, not just italic. */
.script {
  font-family: var(--script);
  text-transform: none;
  letter-spacing: 0;
  color: var(--aqua);
}
/* In the hero the script word stays a full-width second line — it is sized
   with the rest of the hero above. Everywhere else it sits inline, optically
   levelled against the caps. */
h2 .script, h3 .script {
  display: inline-block;
  font-size: var(--script-inline-size);
  line-height: var(--script-inline-leading);
  transform: translateY(var(--script-inline-lift));
}

/* Brand lockup in the nav / footer */
.brand { gap: var(--brand-gap); letter-spacing: var(--brand-tracking); }
.brand > span { font-size: var(--brand-size); line-height: var(--brand-leading); }
.brand small {
  font-family: var(--sans);
  letter-spacing: var(--brand-sub-tracking);
  font-weight: 400;
  /* No opacity here on purpose. This line draws at 9.3px, and dimming it to
     85% took it to 2.2:1 over the hero photo. The size is part of the locked
     nav fit — six links, a wordmark and a CTA in one pill — so contrast is
     bought back by dropping the dimming rather than by growing the text. */
}
.brand .mark {
  width: var(--brand-mark-width);
  height: var(--brand-mark-height);
  display: grid;
  place-items: center;
}
.brand .mark img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* Body face */
body { font-family: var(--sans); font-weight: var(--body-weight); }
strong, b { font-weight: 600; }
.btn { font-family: var(--sans); font-weight: 500; letter-spacing: var(--btn-tracking); }
.eyebrow { font-family: var(--sans); font-weight: 500; letter-spacing: var(--eyebrow-tracking); }
.trust-strip strong {
  font-family: var(--display);
  font-size: var(--trust-name-size);
  letter-spacing: var(--trust-name-tracking);
}
.faq__item summary { font-family: var(--sans); font-weight: 500; }

/* Accent underline on the active nav item + link hovers uses brand aqua */
/* The active link takes --link, not a rose. Rose was picked as AA against
   white, but the pill is frosted glass over a photograph, never white: rose
   measured 2.1:1 there and cannot be rescued at this size. The aqua underline
   below is what actually marks the active item, so the state never rests on
   colour alone (WCAG 1.4.1). */
.nav-links a.active { color: var(--link); font-weight: 500; }
.nav-links a::after { background: var(--aqua); height: var(--nav-underline-height); }

/* The headshot is cut to the brand hexagon, on every page that shows it.
   The 2026 photograph is an opaque square, so the shape is done in CSS rather
   than baked into the file the way the old hexagon PNG was — one asset, and
   changing the shape never means re-exporting the photo.

   No card, no shadow, no radius: box-shadow is drawn on the border box and
   ignores clip-path, so a shadow here would hang behind the hexagon as a
   rectangle. */
.split__media.is-hex {
  background: none;
  box-shadow: none;
  border-radius: 0;
  overflow: visible;
  aspect-ratio: var(--media-card-ratio);
}
.split__media.is-hex img {
  clip-path: var(--hex-clip);
  object-fit: cover;
}

/* The older brand headshot is a hexagon with transparent corners — no crop, no
   card, or the transparency reads as a chipped rectangle. Nothing live uses
   this now; it is kept for the fuller page versions parked in pages/_full/,
   which still reference it. */
.split__media.is-portrait {
  background: none;
  box-shadow: none;
  border-radius: 0;
  aspect-ratio: var(--split-portrait-ratio);
  padding: var(--split-portrait-pad) 0;
  display: grid;
  place-items: center;
}
.split__media.is-portrait img { object-fit: contain; }

/* Primary CTA: solid brand rose. It has to read as the action on both the
   white sections and the purple bands, which an aqua→rose gradient did not. */
.btn--primary { --btn-bg: var(--rose); --btn-fg: #ffffff; }
.btn--primary:hover { --btn-bg: var(--rose-deep); }
.btn--outline { --btn-fg: var(--link); border-color: var(--link); }
.btn--outline:hover { background: var(--link); color: var(--link-contrast); }

/* The brand guide sets headings in all caps. Bebas has no lowercase glyphs so
   it caps them anyway — declaring it explicitly keeps the intent if the
   webfont fails to load. */
h1, h2 { text-transform: uppercase; }
.brand > span { text-transform: uppercase; }

/* ------------------------- Mobile nav fixes --------------------------- */
/* The header is position:fixed with a translateX(-50%) centring transform, so
   it becomes the containing block for its own fixed children. The closed
   slide-in panel therefore parks against the header's inset edge rather than
   the viewport edge, leaving a visible sliver. Push it clear of that inset. */
@media (max-width: 720px) { /* --bp-mobile */
  /* The hero CTAs collide with the decorative scroll cue once the headline
     wraps to four lines. The cue is ornamental — drop it on small screens. */
  .scroll-cue { display: none; }
}

/* ------------------------- Menu (dropdown) --------------------------- */
/* Six links, a wordmark and a pinned CTA need about 970px of pill to sit in a
   row — and that is measured in the stand-in sans, which is the widest the nav
   ever gets. Below --bp-nav-menu they become a dropdown instead. This is a
   wider switch than the content breakpoint on purpose: the nav runs out of room
   long before the columns do.

   The header uses backdrop-filter, which — like a transform — makes it the
   containing block for any position:fixed descendant. A full-height slide-in
   panel therefore collapsed to the header's own 60px box. Rather than fight
   that, the menu is a dropdown anchored under the floating pill, which suits
   the header shape better anyway. */
@media (max-width: 1000px) { /* --bp-nav-menu */
  .nav-toggle { display: block; }
  .nav-cta .btn { display: none; }
  /* The pinned header CTA is hidden here, so surface the same action inside
     the dropdown rather than losing it entirely. */
  .nav-cta-mobile { display: block; margin-top: var(--menu-cta-gap-top); }
  .nav-cta-mobile .btn { display: inline-block; }
  .nav-links {
    position: absolute;
    /* Right-aligned under the pill and capped: stretched across a 1000px pill
       it read as a phone menu blown up. On a phone the pill is narrower than
       the cap, so it still fills the width. */
    inset: auto 0 auto auto;
    top: calc(100% + var(--menu-offset));
    width: min(var(--menu-width), 100%);
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: var(--menu-item-gap);
    background: var(--paper);
    border: var(--border-width) solid var(--line);
    border-radius: var(--menu-radius);
    padding: var(--menu-pad-top) var(--menu-pad-x) var(--menu-pad-bottom);
    box-shadow: 0 var(--menu-shadow-y) var(--menu-shadow-blur) var(--menu-shadow-spread) rgba(30, 14, 70, 0.55);
    transform: translateY(calc(-1 * var(--menu-rise)));
    opacity: 0;
    visibility: hidden;
    /* visibility switches instantly, delayed only on the way OUT so the panel
       stays rendered while it fades. Transitioning visibility over the whole
       duration instead left it computing to hidden for the first quarter
       second of opening — long enough that a link inside it could not take
       focus yet, which is why moving focus into the menu silently did nothing.
       Delay-on-close is the idiom precisely because it keeps the open panel
       focusable from frame one. */
    transition: opacity var(--hover-fast) var(--ease), transform var(--hover-fast) var(--ease),
      visibility 0s linear var(--hover-fast);
  }
  body.nav-open .nav-links {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity var(--hover-fast) var(--ease), transform var(--hover-fast) var(--ease),
      visibility 0s linear 0s;
  }
  /* The page used to keep scrolling behind the open dropdown, which drags the
     menu off the pill it is anchored to and leaves the reader somewhere they
     did not ask to be. Locked here rather than globally: above --bp-nav-menu
     there is no dropdown to scroll behind. main.js pays back the width of the
     scrollbar this removes so nothing shifts sideways as it locks. */
  body.nav-open {
    /* main.js pins the body with position: fixed and its own offset — the only
       lock iOS Safari reliably honours. overflow: hidden stays as the no-JS
       fallback, and padding-right pays back the width of the scrollbar the
       lock removes so nothing shifts sideways. */
    position: fixed;
    left: 0;
    right: 0;
    width: 100%;
    overflow: hidden;
    padding-right: var(--scrollbar-width, 0px);
  }
  .nav-links a {
    display: block;
    color: var(--ink);
    padding: var(--menu-link-pad-y) 0;
    font-size: var(--menu-link-size);
    border-bottom: var(--border-width) solid var(--line);
  }
  .nav-links li:last-of-type a { border-bottom: none; }
  .nav-cta-mobile { border-bottom: none; padding-top: var(--menu-cta-gap); }
  .nav-cta-mobile .btn { display: flex; width: 100%; justify-content: center; }
  .nav-cta-mobile a { border-bottom: none; padding: var(--btn-pad-y) var(--btn-pad-x); }
}

/* ------------------------- Hero fit ----------------------------------- */
/* The scroll cue is decorative and the hero CTAs are not: on a short window
   (a 13" laptop at 1280x800) the cue is what gives way. */
@media (max-height: 900px) { /* --bp-short */
  .scroll-cue { display: none; }
}

/* =================================================================
   Journal — index cards and article layout
   ================================================================= */
.post-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1.5rem; }
.post-card {
  display: grid;
  grid-template-columns: 260px 1fr;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease);
}
.post-card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.post-card__media { display: block; }
.post-card__media img { width: 100%; height: 100%; object-fit: cover; }
.post-card__body { padding: 1.4rem 1.6rem; display: flex; flex-direction: column; gap: 0.5rem; }
.post-card__meta {
  margin: 0;
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.post-card h3 { margin: 0; font-size: 1.35rem; letter-spacing: 0.03em; }
.post-card h3 a { color: var(--ink); }
.post-card:hover h3 a { color: var(--link); }
.post-card p { margin: 0; color: var(--muted); font-size: 0.94rem; }
.post-card .arrow { margin-top: auto; padding-top: 0.4rem; color: var(--link); font-weight: 500; font-size: 0.88rem; }
.post-card .arrow::after { content: " →"; }

/* ------------------------- Article ------------------------------ */
.post-hero {
  background: var(--purple);
  color: #fff;
  padding: calc(4.5rem + 4vw) 0 3rem;
}
.post-hero h1 { color: #fff; margin: 0.35em 0 0.4em; font-size: clamp(2.2rem, 1.6rem + 2.6vw, 3.6rem); }
.post-hero .shell.narrow > .lede,
.post-hero .lede {
  /* Specific enough to beat `.shell.narrow > .lede`, which is one class heavier
     than a plain `.post-hero .lede` and was painting this --muted — a grey
     meant for paper — on the hero's purple, at 1.98:1. */
  color: var(--ink-on-dark-soft);
  font-size: 1.1rem;
  margin: 0;
}
.post-hero__meta {
  margin: 0;
  font-size: 0.76rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--aqua);
}
.post-hero__meta a { color: var(--aqua); text-decoration: underline; text-underline-offset: 3px; }

.post-body { padding-block: 3rem 1rem; }
.post-body h2 { margin: 2.6rem 0 0.6rem; font-size: clamp(1.7rem, 1.4rem + 1.4vw, 2.3rem); }
.post-body h3 { margin: 1.8rem 0 0.5rem; }
.post-body p { margin: 0 0 1.15em; }
.post-body > p:first-of-type { font-size: 1.08rem; }
.post-body ol { padding-left: 1.2rem; }
.post-body ol li { margin-bottom: 0.55rem; }
.post-figure { margin: 0 0 2rem; }
.post-figure img { width: 100%; border-radius: var(--radius); }
.post-figure figcaption {
  margin-top: 0.6rem;
  font-size: 0.85rem;
  color: var(--muted);
  text-align: center;
}

@media (max-width: 680px) {
  .post-card { grid-template-columns: 1fr; }
  .post-card__media img { aspect-ratio: 16 / 9; }
}
.post-card__media img { object-position: center 55%; }

/* =================================================================
   Tap targets
   -----------------------------------------------------------------
   WCAG 2.5.5 asks for 44x44 on every control. Twenty-six of them were
   under it: the hamburger at 30x24, the social circles at 40x40, the
   brand lockups at 42px tall, and every footer link at its 16px line
   box.

   Two techniques, chosen per element:

   1. An invisible centred ::before on controls whose drawn size is
      part of the design (hamburger, social circles). The art keeps
      its exact dimensions; only the hit box grows. The gaps around
      both are wider than the expansion, so no two targets overlap —
      overlapping hit areas cause mis-taps and are worse than small
      ones.

   2. A grown row height on text links, under --bp-tap only. An
      overlay will not work there: --footer-link-gap is 0.55rem, so a
      44px overlay on each link would collide with its neighbours.
      Growing the row is the honest fix, and confining it to narrow
      windows leaves the locked desktop footer untouched.

   Verified by tools/audit's tap-targets detector, which hit-tests the
   rendered page rather than reading boxes off the stylesheet — so it
   sees technique 1 as the real fix it is.
   ================================================================= */

/* --- 1. Overlay: drawn size unchanged, hit box grown --- */
.nav-toggle,
.socials a { position: relative; }

.nav-toggle::before,
.socials a::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--tap-min);
  height: var(--tap-min);
  transform: translate(-50%, -50%);
  /* Purely a hit area. No paint, and it must never intercept the
     pointer from an ancestor that legitimately sits above it. */
  background: transparent;
}

/* The bars are absolutely positioned against the button, so the
   overlay must not become their containing block reference point. It
   does not — ::before is a sibling, not an ancestor — but the bars
   need to stay above it in paint order to remain visible. */
.nav-toggle span { z-index: 1; }
.socials svg { position: relative; z-index: 1; }

/* --- 2. Grown rows on touch-sized windows --- */
@media (max-width: 1000px) { /* --bp-tap */
  /* Footer rows fill their column: "Home" and "Refer" are only ~38px of text,
     so a height-only fix still leaves them narrower than a fingertip. The row
     paints nothing, so a wider hit area is invisible. */
  .footer-links a {
    display: flex;
    align-items: center;
    min-height: var(--tap-min);
  }

  /* Links that stand alone on their own line — the "More on ... ->"
     continuations and the fine-print row. Not prose: nothing sits beside them
     on the line, so growing them costs no leading. */
  .footer-bottom a,
  .cta-band__direct a,
  .contact-method__link,
  .link-cta,
  .inline-links a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap-min);
  }

  /* The brand lockups draw at 42px and stay there. Growing them to 44 pushed
     the floating pill from 57px to 59px, and the pill's height is part of a
     locked design. They are exempt rather than overlooked: the lockup is the
     home link, the menu carries its own "Home" entry, and tools/audit records
     the exemption with that reason instead of quietly passing them. */

  /* Menu rows land at ~42px from their padding alone. */
  .nav-links a {
    display: flex;
    align-items: center;
    min-height: var(--tap-min);
  }

  /* A button label that wraps to one short line can still fall under
     the bar even though the button looks generous. */
  .btn { min-height: var(--tap-min); }

  /* A journal title is an inline link over one to three ragged line boxes, so
     the corners of the block it appears to occupy are not actually part of it —
     and a one-line title is only 26px tall regardless. As a flex box it becomes
     the solid rectangle it already looks like, and the whole title is tappable
     whether it wraps or not. */
  .post-card h3 a {
    display: flex;
    align-items: center;
    min-height: var(--tap-min);
  }
}

/* A photo that never arrived. main.js adds this when an image fails to decode,
   after moving its alt text to a title. A quiet brand tile reads as a
   deliberate blank; a sentence of alt text splashed across a card reads as a
   broken site. The box keeps its reserved size either way. */
.img-missing {
  background: linear-gradient(135deg, var(--surface-tint), var(--pink-soft));
  object-fit: cover;
}
