/* ==========================================================================
   IRONCLAD — Digital Marketing / AI automation, New York
   Design system: Trust & Authority + Conversion pattern (ui-ux-pro-max)
   Art direction: monochrome classical. Sourced from the brand mood board —
   chiaroscuro marble, high-contrast serif display, film grain — with the
   logo's navy and linen carried through as the accent and the light break.
   Zero dependencies. All motion is CSS + IntersectionObserver.
   ========================================================================== */

/* ---------- Tokens ---------- */
:root {
  /* Ground */
  --ink:        #08080A;
  --ink-soft:   #0E0E11;
  --ink-lift:   #15151A;

  /* Brand — taken from the IRONCLAD lockup */
  --bone:       #EFEBE3;   /* logo linen */
  --navy:       #1B3A5C;   /* logo navy  */
  --navy-deep:  #12283F;
  --navy-lift:  #2A5583;

  /* Text on ink — contrast verified in-browser, see README */
  --fg:         #F2EFE9;
  --fg-muted:   #A8A297;
  --fg-subtle:  #8A857C;

  /* Text on linen */
  --on-linen:        #14181D;
  --on-linen-muted:  #4A5560;

  --card:          rgba(255, 255, 255, 0.028);
  --card-hover:    rgba(255, 255, 255, 0.05);
  --border:        rgba(239, 235, 227, 0.13);
  --border-strong: rgba(239, 235, 227, 0.26);

  /* Spacing — density 4/10 (spacious, editorial) */
  --space-2xs: 4px;
  --space-xs:  8px;
  --space-sm:  16px;
  --space-md:  24px;
  --space-lg:  40px;
  --space-xl:  64px;
  --space-2xl: 96px;
  --space-3xl: 128px;

  /* Type */
  /* Three roles, the way editorial print sets type: a display serif for
     headlines, a text serif for reading, and a grotesque for UI furniture
     (labels, buttons, the wordmark). Deliberately no Inter and no Roboto. */
  --font-display: 'Playfair Display', 'Georgia', 'Times New Roman', serif;
  --font-body: 'Source Serif 4', 'Iowan Old Style', Georgia, serif;
  --font-ui: 'Archivo', 'Helvetica Neue', Arial, sans-serif;

  --r-sm: 2px;
  --r-md: 3px;
  --r-lg: 4px;          /* near-square: marble and monuments have edges */
  --shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.9);

  /* Motion — GSAP presets translated to CSS.
     power2.out ≈ cubic-bezier(.215,.61,.355,1) */
  --ease-out:    cubic-bezier(0.215, 0.61, 0.355, 1);
  --ease-slow:   cubic-bezier(0.16, 1, 0.3, 1);
  --t-fast: 180ms;
  --t-mid:  280ms;
  --reveal-dur: 620ms;

  --wrap: 1220px;
  --wrap-narrow: 760px;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 92px;   /* sticky nav clearance for anchor jumps */
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--ink);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }
button, input, textarea { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
p { text-wrap: pretty; }

/* ---------- Accessibility primitives ---------- */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

:focus-visible {
  outline: 2px solid var(--bone);
  outline-offset: 3px;
}
.section--linen :focus-visible { outline-color: var(--navy); }

.skip-link {
  position: absolute; top: -100px; left: var(--space-sm);
  z-index: 200;
  background: var(--bone); color: var(--ink);
  padding: 12px 20px;
  font-weight: 600; letter-spacing: 0.02em;
  transition: top var(--t-fast) var(--ease-out);
}
.skip-link:focus { top: 0; }

/* ==========================================================================
   ATMOSPHERE — chiaroscuro. A single raking light out of the dark, plus
   film grain. Decorative, GPU-composited, and the parallax target.
   ========================================================================== */
.atmos {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  background: var(--ink);
}

.atmos__light {
  position: absolute;
  width: 120vw; height: 110vh;
  top: -22vh; left: 50%;
  margin-left: -60vw;
  background:
    radial-gradient(ellipse 42% 46% at 62% 24%, rgba(239, 235, 227, 0.10), transparent 62%),
    radial-gradient(ellipse 55% 40% at 30% 70%, rgba(27, 58, 92, 0.30), transparent 66%);
  will-change: transform;
  animation: breathe 34s ease-in-out infinite alternate;
}

.atmos__pool {
  position: absolute;
  width: 90vw; height: 80vh;
  bottom: -30vh; right: -18vw;
  background: radial-gradient(circle at 50% 50%, rgba(27, 58, 92, 0.34), transparent 65%);
  filter: blur(40px);
  will-change: transform;
  animation: breathe-b 44s ease-in-out infinite alternate;
}

@keyframes breathe {
  from { transform: translate3d(0, 0, 0) scale(1); opacity: 0.9; }
  to   { transform: translate3d(2.5vw, 3vh, 0) scale(1.1); opacity: 1; }
}
@keyframes breathe-b {
  from { transform: translate3d(0, 0, 0) scale(1.04); }
  to   { transform: translate3d(-3vw, -2vh, 0) scale(0.96); }
}

/* Film grain — the halftone texture from the mood board. Also kills banding. */
.atmos__grain {
  position: absolute; inset: -50%;
  width: 200%; height: 200%;
  opacity: 0.5;
  background-image: 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%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  animation: grain 5s steps(5) infinite;
}
@keyframes grain {
  0%,100% { transform: translate(0, 0); }
  20% { transform: translate(-3%, 2%); }
  40% { transform: translate(2%, -3%); }
  60% { transform: translate(-2%, -2%); }
  80% { transform: translate(3%, 3%); }
}

/* Vignette: pulls the eye to the centre, the way the mood board lighting does */
.atmos__vignette {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 90% 75% at 50% 42%, transparent 30%, rgba(8, 8, 10, 0.75) 100%);
}

