/* ============================================================
   PLANNERPATH — "The Unbroken Line"
   Site system: tokens, base, chrome, components, pointer.

   The token layer below is the PREVIOUS site's, carried across
   whole — palette, type scale, tracking, space, radii, elevation
   and motion. That is deliberate: the film is new, the surface it
   plays on is not. Values here should be changed by editing the
   original's app/styles/tokens.css and re-porting, not by drift.

   The site is entirely light. Sections paint either nothing at all
   or one of the three washes below — indigo at very low alpha,
   fading to transparent at both edges — so the body gradient and
   the dot field read through and the page is one continuous field
   rather than a stack of slabs.
   ============================================================ */

/* ---------------- Tokens ---------------- */
:root {
  /* ---- Palette ---- */
  --bg: #F7F6F8;
  --surface: #ffffff;
  --ink: #0E0D1A;
  --paper: #F7F6F8;
  --muted: #545263;
  --muted-light: #9896A8;
  --line: #EDECED;
  --primary: #3D36BB;
  --primary-dark: #1D138B;
  --primary-soft: #EDEAFC;
  --teal: #1D9E75;
  --bg-gradient-start: #fff;

  --surface-raised: #ffffff;
  --surface-sunken: #F1F0F4;
  --surface-veil: rgba(255, 255, 255, .72);
  --surface-glass: rgba(255, 255, 255, .60);

  --border: #E7E6EB;
  --border-strong: #D6D4DE;
  --border-accent: rgba(61, 54, 187, .22);

  --focus-ring: #3D36BB;
  --focus-halo: rgba(61, 54, 187, .22);

  /* Two-layer elevation: a tight contact shadow plus a wide ambient
     one, so cards read as lifted rather than as a box with a blur
     under it. --highlight is the 1px inner top edge that sells it. */
  --elev-1: 0 1px 2px rgba(14, 13, 26, .04), 0 2px 8px rgba(14, 13, 26, .04);
  --elev-2: 0 2px 4px rgba(14, 13, 26, .04), 0 10px 26px rgba(14, 13, 26, .07);
  --elev-3: 0 4px 8px rgba(14, 13, 26, .05), 0 22px 60px rgba(14, 13, 26, .11);
  --elev-4: 0 8px 16px rgba(14, 13, 26, .06), 0 40px 100px rgba(14, 13, 26, .16);
  --highlight: inset 0 1px 0 rgba(255, 255, 255, .9);
  --spotlight: rgba(61, 54, 187, .07);

  /* The mock's CSS is a verbatim port and references these names. */
  --shadow-sm: var(--elev-1);
  --shadow-md: var(--elev-2);
  --shadow-lg: var(--elev-4);

  /* ---- Section washes ----
     The site has no dark sections. Where a section needs to read as
     distinct it takes one of these — brand indigo at very low alpha
     over the same off-white page, applied as a gradient that fades to
     transparent at BOTH edges so the section melts into its
     neighbours instead of butting against them. That is the whole
     blending mechanism; there are no divider elements. */
  --wash-1: rgba(61, 54, 187, .045);
  --wash-2: rgba(61, 54, 187, .075);
  --wash-3: rgba(61, 54, 187, .11);

  /* ---- Type ----
     Fraunces for display and every number; Lunasima for everything
     else. There is no webfont mono: the original has none, and its
     label voice is Lunasima 700 uppercase at .16em. */
  --font-fraunces: "Fraunces";
  --font-lunasima: "Lunasima";
  --display: var(--font-fraunces), Georgia, "Times New Roman", serif;
  --ui: var(--font-lunasima), Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Fluid scale, fitted to 375 → 1440px. */
  --step--2: clamp(11.5px, 11.15px + .094vw, 12.5px);
  --step--1: clamp(13px, 12.65px + .094vw, 14px);
  --step-0: clamp(15px, 14.47px + .141vw, 16.5px);
  --step-1: clamp(17px, 16.30px + .188vw, 19px);
  --step-2: clamp(19px, 17.24px + .469vw, 24px);
  --step-3: clamp(23px, 20.18px + .751vw, 31px);
  --step-4: clamp(28px, 23.77px + 1.127vw, 40px);
  --step-5: clamp(34px, 27.66px + 1.690vw, 52px);
  --step-6: clamp(40px, 30.14px + 2.630vw, 68px);
  --step-7: clamp(48px, 31.10px + 4.507vw, 96px);
  /* The film hero. Sized against the COLUMN, not the viewport: the
     H1's line breaks are authored, so it has to be small enough that
     the longest phrase fits at every width, or the phrases wrap
     inside their own masks and you get five ragged lines instead of
     four. Re-check both ends if the authored phrases change. */
  --step-hero: clamp(38px, 6.4vw - 20px, 84px);

  --track-display: -.052em;
  --track-head: -.042em;
  --track-sub: -.016em;
  --track-body: -.005em;
  --track-eyebrow: .16em;

  --nav-ink: #33314A;

  /* ---- Space ---- */
  --space-1: 4px;   --space-2: 8px;   --space-3: 12px;  --space-4: 16px;
  --space-5: 20px;  --space-6: 24px;  --space-7: 28px;  --space-8: 32px;
  --space-10: 40px; --space-12: 48px; --space-16: 64px; --space-20: 80px;
  --space-24: 96px;
  --space-section: clamp(64px, 44px + 5.3vw, 120px);

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

  /* ---- Grid ---- */
  --container: 1380px;
  /* TWO header heights, and the distinction is load-bearing.
     --header-h is the LAYOUT reservation: the constant space the
     fixed header occupies at the top of the shell. It never changes.
     --bar-h is the VISUAL bar, which condenses on scroll.

     They used to be one token on a sticky header, which meant the
     whole document moved up 18px the moment you scrolled. Anything
     measured in document coordinates — the entire thread — was then
     valid in only one of the two states. That is what put a strip of
     bare canvas under the footer and what pushed the thread's coil
     18px below the PCI gauge. */
  --header-h: 86px;
  --bar-h: 86px;
  --gutter: clamp(16px, 12px + 1.1vw, 28px);
  --measure: 68ch;

  /* ---- Motion ----
     --motion-ease-page is NOT interchangeable with --motion-ease: it
     is the slow, weighted S the page transition rides. The router
     uses the real GSAP CustomEase; this is the CSS-only fallback. */
  --motion-ease: cubic-bezier(.2, .7, .2, 1);
  --motion-ease-out: cubic-bezier(.16, 1, .3, 1);
  --motion-ease-page: cubic-bezier(.58, .12, .41, .95);
  --motion-pointer: 200ms;
  --motion-entrance: 700ms;
  --motion-signature: 900ms;
  --motion-page: 700ms;
  --motion-travel: 22px;
  --motion-stagger: 80ms;
}

/* ---- The wash utilities ----
   Both edges fade, so a washed section blends into whatever is above
   and below it without a divider. Sequence them so two washed
   sections never touch: where they do, both fades meet and leave a
   pale seam — the opposite of what this is for. */
.wash-1, .wash-2, .wash-3 { position: relative; }
.wash-1 { background: linear-gradient(180deg, transparent 0%, var(--wash-1) 18%, var(--wash-1) 82%, transparent 100%); }
.wash-2 { background: linear-gradient(180deg, transparent 0%, var(--wash-2) 18%, var(--wash-2) 82%, transparent 100%); }
.wash-3 { background: linear-gradient(180deg, transparent 0%, var(--wash-3) 18%, var(--wash-3) 82%, transparent 100%); }

