/* ---------------------------------------------------------------- fonts */

/* Self-hosted 2026-09-10, replacing the Google Fonts <link>. Same files Google
   serves, downloaded once and served from our own domain, so no visitor IP
   reaches a third party. Both are variable fonts, so one file covers 400-700
   and there is no separate file per weight. */

@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/dm-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/dm-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Duke Grooves landing page
   Converted from the Claude Design v8 export. Design tokens follow artboard 01. */

/* ---------------------------------------------------------------- tokens */

:root {
  /* dark set */
  --stage: radial-gradient(ellipse 110% 80% at 50% 40%, #2a2a2a 0%, #141414 55%, #050505 100%);
  --stage-deep: radial-gradient(ellipse 110% 80% at 50% 40%, #202020 0%, #0d0d0d 55%, #030303 100%);
  --stage-flat: #141414;
  --black: #050505;
  --surface: #1c1c1c;
  --surface-2: #242424;
  --line-dark: rgba(255, 255, 255, 0.10);

  /* light set */
  --paper: #faf8f5;
  --paper-soft: #f2eee8;
  --line-light: rgba(10, 10, 10, 0.10);

  /* accent */
  --accent: #ff7a29;
  --accent-ink: #b4460a;          /* accent text on light bands only */
  --accent-tint: #ffc49b;
  --accent-soft: rgba(255, 122, 41, 0.20);
  --accent-edge: rgba(255, 122, 41, 0.25);
  --accent-line: rgba(255, 122, 41, 0.40);
  --accent-wash: rgba(255, 122, 41, 0.07);
  --accent-glow: 0 0 32px rgba(255, 122, 41, 0.45);
  --accent-lift: 0 18px 40px rgba(255, 122, 41, 0.20);

  /* text */
  --fg-1: #ffffff;
  --fg-2: rgba(255, 255, 255, 0.70);
  --fg-muted: rgba(255, 255, 255, 0.55);
  --fg-dim: rgba(255, 255, 255, 0.42);
  --ink-1: #0a0a0a;
  --ink-2: rgba(10, 10, 10, 0.72);
  --ink-muted: rgba(10, 10, 10, 0.62);
  --ink-dim: rgba(10, 10, 10, 0.35);

  /* type */
  --display: Fraunces, Georgia, "Times New Roman", serif;
  --body: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* layout */
  --spine: 1264px;
  /* spine + two max gutters: the width past which the hero stops growing */
  --hero-cap: 1440px;
  /* Width of the widest row in the hero column (the ticks and the proof row),
     and therefore where the scrim's solid black ends. Everything to the right
     of it is photograph, so this number is the trade between the two. */
  --hero-content: 640px;
  /* Readable measure for prose sitting beside a portrait. Both the cap on the
     text and the width of Joe's prose column read from here, so the two rows in
     the solution section cannot drift apart. */
  --prose-cap: 580px;
  /* The portrait column used to be a hard 398px, so as the window narrowed the
     photo kept its width and the prose beside it paid for all of it: by ~800px
     the text was a 264px ribbon running down the page past a picture that
     stopped a third of the way along. The cap now shrinks with the viewport
     below 995px (40vw x 995 = 398px, so it is continuous there and nothing
     above 995px moves) and the two columns narrow together. */
  --portrait-cap: min(398px, 40vw);
  --compare-cap: 740px;
  --spine-mid: 1000px;
  --spine-narrow: 900px;
  --gutter: clamp(20px, 6.1vw, 88px);
  --band-y: clamp(84px, 9.7vw, 140px);
  --band-gap-lg: clamp(72px, 9.2vw, 132px);
  --stack-64: clamp(40px, 4.4vw, 64px);
  --radius: 1.25rem;
  --radius-sm: 1rem;
  --pill: 3rem;

  --ease: cubic-bezier(.16, 1, .3, 1);
}

/* ------------------------------------------------------------- resets */

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

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--black);
  color: var(--fg-1);
  font-family: var(--body);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, video { max-width: 100%; }
p { margin: 0; }
h1, h2, h3 { margin: 0; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-tint); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: #0b0b0b; }
::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.14); border-radius: 6px; }
::-webkit-scrollbar-thumb:hover { background: var(--accent); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* -------------------------------------------------------------- motion */

@keyframes orbDrift {
  0%, 100% { transform: translate3d(0, 0, 0) scale(0.97); }
  50%      { transform: translate3d(30px, -22px, 0) scale(1.05); }
}
@keyframes floatY {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-8px); }
}
@keyframes heroIn {
  from { opacity: 0; transform: translateY(24px); filter: blur(4px); }
  to   { opacity: 1; transform: translateY(0);    filter: blur(0); }
}

.reveal {
  opacity: 0;
  transform: translateY(24px);
  filter: blur(4px);
  transition:
    opacity .7s var(--ease),
    transform .7s var(--ease),
    filter .7s var(--ease);
}
.reveal.is-in { opacity: 1; transform: translateY(0); filter: blur(0); }

.hero-in { opacity: 0; animation: heroIn 1.1s var(--ease) forwards; }
.hero-in--1 { animation-delay: 0.20s; }
.hero-in--2 { animation-delay: 0.45s; }
.hero-in--3 { animation-delay: 0.65s; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .reveal { opacity: 1; transform: none; filter: none; }
  .hero-in { opacity: 1; }
  html { scroll-behavior: auto; }
}

/* ------------------------------------------------------- bands + atmosphere */

.band {
  position: relative;
  padding: var(--band-y) var(--gutter);
  overflow: hidden;
}
.band--dark   { background: var(--stage); color: var(--fg-1); }
.band--deep   { background: var(--stage-deep); color: var(--fg-1); }
.band--flat   { background: var(--black); color: var(--fg-1); }
.band--paper  { background: var(--paper); color: var(--ink-1); }