@media (max-width: 767px) {
  .atmos__pool { filter: blur(26px); }
  .atmos__grain { opacity: 0.36; }
}

/* ---------- Layout ---------- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: clamp(20px, 5vw, 44px);
}
.wrap--narrow { max-width: var(--wrap-narrow); }

main { position: relative; z-index: 1; }

.section {
  position: relative;
  z-index: 1;
  padding-block: clamp(var(--space-xl), 11vw, var(--space-3xl));
}


/* The linen break — the logo's own ground, used once for editorial rhythm */
.section--linen {
  background: var(--bone);
  color: var(--on-linen);
}
.section--linen::before {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: 0.5;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='l'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23l)' opacity='0.18'/%3E%3C/svg%3E");
}
.section--linen > * { position: relative; z-index: 1; }
.section--linen .section__lede,
.section--linen .step__content p { color: var(--on-linen-muted); }
.section--linen .eyebrow { color: var(--navy); }
.section--linen .step { border-color: rgba(20, 24, 29, 0.16); }
.section--linen .step__num { color: var(--navy); -webkit-text-fill-color: var(--navy); }
.section--linen .step__meta { color: var(--navy); border-color: rgba(27, 58, 92, 0.4); }

.section__head { max-width: 760px; margin-bottom: clamp(var(--space-lg), 6vw, var(--space-xl)); }
.section__title { font-size: clamp(2rem, 5vw, 3.4rem); margin-bottom: var(--space-md); }
.section__lede { color: var(--fg-muted); font-size: clamp(1rem, 1.9vw, 1.14rem); max-width: 60ch; }

.eyebrow {
  display: inline-flex; align-items: center; gap: 12px;
  font-family: var(--font-body);
  font-size: 0.6875rem; font-weight: 600;
  letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--fg-muted);
  margin-bottom: var(--space-md);
}
.eyebrow::before {
  content: '';
  width: 28px; height: 1px;
  background: currentColor;
  opacity: 0.6;
}

/* The diamond from the logo lockup, reused as a section ornament */
.rule {
  display: flex; align-items: center; justify-content: center;
  gap: var(--space-sm);
  margin: 0 auto var(--space-lg);
  max-width: 300px;
  color: var(--fg-subtle);
}
.rule::before, .rule::after {
  content: ''; flex: 1; height: 1px;
  background: currentColor; opacity: 0.35;
}
.rule__gem { width: 7px; height: 7px; background: currentColor; transform: rotate(45deg); }

.italic { font-style: italic; }

.disclaimer {
  margin-top: var(--space-md);
  font-size: 0.8125rem;
  color: var(--fg-subtle);
  font-style: italic;
}

/* ==========================================================================
   BUTTONS — square-ish, monumental. Every target ≥ 44px tall.
   ========================================================================== */
.btn {
  --btn-h: 52px;
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  gap: 10px;
  min-height: var(--btn-h);
  padding: 0 28px;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font-family: var(--font-ui);
  font-size: 0.8125rem; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  transition: transform var(--t-mid) var(--ease-out),
              background-color var(--t-mid) var(--ease-out),
              border-color var(--t-mid) var(--ease-out),
              color var(--t-mid) var(--ease-out);
}
.btn__icon { width: 16px; height: 16px; flex: none; transition: transform var(--t-mid) var(--ease-out); }
.btn:hover .btn__icon { transform: translateX(4px); }

.btn--primary { background: var(--bone); color: var(--ink); }
.btn--primary::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.6) 50%, transparent 70%);
  transform: translateX(-120%);
  transition: transform 700ms var(--ease-slow);
}
.btn--primary:hover { transform: translateY(-2px); }
.btn--primary:hover::after { transform: translateX(120%); }
.btn--primary:active { transform: translateY(0); }

.btn--ghost {
  background: transparent;
  border-color: var(--border-strong);
  color: var(--fg);
}
.btn--ghost:hover { background: rgba(239, 235, 227, 0.07); border-color: var(--bone); transform: translateY(-2px); }

/* On the linen section the polarity flips */
.section--linen .btn--primary { background: var(--navy); color: var(--bone); }
.section--linen .btn--ghost { border-color: rgba(20, 24, 29, 0.3); color: var(--on-linen); }
.section--linen .btn--ghost:hover { background: rgba(20, 24, 29, 0.06); border-color: var(--navy); }

.btn--sm  { --btn-h: 44px; padding: 0 20px; font-size: 0.6875rem; }
.btn--lg  { --btn-h: 58px; padding: 0 34px; font-size: 0.875rem; }
.btn--block { display: flex; width: 100%; }

/* ==========================================================================
   NAV
   ========================================================================== */
.nav {
  /* fixed, not sticky: sticky reserves 77px of normal flow, which pushed the
     full-viewport hero down by exactly that much and dropped its CTAs below
     the fold. The nav is transparent over the hero by design, so it should
     not occupy layout at all. */
  position: fixed; top: 0; left: 0; right: 0;
  z-index: 100;
  border-bottom: 1px solid transparent;
  transition: background-color var(--t-mid) var(--ease-out),
              border-color var(--t-mid) var(--ease-out);
}
.nav.is-stuck {
  background: rgba(8, 8, 10, 0.86);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border-bottom-color: var(--border);
}

.nav__inner {
  display: flex; align-items: center; gap: var(--space-md);
  min-height: 76px;
}

