/* ============================================================
   ByrnSites — design tokens

   Brand identity (violet on near-black) is unchanged. What is
   tuned here: contrast values that failed WCAG AA, a single
   easing/duration system, and one scale each for radius,
   shadow and spacing so nothing is hand-picked per component.
   ============================================================ */
:root {
  /* --- Surface & text ------------------------------------- */
  --bg: #07060a;
  --bg-raised: #0d0b12;
  --ink: #f3f1f7;          /* 18.0:1 on --bg */
  --ink-dim: #d9d5e2;      /* 14.0:1 */
  --muted: #a49dae;        /* 7.7:1  — body/lede */
  --muted-2: #948da0;      /* 6.3:1  — small labels (was #7d768a, 4.65:1) */
  --faint: #8b8496;        /* 5.6:1  — footer meta (was #5f596b, 3.01:1 — failed AA) */

  /* --- Brand violet --------------------------------------- */
  /* --accent is for TEXT/icons on dark (5.2:1 on --bg).       */
  /* --cta-* are surface fills sized so white text clears AA:  */
  /* white on #9542f5 = 4.8:1, on #6d28d9 = 7.1:1.             */
  --accent: #a259ff;
  --accent-soft: #c6a3ff;  /* 9.7:1 — links, quiet accents */
  --cta-from: #9542f5;
  --cta-to: #6d28d9;
  --violet-deep: #7c3aed;

  /* --- Borders -------------------------------------------- */
  --border: rgba(255, 255, 255, 0.09);
  --border-soft: rgba(255, 255, 255, 0.08);
  --border-hair: rgba(255, 255, 255, 0.06);
  --border-hover: rgba(198, 163, 255, 0.65);
  --border-accent: rgba(162, 89, 255, 0.42);

  /* --- Spacing (8pt rhythm) -------------------------------- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-7: 32px;
  --sp-8: 40px;
  --sp-10: 56px;

  /* --- Radii ---------------------------------------------- */
  --r-xs: 8px;
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 18px;
  --r-xl: 24px;
  --r-2xl: 28px;
  --r-pill: 999px;

  /* --- Elevation ------------------------------------------ */
  --shadow-sm: 0 2px 8px -2px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 18px 40px -24px rgba(0, 0, 0, 0.8);
  --shadow-lg: 0 40px 80px -40px rgba(0, 0, 0, 0.85);
  --glow-sm: 0 10px 30px -14px rgba(149, 66, 245, 0.75);
  --glow-md: 0 18px 44px -18px rgba(149, 66, 245, 0.8);
  --glow-lg: 0 30px 70px -26px rgba(149, 66, 245, 0.9);

  /* --- Motion ---------------------------------------------- */
  /* Two canonical curves. ease-in is never used on UI: it      */
  /* delays the exact moment the user is watching.              */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --dur-press: 140ms;   /* press feedback   */
  --dur-fast: 180ms;    /* hover, colour    */
  --dur-med: 260ms;     /* disclosure, lift */
  --dur-reveal: 600ms;  /* scroll reveal (marketing, allowed > 300ms) */

  /* --- Type scale ------------------------------------------ */
  --fs-hero: clamp(2.75rem, 1.55rem + 5.6vw, 6.75rem);      /* 44 → 108 */
  --fs-h2: clamp(2.125rem, 1.55rem + 2.7vw, 4.5rem);        /* 34 → 72  */
  --fs-h2-sm: clamp(2rem, 1.55rem + 2vw, 3.75rem);          /* 32 → 60  */
  --fs-h3: clamp(1.25rem, 1.15rem + 0.4vw, 1.4375rem);      /* 20 → 23  */
  --fs-lede: clamp(1.0625rem, 0.95rem + 0.55vw, 1.375rem);  /* 17 → 22  */
  --fs-body: 1rem;
  --fs-sm: 0.9375rem;                                       /* 15 */
  --fs-price: clamp(2.75rem, 2.1rem + 3vw, 4.25rem);        /* 44 → 68  */
  --fs-mono: 0.6875rem;                                     /* 11 */

  --lh-hero: 1.02;
  --lh-h2: 1.06;
  --lh-body: 1.6;

  --header-h: 68px;

}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--sp-5));
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: "DM Sans", system-ui, -apple-system, sans-serif;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; height: auto; }

a { color: var(--accent-soft); text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  a:hover { color: #fff; }
}

::selection { background: var(--violet-deep); color: #fff; }

:where(a, button, input, textarea, summary):focus-visible {
  outline: 2px solid var(--accent-soft);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}

/* Keyboard-only escape hatch past the fixed header */
.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: var(--sp-4);
  z-index: 100;
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--r-pill);
  background: var(--bg-raised);
  border: 1px solid var(--border-hover);
  color: var(--ink);
  font-size: var(--fs-sm);
  font-weight: 500;
  transform: translateY(-200%);
  transition: transform var(--dur-fast) var(--ease-out);
}
/* :focus, not :focus-visible — this link is only ever reachable by
   keyboard, so any focus at all should reveal it. */
.skip-link:focus { transform: translateY(0); }

