/* ============================================================
   Lenis smooth-scroll base styles (required by the library)
   ============================================================ */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }
.lenis.lenis-smooth iframe { pointer-events: none; }

/* ============================================================
   Crewsive — design tokens & base
   SaaS / tech-company aesthetic, faded blue accent
   ============================================================ */

:root {
  --bg:        oklch(0.145 0.012 245);
  --bg-2:      oklch(0.180 0.014 245);
  --bg-3:      oklch(0.225 0.016 245);
  --bg-4:      oklch(0.270 0.018 245);
  --ink:       oklch(0.97 0.008 245);
  --ink-2:     oklch(0.84 0.010 245);
  --ink-3:     oklch(0.62 0.012 245);
  --ink-4:     oklch(0.42 0.012 245);
  --rule:      oklch(1 0 0 / 0.10);
  --rule-2:    oklch(1 0 0 / 0.05);

  --accent:    oklch(0.70 0.090 245);
  --accent-2:  oklch(0.78 0.075 240);
  --accent-soft: oklch(0.70 0.090 245 / 0.14);
  --good:      oklch(0.78 0.13 160);
  --warn:      oklch(0.80 0.13 65);
  --hot:       oklch(0.66 0.20 30);

  --serif: "Instrument Serif", "Instrument Serif Fallback", "EB Garamond", Georgia, serif;
  --sans:  "Inter Tight", "Inter", ui-sans-serif, system-ui, sans-serif;
  /* Secondary face — small UI labels, eyebrows, the hero meta strip.
     Was JetBrains Mono; now Helvetica Neue (with Arial as the
     Windows/no-Helvetica fallback). The thin weight has to be set
     on the consuming rule because custom properties can't carry
     font-weight; see `.hero .meta-strip` and similar. */
  --mono:  "Helvetica Neue", Helvetica, Arial, "Inter Tight", sans-serif;

  --max:    1440px;
  --gutter: clamp(20px, 4vw, 56px);
  --radius: 12px;
  --radius-lg: 18px;
  --radius-xl: 24px;

  /* ── Motion ───────────────────────────────────────────── */
  /* Curves — every transition / animation picks from these. */
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);     /* Apple-feel default — most hovers, reveals */
  --ease-out-soft: cubic-bezier(0.2, 0.8, 0.2, 1);    /* menus, panel reveals, picker tabs */
  --ease-cine:     cubic-bezier(0.45, 0.05, 0.2, 1);  /* dramatic accel-decel — ball zip, hint arrow */
  --ease-in:       cubic-bezier(0.55, 0, 0.95, 0.38); /* exits, collapses, things going away */
  /* Speeds — five-step scale. New motion should snap to one of these. */
  --dur-fast:   160ms;  /* form inputs, color/border state on small UI */
  --dur-base:   250ms;  /* default UI hover/click */
  --dur-medium: 400ms;  /* panel reveals, menu nav-bar swap */
  --dur-slow:   700ms;  /* big section moments, primary menu rows */
  --dur-cine:   920ms;  /* hero scroll-jack lift, ambient menu type */
  --dur-press:  140ms;  /* tactile press feedback — under Emil Kowalski's ~180ms micro-interaction target */
  --ease-press: cubic-bezier(0.34, 1.40, 0.64, 1); /* gentle overshoot settle on release */
  --stagger:    60ms;   /* base per-item delay for reveal cadence */

  /* Live scroll velocity, written each frame by the VelocityMotion
     effect (brand.jsx) from lenis.velocity. Drives the premium
     "lean into the scroll" skew on non-pinned content + the
     velocity-reactive marquee. Clamped in JS; rests at 0. */
  --scroll-skew: 0deg;
  --scroll-vel: 0;
}

[data-theme="light"]{
  --bg:    oklch(0.985 0.005 245);
  --bg-2:  oklch(0.960 0.007 245);
  --bg-3:  oklch(0.930 0.010 245);
  --bg-4:  oklch(0.900 0.012 245);
  --ink:   oklch(0.18 0.012 245);
  --ink-2: oklch(0.30 0.012 245);
  --ink-3: oklch(0.50 0.012 245);
  --ink-4: oklch(0.66 0.012 245);
  --rule:  oklch(0 0 0 / 0.10);
  --rule-2:oklch(0 0 0 / 0.05);
  --accent:oklch(0.55 0.12 245);
  --accent-2:oklch(0.62 0.10 240);
  --accent-soft: oklch(0.55 0.12 245 / 0.10);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Clip horizontal overflow at both html and body. CRITICAL —
   must be `clip`, not `hidden`. `overflow: hidden` on html
   creates a new scrolling container, which silently breaks
   `position: sticky` anywhere on the page (the IntroCoverJack
   stage stops pinning, the hero shelf stops lifting). `clip`
   prevents the same horizontal escape (nav-menu ambient type,
   menu halo) without making html/body a scroll container, so
   the document's scroll element stays the viewport and sticky
   keeps working. */
html { overflow-x: clip; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* Variable fonts render finer high-contrast strokes at display
     sizes and thicker/legible strokes at body sizes when they ship
     an `opsz` axis — harmless no-op otherwise. */
  font-optical-sizing: auto;
  line-height: 1.55;
  overflow-x: clip;
}

/* ── Typographic rendering polish ─────────────────────────────
   `balance` evens out display headings (≤~6 lines) so no line is a
   lonely orphan; `pretty` does the lighter last-line fix on body
   copy (Chromium-only, body-text-scoped to avoid its perf cost on
   large blocks). Both degrade gracefully where unsupported. */
h1, h2, h3, .serif { text-wrap: balance; }
p { text-wrap: pretty; }

/* Metric-matched fallback for the display serif. Georgia is
   size-adjusted toward Instrument Serif's metrics so the swap when
   the webfont loads doesn't shift layout (CLS) — type-jump on load
   is a top tell of an unpolished site. Values are approximate
   (Instrument Serif is a tall, narrow display serif); they get the
   line-box close enough that the reflow is imperceptible. */
@font-face {
  font-family: "Instrument Serif Fallback";
  src: local("Georgia");
  size-adjust: 92%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

/* ============================================================
   HERO scroll-jack zone
   The Hero card is sticky-pinned at the top of a 200vh wrapper.
   Inside the same wrapper, the Intro is also sticky at the top,
   stacked behind the Hero. As the user scrolls 0 → 100vh:
     • the Intro stays exactly where it is (visible behind the
       Hero's frosted glass — that's the "look through" effect)
     • the Hero card translates upward via a scroll-driven
       animation, lifting off and exposing the clear Intro
   At scrollTop = 100vh both stickies release; normal page flow
   resumes into Services and beyond.
   ============================================================ */
::selection { background: var(--accent); color: var(--bg); }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
img { max-width: 100%; display: block; }

/* ── Atmosphere FX layers ─────────────────────────────────────
   Two fixed, pointer-events:none overlays that give the near-black
   palette depth without touching layout or blocking input. Both are
   static (no per-frame work). They sit above section backgrounds
   but below the nav/chrome (z 220) so the chrome isn't tinted. */
.fx-atmosphere,
.fx-grain {
  position: fixed;
  inset: 0;
  pointer-events: none;
}
/* Accent light-pool at the top + a gentle vignette. The vignette's
   center is transparent so centered content stays clean — only the
   frame darkens, focusing the eye and killing dead-flat corners. */
.fx-atmosphere {
  z-index: 2;
  background:
    radial-gradient(120% 80% at 50% -12%,
      color-mix(in oklch, var(--accent) 12%, transparent), transparent 55%),
    radial-gradient(145% 125% at 50% 48%,
      transparent 62%, rgba(0, 0, 0, 0.30) 100%);
}
/* Static film grain — one noise tile, repeated, low opacity, overlay
   blend so it adds texture/breaks banding without shifting hue. No
   animation (animated feTurbulence is a CPU trap). */
.fx-grain {
  z-index: 3;
  opacity: 0.05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}
@media (prefers-reduced-motion: reduce) {
  .fx-grain { opacity: 0.035; }
}

.shell { width: 100%; max-width: var(--max); margin: 0 auto; padding-inline: var(--gutter); }
.serif { font-family: var(--serif); font-weight: 400; letter-spacing: -0.012em; line-height: 1.02; text-wrap: balance; }
.italic { font-style: italic; }
.mono { font-family: var(--mono); font-size: 11px; letter-spacing: 0.04em; color: var(--ink-3); }

.eyebrow {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-3);
  display: inline-flex; align-items: center; gap: 10px;
}
.eyebrow .dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 4px color-mix(in oklch, var(--accent) 25%, transparent);
}

/* ============================================================
   Wordmark — real cursive font (Caveat 700), slanted for
   architectural masculine feel. Reads instantly as "Crewsive".
   ============================================================ */
.crewsive-wm {
  font-family: "Caveat", cursive;
  font-weight: 700;
  font-style: normal;
  letter-spacing: -0.01em;
  line-height: 1;
  display: inline-block;
  transform: skewX(-6deg);
  transform-origin: 50% 60%;
  color: currentColor;
  white-space: nowrap;
  position: relative;
  padding: 0 0.18em 0.06em;
  text-transform: none !important;
}
.crewsive-wm::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  bottom: 0.12em;
  height: 0.06em;
  background: currentColor;
  opacity: 0.7;
  border-radius: 99px;
  transform: rotate(-1.5deg);
}

/* ============================================================
   Top nav
   ============================================================ */

.nav {
  position: fixed; top: 0; left: 0; right: 0;
  /* sits above the editorial menu overlay (200) so brand + CTA + close
     button remain visible — matches Jacob & Co's persistent chrome. */
  z-index: 220;
  /* Brand is absolutely centered; nav__right floats on the right. */
  display: flex; align-items: center; justify-content: flex-end;
  /* taller, more confident chrome */
  padding: 22px var(--gutter);
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-2);
  /* Solid bar — opaque, no glass blur. */
  background: var(--bg);
  border-bottom: 1px solid var(--rule-2);
  transition: background var(--dur-medium) var(--menu-ease), border-color var(--dur-medium) var(--menu-ease);
}
/* Earlier draft hid the trigger globally — that left the
   full-screen overlay menu unreachable on every viewport.
   The Jacob & Co–style trigger styling below (line ~2790)
   already gives it the right dimensions and the close-icon
   crossfade, so override display here too. */
.nav-trigger { width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center; }
.nav-trigger__close { font-size: 44px; }
/* When menu is open, drop the nav background so it floats clean over the overlay */
body.menu-open .nav {
  background: transparent;
  border-bottom-color: transparent;
}
.nav .brand {
  display: inline-flex; align-items: center; gap: 8px; color: var(--ink);
  /* Centered horizontally in the nav bar regardless of what sits in
     `.nav__right` on the trailing edge. */
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
.nav .brand__logo {
  display: block;
  height: 36px;
  width: auto;
  /* PNG ships with a black background — screen blends it out so
     only the white wordmark reads against the dark nav surface. */
  mix-blend-mode: screen;
}
.nav .links { display: flex; gap: 26px; }
.nav .links a:hover { color: var(--ink); }
.nav .cta {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 10px 16px;
  border: 1px solid color-mix(in oklch, var(--accent) 45%, transparent);
  border-radius: 0;
  background: transparent;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  transition: background var(--dur-base) ease, color var(--dur-base) ease, border-color var(--dur-base) ease, transform var(--dur-base) ease;
}
.nav .cta span[aria-hidden] {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  border-radius: 0;
  background: color-mix(in oklch, var(--accent) 18%, transparent);
  font-size: 10px; letter-spacing: 0;
  transition: background var(--dur-base) ease, color var(--dur-base) ease, transform var(--dur-base) ease;
}
.nav .cta:hover { background: var(--accent); color: var(--bg); border-color: var(--accent); transform: translateY(-1px); }
.nav .cta:hover span[aria-hidden] { background: var(--bg); color: var(--accent); transform: translateX(1px); }
@media (max-width: 720px) { .nav .links { display: none; } }

/* Mobile nav layout — Crewsive logo centered, hamburger and
   inline CTA hidden up top. The desktop full-screen menu is
   hover-driven and links to sections that aren't mounted on
   this page, so it stays off on phones; the brand is the only
   top chrome. The primary action is NOT dropped on mobile — it
   moves to `.mobile-jump-cta` below, a persistent thumb-zone
   pill, so a phone visitor can always convert without scrolling
   the whole page to the form. */
@media (max-width: 720px) {
  /* Center the logo as a normal in-flow item. The desktop brand is
     position:absolute on the nav's vertical midline, but on mobile
     nav__right is hidden so the bar collapses to just its padding
     (~28px) — the 32px logo centered on that overflowed the top
     edge and clipped. Static + justify-center + a real top inset
     (incl. notch safe-area) gives the wordmark full clearance. */
  .nav {
    justify-content: center;
    padding: max(16px, calc(env(safe-area-inset-top, 0px) + 12px)) var(--gutter) 14px;
  }
  /* Mobile keeps the menu trigger so the full-screen menu is reachable;
     only the inline "Join the crew" CTA drops (MobileJumpCta covers
     conversion). nav__right is pulled out of flow to the right edge so
     the wordmark can stay centered. */
  .nav .cta { display: none; }
  .nav .nav__right {
    display: flex;
    position: absolute;
    right: var(--gutter);
    top: 50%;
    transform: translateY(-50%);
  }
  .nav .nav-trigger { display: inline-flex; }
  .nav .brand {
    position: static;
    left: auto;
    top: auto;
    transform: none;
  }
  .nav .brand__logo,
  .nav .brand svg { height: 30px; }
}

/* Persistent mobile primary action. Lives in the bottom thumb
   zone (where ~75% of taps land), squared accent pill matching
   the nav/`work-with-me` CTA language. Hidden on desktop. JS
   (MobileJumpCta) toggles `.is-visible`: it appears once the
   reader reaches the Manifesto — keeping the cinematic hero and
   cover/donut scrolljack scenes clean — and hides again when the
   real email form scrolls in, so it never doubles that button. */
.mobile-jump-cta { display: none; }
@media (max-width: 720px) {
  .mobile-jump-cta {
    position: fixed;
    left: 50%;
    bottom: calc(20px + env(safe-area-inset-bottom, 0px));
    z-index: 80;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 15px 26px;
    background: var(--accent);
    color: var(--bg);
    font-family: var(--mono);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
    border-radius: 0;
    box-shadow: 0 12px 34px -10px rgba(0, 0, 0, 0.7);
    /* Resting (hidden) state — nudged down + faded, no pointer. */
    opacity: 0;
    transform: translate(-50%, 26px);
    pointer-events: none;
    transition:
      opacity var(--dur-medium) var(--ease-out-expo),
      transform var(--dur-medium) var(--ease-out-expo);
  }
  .mobile-jump-cta.is-visible {
    opacity: 1;
    transform: translate(-50%, 0);
    pointer-events: auto;
  }
  .mobile-jump-cta span[aria-hidden] {
    font-size: 13px;
    transition: transform var(--dur-base) var(--ease-out-expo);
  }
  .mobile-jump-cta:active span[aria-hidden] { transform: translate(2px, -2px); }
}

/* Scroll-progress orientation cue — mobile only. This page is
   ~7 viewports tall and ~85% of that is pinned scrolljack, where
   the scrollbar gives almost no sense of "how far through am I."
   A 2px accent hairline at the top edge fills left→right with
   scroll progress. Transform-only (compositor-friendly) and
   gated to phones so desktop chrome is untouched. */
.scroll-progress { display: none; }
@media (max-width: 720px) {
  .scroll-progress {
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    /* Above the nav (z 220) — a top-edge progress hairline belongs
       on top of the header, not behind it. */
    z-index: 230;
    background: color-mix(in oklch, var(--ink) 8%, transparent);
    pointer-events: none;
  }
  .scroll-progress__fill {
    height: 100%;
    background: var(--accent);
    transform: scaleX(0);
    transform-origin: 0 50%;
  }
}
@media (prefers-reduced-motion: reduce) {
  .mobile-jump-cta { transition: opacity 0.2s linear; transform: translate(-50%, 0); }
  .mobile-jump-cta:not(.is-visible) { transform: translate(-50%, 0); }
}

/* ============================================================
   Buttons
   ============================================================ */

a.btn, .btn {
  display: inline-flex !important;
  align-items: center;
  gap: 12px;
  padding: 13px 20px;
  border-radius: 8px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 500;
  transition: transform var(--dur-base) ease, background var(--dur-base) ease, color var(--dur-base) ease, border-color var(--dur-base) ease;
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
}
a.btn-primary, .btn-primary { background: var(--accent); color: var(--bg); }
a.btn-primary:hover, .btn-primary:hover { transform: translateY(-1px); background: var(--accent-2); }
.btn-primary .arr {
  width: 20px; height: 20px; border-radius: 4px;
  background: var(--bg); color: var(--accent);
  display: inline-flex; align-items: center; justify-content: center; font-size: 11px;
  transition: transform var(--dur-base) ease;
}
.btn-primary:hover .arr { transform: translateX(2px); }
a.btn-ghost, .btn-ghost { color: var(--ink); border-color: var(--rule); background: transparent; }
a.btn-ghost:hover, .btn-ghost:hover {
  border-color: color-mix(in oklch, var(--ink) 50%, transparent);
  background: var(--bg-2);
}

/* ============================================================
   Section heads
   ============================================================ */

.section-head {
  display: grid; grid-template-columns: 200px 1fr; gap: 40px;
  align-items: start; padding-top: 64px;
}
.section-head .num {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  color: var(--ink-3); text-transform: uppercase;
  display: inline-flex; align-items: center; gap: 10px;
}
.section-head .num::before { content: ""; width: 24px; height: 1px; background: var(--accent); }
.section-head h2 {
  margin: 0;
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(40px, 5.4vw, 76px);
  line-height: 0.98; letter-spacing: -0.018em;
  text-wrap: balance;
}
.section-head h2 em { color: var(--accent); font-style: italic; }
@media (max-width: 720px) {
  .section-head { grid-template-columns: 1fr; gap: 16px; padding-top: 48px; }
}

/* ============================================================
   Hero — full-bleed ambient with build-things-being-refined
   ============================================================ */

/* ── 1. The scroll-jack wrapper. 200vh tall so the page has
        100vh of "buffer" scroll for the jack to play through.
        White background so once the sticky stage releases (last
        100vh of the wrapper), the empty space matches the blank
        white card revealed by the IntroCoverJack right after. */
.hero-jack {
  position: relative;
  height: 200vh;
  background: #ffffff;
}

/* The stage is a single sticky 100vh layer pinned to the top of
   the wrapper. Inside the stage, the floor (Intro) and shelf
   (Hero) are absolutely-positioned and fully overlap — that's
   what makes them occupy the same viewport from scrollTop=0,
   with the Hero's glass diffusing the Intro behind it. */
.hero-jack__stage {
  position: sticky;
  top: 0;
  /* `dvh` tracks the live viewport so the pinned stage always
     fills exactly the visible area on mobile. Raw `100vh` is
     measured against the EXPANDED address-bar state, so the
     pinned scene overflowed and "jumped" when the iOS/Android
     toolbar showed or hid mid-scroll. `vh` stays as the fallback
     for engines without `dvh`; on desktop the two are identical. */
  height: 100vh;
  height: 100dvh;
  width: 100%;
  overflow: hidden;
}

.hero-jack__shelf,
.hero-jack__floor {
  position: absolute;
  inset: 0;
}
.hero-jack__shelf { z-index: 2; }
.hero-jack__floor { z-index: 1; }

/* Intro fills the 100vh stage as a clean white surface — no
   content right now, it's just the blank white card the Hero
   lifts off of and the IntroCoverJack reveals. */
.hero-jack__floor .intro {
  height: 100%;
  padding: 0;
}

/* The shelf's lift is driven by JS (see Hero.jsx scroll handler).
   We declare will-change here so the GPU keeps a layer ready. */
.hero-jack__shelf { will-change: transform, opacity; }

@media (prefers-reduced-motion: reduce) {
  .hero-jack__shelf {
    transform: none !important;
    opacity: 1 !important;
  }
}

/* Mobile keeps the full sticky scroll-jack — same 200vh wrapper
   and 100vh sticky stage as desktop, so the Hero lift behaves
   the same on phones. */

/* On phones the hero-card lift clamps to window.innerHeight while
   the wrappers measure in vh/dvh. When the address bar shows/hides
   those don't match, briefly exposing the white hero-jack floor as
   a band between the dark hero card and the dark IntroCoverJack
   cover when scrolling up. Painting the wrapper + floor dark makes
   any such seam invisible (both the card and the cover are var(--bg)).
   Desktop keeps the white floor — the dark cover peels off of it. */
@media (max-width: 720px) {
  .hero-jack { background: var(--bg); }
  .hero-jack__floor .intro,
  .intro { background: var(--bg); }
}

/* ── 2. The Hero card — solid dark surface. Subtle 1px top-edge
        highlight + soft drop shadow so it reads as a card
        floating on the page, even though card and page share
        the same dark base color. */
.hero {
  position: relative;
  margin: 0;
  border-radius: 0;
  overflow: hidden;
  height: 100%;
  width: 100%;
  background: var(--bg);
  border: 0;
  box-shadow: none;
}

.hero__content {
  position: relative;
  z-index: 1;
  display: grid;
  /* Single row now that the meta-strip lives at the page level
     as <HeroMeta />. Was `auto 1fr` to give the meta-strip its
     own row above the stage; with only .stage left here the auto
     row was capturing the headline and breaking its vertical
     centering. */
  grid-template-rows: 1fr;
  height: 100%;
  padding: 96px var(--gutter) 56px;
}

[data-theme="light"] .hero {
  background: var(--bg);
  border-color: color-mix(in oklch, black 8%, transparent);
  box-shadow:
    0 32px 80px -22px color-mix(in oklch, black 18%, transparent),
    0 6px 18px -8px color-mix(in oklch, black 12%, transparent),
    inset 0 1px 0 color-mix(in oklch, white 50%, transparent);
}

@media (max-width: 720px) {
  /* Keep the sticky scrolljack dimensions; just tighten padding
     and pull the headline scale down for phones. The scale
     override has to live below the desktop `.hero h1` rule for
     source-order to win — see the second @media block. */
  .hero__content { padding: 80px 12px 40px; }
  .hero .stage { padding-block: clamp(16px, 3vh, 32px); row-gap: clamp(14px, 2vh, 24px); }
}

.hero .meta-strip {
  display: flex; justify-content: space-between;
  font-family: var(--mono); font-weight: 200; font-size: 11px; color: var(--ink-3);
  letter-spacing: 0.08em; text-transform: uppercase;
}

/* Top-level fixed meta-strip. Lives at the same visual top-row as
   the old hero strip (96px from viewport top, matching hero
   padding), but pinned with `position: fixed` so it survives
   through the IntroCoverJack white stage and only fades out as
   the circle bloom completes. mix-blend-mode: difference auto-
   inverts white text against whatever's beneath — readable on
   the dark hero, on the white stage, and on the post-inversion
   dark stage without a JS color swap. Sits below the nav (z=220)
   but above page content. */
.hero-meta {
  position: fixed;
  top: 96px;
  left: var(--gutter);
  right: var(--gutter);
  display: flex;
  justify-content: space-between;
  font-family: var(--mono);
  font-weight: 200;
  font-size: 11px;
  color: #ffffff;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  pointer-events: none;
  z-index: 50;
  mix-blend-mode: difference;
  /* Same intro fade-in as the original meta-strip so the hero
     entrance still reads. After that, opacity is driven entirely
     by the JS scroll handler in <HeroMeta />. */
  opacity: 0;
  animation: heroFadeIn 0.6s ease-out 0.2s forwards;
  will-change: opacity;
}

@media (max-width: 720px) {
  /* Sticky scroll-jack collapses on mobile and the IntroCoverJack
     skips its sticky behavior, so the fixed meta-strip would just
     hover awkwardly over the page. Hide it on small viewports. */
  .hero-meta { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hero-meta { animation: none; opacity: 1; }
}
.hero .meta-strip .nowdot { display: inline-flex; align-items: center; gap: 8px; }
.hero .meta-strip .nowdot::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--good);
  box-shadow: 0 0 0 4px color-mix(in oklch, var(--good) 25%, transparent);
}

