/* ============================================================================
   TRAVELYFE — premium marketing one-pager
   Brand system lifted from the app's Theme.swift: British Racing Green #185542,
   warm Gold #FFBF00 highlight, photo-forward white surfaces, ink #12150F, and
   LIVVIC throughout (Black for display, Medium/SemiBold for body) — exactly the
   app's fonts and colours, with a floating glass navbar (AHMEDMEDIAGROUP house
   pattern) and a travel-route layout.
   ============================================================================ */

/* ── Livvic, self-hosted ─────────────────────────────────────────────────────
   This page used to fetch the family from fonts.googleapis.com while the app,
   on the same domain, loaded the same five faces from /fonts. One family, two
   sources, and the marketing side's copy was a render-blocking stylesheet on a
   third-party origin — fetched on arrival, before the consent banner it sits
   above had asked anybody anything, and handing Google the IP address of every
   visitor to the front page in order to do it.

   WOFF2 rather than the TTFs the app declares: same five files through
   scripts/build-fonts.py, 512KB of TTF down to 175KB, no subsetting. Livvic
   covers Latin, Latin Extended and Vietnamese, and this site publishes
   itineraries in all three — a subsetter told only about Latin would strip the
   diacritics out of the Vietnamese ones.

   `swap` on every face, so a font that never arrives costs nothing but its
   fallback. The fallback stack is the same one the app names, which is what
   keeps the reflow to a weight change rather than a relayout.
   ──────────────────────────────────────────────────────────────────────────── */
@font-face { font-family: Livvic; font-weight: 400; font-style: normal; font-display: swap;
             src: url("/fonts/Livvic-Regular.woff2") format("woff2"),
                  url("/fonts/Livvic-Regular.ttf") format("truetype"); }
@font-face { font-family: Livvic; font-weight: 500; font-style: normal; font-display: swap;
             src: url("/fonts/Livvic-Medium.woff2") format("woff2"),
                  url("/fonts/Livvic-Medium.ttf") format("truetype"); }
@font-face { font-family: Livvic; font-weight: 600; font-style: normal; font-display: swap;
             src: url("/fonts/Livvic-SemiBold.woff2") format("woff2"),
                  url("/fonts/Livvic-SemiBold.ttf") format("truetype"); }
@font-face { font-family: Livvic; font-weight: 700; font-style: normal; font-display: swap;
             src: url("/fonts/Livvic-Bold.woff2") format("woff2"),
                  url("/fonts/Livvic-Bold.ttf") format("truetype"); }
@font-face { font-family: Livvic; font-weight: 900; font-style: normal; font-display: swap;
             src: url("/fonts/Livvic-Black.woff2") format("woff2"),
                  url("/fonts/Livvic-Black.ttf") format("truetype"); }

:root {
  /* ══════════════════════════════════════════════════════════════════════════
     Every value below is transcribed from the app's Theme.swift / DesignKit
     Metrics, light appearance. The website is not "in the same style" as the
     app — it is the same design system, so a token that moves in Theme.swift
     is a token that must move here.
     ══════════════════════════════════════════════════════════════════════════ */

  /* ── Ink / neutrals ── */
  --ink:          #121510;              /* Theme.ink */
  --on-ink:       #ffffff;              /* Theme.onInk */
  --ink-2:        rgba(18, 21, 16, 0.66); /* Theme.inkSecondary */
  --ink-3:        rgba(18, 21, 16, 0.62); /* Theme.inkTertiary — 5.15:1 on surface */
  --ink-faded:    rgba(18, 21, 16, 0.33); /* Theme.inkFaded */

  /* ── Surfaces ── */
  --bone:         #ffffff;              /* Theme.bone */
  --surface:      #ffffff;              /* Theme.surface */
  --mist:         #f1f3f0;              /* Theme.mist */
  --raised-fill:  linear-gradient(to bottom, #ffffff, #ffffff);  /* Theme.raisedFill */
  --raised-edge:  rgba(0, 0, 0, 0.05);  /* Theme.raisedEdge */
  --hairline:     rgba(18, 21, 16, 0.07); /* Theme.hairline */
  --on-image-hairline: rgba(0, 0, 0, 0.08);

  /* ── Brand green ── */
  --brand:        #185542;              /* Theme.brand */
  --brand-raised: #226953;              /* Theme.brandRaised — top of brandFill */
  --brand-fill:   linear-gradient(to bottom, #226953, #185542); /* Theme.brandFill */
  --brand-soft:   rgba(24, 85, 66, 0.10); /* Theme.brandSoft */
  --on-brand:     #ffffff;              /* Theme.onBrand */
  --racing-deep:  #06281e;              /* Theme.racingDeep */
  --splash-top:   #1c614c;              /* Theme.splashTop */
  --top-light:    linear-gradient(to bottom, rgba(255,255,255,0.10) 0%, rgba(255,255,255,0) 60%);

  /* ── Dither ──────────────────────────────────────────────────────────────────
     A tile of monochrome fractal noise at 4.5% alpha, laid over the page's long
     gradients as their topmost background layer.

     It is there because sRGB is eight bits and this page ramps green across most
     of a screen. Measured off a 3024px capture: the ramp held single colour values
     for runs of 6 to 22 pixels at a time, which is a step every 3 CSS pixels on a
     2x display — not a smooth gradient, a stack of stripes. No arrangement of
     colour stops fixes that, because the limit is the bit depth and not the maths;
     dithering is the fix, and it is what every image encoder does for the same
     reason. The noise breaks each flat run into two neighbouring values that the
     eye integrates back into the colour that was wanted.

     Declared once, here, and used by `body` and `.launch-bg` — the two elements
     that paint a gradient tall enough to band. 4.5% is the level at which the
     stripes disappear and the texture itself does not become visible; it reads as
     grain on a photograph rather than as an effect. */
  --dither: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.045'/%3E%3C/svg%3E");

  /* ── Accent — yellow has ONE job in the app: value, not state ── */
  --accent:       #ffbf00;              /* Theme.accent */
  --on-accent:    #1a1d14;              /* Theme.onAccent */
  --gold:         #f29e12;              /* Theme.gold — amber, for gold meaning */

  /* ── Status ── */
  --success:      #339e5c;
  --warning:      #d98c1a;
  --danger:       #cc2e29;

  /* ── On photography / tint ── */
  --on-tint:      #ffffff;
  --on-tint-2:    rgba(255, 255, 255, 0.95);
  --on-tint-3:    rgba(255, 255, 255, 0.78);
  --on-tint-fill: rgba(255, 255, 255, 0.18);
  --on-tint-fill-subtle: rgba(255, 255, 255, 0.14);

  /* ── Radii — Theme.corner* ── */
  --r-xl:   28px;
  --r-lg:   22px;
  --r-md:   16px;
  --r-sm:   12px;
  --r-tiny: 2px;
  --r-pill: 999px;

  /* ── Borders — Theme.border* ── */
  --b-hairline: 0.5px;
  --b-thin:     0.75px;
  --b-regular:  1px;
  --b-thick:    1.2px;
  --b-heavy:    1.5px;
  --b-xheavy:   2px;

  /* ── Elevation — Theme.Shadow. SwiftUI's shadow radius is a blur sigma, so
     the CSS blur is 2x it; x/y offsets carry over unchanged. ── */
  --sh-hairline:   0 1px 4px rgba(0, 0, 0, 0.06);
  --sh-raised:     0 3px 16px rgba(0, 0, 0, 0.05);
  --sh-card:       0 12px 40px rgba(0, 0, 0, 0.09);
  --sh-control:    0 4px 16px rgba(0, 0, 0, 0.07);
  --sh-button:     0 6px 24px rgba(0, 0, 0, 0.14);
  --sh-chip-rest:  0 3px 12px rgba(0, 0, 0, 0.06);
  --sh-chip-sel:   0 3px 12px rgba(0, 0, 0, 0.16);
  --sh-chip-image: 0 3px 16px rgba(0, 0, 0, 0.22);
  --sh-floating:   0 8px 32px rgba(0, 0, 0, 0.12);
  --sh-overlay:    0 6px 24px rgba(0, 0, 0, 0.20);
  --sh-text-image: 0 1px 8px rgba(0, 0, 0, 0.28);
  --sh-hero-text:  0 3px 20px rgba(0, 0, 0, 0.35);

  /* ── Spacing — Metrics.s* ── */
  --s2: 2px;  --s4: 4px;   --s6: 6px;   --s8: 8px;   --s10: 10px;
  --s12: 12px; --s14: 14px; --s16: 16px; --s20: 20px; --s24: 24px;
  --s28: 28px; --s32: 32px; --s40: 40px; --s56: 56px;

  /* ── Control metrics — Metrics.* ── */
  --button-h:     56px;   /* Metrics.buttonHeight */
  --control-h:    46px;   /* Metrics.controlHeight */
  --tap:          44px;   /* Metrics.minTapTarget */
  --icon-col:     28px;   /* Metrics.iconColumn */
  --field-icon:   22px;   /* Metrics.fieldIconWidth */
  --card-inset:   18px;   /* Metrics.cardInset */
  --field-pad-y:  14px;   /* Metrics.fieldVerticalPadding */
  --row-pad-y:    14px;   /* Metrics.rowVerticalPadding */

  /* ── Motion — Theme.Duration / Theme.Motion ── */
  --d-micro:     120ms;
  --d-quick:     150ms;
  --d-standard:  200ms;
  --d-moderate:  250ms;
  --d-slow:      300ms;
  --dur:         200ms;             /* = standard */
  --ease:        cubic-bezier(0.42, 0, 0.58, 1);  /* easeInOut */
  --ease-out:    cubic-bezier(0, 0, 0.58, 1);     /* easeOut */
  --ease-in:     cubic-bezier(0.42, 0, 1, 1);     /* easeIn */
  --spring:      cubic-bezier(0.34, 1.4, 0.64, 1);

  /* ── Opacity — Theme.*Opacity ── */
  --o-disabled:       0.5;
  --o-pressed-strong: 0.9;
  --o-pressed-soft:   0.8;

  /* ── Type — Theme.Font.Display is a FOUR-step scale: 32/28/22/20.
     The web keeps those as the floor and scales up for wide viewports; the
     face and weight do not change, because that is what makes it read as the
     app. Display = Livvic Bold (700) by default, Black (900) only where the
     app passes weight: .bold. ── */
  --t-page:       clamp(32px, 5.2vw, 58px);
  --t-sheet:      clamp(28px, 3.6vw, 40px);
  --t-section:    clamp(22px, 2.4vw, 30px);
  --t-subsection: 20px;
  --t-body:       16px;
  --t-body-sm:    15px;
  --t-caption:    13px;
  --t-eyebrow:    11px;

  /* ── Layout (web only — the app has no equivalent) ── */
  --container: 1200px;
  --gutter:    clamp(1.15rem, 4vw, 2.25rem);
  --nav-h:     56px;
  --nav-offset: 16px;

  /* ── Fonts — Livvic, the app's face (Theme.Font.livvic) ── */
  --sans:    "Livvic", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --display: "Livvic", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* ── Legacy aliases, so layout rules further down keep resolving ── */
  --forest: var(--brand); --forest-700: #0e4a38; --forest-bright: var(--brand);
  --forest-deep: var(--racing-deep); --paper: var(--surface);
  --forest-tint: var(--brand-soft); --forest-tint-border: rgba(24, 85, 66, 0.16);
  --gold-soft: rgba(255, 191, 0, 0.22); --sand: var(--mist);
  --hairline-strong: rgba(18, 21, 16, 0.14);
  --on-photo: var(--on-tint-2);
  --shadow-sm: var(--sh-hairline); --shadow-card: var(--sh-card);
  --shadow-lift: var(--sh-floating); --shadow-nav: var(--sh-floating);
  --edge-top: inset 0 1px 0 rgba(255, 255, 255, 0.75);
}

/* ── reset ── */
* { box-sizing: border-box; margin: 0; padding: 0; }
/* Every photograph on this page is wrapped in `<picture>` so a WebP can be offered ahead of
   the JPEG. `display: contents` keeps that wrapper out of the layout entirely: without it the
   element is an inline box, and the `img { width: 100% }` rules further down would be sizing
   themselves against a shrink-to-fit inline parent rather than the fixed frame that holds it. */
picture { display: contents; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; overflow-x: hidden;
  scroll-padding-top: calc(var(--nav-offset) + var(--nav-h) + 1.5rem); }
body {
  font-family: var(--sans);
  color: var(--ink);
  background: var(--paper);
  line-height: 1.6;
  font-weight: 500;
  font-size: 1rem;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img, svg { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
::selection { background: var(--gold-soft); }
:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 3px var(--paper), 0 0 0 5px var(--forest); border-radius: 6px; }

/* skip link — keyboard users jump straight to the content */
.skip-link { position: fixed; top: -60px; left: 50%; transform: translateX(-50%); z-index: 200;
  background: var(--forest); color: #fff; font-weight: 700; font-size: 14px;
  padding: 12px 20px; border-radius: var(--r-pill); box-shadow: var(--shadow-nav);
  transition: top var(--dur) var(--ease); }
.skip-link:focus-visible { top: 12px; }

.wrap { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter); }

/* ============================================================================
   TYPE — Theme.Font. Display steps are Livvic Bold (700); Livvic Black (900)
   is reserved for the one place the app asks for weight: .bold, exactly as
   Theme.Font.display maps .regular -> Livvic-Bold and .bold -> Livvic-Black.
   Body is Livvic Medium (500) at 16. Nothing here invents a size.
   ============================================================================ */
h1 { font-family: var(--display); font-weight: 700; font-size: var(--t-page);
  line-height: 1.06; letter-spacing: -0.022em; text-wrap: balance; }
h2 { font-family: var(--display); font-weight: 700; font-size: var(--t-sheet);
  line-height: 1.1; letter-spacing: -0.02em; text-wrap: balance; }
h3 { font-family: var(--display); font-weight: 700; font-size: var(--t-section);
  line-height: 1.18; letter-spacing: -0.015em; text-wrap: balance; }
h4 { font-family: var(--display); font-weight: 700; font-size: var(--t-subsection);
  line-height: 1.2; letter-spacing: -0.012em; }
/* The one emphatic display weight, for the hero's marked phrase. */
.serif-i { font-style: normal; font-weight: 900; }

/* EyebrowStyle: Livvic-SemiBold 11, uppercase, 1.2pt tracking, inkSecondary.
   The casing is part of the style, not the string — same rule as the app. */
/* EyebrowStyle sets FOUR things and nothing else: the face, uppercase, 1.2pt of
   tracking, and a colour. It is not a pill — the website had wrapped it in one,
   which is why it read as a chip the app has no equivalent of. */
.eyebrow {
  display: inline-flex; align-items: center; gap: var(--s6);
  font-family: var(--sans); font-size: var(--t-eyebrow); font-weight: 600;
  letter-spacing: 1.2px; text-transform: uppercase; color: var(--ink-2);
}
.eyebrow .ic { width: 14px; height: 14px; color: var(--brand); }
.eyebrow--brand { color: var(--brand); }
.eyebrow.on-dark { color: var(--on-tint-3); }
.eyebrow.on-dark .ic { color: var(--accent); }
.eyebrow.on-photo { color: var(--on-tint-2); text-shadow: var(--sh-text-image); }
.eyebrow.on-photo .ic { color: var(--on-tint); }

/* Accent marker behind the hero words. Theme.accent, yellow's one job. */
.mark { position: relative; white-space: nowrap; z-index: 0; color: var(--ink); }
.mark::after { content: ""; position: absolute; left: -.04em; right: -.04em; bottom: .07em;
  height: .36em; background: var(--accent); z-index: -1; border-radius: var(--r-tiny);
  transform: rotate(-1.4deg); }
.mark.on-dark { color: var(--on-tint); }

/* ============================================================================
   ICONS — the sprite in assets/icons.svg holds the SAME Phosphor glyphs the
   app draws (Icon.swift maps each SF Symbol name onto one). Sized on the
   IconSize scale: micro 10, small 12, compact 14, regular 16, prominent 20,
   display 28, hero 56.
   ============================================================================ */
.ic { width: 16px; height: 16px; flex: none; display: block; }
.ic--micro { width: 10px; height: 10px; }
.ic--small { width: 12px; height: 12px; }
.ic--compact { width: 14px; height: 14px; }
.ic--prominent { width: 20px; height: 20px; }
.ic--display { width: 28px; height: 28px; }
.ic--hero { width: 56px; height: 56px; }

/* ============================================================================
   BUTTONS — CapsuleButtonStyle. One recipe; the roles differ only in fill,
   foreground and stroke. Height, font, press feedback and shadow are shared.
   Primary is the BRAND GREEN gradient — in the app, yellow is never a button.
   ============================================================================ */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--s8);
  height: var(--button-h); padding: 0 var(--s28); border-radius: var(--r-pill);
  cursor: pointer; border: none; font-family: var(--sans); font-weight: 700;
  font-size: var(--t-body); white-space: nowrap;
  transition: transform var(--d-micro) var(--ease-out), opacity var(--d-micro) var(--ease-out),
    box-shadow var(--dur) var(--ease), background var(--dur), border-color var(--dur); }