/* ---------- Wordmark — echoes the IRONCLAD lockup ---------- */
.brand {
  display: inline-flex; flex-direction: column;
  justify-content: center;
  align-items: center;      /* the two lines centre on each other, not on the box */
  flex: none;
  min-height: 44px;
}
.brand__word {
  font-family: var(--font-ui);
  font-weight: 800;
  font-size: 1.32rem;
  letter-spacing: 0.1em;
  /* Tracking adds a trailing space after the final D, which shifts the optical
     centre left by half a letter-space. Cancel it so the lockup reads centred. */
  margin-right: -0.1em;
  text-align: center;
  text-transform: uppercase;
  line-height: 1;
  color: var(--fg);
}
.brand__sub {
  align-self: stretch;
  display: flex; align-items: center; gap: 7px;
  margin-top: 5px;
  font-family: var(--font-ui);
  font-size: 0.5rem; font-weight: 600;
  letter-spacing: 0.34em; text-transform: uppercase;
  color: var(--fg-muted);
}
.brand__sub::before, .brand__sub::after {
  content: ''; flex: 1; height: 1px;
  background: currentColor; opacity: 0.45;
}
.brand__gem {
  width: 4px; height: 4px;
  background: currentColor;
  transform: rotate(45deg);
  flex: none;
}

.nav__links { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.nav__links a {
  position: relative;
  padding: 13px 15px;   /* 44px minimum tap target (was 43) */
  font-size: 0.6875rem; font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--fg-muted);
  transition: color var(--t-fast) var(--ease-out);
}
.nav__links a::after {
  content: '';
  position: absolute; left: 15px; right: 15px; bottom: 6px;
  height: 1px;
  background: var(--bone);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--t-mid) var(--ease-out);
}
.nav__links a:hover { color: var(--fg); }
.nav__links a:hover::after { transform: scaleX(1); }

.nav__actions { display: flex; align-items: center; gap: var(--space-xs); flex: none; }

.nav__toggle {
  display: none;
  width: 46px; height: 46px;
  align-items: center; justify-content: center;
  flex-direction: column; gap: 6px;
  margin-left: auto;
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.nav__bar {
  display: block; width: 18px; height: 1px;
  background: var(--fg);
  transition: transform var(--t-mid) var(--ease-out);
}
.nav__toggle[aria-expanded="true"] .nav__bar:first-of-type { transform: translateY(3.5px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] .nav__bar:last-of-type  { transform: translateY(-3.5px) rotate(-45deg); }

.mobile-menu {
  padding: var(--space-sm) clamp(20px, 5vw, 44px) var(--space-md);
  background: rgba(8, 8, 10, 0.98);
  backdrop-filter: blur(18px);
  border-bottom: 1px solid var(--border);
}
.mobile-menu[hidden] { display: none; }
.mobile-menu__links { display: flex; flex-direction: column; margin-bottom: var(--space-md); }
.mobile-menu__links a {
  padding: 15px 2px;
  font-size: 0.75rem; font-weight: 600;
  letter-spacing: 0.2em; text-transform: uppercase;
  border-bottom: 1px solid var(--border);
}

@media (max-width: 1023px) {
  .nav__links, .nav__actions { display: none; }
  .nav__toggle { display: flex; }
}

/* ==========================================================================
   SCROLL HERO
   Vanilla port of smooth-scroll-hero. A sticky full-viewport stage whose media
   layer is revealed through an expanding clip-path while it zooms out, with
   the copy held above it so it is never cropped.

   No-JS default is a plain full-bleed hero at one viewport tall — the long
   scroll track and the clip are only introduced once .js is present, so a
   visitor without JS never gets 1500px of dead scrolling.
   ========================================================================== */
.shero {
  position: relative;
  z-index: 1;
  height: 100vh;
}
.js .shero {
  /* Track length. JS reads data-scroll-height and keeps this in sync. */
  height: calc(var(--shero-scroll, 1500px) + 100vh);
}
@supports (height: 100svh) {
  .shero { height: 100svh; }
  .js .shero { height: calc(var(--shero-scroll, 1500px) + 100svh); }
}

.shero__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}
@supports (height: 100svh) {
  .shero__stage { height: 100svh; }
}

/* ---------- Media layer (clipped) ---------- */
.shero__clip {
  position: absolute;
  inset: 0;
  background: var(--ink);
  will-change: clip-path;
}

.shero__zoom {
  position: absolute;
  inset: 0;
  will-change: transform;
  transform-origin: center center;
}

.shero__still,
.shero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The bust sits at 35-53% of the frame; anchoring here keeps it in shot
     when a narrow viewport crops the sides. */
  object-position: 44% center;
  filter: grayscale(1) contrast(1.12) brightness(0.92);
}

/* The video sits on top of the still and cross-fades in once it can play,
   so there is never a black frame or a pop. */
.shero__video {
  opacity: 0;
  transition: opacity 700ms var(--ease-slow);
}
.shero__video.is-ready { opacity: 1; }

/* Scrim lives inside the clip so it grows with the media. Copy reads against
   the page's own black until the media arrives underneath it. */
.shero__scrim {
  position: absolute;
  inset: 0;
  /* Ramp tuned against measured pixel luminance behind the copy, not by eye.
     The earlier, gentler ramp left the headline's leading edge at 2.64:1 over
     lit marble. This holds the worst case at 7.7:1. */
  background: linear-gradient(
    90deg,
    rgba(8, 8, 10, 0.32) 0%,
    rgba(8, 8, 10, 0.14) 24%,
    rgba(8, 8, 10, 0.68) 40%,
    rgba(8, 8, 10, 0.93) 52%,
    rgba(8, 8, 10, 0.97) 100%
  );
}

/* ---------- Copy layer (never clipped) ---------- */
.shero__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  pointer-events: none;   /* let the stage breathe; the copy re-enables itself */
}
.shero__inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  width: 100%;
  /* Needed for align-items to have anything to resolve against — without it
     the flex parent just centres this box and the mobile bottom-alignment
     silently does nothing. */
  height: 100%;
}
.shero__copy {
  grid-column: 2;
  grid-row: 1;
  pointer-events: auto;
}