/* ============================================================
   Layout primitives
   ============================================================ */
.page { position: relative; width: 100%; overflow: hidden; background: var(--bg); }

.container {
  position: relative;
  z-index: 1;
  max-width: 1280px;
  margin-inline: auto;
  padding-inline: clamp(20px, 5vw, 64px);
}
.container--narrow { max-width: 1000px; }

.section { padding-block: clamp(4rem, 2.6rem + 7vw, 8.25rem); }
.section--tight { padding-block: clamp(3.5rem, 2.4rem + 5.6vw, 7.25rem); }

/* Hairline rules that fade at both ends — cleaner than a hard
   edge-to-edge border, and it lets sections flow into each other. */
.section--divider { position: relative; }
.section--divider::before {
  content: "";
  position: absolute;
  inset-inline: clamp(20px, 5vw, 64px);
  top: 0;
  height: 1px;
  background: linear-gradient(90deg,
    rgba(162, 89, 255, 0) 0%,
    rgba(162, 89, 255, 0.28) 22%,
    rgba(162, 89, 255, 0.28) 78%,
    rgba(162, 89, 255, 0) 100%);
}

/* ============================================================
   Typography components
   ============================================================ */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  margin: 0;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}
.eyebrow--soft { color: var(--accent-soft); }

/* A short accent rule before the label — gives every section a
   consistent, deliberate entry point. */
.eyebrow::before {
  content: "";
  width: 24px;
  height: 1px;
  background: currentColor;
  opacity: 0.55;
}

.heading-hero {
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 600;
  font-size: var(--fs-hero);
  line-height: var(--lh-hero);
  letter-spacing: -0.04em;   /* large type needs negative tracking */
  margin: 0;
  max-width: 17ch;
  text-wrap: balance;
  hyphens: none;
}
.heading-hero em {
  font-style: normal;
  color: var(--accent);
}

.heading-2 {
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.036em;
  margin: var(--sp-5) 0 0;
  max-width: 20ch;
  text-wrap: balance;
}
.heading-2--sm { font-size: var(--fs-h2-sm); max-width: 18ch; }
/* Section headings that lead straight into a grid/list */
.heading-2--lead { margin-bottom: clamp(30px, 5vw, 56px); }

.heading-3 {
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 500;
  font-size: var(--fs-h3);
  line-height: 1.25;
  letter-spacing: -0.015em;
  margin: 0;
}

.lede {
  margin: var(--sp-5) 0 0;
  max-width: 54ch;
  font-size: var(--fs-lede);
  line-height: 1.6;
  color: var(--muted);
}
.lede--narrow { max-width: 44ch; }
.lede--sm { font-size: clamp(0.9375rem, 0.88rem + 0.3vw, 1.125rem); }

/* ============================================================
   Header
   ============================================================ */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: var(--header-h);
  padding: max(12px, env(safe-area-inset-top)) clamp(16px, 4vw, 48px) 12px;
  background: rgba(7, 6, 10, 0.55);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border-bottom: 1px solid transparent;
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
/* Chrome only asserts itself once content is actually behind it */
.site-header.is-stuck {
  background: rgba(7, 6, 10, 0.82);
  border-bottom-color: var(--border-hair);
}

.brand { display: flex; align-items: center; min-height: 44px; }
.brand img { height: 34px; width: auto; display: block; }