.hero .stage {
  display: grid;
  align-content: center;
  justify-items: center;
  text-align: center;
  padding-block: clamp(24px, 4vh, 48px);
  /* Tight row-gap — the rolldowns sit close to the headline so the
     space the labels travel during lift/drop reads as one continuous
     motion instead of crossing a void. */
  row-gap: clamp(10px, 1.4vh, 18px);
}
.hero h1 {
  margin: 0 auto;
  font-family: var(--serif); font-weight: 400;
  /* fluid scale tuned for 1280 → 2560+ desktop range. clamp's
     middle term is the live size at every viewport width, with
     a minimum for laptops and a ceiling so 4K doesn't go absurd.
     max-width in ch keeps the headline as 2 balanced lines
     across all common desktop resolutions. */
  font-size: clamp(64px, 9.6vw, 168px);
  line-height: 1.02; letter-spacing: -0.028em;
  max-width: 22ch;
  padding-bottom: 0.12em;
  text-wrap: balance;
}
.hero h1 .em,
.hero h1 .hw-word.em { color: var(--accent); font-style: italic; }

/* Mobile override — must come AFTER the desktop `.hero h1`
   rule above (same specificity, so source order decides).
   Stack the four words VERTICALLY left-aligned: each `.hw-word`
   gets its own line by forcing display: block on each word
   span, dropping the text-wrap balance + max-width that the
   desktop rule uses for a centered two-line headline. The
   per-character cascade animation keeps working because the
   chars are still inside their .hw-word parents. */
@media (max-width: 720px) {
  .hero .stage {
    align-content: start;
    justify-items: stretch;
    text-align: left;
    padding-top: clamp(48px, 8vh, 96px);
  }
  .hero h1 {
    margin: 0;
    text-align: left;
    text-wrap: initial;
    max-width: none;
    /* Much larger on phones so "I help businesses grow." commands the
       screen. "businesses" is the limiting line — it only used ~67%
       of the content width at the old 18vw, so there was generous
       headroom to grow into. */
    font-size: clamp(72px, 25vw, 140px);
    line-height: 0.98;
    /* Slightly tighter than desktop so the longest line ("businesses")
       still clears the gutter at the larger size. */
    letter-spacing: -0.032em;
    /* Italic accents ("businesses", "grow.") overhang left of the text
       origin; without this pad the swash sits on / past the screen
       edge and reads as clipped. In em so it scales with the type. */
    padding-left: 0.14em;
    padding-bottom: 0;
  }
  .hero h1 .hw-word {
    display: block;
  }
}

/* The "i" in "business" is rendered as a dotless stem (ı) plus
   a separate .i-ball that occupies where the dot would normally
   sit. After the headline cascade, JS triggers the ball to
   detach, arc through space, and land on the "Together" label.
   The numeric tweaks (top, width) are tuned for Instrument
   Serif's metrics — the ball reads as "the dot of the i" until
   it moves. */
.hw-char--i {
  position: relative;
  display: inline-block;
}
.hw-char--i .i-stem {
  display: inline-block;
}
.hw-char--i .i-ball {
  position: absolute;
  top: 0.06em;
  left: calc(50% - 0.05em);
  width: 0.10em;
  height: 0.10em;
  border-radius: 50%;
  background: currentColor;
  pointer-events: none;
  z-index: 2;
  /* offset-rotate kept fixed so the dot doesn't appear to spin
     along the curve (though for a circle it's invisible anyway) */
  offset-rotate: 0deg;
  offset-distance: 0%;
}

/* Ball journey — drives offset-distance along a CSS path() set
   at runtime by JS (ball.style.offsetPath). The path is a real
   Bezier curve composed of two cubics joined smoothly via an
   "S" command: leg one wraps around the right side of
   "business.", leg two sweeps in a long flowing arc leftward
   to "Together". offset-path gives genuine curvature, not the
   geometric segments translate-keyframes can approximate.
   Opacity stays at 1 for the entire journey and only fades in
   the last 8%, so the dot is solid the whole time it's
   travelling and disappears only after landing on Together. */
.hw-char--i .i-ball.zipping {
  animation: ballZip 2.4s var(--ease-cine) forwards;
  will-change: offset-distance, opacity, transform;
}
/* Scale variations layered on top of the path travel give the
   dot a touch of personality without the whiplash — soft pop on
   the rise, gentle compress at the corner wrap, and an easy
   settle into the landing. Opacity stays at 1 the whole journey,
   fades only after the ball has settled atop "Together". */