/* ---------- Hero wordmark ----------
   Stacked in the same grid cell as the copy so the two cross-fade in place
   rather than one appearing beside the other. */
.shero__mark {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  /* Shrink to the wordmark so the rule below spans exactly its width, the way
     the nav lockup does — stretched to the grid cell it ran off to the right. */
  width: fit-content;
  align-self: center;
  justify-self: start;
  pointer-events: none;
  opacity: 0;
  transition: opacity 900ms var(--ease-slow), transform 900ms var(--ease-slow);
}
/* Only under .js — with no JS the copy is already there and this would collide */
.js .shero__mark { opacity: 1; }
.js .shero.is-revealed .shero__mark {
  opacity: 0;
  transform: translate3d(0, -10px, 0);
}

.shero__mark-word {
  font-family: var(--font-ui);
  font-weight: 800;
  font-size: clamp(1.8rem, 3.4vw, 2.9rem);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  line-height: 1;
  margin-right: -0.22em;      /* cancel the trailing track, as in the nav lockup */
  color: var(--fg);
  opacity: 0.62;
}
.shero__mark-sub {
  align-self: stretch;
  display: flex; align-items: center; gap: 10px;
  margin-top: 14px;
  font-family: var(--font-ui);
  font-size: 0.5625rem; font-weight: 600;
  letter-spacing: 0.4em; text-transform: uppercase;
  color: var(--fg-muted);
  opacity: 0.7;
}
.shero__mark-sub::before, .shero__mark-sub::after {
  content: ''; flex: 1; height: 1px;
  background: currentColor; opacity: 0.4;
}

.hero__title {
  font-size: clamp(2.4rem, 5.2vw, 4.2rem);
  font-weight: 400;
  line-height: 1.04;
  letter-spacing: -0.025em;
  margin-bottom: var(--space-md);
}
.hero__title em {
  font-style: italic;
  font-weight: 400;
  color: #93B2D4;   /* lifted for legibility over the lit media */
}

.hero__sub {
  font-size: clamp(1rem, 1.7vw, 1.14rem);
  color: var(--fg-muted);
  max-width: 46ch;
  margin-bottom: var(--space-lg);
}

.hero__cta { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.cta-brief { display: none; }
.hero__note {
  margin-top: var(--space-md);
  font-size: 0.8125rem;
  color: var(--fg-subtle);
}

@media (max-width: 1023px) {
  /* No clip, no zoom, no pin below the desktop breakpoint. In portrait the
     clipped window leaves the copy straddling its edge, and 1500px of pinned
     scrolling over a *static* still is dead scrolling. The reveal is a
     desktop flourish; mobile gets a straight full-bleed hero. */
  /* A short track, not the desktop 1500px — just enough to earn the reveal
     without stranding phone users in dead scrolling. */
  .js .shero { height: calc(620px + 100vh); }
  .shero__clip { clip-path: none !important; }
  .shero__zoom { transform: none !important; }

  .shero__inner {
    grid-template-columns: 1fr;
    align-items: end;
    padding-bottom: 9vh;
  }
  .shero__copy { grid-column: 1; position: relative; isolation: isolate; }
  /* Clear the scroll cue, which owns roughly the bottom 120px in portrait */
  .shero__mark { grid-column: 1; align-self: end; padding-bottom: 17vh; }
  .hero__sub { max-width: 40ch; }

  /* Every line removed here buys back image. The copy block was tall enough
     that its backdrop had to reach up over the face to stay legible; trimming
     it lets the ramp start lower and the head stay lit. */
  .cta-full { display: none; }
  .cta-brief { display: inline; }
  .hero__cta { flex-wrap: nowrap; }
  .hero__cta .btn { flex: 1 1 auto; padding-inline: 18px; }
  .hero__note { display: none; }

  /* A backdrop bound to the copy block rather than to the whole stage.
     A stage-wide ramp strong enough to carry text this high up the screen
     would have blacked out the entire portrait; this darkens only the band
     the text actually occupies and feathers into the image above it, so the
     head stays lit. Bleeds past the wrap padding to reach both edges. */
  .shero__copy::before {
    content: '';
    position: absolute;
    inset: -14vh -50vw -40vh -50vw;
    z-index: -1;
    /* Stops solved against measured pixel luminance, not eyeballed. The
       eyebrow sits at the very top of this block and is 11px, so it needs the
       full 4.5:1 — a gentler feather left it at 3.28:1. This holds 7.4:1. */
    background: linear-gradient(
      180deg,
      transparent 0%,
      rgba(8, 8, 10, 0.78) 8%,
      rgba(8, 8, 10, 0.94) 20%,
      rgba(8, 8, 10, 0.98) 50%,
      var(--ink) 100%
    );
  }

  /* Copy sits over the subject in portrait, so the scrim turns vertical and
     has to work much harder than the desktop ramp. */
  .shero__scrim {
    background: linear-gradient(
      180deg,
      rgba(8, 8, 10, 0.62) 0%,
      rgba(8, 8, 10, 0.28) 20%,
      rgba(8, 8, 10, 0.80) 46%,
      rgba(8, 8, 10, 0.94) 66%,
      var(--ink) 100%
    );
  }
  /* Anchor higher in portrait: the head is in the upper half of the frame */
  .shero__still, .shero__video { object-position: 46% 28%; }
}

@supports (height: 100svh) {
  @media (max-width: 1023px) { .js .shero { height: calc(620px + 100svh); } }
}

/* Reduced motion: no pin, no clip, no zoom. One screen, fully revealed. */
@media (prefers-reduced-motion: reduce) {
  .js .shero { height: 100vh; }
  .shero__clip { clip-path: none !important; }
  .shero__zoom { transform: none !important; }
  /* Requiring a scroll to read the headline is itself a motion dependency.
     Anyone who has asked for less motion gets the copy on arrival. */
  .js .shero__copy .lift { opacity: 1 !important; transform: none !important; }
  .js .shero__copy::before { opacity: 1 !important; }
  .shero__cue { display: none; }
  .js .shero__mark { display: none; }
}



/* ---------- Scroll cue ---------- */
.shero__cue {
  position: absolute;
  left: 50%;
  bottom: clamp(24px, 5vh, 48px);
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 700ms var(--ease-slow);
}
.js .shero__cue { opacity: 1; }
.js .shero.is-revealed .shero__cue { opacity: 0; }

.shero__cue-label {
  font-family: var(--font-ui);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.shero__cue-line {
  width: 1px;
  height: 46px;
  background: linear-gradient(180deg, rgba(239, 235, 227, 0.5), transparent);
  transform-origin: top;
  animation: cue-draw 2.4s var(--ease-slow) infinite;
}
@keyframes cue-draw {
  0%   { transform: scaleY(0); opacity: 0; }
  35%  { transform: scaleY(1); opacity: 1; }
  75%  { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(1) translateY(46px); opacity: 0; }
}

/* ==========================================================================
   PROOF
   ========================================================================== */
.proof { position: relative; z-index: 1; padding-block: clamp(var(--space-lg), 6vw, var(--space-xl)); }
.proof__label {
  text-align: center;
  font-size: 0.625rem; font-weight: 600;
  letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--fg-subtle);
  margin-bottom: var(--space-md);
}

.logos {
  list-style: none; padding: 0;
  display: flex; flex-wrap: wrap;
  justify-content: center; align-items: center;
  gap: var(--space-sm) clamp(var(--space-md), 5vw, var(--space-xl));
  margin-bottom: clamp(var(--space-lg), 7vw, var(--space-xl));
}
.logos li {
  font-family: var(--font-display);
  font-size: clamp(1rem, 2vw, 1.24rem);
  letter-spacing: 0.02em;
  color: var(--fg-muted);
  opacity: 0.7;
  transition: opacity var(--t-mid) var(--ease-out), color var(--t-mid) var(--ease-out);
}
.logos li:hover { opacity: 1; color: var(--fg); }

.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.stat {
  padding: clamp(var(--space-md), 3vw, var(--space-lg)) var(--space-sm);
  text-align: center;
  border-right: 1px solid var(--border);
}
.stat:last-child { border-right: 0; }
.stat dt {
  font-size: 0.625rem; font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--fg-subtle);
  margin-bottom: 10px;
}
.stat dd {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.9rem, 4.4vw, 2.7rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  min-height: 1em;   /* reserved slot so counting never reflows neighbours */
}