.nav { display: flex; align-items: center; gap: clamp(4px, 1.6vw, 18px); }
.nav-link {
  position: relative;
  font-size: var(--fs-sm);
  color: var(--muted);
  padding: 10px var(--sp-2);
  border-radius: var(--r-xs);
  transition: color var(--dur-fast) var(--ease-out);
}
/* Underline grows from the centre rather than a colour-only swap */
.nav-link::after {
  content: "";
  position: absolute;
  left: var(--sp-2); right: var(--sp-2);
  bottom: 4px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transition: transform var(--dur-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .nav-link:hover { color: var(--ink); }
  .nav-link:hover::after { transform: scaleX(1); }
}
@media (max-width: 720px) { .nav-link { display: none; } }

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

   Transform is composed from two independent sources so the
   magnetic pull (JS, --mx/--my) and the press scale (CSS) can
   never overwrite one another.
   ============================================================ */
/* Typed so it can be interpolated. Transitioning the *variable* and
   letting `transform` recompute from it keeps a single writer on
   `transform` itself — transitioning `transform`/`scale` directly
   while JS also writes a var into it leaves the transition wedged
   (observed: a `scale` transition stuck at currentTime 0 forever,
   and a running transition outranks even !important). */
@property --press {
  syntax: "<number>";
  inherits: false;
  initial-value: 1;
}

.btn {
  --mx: 0px;
  --my: 0px;
  --press: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 56px;
  padding: 0 30px;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  font-family: inherit;
  font-size: var(--fs-body);
  font-weight: 500;
  line-height: 1;
  text-align: center;
  cursor: pointer;

  /* One writer per input: JS owns --mx/--my (magnetic, 1:1 with the
     pointer), CSS owns --press. `transform` is composed from both and
     is never written directly by anyone. */
  transform: translate3d(var(--mx), var(--my), 0) scale(var(--press));
  transition: --press var(--dur-press) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
/* Press feedback: the single biggest "this UI is listening" cue */
.btn:active { --press: 0.97; }

.btn--sm { min-height: 44px; padding: 0 20px; font-size: var(--fs-sm); }
.btn--block { width: 100%; }

.btn--primary {
  background: linear-gradient(135deg, var(--cta-from), var(--cta-to));
  color: #fff;
  box-shadow: var(--glow-md);
}
.btn--primary.btn--sm { box-shadow: var(--glow-sm); }
@media (hover: hover) and (pointer: fine) {
  .btn--primary:hover { box-shadow: var(--glow-lg); }
}

.btn--outline {
  border-color: rgba(255, 255, 255, 0.18);
  color: var(--ink);
  background: rgba(255, 255, 255, 0.02);
}
@media (hover: hover) and (pointer: fine) {
  .btn--outline:hover {
    border-color: var(--border-hover);
    background: rgba(255, 255, 255, 0.05);
  }
}

.btn--soft {
  border-color: rgba(198, 163, 255, 0.4);
  background: rgba(162, 89, 255, 0.1);
  color: var(--ink);
}
@media (hover: hover) and (pointer: fine) {
  .btn--soft:hover {
    border-color: rgba(198, 163, 255, 0.8);
    background: rgba(162, 89, 255, 0.16);
  }
}

/* Arrow nudges forward on hover — motion that points at the outcome */
.btn__arrow {
  transition: transform var(--dur-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .btn:hover .btn__arrow { transform: translateX(3px); }
}

/* ============================================================
   Reveal on scroll (CSS owns the motion; JS only adds a class)
   ============================================================ */
.reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-reveal) var(--ease-out),
              transform var(--dur-reveal) var(--ease-out);
}
.reveal.is-visible { opacity: 1; transform: none; }

.word {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.35em);
  transition: opacity 500ms var(--ease-out), transform 560ms var(--ease-out);
}
.word.is-visible { opacity: 1; transform: none; }

/* Reduced motion = gentler, not none. Opacity and colour survive
   (they aid comprehension); every positional change is dropped. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal, .word { opacity: 1 !important; transform: none !important; }
  .btn { transform: none !important; }
  /* Hero content is animated in by GSAP; if motion is off it must be
     visible from the first frame regardless of whether GSAP loaded. */
  [data-hero-el] { opacity: 1 !important; transform: none !important; }
}

/* Reduced transparency: the scrim is doing legibility work, so make it
   near-solid rather than removing it. */
@media (prefers-reduced-transparency: reduce) {
  .hero__scrim { background: rgba(7, 6, 10, 0.9); }
}

/* Higher contrast request: drop the film to a flat backdrop. */
@media (prefers-contrast: more) {
  .hero__scrim { background: rgba(7, 6, 10, 0.94); }
}

/* ============================================================
   Background atmosphere
   ============================================================ */
.bg-fx { position: fixed; inset: 0; pointer-events: none; z-index: 0; overflow: hidden; }
.bg-fx__radial {
  position: absolute; inset: 0;
  background: radial-gradient(120% 60% at 50% -10%, rgba(124, 58, 237, 0.18), rgba(7, 6, 10, 0) 60%);
}
.bg-fx__blob {
  position: absolute;
  border-radius: 50%;
  animation: bsDrift 42s ease-in-out infinite;
}
/* These were `filter: blur(90px)` / `blur(110px)` over a radial
   gradient. Measured: that single declaration cost ~50ms per frame —
   it held the whole page at 15fps while scrolling, because a blurred
   layer is re-rasterised as it drifts. The gradient underneath was
   already doing the visual work; the extra stops below reproduce the
   blur's falloff (and avoid the banding the blur used to mask) for
   free. Removing it took scroll from 15fps to a solid 60. */
.bg-fx__blob--a {
  top: 4vh; left: -12vw; width: 46vw; height: 46vw;
  background: radial-gradient(circle at 40% 40%,
    rgba(162, 89, 255, 0.17) 0%,
    rgba(162, 89, 255, 0.125) 26%,
    rgba(162, 89, 255, 0.06) 48%,
    rgba(162, 89, 255, 0.018) 68%,
    rgba(162, 89, 255, 0) 84%);
}
.bg-fx__blob--b {
  top: 46vh; right: -14vw; width: 52vw; height: 52vw;
  background: radial-gradient(circle at 60% 50%,
    rgba(109, 40, 217, 0.19) 0%,
    rgba(109, 40, 217, 0.14) 26%,
    rgba(109, 40, 217, 0.07) 48%,
    rgba(109, 40, 217, 0.02) 68%,
    rgba(109, 40, 217, 0) 84%);
  animation-duration: 52s;
  animation-direction: reverse;
}
.bg-fx__particles { position: absolute; inset: 0; width: 100%; height: 100%; display: block; opacity: 0.55; }
.bg-fx__grain {
  position: absolute; inset: 0;
  opacity: 0.03;
  mix-blend-mode: overlay;
  background-image:
    repeating-linear-gradient(0deg, rgba(255,255,255,0.9) 0 1px, rgba(255,255,255,0) 1px 3px),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.9) 0 1px, rgba(255,255,255,0) 1px 3px);
}