@keyframes ballZip {
  0%   { offset-distance: 0%;   transform: scale(1);    opacity: 1; }
  22%  { transform: scale(1.08); }
  50%  { transform: scale(0.96); }
  78%  { transform: scale(1.05); }
  92%  { offset-distance: 100%; transform: scale(0.98); opacity: 1; }
  100% { offset-distance: 100%; transform: scale(0.5);  opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .hw-char--i .i-ball.zipping { animation: none; }
}

/* Per-character rise-from-mask, Ouro Labs style. Each .hw-word
   doubles as a clip mask: clip-path leaves horizontal sides
   untouched (so adjacent words can paint into each other's bbox
   via kerning) but clips above ascender slack and below the
   baseline, so any character translated past either edge
   disappears cleanly. Each .hw-char starts pushed 1.5em below
   baseline with a ±2deg rotation and opacity 0; a `.revealed`
   flag on ANY ancestor flips them to their resting state with a
   long expoOut curve. Per-letter duration / rotation / delay are
   baked in via inline CSS vars (--cd, --cr) at render time so
   the motion never marches in lockstep — that randomization is
   the secret to the premium feel. On scroll, JS adds `.is-exit`
   to each hero char which drops it back below the mask with a
   faster snap-in curve.

   The selectors are intentionally generic (not `.hero h1 ...`)
   so the same machinery powers the hero headline AND the
   secondary "how?" tag below it. Each rise group just needs a
   `.hw-word` wrapper around chars and a `.revealed` flip on an
   ancestor. */
.hw-word {
  display: inline-block;
  white-space: nowrap;
  /* Vertical-only mask: clip just above the ascender line and
     well below the baseline (-0.62em) so the deep, left-curling
     descender of the italic "g" in "grow." paints fully at the
     large hero size (the old -0.28em sliced its tail). Still tight
     enough to hide chars translated 2.1em down (entrance) or
     1.35em+16px down (exit). Horizontal sides extend -1000px so
     the line still reads as a single text run. */
  clip-path: inset(-0.05em -1000px -0.62em -1000px);
}
.hw-word .hw-char {
  display: inline-block;
  opacity: 0;
  /* 2.1em (was 1.5em) so chars still start below the looser -0.62em
     descender mask above and stay hidden until they rise. */
  transform: translate3d(0, 2.1em, 0) rotate(var(--cr, 0deg));
  transform-origin: 50% 100%;
  transition:
    transform var(--cd, var(--dur-cine)) var(--ease-out-expo),
    opacity 0s linear;
  will-change: transform, opacity;
  backface-visibility: hidden;
}
.revealed .hw-word .hw-char {
  transform: translate3d(0, 0, 0) rotate(0deg);
  opacity: 1;
}
.hw-word .hw-char.is-exit {
  transform: translate3d(0, calc(1.35em + 16px), 0.02px) rotate(0deg) !important;
  transition-property: transform !important;
  transition-duration: var(--dur-medium) !important;
  transition-timing-function: var(--ease-in) !important;
}

.hero .meta-strip {
  opacity: 0;
  animation: heroFadeIn 0.6s ease-out 0.2s both;
}
.hero .undertags {
  opacity: 0;
  animation: heroFadeIn 0.65s ease-out 1.85s both;
}
.hero .hero-sub {
  opacity: 0;
  animation: heroFadeIn 0.65s ease-out 1.85s both;
}
@keyframes heroFadeIn {
  to { opacity: 1; }
}

/* ============================================================
   Hero sub — single-paragraph sub-line under the headline.
   Lives in the same slot the .undertags rolldowns occupied,
   shares the same sans/font-size baseline, but as plain prose.
   Replaced the three-pillar rolldowns 2026-05-07. The original
   structure is fully preserved in `archive/hero-v1-2026-05-07.md`.
   ============================================================ */
.hero .hero-sub {
  margin: 0 auto;
  max-width: 56ch;
  padding-top: clamp(8px, 1.0vh, 14px);
  font-family: var(--sans);
  font-weight: 300;
  font-size: clamp(22px, 1.95vw, 30px);
  line-height: 1.4;
  letter-spacing: -0.005em;
  color: var(--ink);
  text-align: center;
  text-wrap: balance;
}

/* ============================================================
   "how?" tag — secondary headline that rises in after the hero,
   then on hover the word slides up and out while a paragraph
   rises into the same visual line. Same rolldown choreography as
   the original "Together" pillar: per-character wave, word-level
   overflow mask, label and detail moving in lockstep upward.
   First hover locks the open state for the rest of the session
   (parent gets `.is-locked`), so the paragraph stays even when
   you scroll past — unlike the headline, which drops. The row
   is OUTSIDE the hero h1 so the per-letter scroll-exit ignores
   it. */
.hero-howtag {
  position: relative;
  display: flex;
  justify-content: center;
  margin: clamp(20px, 3vh, 40px) auto 0;
  outline: 0;
  /* Container fades up after the rise machinery is armed so the
     paragraph below isn't visible (even faintly) before the
     entrance. */
  opacity: 0;
  transition: opacity var(--dur-medium) var(--ease-out-expo) 0.05s;
  cursor: pointer;
}
.hero-howtag.is-armed { opacity: 1; }

/* Inline-block parent that anchors the absolute-positioned
   detail. Width tracks the label so the detail can be centered
   over the same horizontal midpoint regardless of viewport. */
.hero-howtag__rd {
  position: relative;
  display: inline-block;
}

.hero-howtag__label {
  display: inline-block;
  position: relative;       /* anchor for pulsing underline pseudo */
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(28px, 3.2vw, 48px);
  line-height: 1.1;
  letter-spacing: -0.012em;
  color: var(--ink);
  /* The .hw-char rise machinery handles the entrance. On hover
     (or once locked), the WHOLE label translates up + fades so
     it cleanly clears the slot for the paragraph. */
  transition:
    transform var(--dur-cine) var(--ease-out-expo),
    opacity var(--dur-medium) var(--ease-out-expo) 140ms;
  will-change: transform, opacity;
}
.hero-howtag:hover .hero-howtag__label,
.hero-howtag:focus-visible .hero-howtag__label,
.hero-howtag.is-locked .hero-howtag__label {
  transform: translateY(-1.3em);
  opacity: 0;
}

/* Hover-cue underline. A faint white base line sits under "how?"
   while a pure-white highlight continuously travels left → right
   across it. The whole pseudo fades in a beat after the label
   cascade resolves, so it doesn't clash with the entrance. The
   pseudo lives on the label so it inherits the label's fade-out
   when the tag is hovered/locked. */
.hero-howtag__label::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.08em;
  height: 1px;
  pointer-events: none;
  opacity: 0;
  background:
    /* Top layer: traveling pure-white highlight (30% wide). */
    linear-gradient(
      90deg,
      transparent 0%,
      #ffffff 50%,
      transparent 100%
    ) -30% 0 / 30% 100% no-repeat,
    /* Base layer: faint white line that's always visible. */
    linear-gradient(
      90deg,
      rgba(255, 255, 255, 0.28),
      rgba(255, 255, 255, 0.28)
    ) 0 0 / 100% 100% no-repeat;
  animation:
    how-cue-in 0.55s ease-out 1.2s forwards,
    how-cue-sweep 1.8s linear 1.2s infinite;
}
@keyframes how-cue-in {
  to { opacity: 1; }
}
@keyframes how-cue-sweep {
  /* Continuous left-to-right travel — the highlight enters from
     the left, crosses the line, exits on the right, then loops. */
  0%   { background-position: -30% 0, 0 0; }
  100% { background-position: 130% 0, 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-howtag__label::after { animation: none; opacity: 1; }
}

/* Paragraph parked at the same top edge as the label, wider
   than the label so prose can wrap naturally. Each word is its
   own clip mask (same pattern as .rolldown .word) and each char
   parks below the word's baseline; on hover/lock the chars rise
   into view in a left-to-right wave. */
.hero-howtag__detail {
  position: absolute;
  top: 0.05em;
  left: 50%;
  transform: translateX(-50%);
  width: min(56ch, 90vw);
  /* Match the hero meta-strip — Helvetica Neue (Arial fallback)
     at thin weight 200 so the detail copy reads as a quiet
     secondary voice next to the serif headline. */
  font-family: var(--mono);
  font-weight: 200;
  font-size: clamp(22px, 1.95vw, 30px);
  line-height: 1.4;
  letter-spacing: -0.005em;
  color: var(--ink);
  text-align: center;
  text-wrap: balance;
  pointer-events: none;
}
.hh-det-word {
  display: inline-block;
  white-space: nowrap;
  overflow: hidden;
  line-height: 1.45;
  vertical-align: top;
}
.hh-det-char {
  display: inline-block;
  /* Parked just past the word's overflow clip — invisible until
     hover/lock pulls it up to translateY(0). */
  transform: translateY(1.45em);
  transition: transform var(--dur-cine) var(--ease-out-expo);
  /* Slightly looser stagger than the original `.rolldown--lg` so
     the wave reads as deliberate rather than rapid. */
  transition-delay: calc(var(--i, 0) * 9ms);
}
.hero-howtag:hover .hh-det-char,
.hero-howtag:focus-visible .hh-det-char,
.hero-howtag.is-locked .hh-det-char {
  transform: translateY(0);
}

/* Post-reveal scroll hint. JS adds .is-shown ~1.4s after the
   lock fires, but only if the user hasn't scrolled yet. The
   first scroll past the threshold removes .is-shown and the
   hint fades back out — its only job is to point users at the
   rest of the page once they've already seen the answer.

   Brand language matches the meta-strip and other utility
   labels on the page: mono small-caps, wide letter-spacing,
   --ink-3 color. Stacked layout (label on top, arrow below) so
   the directional cue points where it wants the user to go. */
.hero-howtag__hint {
  position: absolute;
  /* 100% = label height, +5em ≈ 2 lines of paragraph + breathing
     room. Tuned for the current detail copy length. */
  top: calc(100% + 5em);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  white-space: nowrap;
  /* Editorial italic — the brand's accent voice (same family +
     posture as "businesses grow" in the hero, just smaller and
     softer in tone). */
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(18px, 1.4vw, 22px);
  letter-spacing: -0.005em;
  color: var(--ink-2);
  opacity: 0;
  transition: opacity 0.6s ease;
  pointer-events: none;
}
.hero-howtag__hint.is-shown {
  opacity: 1;
}
.hero-howtag__hint-text {
  /* Tiny inset so the line below feels anchored to the phrase,
     not floating loose. */
  padding: 0 0.18em;
}
.hero-howtag__hint-arrow {
  display: block;
  color: var(--ink-3);
  animation: hintArrowDraw 2.2s var(--ease-cine) infinite;
}
/* Slow downward draw + reset — feels drafted, like the wordmark,
   not the bouncy cartoon arrow it replaces. */
@keyframes hintArrowDraw {
  0%   { transform: translateY(-2px); opacity: 0.45; }
  35%  { opacity: 1; }
  60%  { transform: translateY(4px); opacity: 1; }
  100% { transform: translateY(-2px); opacity: 0.45; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-howtag__hint-arrow { animation: none; }
}

@media (prefers-reduced-motion: reduce) {
  /* Snap any rise-mask group to its resting state. !important
     beats the !important on .is-exit. */
  .hw-word .hw-char,
  .revealed .hw-word .hw-char,
  .hw-word .hw-char.is-exit {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .hero .meta-strip { opacity: 1; animation: none; }
  .hero .undertags  { opacity: 1; animation: none; }
  .hero .hero-sub   { opacity: 1; animation: none; }
  .hero-howtag      { opacity: 1 !important; }
}

/* ============================================================
   Undertags — three pillars under the headline that complete the
   verb "connects". Same sans as the lede, spread wide.

   Hover behavior is a VAAN-Group-style vertical marquee swap:
   the label translates up and out, the detail copy slides in
   from below, with the container expanding vertically to fit.
   ============================================================ */
.hero .undertags {
  /* Each rolldown is absolutely centered on its target fifth of
     the viewport (30vw, 50vw, 70vw — the midpoints of the 2nd,
     3rd, and 4th fifths). Absolute + translateX(-50%) keeps the
     center exact even when the rolldown is wider than its fifth. */
  position: relative;
  display: block;
  width: 100vw;
  max-width: 100vw;
  height: clamp(80px, 9vh, 130px);
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  margin-top: calc(clamp(10px, 1.4vh, 18px) * -0.5);
  padding-bottom: clamp(48px, 7vh, 96px);
  /* Slightly smaller pillars — labels and copy share the same
     scale now, so the row reads as one continuous voice. */
  font-size: clamp(22px, 2.1vw, 30px);
  line-height: 1.35;
  letter-spacing: -0.012em;
  font-family: var(--sans);
  /* 3D context — each char is a real flap rotating in space,
     not just sliding 2D */
  perspective: 900px;
  perspective-origin: 50% 0;
}

.rolldown {
  /* Sized to label content via inline-block, then centered within
     its grid cell (a fifth of the screen) using auto margins. */
  position: relative;
  cursor: default;
  text-align: center;
  outline: 0;
  display: inline-block;
  /* Tight row that still fits descenders (the "g" in "Together"
     was getting clipped at 1.15em). 1.4em keeps the gap between
     label and rising copy minimal while showing full glyphs. */
  height: 1.4em;
}

/* Center each rolldown exactly on the midpoint of its fifth
   (2nd fifth = 30vw, 3rd = 50vw, 4th = 70vw). Absolute + the
   transform on .rolldown's base style keeps the center pinned
   regardless of the label's width. */
.hero .undertags > .rolldown {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
}
.hero .undertags > .rolldown:nth-of-type(1) { left: 30vw; }
.hero .undertags > .rolldown:nth-of-type(2) { left: 50vw; }
.hero .undertags > .rolldown:nth-of-type(3) { left: 70vw; }

/* The wide-detail third pillar lets its detail anchor to .undertags
   so the long copy can stretch all the way across the row — from
   in front of "Together" on the left out past "To Your Customers"
   on the right — rather than being trapped in one column. */
.rolldown--lg {
  position: static;
}


/* clip-wrapper just around the label so its rolling-down chars
   disappear cleanly at the row's bottom edge */
.rolldown__label-clip {
  display: block;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* wrapper layers — no own motion; the per-char spans inside do the rolling */
.rolldown__label,
.rolldown__detail {
  display: block;
  font-family: var(--sans);
  line-height: 1.4;
}

.rolldown__label {
  display: block;
  font-weight: 400;
  /* inherits font-size from .undertags = same as detail */
  letter-spacing: -0.012em;
  color: var(--ink);
  white-space: nowrap;
}

.rolldown__detail {
  /* All details span the same viewport area — 15vw to 85vw.
     Each rolldown is positioned at a different vw-center
     (30/50/70vw), so we offset the detail per-rolldown to land
     in the same screen position regardless. Font size, weight,
     and tracking inherit from .hero .undertags so the copy
     reads at the SAME scale and rhythm as the labels. */
  position: absolute;
  top: 0.55em;
  left: 50%;
  width: 70vw;
  font-weight: 400;
  line-height: 1.4;
  color: var(--ink);
  text-align: left;
  white-space: nowrap;
  pointer-events: none;
  z-index: 5;
  /* Default per-rolldown transform is set below — this is just
     a fallback so the detail is at least centered on screen. */
  transform: translateX(-50%);
}

/* Per-rolldown horizontal compensation so each detail's left
   edge lands at 15vw of the viewport — i.e. all copies spawn
   from the same place ("where Together's copy spawns"). */
.hero .undertags > .rolldown:nth-of-type(1) .rolldown__detail {
  transform: translateX(calc(-50% + 20vw));
}
.hero .undertags > .rolldown:nth-of-type(2) .rolldown__detail {
  transform: translateX(-50%);
}
.hero .undertags > .rolldown:nth-of-type(3) .rolldown__detail {
  transform: translateX(calc(-50% - 20vw));
}

/* Only the long pillar's copy wraps to multiple lines; the
   short ones stay on one line. The wrapped lines are centered
   within the 70vw box (which itself spans the full 15vw–85vw
   strip), so the multi-line copy reads as a balanced block. */
.rolldown--lg .rolldown__detail {
  white-space: normal;
  text-align: center;
}

/* ===== Per-character WAVE (vaan-group style) =====
   Pure 2D vertical sweep — no 3D fold, no opacity fade. Each
   char is its own inline-block with a transition-delay derived
   from --i, producing a left-to-right wave. The label slides
   straight up and out; the detail slides up from below into the
   same line. Word-level overflow: hidden clips chars cleanly at
   the row's top and bottom edges. Each rolldown is INDEPENDENT
   — hovering one does NOT animate its siblings, exactly like
   VAAN's nav links. */
.rolldown {
  --char-stagger: 22ms;
  --label-duration: 520ms;
  --label-ease: var(--ease-out-expo); /* gsap power3.out feel */
}
/* long paragraph: tighter stagger so the tail still lands quickly */
.rolldown--lg { --char-stagger: 6ms; }

/* word wrapper does double duty: it keeps chars from breaking
   mid-word AND clips the rolling chars at the word's box edges
   (this is VAAN's `.WaveText__word` trick — overflow: hidden
   plus line-height: 1 = a perfect per-word mask). */
.rolldown .word {
  display: inline-block;
  white-space: nowrap;
  overflow: hidden;
  /* Tight line-height = small overflow-clip box. The parked copy
     only has to translate just past this clip to hide, which lets
     the rest-state gap between label and copy collapse to almost
     nothing. Inter-line spacing for the multi-line "Customers"
     copy is governed by .rolldown__detail's own line-height, not
     this one, so wrapped paragraphs stay readable. */
  line-height: 1.25;
  vertical-align: top;
}
.rolldown .char {
  display: inline-block;
  will-change: transform;
  transition: transform var(--label-duration) var(--label-ease);
  transition-delay: calc(var(--i, 0) * var(--char-stagger));
}

/* === Default state — label visible, detail parked below. */
.rolldown__label .char {
  transform: translateY(0);
}

/* === First-rolldown shimmer hint — pulses an accent glow on
   the label so the user clocks "this is interactive". The halo
   uses filter: drop-shadow on the OUTER .rolldown so it
   extends beyond .rolldown__label-clip (overflow: hidden,
   which is what was clipping a text-shadow halo into a box).
   Color animates on the inner label, in sync. JS removes the
   .is-hint class after first pointerenter/focus so the
   shimmer never repeats. */
.rolldown.is-hint {
  animation: rolldownShimmerGlow 1.9s ease-in-out infinite;
  will-change: filter;
}
.rolldown.is-hint .rolldown__label {
  animation: rolldownShimmerColor 1.9s ease-in-out infinite;
}
@keyframes rolldownShimmerGlow {
  0%, 100% { filter: drop-shadow(0 0 0 transparent); }
  50% {
    filter:
      drop-shadow(0 0 14px color-mix(in oklch, var(--accent) 95%, transparent))
      drop-shadow(0 0 32px color-mix(in oklch, var(--accent) 65%, transparent))
      drop-shadow(0 0 56px color-mix(in oklch, var(--accent) 35%, transparent));
  }
}
@keyframes rolldownShimmerColor {
  0%, 100% { color: color-mix(in oklch, var(--ink) 38%, transparent); }
  50%      { color: color-mix(in oklch, white 55%, var(--accent) 45%); }
}
@media (prefers-reduced-motion: reduce) {
  .rolldown.is-hint,
  .rolldown.is-hint .rolldown__label { animation: none; }
}
/* Detail chars park just past the .word overflow clip (line-
   height 1.25em). The parked offset is only marginally larger
   than the clip box, so the visible gap between label and rising
   copy is tiny — they look stacked, not separated. */
.rolldown__detail .char {
  transform: translateY(1.25em);
}

/* === Hover/focus on THIS rolldown — label slides up and out,
   detail slides up into its place. Both move in the same
   direction for a clean upward sweep. */
.rolldown:hover .rolldown__label .char,
.rolldown:focus-visible .rolldown__label .char {
  transform: translateY(-100%);
}
.rolldown:hover .rolldown__detail .char,
.rolldown:focus-visible .rolldown__detail .char {
  transform: translateY(0);
}

/* === Base per-index wave delay =====
   These delays are ALWAYS applied to the label chars regardless
   of hover state. That means on un-hover, the labels drop with
   the same staggered wave they rose with, so the falling labels
   don't bunch up and overlap with the falling-back copy detail.
   The :has() rules below add per-scenario overrides on top.

   For the FIRST and SECOND rolldowns (Together, To Your Data),
   JS sets a per-char `--push-delay` based on each char's X
   position so label and detail chars stay spatially synced —
   when the "T" lifts, the detail char physically beneath it
   starts rising at the same instant. The fallback (`calc(var(--i)…)`)
   keeps the original index-based wave if JS hasn't run yet. */
.hero .undertags > .rolldown:nth-of-type(1) .rolldown__label .char,
.hero .undertags > .rolldown:nth-of-type(1) .rolldown__detail .char,
.hero .undertags > .rolldown:nth-of-type(2) .rolldown__label .char,
.hero .undertags > .rolldown:nth-of-type(2) .rolldown__detail .char {
  transition-delay: var(--push-delay, calc(var(--i, 0) * var(--char-stagger)));
}
.hero .undertags > .rolldown:nth-of-type(3) .rolldown__label .char {
  transition-delay: calc(var(--i, 0) * var(--char-stagger) + 480ms);
}

/* === Customers lock-in =====
   Once the user has hovered "To Your Customers" even once,
   the third rolldown's copy is "locked" visible: all labels
   stay rolled up, the long-copy detail stays risen. This
   persists for the rest of the session — it's a deliberate
   stickiness because that copy is a key brand statement. */
.hero .undertags.is-customers-locked > .rolldown:nth-of-type(1) .rolldown__label .char,
.hero .undertags.is-customers-locked > .rolldown:nth-of-type(2) .rolldown__label .char,
.hero .undertags.is-customers-locked > .rolldown:nth-of-type(3) .rolldown__label .char {
  transform: translateY(-100%);
}
.hero .undertags.is-customers-locked > .rolldown:nth-of-type(3) .rolldown__detail .char {
  transform: translateY(0);
}
/* Lock the SHORT details parked below — they shouldn't peek
   through when the user happens to hover Together or Data
   while the lock is active. */
.hero .undertags.is-customers-locked > .rolldown:nth-of-type(1) .rolldown__detail .char,
.hero .undertags.is-customers-locked > .rolldown:nth-of-type(2) .rolldown__detail .char {
  transform: translateY(1.25em);
}

/* === Sibling lift with delay tied to the rising copy =====
   When a rolldown is hovered, its OWN label/detail animate
   immediately (handled above). Sibling labels lift too, but
   STAGGERED — the delay before each sibling starts equals roughly
   how long the per-character wave takes to reach it. So the
   sibling looks like it's being carried up by the same wave that's
   rolling the copy in, not snapping the moment of hover. */

/* Hover the FIRST (Together) or the MIDDLE (To Your Data): the
   rising copy mechanically carries the label up. Both label and
   detail chars share a spatial-wave delay (var(--push-delay), set
   per-char by JS based on X position), so the label char at any
   given X lifts in lockstep with the detail char physically
   beneath it. Same duration on both sides keeps the motion
   locked. Siblings stay still so the focus is entirely on the
   push happening under the cursor. */
.hero .undertags:has(> .rolldown:nth-of-type(1):hover) > .rolldown:nth-of-type(1) .rolldown__label .char,
.hero .undertags:has(> .rolldown:nth-of-type(1):hover) > .rolldown:nth-of-type(1) .rolldown__detail .char,
.hero .undertags:has(> .rolldown:nth-of-type(1):focus-visible) > .rolldown:nth-of-type(1) .rolldown__label .char,
.hero .undertags:has(> .rolldown:nth-of-type(1):focus-visible) > .rolldown:nth-of-type(1) .rolldown__detail .char,
.hero .undertags:has(> .rolldown:nth-of-type(2):hover) > .rolldown:nth-of-type(2) .rolldown__label .char,
.hero .undertags:has(> .rolldown:nth-of-type(2):hover) > .rolldown:nth-of-type(2) .rolldown__detail .char,
.hero .undertags:has(> .rolldown:nth-of-type(2):focus-visible) > .rolldown:nth-of-type(2) .rolldown__label .char,
.hero .undertags:has(> .rolldown:nth-of-type(2):focus-visible) > .rolldown:nth-of-type(2) .rolldown__detail .char {
  transition-duration: 360ms;
  transition-timing-function: var(--ease-cine);
}

/* Hovering Data, Customers' detail also spans 15-85vw — so
   Together's and Customers's labels need to clear the row, or
   they end up sitting in the middle of the rising copy. They
   lift after the wave-hop, matching the spatial timing of Data's
   own push so the whole row reads as one motion. */
.hero .undertags:has(> .rolldown:nth-of-type(2):hover) > .rolldown:nth-of-type(1) .rolldown__label .char,
.hero .undertags:has(> .rolldown:nth-of-type(2):focus-visible) > .rolldown:nth-of-type(1) .rolldown__label .char,
.hero .undertags:has(> .rolldown:nth-of-type(2):hover) > .rolldown:nth-of-type(3) .rolldown__label .char,
.hero .undertags:has(> .rolldown:nth-of-type(2):focus-visible) > .rolldown:nth-of-type(3) .rolldown__label .char {
  transform: translateY(-100%);
  transition-delay: calc(var(--i, 0) * var(--char-stagger) + 240ms);
}

/* Hover the THIRD (To Your Customers): the long copy starts to
   the LEFT of "Together" and cascades rightward, so labels lift
   in left-to-right order. Together lifts first as the wave hits
   it, then Data, then Customers itself last (after the wave has
   travelled across to its position). The hovered rolldown's own
   `.rolldown:hover` rule still triggers — but we override the
   transition-delay so its label is the LAST to leave, matching
   the wave's spatial timing. */
.hero .undertags:has(> .rolldown:nth-of-type(3):hover) > .rolldown:nth-of-type(1) .rolldown__label .char,
.hero .undertags:has(> .rolldown:nth-of-type(3):focus-visible) > .rolldown:nth-of-type(1) .rolldown__label .char {
  transform: translateY(-100%);
  transition-delay: calc(var(--i, 0) * var(--char-stagger) + 80ms);
}
.hero .undertags:has(> .rolldown:nth-of-type(3):hover) > .rolldown:nth-of-type(2) .rolldown__label .char,
.hero .undertags:has(> .rolldown:nth-of-type(3):focus-visible) > .rolldown:nth-of-type(2) .rolldown__label .char {
  transform: translateY(-100%);
  transition-delay: calc(var(--i, 0) * var(--char-stagger) + 360ms);
}
.hero .undertags:has(> .rolldown:nth-of-type(3):hover) > .rolldown:nth-of-type(3) .rolldown__label .char,
.hero .undertags:has(> .rolldown:nth-of-type(3):focus-visible) > .rolldown:nth-of-type(3) .rolldown__label .char {
  transition-delay: calc(var(--i, 0) * var(--char-stagger) + 680ms);
}

@media (prefers-reduced-motion: reduce) {
  .rolldown .char { transition-duration: 0.01ms !important; transition-delay: 0 !important; }
}

@media (max-width: 720px) {
  .hero .undertags {
    grid-template-columns: 1fr;
    gap: 18px;
    max-width: 36ch;
    margin-top: 12px;
  }
  .rolldown__label { font-size: 20px; }
  .rolldown--sm:hover { min-height: 4.5em; }
  .rolldown--lg:hover { min-height: 13em; }
}

.hero .lede {
  /* let the stage's row-gap drive vertical rhythm — no own margin */
  max-width: 60ch; margin: 0 auto;
  color: var(--ink-2); font-size: clamp(18px, 1.6vw, 23px); line-height: 1.5;
}
.hero .lede em { font-style: italic; color: var(--ink); }
.hero .actions { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }
.hero .pillrow {
  display: flex; gap: 28px; justify-content: center; flex-wrap: wrap;
  /* spacing handled by stage row-gap */
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-3);
}
.hero .pillrow span { display: inline-flex; align-items: center; gap: 8px; }
.hero .pillrow span::before {
  content: ""; width: 4px; height: 4px; border-radius: 50%; background: var(--accent);
}

.hero-foot {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: 32px;
  padding-top: 28px;
  border-top: 1px solid var(--rule);
  align-items: end;
}
.hero-foot .motto {
  font-family: var(--serif); font-size: clamp(18px, 1.8vw, 22px);
  line-height: 1.3; letter-spacing: -0.005em; max-width: 42ch;
  color: var(--ink-2);
}
.hero-foot .motto em { color: var(--accent); font-style: italic; }
.hero-foot .stat .num {
  font-family: var(--serif); font-size: clamp(28px, 3.2vw, 40px);
  line-height: 1; letter-spacing: -0.02em;
}
.hero-foot .stat .lbl {
  font-family: var(--mono); font-size: 10px;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-3); margin-top: 8px;
}
@media (max-width: 980px) {
  .hero-foot { grid-template-columns: 1fr 1fr; }
}

/* ============================================================
   Intro — the blank white card that sits behind the Hero shelf
   during the hero-jack lift, and that the IntroCoverJack peels
   the dark cover off of. No content right now; it's purely the
   white surface.
   ============================================================ */
.intro {
  background: #ffffff;
}

/* ============================================================
   IntroCoverJack — the scroll-jacked transition that immediately
   follows the hero-jack. A dark card pinned to the left ~37%
   slides off-screen to the left as the user scrolls through the
   sticky zone, gradually exposing more of the blank white page.
   The right side of the viewport stays white the entire time
   because the cover never extends past 37% of the viewport.

   margin-top: -100vh pulls this section up to overlap the trailing
   100vh of hero-jack (the dead zone that exists post-sticky on the
   hero stage). With the overlap, the dark card slides up into view
   as the Hero lifts off — there's no blank white scroll-distance
   between them. The cover wrapper still has a 200vh footprint
   (100vh sticky + 100vh of natural exit-scroll), but the first
   100vh visually shares the page with the hero-jack's trailing.
   ============================================================ */
.intro-cover-jack {
  position: relative;
  /* 400vh wrapper = 300vh of sticky-scroll duration. Setup phase
     (cover slide + phrase + circle bloom) runs 0.04 → 0.46 of the
     normalized pin; the dots area runs donut → sprout across the
     remaining 0.34 → 1.00 (hammer + Oregon stages removed).

     This was 660vh originally (560vh of pin) — tuned for a three-
     symbol chain. With the chain trimmed to two symbols and the
     final hold-and-drop choreography removed, the section held
     visitors way too long. Cut by ~46% so the scrolljack now
     lasts about three viewports of motion instead of six, and
     visitors can scroll into the manifesto section much sooner.

     Wrapper bg is #000 so once the stage scrolls away post-sticky
     the exposed strip matches the inverted state. */
  height: 400vh;
  margin-top: -100vh;
  background: #000;
}
.intro-cover-jack__stage {
  position: sticky;
  top: 0;
  /* dvh, not raw vh — same address-bar-resize fix as
     .hero-jack__stage. Keeps the pinned cover/phrase/donut scene
     filling exactly the visible viewport on mobile so it never
     jumps when the toolbar shows/hides. vh fallback first. */
  height: 100vh;
  height: 100dvh;
  width: 100%;
  overflow: hidden;
  background: #ffffff;
  /* New stacking context — keeps the circle overlay's
     mix-blend-mode contained inside the stage. */
  isolation: isolate;
}
.intro-cover-jack__cover {
  position: absolute;
  inset: 0 auto 0 0;
  /* "A little more than a third of the left side" — 37% leaves
     the right ~63% of the viewport showing white at all times. */
  width: 37%;
  background: var(--bg);
  will-change: transform;
  /* Side-card headline lives here. Padded inset so the line breathes
     at top + left, and clamped reading width keeps the line from
     stretching to the panel edge as the viewport widens. */
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: clamp(40px, 7vh, 96px) clamp(24px, 3.2vw, 56px);
}

.intro-cover-jack__headline {
  margin: 0;
  /* Sized to fill the dark side panel — large enough to wrap across
     several lines and hold the column visually, but still smaller
     than the hero (which clamps to 168px) so the hero stays the
     dominant moment. The serif + italic accent mirror the hero
     h1 voice. */
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(56px, 7vw, 116px);
  line-height: 1.06;
  letter-spacing: -0.022em;
  color: oklch(0.92 0.012 240);
  width: 100%;
  text-wrap: balance;
}

.intro-cover-jack__headline em {
  color: var(--accent);
  font-style: italic;
}

/* Right-side phrase — sits in the white area to the right of the
   dark cover. Uses the same `.hw-word` / `.hw-char` mask + rise
   machinery as the hero, so the cascade plays once the JS scroll
   handler adds `.revealed`. */
.intro-cover-jack__phrase {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 37%;
  right: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: clamp(40px, 7vh, 96px) clamp(32px, 4vw, 88px);
  font-family: var(--serif);
  font-weight: 400;
  /* Desktop: sized to fit "That's what I build for." on ONE line in
     the right column (smaller than the hi/love scale on purpose so
     the single line never wraps or overflows). Mobile overrides this
     with a much larger, wrapping treatment. */
  font-size: clamp(40px, 5.6vw, 104px);
  line-height: 1.06;
  letter-spacing: -0.022em;
  white-space: nowrap;
  /* Dark ink-blue from the Crewsive palette so the phrase reads
     against the white stage background (var(--bg) is the deep
     navy used elsewhere as the page background). */
  color: var(--bg);
  pointer-events: none;
}
.intro-cover-jack__phrase-inner {
  /* Single flex child — whitespace between words renders here as
     normal inline text (the parent flex would otherwise collapse
     the spaces between sibling .hw-word spans). */
  display: block;
  max-width: 100%;
}
.intro-cover-jack__phrase .hw-word.em {
  color: var(--accent);
  font-style: italic;
  /* Lifted above the circle overlay so the difference blend can't
     touch the brand accent — blue stays blue inside and outside
     the inverted circle. The phrase wrapper has z-index: auto, so
     this z-index participates directly in the stage's stacking
     context and beats the circle's z-index: 3. */
  position: relative;
  z-index: 4;
}

/* "Hi, I'm Luke." — second cascade headline, centered on the
   stage. Lives at z-auto so the circle's mix-blend-mode reaches
   it; dark `var(--bg)` ink inverts to near-white inside the
   bloomed circle, which is exactly when JS adds `.revealed` to
   trigger the rise. The italic accent ("Luke.") gets lifted
   above the circle in the stacking order so it stays brand-blue
   regardless of inversion (same trick as the right-side phrase). */
.intro-cover-jack__hi {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(56px, 7.4vw, 124px);
  line-height: 1.06;
  letter-spacing: -0.022em;
  color: var(--bg);
  text-align: center;
  text-wrap: balance;
  pointer-events: none;
}
.intro-cover-jack__hi-inner {
  display: block;
  max-width: 100%;
  padding: 0 clamp(32px, 4vw, 88px);
}
.intro-cover-jack__hi .hw-word.em {
  color: var(--accent);
  font-style: italic;
  position: relative;
  /* Above the dot-donut canvas (z=4) so "Luke." reads cleanly
     on top of the dots. */
  z-index: 5;
}

/* "I love helping businesses grow…" — fourth cascade. Sits in
   FRONT of the sprout dot field (z:5 — above the difference-blend
   circle at z:3 and the dot canvas at z:4) so the line reads as a
   clean overlay rather than dots carving a halo around it. Because
   it sits above the blend circle, we color it directly in light
   ink (no inversion needed). Italic accents stay brand-blue. */
.intro-cover-jack__love {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--serif);
  font-weight: 400;
  /* Matched to .intro-cover-jack__hi — same headline scale so the
     two reveals read as one continuous statement at the same
     typographic weight, not parent/child. */
  font-size: clamp(56px, 7.4vw, 124px);
  line-height: 1.06;
  letter-spacing: -0.022em;
  color: #ffffff;
  text-align: center;
  text-wrap: balance;
  pointer-events: none;
  z-index: 5;
}
.intro-cover-jack__love-inner {
  display: block;
  /* Widened from 26ch so the longer manifesto line can breathe at
     the larger hi-matching scale without forcing 4+ tight wraps. */
  max-width: 22ch;
  padding: 0 clamp(32px, 4vw, 88px);
}
.intro-cover-jack__love .hw-word.em {
  color: var(--accent);
  font-style: italic;
}
/* HI exit fall — once the user keeps scrolling past the reveal,
   the JS handler adds `.is-exiting` to the wrapper AND `.is-exit`
   to each child .hw-char (mirroring the hero h1's exit cascade).
   Two adjustments vs. the hero's default exit:
     • Drop the .hw-word bottom clip so chars stay visible while
       they fall through the donut (the default clip would mask
       them as soon as they cross baseline, hiding the collision).
     • Push the fall to ~60vh so the chars travel through the
       full vertical span of the donut and off the stage.
   The donut's per-particle alpha-mask collision tracks the chars'
   live bounding rects, so dots get pushed downward in lockstep
   with the falling letters automatically. */
.intro-cover-jack__hi.is-exiting .hw-word {
  clip-path: inset(-0.05em -1000px -100vh -1000px);
}
.intro-cover-jack__hi .hw-char.is-exit {
  transform: translate3d(0, 60vh, 0.02px) rotate(0deg) !important;
  transition-duration: var(--dur-cine) !important;
  transition-timing-function: var(--ease-in) !important;
}

/* Circle inversion overlay — sits on top of the stage; the JS
   scroll handler animates clip-path: circle() from 0 → past the
   viewport diagonal as the user scrolls past the cover-slide.
   mix-blend-mode: difference inverts whatever's beneath the
   circle: the stage's white BG goes to black, and the dark
   `var(--bg)` phrase ink goes to a near-white. */
.intro-cover-jack__circle {
  position: absolute;
  inset: 0;
  background: #fff;
  mix-blend-mode: difference;
  clip-path: circle(0px at 50% 50%);
  pointer-events: none;
  /* Above the cover (no z-index) and the phrase, so the blend
     covers everything inside the stage. */
  z-index: 3;
  will-change: clip-path;
}

/* Reduced motion: the scroll-driven JS bails, so force the cover
   off-screen to expose the phrase behind it. */
@media (prefers-reduced-motion: reduce) {
  .intro-cover-jack__cover {
    transform: translate3d(-100%, 0, 0) !important;
  }
}

/* Mobile KEEPS the full pinned scrolljack — the cover slide, phrase
   reveal, donut → sprout morph all run the same as desktop and
   respond to the user's own scrolling. The only thing disabled on
   touch is the AUTO-SNAP between rest points (see the snap effect's
   mobile guard in brand.jsx), so the page never scrolls by itself
   when you pause. These overrides just full-bleed + recenter each
   scene for phones and push the type up so every statement is big
   and impactful. Colors are left alone — the white stage + inversion
   circle still drive the phrase/Hi ink, same as desktop. */
@media (max-width: 720px) {
  .intro-cover-jack__cover {
    width: 100%;
    padding: clamp(56px, 11vh, 110px) 22px;
    justify-content: center;
    align-items: center;
    text-align: center;
    will-change: transform;
  }
  .intro-cover-jack__headline {
    text-align: center;
    font-size: clamp(48px, 12.5vw, 96px);
    line-height: 1.03;
    max-width: 15ch;
  }
  .intro-cover-jack__phrase {
    left: 0;
    right: 0;
    padding: clamp(24px, 4vh, 56px) 12px;
    justify-content: center;
    text-align: center;
    font-size: clamp(80px, 22vw, 150px);
    line-height: 0.95;
    /* Mobile wraps + stacks big (desktop forces one line). */
    white-space: normal;
  }
  .intro-cover-jack__phrase-inner {
    max-width: 8ch;
    margin: 0 auto;
  }
  /* Hi / sprout — the desktop clamp floors at ~56px on a phone, so
     bump them so every statement reads as big as the phrase. */
  .intro-cover-jack__hi {
    font-size: clamp(64px, 17vw, 128px);
    line-height: 0.98;
  }
  .intro-cover-jack__hi-inner { padding: 0 16px; }
  .intro-cover-jack__love {
    font-size: clamp(58px, 15vw, 110px);
    line-height: 0.98;
  }
  .intro-cover-jack__love-inner { max-width: 15ch; padding: 0 16px; }
}

/* ============================================================
   Velocity marquee — a slim editorial keyword strip. It latches to a
   FIXED bar just under the nav logo (top: --marquee-top, set in JS to
   the live nav height) once the user scrolls past the sprout, and
   stays pinned for the rest of the session — including when scrolling
   back to the top. Hidden (slid up behind the opaque nav) until
   latched. The JS rAF still surges + skews the track with scroll
   velocity, so the bar leans into the scroll even while pinned.
   ============================================================ */
.velo-marquee {
  position: fixed;
  top: var(--marquee-top, 64px);
  left: 0;
  right: 0;
  z-index: 90;            /* under nav (220) + scroll-progress (230), over content */
  overflow: hidden;
  background: var(--bg);
  border-bottom: 1px solid var(--rule-2);
  padding-block: clamp(7px, 1.2vw, 13px);
  /* Hidden until past the sprout: slid up behind the (opaque) nav. */
  transform: translateY(-130%);
  opacity: 0;
  pointer-events: none;
  transition: transform var(--dur-slow) var(--ease-out-expo), opacity var(--dur-medium) var(--ease-out-expo);
}
.velo-marquee.is-stuck {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}
.velo-marquee__track {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  transform-origin: 50% 50%;
  will-change: transform;
}
.velo-marquee__item { display: inline-flex; align-items: center; }
.velo-marquee__text {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(15px, 2.2vw, 26px);
  letter-spacing: -0.015em;
  line-height: 1;
  color: var(--ink-2);
}
/* The keyword is a link (to its service FAQ). Keep the editorial look —
   no underline, inherit the marquee color — and brighten on hover. */
a.velo-marquee__text {
  text-decoration: none;
  cursor: pointer;
  transition: color var(--dur-base) var(--ease-out-expo);
}
a.velo-marquee__text:hover,
a.velo-marquee__text:focus-visible { color: var(--ink); }
.velo-marquee__sep {
  color: var(--accent);
  font-size: clamp(9px, 1.1vw, 14px);
  margin: 0 clamp(16px, 2.6vw, 34px);
  transform: translateY(-0.12em);
}

/* Tactile press on the primary nav CTA — transform is already in its
   transition (above), so just scale on press. */
.nav .cta:active { transform: scale(0.97); }

/* Reduced motion: the marquee holds still (no drift, no skew) and
   the velocity skew vars rest at 0 (the velocity layer in index.html
   already bails, but belt-and-suspenders for the band's own skew). */
@media (prefers-reduced-motion: reduce) {
  .velo-marquee__track { transform: none !important; will-change: auto; }
}

/* ── Preloader (first-visit curtain) ─────────────────────────── */
body.is-preloading { overflow: hidden; }
.preloader {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background: var(--bg);
  transition: opacity var(--dur-slow) var(--ease-out-expo);
}
/* Exit = cross-fade the dark overlay out. The filled preloader logo
   sits exactly where the nav's caustic logo is, so they coincide and
   it reads as one continuous mark as the page reveals behind it. */
.preloader--out { opacity: 0; pointer-events: none; }

/* Wordmark pinned at the nav-logo position (top, centered). */
.preloader__logo {
  position: absolute;
  top: 22px;
  left: 50%;
  transform: translateX(-50%);
  line-height: 0;
}
.preloader__logo-ghost,
.preloader__logo-fill { display: block; }
/* Dim "empty" copy under the fill. */
.preloader__logo-ghost { color: color-mix(in oklch, var(--ink) 16%, transparent); }
/* Caustic copy, clipped from the right by progress → reveals L→R. */
.preloader__logo-fill {
  position: absolute;
  top: 0;
  left: 0;
  clip-path: inset(0 calc(100% - var(--p, 0%)) 0 0);
}
@media (max-width: 720px) {
  .preloader__logo { top: max(16px, calc(env(safe-area-inset-top, 0px) + 12px)); }
  /* Match the nav's mobile logo height (CSS overrides the svg's 36px
     attribute, same trick the nav uses). */
  .preloader__logo .crewsive-wm-svg svg { height: 30px; }
}

/* ============================================================
   Services — STACKING CARDS scrolljack
   Each card sits sticky at the top, the next card slides over it.
   Cards are sized correctly to viewport, with proper depth.
   ============================================================ */

.services {
  padding: clamp(40px, 6vw, 80px) var(--gutter) clamp(80px, 12vw, 140px);
  position: relative;
}

.svc-stack {
  position: relative;
  display: grid;
  gap: clamp(24px, 4vw, 48px);
}

.svc-card {
  position: sticky;
  top: clamp(72px, 10vh, 120px);
  height: min(78vh, 760px);
  border-radius: var(--radius-xl);
  overflow: hidden;
  background: var(--bg-2);
  border: 1px solid var(--rule);
  box-shadow:
    0 1px 0 0 color-mix(in oklch, var(--ink) 8%, transparent) inset,
    0 30px 80px -40px rgba(0,0,0,0.5),
    0 8px 24px -12px rgba(0,0,0,0.4);
  display: grid;
  grid-template-columns: 0.95fr 1.1fr;
  transition: transform var(--dur-slow) var(--ease-out-soft), opacity var(--dur-slow) var(--ease-out-expo);
}
.svc-card.shrink {
  transform: scale(0.96) translateY(-12px);
  opacity: 0.4;
}

.svc-card .copy {
  padding: clamp(28px, 3vw, 44px);
  display: grid; grid-template-rows: auto 1fr auto; gap: 16px;
  border-right: 1px solid var(--rule);
  background:
    radial-gradient(ellipse 80% 60% at 0% 0%, color-mix(in oklch, var(--accent) 8%, transparent), transparent 70%),
    transparent;
}
.svc-card .copy .top {
  display: flex; justify-content: space-between; align-items: center;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  color: var(--ink-3); text-transform: uppercase;
}
.svc-card .copy .top .label { color: var(--accent); display: inline-flex; align-items: center; gap: 10px; }
.svc-card .copy .top .label::before { content: ""; width: 24px; height: 1px; background: var(--accent); }
.svc-card .copy h3 {
  margin: 8px 0 18px;
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(28px, 3vw, 48px);
  line-height: 1.05; letter-spacing: -0.02em;
  padding-bottom: 0.05em;
}
.svc-card .copy h3 em { color: var(--accent); font-style: italic; }
.svc-card .copy p {
  margin: 0; max-width: 42ch;
  color: var(--ink-2); font-size: 16px; line-height: 1.55;
}
.svc-card .copy ul {
  margin: 0; padding: 0; list-style: none;
  display: grid; gap: 10px;
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.04em; color: var(--ink-2);
}
.svc-card .copy ul li { display: flex; gap: 12px; align-items: baseline; }
.svc-card .copy ul li::before { content: "→"; color: var(--accent); }

.svc-card .preview { position: relative; overflow: hidden; background: var(--bg); }

@media (max-width: 820px) {
  .svc-card { grid-template-columns: 1fr; height: auto; min-height: 80vh; }
  .svc-card .copy { border-right: 0; border-bottom: 1px solid var(--rule); }
  .svc-card .preview { min-height: 50vh; }
}

/* ============================================================
   SCENE 1: AI Automations preview
   A live agent run — task tree decomposing, logs streaming,
   custom control panel.
   ============================================================ */

.ai-stage {
  position: absolute; inset: 0;
  display: grid; grid-template-rows: auto 1fr auto;
  padding: 24px;
  gap: 14px;
  font-family: var(--sans);
  background:
    radial-gradient(ellipse 60% 40% at 80% 0%, color-mix(in oklch, var(--accent) 10%, transparent), transparent 70%),
    var(--bg);
}
.ai-stage .titlebar {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-3);
  padding-bottom: 12px; border-bottom: 1px solid var(--rule);
}
.ai-stage .titlebar b { color: var(--ink); font-weight: 600; letter-spacing: 0.06em; }
.ai-stage .titlebar .live { margin-left: auto; color: var(--good); display: inline-flex; align-items: center; gap: 6px; }
.ai-stage .titlebar .live::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--good); animation: pulse 1.6s infinite;
  box-shadow: 0 0 0 4px color-mix(in oklch, var(--good) 25%, transparent);
}
@keyframes pulse {
  0%,100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.5; transform: scale(0.85); }
}

.ai-stage .body {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 14px; min-height: 0;
}
.ai-tree, .ai-log {
  border: 1px solid var(--rule); border-radius: 12px;
  background: var(--bg-2);
  padding: 14px;
  display: grid; gap: 10px;
  min-height: 0;
}
.ai-tree .lbl, .ai-log .lbl {
  font-family: var(--mono); font-size: 9px;
  letter-spacing: 0.16em; color: var(--ink-3); text-transform: uppercase;
}
.ai-tree .row {
  display: grid; grid-template-columns: 18px 1fr auto;
  gap: 8px; align-items: center;
  font-family: var(--sans); font-size: 12px;
  padding: 6px 8px; border-radius: 6px;
  color: var(--ink-2);
  transition: background .3s ease, color .3s ease;
}
.ai-tree .row.indent  { padding-left: 22px; }
.ai-tree .row.indent2 { padding-left: 36px; }
.ai-tree .row.active {
  background: color-mix(in oklch, var(--accent) 12%, transparent);
  color: var(--ink);
}
.ai-tree .row.done { color: var(--ink-3); }
.ai-tree .ic { font-family: var(--mono); font-size: 10px; color: var(--ink-3); }
.ai-tree .row.active .ic { color: var(--accent); }
.ai-tree .row.done .ic { color: var(--good); }
.ai-tree .meta { font-family: var(--mono); font-size: 9px; color: var(--ink-4); letter-spacing: 0.05em; }
.ai-tree .spinner {
  width: 10px; height: 10px; border-radius: 50%;
  border: 1.5px solid var(--accent); border-right-color: transparent;
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.ai-log .lines {
  font-family: var(--mono); font-size: 11px;
  display: grid; gap: 4px; min-height: 0; overflow: hidden;
  color: var(--ink-2);
}
.ai-log .lines .ln { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ai-log .lines .ln .t { color: var(--ink-4); margin-right: 8px; }
.ai-log .lines .ln .k { color: var(--accent); }
.ai-log .lines .ln .ok { color: var(--good); }
.ai-log .lines .ln .warn { color: var(--warn); }

.ai-stage .panel {
  border: 1px solid var(--rule); border-radius: 12px;
  background: var(--bg-2); padding: 12px 14px;
  display: grid; grid-template-columns: auto 1fr auto auto;
  gap: 12px; align-items: center;
  font-family: var(--mono); font-size: 12px;
}
.ai-stage .panel .arrow { color: var(--accent); }
.ai-stage .panel .input { color: var(--ink); letter-spacing: 0.01em; }
.ai-stage .panel .ctrls { display: flex; gap: 6px; }
.ai-stage .panel .ctrls span {
  width: 24px; height: 24px; border-radius: 5px; border: 1px solid var(--rule);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; color: var(--ink-3);
}
.ai-stage .panel .run {
  background: var(--accent); color: var(--bg);
  padding: 6px 12px; border-radius: 5px;
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; font-weight: 600;
}

/* ============================================================
   SCENE 2: Custom sites — picker + per-site design language
   Each preview is its OWN brand world, fully realized.
   ============================================================ */

.sites-stage {
  position: absolute; inset: 0;
  display: grid; grid-template-rows: auto 1fr;
  background: var(--bg);
}
.sites-stage .picker-bar {
  display: flex; gap: 4px;
  padding: 14px;
  border-bottom: 1px solid var(--rule);
  background: var(--bg-2);
}
.sites-stage .picker-bar button {
  flex: 1;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: transparent;
  font-family: var(--mono); font-size: 10px;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-3);
  text-align: left;
  display: grid; gap: 4px;
  cursor: pointer;
  transition: border-color .2s, color .2s, background .2s;
}
.sites-stage .picker-bar button .nm {
  color: var(--ink); font-size: 12px; letter-spacing: 0; text-transform: none; font-family: var(--sans); font-weight: 500;
}
.sites-stage .picker-bar button:hover { background: var(--bg-3); }
.sites-stage .picker-bar button.active {
  background: var(--accent-soft);
  border-color: color-mix(in oklch, var(--accent) 50%, transparent);
  color: var(--accent);
}
.sites-stage .frame {
  position: relative; overflow: hidden;
}
.sites-stage .frame .pane {
  position: absolute; inset: 0;
  opacity: 0; transform: translateY(8px);
  transition: opacity .45s ease, transform .45s ease;
  pointer-events: none;
  overflow: hidden;
}
.sites-stage .frame .pane.active {
  opacity: 1; transform: translateY(0); pointer-events: auto;
}

/* --- Site A: coffee roaster, cream + espresso, editorial --- */
.site-a {
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 80% 60% at 90% 100%, oklch(0.78 0.06 50 / 0.45), transparent 65%),
    oklch(0.94 0.025 70);
  color: oklch(0.20 0.04 40);
  padding: 18px 24px;
  display: grid; grid-template-rows: auto 1fr auto; gap: 14px;
  font-family: var(--sans);
  overflow: hidden;
  min-height: 0;
}
.site-a .nav-a {
  display: flex; justify-content: space-between; align-items: center;
  gap: 16px;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.18em;
  text-transform: uppercase; color: oklch(0.30 0.04 40);
  border-bottom: 1px solid oklch(0.20 0.04 40 / 0.18);
  padding-bottom: 12px;
}
.site-a .nav-a .b {
  font-family: var(--mono); font-weight: 700;
  font-size: 10px; letter-spacing: 0.22em;
  color: oklch(0.20 0.04 40);
  white-space: nowrap; flex-shrink: 0;
}
.site-a .nav-a .links { display: flex; gap: 16px; opacity: 0.7; }
.site-a .nav-a .bag {
  border: 1px solid oklch(0.20 0.04 40 / 0.3);
  padding: 4px 10px; border-radius: 99px;
  font-size: 9px;
}

.site-a .hero-a {
  display: grid; grid-template-columns: 1.3fr 0.9fr; gap: 24px;
  align-items: stretch; min-height: 0; overflow: hidden;
}
.site-a .hero-a .copy {
  display: grid; align-content: center; gap: 14px;
  padding-right: 8px;
}
.site-a .hero-a .kicker {
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.2em;
  text-transform: uppercase; color: oklch(0.45 0.10 30);
  display: inline-flex; align-items: center; gap: 10px;
}
.site-a .hero-a .kicker::before {
  content: ""; width: 18px; height: 1px; background: oklch(0.45 0.10 30);
}
.site-a .hero-a h1 {
  margin: 0;
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(28px, 3.6vw, 52px);
  line-height: 0.96; letter-spacing: -0.022em;
  max-width: 14ch;
}
.site-a .hero-a h1 em {
  font-style: italic; color: oklch(0.42 0.14 30);
}
.site-a .hero-a .copy p {
  margin: 0; font-size: 12px; line-height: 1.5;
  color: oklch(0.30 0.04 40); max-width: 40ch;
}
.site-a .hero-a .ctas {
  display: flex; gap: 12px; align-items: center; margin-top: 4px;
}
.site-a .hero-a .cta {
  background: oklch(0.20 0.04 40); color: oklch(0.94 0.025 70);
  padding: 9px 14px; border-radius: 4px;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.18em;
  text-transform: uppercase; font-weight: 600;
}
.site-a .hero-a .cta-g {
  font-family: var(--serif); font-style: italic; font-size: 13px;
  color: oklch(0.30 0.04 40); border-bottom: 1px solid currentColor; padding-bottom: 1px;
}

/* Coffee bag — drawn vector silhouette */
.site-a .hero-a .prod {
  position: relative;
  display: grid; grid-template-rows: 1fr auto; gap: 10px;
  min-height: 0; align-items: center;
}
.site-a .hero-a .bag-shot {
  position: relative;
  width: 78%; aspect-ratio: 3 / 4.2;
  margin: 0 auto;
  background:
    linear-gradient(170deg,
      oklch(0.32 0.05 35) 0%,
      oklch(0.22 0.05 30) 60%,
      oklch(0.18 0.04 30) 100%);
  border-radius: 4px 4px 8px 8px;
  box-shadow:
    0 1px 0 oklch(0.50 0.04 40 / 0.4) inset,
    0 -2px 4px oklch(0 0 0 / 0.4) inset,
    0 30px 40px -20px oklch(0 0 0 / 0.45);
  /* pinched top */
  clip-path: polygon(8% 0, 92% 0, 96% 8%, 100% 100%, 0 100%, 4% 8%);
}
.site-a .hero-a .bag-shot::before {
  content: ""; position: absolute; left: 8%; right: 8%; top: 4%;
  height: 4px; background: oklch(0.65 0.04 40); border-radius: 2px;
  box-shadow: 0 1px 0 oklch(0 0 0 / 0.3);
}
.site-a .hero-a .bag-shot .band {
  position: absolute; left: 0; right: 0; top: 38%;
  background: oklch(0.92 0.02 80);
  color: oklch(0.18 0.04 40);
  padding: 14px 14px 16px;
  display: grid; gap: 4px; text-align: center;
  font-family: var(--mono);
}
.site-a .hero-a .bag-shot .band .lt {
  font-size: 8px; letter-spacing: 0.22em;
  opacity: 0.7;
}
.site-a .hero-a .bag-shot .band .md {
  font-family: var(--serif); font-size: clamp(13px, 1.4vw, 18px);
  letter-spacing: 0.04em;
  font-weight: 400; line-height: 1; padding: 4px 0;
  border-top: 1px solid oklch(0.18 0.04 40 / 0.2);
  border-bottom: 1px solid oklch(0.18 0.04 40 / 0.2);
  font-style: italic;
}
.site-a .hero-a .bag-shot .band .notes {
  font-family: var(--serif); font-style: italic; font-size: 10px;
  color: oklch(0.42 0.14 30); margin-top: 2px;
}
.site-a .hero-a .dial {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  font-family: var(--mono); font-size: 9px;
  color: oklch(0.30 0.04 40); padding: 0 6px;
}
.site-a .hero-a .dial span { display: grid; gap: 2px; }
.site-a .hero-a .dial b {
  font-family: var(--mono); letter-spacing: 0.16em;
  text-transform: uppercase; font-weight: 600; font-size: 8px;
  opacity: 0.7;
}
.site-a .hero-a .dial i { font-style: normal; letter-spacing: 0.12em; color: oklch(0.42 0.14 30); }

.site-a .ticker-a {
  display: flex; justify-content: center; align-items: center; gap: 14px;
  border-top: 1px solid oklch(0.20 0.04 40 / 0.18); padding-top: 10px;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.16em; text-transform: uppercase;
  color: oklch(0.30 0.04 40); flex-wrap: wrap;
}

/* --- Site B: e-commerce, refined / fashion --- */
.site-b {
  background: oklch(0.97 0.005 80);
  color: oklch(0.18 0.01 80);
  padding: 22px 24px;
  display: grid; grid-template-rows: auto auto 1fr; gap: 16px;
  font-family: var(--sans);
}
.site-b .nav-b {
  display: flex; justify-content: space-between; align-items: center;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
}
.site-b .nav-b .b { font-family: var(--serif); font-size: 22px; letter-spacing: -0.01em; text-transform: none; white-space: nowrap; flex-shrink: 0; }
.site-b .nav-b .links { display: flex; gap: 18px; opacity: 0.6; }
.site-b .nav-b .cart {
  border: 1px solid oklch(0.18 0.01 80 / 0.3); padding: 6px 12px;
  border-radius: 99px; display: inline-flex; gap: 8px;
}
.site-b .h1-b {
  font-family: var(--serif); font-size: clamp(28px, 3.6vw, 44px);
  line-height: 1; letter-spacing: -0.02em; margin: 0;
  max-width: 16ch;
}
.site-b .h1-b em { font-style: italic; opacity: 0.7; }
.site-b .grid-b {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
}
.site-b .card-b {
  border-radius: 4px; overflow: hidden;
  background: oklch(0.92 0.01 80);
  display: grid; grid-template-rows: 1fr auto;
}
.site-b .card-b .ph { aspect-ratio: 3/4; }
.site-b .card-b:nth-child(1) .ph { background: linear-gradient(160deg, oklch(0.62 0.10 30), oklch(0.78 0.07 50)); }
.site-b .card-b:nth-child(2) .ph { background: linear-gradient(160deg, oklch(0.55 0.08 200), oklch(0.78 0.05 200)); }
.site-b .card-b:nth-child(3) .ph { background: linear-gradient(160deg, oklch(0.45 0.04 80), oklch(0.65 0.03 80)); }
.site-b .card-b:nth-child(4) .ph { background: linear-gradient(160deg, oklch(0.78 0.07 130), oklch(0.88 0.04 130)); }
.site-b .card-b .meta {
  padding: 10px 12px; display: grid; grid-template-columns: 1fr auto; gap: 4px;
  background: oklch(0.99 0.005 80);
}
.site-b .card-b .nm { font-size: 12px; }
.site-b .card-b .pr { font-family: var(--mono); font-size: 11px; opacity: 0.7; }
.site-b .card-b .sub { font-family: var(--mono); font-size: 9px; opacity: 0.5; letter-spacing: 0.1em; text-transform: uppercase; grid-column: 1 / -1; }

/* --- Site C: photo portfolio, dark monochrome editorial --- */
.site-c {
  background: oklch(0.10 0.005 240);
  color: oklch(0.95 0.005 240);
  padding: 22px 24px;
  display: grid; grid-template-rows: auto 1fr; gap: 14px;
  font-family: var(--sans);
}
.site-c .nav-c {
  display: flex; justify-content: space-between; align-items: baseline;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.18em;
  text-transform: uppercase; opacity: 0.7;
}
.site-c .nav-c .b {
  font-family: var(--serif); font-size: 22px; letter-spacing: -0.01em; text-transform: none; opacity: 1;
  white-space: nowrap; flex-shrink: 0;
}
.site-c .grid-c {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 6px;
}
.site-c .ph {
  background: oklch(0.20 0.01 240);
  border-radius: 2px; position: relative; overflow: hidden;
}
.site-c .ph::after {
  content: ""; position: absolute; inset: 0; opacity: 0.7;
}
.site-c .ph.tall { grid-row: 1 / 3; }
.site-c .ph.tall::after { background: radial-gradient(circle at 30% 40%, oklch(0.60 0.06 30 / 0.6), transparent 70%); }
.site-c .ph.b1::after { background: radial-gradient(circle at 60% 30%, oklch(0.55 0.04 200 / 0.7), transparent 70%); }
.site-c .ph.b2::after { background: radial-gradient(circle at 40% 60%, oklch(0.45 0.03 80 / 0.7), transparent 70%); }
.site-c .ph.b3::after { background: radial-gradient(circle at 50% 50%, oklch(0.65 0.05 130 / 0.6), transparent 70%); }
.site-c .ph.b4::after { background: radial-gradient(circle at 70% 50%, oklch(0.55 0.08 320 / 0.6), transparent 70%); }
.site-c .ph .cap {
  position: absolute; left: 12px; bottom: 10px; z-index: 2;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.18em;
  text-transform: uppercase; opacity: 0.85;
}

/* --- Site D: SaaS / tech product, clean white & color --- */
.site-d {
  background: oklch(0.98 0.005 245);
  color: oklch(0.15 0.01 245);
  padding: 22px 24px;
  display: grid; grid-template-rows: auto auto 1fr; gap: 16px;
  font-family: var(--sans);
}
.site-d .nav-d {
  display: flex; justify-content: space-between; align-items: center;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
}
.site-d .nav-d .b {
  font-family: var(--sans); font-size: 14px; letter-spacing: -0.01em; text-transform: none; font-weight: 700;
  white-space: nowrap; flex-shrink: 0;
}
.site-d .nav-d .b::before {
  content: ""; display: inline-block; width: 14px; height: 14px;
  background: oklch(0.55 0.18 270); border-radius: 4px;
  margin-right: 8px; vertical-align: -3px;
}
.site-d .nav-d .links { display: flex; gap: 16px; opacity: 0.6; }
.site-d .nav-d .cta {
  background: oklch(0.18 0.01 245); color: oklch(0.98 0.005 245);
  padding: 6px 12px; border-radius: 6px; font-size: 10px;
}
.site-d .h1-d {
  font-family: var(--sans); font-weight: 700;
  font-size: clamp(28px, 3.4vw, 42px);
  line-height: 1.02; letter-spacing: -0.02em;
  max-width: 14ch; margin: 0;
}
.site-d .h1-d em { font-style: normal; color: oklch(0.55 0.18 270); }
.site-d .h1-d .pill {
  display: inline-block; font-family: var(--mono);
  font-size: 10px; padding: 2px 8px; border-radius: 99px;
  background: oklch(0.55 0.18 270 / 0.1); color: oklch(0.55 0.18 270);
  letter-spacing: 0.1em; text-transform: uppercase;
  vertical-align: middle; margin-right: 8px;
}
.site-d .product-d {
  border: 1px solid oklch(0.18 0.01 245 / 0.1); border-radius: 12px;
  background: white; overflow: hidden;
  display: grid; grid-template-rows: auto 1fr;
  box-shadow: 0 20px 50px -20px oklch(0.55 0.18 270 / 0.3);
}
.site-d .product-d .top {
  display: flex; gap: 16px; align-items: center;
  padding: 10px 14px; border-bottom: 1px solid oklch(0 0 0 / 0.06);
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
  color: oklch(0.5 0.01 245);
}
.site-d .product-d .top .tab.on { color: oklch(0.55 0.18 270); }
.site-d .product-d .body {
  display: grid; grid-template-columns: 100px 1fr; gap: 12px;
  padding: 14px;
}
.site-d .product-d .side {
  display: grid; gap: 4px;
}
.site-d .product-d .side .i {
  font-size: 11px; color: oklch(0.5 0.01 245); padding: 5px 8px; border-radius: 4px;
}
.site-d .product-d .side .i.on { background: oklch(0.55 0.18 270 / 0.1); color: oklch(0.55 0.18 270); }
.site-d .product-d .area {
  background: oklch(0.97 0.005 245); border-radius: 8px;
  padding: 14px; display: grid; gap: 10px;
}
.site-d .product-d .stat-row {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
}
.site-d .product-d .stat {
  background: white; border: 1px solid oklch(0 0 0 / 0.06); border-radius: 6px; padding: 10px;
}
.site-d .product-d .stat .v { font-family: var(--sans); font-size: 18px; font-weight: 700; }
.site-d .product-d .stat .l { font-family: var(--mono); font-size: 9px; color: oklch(0.5 0.01 245); letter-spacing: 0.08em; text-transform: uppercase; margin-top: 2px; }
.site-d .product-d .bars {
  display: grid; grid-template-columns: repeat(8, 1fr); gap: 4px; align-items: end; height: 60px;
}
.site-d .product-d .bars b {
  background: oklch(0.55 0.18 270); border-radius: 2px 2px 0 0;
}

/* ============================================================
   SCENE 3: Get Discovered — SEO + AEO + Meta ads + social
   Lots of realistic surfaces stacked on the right.
   ============================================================ */

.disco-stage {
  position: absolute; inset: 0;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 14px; padding: 20px;
  background:
    radial-gradient(ellipse 80% 60% at 100% 0%, color-mix(in oklch, var(--accent) 8%, transparent), transparent 70%),
    var(--bg);
}
.disco-col { display: grid; gap: 12px; min-height: 0; grid-auto-rows: minmax(0, 1fr); }

.surf {
  border: 1px solid var(--rule); border-radius: 12px;
  background: var(--bg-2); padding: 14px;
  display: grid; gap: 8px; min-height: 0;
  position: relative; overflow: hidden;
  transition: border-color var(--dur-medium) ease;
}
.surf .surf-head {
  display: flex; justify-content: space-between; align-items: center;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-3);
}
.surf .surf-head .badge {
  padding: 2px 8px; border: 1px solid var(--rule); border-radius: 99px;
}
.surf .surf-head .delta { color: var(--good); }
.surf.lit { border-color: color-mix(in oklch, var(--accent) 60%, transparent); }
.surf.lit .surf-head .badge { border-color: var(--accent); color: var(--accent); }

/* Google search */
.surf-google {
  background: white; color: oklch(0.18 0.01 245);
  border: 1px solid oklch(0 0 0 / 0.1);
  display: grid; gap: 10px;
}
.surf-google .surf-head { color: oklch(0.50 0.01 245); }
.surf-google .surf-head .badge { border-color: oklch(0 0 0 / 0.15); color: oklch(0.50 0.01 245); }
.surf-google.lit { border-color: oklch(0.55 0.18 250); }
.surf-google .res { display: grid; gap: 6px; }
.surf-google .res .url-row {
  display: flex; gap: 10px; align-items: center;
  font-family: var(--sans); font-size: 11px;
  color: oklch(0.18 0.01 245);
}
.surf-google .res .url-row .fav {
  width: 18px; height: 18px; border-radius: 50%;
  background: oklch(0.55 0.18 250);
  display: inline-block;
  background-image:
    linear-gradient(45deg, transparent 47%, white 47%, white 53%, transparent 53%);
  flex-shrink: 0;
}
.surf-google .res .url-row .site { font-weight: 500; font-size: 12px; }
.surf-google .res .url-row .path { font-size: 10px; color: oklch(0.50 0.01 245); }
.surf-google .res .ttl {
  font-family: var(--sans); font-weight: 500; font-size: 16px; line-height: 1.2;
  color: oklch(0.32 0.10 250); letter-spacing: -0.005em;
}
.surf-google .res .desc { font-family: var(--sans); font-size: 11px; color: oklch(0.30 0.01 245); line-height: 1.5; }
.surf-google .res .desc .tag { color: oklch(0.45 0.18 130); font-weight: 500; }
.surf-google .res .snippets { display: flex; gap: 6px; margin-top: 4px; }
.surf-google .res .snippets .snip {
  font-family: var(--sans); font-size: 10px;
  padding: 3px 9px; border: 1px solid oklch(0 0 0 / 0.08);
  border-radius: 99px; color: oklch(0.40 0.10 250); background: oklch(0.97 0.01 245);
}
.surf-google .rank {
  font-family: var(--mono); font-size: 9px;
  color: oklch(0.50 0.01 245);
  letter-spacing: 0.12em; text-transform: uppercase;
}
.surf-google .rank b { color: oklch(0.45 0.18 130); font-weight: 600; }
.surf-google .rank-foot {
  border-top: 1px dashed oklch(0 0 0 / 0.1); padding-top: 8px; margin-top: auto;
}

/* AI Overview */
.surf-ai {
  background:
    linear-gradient(135deg, color-mix(in oklch, var(--accent) 8%, var(--bg-2)) 0%, var(--bg-2) 70%);
  display: grid; gap: 10px;
}
.surf-ai .ai-tag { display: inline-flex; align-items: center; gap: 8px; }
.surf-ai .ai-tag .spark { color: var(--accent); font-size: 12px; line-height: 1; }
.surf-ai .body { font-family: var(--serif); font-size: 13px; line-height: 1.55; color: var(--ink-2); letter-spacing: -0.005em; }
.surf-ai .body b { color: var(--ink); font-weight: 500; font-style: normal; }
.surf-ai .body .cite {
  font-family: var(--mono); font-size: 8px; color: var(--accent);
  vertical-align: super; padding: 0 3px; border: 1px solid var(--accent);
  border-radius: 3px; margin: 0 1px; letter-spacing: 0.05em;
  background: var(--accent-soft);
}
.surf-ai .sources { display: flex; gap: 6px; flex-wrap: wrap; font-family: var(--mono); font-size: 9px; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.08em; margin-top: auto; }
.surf-ai .sources .s { padding: 3px 7px; border: 1px solid var(--rule); border-radius: 4px; background: var(--bg); }
.surf-ai .sources .s.brand { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }

/* Meta Ads Manager */
.surf-meta {
  background: white; color: oklch(0.18 0.01 245); border: 1px solid oklch(0 0 0 / 0.1);
  display: grid; gap: 8px;
}
.surf-meta .surf-head { color: oklch(0.5 0.01 245); }
.surf-meta .surf-head .meta-mark {
  display: inline-block; width: 14px; height: 14px;
  background: linear-gradient(135deg, oklch(0.55 0.18 240), oklch(0.55 0.18 320));
  border-radius: 4px; margin-right: 6px; vertical-align: -2px;
  color: white; text-align: center; line-height: 14px; font-size: 11px;
}
.surf-meta .surf-head .badge { border-color: oklch(0 0 0 / 0.15); color: oklch(0.5 0.01 245); }
.surf-meta.lit { border-color: oklch(0.55 0.18 240); }

.surf-meta .meta-summary {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
  border-top: 1px solid oklch(0 0 0 / 0.06);
  border-bottom: 1px solid oklch(0 0 0 / 0.06);
  padding: 10px 0; margin-bottom: 4px;
}
.surf-meta .meta-summary .lbl {
  font-family: var(--mono); font-size: 8px; letter-spacing: 0.12em;
  text-transform: uppercase; color: oklch(0.5 0.01 245);
}
.surf-meta .meta-summary .v {
  font-family: var(--sans); font-weight: 600; font-size: 14px;
  color: oklch(0.18 0.01 245); margin-top: 2px;
}
.surf-meta .meta-summary .v .up {
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  color: oklch(0.55 0.15 160); margin-left: 4px; letter-spacing: 0.04em;
}

.surf-meta .row {
  display: grid; grid-template-columns: 1fr auto auto auto;
  gap: 10px; align-items: center;
  padding: 7px 0; border-bottom: 1px solid oklch(0 0 0 / 0.06);
  font-size: 10px;
}
.surf-meta .row:last-child { border-bottom: 0; }
.surf-meta .row .nm { display: flex; align-items: center; gap: 8px; min-width: 0; }
.surf-meta .row .nm .ic {
  width: 22px; height: 22px; border-radius: 4px;
  background: linear-gradient(135deg, oklch(0.55 0.18 240), oklch(0.55 0.18 320));
  flex-shrink: 0;
}
.surf-meta .row .nm .ic.alt { background: linear-gradient(135deg, oklch(0.62 0.20 30), oklch(0.65 0.16 50)); }
.surf-meta .row .nm .ic.alt2 { background: linear-gradient(135deg, oklch(0.65 0.16 130), oklch(0.65 0.10 100)); }
.surf-meta .row .nm .t { font-weight: 500; }
.surf-meta .row .nm .s { font-family: var(--mono); font-size: 8px; color: oklch(0.5 0.01 245); letter-spacing: 0.06em; text-transform: uppercase; }
.surf-meta .row .v { font-family: var(--mono); font-size: 11px; }
.surf-meta .row .v.up { color: oklch(0.55 0.15 160); }
.surf-meta .row .v.dn { color: oklch(0.55 0.18 30); }
.surf-meta .row .pill {
  font-family: var(--mono); font-size: 8px; padding: 2px 8px;
  border-radius: 99px; background: oklch(0.95 0.04 130); color: oklch(0.40 0.10 160);
  letter-spacing: 0.08em; text-transform: uppercase;
}
.surf-meta .row .pill.off { background: oklch(0.93 0 0); color: oklch(0.5 0 0); }

/* Earned mentions strip — multi-platform */
.surf-mentions {
  display: grid; gap: 0;
}
.surf-mentions .surf-head { padding-bottom: 8px; border-bottom: 1px solid var(--rule); }
.surf-mentions .ment {
  display: grid; grid-template-columns: 32px 1fr;
  gap: 12px; padding: 10px 0;
  border-bottom: 1px solid var(--rule-2);
}
.surf-mentions .ment:last-child { border-bottom: 0; }
.surf-mentions .ment .src {
  width: 32px; height: 32px; border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-weight: 700; font-size: 11px;
  letter-spacing: 0.04em; color: white;
}
.surf-mentions .ment .src.ig { background: linear-gradient(135deg, oklch(0.65 0.20 30), oklch(0.55 0.20 320)); }
.surf-mentions .ment .src.tt { background: linear-gradient(135deg, oklch(0.20 0 0), oklch(0.40 0.20 200)); }
.surf-mentions .ment .src.x  { background: oklch(0.15 0 0); }
.surf-mentions .ment .src.rd { background: oklch(0.62 0.18 30); }
.surf-mentions .ment .bod { display: grid; gap: 3px; min-width: 0; }
.surf-mentions .ment .who { font-size: 11px; font-weight: 500; color: var(--ink); }
.surf-mentions .ment .who .meta { font-family: var(--mono); font-size: 9px; color: var(--ink-3); font-weight: 400; letter-spacing: 0.06em; text-transform: uppercase; margin-left: 6px; }
.surf-mentions .ment .txt { font-size: 11px; color: var(--ink-2); line-height: 1.4; }
.surf-mentions .ment .txt .tag { color: var(--accent); font-weight: 500; }
.surf-mentions .ment .stats {
  font-family: var(--mono); font-size: 9px; color: var(--ink-3);
  letter-spacing: 0.06em; text-transform: uppercase;
  display: flex; gap: 12px; margin-top: 2px;
}

/* ============================================================
   Selected work — clean isolated frame, more depth, less busy
   ============================================================ */

.featured {
  padding: clamp(80px, 12vh, 140px) var(--gutter) clamp(80px, 12vh, 140px);
  position: relative;
}
.featured::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(ellipse 60% 50% at 50% 30%, color-mix(in oklch, var(--accent) 6%, transparent), transparent 70%);
  pointer-events: none;
}
.featured .stage {
  position: relative;
  margin-top: 64px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
}
.featured .stage > .frame { margin-bottom: 0; }
.featured .case-meta {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 24px;
  padding: 0 8px;
}
.featured .case-meta .left {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  letter-spacing: 0.14em; text-transform: uppercase;
  display: flex; align-items: center; gap: 12px;
}
.featured .case-meta .left::before {
  content: ""; width: 24px; height: 1px; background: var(--accent);
}
.featured .case-meta .right {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  letter-spacing: 0.14em; text-transform: uppercase;
  text-align: right;
}
.featured .case-meta .right b { color: var(--ink); font-weight: 500; }

.featured h3 {
  margin: 0;
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(36px, 4.4vw, 60px);
  line-height: 1.02; letter-spacing: -0.015em;
  max-width: 22ch;
  padding: 0 8px;
}
.featured h3 em { color: var(--accent); font-style: italic; }

.featured .frame {
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  background: var(--bg-2);
  border: 1px solid var(--rule);
  border-bottom: 0;
  box-shadow:
    0 1px 0 0 color-mix(in oklch, var(--ink) 6%, transparent) inset,
    0 50px 100px -40px rgba(0,0,0,0.5),
    0 16px 40px -16px rgba(0,0,0,0.4);
  overflow: hidden;
  height: clamp(540px, 75vh, 760px);
  position: relative;
}

/* Frame + impact form a single attached card; collapse the gap. */
.featured .stage > .frame { margin-bottom: -40px; }
.featured .impact { margin-top: 0; }

.featured .impact {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  padding: 0;
  background: var(--bg-2);
  border: 1px solid var(--rule);
  border-radius: 0 0 var(--radius-xl) var(--radius-xl);
  box-shadow:
    0 16px 40px -16px rgba(0,0,0,0.4);
}
.featured .impact .stat {
  padding: 36px 32px;
  border-right: 1px solid var(--rule);
  display: grid; gap: 10px;
  align-content: start;
}
.featured .impact .stat:last-child { border-right: 0; }
.featured .impact .stat .v {
  font-family: var(--serif);
  font-size: clamp(48px, 6vw, 88px);
  line-height: 0.95; letter-spacing: -0.025em;
  color: var(--ink);
}
.featured .impact .stat .l {
  font-family: var(--mono); font-size: 11px; color: var(--accent);
  letter-spacing: 0.16em; text-transform: uppercase;
}
.featured .impact .stat .d {
  color: var(--ink-2); font-size: 14px; line-height: 1.5;
  max-width: 44ch; margin-top: 4px;
}

@media (max-width: 980px) {
  .featured .case-meta { grid-template-columns: 1fr; }
  .featured .case-meta .right { text-align: left; }
  .featured .impact { grid-template-columns: 1fr; }
  .featured .impact .stat { border-right: 0; border-bottom: 1px solid var(--rule); }
  .featured .impact .stat:last-child { border-bottom: 0; }
}

/* ============================================================
   HVAC reporting software — accurate-feeling preview
   ============================================================ */

.hvac {
  position: absolute; inset: 0;
  display: grid; grid-template-columns: 168px 1fr;
  font-family: var(--sans);
  background: var(--bg);
  font-size: 12px;
}
.hvac .side {
  border-right: 1px solid var(--rule);
  padding: 0;
  display: grid; gap: 0; align-content: start;
  background: color-mix(in oklch, var(--bg) 92%, var(--bg-2));
}
.hvac .side .brand-h {
  padding: 16px 14px;
  border-bottom: 1px solid var(--rule);
  display: grid; gap: 4px;
}
.hvac .side .brand-h .nm {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.18em;
  color: var(--ink); font-weight: 600;
}
.hvac .side .brand-h .sub { font-size: 9px; color: var(--ink-4); letter-spacing: 0.04em; }
.hvac .side .group {
  padding: 10px 8px 4px;
  font-family: var(--mono); font-size: 8px;
  color: var(--ink-4); letter-spacing: 0.18em; text-transform: uppercase;
}
.hvac .side .item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 14px;
  font-size: 11px; color: var(--ink-3);
  cursor: default;
  position: relative;
}
.hvac .side .item .ic { width: 12px; opacity: 0.6; font-family: var(--mono); font-size: 11px; }
.hvac .side .item.active {
  background: var(--accent-soft);
  color: var(--ink);
}
.hvac .side .item.active::before {
  content: ""; position: absolute; left: 0; top: 4px; bottom: 4px; width: 2px;
  background: var(--accent);
}
.hvac .side .item.active .ic { color: var(--accent); opacity: 1; }

.hvac .main { display: grid; grid-template-rows: auto 1fr; min-height: 0; }
.hvac .topbar {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 18px; border-bottom: 1px solid var(--rule);
  font-family: var(--mono); font-size: 10px; color: var(--ink-3);
  letter-spacing: 0.1em; text-transform: uppercase;
}
.hvac .topbar .ttl { color: var(--ink); font-weight: 600; letter-spacing: 0.06em; font-size: 11px; }
.hvac .topbar .pill {
  padding: 4px 10px; border: 1px solid var(--rule); border-radius: 6px;
  display: inline-flex; gap: 8px; align-items: baseline;
}
.hvac .topbar .pill b { color: var(--ink); font-weight: 500; font-family: var(--sans); font-size: 11px; }
.hvac .topbar .right { margin-left: auto; display: flex; gap: 10px; align-items: center; font-size: 9px; }
.hvac .topbar .acc {
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--accent); color: var(--bg);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 600;
}

.hvac .content {
  padding: 16px;
  display: grid; gap: 14px;
  grid-template-rows: auto 1fr;
  min-height: 0; overflow: hidden;
}
.hvac .toprow {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
.hvac .kpibox {
  border: 1px solid var(--rule); border-radius: 10px;
  background: var(--bg-2);
  padding: 14px;
  display: grid; gap: 6px;
}
.hvac .kpibox .lbl {
  font-family: var(--mono); font-size: 9px;
  color: var(--ink-3); letter-spacing: 0.16em; text-transform: uppercase;
}
.hvac .kpibox .val {
  font-family: var(--sans); font-size: 22px; font-weight: 600;
  color: var(--ink); letter-spacing: -0.01em; line-height: 1;
}
.hvac .kpibox .dlt {
  font-family: var(--mono); font-size: 10px;
  display: flex; gap: 6px; align-items: center;
  color: var(--ink-3);
}
.hvac .kpibox .dlt .up { color: var(--good); }
.hvac .kpibox .dlt .down { color: var(--hot); }
.hvac .kpibox .spark { height: 28px; }
.hvac .kpibox .spark svg { width: 100%; height: 100%; }

.hvac .twocol {
  display: grid; grid-template-columns: 1.5fr 1fr;
  gap: 12px; min-height: 0;
}
.hvac .panel-h {
  border: 1px solid var(--rule); border-radius: 10px;
  background: var(--bg-2);
  padding: 14px;
  display: grid; grid-template-rows: auto 1fr;
  gap: 10px; min-height: 0;
}
.hvac .panel-h .head {
  display: flex; justify-content: space-between; align-items: center;
}
.hvac .panel-h .head .ttl {
  font-family: var(--mono); font-size: 9px; color: var(--ink-3);
  letter-spacing: 0.16em; text-transform: uppercase;
}
.hvac .panel-h .head .tabs {
  display: flex; gap: 4px;
  font-family: var(--mono); font-size: 9px; color: var(--ink-3);
  letter-spacing: 0.1em; text-transform: uppercase;
}
.hvac .panel-h .head .tabs span { padding: 2px 6px; border-radius: 4px; }
.hvac .panel-h .head .tabs .on { background: var(--bg-3); color: var(--ink); }

.hvac .chart-h { position: relative; min-height: 0; }
.hvac .chart-h svg { width: 100%; height: 100%; display: block; }

.hvac .leakslist { display: grid; gap: 4px; min-height: 0; overflow: hidden; }
.hvac .leakslist .row {
  display: grid; grid-template-columns: 1fr auto auto;
  gap: 10px; align-items: center;
  padding: 7px 8px; border-radius: 6px;
  font-size: 11px;
  background: var(--bg);
  border: 1px solid var(--rule-2);
}
.hvac .leakslist .row .nm { color: var(--ink); }
.hvac .leakslist .row .src { font-family: var(--mono); font-size: 9px; color: var(--ink-3); letter-spacing: 0.06em; text-transform: uppercase; }
.hvac .leakslist .row .v { font-family: var(--mono); font-size: 11px; color: var(--accent); }

/* ============================================================
   Process
   ============================================================ */

.process { padding: 40px var(--gutter) 120px; }
.process .wrap { margin-top: 56px; display: grid; grid-template-columns: 200px 1fr; gap: 40px; }
.process .step {
  display: grid; grid-template-columns: 80px 1.2fr 1fr; gap: 32px;
  padding: 24px 0; border-top: 1px solid var(--rule);
  align-items: start; transition: background .3s ease;
}
.process .step:last-child { border-bottom: 1px solid var(--rule); }
.process .step:hover { background: color-mix(in oklch, var(--ink) 3%, transparent); }
.process .step .num { font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em; color: var(--ink-3); }
.process .step h4 {
  margin: 0;
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(28px, 3.2vw, 42px);
  line-height: 1.02; letter-spacing: -0.015em;
}
.process .step h4 em { color: var(--accent); font-style: italic; }
.process .step p { margin: 0; color: var(--ink-2); max-width: 42ch; }
.process .step .duration {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3); margin-top: 12px;
  letter-spacing: 0.08em; text-transform: uppercase;
}
@media (max-width: 980px) {
  .process .wrap { grid-template-columns: 1fr; }
  .process .step { grid-template-columns: 1fr; gap: 12px; padding: 22px 0; }
}

/* ============================================================
   Hungry
   ============================================================ */

.hungry { padding: 60px var(--gutter) 120px; position: relative; overflow: hidden; }
.hungry .grid {
  display: grid; grid-template-columns: 1fr 1.3fr;
  gap: 60px; align-items: start; margin-top: 56px;
}
.hungry .left { position: sticky; top: 100px; align-self: start; }
.hungry .left h3 {
  margin: 0;
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(36px, 4.2vw, 56px);
  line-height: 1.02; letter-spacing: -0.02em;
}
.hungry .left h3 em { color: var(--accent); font-style: italic; }
.hungry .left .sig { margin-top: 28px; }
.hungry .left .stamp {
  margin-top: 14px;
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: 10px;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-3);
}
.hungry .left .stamp::before { content: ""; width: 24px; height: 1px; background: var(--ink-4); }
.hungry .right p { font-size: 18px; color: var(--ink-2); max-width: 56ch; margin: 0 0 16px; }
.hungry .right p em { font-style: italic; color: var(--ink); }
.hungry .right .promises {
  margin-top: 28px; display: grid; gap: 0;
  border: 1px solid var(--rule); border-radius: var(--radius-lg); overflow: hidden;
}
.hungry .right .promises .row {
  display: grid; grid-template-columns: 64px 1fr;
  gap: 16px; align-items: baseline;
  padding: 18px 22px; border-bottom: 1px solid var(--rule);
  transition: background var(--dur-base) ease;
}
.hungry .right .promises .row:last-child { border-bottom: 0; }
.hungry .right .promises .row:hover { background: var(--bg-2); }
.hungry .right .promises .row .n { font-family: var(--mono); font-size: 11px; color: var(--accent); letter-spacing: 0.1em; }
.hungry .right .promises .row .b { color: var(--ink); font-size: 16px; line-height: 1.45; }
.hungry .right .promises .row .b em { color: var(--accent); font-style: italic; }
@media (max-width: 980px) {
  .hungry .grid { grid-template-columns: 1fr; gap: 30px; }
  .hungry .left { position: static; }
}

/* ============================================================
   FAQ
   ============================================================ */

.faq { padding: 40px var(--gutter) 120px; }
.faq .list { margin-top: 56px; border-top: 1px solid var(--rule); }
.faq details { border-bottom: 1px solid var(--rule); padding: 22px 0; }
.faq summary {
  display: flex; justify-content: space-between; align-items: baseline; gap: 24px;
  cursor: pointer; list-style: none;
  font-family: var(--serif);
  font-size: clamp(22px, 2.4vw, 30px);
  line-height: 1.1; letter-spacing: -0.01em; text-wrap: balance;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary .icon {
  font-family: var(--mono); font-size: 14px; color: var(--ink-3);
  flex-shrink: 0; transition: transform .3s ease, color .3s ease;
}
.faq details[open] summary .icon { transform: rotate(45deg); color: var(--accent); }
.faq details .a { margin-top: 12px; color: var(--ink-2); max-width: 70ch; font-size: 16px; line-height: 1.6; }

/* ============================================================
   CTA + Footer
   ============================================================ */

.cta .eyebrow .dot {
  background: var(--good);
  box-shadow: 0 0 0 4px color-mix(in oklch, var(--good) 25%, transparent);
}
.cta {
  padding: clamp(90px, 12vw, 160px) var(--gutter);
  border-top: 1px solid var(--rule);
  position: relative; overflow: hidden;
}
.cta .bg {
  position: absolute; inset: 0;
  background-image: radial-gradient(ellipse 80% 60% at 50% 80%,
    color-mix(in oklch, var(--accent) 16%, transparent) 0%, transparent 70%);
  pointer-events: none;
}
.cta .inner {
  position: relative; display: grid; gap: 32px;
  text-align: center; max-width: 1200px; margin: 0 auto;
}
.cta h2 {
  margin: 0;
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(44px, 6vw, 96px);
  line-height: 1.05; letter-spacing: -0.025em; text-wrap: balance;
}
.cta h2 em { color: var(--accent); font-style: italic; }
.cta p { margin: 0 auto; max-width: 50ch; color: var(--ink-2); font-size: 18px; }
.cta .actions { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-top: 4px; }
.cta .btn-big {
  display: inline-flex; align-items: center; gap: 14px;
  padding: 18px 26px; border-radius: 8px;
  background: var(--accent); color: var(--bg);
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 500;
  transition: transform var(--dur-base) ease, background var(--dur-base) ease;
}
.cta .btn-big:hover { transform: translateY(-1px); background: var(--accent-2); }
.cta .btn-big.ghost { background: transparent; color: var(--ink); border: 1px solid var(--rule); }
.cta .btn-big.ghost:hover { background: var(--bg-2); border-color: var(--ink-3); }
.cta .btn-big .arr {
  width: 22px; height: 22px; border-radius: 4px;
  background: var(--bg); color: var(--accent);
  display: inline-flex; align-items: center; justify-content: center; font-size: 11px;
}

.foot {
  padding: 30px var(--gutter) 28px;
  border-top: 1px solid var(--rule);
  display: grid; grid-template-columns: auto 1fr auto; gap: 32px; align-items: center;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-3);
}
.foot a:hover { color: var(--ink); }
.foot .brand-foot { display: inline-flex; align-items: center; gap: 12px; color: var(--ink); text-transform: none; }
.foot .brand-foot .yr { font-family: var(--mono); font-size: 11px; color: var(--ink-3); }

/* SVG wordmark must not inherit uppercase / letter-spacing from nav/foot */
.crewsive-wm-svg, .crewsive-wm-svg svg, .crewsive-wm-svg text {
  text-transform: none !important;
  letter-spacing: 0 !important;
}
.crewsive-wm-svg svg text { font-style: normal; }
.foot .links { display: flex; gap: 22px; justify-content: center; flex-wrap: wrap; }
@media (max-width: 720px) { .foot { grid-template-columns: 1fr; text-align: center; } }

/* ============================================================
   Editorial menu — Jacob & Co–inspired full-screen takeover.
   Trigger is a single hairline; overlay is a typographic
   composition with per-item ornaments and a shared halo.
   ============================================================ */

/* Menu easing alias — kept for back-compat with older selectors. */
:root {
  --menu-ease: var(--ease-out-soft);
}

body.menu-open { overflow: hidden; }

/* nav right cluster (CTA + trigger together) */
.nav .nav__right {
  display: flex;
  align-items: center;
  gap: 14px;
}

/* hide the now-deprecated inline links if any code path still renders them */
.nav .links { display: none !important; }
@media (max-width: 720px) { .nav .links { display: none !important; } }

/* the trigger — single hairline that morphs into a serif × */
.nav-trigger {
  width: 44px;
  height: 44px;
  position: relative;
  color: var(--ink);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  /* Re-enabled: the full-screen menu now routes to the real services /
     free-audit / FAQ directory pages, so the trigger is visible again. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* ensure trigger sits above the menu overlay */
  z-index: 220;
}
/* Two stacked hairlines that collapse into one on hover —
   Jacob & Co–style. When the menu opens, both fade out and
   the serif × cross-fades in. */
.nav-trigger__line {
  position: absolute;
  left: 4px; right: 4px;
  height: 1px;
  background: currentColor;
  transform-origin: center;
  transition:
    top       450ms var(--menu-ease),
    opacity   220ms var(--menu-ease),
    transform 500ms var(--menu-ease);
}
.nav-trigger__line--top    { top: calc(50% - 4px); }
.nav-trigger__line--bottom { top: calc(50% + 4px); }

/* hover: both lines glide to the centerline so they overlap into one */
.nav-trigger:hover .nav-trigger__line--top,
.nav-trigger:hover .nav-trigger__line--bottom { top: 50%; }

/* open: both lines collapse and fade so the serif × can take over */
.nav-trigger[aria-expanded="true"] .nav-trigger__line {
  opacity: 0;
  top: 50%;
  transform: scaleX(0);
}
.nav-trigger__close {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--serif);
  font-weight: 400;
  font-size: 38px;
  line-height: 1;
  color: var(--ink);
  opacity: 0;
  transform: scale(0.5) rotate(-25deg);
  transition: opacity 350ms var(--menu-ease) 120ms, transform 500ms var(--menu-ease) 120ms;
}
.nav-trigger[aria-expanded="true"] .nav-trigger__close {
  opacity: 1;
  transform: scale(1) rotate(0);
}

/* ===== overlay ===== */
.nav-menu {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  pointer-events: none;
  opacity: 0;
  transition: opacity 600ms var(--menu-ease);
}
.nav-menu::before {
  content: '';
  position: absolute;
  inset: 0;
  background: color-mix(in oklch, var(--bg) 94%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.nav-menu--open {
  pointer-events: auto;
  opacity: 1;
}

/* ambient background type */
.nav-menu__ambient {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  padding: 0 0 64px 4vw;
  pointer-events: none;
  overflow: hidden;
  z-index: 1;
}
.nav-menu__ambient-text {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(110px, 18vw, 280px);
  line-height: 0.85;
  letter-spacing: -0.035em;
  color: color-mix(in oklch, var(--ink) 5%, transparent);
  white-space: nowrap;
  opacity: 0;
  transition: opacity var(--dur-cine) var(--menu-ease) 200ms;
}
.nav-menu--open .nav-menu__ambient-text { opacity: 1; }

/* shared halo — soft glow that follows the active item */
.menu-halo {
  position: absolute;
  left: 50%;
  top: 50%;
  width: clamp(560px, 70vw, 1080px);
  height: clamp(280px, 40vh, 460px);
  pointer-events: none;
  background: radial-gradient(ellipse at center,
    color-mix(in oklch, var(--ink) 7%, transparent) 0%,
    color-mix(in oklch, var(--ink) 3%, transparent) 35%,
    transparent 65%);
  filter: blur(6px);
  transform: translate(-50%, calc(-50% + var(--halo-y, 0%)));
  opacity: 0;
  transition:
    transform 1000ms var(--menu-ease),
    opacity   600ms var(--menu-ease);
  z-index: 0;
}
.nav-menu--open .menu-halo { opacity: 0.7; }
.menu-halo--locked          { opacity: 1; }

/* primary nav */
.nav-menu__primary {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 4px;
  padding: 120px var(--gutter) 32px;
  list-style: none;
  margin: 0;
  position: relative;
  z-index: 2;
}
.nav-menu .primary-row {
  opacity: 0;
  transform: translateY(36px);
  transition: opacity var(--dur-slow) var(--menu-ease), transform var(--dur-slow) var(--menu-ease);
}
.nav-menu--open .primary-row { opacity: 1; transform: translateY(0); }
.nav-menu--open .primary-row:nth-child(1) { transition-delay: 140ms; }
.nav-menu--open .primary-row:nth-child(2) { transition-delay: 220ms; }
.nav-menu--open .primary-row:nth-child(3) { transition-delay: 300ms; }
.nav-menu--open .primary-row:nth-child(4) { transition-delay: 380ms; }

.nav-menu .primary-item {
  display: inline-block;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(54px, 8.6vw, 132px);
  line-height: 1.04;
  letter-spacing: 0em;
  color: var(--ink);
  cursor: pointer;
  opacity: 1;
  text-decoration: none;
  text-transform: none;
  padding: 0 8px;
  transition:
    opacity        var(--dur-medium) var(--menu-ease),
    letter-spacing var(--dur-slow)   var(--menu-ease),
    transform      var(--dur-slow)   var(--menu-ease);
  will-change: letter-spacing, transform, opacity;
}
.nav-menu .nav-menu__primary--has-hover .primary-item { opacity: 0.18; }
.nav-menu .nav-menu__primary--has-hover .primary-item--active {
  opacity: 1;
  letter-spacing: 0.08em;
}

/* secondary nav */
.nav-menu__secondary {
  padding: 0 var(--gutter) 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0;
  position: relative;
  z-index: 2;
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-slow) var(--menu-ease) 540ms, transform var(--dur-slow) var(--menu-ease) 540ms;
}
.nav-menu--open .nav-menu__secondary { opacity: 1; transform: translateY(0); }
.nav-menu .secondary-item {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--ink);
  padding: 6px 22px;
  transition: opacity var(--dur-base) var(--menu-ease);
}
.nav-menu .secondary-item:hover { opacity: 0.5; }
.nav-menu .secondary-divider {
  width: 1px;
  height: 11px;
  background: var(--rule);
  display: inline-block;
}

/* ===== Per-item ornaments ===== */
.ornament {
  position: absolute;
  inset: 16vh 4vw 20vh 4vw;
  pointer-events: none;
  color: var(--ink);
  opacity: 0;
  transform: scale(0.99);
  filter: blur(1.5px);
  transition:
    opacity   850ms var(--menu-ease),
    transform 950ms var(--menu-ease),
    filter    700ms var(--menu-ease);
  z-index: 1;
}
.ornament--active {
  opacity: 0.72;
  transform: scale(1);
  filter: blur(0);
}
.ornament > * {
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity   var(--dur-slow) var(--menu-ease),
    transform 800ms          var(--menu-ease);
}
.ornament--active > * { opacity: 1; transform: translateY(0); }
.ornament--active > *:nth-child(1) { transition-delay:  80ms; }
.ornament--active > *:nth-child(2) { transition-delay: 160ms; }
.ornament--active > *:nth-child(3) { transition-delay: 240ms; }
.ornament--active > *:nth-child(4) { transition-delay: 320ms; }
.ornament--active > *:nth-child(5) { transition-delay: 400ms; }
.ornament--active > *:nth-child(6) { transition-delay: 480ms; }
.ornament--active > *:nth-child(7) { transition-delay: 560ms; }

.ornament .orn-label {
  position: absolute;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
  opacity: 0.85;
}
.ornament .orn-svg {
  position: absolute;
  pointer-events: none;
  stroke: currentColor;
  fill: none;
}