@media (max-width: 767px) {
  .stats { grid-template-columns: repeat(2, 1fr); }
  .stat:nth-child(2) { border-right: 0; }
  .stat:nth-child(1), .stat:nth-child(2) { border-bottom: 1px solid var(--border); }
}

/* ==========================================================================
   CARDS
   ========================================================================== */
.cards { display: grid; gap: 1px; background: var(--border); border: 1px solid var(--border); }
.cards--3 { grid-template-columns: repeat(3, 1fr); }

.card {
  position: relative;
  padding: clamp(var(--space-md), 3vw, var(--space-lg));
  background: var(--ink);
  transition: background-color var(--t-mid) var(--ease-out);
}
.card:hover { background: var(--ink-lift); }

.card__num {
  display: block;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  letter-spacing: 0.14em;
  color: var(--fg-subtle);
  margin-bottom: var(--space-md);
}
.card__title {
  font-size: 1.45rem; font-weight: 400;
  margin-bottom: 12px;
}
.card__body { color: var(--fg-muted); font-size: 0.9375rem; }

.icon {
  width: 24px; height: 24px;
  margin-bottom: var(--space-md);
  fill: none;
  stroke: var(--fg);
  stroke-width: 1.25;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: 0.85;
}
.icon--sm { width: 17px; height: 17px; margin: 0; flex: none; }

/* ---------- Bento (deliberate asymmetry) ---------- */
.bento {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
}
.bento__a, .bento__d, .bento__f { grid-column: span 2; }

@media (max-width: 1023px) {
  .cards--3, .bento { grid-template-columns: repeat(2, 1fr); }
  .bento__a, .bento__d, .bento__f { grid-column: span 2; }
}
@media (max-width: 639px) {
  .cards--3, .bento { grid-template-columns: 1fr; }
  .bento__a, .bento__d, .bento__f { grid-column: span 1; }
}

/* ---------- Case cards ---------- */
.card--case .card__kicker {
  font-size: 0.625rem; font-weight: 600;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--fg-subtle);
  margin-bottom: var(--space-md);
}
.card__metric {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.4rem, 5.5vw, 3.2rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  min-height: 1em;
}
.card__metric-label {
  font-size: 0.875rem; font-weight: 500;
  color: var(--fg);
  margin: 10px 0 var(--space-sm);
}

/* ==========================================================================
   STEPS
   ========================================================================== */
.steps { list-style: none; padding: 0; display: grid; }
.step {
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: var(--space-md);
  padding: var(--space-lg) 0;
  border-top: 1px solid var(--border);
}
.step:last-child { border-bottom: 1px solid var(--border); }
.step__num {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  line-height: 1;
  color: var(--fg-subtle);
}
.step__title {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-sm);
  font-size: 1.5rem; font-weight: 400;
  margin-bottom: 10px;
}
.step__meta {
  font-family: var(--font-ui);
  font-size: 0.625rem; font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--fg-muted);
  padding: 4px 11px;
  border: 1px solid var(--border-strong);
  white-space: nowrap;   /* the label must never wrap mid-phrase */
}
.step__content p { color: var(--fg-muted); max-width: 66ch; }

@media (max-width: 639px) {
  .step { grid-template-columns: 1fr; gap: var(--space-xs); padding: var(--space-md) 0; }
}

/* ==========================================================================
   QUOTE
   ========================================================================== */
.quote {
  margin: clamp(var(--space-lg), 6vw, var(--space-xl)) auto 0;
  max-width: 860px;
  text-align: center;
  padding: clamp(var(--space-md), 4vw, var(--space-xl)) 0 0;
  border-top: 1px solid var(--border);
}
.quote blockquote p {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 3.4vw, 2.15rem);
  font-weight: 400; font-style: italic;
  line-height: 1.34;
  letter-spacing: -0.015em;
  text-wrap: balance;
  margin-bottom: var(--space-lg);
}
.quote figcaption { display: flex; align-items: center; justify-content: center; gap: 14px; }
.quote__avatar {
  display: grid; place-items: center;
  width: 42px; height: 42px;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  font-family: var(--font-display);
  font-size: 0.8125rem;
  flex: none;
}
.quote__who { display: flex; flex-direction: column; line-height: 1.45; text-align: left; }
.quote__who strong {
  font-size: 0.75rem; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.quote__who span { font-size: 0.8125rem; color: var(--fg-subtle); }

/* ==========================================================================
   FAQ — <details> so it works with zero JS
   ========================================================================== */
.faq { border-top: 1px solid var(--border); }
.faq__item { border-bottom: 1px solid var(--border); }
.faq__item summary {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-md);
  min-height: 68px;
  padding: var(--space-sm) 0;
  font-family: var(--font-display);
  font-size: 1.2rem; font-weight: 400;
  cursor: pointer;
  list-style: none;
  transition: color var(--t-fast) var(--ease-out);
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary:hover { color: var(--fg-muted); }

.faq__chevron {
  width: 18px; height: 18px; flex: none;
  color: var(--fg-subtle);
  transition: transform var(--t-mid) var(--ease-out);
}
.faq__item[open] .faq__chevron { transform: rotate(180deg); }

.faq__body { padding: 0 0 var(--space-md); }
.faq__body p { color: var(--fg-muted); font-size: 0.9375rem; max-width: 68ch; }

.faq__item[open] .faq__body { animation: faq-open 340ms var(--ease-out); }
@keyframes faq-open {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   CONTACT / BOOKING
   ========================================================================== */
.contact__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(var(--space-lg), 5vw, var(--space-xl));
}
.contact__intro { max-width: 760px; }

.contact__list {
  list-style: none; padding: 0;
  margin-top: var(--space-lg);
  display: flex; flex-wrap: wrap;
  gap: 12px clamp(var(--space-md), 4vw, var(--space-xl));
}
.contact__list li { display: flex; align-items: center; gap: 13px; font-size: 0.9375rem; color: var(--fg-muted); }
.contact__list a {
  display: inline-flex; align-items: center;
  min-height: 44px;                 /* tap target — it was a 20px inline link */
  border-bottom: 1px solid var(--border-strong);
  transition: border-color var(--t-fast);
}
.contact__list a:hover { border-color: var(--bone); }
.contact__list em { font-style: normal; color: var(--fg-subtle); font-size: 0.8125rem; }

/* Calendly embed. min-height reserves the slot so the widget loading
   cannot shift the page (CLS). */
.booking {
  background: rgba(239, 235, 227, 0.028);
  border: 1px solid var(--border);
  padding: var(--space-xs);
}
/* An explicit height, not min-height: Calendly's injected iframe is sized
   height:100%, and a percentage height needs a definite basis to resolve
   against. Under min-height it collapsed to a 150px strip. */
.booking__frame { height: 700px; width: 100%; }
.booking__frame iframe { height: 100% !important; width: 100% !important; }
.calendly-inline-widget:has(iframe) .booking__fallback { display: none; }
.booking__fallback[hidden] { display: none; }   /* class beats the UA [hidden] rule */
.booking__fallback {
  display: grid; place-items: center; gap: var(--space-md);
  min-height: 700px;
  padding: var(--space-lg);
  text-align: center;
}
.booking__fallback p { color: var(--fg-muted); max-width: 40ch; }

@media (max-width: 1023px) {
  .booking__frame { height: 1000px; }        /* stacked layout runs much taller */
  .booking__fallback { min-height: 620px; }
}
@media (max-width: 639px) {
  .booking__frame { height: 1060px; }
}

/* ==========================================================================
   FOOTER
   ========================================================================== */
.footer {
  position: relative;
  z-index: 1;
  border-top: 1px solid var(--border);
  background: rgba(6, 6, 8, 0.9);
  padding-top: clamp(var(--space-lg), 6vw, var(--space-xl));
}
.footer__inner {
  display: grid;
  grid-template-columns: 1.4fr 2fr;
  gap: var(--space-lg);
  padding-bottom: var(--space-lg);
}
.footer__tag { margin-top: var(--space-md); color: var(--fg-subtle); font-size: 0.875rem; max-width: 34ch; }

.footer__nav { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-md); }
.footer__nav div { display: flex; flex-direction: column; }
.footer__head {
  font-family: var(--font-ui);
  font-size: 0.625rem; font-weight: 600;
  letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--fg-subtle);
  margin-bottom: var(--space-xs);
}
.footer__nav a {
  display: flex; align-items: center;
  min-height: 44px;              /* tap target, not a bare line of text */
  font-size: 0.875rem;
  color: var(--fg-muted);
  transition: color var(--t-fast) var(--ease-out);
  width: fit-content;
}
.footer__nav a:hover { color: var(--fg); }

.footer__base {
  display: flex; flex-wrap: wrap; gap: var(--space-xs) var(--space-md);
  justify-content: space-between;
  padding-block: var(--space-md);
  border-top: 1px solid var(--border);
  font-size: 0.75rem;
  color: var(--fg-subtle);
}
.footer__legal { font-style: italic; }

@media (max-width: 767px) {
  .footer__inner { grid-template-columns: 1fr; }
  .footer__nav { grid-template-columns: repeat(2, 1fr); }
}

/* ==========================================================================
   MOTION — reveal system
   Presets: y 24px / ~600ms / power2.out, stagger 80ms, capped at 8 children.
   Applied only under html.js so no-JS visitors and crawlers get final state.
   ========================================================================== */
.js .reveal {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition: opacity var(--reveal-dur) var(--ease-slow),
              transform var(--reveal-dur) var(--ease-slow);
  will-change: opacity, transform;
}
.js .reveal.is-in { opacity: 1; transform: translate3d(0, 0, 0); will-change: auto; }

.js [data-stagger] > * {
  opacity: 0;
  transform: translate3d(0, 20px, 0);
  transition: opacity 540ms var(--ease-slow), transform 540ms var(--ease-slow);
  transition-delay: calc(var(--i, 0) * 80ms);
}
.js [data-stagger].is-in > * { opacity: 1; transform: translate3d(0, 0, 0); }

/* Hero copy — held back until the scroll reveal fires.
   Only under .js: a no-JS visitor gets the copy immediately, since nothing
   would ever be there to reveal it. */
.js .shero__copy .lift {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition: opacity 760ms var(--ease-slow), transform 760ms var(--ease-slow);
  transition-delay: calc(var(--i, 0) * 90ms);
}
.js .shero__copy.is-revealed .lift {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}
/* The copy's own backdrop comes with it, or it would sit there as a dark
   band over the portrait before there is any text to justify it. */
.js .shero__copy::before {
  opacity: 0;
  transition: opacity 760ms var(--ease-slow);
}
.js .shero__copy.is-revealed::before { opacity: 1; }


/* ==========================================================================
   UI FURNITURE
   Body is now a text serif, so every label, button and micro-caps element has
   to be reassigned to the grotesque or it renders as small-caps serif.
   ========================================================================== */
.eyebrow, .nav__links a, .mobile-menu__links a, .proof__label, .stat dt,
.card__kicker, .card__metric-label, .quote__who strong, .quote__who span,
.skip-link, .hero__note, .footer__base, .booking__fallback p, .contact__list,
.logos li {
  font-family: var(--font-ui);
}
/* Serif numerals are the point — keep display figures on the display face */
.stat dd, .card__metric, .step__num, .card__num {
  font-family: var(--font-display);
}
.logos li { letter-spacing: 0.01em; font-weight: 500; }

/* Source Serif runs a touch light on a dark ground; nudge it back */
body { font-size: 17px; line-height: 1.66; }
.card__body, .step__content p, .faq__body p { font-size: 1rem; }

/* ==========================================================================
   SECTION GROUND
   The lower sections were a flat wash. Three restrained devices instead:
   margin rules bracketing the content column, a directional light per
   section that keeps the hero's chiaroscuro going, and a horizon hairline.
   Nothing here adds visual noise — it adds structure.
   ========================================================================== */

/* Margin rules — hung on .wrap so they land exactly on the content column */
.section > .wrap,
.proof > .wrap { position: relative; }

.section > .wrap::before,
.section > .wrap::after {
  content: '';
  position: absolute;
  top: -4vh; bottom: -4vh;
  width: 1px;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    transparent 0%,
    rgba(239, 235, 227, 0.11) 14%,
    rgba(239, 235, 227, 0.11) 86%,
    transparent 100%
  );
}
.section > .wrap::before { left: 0; }
.section > .wrap::after  { right: 0; }

.section--linen > .wrap::before,
.section--linen > .wrap::after {
  background: linear-gradient(
    180deg,
    transparent 0%,
    rgba(20, 24, 29, 0.16) 14%,
    rgba(20, 24, 29, 0.16) 86%,
    transparent 100%
  );
}

@media (max-width: 639px) {
  /* At phone width the rules sit under the thumb margin and just read as clutter */
  .section > .wrap::before, .section > .wrap::after { display: none; }
}

/* Directional light — alternates side so the page reads as lit from a
   moving source rather than evenly flooded. */
.section {
  background-image:
    radial-gradient(ellipse 70% 46% at 12% -4%, rgba(239, 235, 227, 0.045), transparent 62%),
    radial-gradient(ellipse 60% 40% at 96% 104%, rgba(27, 58, 92, 0.16), transparent 66%);
}
.section--alt {
  background-color: rgba(13, 13, 16, 0.66);
  background-image:
    radial-gradient(ellipse 70% 46% at 88% -4%, rgba(239, 235, 227, 0.05), transparent 62%),
    radial-gradient(ellipse 60% 40% at 6% 104%, rgba(27, 58, 92, 0.18), transparent 66%);
}
.section--linen { background-image: none; }

/* Horizon hairline — the edge where one section hands off to the next */
.section + .section,
.proof + .section {
  border-top: 1px solid rgba(239, 235, 227, 0.06);
}
.section--linen { border-top-color: rgba(239, 235, 227, 0.14); }

/* ==========================================================================
   MICRO-INTERACTIONS
   ========================================================================== */

/* ---- Typographic reveal ----
   Words rise out of their own overflow. This is the one that separates a
   designed page from a fade-up template; JS does the splitting. */
.js .split .w {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  /* room for descenders, which a plain overflow:hidden would guillotine */
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}
.js .split .w > i {
  display: inline-block;
  font-style: inherit;
  font-weight: inherit;
  transform: translate3d(0, 108%, 0);
  transition: transform 820ms var(--ease-slow);
  transition-delay: calc(var(--wi, 0) * 42ms);
}
.js .split.is-in .w > i,
.js .is-in .split .w > i { transform: translate3d(0, 0, 0); }

/* ---- Rule that draws in beside a section eyebrow ---- */
/* Scoped to section heads only, and only under .js — a no-JS visitor must
   never be left with an invisible rule. */
.js .reveal .eyebrow::before {
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 700ms var(--ease-slow) 140ms;
}
.js .reveal.is-in .eyebrow::before { transform: scaleX(1); }

/* ---- Directional underline: draws from the left, retracts to the right ---- */
.nav__links a::after {
  transform-origin: right;
  transition: transform 420ms var(--ease-slow);
}
.nav__links a:hover::after,
.nav__links a:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}

.footer__nav a, .contact__list a { position: relative; }
.footer__nav a::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 10px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 420ms var(--ease-slow);
}
.footer__nav a:hover::after,
.footer__nav a:focus-visible::after { transform: scaleX(1); transform-origin: left; }

/* ---- Cards: a light that follows the pointer, and a hairline that draws ---- */
.card { --mx: 50%; --my: 50%; overflow: hidden; }
.card::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    260px circle at var(--mx) var(--my),
    rgba(239, 235, 227, 0.055),
    transparent 62%
  );
  opacity: 0;
  transition: opacity 320ms var(--ease-out);
}
.card:hover::after { opacity: 1; }

.card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: var(--bone);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 520ms var(--ease-slow);
  pointer-events: none;
}
.card:hover::before { transform: scaleX(1); }

/* The kicker steps aside as the card wakes up. Under 2px — feedback, not motion. */
.card__num, .card__kicker, .card .icon {
  transition: transform 320ms var(--ease-out), color 320ms var(--ease-out);
}
.card:hover .card__num,
.card:hover .card__kicker,
.card:hover .icon { transform: translateX(2px); }
.card:hover .card__num { color: var(--fg); }

/* ---- Steps: the rule brightens and the number leads ---- */
.step { transition: border-color 420ms var(--ease-out); }
.step:hover { border-top-color: rgba(239, 235, 227, 0.3); }
.section--linen .step:hover { border-top-color: rgba(20, 24, 29, 0.4); }
.step__num { transition: transform 420ms var(--ease-slow), opacity 420ms var(--ease-out); }
.step:hover .step__num { transform: translateX(4px); }

/* ---- FAQ: the row indents and a rule draws down the left edge ---- */
.faq__item { position: relative; }
.faq__item::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 1px;
  background: var(--bone);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 420ms var(--ease-slow);
}
.faq__item[open]::before,
.faq__item:hover::before { transform: scaleY(1); }
.faq__item summary { transition: padding-left 420ms var(--ease-slow), color var(--t-fast); }
.faq__item[open] summary,
.faq__item:hover summary { padding-left: 18px; }

/* ---- Logos: the row dims so the hovered one steps forward ---- */
.logos:hover li { opacity: 0.34; }
.logos li { transition: opacity 340ms var(--ease-out), color 340ms var(--ease-out); }
.logos:hover li:hover { opacity: 1; color: var(--fg); }

/* ---- Stats: the dividing rules draw in as the row arrives ---- */
.stat { position: relative; }
.stat::after {
  content: '';
  position: absolute; right: -1px; top: 18%; bottom: 18%;
  width: 1px;
  background: var(--border-strong);
  transform: scaleY(0);
  transform-origin: center;
  transition: transform 700ms var(--ease-slow);
  transition-delay: calc(var(--i, 0) * 90ms + 260ms);
}
.stats.is-in .stat::after { transform: scaleY(1); }
.stat:last-child::after { display: none; }

/* ---- Magnetic primary CTA. One focal element, clamped. ---- */
.shero .btn--primary { will-change: transform; }

/* ==========================================================================
   REDUCED MOTION — everything above resolves to its final state
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .js .split .w > i { transform: none !important; transition: none !important; }
  .eyebrow::before { transform: scaleX(1) !important; }
  .stats .stat::after { transform: scaleY(1) !important; }
  .card::after { display: none; }
  .card::before,
  .faq__item::before { transition: none !important; }
  .card:hover .card__num,
  .card:hover .card__kicker,
  .card:hover .icon,
  .step:hover .step__num { transform: none !important; }
  .faq__item[open] summary,
  .faq__item:hover summary { padding-left: 0; }
}

@media (hover: none) {
  /* Nothing hover-dependent should fire on tap */
  .card::after, .card::before { display: none; }
  .logos:hover li { opacity: 0.7; }
  .faq__item:hover summary { padding-left: 0; }
  .faq__item[open] summary { padding-left: 18px; }
}

/* ==========================================================================
   REDUCED MOTION — final state, immediately.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .js .reveal, .js [data-stagger] > *, .js .lift {
    opacity: 1 !important; transform: none !important; animation: none !important;
  }
  .atmos__light, .atmos__pool, .atmos__grain { animation: none !important; }
  .btn--primary::after { display: none; }
}

/* Coarse pointers get no hover-lift — it fires on tap and reads as lag */
@media (hover: none) {
  .card:hover, .btn--primary:hover, .btn--ghost:hover { transform: none; }
}

/* ---------- Print ---------- */
@media print {
  .atmos, .nav, .mobile-menu, .booking { display: none !important; }
  body { background: #fff; color: #000; }
  .js .reveal, .js [data-stagger] > *, .js .lift { opacity: 1 !important; transform: none !important; }
}