/* Animates `translate`, not `transform`, so the pointer tilt can own
   `rotate` on a sibling layer without the animation overriding it —
   a running animation wins over inline styles in the cascade. */
@keyframes bsPulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 0.9; } }
@keyframes bsDrift {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  33% { transform: translate3d(3vw, -2.2vh, 0) scale(1.05); }
  66% { transform: translate3d(-2.2vw, 3vh, 0) scale(0.97); }
}
@keyframes bsShimmer { 0% { background-position: 0% 50%; } 100% { background-position: 200% 50%; } }

/* ============================================================
   Hero
   ============================================================ */
/* Full-bleed cinematic hero.
   svh, not vh: on mobile browsers vh is the *largest* viewport, so a
   100vh hero sits partly under the retracting URL bar on first paint.
   The vh line is the fallback for engines without svh. */
.hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  /* Bottom padding is deliberately heavier than the top so the copy
     settles a little ABOVE the geometric centre. A block centred by
     arithmetic reads as sitting low, because the fixed header already
     occupies the top of the frame — this is optical centring, and it
     is also what opens the run of clear film beneath the buttons. */
  padding-block:
    clamp(7rem, 5.4rem + 7vw, 10rem)
    clamp(8rem, 6rem + 6vw, 12rem);
  overflow: hidden;
}
.hero__inner { width: 100%; }

/* Media layer ---------------------------------------------------- */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  background-color: var(--bg);
  /* The poster lives here rather than on the <video poster> attribute so
     it can be art-directed: a 16:9 still stretched over a phone is the
     same blur problem the film itself has, and only CSS can pick a
     different crop per viewport shape. The video paints on top of it. */
  background-image: url("media/hero-poster.jpg");
  background-image: image-set(
    url("media/hero-poster.webp") type("image/webp"),
    url("media/hero-poster.jpg") type("image/jpeg"));
  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50% 42%;
  /* This layer is opaque, so inside the hero it hides the fixed
     background atmosphere that the rest of the page shows — which left
     a visible horizontal seam at the hero's bottom edge. Dissolving the
     whole layer (film + scrim together) lets the page's own backdrop
     come through, so the film ends by becoming the site rather than
     stopping against it. */
  -webkit-mask-image: linear-gradient(to bottom, #000 68%, rgba(0, 0, 0, 0.35) 88%, transparent 99%);
          mask-image: linear-gradient(to bottom, #000 68%, rgba(0, 0, 0, 0.35) 88%, transparent 99%);
}
.hero__video,
.hero__media > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* The landscape cut is a 16:9 plate. Portrait viewports crop it hard,
     so bias the crop upward — the Earth limb and lunar horizon both sit
     above centre, and centre-cropping would push them off the top. */
  object-position: 50% 42%;
  /* Composited on its own layer so the scroll scale never repaints the
     text above it. */
  will-change: transform;
  transform: translateZ(0);
}
/* Held back until the first frame is decodable, then crossed in over the
   poster underneath. The poster is that exact frame, so the handover is
   invisible — this only exists so a not-yet-decoded <video> can never
   paint its own empty box over the poster. */
.hero__video {
  background: transparent;
  opacity: 0;
  transition: opacity 240ms linear;
}
.hero__video.is-ready { opacity: 1; }

/* Phones in portrait get a 9:16 cut of the same film — 608 source pixels
   across the width instead of the ~220 a 16:9 plate has left after
   `cover` crops it, on a screen that is often 3× dense. Squarely
   centred: the vertical bias above only exists to protect a wide crop.
   The condition has to match the one in initHeroVideo() exactly, or the
   poster and the film it hands over to would be different crops. */
@media (max-aspect-ratio: 1 / 1) and (max-width: 767px) {
  .hero__media {
    background-image: url("media/hero-poster-portrait.jpg");
    background-image: image-set(
      url("media/hero-poster-portrait.webp") type("image/webp"),
      url("media/hero-poster-portrait.jpg") type("image/jpeg"));
    background-position: 50% 50%;
  }
  .hero__video,
  .hero__media > img { object-position: 50% 50%; }
}

/* Scrim ----------------------------------------------------------
   Three stacked jobs, cheapest first:
     1. a flat wash that guarantees the contrast floor;
     2. a bottom ramp to solid --bg so the hero dissolves into the page
        instead of ending on a hard edge;
     3. a soft top wash so the fixed header keeps its own contrast.

   Shaped from measurement, not taste: sampling the copy's own bounding
   box across a full loop puts the brightest 1% at the lower right of
   the block — the lit cloud deck and the lunar horizon both land there
   — while the left runs 8:1 with room to spare. So the weight goes
   where the film is bright and nowhere else. */