/* SERVICES — drafting marks */
.orn-services .orn-arc {
  top: -1px; right: -1px;
  width: clamp(80px, 9vw, 130px);
  height: clamp(80px, 9vw, 130px);
}
.orn-services .orn-cross {
  bottom: -1px; left: -1px;
  width: 56px; height: 56px;
}
.orn-services .orn-label--tl { top: -22px; left: 0; }
.orn-services .orn-label--br { bottom: -22px; right: 0; }
.orn-services .orn-rule {
  position: absolute;
  left: 16%; right: 16%;
  bottom: 50%;
  height: 1px;
  border-top: 1px dashed currentColor;
  opacity: 0.4;
}

/* WORK — portfolio framing */
.orn-work .orn-frame {
  position: absolute;
  inset: 6% 3%;
  border: 1px solid currentColor;
  opacity: 0.32;
}
.orn-work .orn-corner {
  position: absolute;
  width: 18px; height: 18px;
}
.orn-work .orn-corner--tl { top: 6%; left: 3%; border-top: 2px solid currentColor; border-left: 2px solid currentColor; transform: translate(-1px, -1px); }
.orn-work .orn-corner--tr { top: 6%; right: 3%; border-top: 2px solid currentColor; border-right: 2px solid currentColor; transform: translate(1px, -1px); }
.orn-work .orn-corner--bl { bottom: 6%; left: 3%; border-bottom: 2px solid currentColor; border-left: 2px solid currentColor; transform: translate(-1px, 1px); }
.orn-work .orn-corner--br { bottom: 6%; right: 3%; border-bottom: 2px solid currentColor; border-right: 2px solid currentColor; transform: translate(1px, 1px); }
.orn-work .orn-label--tl { top: -22px; left: 0; }
.orn-work .orn-label--br { bottom: -22px; right: 0; }

/* PROCESS — clean spine, dots, italic words */
.orn-process .orn-spine {
  position: absolute;
  left: 5%;
  top: 8%;
  bottom: 8%;
  width: 1px;
  background: currentColor;
  opacity: 0.32;
}
.orn-process .orn-node {
  position: absolute;
  left: 5%;
  transform: translate(-3px, -50%);
  display: flex;
  align-items: center;
  gap: 14px;
  white-space: nowrap;
}
.orn-process .orn-node--1 { top: 18%; }
.orn-process .orn-node--2 { top: 50%; }
.orn-process .orn-node--3 { top: 82%; }
.orn-process .orn-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  display: inline-block;
  flex-shrink: 0;
}
.orn-process .orn-num {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  opacity: 0.55;
  margin-left: 6px;
}
.orn-process .orn-word {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(20px, 2vw, 26px);
  letter-spacing: -0.005em;
  opacity: 0.92;
  text-transform: none;
}
.orn-process .orn-curve {
  position: absolute;
  right: 3%;
  top: 12%;
  bottom: 12%;
  width: clamp(60px, 6vw, 110px);
  height: auto;
  stroke-width: 0.7;
  opacity: 0.65;
}

/* FAQ — editorial pull-quotes */
.orn-faq .orn-quote {
  position: absolute;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(140px, 22vw, 300px);
  line-height: 0.72;
  color: currentColor;
  opacity: 0.55;
}
.orn-faq .orn-quote--open  { top: -28px;  left:  -8px; }
.orn-faq .orn-quote--close { bottom: -120px; right: -8px; }
.orn-faq .orn-label--tr    { top: -22px; right: 0; }

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  .nav-menu, .nav-menu *, .ornament, .ornament *, .menu-halo, .nav-trigger * {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* Small screens */
@media (max-width: 720px) {
  .nav-menu__primary { gap: 2px; padding: 110px var(--gutter) 20px; }
  .nav-menu .primary-item { font-size: clamp(40px, 11vw, 70px); }
  .nav-menu__secondary { gap: 0 4px; padding: 0 var(--gutter) 36px; }
  .nav-menu .secondary-item { padding: 6px 12px; font-size: 10px; }
  .nav-menu .secondary-divider { display: none; }
  .nav-menu__ambient-text { font-size: clamp(90px, 22vw, 160px); }
  .orn-faq .orn-quote { font-size: clamp(110px, 28vw, 200px); }
}

/* ============================================================
   SEO audit popup — square, black, minimal, hard edges
   ============================================================ */
@keyframes seoPopIn {
  0%   { opacity: 0; transform: translateY(16px); }
  100% { opacity: 1; transform: translateY(0); }
}

.seo-popup {
  position: fixed;
  left: 24px;
  bottom: 24px;
  z-index: 9000;
  width: 440px;
  height: 440px;
  padding: 32px;
  background: #000;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 0;
  box-shadow:
    0 30px 60px -25px rgba(0, 0, 0, 0.9),
    0 8px 24px -12px rgba(0, 0, 0, 0.7);
  color: #fff;
  display: flex;
  flex-direction: column;
  animation: seoPopIn 280ms ease-out both;
}

.seo-popup__close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  font-family: var(--sans);
  font-size: 20px;
  line-height: 1;
  color: rgba(255, 255, 255, 0.55);
  border: 0;
  border-radius: 0;
  transition: color 120ms ease;
}
.seo-popup__close:hover {
  color: #fff;
}

.seo-popup__title {
  font-size: 40px;
  line-height: 0.98;
  margin: 0;
  letter-spacing: -0.015em;
  color: #fff;
}
.seo-popup__title em {
  font-style: italic;
  color: #fff;
}

.seo-popup__kicker {
  margin: 8px 0 18px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #fff;
  opacity: 0.6;
}

.seo-popup__form {
  display: grid;
  gap: 6px;
  margin-top: auto;
}

.seo-popup__field {
  display: block;
  position: relative;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  transition: border-color var(--dur-fast) ease;
}
.seo-popup__field:focus-within {
  border-color: rgba(255, 255, 255, 0.55);
}
.seo-popup__field > span {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
  pointer-events: none;
  transition: top var(--dur-fast) ease, font-size var(--dur-fast) ease, color var(--dur-fast) ease, transform var(--dur-fast) ease;
}
.seo-popup__field:focus-within > span,
.seo-popup__field.has-value > span {
  top: 4px;
  transform: translateY(0);
  font-size: 8.5px;
  color: rgba(255, 255, 255, 0.55);
}
.seo-popup__field input,
.seo-popup__field select {
  width: 100%;
  height: 32px;
  padding: 12px 0 4px;
  font: inherit;
  font-size: 13px;
  color: #fff;
  background: transparent;
  border: 0;
  border-radius: 0;
  outline: none;
}
.seo-popup__field select {
  appearance: none;
  -webkit-appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, rgba(255,255,255,0.55) 50%),
    linear-gradient(135deg, rgba(255,255,255,0.55) 50%, transparent 50%);
  background-position:
    calc(100% - 10px) 60%,
    calc(100% - 5px) 60%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 22px;
}
.seo-popup__field select option {
  background: #000;
  color: #fff;
}

.seo-popup__submit {
  margin-top: 12px;
  height: 40px;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: #fff;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  transition: background var(--dur-fast) ease, border-color var(--dur-fast) ease, color var(--dur-fast) ease;
}
.seo-popup__submit:hover {
  background: #fff;
  color: #000;
  border-color: #fff;
}
.seo-popup__submit .arr {
  display: inline-block;
  font-size: 14px;
  transition: transform 200ms ease;
}
.seo-popup__submit:hover .arr { transform: translateX(3px); }

.seo-popup__sent {
  margin-top: auto;
  padding: 18px;
  background: #000;
  border: 1px solid #fff;
  border-radius: 0;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 13px;
  line-height: 1.45;
  color: #fff;
}
.seo-popup__sent strong { display: block; margin-bottom: 3px; }
.seo-popup__sent span { color: #fff; opacity: 0.65; font-size: 12.5px; }
.seo-popup__sent-mark {
  width: 22px; height: 22px;
  flex: 0 0 22px;
  display: grid; place-items: center;
  background: #fff;
  color: #000;
  font-weight: 600;
  font-size: 13px;
}

@media (max-width: 520px) {
  .seo-popup {
    left: 12px;
    right: 12px;
    bottom: 12px;
    width: auto;
    height: auto;
    aspect-ratio: 1 / 1;
    max-height: calc(100vh - 24px);
    padding: 22px;
  }
  .seo-popup__title { font-size: 32px; }
}

@media (prefers-reduced-motion: reduce) {
  .seo-popup { animation: none; }
}

/* ============================================================
   DotDonut — background dot-torus canvas. Mounted into
   `.intro-cover-jack__stage` at runtime by the DotDonut effect.
   z-index: 4 sits ABOVE the circle inversion overlay (z=3) so
   the difference blend doesn't flip blue dots to orange. The
   `.intro-cover-jack__hi` headline gets bumped to z=5 below so
   text still paints on top of the dots.
   ============================================================ */
.dot-donut {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 4;
}
@media (prefers-reduced-motion: reduce) {
  .dot-donut { display: none; }
}

/* ============================================================
   Manifesto — first "normal website" section after the
   IntroCoverJack. Stripped down to a single editorial declaration:
   one centered serif statement ("I build: …") and a quiet footer
   row. No cards, no eyebrow, no lede paragraph — the page below
   the fold is a deliberate moment of restraint after the
   scrolljack's motion.

   Layout:
     [statement]  one big centered serif sentence
     [foot]       email + back-to-top, two columns

   Section is sized to fill the viewport so the statement lands as
   its own page — visitors scroll out of the scrolljack into a
   clean stage, read one line, then choose where to go next.
   ============================================================ */
.manifesto {
  position: relative;
  /* Match the IntroCoverJack wrapper's bg (#000) instead of
     --bg, so the section-top boundary doesn't read as a color
     step. The shader paints over this background fully where
     it's drawing, but in the bleed area above the section and
     anywhere the canvas might fail, the surrounding color is
     identical above and below the boundary line. */
  background: #000;
  color: var(--ink);
  /* Top/bottom padding sets the section's breathing room from
     the scrolljack above and the page edge below. Compressed
     from the original full-viewport setup so the section feels
     focused rather than airy. */
  padding: clamp(72px, 11vh, 130px) var(--gutter) clamp(48px, 7vh, 90px);
  display: flex;
  flex-direction: column;
  /* Subtle top rule so the eye registers the scrolljack ending and
     the manifesto beginning as two distinct stages. */
  border-top: 1px solid var(--rule-2);
  /* Lift above the dot canvas (z 1) and below the nav (z 220). */
  z-index: 6;
}
/* Lifted above the WebGL shader canvas (z:0). `.manifesto` is
   already position:relative, so this creates a clean two-layer
   stack: shader behind, content in front. */
.manifesto__inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  display: grid;
  /* Tight gap between editorial copy, tile grids, and the footer
     — compresses what used to be very generous breathing room so
     the section reads as a single dense moment, not five separated
     beats. */
  gap: clamp(28px, 4.2vh, 60px);
}

/* ── Editorial copy trio — "I build:" + aside + tagline ─────
   All three plain-text moments in the section share the same
   typographic system: italic serif, centered, big and confident.
   Italicizing the editorial lines distinguishes them from the
   non-italic serif inside the tiles, so visitors read the two
   voices (statements vs. offerings) without effort. */
/* Editorial trio — wrapped in 1:1 Apple Liquid-Glass capsules.
   Anatomy (built per the iOS 26 dock/control-panel reference):
     1. Outer:  large soft drop shadow lifting the capsule
                off the section.
     2. Body:   heavy border-radius (~0.55em — pill-ish for
                the short "I build:", roomy-rounded-rect for
                the longer lines), near-clear fill.
     3. Backdrop: ::before pseudo carries a strong blur +
                saturate + brightness AND the SVG displacement
                filter, so the columns behind the chip get
                bent like light through a lens, not just
                smeared like frosted plastic.
     4. Bevel:  inset shadow stack on the parent — bright
                hairline at the TOP edge (light catching the
                upper rim), darker hairline at the BOTTOM
                (the underside in shadow), thin white rim
                around the entire perimeter, and a soft
                interior glow that gives the capsule body.
   The text content sits on top of the pseudo because the
   parent uses `isolation: isolate` and the pseudo is set to
   `z-index: -1`. */
.manifesto__statement {
  /* Layout — shrink to text, then center as a block. */
  width: fit-content;
  max-width: min(36ch, 100%);
  margin: 0 auto;
  /* Type — unchanged from the editorial-trio system. */
  font-family: var(--serif);
  font-weight: 400;
  font-style: italic;
  font-size: clamp(40px, 4.6vw, 80px);
  line-height: 1.08;
  letter-spacing: -0.022em;
  /* Frosted-glass text — the letters read as a sandblasted /
     etched-frosted region of the same material as the pill,
     not as ink painted on top. Real frosted glass scatters
     light: the surface looks softly luminous and the edges of
     the etched region glow faintly because light leaks out
     through the diffuse material.

     We rebuild that on the web with:
       • A semi-opaque white BODY (translucent white, like
         milky glass — never fully solid because the shader
         columns should still show through faintly).
       • A stacked white text-shadow halo from tight (a hair
         past the letter edge) to wide (~0.14em). Each ring is
         dimmer than the last so the overall feel is "light
         scattering out", not "drop shadow".
       • A very subtle dark grounding shadow so the letters
         stay legible when the lens-brightened pill body
         washes them out from below.

     The previous attempt was `background-clip: text` with a
     linear-gradient inside each letter. That approach was
     interacting badly with the lens behind: the gradient
     sampling shifted as the SDF displaced the backdrop, which
     is what was producing the visible warp on the bottom row
     of letters in the user-reported screenshot. Killing the
     gradient + clip makes the text rendering deterministic. */
  color: rgba(255, 255, 255, 0.84);
  text-shadow:
    0 0 0.025em rgba(255, 255, 255, 0.55),
    0 0 0.060em rgba(255, 255, 255, 0.28),
    0 0 0.140em rgba(255, 255, 255, 0.12),
    0 0.012em 0.020em rgba(0, 0, 0, 0.30);
  text-align: center;
  text-wrap: balance;
  /* Capsule geometry. Padding is em-based so the chip scales
     proportionally with type; the larger right/left padding
     leaves visual room for the specular rim. */
  position: relative;
  isolation: isolate;
  /* Roomier vertical padding — the previous 0.28em/0.18em
     made the pill so short relative to its width that the
     stadium curve at the ends barely registered. Bumping
     top to 0.52em and bottom to 0.42em gives the pill enough
     vertical presence that the curved caps read clearly as
     pill ends, not as the rounded corners of a generic
     rectangle. Sides bumped too so the text doesn't crowd
     into the caps. */
  padding: 0.52em 0.85em 0.42em;
  /* Full pill — Apple's Liquid Glass capsules (Dynamic Island,
     iOS 26 Control Center stacked controls) are stadium-shape
     at any aspect: border-radius collapses to half the minor
     dimension. 9999px is the "as round as possible" idiom; the
     browser clamps it to min(w,h)/2 automatically. */
  border-radius: 9999px;
  /* Apple-style anatomy — asymmetric rim (bright top-left,
     dim bottom-right) suggests a directional light source
     and reads as actual curvature instead of a generic
     border. Two-tier drop shadow (tight contact + wide
     ambient) gives the pill weight without flattening. */
  /* Shu Ding's exact box-shadow recipe — outer drop for depth +
     a single dark inset shadow at the top edge. That's it. The
     previous version was stacking 9 shadow layers (multi-rim,
     contact, ambient, halo) on top of his minimal filter, which
     was the "crap" diluting the clean look the SDF lens delivers
     on its own. */
  box-shadow:
    0 4px 8px rgba(0, 0, 0, 0.25),
    0 -10px 25px -2px rgba(0, 0, 0, 0.15) inset;
}
/* The lens layer — actual refraction of the backdrop via SVG
   displacement map. The procedural map (built per-pill in JS;
   see LiquidGlassPills in extras.jsx) encodes a convex height
   field so the displacement is near-zero in the center and
   ramps to maximum at the perimeter — light bends most at the
   edges of a real lens. The `--lens` custom property is set
   inline by JS to `url(#liquid-pill-N)`, so each pill gets a
   filter sized to its own bounding box.

   Fallback: when `backdrop-filter: url()` isn't supported
   (Safari, Firefox), the url() segment is ignored and the rest
   of the backdrop-filter stack still applies — you get a clean
   frosted-glass look instead of the lens. */
.manifesto__statement::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  /* CRITICAL — without this the pseudo is a RECTANGLE inset:0
     into the parent, and even though the parent element is
     pill-shaped, the rectangular lens region behind shows as
     a square outline. `inherit` picks up the parent's 9999px
     so the backdrop-filter region is clipped to the same
     stadium pill shape. The box tiles' ::before has had this
     line since they were first wired; the trio's ::before
     was missing it, which is why all three editorial pills
     were reading as squares despite the parent's pill radius. */
  border-radius: inherit;
  /* Shu Ding's exact filter chain — `url(#lens)` for the SDF
     displacement + 0.25px blur (basically AA) + small contrast
     boost + gentle brightness + saturate. No body tint, no
     pre-blur stack, no rim, no specular. The lens carries it. */
  -webkit-backdrop-filter: blur(8px) contrast(1.15) brightness(1.05) saturate(1.15);
          backdrop-filter: var(--lens, none) blur(0.25px) contrast(1.20) brightness(1.05) saturate(1.10);
}
/* Inverse-luminance text — used ONLY on the aside text per
   the brief ("the font for But there's more... needs to invert
   to dark when the background is light and vice versa").

   Apply to a plain inline <span> (NOT inline-block, which the
   previous version used — that created its own box and caused
   the lens area around the text to render slightly differently
   in some browsers). With plain inline + mix-blend-mode the
   blending operates only on the glyph pixels themselves.

   Math: `mix-blend-mode: difference` with white → per-channel
   |1 - backdrop| = 1 - backdrop. So bright spots in the
   shader caustics behind → dark text on that letter; dark
   spots → bright text. Auto-balancing as the lens distorts. */
.manifesto__inv-text {
  color: #ffffff;
  text-shadow: none;
  mix-blend-mode: difference;
}

/* No ::after — Shu Ding's demo has none. The previous iteration
   stacked a radial specular peak + diagonal rake + wet-line
   box-shadow on top, all of which read as generic
   "glassmorphism polish" against the clean SDF lens. */
/* "I build:" — NOT a pill. The user wants this heading to read
   as a clean serif statement, not as another capsule. Strip
   all the pill chrome (padding, border-radius, box-shadow,
   isolation) and disable the ::before lens layer. Keeps the
   frosted text treatment inherited from the shared rule. */
.manifesto__statement {
  max-width: none;
  line-height: 1;
  padding: 0;
  border-radius: 0;
  box-shadow: none;
  isolation: auto;
}
.manifesto__statement::before {
  content: none;
}
/* ── Manifesto tagline — single-line wide pill ───────────────────
   FROM-THE-GROUND-UP rebuild (same pattern as .manifesto__aside).
   Mirrors .manifesto__box VERBATIM for everything that defines
   the pill chrome and refraction layer, with tagline-only
   adjustments (single-line italic editorial type) layered on top.
   This guarantees the tagline refracts identically to the boxes —
   the previous trio-shared rule used the wrong backdrop-filter
   chain (blur 8 / brightness 1.05 / saturate 1.10) instead of the
   box chain (blur 14 / brightness 1.02 / saturate 1.20). */
.manifesto__tagline {
  /* --- Box container recipe (verbatim from .manifesto__box) --- */
  position: relative;
  isolation: isolate;
  min-height: clamp(80px, 10vh, 120px);
  padding: clamp(14px, 1.6vw, 28px) clamp(28px, 3.0vw, 56px);
  border-radius: 9999px;
  border: none;
  box-shadow:
    0 4px 8px rgba(0, 0, 0, 0.25),
    0 -10px 25px -2px rgba(0, 0, 0, 0.15) inset;
  background-color: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* --- Tagline-only: standalone single-line italic editorial type. */
  width: fit-content;
  max-width: 100%;
  margin: 0 auto;
  font-family: var(--serif);
  font-weight: 400;
  font-style: italic;
  font-size: clamp(20px, 2.8vw, 52px);
  line-height: 1.1;
  letter-spacing: -0.022em;
  white-space: nowrap;
  color: #ffffff;
  text-shadow: none;
}
/* ── Manifesto aside — single-line wide pill ─────────────────────
   FROM-THE-GROUND-UP rebuild. The previous version inherited
   from the editorial trio rule it shared with .manifesto__statement
   and .manifesto__tagline. That rule used a different backdrop-filter
   chain (blur 8px / brightness 1.05 / saturate 1.10) than the
   .manifesto__box rows surrounding the aside (blur 14px / brightness
   1.02 / saturate 1.20). Patching that with overrides kept leaving
   the aside refracting differently than the boxes.
   This rule now mirrors .manifesto__box VERBATIM for everything
   that defines the pill chrome and refraction layer (position,
   isolation, padding-style, border-radius, box-shadow, body tint,
   backdrop-filter). Aside-only adjustments (single-line, wider,
   italic editorial type) are layered AFTER the box clone so the
   refraction is guaranteed identical. */