/* paper bands that follow one another share an edge, so kill the seam */
.band--joined-top { padding-top: 0; }
/* A colour change does half the separating work, so a paper band following
   another paper band needs less air than the 280 a dark-to-paper seam gets.
   These two ran 140 + 124 = 284 of blank paper, which read as a hole rather
   than a break. Now 140 + 44 = 184. */
.band--joined-top > .container { padding-top: clamp(28px, 3.1vw, 44px); }
/* A dark band opens with a 120px seam gradient, so a bordered card sitting at
   the standard 140 top padding lands 20px after the fade and reads as crowded
   against it. This clears the seam properly before the card starts. */
.band--seam-clear { padding-top: calc(var(--band-y) + clamp(48px, 5.1vw, 80px)); }

.container {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--spine);
  margin-inline: auto;
}
.container--mid    { max-width: var(--spine-mid); }
.container--narrow { max-width: var(--spine-narrow); }

.stack   { display: flex; flex-direction: column; }
.stack-56 { gap: clamp(36px, 3.9vw, 56px); }
.stack-64 { gap: clamp(40px, 4.4vw, 64px); }
.stack-48 { gap: clamp(32px, 3.3vw, 48px); }
.stack-44 { gap: clamp(30px, 3.1vw, 44px); }

.grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.04;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}
.grain--light { opacity: 0.02; }
.grain--strong { opacity: 0.06; }

.orb {
  position: absolute;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0.2;
  filter: blur(80px);
  pointer-events: none;
  animation: orbDrift 12s var(--ease) infinite;
}
.orb--bright { opacity: 0.28; }

/* the soft transition from the band above */
.seam {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 120px;
  pointer-events: none;
}
.seam--from-dark {
  background: linear-gradient(180deg, #050505 0%, rgba(5, 5, 5, 0.55) 38%, rgba(250, 248, 245, 0) 100%);
}
.seam--from-paper {
  z-index: 3;
  background: linear-gradient(180deg, #faf8f5 0%, rgba(250, 248, 245, 0.5) 40%, rgba(5, 5, 5, 0) 100%);
}

/* ---------------------------------------------------------------- type */

.rule {
  width: 48px;
  height: 2px;
  background: linear-gradient(90deg, var(--accent), rgba(255, 122, 41, 0.15));
}

.heading {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
/* a second heading inside one section: reads as the next movement, not a new pitch */
.heading--sub { margin-top: clamp(18px, 2.2vw, 32px); }

h1, .h1 {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(2.5rem, 5vw, 4.5rem);
  line-height: 1.06;
  letter-spacing: -0.025em;
  text-wrap: balance;
}
.h2 {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(2rem, 3.34vw, 3rem);
  line-height: 1.12;
  letter-spacing: -0.02em;
  text-wrap: pretty;
}
.h2--sm {
  font-size: clamp(1.875rem, 2.78vw, 2.5rem);
  line-height: 1.15;
}
.h2--xl {
  font-size: clamp(2.125rem, 3.62vw, 3.25rem);
  line-height: 1.1;
  letter-spacing: -0.025em;
  text-wrap: balance;
}
.h3 {
  font-family: var(--display);
  font-weight: 500;
  font-size: 1.5rem;
  line-height: 1.25;
}
.h3--sm { font-size: 1.375rem; }
/* one of the three benefit headings wraps to two lines, so reserve two for all
   of them and the body copy starts on the same line across the row */
.card .h3:not(.h3--sm) { min-height: 3.75rem; }
.h3--sans {
  font-family: var(--body);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.35;
}

.pull {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.375rem, 1.95vw, 1.75rem);
  line-height: 1.35;
  letter-spacing: -0.01em;
  text-wrap: pretty;
}
.pull--sm { font-size: clamp(1.3rem, 1.81vw, 1.625rem); }
/* The drills line sits under the portrait-and-prose block and reads as ragged
   unless it ends where that block ends. At 26px it measured 1083 against the
   block's 1042, so the cap drops to 25px (26 x 1042/1083). Scoped to this one
   line: the other two .pull--sm run at full size. */
.pull--fit { font-size: clamp(1.3rem, 1.81vw, 1.5625rem); }

/* Two body steps only, 15px and 17px. The page used to run 14/15/16/17/18, five
   steps inside four pixels, which reads as noise rather than as hierarchy.
   Anything that needs to look bigger jumps clear of the pair, to 20 or above. */
.lede {
  font-size: 1.0625rem;
  line-height: 1.75;
  text-wrap: pretty;
}
.body { font-size: 1.0625rem; line-height: 1.75; text-wrap: pretty; }
.small { font-size: 0.9375rem; line-height: 1.7; text-wrap: pretty; }
.caption { font-size: 0.85rem; line-height: 1.6; }

.fg-2 { color: var(--fg-2); }
.fg-muted { color: var(--fg-muted); }
.fg-dim { color: var(--fg-dim); }
.ink-2 { color: var(--ink-2); }
.ink-muted { color: var(--ink-muted); }

/* Breaks that only hold in the wide layout. Below the split breakpoint the
   column is narrow enough that a forced break reads as a mistake. */
@media (max-width: 900px) { br.br-wide { display: none; } }

.measure { max-width: 68ch; }
.measure-wide { max-width: 78ch; }

/* --------------------------------------------------------------- buttons */

.btn {
  display: inline-flex;
  align-items: center;
  flex: none;
  gap: 0.6rem;
  padding: 0.85rem 2rem;
  border: none;
  min-height: 44px;
  border-radius: var(--pill);
  background: var(--accent);
  white-space: nowrap;
  color: var(--ink-1);
  font-family: var(--body);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-decoration: none;
  cursor: pointer;
  transition: all .35s var(--ease);
}
.btn:hover {
  color: var(--ink-1);
  transform: translateY(-2px);
  box-shadow: var(--accent-glow);
}
/* Was a &rarr; text glyph, which sat low (a flex centres its line box, not its
   ink) and rendered as a hairline next to a 600-weight label whatever weight it
   was given. An SVG at stroke 2.5 matches the label's weight and centres on its
   own box, so both problems go with the glyph. */
.btn .arrow { display: inline-flex; align-items: center; }

.btn--ghost {
  background: transparent;
  border: 1px solid var(--line-light);
  color: var(--accent-ink);
}
.btn--ghost:hover {
  color: var(--accent-ink);
  transform: none;
  box-shadow: none;
  border-color: var(--accent-line);
  background: rgba(255, 122, 41, 0.08);
}

/* ----------------------------------------------------------------- cards */

.card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: clamp(26px, 2.5vw, 36px);
  border-radius: var(--radius);
  transition: all .35s var(--ease);
}
.card--dark {
  gap: 16px;
  background: var(--surface);
  border: 1px solid var(--line-dark);
}
.card--light {
  gap: 18px;
  background: var(--paper-soft);
  border: 1px solid var(--line-light);
}
.card--hover:hover {
  transform: translateY(-4px);
  border-color: var(--accent-line);
  box-shadow: var(--accent-lift);
}
.card--static { transition: none; }

.grid {
  display: grid;
  gap: 24px;
  align-items: stretch;
}
.grid--280 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid--300 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.grid--240 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 20px; }
/* Two equal 1fr columns left 202px of dead air between a 398px portrait and the
   prose beside it. The photo column is now exactly the portrait's cap, so the
   prose starts where the picture ends. */
.grid--split {
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: clamp(40px, 4.4vw, 64px);
  align-items: center;
}
/* Mid-width band: as the window narrows the prose runs further and further past
   the bottom of the portrait, and in a two-column grid every one of those extra
   lines stays trapped in a narrow ribbon with empty page beside it. Between the
   phone stack and 995px the row stops being a grid and the portrait becomes a
   float, so the text sets beside the picture and then runs the full width of
   the container underneath it, which is where the dead space used to be. 995px
   is the ceiling because the portrait cap reaches its full 398px there, so the
   desktop layout above is untouched and the two rules change over together. */
@media (min-width: 721px) and (max-width: 995px) {
  .grid--split { display: block; }
  .grid--split::after { content: ""; display: block; clear: both; }
  /* Scoped through .grid--split rather than written bare: the .split__prose
     base rule sits further down the file at the same specificity and would
     otherwise win and keep the flex column. */
  .grid--split .split__prose { display: block; max-width: none; }
  .grid--split .split__prose > * + * { margin-top: 26px; }
  .grid--split .plate--portrait {
    float: left;
    width: var(--portrait-cap, 398px);
    margin: 0 clamp(28px, 3.6vw, 44px) 22px 0;
  }
  .split--reverse .plate--portrait {
    float: right;
    margin: 0 0 22px clamp(28px, 3.6vw, 44px);
  }
}
@media (min-width: 721px) {
  .grid--split { grid-template-columns: var(--portrait-cap, 398px) minmax(0, 1fr); }
  /* Joe's row is the mirror of Duke's, measured rather than stretched: prose on
     the spine's left edge (level with Duke's photo), photo's right edge level
     with the right edge of Duke's prose above. Same three widths in reverse
     order, so both rows end on the same x. */
  .grid--reverse {
    grid-template-columns: minmax(0, var(--prose-cap)) var(--portrait-cap, 398px);
    justify-content: start;
  }
}
.grid--steps {
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: clamp(32px, 3.3vw, 48px);
  align-items: start;
}

/* Three-item rows drop to two columns as the window narrows, which leaves the
   third item alone at the left edge with an empty column beside it. In the
   two-column regime only, the orphan takes the whole row and is centred at one
   column's width. Container queries rather than media queries because the
   regime is set by the grid's own width: n columns when W >= n*minmax + (n-1)*gap.
   Guarded by :last-child:nth-child(3) so it only ever fires on a 3-item grid. */
.grid--280   { container: g280 / inline-size; }
.grid--300   { container: g300 / inline-size; }
.grid--steps { container: gsteps / inline-size; }
/* The 2x2 rule below styles .grid--240 itself, and a container cannot query
   itself, so the container is its parent wrapper (same width, block child). */
.g240-host   { container: g240 / inline-size; }

/* Four safeguarding cards: auto-fit would pass through 3+1 on the way down,
   stranding the fourth. Force an even 2x2 across the whole band between the
   two- and four-column thresholds. 240px columns, 20px gap: two from 500px,
   three from 740px, four from 1020px. */
@container g240 (min-width: 500px) and (max-width: 1019.9px) {
  .grid--240 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* 280px columns, 24px gap: two columns from 584px, three from 888px. */
@container g280 (min-width: 584px) and (max-width: 887.9px) {
  .grid--280 > :last-child:nth-child(3) {
    grid-column: 1 / -1;
    justify-self: center;
    width: calc(50% - 12px);
  }
}
/* 300px columns, 24px gap: two from 624px, three from 948px. */
@container g300 (min-width: 624px) and (max-width: 947.9px) {
  .grid--300 > :last-child:nth-child(3) {
    grid-column: 1 / -1;
    justify-self: center;
    width: calc(50% - 12px);
  }
}
/* 280px columns, gap clamp(32px, 3.3vw, 48px). The gutter is 6.1vw a side, so
   the container is 0.878 * viewport and the gap is still 32px until roughly
   851px of container: two columns from 592px, three from 908px. */
@container gsteps (min-width: 592px) and (max-width: 907.9px) {
  .grid--steps > :last-child:nth-child(3) {
    grid-column: 1 / -1;
    justify-self: center;
    width: calc(50% - clamp(16px, 1.65vw, 24px));
  }
}

.chip {
  align-self: flex-start;
  padding: 0.4rem 0.9rem;
  border-radius: var(--pill);
  background: var(--accent-soft);
  border: 1px solid var(--accent-edge);
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-tint);
}
.chip--ink {
  padding: 0.3rem 0.7rem;
  background: rgba(255, 122, 41, 0.14);
  font-size: 0.6rem;
  color: var(--accent-ink);
}

.stars {
  display: flex;
  gap: 4px;
  font-size: 1.3rem;
  line-height: 1;
  color: var(--accent);
}

.avatar {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  flex: none;
  object-fit: cover;
  object-position: 50% 30%;
  background-color: #201a16;
  border: 1px solid var(--line-dark);
  overflow: hidden;
  font-size: 0;
}
.avatar--placeholder {
  background-image: repeating-linear-gradient(115deg, rgba(255, 255, 255, 0.06) 0 2px, transparent 2px 9px);
}

.byline {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: auto;
  padding-top: 8px;
}
.byline__name { font-weight: 600; color: var(--fg-1); }

/* photography that has not been shot yet */
.plate {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  background-color: #171310;
  background-image: repeating-linear-gradient(115deg, rgba(255, 255, 255, 0.045) 0 2px, transparent 2px 11px);
  border: 1px solid var(--line-dark);
}
.plate--portrait { aspect-ratio: 4 / 5; }
/* The portrait plates are capped, or a half-width 4:5 box renders ~600x750 and
   towers over the prose beside it. Pinned to the outer edge of their column so
   the cap reads as deliberate framing rather than a floating image. */
@media (min-width: 721px) {
  /* 398px x 1.25 = 498px, which is the height of the prose column beside it at
     the spine width, so the portrait's top and bottom meet the body text.
     Both portraits share the cap, so Joe's is the same size as Duke's. */
  .plate--portrait { width: 100%; max-width: var(--portrait-cap, 398px); justify-self: start; }
  .split--reverse .plate--portrait { justify-self: end; }
}
/* a plate with a real photograph in it: kill the placeholder hatching */
.plate--filled { background-image: none; }
.plate__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 30%;
}
.plate__note {
  position: absolute;
  left: 24px; right: 24px; bottom: 22px;
  font-family: var(--mono);
  font-size: 0.7rem;
  line-height: 1.7;
  letter-spacing: 0.04em;
  color: var(--fg-dim);
}

/* the per-letter wordmark caption, justified to the line above it */
.lockup { display: grid; grid-template-columns: max-content; gap: 2px; align-self: flex-start; }
.lockup__name {
  font-family: var(--display);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.lockup__sub {
  display: flex;
  justify-content: space-between;
  width: 0;
  min-width: 100%;
  font-weight: 600;
  line-height: 1.2;
  text-transform: uppercase;
}
.lockup__sub .sp { width: 0.32em; }

/* -------------------------------------------------------------- site nav */

.site-nav {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  padding: 22px var(--gutter);
  background: rgba(5, 5, 5, 0.55);
  backdrop-filter: blur(16px);
}
.site-nav .lockup { align-self: center; }
.site-nav .lockup__name { font-size: 1.25rem; line-height: 1; }
.site-nav .lockup__sub { font-size: 0.6rem; color: var(--fg-muted); }

@media (max-width: 480px) {
  .site-nav { gap: 14px; padding-block: 14px; }
  .site-nav .btn { padding: 0.7rem 1.15rem; font-size: 0.8rem; }
}

/* ----------------------------------------------------------------- hero */

.hero {
  position: relative;
  min-height: 900px;
  background: var(--black);
  overflow: hidden;
}
/* The photo and both scrims live in here, so capping this one box freezes the
   whole hero composition at its 1440px look and centres it. Past that width the
   page paints --black either side, which is what the scrim resolves to anyway. */
.hero__bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  max-width: var(--hero-cap);
  margin-inline: auto;
}
/* Past the cap the photo is sliced by the stage edge instead of bleeding off
   screen, so give it somewhere to go: a short fade into the same black. */
@media (min-width: 1441px) {
  .hero__bg::after {
    content: "";
    position: absolute;
    inset: 0 0 0 auto;
    width: 100px;
    background: linear-gradient(90deg, rgba(5, 5, 5, 0) 0%, var(--black) 92%);
    pointer-events: none;
  }
}

/* the orb is anchored to the hero, so it has to move with the stage */
.hero .orb { margin-left: max(0px, calc((100% - var(--hero-cap)) / 2)); }

/* The photograph bleeds off the right edge and dissolves into the page ground.
   The fade is a CSS mask, never baked into the JPEG, so it survives any panel width. */
.hero__photo {
  position: absolute;
  inset: 0 -24px 0 auto;
  width: 60%;
  background-image: url("assets/hero-jo.jpg");
  background-size: cover;
  background-position: 50% 44%;
  -webkit-mask-image: radial-gradient(ellipse 84% 100% at 62% 54%, #000 36%, rgba(0, 0, 0, 0.6) 64%, transparent 90%);
  mask-image: radial-gradient(ellipse 84% 100% at 62% 54%, #000 36%, rgba(0, 0, 0, 0.6) 64%, transparent 90%);
}

/* Solid ground under the whole text column, then a fast falloff so the photo
   emerges out of the black instead of sitting under a scrim. The 58% stop is
   measured past the widest element in the column, not estimated. */
/* The solid stop used to be 58% of the photo's width while the text column's
   right edge is a different formula entirely, so between 900px and full screen
   the two drifted apart and the subscriber count slid off the black. This
   tracks the column instead: solid to wherever the column ends, then a fixed
   280px falloff, so the fade sits in the same place relative to the text at
   every width. `--scrim-solid` is measured from the photo's left edge, which is
   the origin of this gradient and is inset once past --hero-cap. */
.hero__scrim-x {
  --col-left: max(var(--gutter), (100vw - var(--spine)) / 2);
  --col-w: min(56vw, var(--hero-content));
  --col-right: calc(var(--col-left) + var(--col-w));
  --bg-left: max(0px, (100vw - var(--hero-cap)) / 2);
  --scrim-solid: calc(var(--col-right) - var(--bg-left) + 16px);
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg,
    #050505 0%,
    #050505 var(--scrim-solid),
    rgba(5, 5, 5, 0.80) calc(var(--scrim-solid) + 56px),
    rgba(5, 5, 5, 0.42) calc(var(--scrim-solid) + 118px),
    rgba(5, 5, 5, 0.13) calc(var(--scrim-solid) + 180px),
    rgba(5, 5, 5, 0) calc(var(--scrim-solid) + 250px));
}
.hero__scrim-y {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(5, 5, 5, 0.42) 0%, rgba(5, 5, 5, 0) 22%, rgba(5, 5, 5, 0) 68%, rgba(5, 5, 5, 0.9) 100%);
}

@media (min-resolution: 1.5dppx) {
  .hero__photo { background-image: url("assets/hero-jo@2x.jpg"); }
}

/* the orb sits above the scrim, or extending the black kills the warm glow */
.hero .orb { z-index: 7; }

.hero__inner {
  position: relative;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  /* The hero used to run 73px short of its own min-height, which is the dead
     black space under Don. The gap spreads that back through the column. */
  gap: 40px;
  width: 56%;
  max-width: 800px;
  /* The photo stays full bleed, but the text column shares its left edge with
     every .container below it. Under 1440px that is just the gutter; past it,
     half the leftover width, which is exactly where .container starts. */
  margin-inline-start: max(var(--gutter), calc((100% - var(--spine)) / 2));
  padding: clamp(44px, 5.4vw, 78px) 0 clamp(44px, 4.4vw, 64px);
  text-align: left;
}
.hero__eyebrow {
  white-space: nowrap;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--accent);
}
.hero__kicker {
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.25rem, 1.8vw, 1.6rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
}
.hero__blurb {
  max-width: 34ch;
  font-size: clamp(1.0625rem, 1.28vw, 1.25rem);
  line-height: 1.55;
  color: var(--fg-2);
  text-wrap: pretty;
}
.hero__cta {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
  margin-top: 6px;
}
.hero__cta p {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--fg-2);
}

.ticks {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 22px;
  width: 100%;
  /* Same width as the proof row below, so the last tick ends level with the
     subscriber count instead of stopping short of it. Both are pinned to
     --hero-content, which is also what the scrim's solid stop tracks: these two
     rows are the widest things in the column, so narrowing them is what gives
     the photograph its left side back. */
  max-width: var(--hero-content);
  margin-top: 12px;
}
/* The mark centres on the two-line label rather than hanging off the first line,
   which is Duke's "line up between the text". */
.tick {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.45;
}
.tick__mark { font-size: 1.5rem; line-height: 1; color: var(--accent); flex: none; }
/* The middle label is the shortest, so it has two defensible homes and both
   look wrong: flush left in its column puts the three tick marks on an even
   rhythm but leaves a wide hole after its text, and centred in the column
   evens the gaps between the text blocks but throws the marks out. This sits
   halfway between the two. A transform rather than a margin, so it cannot
   change the column's available width and re-wrap the label; a percentage, so
   it scales with the label instead of being a magic pixel count. Only while
   the three are side by side: in the stacked layout it would be the one odd
   item in a left-aligned list. Extended from 901px to 601px on 2026-09-10, when
   the tablet band went back to three across and inherited the same wrong-looking
   middle. */
@media (min-width: 601px) {
  .tick:nth-child(2) { justify-self: start; transform: translateX(20%); }
}

/* Proof block: Don on the left, a hairline, the subscriber count anchoring the
   right end of the row where the photo starts to come through. */
.hero__proof {
  display: flex;
  align-items: flex-start;
  gap: 22px;
  width: 100%;
  max-width: var(--hero-content);
  margin-top: 12px;
  padding-top: 34px;
  border-top: 1px solid var(--line-dark);
}
.hero__proof-rule {
  width: 1px;
  align-self: stretch;
  background: var(--line-dark);
  flex: none;
}
.hero__quote {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  min-width: 0;
  flex: 1 1 auto;
  text-align: left;
}
.hero__quote-body { min-width: 0; }
.hero__quote .stars { font-size: 1.3rem; margin-bottom: 7px; }
.hero__quote blockquote { margin: 0 0 6px; }
.hero__quote figcaption { margin: 0; }

/* The avatar and the count are sized and offset to sit centred on the two lines
   of quote text, not on the whole block. Two 0.9rem lines occupy 46px of line
   box but only 36px of glyph, so aligning to the box reads as misaligned. */
.hero__quote .avatar {
  width: 56px;
  height: 56px;
  margin-top: 17px;
}
/* the quote only holds its designed line break where there is room for it */
.hero__quote-l1 { white-space: normal; }
@media (max-width: 1200px) {
  .hero__quote-br { display: none; }
}
@media (min-width: 1201px) {
  .hero__quote-l1 { white-space: nowrap; }
}

.stat {
  display: inline-flex;
  align-items: stretch;
  gap: 0.9rem;
  align-self: flex-start;
  height: 48px;
  margin-top: 21px;
  flex: none;
}
.stat__play {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: stretch;
  width: 56px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.13);
  border: 1px solid rgba(255, 255, 255, 0.22);
  flex: none;
}
.stat__play::before {
  content: "";
  width: 0; height: 0;
  border-left: 14px solid rgba(255, 255, 255, 0.82);
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  margin-left: 3px;
}
/* max-content column so the caption justifies to the number's width rather than
   the number shrinking to the caption's. width:0 keeps the caption out of the
   intrinsic sizing; min-width:100% then stretches it to the column. */
.stat__body {
  display: grid;
  grid-template-columns: max-content;
  align-content: center;
  gap: 3px;
  text-align: left;
}
.stat__n {
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.stat__label {
  width: 0;
  min-width: 100%;
  font-size: 0.68rem;
  color: var(--fg-muted);
}

/* Below the two-column breakpoint the photograph goes full width behind the
   text and fades downward instead of sideways. The dedicated mobile crop comes
   once this slot has been measured on a real device. */
@media (max-width: 1200px) and (min-width: 901px) {
  .hero__inner { width: 64%; }
  /* the column widens here, so the scrim's solid stop has to widen with it */
  .hero__scrim-x { --col-w: min(64vw, var(--hero-content)); }
  .hero__proof { gap: 18px; }
  .stat__n { font-size: 1.3rem; }
  /* Below 1200px the text column keeps its width while the photo box shrinks
     with the viewport, so the scrim's solid black eats further and further into
     the frame: at 920px it swallowed everything but a sliver of Jo's right arm.
     The photo is height-constrained under `cover` here, so the image is ~195px
     wider than its box and there is that much slack to slide. This walks the
     crop from the design's 50% at 1200px to roughly 6% at 900px, which moves her
     out of the black instead of narrowing the column and reflowing the text.
     `min()` caps it at 0% so the crop can never run past the image's left edge
     and tile. Continuous at 1200px (the calc lands back on 50%), so there is no
     jump. Verified at 905, 920, 1000, 1100, 1195 and 1440, 2026-09-10. */
  .hero__photo {
    background-position-x: min(0%, calc(50% + (1200px - 100vw) * 0.29));
  }
}

@media (max-width: 900px) {
  .hero { min-height: 0; }
  .hero__photo {
    inset: 0;
    width: 100%;
    background-position: 50% 12%;
    -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 34%, rgba(0, 0, 0, 0.45) 62%, transparent 86%);
    mask-image: linear-gradient(180deg, #000 0%, #000 34%, rgba(0, 0, 0, 0.45) 62%, transparent 86%);
  }
  .hero__scrim-x {
    background: linear-gradient(180deg, rgba(5, 5, 5, 0.25) 0%, rgba(5, 5, 5, 0.55) 34%, #050505 62%, #050505 100%);
  }
  .hero__scrim-y { background: none; }
  /* the orb goes back under the photo on mobile, or it washes her face orange */
  .hero .orb { z-index: 2; }
  .hero__bg { z-index: 5; }
  .hero__inner {
    width: 100%;
    max-width: none;
    gap: 24px;
    margin-inline-start: 0;
    padding-inline: var(--gutter);
    /* Was clamp(200px, 46vw, 340px), which reserved a band of photograph above
       the eyebrow. On a phone the image is height-constrained under `cover`, so
       that band was the top of the frame (the stage wall above her head) rather
       than anything of the subject, and it pushed the headline most of a screen
       down. Shrinking the hero scales the whole composition up together: the
       eyebrow sits just under the header and her face still emerges to the
       right of the text. Verified on a 430px viewport, 2026-09-10. */
    padding-top: clamp(36px, 9vw, 72px);
  }
  .hero__blurb { max-width: 40ch; }
  .ticks { grid-template-columns: 1fr; gap: 14px; }
  .hero__proof { flex-direction: column; gap: 22px; max-width: none; }
  .hero__proof-rule { display: none; }
  .stat { margin-top: 0; }
}

/* Phone only. Under `cover` the frame is height-constrained here, so the whole
   image height maps onto the hero height and background-position-y does nothing;
   lifting the layer is the only vertical lever there is, and it moves her head
   up by exactly this many pixels at fixed scale. The bottom edge it exposes is
   already past the mask's transparent stop. Stops at 600px because by tablet
   width the headline runs on one line and a lift this size puts her face behind
   it. Verified at 430px and 800px, 2026-09-10. */
@media (max-width: 600px) {
  .hero__photo { transform: translateY(clamp(-120px, -24vw, -70px)); }
}

/* Tablet band. Two fixes that only apply between the desktop breakpoint and the
   phone rules, so nothing above 900px moves.

   1. The photo. Here the frame is width-constrained under `cover`, so the image
      overflows vertically and `background-position-y` is a real lever (unlike on
      a phone, where it does nothing and only a transform moves the layer). The
      inherited 12% left a band of stage wall above her head and pushed her face
      below the headline. 45% lifts her about 80px: head fully in frame, the
      headline crossing at her shoulders, the stick in shot. The drum kit cannot
      come in at this width. The vertical scrim goes fully solid at 62% of the
      hero, so anything lower is painted over whatever the crop shows, and
      lifting far enough to clear that band cuts the top of her head.
   2. The ticks. Three across, as on desktop, rather than the phone's stack. The
      column is full width here, so they fit down to 601px.

   Verified at 620, 700 and 886, 2026-09-10. */
@media (max-width: 900px) and (min-width: 601px) {
  .hero__photo { background-position-y: 45%; }
  .ticks { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px; max-width: none; }
}

@media (max-width: 480px) {
  .hero__quote-l1 { white-space: normal; }
  .hero__eyebrow { white-space: normal; }
  .hero__quote .avatar { width: 46px; height: 46px; margin-top: 14px; }
}

/* --------------------------------------------------------------- problem */

.pains {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 26px;
  max-width: 62ch;
}
.pains li {
  display: flex;
  align-items: flex-start;
  gap: 18px;
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--ink-2);
  text-wrap: pretty;
}
.pains li::before {
  content: "";
  flex: none;
  width: 18px;
  height: 2px;
  margin-top: 15px;
  background: var(--accent-ink);
}

/* -------------------------------------------------------------- solution */

/* The drills line had 64px of air above it and 132px below, because the gap
   above is the inner stack's and the gap below is the container's. Both are the
   stack's number now, which lifts Joe's block by the difference, and the same
   difference comes off the section's bottom so the block does not simply slide
   into the space underneath. Taking the whole 68px off the bottom made the
   section end early against its neighbour, so the bottom gives back half:
   68px of lift, a 106px bottom at 1569, 58 and 88 at 1200. Written against
   --band-y and the two clamps rather than as measured pixels, so it holds at
   every width. */
.solution-stack { gap: var(--stack-64); }
.band--solution { padding-bottom: calc(var(--band-y) - (var(--band-gap-lg) - var(--stack-64)) / 2); }

.split { display: flex; flex-direction: column; gap: 26px; }
/* Closing the gap beside the portrait handed the prose the whole 802px column,
   which runs past 100 characters a line. Capped back into the readable band;
   the leftover sits outside the text block as margin rather than inside it as a
   hole, which is the thing that read as dead space. */
.split__prose { display: flex; flex-direction: column; gap: 26px; max-width: var(--prose-cap); }

/* Joe's portrait sits right of the prose on wide screens */
@media (min-width: 721px) {
  .split--reverse .plate { order: 2; }
}

/* Single column: both portraits follow their own prose. Duke's photo used to
   land straight under the section headline, which is about lessons rather than
   about him, so it arrived with no caption and no context. Photo-after-prose
   gives both blocks the same shape and reaches the reader already introduced. */
@media (max-width: 720px) {
  .grid--split .split__prose { order: 1; }
  .grid--split .plate--portrait { order: 2; }
}

/* --------------------------------------------------------------- process */

.step { position: relative; display: flex; flex-direction: column; gap: 16px; }
.step__n {
  position: relative;
  font-family: var(--display);
  font-weight: 500;
  font-size: 4rem;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--accent);
}
.step__thread {
  position: absolute;
  top: 34px;
  left: 84px;
  right: -48px;
  height: 1px;
  background: linear-gradient(90deg, rgba(255, 122, 41, 0.45), rgba(255, 122, 41, 0.05));
  pointer-events: none;
}
@media (max-width: 900px) { .step__thread { display: none; } }

/* ---------------------------------------------------------- testimonials */

.feature-video { position: relative; width: 100%; }
.feature-video video {
  width: 100%;
  display: block;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  background: #101010;
  border: 1px solid var(--line-dark);
}
.feature-video__play {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(64px, 8vw, 96px);
  height: clamp(64px, 8vw, 96px);
  padding: 0;
  border: 1px solid var(--accent-line);
  border-radius: 50%;
  background: rgba(255, 122, 41, 0.92);
  cursor: pointer;
  transition: all .35s var(--ease);
}
.feature-video__play:hover {
  transform: translate(-50%, -50%) scale(1.06);
  box-shadow: var(--accent-glow);
}
.feature-video__play::before {
  content: "";
  width: 0; height: 0;
  border-left: 26px solid var(--ink-1);
  border-top: 16px solid transparent;
  border-bottom: 16px solid transparent;
  margin-left: 7px;
}
.feature-video.is-playing .feature-video__play { display: none; }

/* -------------------------------------------------------------- compare */

/* The closing lines used to sit under a centred card, so the section had three
   left edges (heading 148, card 390, text 148) and an empty bottom-right
   quadrant. The card now holds the spine's left edge and the closing lines sit
   beside it, which fills that corner and takes ~160px off the section's height.
   Card cap is set by the longest row label at its natural width: 348px of text
   plus 16px padding needs 364px, and 740 - 2 border - 60 padding - 300 marks
   leaves 378, so nothing in column one wraps. */
.compare-split { display: grid; gap: clamp(40px, 4.4vw, 64px); }
@media (min-width: 1360px) {
  .compare-split {
    grid-template-columns: minmax(0, var(--compare-cap)) minmax(0, 1fr);
    align-items: center;
  }
}
.compare-closer { gap: 20px; max-width: 66ch; }

.compare-card {
  width: 100%;
  max-width: var(--compare-cap);
  margin-inline: 0;
  padding: clamp(20px, 2.4vw, 34px) clamp(18px, 2.2vw, 30px);
  background: var(--paper-soft);
  border: 1px solid var(--line-light);
  border-radius: var(--radius);
}
.compare {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}
.compare col.mark { width: 150px; }
.compare th,
.compare td { padding: 22px 8px; text-align: center; }
.compare thead th { padding: 14px 8px; }
.compare th[scope="row"] {
  padding: 22px 16px 22px 0;
  text-align: left;
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.5;
  color: var(--ink-2);
  border-bottom: 1px solid var(--line-light);
  text-wrap: pretty;
}
.compare thead .lbl { padding: 14px 12px 14px 0; }
.compare .col-head {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(10, 10, 10, 0.66);
}
.compare .col-head--here {
  color: var(--accent-ink);
  background: var(--accent-wash);
  border-left: 1px solid var(--accent-line);
  border-right: 1px solid var(--accent-line);
  border-top: 1px solid var(--accent-line);
  border-top-left-radius: 0.75rem;
  border-top-right-radius: 0.75rem;
}
.compare td.here {
  background: var(--accent-wash);
  border-left: 1px solid var(--accent-line);
  border-right: 1px solid var(--accent-line);
  border-bottom: 1px solid var(--line-light);
}
.compare td.usual { border-bottom: 1px solid var(--line-light); }
.compare tbody tr:last-child td.here {
  border-bottom: 1px solid var(--accent-line);
  border-bottom-left-radius: 0.75rem;
  border-bottom-right-radius: 0.75rem;
}
.compare tbody tr:last-child th[scope="row"],
.compare tbody tr:last-child td.usual { border-bottom: 0; }
.compare .mk { font-size: 1.65rem; line-height: 1; color: var(--accent-ink); }
.compare .mk--dim { color: rgba(10, 10, 10, 0.62); }

@media (max-width: 560px) {
  .compare-card { padding: 18px 14px; }
  .compare col.mark { width: 68px; }
  .compare .mk { font-size: 1.35rem; }
  .compare th[scope="row"] { font-size: 0.9375rem; padding-right: 10px; }
  .compare th, .compare td { padding: 16px 4px; }
}

/* ------------------------------------------------------------------ faq */

.faq { display: flex; flex-direction: column; max-width: var(--spine-narrow); }
.faq__item { border-bottom: 1px solid var(--line-light); }
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  width: 100%;
  padding: 24px 4px;
  border: none;
  background: transparent;
  text-align: left;
  font-family: var(--body);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.5;
  color: var(--ink-1);
  cursor: pointer;
  transition: color .35s var(--ease);
}
.faq__q:hover { color: var(--accent-ink); }
.faq__q span { text-wrap: pretty; }
.faq__icon {
  flex: none;
  font-size: 1.35rem;
  font-weight: 400;
  line-height: 1;
  color: var(--accent-ink);
  transition: transform .35s var(--ease);
}
.faq__q[aria-expanded="true"] .faq__icon { transform: rotate(45deg); }
.faq__a {
  overflow: hidden;
  max-height: 0;
  transition: max-height .35s var(--ease);
}
.faq__a p {
  max-width: 68ch;
  padding: 0 48px 26px 4px;
  font-size: 1.0625rem;
  line-height: 1.75;
  color: var(--ink-2);
  text-wrap: pretty;
}
@media (max-width: 560px) { .faq__a p { padding-right: 4px; } }

/* ------------------------------------------------------------ guarantee */

.guarantee {
  display: flex;
  flex-direction: column;
  gap: 26px;
  max-width: 920px;
  margin-inline: auto;
  padding: clamp(32px, 3.9vw, 56px);
  border-radius: var(--radius);
  background: rgba(255, 122, 41, 0.05);
  border: 1px solid var(--accent-line);
}

/* ------------------------------------------------------------ final CTA */

.closer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
  max-width: 820px;
  margin-inline: auto;
  text-align: center;
}
/* the card and the closer are both wider than their text wants to be */
.closer .lede { max-width: 58ch; }
.guarantee .lede { max-width: 62ch; }

.closer__actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Matches the space above the button, which is .closer's 28px gap plus the
     32px margin below. Both are fixed rather than clamped, so one fixed value
     here stays symmetrical at every width. */
  gap: 60px;
  margin-top: 32px;
}
.closer__actions a.wa {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* --------------------------------------------------------------- footer */

.site-footer { padding-block: clamp(64px, 6.7vw, 96px) clamp(72px, 7.5vw, 108px); }
.site-footer .lockup__name { font-size: 1rem; color: var(--fg-2); }
.site-footer .lockup__sub { font-size: 0.55rem; color: rgba(255, 255, 255, 0.50); }
.footer__cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 40px;
}
.footer__col { display: flex; flex-direction: column; gap: 12px; }
.footer__col p:first-child { font-size: 0.9375rem; font-weight: 600; line-height: 1.4; color: var(--fg-2); }
.footer__col p + p { max-width: 52ch; font-size: 0.8rem; line-height: 1.7; color: var(--fg-dim); text-wrap: pretty; }
.footer__legal {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 0.8rem;
  color: var(--fg-dim);
}
.footer__legal a {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding-inline: 4px;
  margin-inline: -4px;
  color: var(--fg-muted);
}
.footer__legal a:hover { color: var(--accent); }

/* ----------------------------------------------------------- sticky bar */

.sticky-cta {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 60;
  display: none;
  padding: 12px 14px calc(12px + env(safe-area-inset-bottom));
  background: rgba(5, 5, 5, 0.82);
  backdrop-filter: blur(16px);
  border-top: 1px solid var(--line-dark);
  opacity: 0;
  pointer-events: none;
  transition: opacity .35s var(--ease);
}
.sticky-cta.is-on { opacity: 1; pointer-events: auto; }
.sticky-cta .btn {
  display: flex;
  justify-content: center;
  width: 100%;
  min-height: 48px;
}
.sticky-cta .btn:hover { transform: none; }

@media (max-width: 640px) {
  .sticky-cta { display: block; }
}