.hero__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* Alphas multiply, they do not add: three 0.3 layers is 0.66, not
     0.9. Tuned so the composite lands near 74% at the left of the copy
     and around 43% on the right, where nothing needs to stay legible
     and the film should read. */
  background:
    linear-gradient(to bottom,
      rgba(7, 6, 10, 0.58) 0%,
      rgba(7, 6, 10, 0.15) 27%,
      rgba(7, 6, 10, 0.26) 58%,
      rgba(7, 6, 10, 0.40) 72%,
      rgba(7, 6, 10, 0.74) 90%,
      rgba(7, 6, 10, 0.88) 100%),
    linear-gradient(100deg,
      rgba(7, 6, 10, 0.64) 0%,
      rgba(7, 6, 10, 0.30) 50%,
      rgba(7, 6, 10, 0.18) 78%,
      rgba(7, 6, 10, 0.12) 100%),
    rgba(7, 6, 10, 0.18);
}

/* Portrait needs a different shape, not a stronger one. The copy runs
   from edge to edge here, so a left-to-right ramp has nowhere to hide
   the weight — the reading band has to be held vertically instead. */
@media (max-aspect-ratio: 1 / 1) {
  .hero__scrim {
    background:
      linear-gradient(to bottom,
        rgba(7, 6, 10, 0.60) 0%,
        rgba(7, 6, 10, 0.24) 18%,
        rgba(7, 6, 10, 0.36) 42%,
        rgba(7, 6, 10, 0.44) 60%,
        rgba(7, 6, 10, 0.50) 72%,
        rgba(7, 6, 10, 0.74) 90%,
        rgba(7, 6, 10, 0.88) 100%),
      rgba(7, 6, 10, 0.22);
  }
}

.hero__darken {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: var(--bg);
  opacity: 0;
}


.hero-cta-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: clamp(28px, 4vw, 40px); }


/* ============================================================
   Feature cards
   ============================================================ */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: clamp(14px, 2vw, 22px);
  margin-top: clamp(36px, 6vw, 64px);
}
.feature-card {
  padding: clamp(24px, 3vw, 32px);
  border-radius: var(--r-lg);
  background: linear-gradient(170deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.015));
  border: 1px solid var(--border-soft);
  transition: transform var(--dur-med) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-med) var(--ease-out);
}
.feature-card__desc { margin: var(--sp-3) 0 0; color: var(--muted); }
@media (hover: hover) and (pointer: fine) {
  .feature-card:hover {
    transform: translateY(-4px);
    border-color: var(--border-accent);
    box-shadow: 0 24px 48px -30px rgba(124, 58, 237, 0.6);
  }
}

/* ============================================================
   Services list
   ============================================================ */
.service-list { display: flex; flex-direction: column; border-top: 1px solid var(--border); }
.service-row {
  position: relative;
  display: grid;
  gap: var(--sp-3);
  padding: clamp(22px, 3.4vw, 34px) var(--sp-5);
  margin-inline: calc(var(--sp-5) * -1);
  border-bottom: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: background var(--dur-med) var(--ease-out);
}
.service-row__head { display: flex; align-items: baseline; gap: var(--sp-4); flex-wrap: wrap; }
.service-row__tag { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 12px; color: var(--accent); }
.service-row__title {
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 500;
  font-size: clamp(24px, 3.4vw, 38px);
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin: 0;
  transition: transform var(--dur-med) var(--ease-out);
}
.service-row__desc { margin: 0; max-width: 60ch; color: var(--muted); }
@media (hover: hover) and (pointer: fine) {
  .service-row:hover { background: linear-gradient(90deg, rgba(162, 89, 255, 0.07), rgba(162, 89, 255, 0)); }
  /* Move the title, not the row's padding — transform doesn't reflow */
  .service-row:hover .service-row__title { transform: translateX(8px); }
}

/* ============================================================
   Signature / globe
   ============================================================ */
.signature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: clamp(28px, 5vw, 64px);
  align-items: center;
}
.globe-wrap { display: flex; justify-content: center; }
.globe-wrap canvas { width: 100%; max-width: 460px; aspect-ratio: 1; display: block; }

/* ============================================================
   Process steps
   ============================================================ */
.steps-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: clamp(18px, 2.4vw, 26px);
  list-style: none;
  margin: 0;
  padding: 0;
}
.step { padding-top: var(--sp-6); border-top: 2px solid var(--step-tint, rgba(162, 89, 255, 0.55)); }
.step__num { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 12px; color: var(--accent); }
.step__title { margin-top: var(--sp-3); }
.step__desc { margin: var(--sp-3) 0 0; font-size: var(--fs-sm); color: var(--muted); }

/* ============================================================
   Pricing
   ============================================================ */
.pricing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 330px), 1fr));
  gap: clamp(18px, 2.4vw, 28px);
  align-items: stretch;
}
.price-card {
  display: flex;
  flex-direction: column;
  padding: clamp(28px, 3.6vw, 44px);
  border-radius: var(--r-xl);
  border: 1px solid var(--border);
  background: linear-gradient(170deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.012));
  transition: transform var(--dur-med) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-med) var(--ease-out);
}
.price-card--featured {
  position: relative;
  border-color: var(--border-accent);
  background: linear-gradient(170deg, rgba(162, 89, 255, 0.16), rgba(109, 40, 217, 0.05));
  box-shadow: 0 50px 110px -55px rgba(162, 89, 255, 0.85);
  overflow: hidden;
}
.price-card--featured::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(115deg, rgba(198, 163, 255, 0.7), rgba(198, 163, 255, 0) 35%, rgba(198, 163, 255, 0) 65%, rgba(198, 163, 255, 0.55));
  background-size: 200% 100%;
  animation: bsShimmer 8s linear infinite;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}