.manifesto__aside {
  /* --- Box container recipe (verbatim from .manifesto__box) --- */
  position: relative;
  isolation: isolate;
  min-height: clamp(80px, 10vh, 120px);
  padding: clamp(14px, 1.6vw, 28px) clamp(28px, 3.0vw, 56px);
  border-radius: 9999px;
  border: none;
  box-shadow:
    0 4px 8px rgba(0, 0, 0, 0.25),
    0 -10px 25px -2px rgba(0, 0, 0, 0.15) inset;
  background-color: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* --- Aside-only: standalone (not in a grid), single-line italic
     editorial type at the trio scale. */
  width: fit-content;
  max-width: 100%;
  margin: 0 auto;
  font-family: var(--serif);
  font-weight: 400;
  font-style: italic;
  font-size: clamp(20px, 2.8vw, 52px);
  line-height: 1.1;
  letter-spacing: -0.022em;
  white-space: nowrap;
  color: #ffffff;
  text-shadow: none;
}
/* On narrow viewports the one-line constraint stops being
   reasonable — let the pill wrap rather than overflow the screen. */
@media (max-width: 720px) {
  .manifesto__aside { white-space: normal; }
}
/* Refraction layer — EXACT clone of .manifesto__box::before. Same
   SDF lens, same blur, same contrast, same brightness, same saturate,
   same body tint, same z-index. The two pseudos render with
   identical rules; only the per-pill lens ID differs (set inline
   by LiquidGlassPills so each filter matches its own dimensions). */
.manifesto__aside::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background-color: rgba(6, 10, 20, 0.62);
  -webkit-backdrop-filter: blur(14px) contrast(1.15) brightness(1.02) saturate(1.20);
          backdrop-filter: var(--lens, none) blur(0.25px) contrast(1.20) brightness(1.02) saturate(1.15);
  transition: background-color var(--dur-base) var(--ease-out-expo);
}
/* Refraction layer — EXACT clone of .manifesto__box::before. Same
   SDF lens, blur, contrast, brightness, saturate, body tint, and
   z-index as the box pills (and the aside above), so the tagline
   refracts identically to the rest of the manifesto stack. */
.manifesto__tagline::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background-color: rgba(6, 10, 20, 0.62);
  -webkit-backdrop-filter: blur(14px) contrast(1.15) brightness(1.02) saturate(1.20);
          backdrop-filter: var(--lens, none) blur(0.25px) contrast(1.20) brightness(1.02) saturate(1.15);
  transition: background-color var(--dur-base) var(--ease-out-expo);
}
/* On very narrow viewports the one-line constraint stops being
   reasonable — let the chip wrap instead of overflowing the
   screen edge. */
@media (max-width: 520px) {
  .manifesto__tagline {
    white-space: normal;
  }
}

/* ── Rectangle-tile grids ────────────────────────────────── */
/* Both grids share the same tile language; the .--two modifier
   doesn't change layout (it's already 2 columns), it just labels
   the smaller back-of-house pair for readability in the markup. */
.manifesto__boxes {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(14px, 1.4vw, 22px);
  max-width: 1180px;
  width: 100%;
}
.manifesto__box {
  position: relative;
  isolation: isolate;
  /* Shorter min-height + tighter vertical padding pushes the
     box aspect from ~3.5:1 (which read as squarish despite the
     pill radius) toward ~5:1 — wide and short, the way a real
     pill capsule looks. Combined with the smaller font-size
     below, the curved caps at the ends become the dominant
     silhouette instead of a side-detail. */
  min-height: clamp(80px, 10vh, 120px);
  padding: clamp(14px, 1.6vw, 28px) clamp(28px, 3.0vw, 56px);
  /* Fluid pill — matches the editorial trio. Browser clamps
     9999px to min(width, height)/2, so each tile becomes a
     stadium pill at its own dimensions. With min-height
     ~150px and typical column width ~590px, that's roughly
     a 75px radius — a clearly pill-shaped capsule, not the
     squircle the earlier version shipped. */
  border-radius: 9999px;
  border: none;
  /* Shu Ding's exact recipe — outer drop + single dark inset
     at the top edge. Same shadow language as the editorial
     trio so the tiles read as the same material at a larger
     scale. The previous 9-layer Apple bevel stack was the
     same "fake glass polish" pattern the trio stripped out. */
  box-shadow:
    0 4px 8px rgba(0, 0, 0, 0.25),
    0 -10px 25px -2px rgba(0, 0, 0, 0.15) inset;
  /* Keep the original border-fill hover animation. The four
     background-image lines paint on top of the body fill and
     grow on hover. Background-color goes to fully transparent
     so the refraction pseudo (below) does ALL the surface
     painting. */
  background-color: transparent;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.55)),
    linear-gradient(rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.55)),
    linear-gradient(rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.55)),
    linear-gradient(rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.55));
  background-position: top left, top right, bottom right, bottom left;
  background-size: 0% 1px, 1px 0%, 0% 1px, 1px 0%;
  background-repeat: no-repeat;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  transition:
    background-size 0.75s var(--ease-out-expo);
}
/* Same SDF-lens chain as the editorial trio, plus the box's
   own dark fill so the tile maintains its near-black darkness
   over the refracted shader. The translucent-blue-black tint
   (rgba 6,10,20,0.52) sits ON TOP of the lensed backdrop —
   the lens bends what's behind, then the dark fill mutes it
   ~48%, then the frosted text floats on top with high contrast. */
.manifesto__box::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background-color: rgba(6, 10, 20, 0.62);
  -webkit-backdrop-filter: blur(14px) contrast(1.15) brightness(1.02) saturate(1.20);
          backdrop-filter: var(--lens, none) blur(0.25px) contrast(1.20) brightness(1.02) saturate(1.15);
  transition: background-color var(--dur-base) var(--ease-out-expo);
}
.manifesto__box:hover::before {
  /* Slight lift on hover so the tile reads as illuminated */
  background-color: rgba(14, 22, 40, 0.58);
}
.manifesto__box:hover {
  /* Border fill resolves on hover — top + bottom lines grow
     full width, left + right lines grow full height. */
  background-size: 100% 1px, 1px 100%, 100% 1px, 1px 100%;
}
/* Stretched link — makes the whole pill navigate to its service page
   without disturbing the lens (::before, z-index -1) or the centered
   text. Transparent overlay above the text; pill :hover still fires
   because the link is a child of the box. */
.manifesto__box-link {
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  /* a11y: a focus ring when tabbed to, since there's no visible text */
}
.manifesto__box-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
.manifesto__box-text {
  /* Scaled back from clamp(34px, 4vw, 72px) to fit the
     shorter pill-aspect tiles. The previous size demanded a
     200px-tall tile to read comfortably; with the new
     ~100px min-height each phrase needs to fit on one line at
     smaller scale. */
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(20px, 2.2vw, 38px);
  line-height: 1.04;
  letter-spacing: -0.022em;
  text-wrap: balance;
  /* Same frosted-glass treatment as the editorial trio — milky
     translucent white body + stacked soft white halo (light
     scattering OUT of the sandblasted region) + subtle dark
     grounding shadow so letters stay legible against the dark
     tinted tile body. Em-based offsets keep the halo
     proportional across the box-text size range. */
  color: rgba(255, 255, 255, 0.86);
  text-shadow:
    0 0 0.025em rgba(255, 255, 255, 0.55),
    0 0 0.060em rgba(255, 255, 255, 0.28),
    0 0 0.140em rgba(255, 255, 255, 0.12),
    0 0.012em 0.020em rgba(0, 0, 0, 0.35);
}
/* Aside + tagline share their full type system with .manifesto__statement
   above — see the editorial-copy-trio rule. No size or color
   overrides here; the three plain-text beats are now intentionally
   identical so the section reads as one editorial voice. */

/* ── Foot ─────────────────────────────────────────────────── */
.manifesto__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: clamp(40px, 6vh, 72px);
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.manifesto__mail,
.manifesto__top {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--ink);
  transition: color var(--dur-base) var(--ease-out-expo);
}
.manifesto__mail { font-size: clamp(14px, 1.1vw, 18px); letter-spacing: 0.04em; text-transform: none; }
.manifesto__mail:hover,
.manifesto__top:hover { color: var(--accent); }
.manifesto__mail span[aria-hidden],
.manifesto__top span[aria-hidden] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px; height: 22px;
  border-radius: 5px;
  background: color-mix(in oklch, var(--accent) 16%, transparent);
  color: var(--accent);
  font-size: 11px; letter-spacing: 0;
  transition: background var(--dur-base) var(--ease-out-expo),
              transform var(--dur-base) var(--ease-out-expo);
}
.manifesto__mail:hover span[aria-hidden] { transform: translate(1px, -1px); }
.manifesto__top:hover span[aria-hidden] { transform: translateY(-2px); }

/* ── WebGL shader background ─────────────────────────────── */
/* Full-section canvas mounted by ManifestoShaderBG (extras.jsx).
   Sits at z:0 inside .manifesto (z:6), with .manifesto__inner
   lifted to z:1 above it. pointer-events:none so the shader
   never intercepts clicks on the tiles or the foot links.

   The canvas extends UPWARD past the manifesto by 80vh into the
   post-sticky strip of the IntroCoverJack — the wrapper above
   has no z-index, so the higher-z .manifesto (and its child
   canvas) paints on top of it. A linear-gradient mask fades the
   top portion to transparent, so as the visitor scrolls out of
   the sprout/copy stage the glass effect appears to quietly
   rise up to meet the manifesto instead of slamming on at the
   section boundary.

   Tuning knobs:
     • top / height: how far the bleed extends upward
     • mask stops:   how the fade is shaped — the 25%/55% pair
                     gives a calm S-curve (transparent for the
                     top quarter, then a smooth ramp). Push 55%
                     higher for a longer fade, lower for a
                     snappier reveal.                              */
.manifesto__shader-bg {
  position: absolute;
  left: 0;
  right: 0;
  top: -100vh;
  bottom: 0;
  width: 100%;
  height: calc(100% + 100vh);
  display: block;
  z-index: 0;
  pointer-events: none;
  /* Full opacity — the shader paints its own dark base color
     that matches the surrounding #000, so we don't need the
     0.92 transparency to "soften" it. Going fully opaque means
     no pass-through, which means zero chance of a color step
     at the section boundary. */
  opacity: 1.0;
  /* 10-stop cubic-ease curve approximating cubic-bezier(0.65, 0,
     0.35, 1). Spread across the entire 100vh+ canvas so there
     is no point in the curve steeper than ~3% alpha per 10%
     of canvas height — the eye reads the transition as a soft
     atmospheric appearance, not a fade-in animation. */
  -webkit-mask-image: linear-gradient(
    to bottom,
    rgba(0,0,0,0.000)   0%,
    rgba(0,0,0,0.005)  10%,
    rgba(0,0,0,0.020)  20%,
    rgba(0,0,0,0.060)  30%,
    rgba(0,0,0,0.150)  40%,
    rgba(0,0,0,0.320)  50%,
    rgba(0,0,0,0.560)  60%,
    rgba(0,0,0,0.800)  70%,
    rgba(0,0,0,0.950)  80%,
    rgba(0,0,0,1.000)  92%
  );
          mask-image: linear-gradient(
    to bottom,
    rgba(0,0,0,0.000)   0%,
    rgba(0,0,0,0.005)  10%,
    rgba(0,0,0,0.020)  20%,
    rgba(0,0,0,0.060)  30%,
    rgba(0,0,0,0.150)  40%,
    rgba(0,0,0,0.320)  50%,
    rgba(0,0,0,0.560)  60%,
    rgba(0,0,0,0.800)  70%,
    rgba(0,0,0,0.950)  80%,
    rgba(0,0,0,1.000)  92%
  );
}
/* Hide the manifesto's top hairline once the shader is bleeding
   over it — leaving the line in place reads as a visible seam
   right where we're trying to sell continuity. */
.manifesto { border-top-color: transparent; }


/* ── Responsive ──────────────────────────────────────────── */
@media (max-width: 720px) {
  /* Tighten section padding so the editorial copy doesn't sit
     miles from the section edges on a phone. Shader bleed +
     mask + backdrop-filter refraction all remain on the box
     pills — same recipe as desktop. */
  .manifesto { padding-top: clamp(56px, 9vh, 96px); padding-bottom: clamp(40px, 6vh, 72px); }

  /* Boxes (offerings) keep the pill chrome; just relax the
     min-height + shrink type so they fit narrow viewports. */
  .manifesto__box {
    min-height: 0;
    padding: 14px 22px;
  }
  .manifesto__box-text { font-size: clamp(16px, 4.6vw, 24px); }

  /* "I build:" — phone-scaled. (Centered already from the base
     rule.) */
  .manifesto__statement {
    font-size: clamp(34px, 9vw, 56px);
  }

  /* Aside + tagline ("But there's more…" / "If you do it on a
     computer…") on phones: KEEP the box-pill glass, but fully
     CLEAR. An earlier draft made these solid white with dark
     text — the user wants the opposite: the same translucent
     refraction as the surrounding box pills, just with the dark
     rgba(6,10,20,.62) body tint removed, so they read as clear
     frosted glass (not dark-tinted, and certainly not white).
     Light text floats over the clear glass. */
  .manifesto__aside,
  .manifesto__tagline {
    min-height: 0;
    padding: 14px 22px;
    font-size: clamp(18px, 5vw, 26px);
    white-space: normal;
    /* Grey panel on mobile (per request): light-grey editorial text on
       an elevated grey pill instead of clear glass. */
    color: var(--ink-2);
    border: 1px solid var(--rule);
  }
  /* Re-enable the refraction pseudo (the base mobile draft set
     content:none) and zero ONLY its body tint. Position, inset,
     border-radius, and the blur/lens chain still come from the
     base .manifesto__{aside,tagline}::before rules, so these
     refract exactly like the box pills — minus the dark fill. */
  .manifesto__aside::before,
  .manifesto__tagline::before {
    content: '';
    /* Grey background fill on mobile (per request): solid --bg-4
       surface. The base blur/lens chain sits behind this opaque
       fill (hidden), which is the intended "grey chip" look. */
    background-color: var(--bg-4);
  }
}
@media (max-width: 700px) {
  /* Phones — collapse the 2x2 into a single column. The last
     tile's grid-column: 1 / -1 still works since -1 maps to the
     end of whatever the column count is. */
  .manifesto__boxes {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 540px) {
  .manifesto__foot {
    flex-direction: column;
    align-items: flex-start;
    gap: 22px;
  }
}

/* ============================================================
   WorkWithMe — final black section with email capture. Sits
   below the manifesto's shader; same #000 base so the seam
   reads as continuation, then the section breathes with a tall
   pad before delivering one bold headline, one input, one
   tagline.
   ============================================================ */
.work-with-me {
  position: relative;
  background: #000;
  color: var(--ink);
  padding: clamp(120px, 18vh, 220px) var(--gutter) clamp(110px, 16vh, 200px);
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  /* Above the dot canvas (z 1), below the nav (z 220). */
  z-index: 6;
  overflow: hidden;
}
/* Soft radial vignette — pulls focus to the headline + form
   without painting a hard edge against the manifesto seam. */
.work-with-me::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(
    ellipse at 50% 45%,
    rgba(255, 255, 255, 0.04) 0%,
    rgba(255, 255, 255, 0) 55%
  );
  pointer-events: none;
}
.work-with-me__inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
  display: grid;
  gap: clamp(36px, 5.5vh, 72px);
}

/* ── Legal fine print — privacy link + age note shown beneath the
   data-collection forms (Work-with-me + SEO audit popup). Quiet,
   small, token-driven so it never competes with the CTA. */
.legal-fineprint {
  margin: 14px auto 0;
  max-width: 52ch;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--ink-3);
  text-align: center;
}
.legal-fineprint a {
  color: var(--ink-2);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: opacity var(--dur-base) var(--ease-out-expo);
}
.legal-fineprint a:hover { opacity: 0.72; }
.legal-fineprint--popup {
  margin-top: 10px;
  font-size: 11px;
  line-height: 1.45;
  text-align: left;
  max-width: none;
}
.work-with-me__title {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-style: normal;
  font-size: clamp(56px, 8vw, 132px);
  line-height: 0.98;
  letter-spacing: -0.028em;
  color: #fff;
  text-wrap: balance;
}
.work-with-me__title em {
  font-style: italic;
  color: #fff;
}
.work-with-me__subhead {
  margin: 0 auto;
  font-family: var(--serif);
  font-weight: 400;
  font-style: normal;
  font-size: clamp(20px, 2.2vw, 34px);
  line-height: 1.2;
  letter-spacing: -0.012em;
  color: rgba(255, 255, 255, 0.78);
  white-space: nowrap;
}
.work-with-me__subhead em {
  font-style: italic;
  /* Brand-blue gradient painted directly onto the glyphs via
     background-clip: text. Goes from the deeper accent on the
     left to the lighter accent variant on the right so the
     phrase reads like a directional lift — apt for "to the
     next level". Scoped narrowly to this one element only —
     an earlier attempt to expand it across every accent-blue
     italic word kept clipping italic descenders and never
     fully matched the look of this one. All other blue italic
     words use their original `color: var(--accent)` rules. */
  background-image: linear-gradient(
    90deg,
    var(--accent) 0%,
    var(--accent-2) 55%,
    #ffffff 100%
  );
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
          color: transparent;
}
@media (max-width: 620px) {
  .work-with-me__subhead { white-space: normal; text-wrap: balance; }
}
.work-with-me__form {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 12px;
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
}
.work-with-me__field {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
}
.work-with-me__label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.work-with-me__field input {
  width: 100%;
  padding: 16px 20px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 0;
  color: #fff;
  font-family: var(--mono);
  font-size: 14px;
  letter-spacing: 0.02em;
  -webkit-backdrop-filter: blur(22px) saturate(180%) brightness(1.06) contrast(1.04);
          backdrop-filter: blur(22px) saturate(180%) brightness(1.06) contrast(1.04);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    inset 0 -1px 0 rgba(255, 255, 255, 0.08),
    inset 1px 0 0 rgba(255, 255, 255, 0.14),
    inset -1px 0 0 rgba(255, 255, 255, 0.14),
    0 16px 40px -10px rgba(0, 0, 0, 0.55);
  transition: border-color var(--dur-base) ease, background var(--dur-base) ease, box-shadow var(--dur-base) ease;
  outline: none;
}
.work-with-me__field input::placeholder {
  color: rgba(255, 255, 255, 0.42);
}
.work-with-me__field input:focus {
  border-color: var(--accent);
  background: rgba(255, 255, 255, 0.06);
  box-shadow: 0 0 0 4px color-mix(in oklch, var(--accent) 20%, transparent);
}
.work-with-me__submit {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 16px 26px;
  background: var(--accent);
  color: #000;
  border: 1px solid var(--accent);
  border-radius: 0;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: transform var(--dur-press) var(--ease-press), background var(--dur-base) ease, box-shadow var(--dur-base) ease;
  white-space: nowrap;
}
.work-with-me__submit:hover {
  transform: translateY(-1px);
  box-shadow: 0 12px 32px -10px color-mix(in oklch, var(--accent) 50%, transparent);
}
/* Tactile press — scale down on press, spring-overshoot back on
   release (var(--ease-press)). Reads as physical "give." */
.work-with-me__submit:active { transform: scale(0.97); }
/* Success — flip to a confirmation green with a drawn checkmark, the
   "peak-end" beat: the last thing the visitor remembers. */
.work-with-me__submit.is-success {
  background: var(--good);
  border-color: var(--good);
  color: #04130c;
  cursor: default;
}
.work-with-me__check {
  display: inline-flex;
}
.work-with-me__check svg path {
  stroke-dasharray: 30;
  stroke-dashoffset: 30;
  animation: wwm-check-draw 0.5s var(--ease-out-expo) 0.06s forwards;
}
@keyframes wwm-check-draw { to { stroke-dashoffset: 0; } }
.work-with-me__msg--ok {
  animation: wwm-msg-in 0.5s var(--ease-out-expo) both;
}
@keyframes wwm-msg-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .work-with-me__check svg path { animation: none; stroke-dashoffset: 0; }
  .work-with-me__msg--ok { animation: none; }
}
.work-with-me__submit:disabled {
  opacity: 0.55;
  cursor: default;
  transform: none;
  box-shadow: none;
}
.work-with-me__submit span[aria-hidden] {
  display: inline-block;
  transition: transform var(--dur-base) ease;
}
.work-with-me__submit:hover span[aria-hidden] { transform: translateX(2px); }
.work-with-me__msg {
  margin: -20px 0 0;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.work-with-me__msg--ok  { color: var(--accent); }
.work-with-me__msg--err { color: #ff6b6b; }
.work-with-me__tagline {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-style: normal;
  font-size: clamp(22px, 2.4vw, 36px);
  line-height: 1.2;
  letter-spacing: -0.012em;
  color: rgba(255, 255, 255, 0.78);
  text-wrap: balance;
}
.work-with-me__tagline em {
  font-style: italic;
  color: #fff;
}

@media (max-width: 620px) {
  .work-with-me__form { flex-direction: column; }
  .work-with-me__submit { width: 100%; justify-content: center; }
}

@media (max-width: 720px) {
  /* Full-viewport conversion moment — fills the screen with
     vertical centering so the visitor lands on title + form
     with no other content competing for attention. dvh handles
     the iOS URL-bar collapse so the section never falls short. */
  .work-with-me {
    min-height: 100dvh;
    padding-top: clamp(56px, 10vh, 96px);
    padding-bottom: clamp(56px, 10vh, 96px);
  }
  .work-with-me__inner { gap: clamp(24px, 4vh, 40px); }
  .work-with-me__title { font-size: clamp(48px, 14vw, 80px); }
  .work-with-me__subhead { font-size: clamp(16px, 4.6vw, 22px); }
  .work-with-me__tagline { font-size: clamp(18px, 4.8vw, 24px); }
  /* Bigger tap target for the email field — 16px font keeps iOS
     Safari from auto-zooming when the input gets focus. */
  .work-with-me__field input { font-size: 16px; padding: 16px 18px; }
  .work-with-me__submit { padding: 18px 22px; }
}