.btn .ic { width: 18px; height: 18px; }
.btn--sm { height: var(--control-h); padding: 0 var(--s20); font-size: var(--t-caption); }
.btn--block { width: 100%; }
.btn:disabled { opacity: var(--o-disabled); pointer-events: none; }
/* Press: scaleEffect(0.985) + 0.9 opacity, from CapsuleButtonStyle. */
.btn:active { transform: scale(0.985); opacity: var(--o-pressed-strong); }

.btn--primary { background: var(--brand-fill); color: var(--on-brand);
  box-shadow: var(--sh-button); position: relative; }
.btn--primary::after { content: ""; position: absolute; inset: 0; border-radius: inherit;
  border: var(--b-hairline) solid rgba(255, 255, 255, 0.14); pointer-events: none; }
.btn--primary:hover { background: linear-gradient(to bottom, #2a7a60, #1c6350); }

/* Secondary — raisedFill, ink, hairline at borderThick, Shadow.control. */
.btn--secondary, .btn--outline { background: var(--raised-fill); color: var(--ink);
  border: var(--b-thick) solid var(--hairline); box-shadow: var(--sh-control); }
.btn--secondary:hover, .btn--outline:hover { border-color: rgba(18, 21, 16, 0.14); }
.btn--secondary:active, .btn--outline:active { transform: scale(0.99); opacity: var(--o-pressed-soft); }

.btn--danger { background: var(--danger); color: var(--on-ink); box-shadow: var(--sh-button); }

/* On photography — ChipTone.onTint: onTintFill, white, hairline. */
.btn--ghost { background: var(--on-tint-fill); color: var(--on-tint);
  border: var(--b-regular) solid rgba(255, 255, 255, 0.34); backdrop-filter: blur(8px); }
.btn--ghost:hover { background: rgba(255, 255, 255, 0.26); }

/* The gold button is GONE on purpose: in the app, Theme.accent labels value
   (a saving, a Pro marker, a flight) and never carries an action. Every CTA
   that was gold is now the primary green capsule. */

/* App Store badge — ink capsule at cornerMedium, the one non-brand control. */
.appstore { display: inline-flex; align-items: center; gap: var(--s12); height: var(--button-h);
  padding: 0 var(--s24) 0 var(--s20); border-radius: var(--r-md); background: var(--ink);
  color: var(--on-ink); box-shadow: var(--sh-button);
  transition: transform var(--d-micro) var(--ease-out), opacity var(--d-micro); }
.appstore:active { transform: scale(0.985); opacity: var(--o-pressed-strong); }
.appstore svg { width: 27px; height: 27px; flex: none; }
.appstore .as-t { display: flex; flex-direction: column; line-height: 1.05; align-items: flex-start; }
.appstore .as-t small { font-size: var(--t-eyebrow); font-weight: 500; opacity: .82; letter-spacing: .02em; }
.appstore .as-t b { font-family: var(--sans); font-size: 19px; font-weight: 700; letter-spacing: -.01em; }

/* ============================================================================
   NAV — the AHMEDMEDIAGROUP house pattern, verbatim: a floating glass pill.
   Geometry, gaps, padding, link sizes, toggle and breakpoints are AMG's
   (css/styles.css "Nav - floating glass pill"). Only the surface differs, and
   it has to: AMG is a dark site and sits on rgba(7,19,28,.66); Travelyfe is a
   light one, so the same pill is white-translucent over the hero photograph.
   ============================================================================ */
.nav {
  position: fixed; top: var(--nav-offset); left: 50%; transform: translateX(-50%);
  z-index: 100;
  width: max-content;
  max-width: calc(100% - (var(--gutter) * 1.4));
  height: var(--nav-h);
  display: flex; align-items: center; gap: 1.4rem;
  padding: 0 0.55rem 0 1.2rem;
  /* Deep green glass. Everything inside the pill is therefore light-on-dark — the link,
     burger and CTA colours below all depend on this and must move with it. */
  background: rgba(6, 40, 30, 0.72);
  backdrop-filter: blur(22px) saturate(150%);
  -webkit-backdrop-filter: blur(22px) saturate(150%);
  border: var(--b-regular) solid rgba(255, 255, 255, 0.16);
  border-radius: var(--r-pill);
  /* --edge-top is a 75%-white inset built for light surfaces; on the green pill it draws a
     bright line across the top. Same idea, dialled down to a sheen. */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10), var(--shadow-nav);
  transition: top var(--dur) var(--ease), background var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
/* Scrolled, the pill sits over white page content rather than the dark hero, so it goes
   more opaque instead of switching to white — a pill that changed colour halfway down the
   page would read as two different navs. */
.nav.is-scrolled { top: 10px; background: rgba(6, 40, 30, 0.92); border-color: rgba(255, 255, 255, 0.12); }

.nav .brand { display: inline-flex; align-items: center; }
.nav .brand .logo { height: 28px; width: auto; flex: none; display: block; }
@media (max-width: 480px) { .nav .brand .logo { height: 24px; } }

.nav-links { display: none; align-items: center; gap: 1.7rem; }
.nav-links a { font-family: var(--sans); font-size: 0.9rem; font-weight: 500;
  color: rgba(255, 255, 255, 0.78); transition: color var(--dur) var(--ease); }
.nav-links a:hover, .nav-links a[aria-current="page"] { color: #fff; }
.nav-actions { display: flex; align-items: center; gap: 0.4rem; }

@media (min-width: 920px) { .nav-links { display: inline-flex; } }
@media (max-width: 919px) { .nav-actions .appstore-mini { display: none; } }
@media (max-width: 480px) { .nav { max-width: calc(100% - 16px); padding: 0 0.45rem 0 0.95rem; } }

.appstore-mini { display: inline-flex; align-items: center; gap: var(--s8);
  height: 40px; padding: 0 var(--s16); border-radius: var(--r-pill);
  background: #fff; color: var(--racing-deep); position: relative;
  font-family: var(--sans); font-weight: 700; font-size: var(--t-caption);
  box-shadow: var(--sh-control);
  transition: transform var(--d-micro) var(--ease-out), opacity var(--d-micro); }
.appstore-mini::after { content: ""; position: absolute; inset: 0; border-radius: inherit;
  border: var(--b-hairline) solid rgba(6, 40, 30, 0.10); }
.appstore-mini:active { transform: scale(0.985); opacity: var(--o-pressed-strong); }
.appstore-mini svg, .appstore-mini .ic { width: 15px; height: 15px; }

.nav-toggle { width: 40px; height: 40px; display: inline-flex; align-items: center;
  justify-content: center; border-radius: var(--r-pill);
  border: var(--b-regular) solid rgba(255, 255, 255, 0.22); position: relative; z-index: 110; }
.nav-toggle span { position: relative; display: block; width: 16px; height: 1.5px;
  background: #fff; border-radius: 2px; transition: background var(--dur); }
.nav-toggle span::before, .nav-toggle span::after { content: ''; position: absolute; left: 0;
  width: 16px; height: 1.5px; background: #fff; border-radius: 2px;
  transition: transform var(--dur), top var(--dur); }
.nav-toggle span::before { top: -5px; }
.nav-toggle span::after  { top:  5px; }
.nav-toggle.is-open span { background: transparent; }
.nav-toggle.is-open span::before { top: 0; transform: rotate(45deg); }
.nav-toggle.is-open span::after  { top: 0; transform: rotate(-45deg); }
@media (min-width: 900px) { .nav-toggle { display: none; } }

.drawer { position: fixed; top: calc(var(--nav-offset) + var(--nav-h) + 10px); left: 50%;
  width: calc(100% - var(--gutter)); max-width: 460px;
  background: rgba(255, 255, 255, 0.96); backdrop-filter: blur(26px); -webkit-backdrop-filter: blur(26px);
  border: 1px solid var(--hairline); border-radius: var(--r-lg); padding: 0.7rem 1rem 1rem;
  display: flex; flex-direction: column; gap: 0.1rem;
  opacity: 0; visibility: hidden; pointer-events: none; transform: translate(-50%, -8px);
  transition: opacity var(--dur), transform var(--dur), visibility 0s var(--dur); z-index: 99; box-shadow: var(--shadow-lift); }
.drawer.is-open { opacity: 1; visibility: visible; pointer-events: auto; transform: translate(-50%, 0); transition-delay: 0s; }
.drawer a { font-family: var(--sans); font-size: 16px; font-weight: 600; color: var(--ink);
  padding: 0.85rem 0.35rem; border-bottom: 1px solid var(--hairline); }
.drawer a:last-of-type { border-bottom: 0; }
.drawer .btn { margin-top: 0.8rem; }
@media (min-width: 900px) { .drawer { display: none; } }

/* ============================================================================
   HERO
   ============================================================================ */
.hero { position: relative; min-height: 100svh; display: flex; align-items: center;
  padding: clamp(120px, 17vh, 170px) 0 clamp(70px, 9vh, 96px); isolation: isolate;
  /* NOT `overflow: hidden`. That clipped the Download menu, which opens below a button
     sitting near the hero's foot — the Web option was cut off mid-row. `clip` with a
     margin still contains the floating photo prints and route (they overhang by ~130px)
     but lets the menu paint past the edge. */
  overflow: clip; overflow-clip-margin: 320px; }

/* Landscape phones, and any desktop window someone has dragged short.
   Measured at 844x390, 932x430, 1024x500 and 1280x600: the padding above resolves to its
   120px FLOOR once 17vh falls below it, so on a 390px-tall viewport nearly a third of the
   screen was empty space above the headline, `100svh` then held the section taller than the
   screen anyway, and the Download button landed under the consent banner. It is the floor
   that is wrong on a short viewport, not the ratio — a clamp cannot express "and no more
   than a quarter of the screen", so the case gets its own rule.
   Kept to landscape shapes by the width condition: a 390x844 phone is tall, not short, and
   its hero is correct as it stands. */
@media (max-height: 620px) and (min-width: 620px) {
  .hero { min-height: auto;
          padding: calc(var(--nav-offset) + var(--nav-h) + 28px) 0 clamp(32px, 7vh, 56px); }
}
.hero__bg { position: absolute; inset: 0; z-index: -2; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; object-position: 62% center; }
.hero__bg--unused::after { content: ""; position: absolute; inset: 0; background:
  linear-gradient(98deg, rgba(4,29,21,0.90) 0%, rgba(4,29,21,0.62) 34%, rgba(4,29,21,0.14) 62%, rgba(4,29,21,0) 80%),
  linear-gradient(to top, rgba(4,29,21,0.6) 2%, rgba(4,29,21,0) 42%); }
.hero .wrap { display: grid; grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr); gap: 48px; align-items: center; }

.hero-copy { max-width: 620px; }
.hero h1 { color: #fff; font-size: clamp(40px, 6.3vw, 78px); margin: 22px 0 0; line-height: 1.02;
  letter-spacing: -0.022em; text-shadow: 0 2px 40px rgba(4,29,21,0.4); }
.hero h1 .serif-i { color: #fff; }
.hero .lead { color: var(--on-photo); font-size: clamp(17px, 1.55vw, 20px); font-weight: 500;
  margin-top: 24px; max-width: 540px; text-shadow: 0 1px 18px rgba(4,29,21,0.45); }
.hero-actions { display: flex; align-items: center; gap: 14px; margin-top: 34px; flex-wrap: wrap; }

/* scroll cue */
.scroll-cue { position: absolute; bottom: 26px; left: 50%; transform: translateX(-50%); z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 7px; color: rgba(255,255,255,0.7);
  font-size: 11px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; }
.scroll-cue .mouse { width: 22px; height: 34px; border: 1.6px solid rgba(255,255,255,0.5); border-radius: 12px; position: relative; }
.scroll-cue .mouse::after { content: ""; position: absolute; top: 6px; left: 50%; transform: translateX(-50%);
  width: 3px; height: 6px; background: var(--accent); border-radius: 2px; animation: wheel 1.6s var(--ease-out) infinite; }
@keyframes wheel { 0% { opacity: 0; transform: translate(-50%, 0); } 40% { opacity: 1; } 100% { opacity: 0; transform: translate(-50%, 9px); } }
@media (max-width: 980px) { .scroll-cue { display: none; } }

/* ── phone mockup ── */
.hero-device { display: flex; justify-content: center; }
.phone { position: relative; width: 300px; aspect-ratio: 300 / 624; border-radius: 48px; background: #0a0d09;
  padding: 10px;
  box-shadow:
    0 1px 2px rgba(6, 40, 30, 0.10),        /* contact — keeps the edge crisp */
    0 12px 26px -10px rgba(6, 40, 30, 0.20), /* lift */
    0 34px 62px -34px rgba(6, 40, 30, 0.24); /* ambient, tight enough not to pool */
  animation: floaty 7s var(--ease-out) infinite; }
@keyframes floaty { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
.phone::before { content: ""; position: absolute; top: 16px; left: 50%; transform: translateX(-50%);
  width: 96px; height: 26px; background: #0a0d09; border-radius: 999px; z-index: 4; }
.phone-screen { position: relative; width: 100%; height: 100%; border-radius: 40px; overflow: hidden; background: #fff; display: flex; flex-direction: column; }
.app-top { padding: 50px 18px 10px; display: flex; align-items: flex-end; justify-content: space-between; }
.app-top .app-h { font-family: var(--display); font-size: 24px; font-weight: 700; letter-spacing: -.02em; }
.app-top .app-sub { font-size: 12.5px; color: var(--ink-2); font-weight: 600; margin-top: 2px; }
.app-top .app-av { width: 32px; height: 32px; border-radius: 50%; background: var(--brand-fill); }
.app-chips { display: flex; gap: 7px; padding: 8px 18px 12px; flex-wrap: wrap; }
/* ChipChrome: unselected is raisedFill + ink + hairline + chipResting; selected
   is brandFill + onBrand + chipSelected. Font 13 semibold, scaled for the mock. */
.app-chip { font-size: 11px; font-weight: 600; padding: 6px 12px; border-radius: var(--r-pill);
  background: var(--surface); color: var(--ink); border: var(--b-regular) solid var(--hairline);
  box-shadow: var(--sh-chip-rest); }
.app-chip.on { background: var(--brand-fill); color: var(--on-brand); border-color: transparent;
  box-shadow: var(--sh-chip-sel); }
.app-card { position: relative; margin: 0 16px 14px; border-radius: 20px; overflow: hidden; flex: 1; min-height: 0; box-shadow: var(--shadow-card); }
.app-card img { width: 100%; height: 100%; object-fit: cover; position: absolute; inset: 0; }
.app-card .scrim { position: absolute; inset: 0; background: linear-gradient(to top, rgba(4,29,21,0.97) 2%, rgba(4,29,21,0.5) 36%, rgba(4,29,21,0) 64%); }
.app-card .heart { position: absolute; top: 12px; right: 12px; width: 30px; height: 30px; border-radius: 50%;
  background: rgba(255,255,255,0.22); backdrop-filter: blur(8px); display: grid; place-items: center; }
.app-card .heart svg { width: 16px; height: 16px; color: #fff; }
/* ChipTone.accent — value, not state. Yellow's one job in the app. */
.app-card .badge { position: absolute; top: 12px; left: 12px; font-size: 10.5px; font-weight: 600;
  background: var(--accent); color: var(--on-accent); padding: 5px 10px; border-radius: var(--r-pill);
  border: var(--b-regular) solid var(--on-image-hairline);
  box-shadow: var(--sh-chip-image); }
.app-card .meta { position: absolute; left: 14px; right: 14px; bottom: 14px; color: #fff; }
.app-card .meta .tname { font-family: var(--display); font-size: 19px; font-weight: 700; letter-spacing: -.01em; }
.app-card .meta p { font-size: 11.5px; opacity: .9; font-weight: 600; margin-top: 3px; }
.app-card .meta .row { display: flex; gap: 8px; margin-top: 10px; font-size: 11px; font-weight: 700; }
.app-card .meta .row span { display: inline-flex; align-items: center; gap: 4px; background: var(--on-tint-fill); backdrop-filter: blur(8px); padding: 4px 9px; border-radius: var(--r-pill); }
.app-card .meta .row svg { width: 12px; height: 12px; }
.app-nav { display: flex; justify-content: space-around; padding: 11px 16px 22px; border-top: 1px solid var(--hairline); }
.app-nav .item { display: flex; flex-direction: column; align-items: center; gap: 3px; font-size: 9.5px; font-weight: 700; color: var(--ink-3); }
.app-nav .item.on { color: var(--brand); }
.app-nav .item svg { width: 21px; height: 21px; }
.app-fab { position: absolute; right: 16px; bottom: 70px; width: 52px; height: 52px; border-radius: 50%;
  background: var(--brand-fill); color: var(--on-brand); display: grid; place-items: center; box-shadow: var(--sh-floating); z-index: 3; }
.app-fab svg { width: 24px; height: 24px; }

/* ============================================================================
   TRUST STRIP
   ============================================================================ */
.trust { background: var(--brand); color: var(--on-brand); }
.trust .wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px 34px; padding: 22px var(--gutter); }
.trust .item { display: inline-flex; align-items: center; gap: 9px; font-weight: 700; font-size: 14.5px; color: rgba(255,255,255,0.94); }
.trust .item .ic { width: 17px; height: 17px; color: var(--accent); flex: none; }
.trust .sep { width: 5px; height: 5px; border-radius: 50%; background: rgba(255,255,255,0.28); }
@media (max-width: 620px) { .trust .sep { display: none; } }

/* ============================================================================
   SECTION SHELL
   ============================================================================ */
.section { padding: clamp(78px, 10vw, 140px) 0; position: relative; }
.section--sand { background: var(--sand); }
.sec-head { max-width: 720px; }
.sec-head.center { margin-inline: auto; text-align: center; }
.sec-head.center .eyebrow { margin-inline: auto; }
.sec-head h2 { font-size: clamp(32px, 4.6vw, 56px); margin-top: 18px; line-height: 1.04; }
.sec-head p { color: var(--ink-2); font-size: clamp(16px, 1.4vw, 19px); margin-top: 18px; font-weight: 500; max-width: 620px; }
.sec-head.center p { margin-inline: auto; }

/* ============================================================================
   FEATURES — consistent grid
   ============================================================================ */
.features-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 58px; }
/* surfaceCard(cornerLarge): raisedFill, raisedEdge at borderThin, and BOTH
   shadows the app stacks — Shadow.hairline over Shadow.card. */
.fcard { background: var(--raised-fill); border-radius: var(--r-lg); padding: var(--s28);
  border: var(--b-thin) solid var(--raised-edge);
  box-shadow: var(--sh-hairline), var(--sh-card);
  display: flex; flex-direction: column; position: relative; overflow: hidden;
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease); }
.fcard:hover { transform: translateY(-4px); }
.fcard .icw { width: 52px; height: 52px; border-radius: var(--r-md); display: grid; place-items: center;
  background: var(--forest-tint); color: var(--forest-bright); margin-bottom: 22px; transition: background var(--dur), color var(--dur); }
.fcard:hover .icw { background: var(--brand-fill); color: var(--on-brand); }
.fcard .icw .ic { width: 25px; height: 25px; }
.fcard.is-accent { background: var(--brand-fill); border-color: transparent; color: var(--on-tint); }
.fcard.is-accent .icw { background: var(--on-tint-fill); color: var(--accent); }
.fcard.is-accent:hover .icw { background: var(--accent); color: var(--on-accent); }
.fcard h3 { font-size: 21px; letter-spacing: -.01em; line-height: 1.12; }
.fcard.is-accent h3 { color: #fff; }
.fcard p { color: var(--ink-2); font-size: 15px; margin-top: 10px; font-weight: 500; line-height: 1.6; }
.fcard.is-accent p { color: rgba(255,255,255,0.82); }

/* ============================================================================
   HOW IT WORKS — travel route
   ============================================================================ */
.how { background: var(--sand); overflow: hidden; }
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; margin-top: 64px; position: relative; }
/* dotted route line behind the pins */
.steps::before { content: ""; position: absolute; top: 27px; left: 16%; right: 16%; height: 2px;
  background-image: linear-gradient(to right, var(--forest-bright) 38%, transparent 0%);
  background-size: 14px 2px; background-repeat: repeat-x; opacity: 0.4; }
.step { position: relative; text-align: center; padding: 0 8px; }
.step .pin { width: 56px; height: 56px; margin: 0 auto 24px; border-radius: 50%; display: grid; place-items: center;
  background: var(--brand-fill); color: var(--on-brand); font-family: var(--display); font-size: 22px; font-weight: 700;
  box-shadow: 0 12px 26px -10px rgba(11,40,30,0.5), var(--edge-top); position: relative; z-index: 1;
  border: 3px solid var(--sand); }
.step.is-gold .pin { background: var(--brand-fill); color: var(--on-brand); }
.step h3 { font-size: 22px; letter-spacing: -.01em; }
.step p { color: var(--ink-2); font-size: 15px; margin-top: 10px; font-weight: 500; max-width: 300px; margin-inline: auto; }
@media (max-width: 760px) { .steps { grid-template-columns: 1fr; gap: 34px; } .steps::before { display: none; } }

/* ============================================================================
   EXPLORE — curated trips rail
   ============================================================================ */
.explore { background: var(--paper); overflow-x: clip; }
.explore .sec-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 28px; flex-wrap: wrap; max-width: none; }
.explore .sec-head .left { max-width: 640px; }
.explore-lead { margin: 0 0 6px; }
.rail { display: flex; gap: 22px; width: 100%; max-width: 100%; overflow-x: auto;
  /* full-bleed rail: first card lines up with the .wrap container's content edge */
  --rail-inset: calc((100% - min(100%, var(--container))) / 2 + var(--gutter));
  padding: 54px var(--rail-inset) 30px; scroll-padding-inline: var(--rail-inset);
  scroll-snap-type: x mandatory; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.rail::-webkit-scrollbar { display: none; }
/* ── The itinerary card — ItineraryCard (ItineraryCards.swift) ──────────────
 * ZStack(alignment: .bottom): hero image, a tint gradient keyed to the image,
 * Theme.legibilityScrim, then the info block. photoCardEdge() clips it at
 * cornerXLarge with a white-12% edge. Padding is 22 (the non-compact value).
 * ─────────────────────────────────────────────────────────────────────────── */
.trip { position: relative; flex: 0 0 318px; height: 430px; border-radius: var(--r-xl);
  overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end;
  isolation: isolate; background: var(--racing-deep);
  transition: transform var(--dur) var(--ease-out); }
.trip::after { content: ""; position: absolute; inset: 0; border-radius: inherit;
  border: var(--b-regular) solid rgba(255, 255, 255, 0.12); pointer-events: none; z-index: 3; }
.trip:hover { transform: translateY(-6px); }
.trip img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  z-index: 0; transition: transform 700ms var(--ease-out); }
.trip:hover img { transform: scale(1.05); }

/* The app derives this tint from the cover's dominant colour, clamped to a
   0.30–0.46 brightness band (ImageColor + readableTint). A stylesheet cannot
   sample the image, so racing-deep stands in at the same stop positions —
   0.18/0.5/0.78/1.0 — and Theme.legibilityScrim is layered over it exactly as
   the app layers it. */
.trip .trip-tint { position: absolute; inset: 0; z-index: 1; background:
  linear-gradient(to bottom,
    rgba(6, 40, 30, 0) 18%, rgba(6, 40, 30, 0.45) 50%,
    rgba(6, 40, 30, 0.85) 78%, rgba(6, 40, 30, 1) 100%),
  linear-gradient(to bottom, rgba(0, 0, 0, 0) 35%, rgba(0, 0, 0, 0.45) 100%); }

.trip .tbody { position: relative; z-index: 2; padding: 22px;
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s8);
  color: var(--on-tint); }
/* @handle — body(13, .semibold) in onTintSecondary, one line. */
.trip .t-handle { display: inline-flex; align-items: center; gap: var(--s6);
  font-size: var(--t-caption); font-weight: 600; color: var(--on-tint-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.trip .t-pro { color: var(--accent); }
/* The route line is an EYEBROW: Livvic SemiBold 11, uppercase, 1.2pt tracking. */
.trip .t-route { font-size: var(--t-eyebrow); font-weight: 600; letter-spacing: 1.2px;
  text-transform: uppercase; color: var(--on-tint-2);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* Title — display(.sheet) at weight .heavy, i.e. Livvic Black 28, tracking -0.5. */
.trip .tbody h3 { font-family: var(--display); font-size: 28px; font-weight: 900;
  letter-spacing: -0.5px; line-height: 1.1; color: var(--on-tint);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
/* statsRow — HStack(spacing: s14) of IconStat(micro glyph + body(12, .semibold)). */
.trip .t-stats { display: flex; flex-wrap: wrap; gap: var(--s14); margin-top: var(--s2); }
.trip .t-stats .stat { display: inline-flex; align-items: center; gap: var(--s4);
  font-size: 12px; font-weight: 600; color: var(--on-tint-2); white-space: nowrap; }

.rail-hint { display: flex; align-items: center; gap: 8px; color: var(--ink-2); font-size: 13px; font-weight: 600; }

/* ============================================================================
   PLATFORMS — dark green band
   ============================================================================ */
.platforms { background: var(--forest-deep); color: #fff; overflow: hidden; position: relative; isolation: isolate; }
.platforms::before { content: ""; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(900px 540px at 82% -8%, rgba(243,201,60,0.16), transparent 60%),
              radial-gradient(700px 500px at 8% 110%, rgba(24,85,66,0.4), transparent 62%); }
.platforms .wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; }
.platforms h2 { color: #fff; font-size: clamp(32px, 4.2vw, 52px); }
.platforms .lead { color: rgba(255,255,255,0.82); font-size: 18px; margin-top: 20px; max-width: 480px; }
.plat-list { display: flex; gap: 12px; margin-top: 34px; flex-wrap: wrap; }
.plat-chip { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; font-size: 15px;
  background: rgba(255,255,255,0.07); border: 1px solid rgba(255,255,255,0.16); padding: 13px 20px; border-radius: 14px; }
.plat-chip .ic { width: 20px; height: 20px; color: var(--accent); }
.plat-visual { display: grid; grid-template-columns: 1.2fr 0.8fr; gap: 18px; }
.plat-visual .pv { border-radius: var(--r-lg); overflow: hidden; position: relative; box-shadow: var(--shadow-lift); border: 1px solid rgba(255,255,255,0.1); }
.plat-visual .pv img { width: 100%; height: 100%; object-fit: cover; }
.plat-visual .tall { grid-row: span 2; aspect-ratio: 3 / 5; }
.plat-visual .pv.sm { aspect-ratio: 1 / 1; }

/* ============================================================================
   FREE / PRIVACY
   ============================================================================ */
.free { background: var(--paper); }
.free .wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; }
.free h2 { font-size: clamp(30px, 3.8vw, 48px); }
.free p { font-size: clamp(16px, 1.4vw, 19px); margin-top: 18px; font-weight: 500; color: var(--ink-2); }
.free .price-tag { display: inline-flex; align-items: baseline; gap: 8px; margin-top: 26px; }
.free .price-tag b { font-family: var(--display); font-size: 48px; font-weight: 700; color: var(--brand); letter-spacing: -.03em; }
.free .price-tag span { font-size: 15px; font-weight: 600; color: var(--ink-2); }
.free-points { display: grid; gap: 14px; }
.free-points .fp { display: flex; gap: 16px; align-items: flex-start; background: var(--sand);
  border: 1px solid var(--hairline); border-radius: var(--r-md); padding: 20px 22px;
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur); }
.free-points .fp:hover { transform: translateX(4px); box-shadow: var(--shadow-card); }
.free-points .fp .fpic { width: 42px; height: 42px; border-radius: 12px; flex: none; display: grid; place-items: center; background: var(--forest-tint); color: var(--forest-bright); }
.free-points .fp .fpic .ic { width: 21px; height: 21px; }
.free-points .fp b { font-weight: 700; font-size: 16px; font-family: var(--sans); }
.free-points .fp span { display: block; font-size: 14px; color: var(--ink-2); font-weight: 500; margin-top: 3px; line-height: 1.55; }

/* ============================================================================
   FINAL CTA
   ============================================================================ */
.cta { position: relative; overflow: hidden; color: #fff; text-align: center; isolation: isolate;
  padding: clamp(96px, 13vw, 168px) 0; }
.cta .cta-bg { position: absolute; inset: 0; z-index: -2; }
.cta .cta-bg img { width: 100%; height: 100%; object-fit: cover; object-position: center 42%; }
.cta .cta-bg::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to bottom, rgba(4,29,21,0.78), rgba(4,29,21,0.92)); }
.cta h2 { font-size: clamp(36px, 5.6vw, 72px); color: #fff; }
.cta p { color: var(--on-photo); font-size: clamp(17px, 1.5vw, 20px); margin: 20px auto 0; max-width: 560px; font-weight: 500; }
.cta .cta-actions { display: flex; justify-content: center; gap: 16px; margin-top: 40px; flex-wrap: wrap; }
.cta .cta-sub { margin-top: 22px; color: rgba(255,255,255,0.74); font-size: 14px; font-weight: 600; }

/* ============================================================================
   FOOTER — the AHMEDMEDIAGROUP house pattern: one bar, a hairline above it,
   copyright on the left and a handful of links on the right. No four-column
   link farm; this is a one-page site with five destinations.
   ============================================================================ */
.footer { border-top: var(--b-regular) solid var(--hairline); padding-block: 1.85rem; }
.footer-bar { display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 1rem 1.5rem; }
.footer-brand { display: inline-flex; align-items: center; gap: 0.6rem; }
.footer-brand .logo { height: 22px; width: auto; }
.footer-copy { font-family: var(--sans); font-size: var(--t-eyebrow); line-height: 1;
  letter-spacing: 1.2px; text-transform: uppercase; color: var(--ink-3); }
.footer-copy a { color: var(--ink-2); transition: color var(--dur); }
.footer-copy a:hover { color: var(--ink); }
.footer-sep { color: var(--ink-faded); margin: 0 0.45rem; }
.footer-links { display: flex; flex-wrap: wrap; gap: 1.75rem; }
.footer-links a { font-family: var(--sans); font-size: var(--t-eyebrow); line-height: 1;
  letter-spacing: 1.2px; text-transform: uppercase; color: var(--ink-3);
  transition: color var(--dur); }
.footer-links a:hover { color: var(--ink); }

/* The regional index. Set quieter than the footer's own row — it is a crawl path first and
   a reader's shortcut second, and it must not compete with the CTA immediately above it. */
/* Centred at every width, heading and links together. It is a nine-item row that wraps to
   two or three lines depending on the viewport, and left-aligned those lines end ragged at
   different points — which reads as a mistake rather than as a list. Centred, each line is
   balanced against the one above it and the block sits under the CTA card on the same axis.
   Deliberately not inside a media query: the answer is the same at 320 and at 1920. */
.footer-browse { padding-bottom: 1.6rem; margin-bottom: 1.6rem; text-align: center;
  border-bottom: var(--b-hairline, 1px) solid var(--hairline); }
.footer-browse__h { font-family: var(--sans); font-size: var(--t-eyebrow); font-weight: 600;
  line-height: 1; letter-spacing: 1.2px; text-transform: uppercase; color: var(--ink-3);
  margin-bottom: 0.9rem; }
.footer-browse__list { list-style: none; display: flex; flex-wrap: wrap;
  justify-content: center; gap: 0.7rem 1.6rem; }
.footer-browse__list a { font-family: var(--sans); font-size: var(--t-body-sm); font-weight: 600;
  color: var(--ink-2); transition: color var(--dur); }
.footer-browse__list a:hover { color: var(--brand); }

/* ============================================================================
   COOKIE CONSENT — shown only when analytics is configured (see main.js)
   ============================================================================ */
.consent { position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 150;
  width: calc(100% - var(--gutter)); max-width: 560px;
  display: flex; align-items: center; gap: 16px 20px; flex-wrap: wrap; justify-content: space-between;
  background: rgba(255, 255, 255, 0.94); backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid var(--hairline); border-radius: var(--r-lg); padding: 16px 18px;
  box-shadow: var(--shadow-lift), var(--edge-top); }
.consent[hidden] { display: none; }
/* Room at the foot of the document for the fixed banner, so it stops covering the footer
   while it is up. `--consent-h` is written by site.js from the banner's measured height —
   it wraps to two rows by 430px and three by 320px, so a constant here would be wrong at
   two of the three widths this was tested at. The 18px matches the banner's own `bottom`
   offset and the 12px is the gap that keeps the last footer row clear of its edge. */
body.has-consent { padding-bottom: calc(var(--consent-h, 96px) + 18px + 12px); }
.consent__text { font-size: 13.5px; font-weight: 500; color: var(--ink-2); flex: 1 1 240px; line-height: 1.5; }
.consent__text a { color: var(--forest-bright); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }
.consent__actions { display: flex; gap: 8px; flex: none; }
@media (max-width: 480px) { .consent__actions { flex: 1 1 100%; } .consent__actions .btn { flex: 1; } }

/* ============================================================================
   SUBPAGES — legal + error
   ============================================================================ */
.subpage { padding-top: calc(var(--nav-offset) + var(--nav-h) + 48px); padding-bottom: clamp(64px, 9vw, 120px); background: var(--paper); min-height: 70vh; }
.back-link { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; font-weight: 700;
  color: var(--forest-bright); margin-bottom: 26px; }
.back-link svg { width: 15px; height: 15px; }
.back-link:hover { color: var(--forest); }

.legal .wrap { max-width: 780px; }
.legal h1 { font-size: clamp(32px, 5vw, 52px); }
.legal-updated { color: var(--ink-3); font-size: 14px; font-weight: 600; margin-top: 10px; }
.legal h2 { font-size: clamp(20px, 2.4vw, 26px); margin-top: 44px; }
.legal h3 { font-size: 18px; margin-top: 26px; }
.legal p, .legal li { color: var(--ink-2); font-size: 16px; font-weight: 500; margin-top: 14px; line-height: 1.7; }
.legal ul { margin-top: 14px; padding-left: 22px; }
.legal li { margin-top: 8px; }
.legal a { color: var(--forest-bright); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
.legal a:hover { color: var(--forest); }

.error { display: grid; place-items: center; text-align: center; }
.error .wrap { max-width: 620px; }
.error h1 { font-size: clamp(34px, 6vw, 64px); margin-top: 18px; }
.error p { color: var(--ink-2); font-size: clamp(16px, 1.4vw, 19px); margin: 18px auto 34px; max-width: 460px; font-weight: 500; }

/* ============================================================================
   REVEAL
   ============================================================================ */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out); }
.reveal.in { opacity: 1; transform: none; }
.reveal[data-delay="1"] { transition-delay: 0.08s; }
.reveal[data-delay="2"] { transition-delay: 0.16s; }

/* ============================================================================
   RESPONSIVE
   ============================================================================ */
@media (max-width: 980px) {
  .hero .wrap { grid-template-columns: 1fr; }
  /* Centred once it stacks. The device column beside the copy is gone at this width, so
     left-aligned copy sits against the gutter with nothing to balance it — and the menu
     rule below CENTRES ITSELF ON THIS BUTTON, so a left-aligned button put the panel's
     left edge at roughly `gutter - 30px`, off the screen. That is the clipped icon column
     in the 2026-08-15 screenshot. These two facts are coupled: if the hero is ever
     un-centred here, re-anchor `.dl-menu` in the same change. */
  .hero-copy { max-width: none; text-align: center; }
  .hero .lead { margin-left: auto; margin-right: auto; }
  .hero-actions { justify-content: center; }
  .hero { min-height: auto; }
  .features-grid { grid-template-columns: repeat(2, 1fr); }
  .platforms .wrap, .free .wrap { grid-template-columns: 1fr; gap: 40px; }
  .footer .wrap { grid-template-columns: 1fr 1fr; gap: 32px; }
}
@media (max-width: 640px) {
  .features-grid { grid-template-columns: 1fr; }
  .footer .wrap { grid-template-columns: 1fr 1fr; }
  .footer .brand { grid-column: 1 / -1; }
  .trip { flex: 0 0 80vw; height: 400px; }
}
@media (max-width: 420px) {
  .nav { gap: 0.5rem; padding: 0 0.4rem 0 1rem; }
  .footer .wrap { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; }
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
}


/* ============================================================================
   SURFACES & FORMS — the app's card and field recipes, verbatim.

   surfaceCard  : cornerLarge 22, raisedFill, raisedEdge @ borderThin, hairline+card
   borderedCard : cornerMedium 16, raisedFill, hairline @ borderRegular, raised
   field        : FloatingLabelChrome — cornerMedium 16, raisedFill, hairline @
                  borderRegular resting / inkSecondary 35% @ borderHeavy focused,
                  with the label floating up into a notch cut in the border.
   ============================================================================ */
.card {
  background: var(--raised-fill); border-radius: var(--r-lg); padding: var(--card-inset);
  border: var(--b-thin) solid var(--raised-edge);
  box-shadow: var(--sh-hairline), var(--sh-card);
}
.card--bordered {
  border-radius: var(--r-md); border: var(--b-regular) solid var(--hairline);
  box-shadow: var(--sh-raised);
}

/* ── Chips — ChipChrome. size chip = 16/12, pill = 12/6, badge = 8/4 ── */
.chip {
  display: inline-flex; align-items: center; gap: var(--s8);
  font-family: var(--sans); font-size: var(--t-caption); font-weight: 600;
  padding: var(--s6) var(--s12); border-radius: var(--r-pill);
  background: var(--mist); color: var(--ink); border: var(--b-regular) solid transparent;
}
.chip--tap { padding: var(--s12) var(--s16); }
.chip--badge { padding: var(--s4) var(--s8); font-size: var(--t-eyebrow); }
.chip--unselected { background: var(--raised-fill); border-color: var(--hairline); box-shadow: var(--sh-chip-rest); }
.chip--selected { background: var(--brand-fill); color: var(--on-brand); box-shadow: var(--sh-chip-sel); }
.chip--brand-soft { background: var(--brand-soft); color: var(--brand); }
.chip--accent { background: var(--accent); color: var(--on-accent); border-color: var(--on-image-hairline); }
.chip--on-tint { background: var(--on-tint-fill); color: var(--on-tint); }
.chip .ic { width: 14px; height: 14px; }

/* ── Fields ── */
.field { position: relative; display: block; }
.field > input, .field > select, .field > textarea {
  width: 100%; min-height: 48px; font-family: var(--sans); font-size: var(--t-body);
  font-weight: 500; color: var(--ink); background: var(--surface);
  border: var(--b-regular) solid var(--hairline); border-radius: var(--r-md);
  padding: var(--field-pad-y) var(--s16); appearance: none;
  transition: border-color var(--d-standard) var(--ease), box-shadow var(--d-standard) var(--ease);
}
.field > textarea { min-height: 96px; resize: vertical; line-height: 1.55; }
.field > select { cursor: pointer; }
.field > :is(input, select, textarea):focus {
  outline: none; border-color: rgba(18, 21, 16, 0.35);
  box-shadow: inset 0 0 0 0.5px rgba(18, 21, 16, 0.35);   /* = borderHeavy 1.5 */
}
.field > input::placeholder, .field > textarea::placeholder { color: transparent; }

/* The label rests inside the field as its placeholder, then floats up into a gap
   in the border once the field is focused or filled — the app's exact behaviour.
   The notch is the label's own surface-coloured background sitting on the stroke. */
.field > label {
  position: absolute; left: var(--s16); top: 50%; transform: translateY(-50%);
  font-family: var(--sans); font-size: var(--t-body); font-weight: 500;
  color: var(--ink-2); pointer-events: none; max-width: calc(100% - var(--s32));
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  transition: all var(--d-standard) var(--ease);
}
.field > :is(input, textarea):focus ~ label,
.field > :is(input, textarea):not(:placeholder-shown) ~ label,
.field > select:focus ~ label,
.field.is-filled > label {
  top: 0; left: var(--s10); transform: translateY(-50%);
  font-size: 12px; font-weight: 600; padding: 0 var(--s6);
  background: var(--surface); color: var(--ink-2);
}
.field > :is(input, select, textarea):focus ~ label { color: var(--brand); }
.field > textarea ~ label { top: var(--s24); }
.field > textarea:focus ~ label, .field > textarea:not(:placeholder-shown) ~ label { top: 0; }
.field .hint { display: block; margin: var(--s6) 0 0 var(--s16); font-size: 12px;
  font-weight: 500; color: var(--ink-3); }
.field.is-error > :is(input, select, textarea) { border-color: var(--danger); }
.field.is-error .hint { color: var(--danger); }

/* ── Feature cards: the Pro marker and the tier note ── */
.fcard h3 { display: flex; align-items: center; gap: var(--s8); flex-wrap: wrap; }
.fcard .f-tier { font-size: 10px; letter-spacing: 0.6px; text-transform: uppercase;
  font-weight: 700; flex: none; }
.fcard.is-accent .f-tier { background: var(--on-tint-fill); color: var(--accent);
  border-color: transparent; }
.f-note { margin-top: var(--s28); text-align: center; font-size: var(--t-caption);
  font-weight: 500; color: var(--ink-3); }

/* ============================================================================
   THE LAUNCH BACKDROP — Theme.splashTop under the app's own SplashView stack
   (LaunchGate.swift): a racing-deep radial closing in from the edges, and a
   gold wash rising off the bottom. This is literally the first thing the app
   shows on launch, so the site opens on the same surface the product does —
   rather than on a stock sunset, which is nobody's brand.
   ============================================================================ */
.launch-bg { position: absolute; inset: 0; z-index: -2; background:
  /* accent rising from the bottom: .20 at 0, .07 at .18, 0 by .48 */
  linear-gradient(to top,
    rgba(255, 191, 0, 0.20) 0%, rgba(255, 191, 0, 0.07) 18%, rgba(255, 191, 0, 0) 48%),
  /* racing-deep closing in from the edges */
  radial-gradient(ellipse 62% 78% at 50% 50%,
    rgba(6, 40, 30, 0) 12%, rgba(6, 40, 30, 1) 100%),
  var(--splash-top); }

/* ============================================================================
   FEATURE LIST — the app's row anatomy, not a bento of icon cards.
   PaywallView's benefitGrid is a tight two-column grid of icon + name and says
   so in as many words: "not five paragraph rows". Rows use the app's fixed
   28pt icon column (Metrics.iconColumn) so the text edges line up, with the
   divider inset to the text (Metrics.rowDividerInset), exactly as a settings
   or benefits row does in the app.
   ============================================================================ */
.feature-list { display: grid; grid-template-columns: 1fr; gap: 0;
  margin-top: var(--s40); border-top: var(--b-regular) solid var(--hairline); }
@media (min-width: 860px) { .feature-list { grid-template-columns: 1fr 1fr; column-gap: var(--s40); } }
.frow { display: flex; align-items: flex-start; gap: var(--s12);
  padding: var(--s20) 0; border-bottom: var(--b-regular) solid var(--hairline); }
.frow .icw { width: var(--icon-col); flex: none; display: grid; place-items: center;
  color: var(--brand); padding-top: 2px; }
.frow .icw .ic { width: 20px; height: 20px; }
.frow .ftext { min-width: 0; }
.frow h3 { display: flex; align-items: center; gap: var(--s8); flex-wrap: wrap;
  font-family: var(--sans); font-size: var(--t-body); font-weight: 600;
  letter-spacing: 0; line-height: 1.3; color: var(--ink); }
.frow p { margin-top: var(--s4); font-size: var(--t-caption); font-weight: 500;
  line-height: 1.55; color: var(--ink-2); }
.frow .f-tier { font-size: 10px; letter-spacing: 0.6px; text-transform: uppercase;
  font-weight: 700; flex: none; }

/* A sized slot for a real app screenshot. Renders nothing until one exists —
   an empty frame with a label in it is worse than no frame at all. */
.shot { display: none; }
.shot:has(img) { display: block; border-radius: var(--r-xl); overflow: hidden;
  border: var(--b-regular) solid var(--hairline); box-shadow: var(--sh-card); }

/* ============================================================================
   HERO STAGE — the phone and the things orbiting it
   ----------------------------------------------------------------------------
   Photo cards, a dashed route and a couple of badges, all decorative. Three
   rules keep it from going wrong:

   1. The stage is exactly the width of the phone. Everything else hangs off it
      with negative offsets and sits at z-index 0, so the phone (z-index 2) is
      always the thing in front and the layout never grows to fit decoration.
      `.hero` already clips with overflow:hidden, so nothing causes a scrollbar.
   2. Each orbiting piece drifts on the SAME keyframes as the phone but with its
      own duration and delay, so they never move as one slab.
   3. All of it is gone below 980px, where the phone drops to 250px and the
      orbit would sit on top of it rather than around it.
   ============================================================================ */

.stage { position: relative; width: 300px; }
.stage .phone { position: relative; z-index: 2; }

.deco { position: absolute; z-index: 0; pointer-events: none; }

/* ── the dashed route, drawn behind everything ── */
.deco-route {
  /* The global `img, svg { max-width: 100% }` reset clamps this to the 300px stage and
     squashes the curves flat. It is decoration that deliberately exceeds its parent. */
  max-width: none;
  width: 520px; height: 660px;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  z-index: 0; opacity: 0.9;
}

/* ── photo cards: a print, not a screenshot — white mount, slight tilt ── */
.deco-photo {
  width: 152px; border-radius: 14px; overflow: hidden; background: #fff;
  padding: 8px 8px 26px;                     /* the deep lower margin reads as a print */
  box-shadow: 0 2px 5px rgba(6, 40, 30, 0.07), 0 16px 30px -14px rgba(6, 40, 30, 0.30);
  animation: drift 9s var(--ease-out) infinite;
}
.deco-photo img { width: 100%; height: 118px; object-fit: cover; border-radius: 8px; }
.deco-photo--l { left: -132px; top: 84px;  transform: rotate(-8deg);  animation-delay: -1.2s; }
.deco-photo--r { right: -124px; bottom: 96px; transform: rotate(7deg); animation-delay: -3.4s; }

/* ── badges: brand glyphs, not stock 3D props ── */
.deco-badge {
  width: 58px; height: 58px; border-radius: 20px; display: grid; place-items: center;
  box-shadow: 0 2px 4px rgba(6, 40, 30, 0.07), 0 12px 22px -10px rgba(6, 40, 30, 0.26);
  animation: drift 7.5s var(--ease-out) infinite;
}
.deco-badge .ic { width: 27px; height: 27px; }
.deco-badge--pin {
  left: -74px; top: -14px; background: var(--accent); color: var(--on-accent);
  transform: rotate(-10deg); animation-delay: -0.6s;
}
.deco-badge--compass {
  right: -68px; top: 176px; background: #fff; color: var(--brand);
  transform: rotate(9deg); animation-delay: -2.6s;
}

/* ── one live-looking chip, echoing the stats on a real itinerary card ── */
.deco-chip {
  /* Sits ABOVE the phone (z-index 3), not behind it. At z-index 0 its left half
     disappeared under the device and it read as a clipped, broken label. */
  z-index: 3;
  right: -104px; top: 40px;
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  font-size: 12px; font-weight: 700; color: var(--ink);
  background: #fff; padding: 9px 14px; border-radius: var(--r-pill);
  box-shadow: 0 2px 4px rgba(6, 40, 30, 0.06), 0 10px 20px -10px rgba(6, 40, 30, 0.24);
  transform: rotate(4deg);
  animation: drift 8.5s var(--ease-out) infinite; animation-delay: -4.1s;
}
.deco-chip .ic { width: 14px; height: 14px; color: var(--brand); }

/* The shared `floaty` keyframes animate `transform`, which REPLACES the whole property —
   so a card with `transform: rotate(-8deg)` snapped square the moment the animation began.
   `translate` is an independent transform property, so drift and tilt compose instead of
   fighting. Same motion, rotation survives. */
@keyframes drift { 0%, 100% { translate: 0 0; } 50% { translate: 0 -14px; } }

/* Drift is decoration. Anyone who has asked the OS to stop animation gets none. */
@media (prefers-reduced-motion: reduce) {
  .deco-photo, .deco-badge, .deco-chip { animation: none; }
}

/* ── The hero composition, kept on a phone ────────────────────────────────────────────
   It used to be hidden outright below 980px, because at its desk size it is ~556px wide:
   a 300px stage with photo prints hanging 132px and 124px outside it. That does not fit a
   390px screen, and the honest options were to drop it or to make it shrink. It shrinks.

   Everything that positions a decoration is expressed in `vw` against a `vw`-sized stage,
   so the whole arrangement scales as one piece instead of the prints drifting off while
   the phone stays put. Budget at any width: stage is 58vw centred, so its edges sit at
   21vw and 79vw; the furthest decoration reaches 3vw on the left and 96vw on the right,
   which clears both gutters. `.hero` is `overflow: clip`, so even if a future value
   overshoots it cannot produce a horizontal scrollbar — it will just be cut, silently.
   Check the numbers rather than trusting the clip. ── */
@media (max-width: 980px) {
  .hero-device { display: flex; margin-top: 46px; }
  .stage { width: min(300px, 58vw); }
  .stage .phone { width: 100%; }

  .deco-photo { width: 34vw; max-width: 152px; padding: 6px 6px 20px; }
  .deco-photo img { height: 26vw; max-height: 118px; }
  .deco-photo--l { left: -18vw; top: 12%; }
  .deco-photo--r { right: -17vw; bottom: 14%; }

  .deco-badge { width: 12vw; max-width: 58px; height: 12vw; max-height: 58px; border-radius: 28%; }
  .deco-badge .ic { width: 5.5vw; max-width: 27px; height: 5.5vw; max-height: 27px; }
  .deco-badge--pin { left: -8vw; top: -2%; }
  .deco-badge--compass { right: -7vw; top: 26%; }

  .deco-chip { right: -14vw; top: 6%; font-size: 11px; padding: 7px 11px; gap: 5px; }
  .deco-route { width: 130%; height: 116%; }
}

/* ── Footer: one row — copyright left, links right, pushed apart by the space-between
      already on .footer-bar. `flex-wrap` is inherited from that rule, so on a narrow
      viewport the links drop to their own line without needing a breakpoint. ── */
.footer-links { gap: 1.6rem; }

/* Once those two rows stack, `space-between` has nothing to push against — a single item
   on a line falls back to flex-start, which is why both rows sat hard against the left
   gutter on a phone. Centre them, and pull the pair together: the 1rem row-gap inherited
   from `.footer-bar` reads as a gulf between two lines of 12px uppercase text.
   `flex-basis: 100%` forces the stack rather than relying on where the natural wrap
   happens to land, so the centring can never apply to a row that is still side-by-side. */
@media (max-width: 780px) {
  .footer-bar { justify-content: center; row-gap: 0.5rem; }
  .footer-copy, .footer-links { flex-basis: 100%; }
  .footer-copy { text-align: center; }
  .footer-links { justify-content: center; }
}

/* ============================================================================
   ONE CONTINUOUS PAGE WASH
   ----------------------------------------------------------------------------
   The page used to be a stack of independently-coloured bands — dark green hero,
   two --sand sections, a photo-backed CTA — so every boundary was a visible seam.
   Now nothing paints its own ground except the hero, and the hero fades to
   transparent at its own bottom edge, so it dissolves into the page instead of
   ending at a line.

   WHY THE GREEN IS ON .hero AND NOT ON <body>
   The first attempt put the whole ramp on <body> with stops in vh. That breaks at
   two viewports at once: the hero is `min-height: 100svh` on desktop but `auto`
   below 980px, so a fixed vh stop either fades the green out before the hero ends
   (white hero text and a white-bordered ghost button on near-white — measured, it
   was unreadable) or spills green under the features heading, whose text is dark
   ink. Anchoring the green to the hero makes it correct at every height for free.
   ============================================================================ */

body {
  background:
    /* The dither, over everything. Same reason as the hero's: these are long, low-contrast
       ramps and eight bits per channel cannot draw them without stepping. Tiled, so it costs
       one 160px image for the whole document. */
    var(--dither),

    /* Gold at the foot, anchored to the bottom of the document. */
    linear-gradient(to top, rgba(255, 191, 0, 0.22) 0%, rgba(255, 191, 0, 0.13) 22%,
                            rgba(255, 191, 0, 0.06) 44%, rgba(255, 191, 0, 0.02) 68%,
                            rgba(255, 191, 0, 0) 100%) bottom / 100% 760px no-repeat,

    /* The tail of the green, CONTINUING PAST the hero. Without this the hero faded to
       transparent at its own bottom edge and revealed pure white underneath, which drew a
       hard line straight across the page — the exact seam this whole change removes. The
       hero now hands over to this mid-fade instead of landing on white. Same hue, so the
       handoff is invisible.

       Eased, like the hero's: the alpha steps used to be .40 / .26 / .12 / .04 / 0 across
       five stops and 1800px, which falls fast early and then crawls — the shape a reader
       sees as "it changed here". Nine stops on a curve instead, and the same colour. */
    linear-gradient(to bottom,
      rgba(120, 160, 145, 0.40) 0px,
      rgba(120, 160, 145, 0.355) 260px,
      rgba(120, 160, 145, 0.305) 520px,
      rgba(120, 160, 145, 0.25) 780px,
      rgba(120, 160, 145, 0.195) 1020px,
      rgba(120, 160, 145, 0.14) 1250px,
      rgba(120, 160, 145, 0.088) 1450px,
      rgba(120, 160, 145, 0.045) 1620px,
      rgba(120, 160, 145, 0.015) 1740px,
      rgba(120, 160, 145, 0) 1820px) top / 100% 1820px no-repeat,

    #ffffff;
  background-size: 160px 160px, 100% 760px, 100% 1820px, auto;
}

/* The hero's own ground: racing green, dissolving over its final third.
   ────────────────────────────────────────────────────────────────────────────────
   The ramp is EASED, not linear, and it is dithered.

   What was wrong, measured off a capture rather than judged by eye: the alpha fell
   from 1 to 0 across just eighteen per cent of the hero's height (stops at 70, 80
   and 88), so the handover happened in a narrow enough band to read as an edge —
   the "transition part" rather than a transition. And the ramp banded, holding one
   colour value for six pixels at a stretch through the middle third.

   Both are fixed here and neither by re-picking a colour:

   * Twelve stops instead of seven, spaced on an ease rather than evenly. Colour
     moves fastest through the middle and slowest at each end, which is where a
     linear ramp betrays itself — the eye finds the two ends and reads everything
     between them as one flat move with a seam in it.
   * The alpha handover now runs from 62% to 96% instead of 70% to 88%, so it is
     spread across roughly twice the distance and lands on the body's sage tail
     more gently.
   * `in oklab` on the second declaration, interpolating perceptually so the
     midpoint sits where the eye puts it rather than where the maths does. The
     first declaration is the sRGB fallback with the same stops; a browser that
     cannot parse the second keeps it. This is the same two-declaration pattern the
     CTA card already uses, for the same reason.
   * `--dither` on top, because none of the above can beat eight bits per channel.

   Still fully transparent before the clip edge, NOT at it: the last stretch of hero
   is deliberately bare so the body's sage tail shows through, which is what makes
   the boundary disappear. A gradient still coloured at its clip edge draws a line. */
.launch-bg {
  position: absolute; inset: 0; z-index: -2;
  background:
    var(--dither),
    /* Cloud forms — low contrast, they should read as depth, not as weather. */
    radial-gradient(58% 22% at 16% 18%, rgba(255, 255, 255, 0.10), transparent 72%),
    radial-gradient(46% 18% at 82% 30%, rgba(255, 255, 255, 0.075), transparent 72%),
    radial-gradient(40% 15% at 52% 9%,  rgba(255, 255, 255, 0.06),  transparent 72%),
    linear-gradient(to bottom,
      var(--racing-deep) 0%,
      #072b21 8%,
      #093221 16%,
      #0b3a2c 24%,
      #0f4534 34%,
      #16553f 44%,
      var(--splash-top) 54%,
      rgba(38, 108, 86, 0.80) 62%,
      rgba(70, 132, 108, 0.56) 71%,
      rgba(100, 150, 128, 0.34) 80%,
      rgba(118, 158, 143, 0.15) 89%,
      rgba(120, 160, 145, 0) 96%,
      rgba(120, 160, 145, 0) 100%);
  background:
    var(--dither),
    radial-gradient(58% 22% at 16% 18%, rgba(255, 255, 255, 0.10), transparent 72%),
    radial-gradient(46% 18% at 82% 30%, rgba(255, 255, 255, 0.075), transparent 72%),
    radial-gradient(40% 15% at 52% 9%,  rgba(255, 255, 255, 0.06),  transparent 72%),
    linear-gradient(to bottom in oklab,
      var(--racing-deep) 0%,
      #072b21 8%,
      #093221 16%,
      #0b3a2c 24%,
      #0f4534 34%,
      #16553f 44%,
      var(--splash-top) 54%,
      rgba(38, 108, 86, 0.80) 62%,
      rgba(70, 132, 108, 0.56) 71%,
      rgba(100, 150, 128, 0.34) 80%,
      rgba(118, 158, 143, 0.15) 89%,
      rgba(120, 160, 145, 0) 96%,
      rgba(120, 160, 145, 0) 100%);
  background-size: 160px 160px, auto, auto, auto, auto;
}

/* Every band that used to paint its own ground now sits on the wash. */
.section--sand  { background: transparent; }
.how            { background: transparent; }
.explore        { background: transparent; }
.free           { background: transparent; }
.cta            { background: transparent; }

/* The step pins punched a --sand-coloured ring out of the old flat band. With no
   flat band to match, the ring becomes a white halo, which is what it was for. */
.step .pin { border-color: rgba(255, 255, 255, 0.9); }

/* The CTA was white-on-photo. It now sits on the pale gold foot of the wash, so it
   takes the page's ink instead — white text there would be unreadable. */
.cta            { color: var(--ink); }
.cta h2         { color: var(--ink); }
.cta p          { color: var(--ink-2); }
.cta .cta-sub   { color: var(--ink-3); }


/* ============================================================================
   SHADOWS ON A PAGE THAT IS NO LONGER DARK
   ----------------------------------------------------------------------------
   Every shadow above was tuned against the old dark-green hero, where a wide,
   heavy, near-black cast simply disappeared into the background. The page is now
   a wash that runs to near-white behind the lower half of the phone, and those
   same shadows read there as a grey-green smudge pooling under the device.

   The replacements are layered rather than single: a 1-2px contact shadow to keep
   the edge crisp, a mid lift, and a tight ambient. Lower alpha, much smaller blur
   radii, and a negative spread so the ambient cannot spill sideways. They read as
   depth on white and are still present against the green at the top.
   ============================================================================ */


/* ============================================================================
   FEATURES — bento grid
   ----------------------------------------------------------------------------
   Six columns, so the three row shapes (4+2, 2+2+2, 6) all divide cleanly and no
   card ever lands on a fractional gap.

   Each card clips its screenshot at the bottom edge on purpose: the device is
   pushed past the card boundary and cropped, which is what stops these reading as
   "box with a picture in it". It also means the card height is set by the copy,
   not by the 1:2.17 phone, so a row of three stays level whatever the text does.
   ============================================================================ */

.bento {
  display: grid; grid-template-columns: repeat(6, 1fr);
  gap: clamp(14px, 1.4vw, 20px); margin-top: clamp(40px, 5vw, 60px);
}

.bento-card {
  grid-column: span 2; position: relative; overflow: hidden;
  border-radius: clamp(20px, 2vw, 28px);
  background: rgba(255, 255, 255, 0.66);
  border: var(--b-regular) solid rgba(6, 40, 30, 0.07);
  box-shadow: 0 1px 2px rgba(6, 40, 30, 0.04), 0 14px 34px -22px rgba(6, 40, 30, 0.28);
  padding: clamp(24px, 2.4vw, 34px);
  display: flex; flex-direction: column; gap: var(--s20);
  min-height: 400px;
}
.bento-card--wide { grid-column: span 4; }
.bento-card--full { grid-column: span 6; }

.bento-num {
  display: inline-block; font-size: 12px; font-weight: 900; letter-spacing: 2px;
  color: var(--brand); opacity: 0.45;
}
.bento-copy h3 {
  display: flex; align-items: center; gap: var(--s8); flex-wrap: wrap;
  margin-top: var(--s6);
  font-size: clamp(20px, 1.9vw, 27px); line-height: 1.14; letter-spacing: -0.01em;
}
.bento-copy p {
  margin-top: var(--s12); font-size: var(--t-body-sm); font-weight: 500;
  color: var(--ink-2); max-width: 44ch;
}

/* The screenshot hangs off the bottom of the card and is clipped by its overflow. */
.bento-shot { margin: auto -8px calc(clamp(24px, 2.4vw, 34px) * -1 - 90px); display: flex; justify-content: center; }
.bento-shot .phone { width: 232px; animation: none; }   /* no drift inside a card */

/* Split cards put the copy beside the device instead of above it. */
.bento-card--split { flex-direction: row; align-items: center; gap: clamp(20px, 3vw, 48px); }
.bento-card--split .bento-copy { flex: 1 1 auto; }
.bento-card--split .bento-shot { flex: 0 0 auto; margin: 0 0 -120px; }
.bento-card--split .bento-shot .phone { width: 250px; }

/* The closing card spans all six columns. Split there left ~400px of dead space between
   the copy and the device, so it centres instead: copy over a centred phone, which is the
   one arrangement that fills a full-bleed width without inventing content to pad it. */
.bento-card--centre { align-items: center; text-align: center; }
.bento-card--centre .bento-copy p { max-width: 56ch; margin-inline: auto; }
.bento-card--centre .bento-copy h3 { justify-content: center; }
.bento-card--centre .bento-shot { margin-bottom: calc(clamp(24px, 2.4vw, 34px) * -1 - 150px); }
.bento-card--centre .bento-shot .phone { width: 268px; }

@media (max-width: 1040px) {
  .bento-card, .bento-card--wide { grid-column: span 3; }
  .bento-card--full { grid-column: span 6; }
}
@media (max-width: 720px) {
  .bento-card, .bento-card--wide, .bento-card--full { grid-column: span 6; }
  .bento-card--split { flex-direction: column; align-items: stretch; }
  .bento-card--split .bento-shot { margin: auto -8px -110px; }
}

/* Placeholder screens for the three account-gated features. Reminders, collaboration and
   sharing all require a signed-in account, so the harness can only photograph their
   "Not Signed In" empty state — a screenshot that actively sells against the feature. A
   branded panel is honest by comparison: it holds the layout, matches the other cards, and
   is one <img> away from being the real thing. */
.phone-screen--placeholder {
  display: grid; place-items: center;
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(255, 255, 255, 0.10), transparent 70%),
    linear-gradient(165deg, var(--splash-top) 0%, var(--racing-deep) 100%);
}
.phone-screen--placeholder .ic {
  width: 76px; height: 76px; color: rgba(255, 255, 255, 0.32);
}

/* ============================================================================
   FINAL CTA — an inset card, not a full-bleed band
   ----------------------------------------------------------------------------
   The page is one continuous wash, so a full-width coloured band here would put
   back the hard edge that change existed to remove. The card sits on the wash
   and runs its gradient the same direction the page does — racing green at the
   top, gold at the foot — so it reads as a concentrated version of the page.

   That gradient is also why the two halves take different ink: the headline sits
   on green and is white, the ask sits on gold and takes page ink. Same reason the
   App Store button flips to white here — the default black slab is a hole
   punched in the warm end of the card.
   ============================================================================ */

.cta { padding: clamp(20px, 4vw, 64px) 0 clamp(56px, 7vw, 96px); text-align: left; }

.cta-card {
  position: relative; overflow: hidden;
  border-radius: clamp(24px, 3vw, 40px);
  padding: clamp(28px, 3.4vw, 52px);
  min-height: clamp(400px, 42vw, 520px);
  display: flex; flex-direction: column; justify-content: space-between;
  gap: clamp(28px, 4vw, 56px);
  /* Six stops in sRGB put a visible seam across the middle of this card. Two causes, and
     the banding needed both fixed:

     1. RATE. The ramp loitered in green for the first 46% then swung green -> sage -> gold
        inside the next 38%. An eye reads an uneven rate as an edge. The stops below are
        spaced so the perceived change per pixel is roughly constant top to bottom.
     2. HUE PATH. Interpolating #1c614c to #e8c579 in sRGB drops saturation from 0.56 to
        0.31 at the midpoint — a dull olive band, which is the part that actually looked
        unfinished. Green to gold has to pass somewhere near olive, but it should pass
        THROUGH it, not sit in it.

     The first declaration is the sRGB fallback with a denser, better-paced set of stops.
     The second re-runs the same ramp `in oklab`, which interpolates perceptually and holds
     chroma across the handover; browsers that do not parse it keep the fallback. */
  background:
    radial-gradient(80% 50% at 22% 8%, rgba(255, 255, 255, 0.10), transparent 70%),
    linear-gradient(to bottom,
      var(--racing-deep) 0%, #0c3a2c 14%, #124b3a 28%, var(--splash-top) 42%,
      #34714f 55%, #6b8c5c 68%, #a9a86a 78%, #d4bd75 88%, #ffd98a 100%);
  background:
    radial-gradient(80% 50% at 22% 8%, rgba(255, 255, 255, 0.10), transparent 70%),
    linear-gradient(to bottom in oklab,
      var(--racing-deep) 0%, #0c3a2c 14%, #124b3a 28%, var(--splash-top) 42%,
      #34714f 55%, #6b8c5c 68%, #a9a86a 78%, #d4bd75 88%, #ffd98a 100%);
  box-shadow: 0 2px 6px rgba(6, 40, 30, 0.08), 0 30px 60px -34px rgba(6, 40, 30, 0.42);
}

.cta-card__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; }
.cta-card h2 { color: #fff; font-size: clamp(32px, 4.6vw, 62px); line-height: 1.04; margin: 0; }
/* The anchor is the flex child of .cta-card__top now, not the image — so the layout lives
   here and .cta-card__mark keeps only its own sizing. Moving one without the other is what
   would silently drop the `order: -1` further down. */
/* The brand column is the flex child of .cta-card__top now — logo, then the social row
   beneath it. Right-aligned to match the logo's old position at the card's top corner. */
.cta-card__brandcol { display: flex; flex-direction: column; align-items: flex-end; gap: 16px; flex: none; }
.cta-card__marklink { display: inline-flex; flex: none; line-height: 0; }

/* Seven buttons at 44px plus six 10px gaps is 368px — wider than the card's content box on
   a phone (~334px at 390px wide). It wraps rather than overflowing, and follows the
   column's alignment when it does: right under the logo, left once the card stacks. */
.social {
  display: flex; flex-wrap: wrap; justify-content: flex-end;
  gap: 10px; list-style: none; margin: 0; padding: 0;
}
/* 44px, not the 40 the reference row uses: this is the minimum comfortable touch target,
   and these sit low on a card people reach for with a thumb. */
.social__btn {
  width: 44px; height: 44px; border-radius: 13px;
  display: grid; place-items: center;
  color: rgba(255, 255, 255, 0.82);
  border: var(--b-regular) solid rgba(255, 255, 255, 0.24);
  transition: background var(--dur), color var(--dur), border-color var(--dur);
}
.social__btn:hover, .social__btn:focus-visible {
  background: rgba(255, 255, 255, 0.13); color: #fff; border-color: rgba(255, 255, 255, 0.45);
}
.social__btn svg { width: 18px; height: 18px; display: block; }
.cta-card__mark { height: clamp(32px, 3vw, 44px); width: auto; display: block; opacity: 0.95; }

.cta-card__bottom {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: clamp(24px, 4vw, 56px);
}

/* A SCRIM for the copy in this corner — not a text-shadow, and the distinction is the point.
   ────────────────────────────────────────────────────────────────────────────────────────
   `.cta-card__ask` is white, and it sits about 65–85% down a card that has ramped from
   racing green to gold by then. Measured against those stops, plain white lands at 2.76:1,
   2.47:1 and 1.95:1. AA wants 4.5:1.

   It used to carry a dark text-shadow, which reads as a fix and is not one: WCAG measures
   the glyph against the background it is composited over, and a shadow contributes nothing
   to that number. It moved the impression and left the measurement where it was. This
   darkens the actual pixels, so the measurement moves with it — racing deep, the card's own
   darkest value, so it reads as more of the card rather than a grey patch. 0.55 is where the
   worst ground in the band clears 4.5:1; the peak is higher so the whole text area stays
   above it as the ellipse feathers.

   ANCHORED TO THE CORNER, and that is not a detail. The first attempt put this on the ask
   block itself, where the ellipse was wider than its own box — so the box clipped it and
   drew a rectangle with three straight edges through the middle of the card. Centred on the
   card's bottom-right corner it reaches full strength only where the card ends anyway, and
   fades to nothing well inside the other two sides. A vignette has no edge to notice; a
   panel does.

   Nothing under it goes dark-on-dark: the corner holds this copy and the Download pill,
   which is white, and the photo prints are at the opposite end. */
.cta-card::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(76% 56% at 100% 100%,
    rgba(6, 40, 30, 0.70) 0%,
    rgba(6, 40, 30, 0.62) 28%,
    rgba(6, 40, 30, 0.40) 54%,
    rgba(6, 40, 30, 0.16) 78%,
    rgba(6, 40, 30, 0) 100%);
}
/* Above the scrim. Both rows, so the h2 and the brand column are not dimmed by it either. */
.cta-card__top, .cta-card__bottom { position: relative; z-index: 1; }

/* Bottom-left art: the same photo-print motif as the hero, so the page closes on the
   language it opened with. Decorative — it carries no information the copy does not. */
.cta-card__art { position: relative; flex: 0 0 auto; width: 260px; height: 150px; }
.cta-print {
  position: absolute; bottom: 0; width: 136px; border-radius: 12px; overflow: hidden;
  background: #fff; padding: 7px 7px 22px;
  box-shadow: 0 2px 5px rgba(6, 40, 30, 0.10), 0 14px 26px -14px rgba(6, 40, 30, 0.35);
}
.cta-print img { width: 100%; height: 100px; object-fit: cover; border-radius: 7px; }
.cta-print--a { left: 0;   transform: rotate(-7deg); }
.cta-print--b { left: 108px; bottom: 14px; transform: rotate(6deg); }

.cta-card__ask { text-align: right; max-width: 520px; margin-left: auto; }

/* White, sitting on the scrim above — which is what makes it legible rather than merely
   look it. `position: relative` puts the text over the ::before rather than under it. */
.cta-card__ask p {
  position: relative; z-index: 1;
  color: #fff; font-size: clamp(16px, 1.4vw, 19px); margin: 0; font-weight: 500;
  line-height: 1.45;
}
.cta-card .cta-actions { display: flex; justify-content: flex-end; gap: 14px; margin-top: 22px; flex-wrap: wrap; }
.cta-card .cta-sub { margin-top: 18px; color: rgba(18, 21, 16, 0.62); font-size: 13.5px; font-weight: 600; }

/* White pill, matching the card's warm foot rather than punching a black hole in it. */
.appstore--light { background: #fff; color: var(--racing-deep); box-shadow: 0 2px 6px rgba(6, 40, 30, 0.10), 0 12px 24px -14px rgba(6, 40, 30, 0.36); }
.appstore--light small { color: rgba(6, 40, 30, 0.66); }

@media (max-width: 860px) {
  /* Centred once the card stacks. Every one of these is load-bearing: at desk size the
     card is a two-column arrangement and each half carries its own alignment — brand
     column right, ask text right, actions right. Stacked, each of those becomes an
     off-centre element on a narrow card, which is why the whole thing read as left
     aligned. Centre them together or not at all. */
  .cta-card__top { flex-direction: column; align-items: center; }
  .cta-card h2 { text-align: center; }
  /* Follows whatever is currently the flex child of .cta-card__top — the image, then the
     anchor when the logo became a link, now the column that holds the logo and socials.
     Left behind on an inner element this silently stops working. */
  .cta-card__brandcol { order: -1; align-items: center; }
  .social { justify-content: center; }
  .cta-card__bottom { flex-direction: column; align-items: center; }
  /* The prints are absolutely positioned at `left: 0` and `left: 108px`, so the artwork
     is 244px wide (108 + 136) no matter how wide its container is. Stretched to 100% the
     box centred but the pictures inside it did not — they stayed pinned to its left edge,
     which is why everything else on this card looked centred and these did not. Size the
     box to the artwork and `align-items: center` on the parent does the rest.
     150px, not 132: print --b sits at `bottom: 14px` and is 129px tall, so it needs 143. */
  .cta-card__art { width: 244px; height: 150px; }
  .cta-card__ask { text-align: center; margin-inline: auto; }
  /* Stacked, so the copy is centred and the card is taller: the scrim rises off the whole
     foot rather than out of one corner, which is where the copy now sits. */
  .cta-card::before {
    background: radial-gradient(120% 42% at 50% 100%,
      rgba(6, 40, 30, 0.70) 0%,
      rgba(6, 40, 30, 0.62) 30%,
      rgba(6, 40, 30, 0.38) 58%,
      rgba(6, 40, 30, 0.14) 80%,
      rgba(6, 40, 30, 0) 100%);
  }
  .cta-card .cta-actions { justify-content: center; }
}

/* 244px still overruns the smallest supported card: a 320px viewport leaves 232px of
   content once the page gutter and the card's own 28px padding are taken off. `.cta-card`
   is `overflow: hidden`, so it would clip rather than scroll — silently, 6px off each
   print. Step the whole composition down instead. Extent here is 92 + 116 = 208. */
@media (max-width: 360px) {
  .cta-card__art { width: 208px; height: 128px; }
  .cta-print { width: 116px; }
  .cta-print img { height: 85px; }
  .cta-print--b { left: 92px; }
}

/* ============================================================================
   HERO DOWNLOAD MENU
   ----------------------------------------------------------------------------
   Built on <details>/<summary>, not a scripted popover: it opens, takes keyboard
   focus and closes on Escape natively, so the only download affordance on the
   page still works with JavaScript blocked or main.js failed. The script adds
   click-outside-to-close and nothing else.
   ============================================================================ */

.dl { position: relative; display: inline-block; }
.dl > summary { list-style: none; cursor: pointer; }
.dl > summary::-webkit-details-marker { display: none; }

.dl-btn {
  display: inline-flex; align-items: center; gap: 10px;
  height: 56px; padding: 0 26px; border-radius: var(--r-pill);
  background: #fff; color: var(--racing-deep);
  font-family: var(--sans); font-weight: 700; font-size: 17px;
  box-shadow: 0 2px 6px rgba(6, 40, 30, 0.10), 0 14px 28px -16px rgba(6, 40, 30, 0.5);
  transition: transform var(--d-micro) var(--ease-out);
}
.dl-btn:active { transform: scale(0.985); }
.dl-chev { width: 17px; height: 17px; transition: transform var(--dur) var(--ease); }
.dl[open] .dl-chev { transform: rotate(180deg); }

.dl-menu {
  position: absolute; top: calc(100% + 10px); left: 0; z-index: 60;
  min-width: 274px; padding: 8px;
  background: rgba(255, 255, 255, 0.97);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border: var(--b-regular) solid rgba(6, 40, 30, 0.08);
  border-radius: 20px;
  box-shadow: 0 2px 8px rgba(6, 40, 30, 0.08), 0 26px 52px -22px rgba(6, 40, 30, 0.55);
  animation: dlIn 160ms var(--ease-out);
}
@keyframes dlIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .dl-menu { animation: none; } }

.dl-opt {
  display: flex; align-items: center; gap: 13px;
  padding: 11px 13px; border-radius: 13px; color: var(--ink);
  transition: background var(--d-micro);
}
.dl-opt:hover, .dl-opt:focus-visible { background: var(--brand-soft); }
.dl-opt__ic { width: 26px; display: grid; place-items: center; color: var(--racing-deep); flex: none; }
.dl-opt__ic svg { width: 19px; height: 19px; }
.dl-opt__t { display: flex; flex-direction: column; line-height: 1.25; }
.dl-opt__t b { font-size: 15.5px; font-weight: 700; }
.dl-opt__t small { font-size: 12.5px; color: var(--ink-3); font-weight: 500; }

@media (max-width: 980px) {
  /* The hero is centred once it stacks, so the menu is too — anchored left it hung
     off the side of a narrow screen. */
  .dl-menu { left: 50%; transform: translateX(-50%); }
  /* `dlIn` animates `transform`, and an animated `transform` REPLACES the
     `translateX(-50%)` above for as long as it runs — the same trap `floaty` hit when it
     wiped a card's `rotate()`. Redefined here to touch opacity only, so the centring
     survives the 160ms. Keep these two rules together: separating them re-breaks it. */
  @keyframes dlIn { from { opacity: 0; } to { opacity: 1; } }

  /* `min-width: 274px` is wider than the content box of a 320px phone once the page
     gutter is taken off, so the menu was sized past the screen before it was even
     positioned. Cap it at the viewport and let it shrink; 274px still wins on anything
     roomier. */
  .dl-menu { min-width: 0; width: min(274px, calc(100vw - 28px)); }
}

/* ── The same menu in the nav pill and the CTA card ────────────────────────────
   One component, three placements. Both of these sit at the right-hand end of their
   container, so their menus are right-aligned; left-aligned they hung off the page. */
.dl--right .dl-menu { left: auto; right: 0; }

.dl--nav .dl-btn {
  height: 40px; padding: 0 var(--s16); gap: var(--s8);
  font-size: var(--t-caption); font-weight: 700;
  background: #fff; color: var(--racing-deep);
  box-shadow: var(--sh-control);
}
.dl--nav .dl-chev { width: 14px; height: 14px; }
/* Icon-only trigger: the horizontal padding was sized for a word, and left as-is it reads
   as a wide pill with two small glyphs adrift in the middle. Square it up instead. */
.dl-btn--icon { padding: 0 var(--s12); gap: 5px; }
.dl-btn--icon .dl-ic { width: 18px; height: 18px; flex: none; }

.dl--cta .dl-btn {
  height: 56px; padding: 0 26px; gap: 10px;
  background: #fff; color: var(--racing-deep); font-size: 17px;
  box-shadow: 0 2px 6px rgba(6, 40, 30, 0.10), 0 12px 24px -14px rgba(6, 40, 30, 0.36);
}
/* The CTA sits low on the page, so its menu opens upward rather than off the bottom. */
.dl--cta .dl-menu { top: auto; bottom: calc(100% + 10px); }

@media (max-width: 980px) {
  /* dl--right must survive the centring rule that the hero menu uses. */
  .dl--right .dl-menu { left: auto; right: 0; transform: none; }
}

/* ── Two fixes found by using the menus ────────────────────────────────────────
   1. The hero menu overhangs the hero by ~70px, and `.section` is `position:
      relative`, so the features section — later in the DOM — painted over the
      overhang. The bottom row (Web) was visible but not clickable. Lifting the
      hero only while a menu is open keeps the decorations from ever overlaying
      the next section at rest. `:has()` does it in CSS; main.js sets the same
      class for anything that lacks it.
   2. The CTA menu sits inside a right-aligned block and inherited its alignment,
      so the option labels drifted to the middle of the row. */
.hero:has(.dl[open]), .hero.dl-open { z-index: 20; }
.dl-menu { text-align: left; }

/* 3. `dl--right` is right for the nav, where the button really does sit at the right-hand
      end of the pill. It is wrong for the CTA below 860px: `.cta-card .cta-actions` flips
      to `flex-start` there, so the button moves to the left gutter while its menu stayed
      pinned to the button's RIGHT edge — putting the panel's left edge at about
      `gutter - 59px`, further off-screen than the hero's was. Anchor it to the same edge
      the button now sits on. Must stay after the `max-width: 980px` `.dl--right` rule:
      the two selectors have equal specificity, so source order is what decides. */
@media (max-width: 860px) {
  .dl--cta .dl-menu { left: 50%; right: auto; transform: translateX(-50%); }
}