@media (hover: hover) and (pointer: fine) {
  .price-card:hover { transform: translateY(-4px); border-color: rgba(198, 163, 255, 0.45); }
}

.price-card__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; min-height: 28px; }
.price-card__kicker { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted-2); }
.price-card--featured .price-card__kicker { color: var(--accent-soft); }
.price-card__badge {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: 6px 13px; border-radius: var(--r-pill);
  background: linear-gradient(135deg, var(--cta-from), var(--cta-to));
  color: #fff;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  box-shadow: var(--glow-sm);
}
.price-card__badge-dot { width: 5px; height: 5px; border-radius: var(--r-pill); background: #fff; animation: bsPulse 2.4s ease-in-out infinite; }
.price-card__name { margin-top: var(--sp-4); font-size: clamp(1.4375rem, 1.3rem + 0.5vw, 1.75rem); }
.price-card__amount { display: flex; align-items: baseline; gap: var(--sp-3); margin-top: var(--sp-5); }
.price-card__value { font-family: "Bricolage Grotesque", sans-serif; font-weight: 600; font-size: var(--fs-price); letter-spacing: -0.03em; line-height: 0.9; }
.price-card__value--gradient {
  background: linear-gradient(100deg, #ffffff, var(--accent-soft));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.price-card__period { font-size: var(--fs-sm); color: var(--muted-2); }
.price-card--featured .price-card__period { color: var(--muted); }
.price-card__desc { margin: var(--sp-5) 0 0; max-width: 34ch; font-size: var(--fs-sm); color: var(--muted); }
.price-card--featured .price-card__desc { color: var(--ink-dim); }
.price-card__rule { height: 1px; margin: clamp(22px, 3vw, 30px) 0; background: linear-gradient(90deg, rgba(162, 89, 255, 0.4), rgba(255, 255, 255, 0)); }
.price-card--featured .price-card__rule { background: linear-gradient(90deg, rgba(198, 163, 255, 0.6), rgba(255, 255, 255, 0)); }

.check-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
.check-item { display: flex; gap: var(--sp-3); align-items: flex-start; font-size: clamp(0.9375rem, 0.9rem + 0.2vw, 1.03125rem); line-height: 1.45; color: var(--ink-dim); }
.price-card--featured .check-item { color: #efecf5; }
.check-item svg { flex: none; margin-top: 3px; color: var(--accent-soft); }
.price-card--featured .check-item svg { color: #d9c2ff; }

.price-card__cta { margin-top: auto; margin-block-start: clamp(28px, 4vw, 38px); }

.addon-panel {
  margin-top: clamp(16px, 2.4vw, 26px);
  padding: clamp(26px, 3.4vw, 40px);
  border-radius: var(--r-xl);
  border: 1px solid var(--border);
  background: linear-gradient(120deg, rgba(255, 255, 255, 0.035), rgba(255, 255, 255, 0.01));
}
.addon-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: clamp(24px, 4vw, 48px); align-items: center; }
.addon-title { margin-top: var(--sp-3); font-size: clamp(1.375rem, 1.2rem + 0.7vw, 1.875rem); }
.addon-amount { display: flex; align-items: baseline; gap: var(--sp-2); margin-top: var(--sp-3); }
.addon-value { font-family: "Bricolage Grotesque", sans-serif; font-weight: 600; font-size: clamp(34px, 5vw, 46px); letter-spacing: -0.03em; line-height: 1; }
.addon-period { font-size: var(--fs-sm); color: var(--muted-2); }
.addon-desc { margin: var(--sp-4) 0 0; max-width: 42ch; font-size: var(--fs-sm); color: var(--muted); }
.addon-features { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); gap: var(--sp-3); list-style: none; margin: 0; padding: 0; }
.addon-feature { display: flex; gap: var(--sp-3); align-items: center; font-size: var(--fs-sm); color: var(--ink-dim); }
.addon-feature__dot { width: 6px; height: 6px; border-radius: var(--r-pill); background: var(--accent); flex: none; }
.addon-cta { margin-top: clamp(22px, 3vw, 30px); }

/* ============================================================
   FAQ
   ============================================================ */
.faq-list { display: flex; flex-direction: column; border-top: 1px solid var(--border); }
.faq-item { border-bottom: 1px solid var(--border); }
/* The question is a heading for structure; the button inside it does the
   interaction. The heading itself carries no visual style of its own. */
.faq-heading { margin: 0; font: inherit; }
.faq-question {
  width: 100%;
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-5);
  padding: clamp(20px, 2.6vw, 26px) 0;
  background: none; border: none;
  color: var(--ink);
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 500;
  font-size: clamp(1.0625rem, 1rem + 0.45vw, 1.375rem);
  line-height: 1.3;
  text-align: left;
  cursor: pointer;
  min-height: 56px;
  transition: color var(--dur-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .faq-question:hover { color: var(--accent-soft); }
  .faq-question:hover .faq-icon { border-color: var(--border-hover); }
}
.faq-icon {
  flex: none; width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: var(--accent-soft);
  transition: transform var(--dur-med) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.faq-item[data-open="true"] .faq-icon { transform: rotate(45deg); border-color: rgba(198, 163, 255, 0.6); }

/* visibility (not just max-height) so collapsed answers leave the
   a11y tree and the tab order; delayed so it doesn't cut the collapse */
.faq-answer {
  overflow: hidden;
  max-height: 0;
  visibility: hidden;
  transition: max-height var(--dur-med) var(--ease-out),
              visibility 0s linear var(--dur-med);
}
.faq-item[data-open="true"] .faq-answer {
  visibility: visible;
  transition: max-height var(--dur-med) var(--ease-out), visibility 0s;
}
.faq-answer p { margin: 0; padding: 0 0 26px; max-width: 62ch; color: var(--muted); }

/* ============================================================
   Contact
   ============================================================ */
.contact-panel {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-2xl);
  border: 1px solid var(--border);
  background: linear-gradient(160deg, rgba(162, 89, 255, 0.16), rgba(7, 6, 10, 0.2));
  padding: clamp(30px, 6vw, 76px);
}
.contact-panel__glow { position: absolute; inset: 0; background: radial-gradient(70% 90% at 90% 10%, rgba(124, 58, 237, 0.28), rgba(7, 6, 10, 0) 70%); pointer-events: none; }
.contact-grid { position: relative; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: clamp(28px, 5vw, 56px); align-items: start; }
.contact-lede { color: #c8c2d4; }
/* Hit area is the 44px-tall anchor; the underline hugs the text via
   the inner span, so the touch target grows without the rule
   detaching from the baseline. */
.contact-email {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-top: var(--sp-4);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: var(--fs-sm);
  color: var(--accent-soft);
}
.contact-email span {
  border-bottom: 1px solid rgba(198, 163, 255, 0.4);
  padding-bottom: 3px;
  transition: border-color var(--dur-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .contact-email:hover span { border-color: #fff; }
}

.contact-form { display: flex; flex-direction: column; gap: var(--sp-4); }
.field-group { display: flex; flex-direction: column; gap: 6px; }
.field-label {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--muted);
}
.field {
  width: 100%;
  min-height: 54px;
  padding: 0 18px;
  border-radius: var(--r-md);
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(7, 6, 10, 0.5);
  color: var(--ink);
  font-family: inherit;
  font-size: var(--fs-body);
  transition: border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}
.field::placeholder { color: var(--muted-2); }
.field:hover { border-color: rgba(255, 255, 255, 0.22); }
.field:focus {
  border-color: rgba(198, 163, 255, 0.65);
  background: rgba(7, 6, 10, 0.75);
}
textarea.field { min-height: 0; padding: 16px 18px; resize: vertical; line-height: 1.5; }
.form-note { min-height: 20px; font-size: var(--fs-sm); color: var(--accent-soft); }
.form-hint { margin: 0; font-size: 13px; color: var(--muted-2); }

/* ============================================================
   Sticky mobile CTA
   ============================================================ */
.sticky-cta {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
  padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + env(safe-area-inset-bottom));
  background: linear-gradient(180deg, rgba(7, 6, 10, 0), rgba(7, 6, 10, 0.94) 45%);
  transform: translateY(110%);
  transition: transform var(--dur-med) var(--ease-out);
}
.sticky-cta.is-visible { transform: translateY(0); }
.sticky-cta__price { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 12px; opacity: 0.85; }
@media (min-width: 721px) { .sticky-cta { display: none; } }

/* ============================================================
   Footer
   ============================================================ */
.site-footer { position: relative; z-index: 1; padding: clamp(32px, 5vw, 48px) clamp(20px, 5vw, 64px); border-top: 1px solid var(--border-hair); }
.site-footer__inner { max-width: 1280px; margin-inline: auto; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-5); }
.site-footer img { height: 24px; width: auto; display: block; opacity: 0.75; }
.site-footer__links { display: flex; gap: clamp(14px, 3vw, 30px); flex-wrap: wrap; }
.site-footer__links a {
  font-size: var(--fs-sm);
  color: var(--muted-2);
  transition: color var(--dur-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .site-footer__links a:hover { color: var(--ink); }
}
.site-footer__meta { margin: 0; font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 12px; color: var(--faint); }

/* Second row: legal links sit apart from the site nav rather than
   crowding into it — six links in one row starts wrapping awkwardly
   around 1024px, and these serve a different purpose anyway. */
.site-footer__legal {
  max-width: 1280px;
  margin-inline: auto;
  margin-top: clamp(24px, 3vw, 34px);
  padding-top: clamp(20px, 2.5vw, 28px);
  border-top: 1px solid var(--border-hair);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
}
.site-footer__links--legal a { color: var(--faint); }

/* ============================================================
   Content pages (Privacy, Terms)

   Same tokens as the rest of the site — no separate legal-page
   styling. The only difference from a marketing section is a longer
   line height and a tighter measure, because this is text to be read
   rather than scanned.
   ============================================================ */
.page-head {
  position: relative;
  z-index: 1;
  padding-block: clamp(8rem, 6rem + 7vw, 12rem) clamp(2rem, 1.5rem + 2vw, 3.5rem);
}
.page-head__title {
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.036em;
  margin: var(--sp-5) 0 0;
  max-width: 18ch;
  text-wrap: balance;
}
.page-head__lede {
  margin: var(--sp-5) 0 0;
  max-width: 58ch;
  font-size: var(--fs-lede);
  line-height: 1.6;
  color: var(--muted);
}
.page-head__meta {
  margin: var(--sp-6) 0 0;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 12px;
  color: var(--faint);
}

.prose { max-width: 68ch; padding-bottom: clamp(4rem, 3rem + 5vw, 7rem); }

.prose h2 {
  font-family: "Bricolage Grotesque", sans-serif;
  font-weight: 550;
  font-size: var(--fs-h3);
  line-height: 1.25;
  letter-spacing: -0.015em;
  color: var(--ink);
  margin: clamp(2.5rem, 2rem + 2vw, 3.5rem) 0 var(--sp-4);
}
.prose h2:first-child { margin-top: 0; }

/* A numbered rail down the left of each clause — the same device the
   marketing sections use for their eyebrows, so the legal pages read
   as the same publication rather than a bolted-on template. */
.prose h2 { counter-increment: clause; position: relative; }
.prose { counter-reset: clause; }
.prose h2::before {
  content: counter(clause, decimal-leading-zero);
  position: absolute;
  left: -3.25rem;
  top: 0.15em;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--accent);
}
/* The rail hangs 52px into the gutter, but the container's gutter is
   5vw — it drops under 52px around 1040px wide and the numbers would
   clip off the left edge. Fall back to stacking them above the heading
   while there is still room to spare. */
@media (max-width: 1080px) {
  .prose h2::before { position: static; display: block; margin-bottom: var(--sp-2); }
}

.prose p {
  margin: 0 0 var(--sp-4);
  color: var(--muted);
  line-height: 1.75;   /* looser than marketing copy: this is read, not scanned */
}
.prose ul { margin: 0 0 var(--sp-4); padding: 0; list-style: none; }
.prose li {
  position: relative;
  padding-left: var(--sp-6);
  margin-bottom: var(--sp-3);
  color: var(--muted);
  line-height: 1.75;
}
.prose li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 6px;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--accent);
  opacity: 0.75;
}
.prose strong { color: var(--ink-dim); font-weight: 500; }
.prose a { color: var(--accent-soft); text-decoration: underline; text-underline-offset: 3px; }
.prose > :last-child { margin-bottom: 0; }

/* Closing note — visually quieter than a clause, but still on-brand. */
.prose__note {
  margin-top: clamp(2.5rem, 2rem + 2vw, 3.5rem);
  padding: clamp(20px, 3vw, 28px);
  border-radius: var(--r-lg);
  border: 1px solid var(--border-soft);
  background: linear-gradient(170deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0.012));
}
.prose__note p { margin: 0; font-size: var(--fs-sm); }

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 1024px) {
  .hero { padding-top: clamp(6.5rem, 5rem + 6vw, 9rem); }
}