/* The opening frame is the exception: it holds full tint from the very
   top, because the header sits on it and a fade there would read as a
   pale stripe above the headline. It only fades downward. */
.wash-top { background: linear-gradient(180deg, var(--wash-3) 0%, var(--wash-3) 46%, transparent 100%); }

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

html {
  -webkit-text-size-adjust: 100%;
  /* Lenis owns programmatic scrolling; scroll-behavior: smooth would
     fight it and land anchor jumps in the wrong place. */
  scroll-behavior: auto;
  /* `clip`, not `hidden`. `overflow-x: hidden` forces overflow-y to
     `auto`, which turns the element into a scroll container and
     breaks every `position: sticky` scene inside it. */
  overflow-x: clip;
}

/* ---- Scrollbar ----------------------------------------------
   Hidden everywhere, on every scroller. The page still scrolls by
   wheel, trackpad, keyboard, touch and Lenis — only the indicator
   is gone. `overflow: hidden` would NOT be equivalent; it would
   kill scrolling outright. Two declarations for two engines:
   scrollbar-width is the standard property, the ::-webkit- pseudo
   covers older WebKit and Chromium. Both resolve to zero width, so
   nothing reserves space and there is no gutter to stabilise. */
* {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
*::-webkit-scrollbar { display: none; width: 0; height: 0; }

body {
  margin: 0;
  color: var(--ink);
  /* No radial, and no background-attachment. The radial used to sit
     behind the top of every page and read as a glow around the header;
     `fixed` had additionally pinned it to the viewport so it followed
     you down. Only the white-to-off-white ramp remains, which lifts
     the top of the page without putting colour behind the chrome. */
  background: linear-gradient(180deg, var(--bg-gradient-start) 0%, var(--bg) 70%);
  background-repeat: no-repeat;
  font-family: var(--ui);
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 { margin: 0; font-weight: 500; }
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }

/* Fraunces' opsz axis is deliberately not loaded, but a browser that
   ever sees it must not drive it: high optical size is the thin,
   high-contrast display cut. */
.font-serif, h1, h2, .stat-num {
  font-optical-sizing: none;
}

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

:where(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}
.btn:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px var(--focus-halo);
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; top: -100px; left: var(--gutter);
  z-index: 200; padding: 12px 18px;
  background: var(--primary); color: #fff;
  font-size: var(--step--1); font-weight: 700;
  border-radius: var(--r-sm);
}
.skip-link:focus { top: 14px; }

/* ---------------- Decorative layers ---------------- */

/* One fixed viewport-anchored layer, so pointer viewport coords ARE
   its local coords and no rect maths is needed. Both grids use the
   same 26px cell and the same anchoring, so the bright dots land
   exactly on the dim ones. No mix-blend-mode: it would force the
   whole page into a blending group and reorder the sticky header. */
.dot-field {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: radial-gradient(rgba(112, 102, 240, .09) 1px, transparent 1px);
  background-size: 26px 26px;
}
.dot-field::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(112, 102, 240, .34) 1px, transparent 1px);
  background-size: 26px 26px;
  mask-image: radial-gradient(260px circle at var(--hx, -999px) var(--hy, -999px), #000 0%, rgba(0, 0, 0, .55) 45%, transparent 72%);
  -webkit-mask-image: radial-gradient(260px circle at var(--hx, -999px) var(--hy, -999px), #000 0%, rgba(0, 0, 0, .55) 45%, transparent 72%);
  opacity: 0;
  transition: opacity 300ms var(--motion-ease);
}
html[data-pointer="true"] .dot-field::after { opacity: 1; }

/* z-index 45: above the page-transition overlay (40), so the grain
   stays continuous over the outgoing page while it recedes, but
   below the header (50), which is glass and shouldn't be dusted. */
.body-grain {
  position: fixed;
  inset: 0;
  z-index: 45;
  pointer-events: none;
  opacity: .028;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------------- Layout ---------------- */

/* [data-page-shell] MUST STAY VISUALLY INERT.
   No position, transform, filter, contain, will-change, perspective,
   content-visibility or backdrop-filter — ever. Any one of them makes
   this a containing block for absolutely-positioned descendants, and
   .thread-layer (position: absolute; top: 0) would then anchor to it
   instead of the initial containing block. The shell starts
   --header-h lower than the ICB because the sticky header occupies
   that much normal flow, so the entire thread, all its anchors and
   the tip tracking would silently shift down by 74px and the curve
   would just look subtly wrong. It would not throw.
   This is also the node the page transition clones, so anything that
   paints here paints twice during a navigation. */
[data-page-shell] { display: block; padding-top: var(--header-h); }

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

/* Paper sections paint NOTHING — the body gradient and dot field
   read straight through, which is what makes the page one field
   instead of a stack of slabs. Only ink sections are opaque. */
.section { padding: var(--space-section) 0; position: relative; }
.section-tight { padding: clamp(44px, 30px + 3vw, 80px) 0; }
.section-flush-top { padding-top: 0; }

/* Kept as an alias so the page modules did not all need editing; it is
   simply the quiet wash. */
.on-sunken { background: linear-gradient(180deg, transparent 0%, var(--wash-1) 18%, var(--wash-1) 82%, transparent 100%); }

/* The CTA band is the strongest wash on a page, not a dark slab. */
.cta-band { background: linear-gradient(180deg, transparent 0%, var(--wash-3) 22%, var(--wash-3) 70%, transparent 100%); }

/* Lift real content above the dot field. */
main > section > *,
main > .container,
main > div > .container { position: relative; z-index: 1; }

.grid { display: grid; gap: var(--gutter); }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 1000px) {
  .grid-4, .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 660px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: minmax(0, 1fr); }
}

.split {
  display: grid;
  grid-template-columns: 1.08fr .92fr;
  gap: clamp(32px, 18px + 2.6vw, 72px);
  align-items: start;
}
@media (max-width: 940px) { .split { grid-template-columns: minmax(0, 1fr); } }

/* ---------------- Type ----------------
   EVERY h1 and h2 is serif. Scoping this to specific containers is
   how the film's chapter headings silently fell back to the body
   sans — they live in .runway-head, .gap-scene and friends, not in
   a .section-head. h3 is the deliberate exception below: card
   headings are bold SANS, which is what anchors them. */
h1, h2 {
  font-family: var(--display);
  font-weight: 500;
  letter-spacing: var(--track-head);
  line-height: 1.02;
  color: var(--ink);
  text-wrap: balance;
}
h2 { font-size: var(--step-5); }

.page-hero h1 {
  font-size: var(--step-6);
  line-height: .98;
  letter-spacing: var(--track-display);
  max-width: 16ch;
}
.section-head h2, .split h2, .cta-band h2 { font-size: var(--step-5); }

em, .display-italic {
  font-style: italic;
  font-weight: 500;
  color: var(--primary);
}

/* Card headings are BOLD SANS, not serif. Lunasima ships only 400
   and 700, so this 600 resolves up to real Bold — that solidity is
   what anchors every card, and it is most of the difference between
   this and a lighter variable-weight pairing. */
h3, .card h3 {
  font-family: var(--ui);
  font-size: var(--step-1);
  font-weight: 600;
  line-height: 1.28;
  letter-spacing: var(--track-sub);
  color: var(--ink);
}

.lede {
  color: var(--muted);
  font-size: var(--step-1);
  line-height: 1.7;
  max-width: 56ch;
}
.lede-sm { font-size: var(--step-0); line-height: 1.72; }

.section-head { max-width: 780px; margin-bottom: var(--space-12); }
.section-head h2 { margin-bottom: var(--space-5); }

.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0 0 var(--space-6);
  color: var(--primary);
  font-size: var(--step--2);
  font-weight: 700;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  line-height: 1;
}
.eyebrow::before {
  content: "";
  width: 26px; height: 1px;
  background: currentColor;
  opacity: .55;
  flex: none;
}
/* The long tail. Draws 100ms after the leading rule so the pair
   reads as one stroke continuing past the label. */
.eyebrow::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  min-width: 24px;
  background: linear-gradient(90deg, var(--border-strong), transparent);
}

.stack > * + * { margin-top: var(--space-5); }

/* ---------------- Buttons ---------------- */
.btn {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
  min-height: 52px;
  padding: 0 var(--space-6);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  font-family: var(--ui);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: var(--track-body);
  cursor: pointer;
  transition: transform var(--motion-pointer) var(--motion-ease),
              box-shadow var(--motion-pointer) var(--motion-ease),
              background var(--motion-pointer) var(--motion-ease),
              border-color var(--motion-pointer) var(--motion-ease);
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0) scale(.985); }
.btn .arrow { display: inline-block; transition: transform var(--motion-pointer) var(--motion-ease); }
.btn:hover .arrow { transform: translateX(4px); }

.btn-primary {
  color: #fff;
  background: var(--primary);
  border-color: rgba(0, 0, 0, .14);
  box-shadow: 0 10px 26px rgba(61, 54, 187, .22), inset 0 1px 0 rgba(255, 255, 255, .2);
}
.btn-primary:hover {
  background: var(--primary-dark);
  box-shadow: 0 16px 36px rgba(61, 54, 187, .3), inset 0 1px 0 rgba(255, 255, 255, .24);
}

.btn-ghost {
  color: var(--primary);
  background: var(--surface-raised);
  border-color: var(--border-strong);
  box-shadow: var(--elev-1), var(--highlight);
}
.btn-ghost:hover { background: var(--surface-sunken); border-color: var(--border-accent); }

.btn-sm { min-height: 46px; padding-inline: var(--space-5); border-radius: var(--r-sm); }

.actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-8); }

.text-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--primary);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: var(--track-body);
  transition: gap var(--motion-pointer) var(--motion-ease),
              color var(--motion-pointer) var(--motion-ease);
}
.text-link:hover { gap: 11px; color: var(--primary-dark); }

.inline-link { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }

/* ---------------- Header ----------------
   z-index 60: above the transition overlay (58), so the chrome
   persists un-animated while the content slides beneath it. */
/* FIXED, not sticky. A sticky header occupies flow, so condensing it
   moves every element below by the difference. Out of flow, its height
   is free to change and the document never shifts. The shell reserves
   the space with a constant padding-top instead. */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 60;
  transition: background-color .4s var(--motion-ease);
}
.site-header[data-scrolled="true"] { --bar-h: 68px; }


/* Glass lives on masked pseudos, not the header itself, so there is
   no bar edge — content melts into whatever scrolls beneath. Two
   stacked layers make the frost GRADUATE: strong blur + tint up top,
   then a lighter pass that outlives it, so blur steps 20px → 6px → 0
   instead of cutting from 20px to sharp on a line. Masks must stay
   on the same element as the backdrop-filter; on a parent they would
   turn the header into a backdrop root and kill the blur.
   This is also why the header sits OUTSIDE [data-page-shell]: the
   transition clips an overlay, and any such ancestor would flatten
   the frost for the whole 700ms. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0 0 -8px 0;
  z-index: -1;
  pointer-events: none;
  background-color: var(--surface-glass);
  backdrop-filter: blur(20px) saturate(150%);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
  mask-image: linear-gradient(to bottom, #000 42%, rgba(0,0,0,.85) 58%, rgba(0,0,0,.55) 70%, rgba(0,0,0,.28) 80%, rgba(0,0,0,.1) 89%, transparent 97%);
  -webkit-mask-image: linear-gradient(to bottom, #000 42%, rgba(0,0,0,.85) 58%, rgba(0,0,0,.55) 70%, rgba(0,0,0,.28) 80%, rgba(0,0,0,.1) 89%, transparent 97%);
  transition: background-color .4s var(--motion-ease);
}
.site-header[data-scrolled="true"]::before { background-color: var(--surface-veil); }
.site-header::after {
  content: "";
  position: absolute;
  inset: 34% 0 -28px 0;
  z-index: -1;
  pointer-events: none;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  mask-image: linear-gradient(to bottom, transparent 0%, rgba(0,0,0,.45) 26%, #000 44%, #000 58%, rgba(0,0,0,.55) 72%, rgba(0,0,0,.28) 84%, rgba(0,0,0,.09) 93%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, rgba(0,0,0,.45) 26%, #000 44%, #000 58%, rgba(0,0,0,.55) 72%, rgba(0,0,0,.28) 84%, rgba(0,0,0,.09) 93%, transparent 100%);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header::before { background-color: rgba(255, 255, 255, .92); }
}

/* Three columns, not a flex row: the nav has to centre on the PAGE,
   and the two flanks are nowhere near equal (brand ~194px, button
   ~142px). A flex row with an auto margin centres the nav in the
   leftover space, which is ~26px off. Symmetric 1fr tracks put the
   auto middle column on the container's centre line — and since
   .container is max-width with an auto inline margin, that is the
   page's centre.
   It also survives the condense: the brand narrows 194px → 166px at
   the 20px scroll threshold, and a container-relative track does not
   care, where anything measured off the brand would jog 14px. */
.header-inner {
  min-height: var(--bar-h);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: clamp(16px, 1.6vw, 34px);
  transition: min-height var(--motion-pointer) var(--motion-ease);
}
.header-inner > .brand { justify-self: start; }
.header-inner > .header-actions { justify-self: end; }

.brand { display: inline-flex; align-items: center; flex: none; color: var(--ink); }
/* One image, not a mark plus a text span: the 2026 lockup draws the
   mark and the wordmark as a single piece. Height drives it and width
   follows, so the aspect ratio is never at risk. */
.brand-wordmark { height: 34px; width: auto; transition: height var(--motion-pointer) var(--motion-ease); }
.site-header[data-scrolled="true"] .brand-wordmark { height: 29px; }
.site-footer .brand-wordmark { height: 30px; }

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(14px, 1.7vw, 32px);
  color: var(--nav-ink);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: -.005em;
  transition: color .4s var(--motion-ease);
}
.site-nav a, .nav-dd > summary {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 0;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--motion-pointer) ease;
}
.site-nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 100%; bottom: -3px;
  height: 2px;
  background: var(--primary);
  border-radius: 999px;
  transition: right .24s var(--motion-ease);
}
.site-nav a:hover, .nav-dd > summary:hover { color: var(--ink); }
.site-nav a:hover::after { right: 0; }
.site-nav a[aria-current="page"] { color: var(--ink); }
.site-nav a[aria-current="page"]::after { right: 0; opacity: .55; }

.nav-dd { position: relative; }
.nav-dd > summary { list-style: none; }
.nav-dd > summary::-webkit-details-marker { display: none; }
.nav-dd > summary::marker { content: ""; }
.nav-dd svg { transition: transform var(--motion-pointer) ease; }
.nav-dd[open] svg { transform: rotate(180deg); }
.nav-dd-panel {
  position: absolute;
  top: calc(100% + 16px);
  left: 50%;
  transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 2px;
  min-width: 212px;
  padding: var(--space-2);
  border: 1px solid #E7E6EB;
  border-radius: var(--r-md);
  background: #fff;
  box-shadow: var(--elev-3), inset 0 1px 0 rgba(255,255,255,.9);
  z-index: 60;
}
.nav-dd-panel a {
  padding: 10px 12px;
  border-radius: var(--r-xs);
  color: #545263;
  font-weight: 600;
  transition: background .15s ease, color .15s ease;
}
.nav-dd-panel a:hover { background: #F1F0F4; color: #0E0D1A; }
.nav-dd-panel a::after { display: none; }

.header-actions { display: flex; align-items: center; gap: var(--space-5); flex: none; }

.nav-toggle {
  display: none;
  margin-left: auto;
  width: 44px; height: 44px;
  align-items: center; justify-content: center;
  background: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-pill);
  color: var(--ink);
  cursor: pointer;
}
.nav-toggle span { display: block; width: 15px; height: 1.5px; background: currentColor; border-radius: 2px; position: relative; }
.nav-toggle span::before, .nav-toggle span::after {
  content: ""; position: absolute; left: 0;
  width: 15px; height: 1.5px; background: currentColor; border-radius: 2px;
}
.nav-toggle span::before { top: -5px; }
.nav-toggle span::after { top: 5px; }

/* 1150px, not 1080px. The centred nav needs room for the WIDER of the
   two flanks on BOTH sides, not just the sum: at 1081px each 1fr track
   is ~198px against a 194px brand, which is not a margin.
   THIS NUMBER IS DUPLICATED IN static/js/site.js (the ddFloating
   matchMedia). Change both or the dropdown runs its floating logic
   while the nav is a drawer. */
@media (max-width: 1150px) {
  /* Two columns here: .site-nav is fixed (out of flow, not a grid
     item) and .header-actions is gone, so only brand + toggle remain. */
  .header-inner { grid-template-columns: 1fr auto; }
  .header-actions { display: none; }
  .nav-toggle { display: inline-flex; }
  .site-nav {
    position: fixed;
    inset: var(--bar-h) 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin: 0;
    padding: var(--space-3) var(--gutter) var(--space-7);
    background: #fff;
    color: #545263;
    border-bottom: 1px solid #E7E6EB;
    box-shadow: var(--elev-4);
    transform: translateY(-12px);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--motion-entrance) var(--motion-ease), transform var(--motion-entrance) var(--motion-ease);
    max-height: calc(100svh - var(--bar-h));
    overflow-y: auto;
  }
  .site-nav.open { opacity: 1; transform: none; pointer-events: auto; }
  .site-nav a, .nav-dd > summary { padding: 14px 2px; border-bottom: 1px solid #EDECED; font-size: 16px; }
  .site-nav a::after { display: none; }
  .nav-dd-panel { position: static; transform: none; box-shadow: none; border: 0; padding: 0 0 0 16px; background: none; }
}
@media (max-width: 420px) { .brand-wordmark { height: 28px; } }

/* ---------------- Footer ---------------- */
/* Light, like everything else. The tone is the sunken surface rather
   than a wash, so the foot of the page settles rather than lifting,
   and a hairline separates it without a hard colour edge. */
.site-footer {
  position: relative;
  z-index: 1;
  /* No border. The footer emerges from the page colour over its first
     140px instead of starting on a hard line, so the seam disappears
     the same way every other section boundary does. */
  background-color: var(--surface-sunken);
  background-image: linear-gradient(180deg, var(--bg) 0%, rgba(247, 246, 248, 0) 140px);
  color: var(--muted);
  padding: clamp(56px, 40px + 3vw, 92px) 0 var(--space-8);
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.7fr repeat(4, minmax(0, 1fr));
  gap: clamp(24px, 16px + 2vw, 52px);
}
@media (max-width: 960px) { .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .footer-grid { grid-template-columns: minmax(0, 1fr); } }

.footer-blurb { margin-top: var(--space-4); max-width: 34ch; font-size: var(--step--1); line-height: 1.7; }
.site-footer h4 {
  margin: 0 0 var(--space-4);
  color: var(--ink);
  font-size: var(--step--2);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.site-footer .footer-col a {
  display: block;
  margin-bottom: var(--space-3);
  font-size: var(--step--1);
  color: var(--muted);
  transition: color var(--motion-pointer) ease;
}
.site-footer .footer-col a:hover { color: var(--primary); }

.footer-legal {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--space-3);
  margin-top: var(--space-16);
  padding-top: var(--space-6);
  border-top: 1px solid var(--border);
  font-size: var(--step--2);
  letter-spacing: .04em;
}

/* ---------------- Page hero ---------------- */
.page-hero {
  position: relative;
  padding: clamp(44px, 4vw, 84px) 0 var(--space-16);
  overflow: hidden;
}
.page-hero h1 { margin-top: var(--space-6); }
.page-hero .lede { margin-top: var(--space-7); max-width: 62ch; }

.hero-thread {
  position: absolute;
  top: 0;
  left: calc(var(--gutter) - 1px);
  width: 1px; height: 100%;
  background: linear-gradient(180deg, var(--primary) 0%, transparent 100%);
  opacity: .32;
}
@media (max-width: 900px) { .hero-thread { display: none; } }

/* ---------------- Centred heroes ----------------
   The film's opening frame and every interior hero centre; Live's
   split hero does not, hence .page-hero-centred rather than
   .page-hero.

   The eyebrow needs its own handling: it is a flex row whose ::after
   tail is `flex: 1 1 auto`, so it grows to fill the line and
   text-align has no effect on it at all. Dropping the tail is what
   lets the leading rule sit centred — exactly what .cta-band does. */
.film-hero .container,
.page-hero-centred .container { text-align: center; }

.film-hero .eyebrow,
.page-hero-centred .eyebrow { justify-content: center; }
.film-hero .eyebrow::after,
.page-hero-centred .eyebrow::after { display: none; }

.film-hero h1,
.film-hero .lede,
.page-hero-centred h1,
.page-hero-centred .lede { margin-inline: auto; }

.film-hero .actions,
.page-hero-centred .actions { justify-content: center; }

/* ---------------- Cards ("islands") ----------------
   The spotlight is a background-image layer, not a pseudo-element:
   pseudo layering would need `isolation: isolate`, which creates a
   backdrop root — the exact thing that would silently flatten the
   backdrop-filter inside .product-preview and the header. */
.card, .stat-card, .panel, .pricing-card, .founder-col, .session-card {
  position: relative;
  padding: var(--space-7) var(--space-6);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  background-color: var(--surface-raised);
  background-image: radial-gradient(360px circle at var(--mx, 50%) var(--my, -10%), var(--spotlight), transparent 70%);
  background-repeat: no-repeat;
  box-shadow: var(--elev-1), var(--highlight);
  transition: transform var(--motion-pointer) var(--motion-ease),
              box-shadow var(--motion-pointer) var(--motion-ease),
              border-color var(--motion-pointer) var(--motion-ease);
}
.card:hover, .stat-card:hover, .panel:hover,
.pricing-card:hover, .founder-col:hover, .session-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--elev-3), var(--highlight);
  border-color: var(--border-accent);
}

.card { height: 100%; display: flex; flex-direction: column; }
/* Inline-ish children of a column flex container stretch to full width
   by default, which turns a pill into a bar and a text link into an
   invisible full-width hit area. These hug their content instead. */
.card .count,
.card .text-link,
.card .step-num,
.not-are-label { align-self: flex-start; }
.card h3 { margin: 0; }
.card p, .stat-card p, .panel p {
  margin: var(--space-3) 0 0;
  color: var(--muted);
  font-size: var(--step--1);
  line-height: 1.65;
}
.card .text-link { margin-top: auto; padding-top: var(--space-5); }

/* Values get the deeper primary heading the original gave them. */
.card-value h3 { color: var(--primary-dark); }

.panel { padding: var(--space-8); border-radius: var(--r-2xl); box-shadow: var(--elev-2), var(--highlight); height: 100%; }
.panel p { font-size: var(--step-0); line-height: 1.72; }
.panel-compact { height: auto; align-self: start; }

/* Numbered step card */
.step-num {
  display: grid; place-items: center;
  width: 42px; height: 42px;
  margin-bottom: var(--space-5);
  border-radius: var(--r-md);
  background: var(--primary);
  color: #fff;
  font-size: var(--step-0);
  font-weight: 700;
  box-shadow: 0 10px 22px rgba(61, 54, 187, .26), inset 0 1px 0 rgba(255, 255, 255, .2);
}

/* Stat */
.stat-card { height: 100%; }
.stat-num {
  display: block;
  font-family: var(--display);
  font-size: var(--step-5);
  font-weight: 500;
  letter-spacing: var(--track-head);
  line-height: 1.05;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat-num em { font-style: normal; font-weight: 500; color: var(--primary); }
.stat-card p { max-width: 24ch; }

/* Role cards — the spotlight composites OVER the audience tint. */
.role-card { border-top: 3px solid var(--role, var(--primary)); }
.role-card .text-link { color: var(--role, var(--primary)); }
.role-student { --role: #3D36BB; background-image: radial-gradient(360px circle at var(--mx,50%) var(--my,-10%), var(--spotlight), transparent 70%), linear-gradient(180deg, #EDEAFC, transparent 46%); }
.role-firm    { --role: #185FA5; background-image: radial-gradient(360px circle at var(--mx,50%) var(--my,-10%), var(--spotlight), transparent 70%), linear-gradient(180deg, #E6F1FB, transparent 46%); }
.role-uni     { --role: #854F0B; background-image: radial-gradient(360px circle at var(--mx,50%) var(--my,-10%), var(--spotlight), transparent 70%), linear-gradient(180deg, #FAEEDA, transparent 46%); }
.role-pro     { --role: #1D9E75; background-image: radial-gradient(360px circle at var(--mx,50%) var(--my,-10%), var(--spotlight), transparent 70%), linear-gradient(180deg, #E3F5EE, transparent 46%); }

/* Domain card */
.domain-card .count {
  display: inline-flex; align-items: center;
  min-height: 26px; padding: 0 11px;
  margin-bottom: var(--space-4);
  border-radius: var(--r-pill);
  background: var(--primary-soft);
  color: var(--primary);
  font-size: var(--step--2);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* Trust blocks opt out of the card surface entirely. */
.tick-block {
  padding: var(--space-5) 0 0;
  border: 0;
  border-top: 1px solid var(--border);
  border-radius: 0;
  background-color: transparent;
  box-shadow: none;
}
.tick-block:hover { transform: none; box-shadow: none; border-color: var(--border); }
.tick-block h3 { font-size: var(--step-0); }
.tick-block .tick { color: var(--teal); margin-right: 4px; }

/* Lists */
.check-list { display: grid; gap: var(--space-3); margin-top: var(--space-6); }
.check-list li {
  position: relative;
  padding-left: 30px;
  color: var(--muted);
  font-size: var(--step-0);
  line-height: 1.65;
}
.check-list li::before {
  content: "✓";
  position: absolute; left: 0; top: 0;
  color: var(--teal);
  font-weight: 700;
}

.note {
  font-size: var(--step--1);
  line-height: 1.65;
  color: var(--primary-dark);
  background: var(--primary-soft);
  padding: var(--space-5) var(--space-6);
  border-radius: var(--r-lg);
}
.fine-print { font-size: var(--step--2); color: var(--muted-light); line-height: 1.6; }
.fine-print a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* Sample-report rows (For Firms) */
.report-rows { display: grid; gap: var(--space-3); margin-top: var(--space-5); }
.report-row { padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
.report-row strong { display: block; font-size: var(--step--1); font-weight: 700; }
.report-row span { display: block; margin-top: 4px; font-size: var(--step--2); color: var(--muted); }

/* ---------------- CTA band ---------------- */
.cta-band { position: relative; overflow: hidden; padding: clamp(72px, 50px + 5vw, 140px) 0; text-align: center; }
.cta-band .eyebrow { justify-content: center; }
.cta-band .eyebrow::after { display: none; }
.cta-band h2 { max-width: 18ch; margin-inline: auto; margin-bottom: var(--space-6); }
.cta-band .lede { margin-inline: auto; }
.cta-band .actions { justify-content: center; }
.cta-band .fine-print { margin-top: var(--space-6); }
.cta-glow {
  position: absolute; left: 50%; top: 50%;
  width: min(900px, 120vw); aspect-ratio: 1;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(61, 54, 187, .07) 0%, transparent 62%);
  pointer-events: none;
}
.cta-band > .container { position: relative; z-index: 1; }

/* ---------------- Pricing ---------------- */
.pricing-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gutter); align-items: stretch; }
@media (max-width: 900px) { .pricing-grid { grid-template-columns: minmax(0, 1fr); max-width: 520px; margin-inline: auto; } }
.pricing-card { display: flex; flex-direction: column; }
.pricing-card.featured { border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary), var(--elev-3); }
.pricing-tag {
  position: absolute; top: -12px; left: var(--space-6);
  padding: 4px 12px; border-radius: var(--r-pill);
  background: var(--primary); color: #fff;
  font-size: var(--step--2); font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
}
.pricing-card h3 { font-size: var(--step-2); }
.pricing-tagline { margin: var(--space-1) 0 var(--space-6); color: var(--muted); font-size: var(--step--1); }
.pricing-price { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: var(--space-6); padding-bottom: var(--space-6); border-bottom: 1px solid var(--line); }
.pricing-price-num {
  font-family: var(--display);
  font-size: var(--step-4);
  font-weight: 600;
  letter-spacing: var(--track-head);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.pricing-price-note { color: var(--muted-light); font-size: var(--step--1); }
.pricing-features { display: grid; gap: var(--space-3); margin-bottom: var(--space-8); }
.pricing-features li { position: relative; padding-left: 24px; color: var(--muted); font-size: var(--step--1); line-height: 1.6; }
.pricing-features li::before { content: ""; position: absolute; left: 0; top: .55em; width: 10px; height: 1px; background: var(--primary); opacity: .6; }
.pricing-card .btn { margin-top: auto; }
.pricing-note { margin: var(--space-3) 0 0; font-size: var(--step--2); color: var(--muted-light); line-height: 1.5; }

/* ---------------- Live / event ---------------- */
.session-card { padding: var(--space-8); border-radius: var(--r-2xl); box-shadow: var(--elev-2), var(--highlight); }
.session-label { display: block; color: var(--primary); font-size: var(--step--2); font-weight: 700; letter-spacing: var(--track-eyebrow); text-transform: uppercase; }
.session-date { font-family: var(--display); font-size: var(--step-3); font-weight: 500; line-height: 1.06; letter-spacing: var(--track-head); margin: var(--space-4) 0; }
.session-sub { display: block; color: var(--muted-light); font-size: var(--step--2); line-height: 1.6; }

/* ---------------- The Live bento ----------------
   Replaces a four-cell hairline strip that used `auto-fit` and so
   resolved to three columns for four items, leaving a dead grey square
   bottom-right. Every track here is explicit and every cell is filled
   at every breakpoint — geomcheck asserts it.

   Tiles are `.card` first, so the border, radius, elevation, hover lift
   and the --mx/--my pointer spotlight all come from the existing card
   system rather than being restated. `.card` is already in pointer.js's
   CARD_SELECTOR, so the spotlight needs no wiring. */
.bento {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--gutter);
}
.bento-wide { grid-column: span 2; }

.bento-tile {
  position: relative;
  overflow: hidden;
  padding: clamp(24px, 2.4vw, 36px);
  gap: 0;
}
.bento-icon {
  display: block;
  margin-bottom: var(--space-4);
  color: var(--primary);
  transform-origin: left center;
  transition: transform var(--motion-entrance) var(--motion-ease);
}
.bento-tile:hover .bento-icon { transform: scale(1.14); }
.bento-eyebrow {
  margin: 0 0 var(--space-3);
  color: var(--muted-light);
  font-size: var(--step--2);
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.bento-value {
  margin: 0;
  font-family: var(--display);
  font-size: var(--step-2);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: var(--track-head);
}
.bento-value-lg { font-size: var(--step-4); line-height: 1; }
.bento-value-sm { font-size: var(--step-0); line-height: 1.4; }
.bento-note {
  margin: var(--space-4) 0 0;
  max-width: 52ch;
  color: var(--muted);
  font-size: var(--step--1);
  line-height: 1.65;
}

/* The reference slides its CTA up from hidden on group-hover. Do the
   same — but only where there IS a hover. On touch the link is simply
   there, because a primary action you can only reach by hovering is
   not a primary action. :focus-within covers the keyboard. */
.bento-cta { margin-top: var(--space-5); }
@media (hover: hover) and (pointer: fine) {
  .bento-cta {
    opacity: 0;
    transform: translateY(10px);
    transition: opacity var(--motion-entrance) var(--motion-ease), transform var(--motion-entrance) var(--motion-ease);
  }
  .bento-tile:hover .bento-cta,
  .bento-tile:focus-within .bento-cta { opacity: 1; transform: none; }
}

/* --- layout variants --- */

/* Decorative visual above, body at the bottom, masked so the artwork
   dissolves rather than stopping on a line — the reference's
   [mask-image:linear-gradient(to_top,transparent,#000)]. */
.bento-stack { display: flex; flex-direction: column; justify-content: flex-end; min-height: 300px; }
.bento-stack .bento-visual {
  position: absolute;
  top: 0; left: 0; right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 62%;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to top, transparent 4%, #000 46%);
  mask-image: linear-gradient(to top, transparent 4%, #000 46%);
  transition: transform var(--motion-entrance) var(--motion-ease);
}
.bento-stack:hover .bento-visual { transform: scale(1.06); }
.bento-stack .bento-body { position: relative; }

/* Body beside the visual — the dates are real content, so they are NOT
   faded into a backdrop the way the decorative visuals are. */
.bento-beside { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 15.5rem); gap: clamp(24px, 3vw, 52px); align-items: center; }

/* Body above, visual full-bleed across the foot. The body centres in
   whatever height the row's taller tile dictates, rather than sitting
   against the top with all the slack in one lump above the marquee.
   Its height already includes the CTA, hidden or not, so revealing the
   CTA on hover reflows nothing. */
.bento-foot { display: flex; flex-direction: column; padding-bottom: 0; }
.bento-foot .bento-body { margin-block: auto; }
.bento-foot .bento-visual { margin: var(--space-6) calc(clamp(24px, 2.4vw, 36px) * -1) 0; }

/* --- the dates --- */
.bento-dates { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.bento-date {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 10px 14px;
  border-radius: var(--r-xs);
  color: var(--muted);
  font-size: var(--step--1);
  white-space: nowrap;
  transition: background var(--motion-pointer) ease, color var(--motion-pointer) ease;
}
.bento-date-dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; opacity: .4; flex: none; }
.bento-date:hover { background: var(--surface-sunken); color: var(--ink); }
/* site.js marks this from the same date list the session card reads. */
.bento-date.is-next {
  background: var(--primary-soft);
  color: var(--primary-dark);
  font-weight: 700;
}
.bento-date.is-next .bento-date-dot { opacity: 1; }

/* --- the clock --- */
.bento-clock { width: min(200px, 78%); height: auto; overflow: visible; }
.clock-face { fill: none; stroke: var(--border-strong); stroke-width: 1; opacity: .5; }
.clock-tick { stroke: var(--border-strong); stroke-width: 1.2; stroke-linecap: round; opacity: .5; }
.clock-tick-q { stroke: var(--muted-light); stroke-width: 1.6; opacity: .8; }
/* 2πr at r=46 is 289.03. Half the dial is the 10:00→16:00 span, and the
   210deg rotation is where 10 o'clock lands once SVG's 3-o'clock start
   is accounted for.
   The dash is 144.5 and the gap is the full circumference, so the arc
   is DRAWN at offset 0 and hidden at 144.5 — offset shifts the pattern
   backwards, so offsetting by the dash length puts position 0 at the
   dash's end and nothing renders at all. */
.clock-arc {
  fill: none;
  stroke: var(--primary);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-dasharray: 144.5 289.03;
  stroke-dashoffset: 0;
  transform: rotate(210deg);
  transform-origin: 60px 60px;
  transition: stroke-dashoffset 1.1s var(--motion-ease) .15s;
}
html[data-motion] .reveal .clock-arc { stroke-dashoffset: 144.5; }
html[data-motion] .reveal.in .clock-arc { stroke-dashoffset: 0; }

/* --- the route --- */
.bento-route { width: min(180px, 70%); height: auto; overflow: visible; }
.route-line {
  fill: none;
  stroke: var(--primary);
  stroke-width: 1.8;
  stroke-linecap: round;
  opacity: .55;
  stroke-dasharray: 210;
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 1.2s var(--motion-ease) .1s;
}
html[data-motion] .reveal .route-line { stroke-dashoffset: 210; }
html[data-motion] .reveal.in .route-line { stroke-dashoffset: 0; }
.route-node { fill: var(--primary); opacity: .5; }
.route-dest { fill: var(--primary); opacity: .16; }
.route-dest-core { fill: var(--primary); }

/* --- the inclusions marquee ---
   The reference's <Marquee pauseOnHover>. A CSS loop, not GSAP, so a
   page transition has nothing to tear down. The track holds the chip
   set TWICE and travels exactly -50%, which is what makes the seam
   invisible; shorten either and a bare gap appears at the wrap. */
.bento-marquee {
  position: relative;
  overflow: hidden;
  padding-block: var(--space-5);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 16%, #000 84%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 16%, #000 84%, transparent);
}
.bento-marquee-track { display: flex; width: max-content; gap: var(--space-3); }
html[data-motion] .bento-marquee-track { animation: bento-marquee 34s linear infinite; }
.bento-marquee:hover .bento-marquee-track { animation-play-state: paused; }
@keyframes bento-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.bento-chip {
  flex: none;
  padding: 9px 16px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface-raised);
  color: var(--muted);
  font-size: var(--step--2);
  font-weight: 600;
  white-space: nowrap;
}

@media (max-width: 1040px) {
  .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bento-wide { grid-column: span 2; }
}
@media (max-width: 720px) {
  .bento { grid-template-columns: minmax(0, 1fr); }
  .bento-wide { grid-column: span 1; }
  /* The dates would be squeezed to a sliver beside the body. */
  .bento-beside { grid-template-columns: minmax(0, 1fr); align-items: start; }
  .bento-stack { min-height: 260px; }
}

/* ---------------- Founders ---------------- */
.founder-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gutter); }
@media (max-width: 820px) { .founder-grid { grid-template-columns: minmax(0, 1fr); } }
.founder-col { padding: var(--space-10); border-radius: var(--r-2xl); box-shadow: var(--elev-2), var(--highlight); display: flex; flex-direction: column; }
.founder-photo-row { display: flex; align-items: center; gap: var(--space-4); margin-bottom: var(--space-5); }
.founder-photo { width: 96px; height: 96px; border-radius: 50%; object-fit: cover; border: 1px solid var(--border); background: var(--surface-sunken); }
.founder-linkedin {
  display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: var(--r-pill);
  background: var(--primary); color: #fff; flex-shrink: 0;
  transition: transform var(--motion-pointer) ease, background var(--motion-pointer) ease;
}
.founder-linkedin:hover { transform: translateY(-2px); background: var(--primary-dark); }
.credential-pills { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }
.credential-pill {
  padding: 4px 11px; border-radius: var(--r-pill);
  background: var(--primary-soft); color: var(--primary);
  font-size: var(--step--2); font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
}
.founder-col h3 { font-family: var(--display); font-size: var(--step-4); font-weight: 500; letter-spacing: var(--track-head); line-height: 1.05; }
.founder-role { margin: var(--space-2) 0 var(--space-5); color: var(--primary); font-size: var(--step--2); font-weight: 700; letter-spacing: .14em; text-transform: uppercase; line-height: 1.5; }
.founder-col p:not(.founder-role) { color: var(--muted); font-size: var(--step-0); line-height: 1.75; margin-top: var(--space-4); }

/* ---------------- Foundations ---------------- */
.module-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--gutter); }
.module-card { display: flex; flex-direction: column; }
.module-points { display: grid; gap: var(--space-2); margin: var(--space-4) 0 var(--space-5); }
.module-points li { position: relative; padding-left: 20px; color: var(--muted); font-size: var(--step--1); line-height: 1.55; }
.module-points li::before { content: ""; position: absolute; left: 0; top: .6em; width: 8px; height: 1px; background: var(--primary); }
.module-outcome { margin-top: auto; padding: var(--space-4); border-radius: var(--r-md); background: var(--primary-soft); color: var(--primary-dark); font-size: var(--step--2); line-height: 1.55; }
.module-outcome strong { font-weight: 700; }

.not-are { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gutter); }
@media (max-width: 720px) { .not-are { grid-template-columns: minmax(0, 1fr); } }
.not-are-label { display: inline-block; margin-bottom: var(--space-5); font-size: var(--step--2); font-weight: 700; letter-spacing: var(--track-eyebrow); text-transform: uppercase; }
.label-not { color: #B4304A; }
.label-are { color: var(--teal); }
.not-list { display: grid; gap: var(--space-3); }
.not-list li { display: flex; gap: 12px; color: var(--muted); font-size: var(--step-0); }
.cross { color: #B4304A; }

/* ---------------- Legal ---------------- */
.legal-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 250px;
  gap: clamp(32px, 20px + 3vw, 80px);
  align-items: start;
  padding: clamp(56px, 40px + 3vw, 104px) 0;
  position: relative;
  z-index: 1;
}
@media (max-width: 940px) { .legal-layout { grid-template-columns: minmax(0, 1fr); } .legal-toc { display: none; } }

.legal-page { max-width: var(--measure); }
.legal-page h1 { font-family: var(--display); font-size: var(--step-5); font-weight: 500; letter-spacing: var(--track-head); line-height: 1.02; }
.legal-updated { margin: var(--space-3) 0 0; font-size: var(--step--2); color: var(--muted-light); letter-spacing: .04em; }
.legal-intro { margin: var(--space-6) 0 0; font-size: var(--step-0); line-height: 1.78; color: var(--muted); }
.legal-page h2 {
  font-family: var(--display);
  font-size: var(--step-2);
  font-weight: 500;
  letter-spacing: var(--track-sub);
  margin: var(--space-12) 0 var(--space-4);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border);
  color: var(--ink);
  scroll-margin-top: calc(var(--bar-h) + 24px);
}
.legal-page p { font-size: var(--step-0); line-height: 1.78; color: var(--muted); margin: 0 0 var(--space-4); }
.legal-page ul { display: grid; gap: var(--space-2); margin: var(--space-4) 0; }
.legal-page li { position: relative; padding-left: 24px; font-size: var(--step-0); line-height: 1.78; color: var(--muted); }
.legal-page li::before { content: ""; position: absolute; left: 0; top: .82em; width: 12px; height: 1px; background: var(--primary); }
.legal-page strong { color: var(--ink); font-weight: 600; }
.legal-page a { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }
.legal-contact { margin-top: var(--space-16); padding: var(--space-8); border: 1px solid var(--border); border-radius: var(--r-xl); background: var(--surface-raised); box-shadow: var(--elev-1), var(--highlight); }
.legal-contact h2 { margin-top: 0; padding-top: 0; border-top: 0; }

.legal-toc { position: sticky; top: calc(var(--bar-h) + 32px); }
.legal-toc h4 { margin: 0 0 var(--space-4); color: var(--muted-light); font-size: var(--step--2); font-weight: 700; letter-spacing: var(--track-eyebrow); text-transform: uppercase; }
.legal-toc a {
  display: block;
  padding: 7px 12px;
  border-left: 2px solid var(--border);
  border-radius: 0 var(--r-xs) var(--r-xs) 0;
  color: var(--muted-light);
  font-size: var(--step--1);
  line-height: 1.4;
  transition: color var(--motion-pointer) ease, background var(--motion-pointer) ease, border-color var(--motion-pointer) ease;
}
.legal-toc a:hover { color: var(--ink); background: var(--surface-sunken); border-left-color: var(--border-strong); }
.legal-toc a.active { color: var(--primary); border-left-color: var(--primary); font-weight: 700; }

/* ---------------- 404 ---------------- */
.error-page {
  min-height: calc(100svh - var(--header-h));
  display: grid; place-items: center; text-align: center;
  background: linear-gradient(180deg, var(--wash-3) 0%, transparent 70%);
  padding: var(--space-24) 0;
}
.error-code { color: var(--primary); font-size: var(--step--2); font-weight: 700; letter-spacing: .3em; text-transform: uppercase; margin-bottom: var(--space-6); }
.error-page h1 { color: var(--ink); font-family: var(--display); font-size: var(--step-6); font-weight: 500; letter-spacing: var(--track-display); max-width: 14ch; margin-inline: auto; }
.error-page .lede { max-width: 46ch; margin-inline: auto; }

/* ---------------- Reveals ---------------- */
html[data-motion] .reveal { opacity: 0; transform: translateY(var(--pp-travel, 18px)); }
html[data-motion] .reveal.in {
  opacity: 1;
  transform: none;
  transition: opacity var(--motion-entrance) var(--motion-ease),
              transform var(--motion-entrance) var(--motion-ease);
  transition-delay: var(--d, 0ms);
}
html[data-motion] .section-head > h2 { --pp-travel: 26px; }

/* Masked line reveal. The mask is unconditional — with nothing
   translated inside it, `overflow: hidden` on a block that fits its
   line is invisible. The generous padding/negative-margin pairs give
   Fraunces' descenders and italic side bearings room to clear the
   mask edge without changing the leading. */
.line-mask {
  display: block;
  overflow: hidden;
  padding-bottom: .2em;  margin-bottom: -.2em;
  padding-top: .3em;     margin-top: -.3em;
  padding-inline: .22em; margin-inline: -.22em;
}
.line-in { display: block; }
.lines { text-wrap: wrap; }
.lines .line-in { text-wrap: balance; }

html[data-motion] .lines .line-in { transform: translateY(140%); }
html[data-motion] .lines.in .line-in {
  transform: none;
  transition: transform var(--motion-signature) var(--motion-ease);
  transition-delay: calc(80ms + var(--i, 0) * 48ms);
}

/* The eyebrow draws itself. */
@keyframes pp-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }
html[data-motion] .reveal .eyebrow::before,
html[data-motion] .reveal.eyebrow::before,
html[data-motion] .reveal .eyebrow::after,
html[data-motion] .reveal.eyebrow::after { transform: scaleX(0); transform-origin: left center; }
html[data-motion] .reveal.in .eyebrow::before,
html[data-motion] .reveal.eyebrow.in::before {
  animation: pp-draw var(--motion-signature) var(--motion-ease) both;
  animation-delay: calc(var(--d, 0ms) + 120ms);
}
html[data-motion] .reveal.in .eyebrow::after,
html[data-motion] .reveal.eyebrow.in::after {
  animation: pp-draw var(--motion-signature) var(--motion-ease) both;
  animation-delay: calc(var(--d, 0ms) + 220ms);
}

/* Clip wipe for headings that have no authored line masks. The −12%
   bottom overshoot keeps descenders out of the clip edge.

   The wipe MUST live on an inner span, never on the observed element
   itself. IntersectionObserver ignores opacity but it does NOT ignore
   clip-path: an element clipped to `inset(0 0 100% 0)` has a
   zero-area intersection rect and therefore never crosses any
   threshold, so it would sit permanently invisible while everything
   around it revealed normally. */
@keyframes pp-wipe { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 -12% 0); } }
html[data-motion] .wipe { display: block; clip-path: inset(0 0 100% 0); }
html[data-motion] .reveal.in .wipe { animation: pp-wipe var(--motion-signature) var(--motion-ease) both; animation-delay: var(--d, 0ms); }

/* Hero entrance ladder — CSS only, no JS dependency. */
@keyframes rise { to { opacity: 1; transform: translateY(0); } }
html[data-motion] .rise { opacity: 0; transform: translateY(var(--motion-travel)); animation: rise var(--motion-entrance) var(--motion-ease) forwards; }
html[data-motion] .rise-1 { animation-delay: .05s; }
html[data-motion] .rise-2 { animation-delay: .16s; }
html[data-motion] .rise-3 { animation-delay: .27s; }
html[data-motion] .rise-4 { animation-delay: .38s; }
html[data-motion] .rise-5 { animation-delay: .5s; }

@keyframes bar-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes float-slow { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(-18px, 22px); } }

/* ---------------- Page transition overlay ----------------
   Built in JS, appended to <body>. Three layers, one job each:
   #pt-overlay the curtain, .pt-viewport the push-back, .pt-clone a
   detached copy of the outgoing shell.
   z-index 58 — NOT the 40 the original used. The film's .hud is
   `position: fixed; z-index: 55` and lives inside the shell, so at
   40 the INCOMING page's HUD would paint straight through the
   curtain on any navigation to the homepage. 58 clears the HUD (55),
   every scene (5) and the thread (4), and still sits below the
   header (50 → raised to 60 below) so the live header keeps painting
   on top, un-animated, with its backdrop-filter still sampling the
   document. .pt-viewport is exactly viewport-sized: these pages run
   to 15,000px and scaling a clone that tall about its own centre
   would fling content off screen. */
#pt-overlay {
  position: fixed;
  inset: 0;
  overflow: hidden;
  z-index: 58;
  pointer-events: none;
  contain: paint;
  will-change: clip-path;
  clip-path: inset(0 0 0 0);
  background-color: var(--bg);
  background-repeat: no-repeat;
}
.pt-viewport { position: absolute; inset: 0; overflow: hidden; transform-origin: 50% 50%; will-change: transform, opacity; }
.pt-clone { position: absolute; left: 0; }
/* Zeroing duration and delay rather than `animation: none` is
   deliberate: .rise sits at opacity 0 and gets its visible state
   from the animation's forwards fill, so removing the animation
   would blank the copied text. A zero-length animation lands on its
   end state immediately — exactly the frozen frame we want. */
#pt-overlay *, #pt-overlay *::before, #pt-overlay *::after {
  animation-duration: 0s !important;
  animation-delay: 0s !important;
  transition: none !important;
}

/* ---------------- Reduced motion ---------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html[data-motion] .reveal,
  html[data-motion] .lines .line-in,
  html[data-motion] .rise { opacity: 1 !important; transform: none !important; animation: none !important; }
  html[data-motion] .wipe { clip-path: none; animation: none; }
  .body-grain { display: none; }
  .pv-domain-bar span, .pv-journey-bar span { animation: none; transform: scaleX(1); }
  .product-preview { transform: none; transition: none; }
  .pv-tile:hover { transform: none; box-shadow: var(--elev-1); }
  .btn:hover, .card:hover, .stat-card:hover, .panel:hover,
  .pricing-card:hover, .founder-col:hover, .session-card:hover { transform: none; }
  .hero-glow { animation: none !important; }
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ---------------- Utilities ---------------- */
.center { text-align: center; }
.mx-auto { margin-inline: auto; }
.mt-0 { margin-top: 0; }
.mt-2 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-6); }
.mt-6 { margin-top: var(--space-10); }
.mb-0 { margin-bottom: 0; }
.max-720 { max-width: 720px; }
.max-820 { max-width: 820px; }