/* Short viewports — small phones, and any phone turned landscape.
   Both paddings come down together so the copy keeps its clearance
   under the fixed header instead of being squeezed against it. */
@media (max-height: 620px) {
  .hero {
    padding-block:
      clamp(4.5rem, 3.5rem + 4vw, 6.5rem)
      clamp(4rem, 3rem + 4vw, 6rem);
  }
}

@media (max-width: 768px) {
  :root { --header-h: 62px; }
  .container, section { max-width: 100%; }
}

@media (max-width: 640px) {
  .hero-cta-row .btn,
  .price-card__cta,
  .addon-cta,
  .contact-form button[type="submit"] { width: 100%; }
  /* Clear the sticky CTA so it never covers the footer's last line */
  .site-footer { padding-bottom: calc(88px + env(safe-area-inset-bottom)); }
  .site-footer__inner { justify-content: center; text-align: center; }
}

@media (max-width: 420px) {
  .brand img { height: 29px; }
  .heading-hero { letter-spacing: -0.03em; }
}

/* ============================================================
   Lenis
   Native smooth scrolling and Lenis both animating the scroll
   position fight each other, so the CSS one is switched off exactly
   while Lenis is running. These are Lenis's own required styles.
   ============================================================ */
html.lenis, html.lenis body { height: auto; }
/* Keyed on `.lenis`, not Lenis's documented `.lenis-smooth`: this build
   only ever sets the base class, so the -smooth selector never matched
   and native smooth scrolling stayed on underneath Lenis. */
.lenis { scroll-behavior: auto !important; }
.lenis [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }
