/* ═══════════════════════════════════════════════════════════════════
   Kerf Delay

   THE IDEA IN ONE LINE
   Two colours carry meaning and nothing else does. Pink is the delay,
   violet is the dry signal — the same language the plugin uses in its
   own graphs. Everything else on the page is charcoal and off-white,
   so when pink appears you know what it's telling you.

   The palette values are lifted from Source/Theme.h, not invented.

   1  Tokens
   2  Reset and base
   3  Type primitives
   4  Buttons
   5  Header, buy bar, thumb bar
   6  Placeholders
   7  Hero
   8  Proof — one box, three sources
   9  Sections 01–03
   10 See it, reviews
   11 Specs and buy
   12 Footer
   13 Reveals
   14 Responsive
   15 Reduced motion, print
   ═══════════════════════════════════════════════════════════════════ */


/* ═══ 1 ═══ Tokens ════════════════════════════════════════════════ */

:root {
  /* Ground. Theme.h's bg0 is #111417; the page sits one step below it
     so the faceplate reads as an object on a surface. */
  --bg:        #0b0e11;
  --bg-2:      #101317;   /* panel sections */
  --surface:   #14171b;   /* cards, placeholders, players */
  --surface-2: #1b1e23;   /* wells inside a surface */
  --line:      #23272e;   /* hairlines */
  --line-2:    #333842;   /* hairlines on a surface */

  /* Ink */
  --fg:        #e9eef5;   /* 16.6:1 */
  --fg-2:      #c3c9d3;   /* prose — 11.6:1 */
  --fg-3:      #8b929e;   /* captions, labels — 6.2:1, 5.7:1 on --surface */

  /* Theme.h's textDim. The quietest colour that still clears 4.5:1 on
     every ground on this page, including --surface. Anything small and
     grey uses this, not --fg-4. */
  --fg-dim:    #7f8794;   /* 5.3:1, 5.0:1 on --surface */

  /* Below the small-text threshold on purpose. Display sizes and
     drawn marks only — never body copy, never a label. */
  --fg-4:      #656d7c;   /* 3.7:1 — large text only */

  /* The two signal colours, straight out of the plugin.
     PINK is the delay. VIOLET is the dry. They are never decorative and
     they never appear on anything that isn't one of those two things. */
  --wet:       #ff5fa8;   /* 6.9:1 */
  --wet-soft:  rgba(255, 95, 168, 0.14);
  --dry:       #9b8cff;   /* 7.0:1 */
  --dry-soft:  rgba(155, 140, 255, 0.14);

  /* Sale red. The only red on the page, and it means exactly one thing:
     the struck-through old price. Kept off everything else. */
  --sale:      #f2555a;

  /* Headline decay. Line 1 is the source; each line after it is a
     repeat, one step quieter. */
  --ln-1: var(--fg);
  --ln-2: #949cab;        /* 7.0:1 */
  --ln-3: var(--fg-4);    /* 3.8:1 — only ever used at display size */

  /* Type. Three faces, three jobs, no overlap.
       Geist       — big titles only, nothing under 1.5rem
       Geist Mono  — nav, buttons, labels, tags, all numeric data
       Inter       — prose and everything else                       */
  --f-display: 'Geist', system-ui, -apple-system, sans-serif;
  --f-mono:    'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  --f-body:    'Inter', system-ui, -apple-system, sans-serif;

  --t-xs:  0.6875rem;
  --t-sm:  0.8125rem;
  --t-md:  0.9375rem;
  --t-lg:  1.0625rem;
  --t-xl:  1.375rem;

  /* Wider than the 1200–1280px both reference templates use. At 1240 the
     page read as a narrow column stranded in the middle of a big monitor.
     Long-form text doesn't get harder to read as this grows, because the
     lede and every .prose paragraph are capped in ch independently. */
  --wrap: 1560px;
  --gut:  clamp(20px, 4vw, 64px);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  /* Ported verbatim from the energy-drink template's motion — every
     fade-up and line reveal on that page uses this curve. */
  --ease-gz: cubic-bezier(0.25, 0.4, 0.25, 1);
}


/* ═══ 2 ═══ Reset and base ════════════════════════════════════════ */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 80px;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg-2);
  font-family: var(--f-body);
  font-size: var(--t-md);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg, video { display: block; max-width: 100%; }

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  background: var(--fg);
  color: var(--bg);
  padding: 12px 18px;
  font-family: var(--f-mono);
  font-size: var(--t-sm);
}
.skip:focus { left: 12px; top: 12px; }

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


/* Vertical rhythm is set per section in §9, not here. One uniform
   section padding is the fastest way to make a page look machine-set,
   so these are only the fallbacks. */
.sec { position: relative; padding-block: 88px; }

/* Panel sections. There are exactly two — 02 and 06. Two dark movements
   against the page ground is the right amount; a third makes it stripey. */
.panel {
  background: var(--bg-2);
  border-block: 1px solid var(--line);
}


/* ═══ 3 ═══ Type primitives ═══════════════════════════════════════ */

.display {
  font-family: var(--f-display);
  font-weight: 300;
  letter-spacing: -0.035em;
  line-height: 0.98;
  margin: 0;
  text-wrap: balance;
}

.display .ln { display: block; }
.ln--1 { color: var(--ln-1); }
.ln--2 { color: var(--ln-2); }
.ln--3 { color: var(--ln-3); }

.h2 { font-size: clamp(2rem, 4vw, 3.5rem); }

/* Everything small is Geist Mono. */
.eyebrow,
.head__nav a,
.btn,
.ab__tag, .ab__time, .ab__src, .ab__status,
.ph__dim,
.vf__cap, .vf__status,
.points__n, .hero__trust,
.models__n, .ticks__k,
.spec dd, .price,
.reviews__label,
.buybar__price, .foot__copy,
.abox__head, .abox__foot, .legend {
  font-family: var(--f-mono);
  font-weight: 400;
  font-variant-ligatures: none;
}

.eyebrow {
  font-size: var(--t-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin: 0 0 16px;
}

.lede {
  font-size: clamp(1.0625rem, 1.6vw, var(--t-xl));
  line-height: 1.5;
  color: var(--fg-2);
  margin: 0 0 26px;
  max-width: 46ch;
}

.prose p { margin: 0 0 18px; max-width: 62ch; }
.prose p:last-child { margin-bottom: 0; }


/* ═══ 4 ═══ Buttons ═══════════════════════════════════════════════ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 22px;
  font-size: var(--t-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: 2px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .18s var(--ease),
              border-color .18s var(--ease),
              color .18s var(--ease);
}

/* The primary action is near-white, not pink. Pink means one thing on
   this page and "buy" isn't it. */
.btn--solid {
  background: var(--fg);
  color: var(--bg);
  border-color: var(--fg);
}
.btn--solid:hover { background: #fff; border-color: #fff; }

.btn--ghost {
  background: transparent;
  color: var(--fg);
  border-color: var(--line-2);
}
.btn--ghost:hover { border-color: var(--fg-3); background: rgba(255, 255, 255, .03); }

.btn--sm { padding: 10px 16px; font-size: var(--t-xs); }
.btn--lg { padding: 17px 30px; }

.btn-row { display: flex; flex-wrap: wrap; gap: 12px; }


/* ═══ 5 ═══ Header, buy bar, thumb bar ════════════════════════════ */

.head {
  position: relative;
  z-index: 20;
  border-bottom: 1px solid var(--line);
}

.head__in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  min-height: 68px;
}

.wordmark {
  font-family: var(--f-display);
  font-weight: 400;
  font-size: var(--t-lg);
  letter-spacing: -0.02em;
  color: var(--fg);
  text-decoration: none;
}

.head__nav { display: flex; gap: 28px; }

.head__nav a {
  font-size: var(--t-xs);
  letter-spacing: 0.14em;
  color: var(--fg-3);
  text-decoration: none;
  transition: color .18s var(--ease);
}
.head__nav a:hover { color: var(--fg); }

.buybar {
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: 60;
  background: rgba(11, 14, 17, 0.9);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
  transform: translateY(-100%);
  transition: transform .32s var(--ease);
}
.buybar.is-in { transform: none; }

.buybar__in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  min-height: 60px;
}

.buybar__id { display: flex; align-items: baseline; gap: 14px; }

.buybar__name {
  font-family: var(--f-display);
  font-weight: 400;
  font-size: var(--t-md);
  color: var(--fg);
}
.buybar__price { font-size: var(--t-sm); color: var(--fg-3); }

.buybar__acts { display: flex; gap: 10px; }

.thumb {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 60;
  display: none;
  gap: 10px;
  padding: 12px var(--gut) calc(12px + env(safe-area-inset-bottom));
  background: rgba(11, 14, 17, 0.94);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
  transform: translateY(110%);
  transition: transform .32s var(--ease);
}
.thumb .btn { flex: 1; }
.thumb.is-in { transform: none; }


/* ═══ 6 ═══ Placeholders ══════════════════════════════════════════
   A considered empty state: hairline frame, registration ticks, the
   exact pixel size in mono, and a sentence saying what belongs there.
   Swap for an <img> at the same ratio — see NOTES.md.               */

.ph {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: var(--ar, 16 / 9);
  padding: 24px;
  background:
    repeating-linear-gradient(
      -45deg,
      transparent 0 9px,
      rgba(255, 255, 255, 0.016) 9px 10px
    ),
    var(--surface);
  border: 1px solid var(--line-2);
  border-radius: 2px;
  overflow: hidden;
}

/* Registration marks, not decoration — they say "this frame is the
   exact size of the thing that goes here". */
.ph::before, .ph::after {
  content: "";
  position: absolute;
  width: 13px; height: 13px;
  border: 1px solid var(--fg-4);
  opacity: .55;
}
.ph::before { top: 10px;    left: 10px;  border-right: 0; border-bottom: 0; }
.ph::after  { bottom: 10px; right: 10px; border-left: 0;  border-top: 0;    }

.ph__txt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
  max-width: 42ch;
}

.ph__dim {
  font-size: var(--t-xs);
  letter-spacing: 0.14em;
  color: var(--fg-3);
  padding: 5px 11px;
  border: 1px solid var(--line-2);
  border-radius: 2px;
}

.ph__desc { font-size: var(--t-sm); line-height: 1.5; color: var(--fg-dim); }



/* ═══ 7 ═══ Hero ══════════════════════════════════════════════════ */

/* Top padding kept small so the eyebrow starts just above the second row
   of the background dot grid (rows sit every 26px). */
.hero { padding-block: clamp(14px, 1.6vw, 22px) clamp(56px, 6vw, 96px); overflow: hidden; }

/* The hero is the one place the page is allowed to breathe. Moving the
   outcome strip into the next section paid for all of this. */
.hero .eyebrow { margin-bottom: 26px; }

/* Dot field. Fades out before the fold so it never competes with the
   screenshot. */
.dots {
  position: absolute;
  inset: 0 0 auto 0;
  height: 640px;
  pointer-events: none;
  background-image: radial-gradient(rgba(255, 255, 255, .075) 1px, transparent 1px);
  background-size: 26px 26px;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 92%);
          mask-image: linear-gradient(180deg, #000 0%, transparent 92%);
}

.hero .wrap { position: relative; z-index: 1; }

/* Sized to the column it sits in, not to the viewport. The old
   clamp(3rem, 10vw, 7.25rem) ran to 116px across the full page width and
   ate the entire fold on its own. */
/* Capped so the longest line — "The industry standard", 21 characters —
   fits its column on one line. If it wraps, the wrapped part inherits its
   parent's colour and the three-step decay reads as four lines going
   1-2-2-3, which looks like a mistake. Check this if you edit the h1. */
.hero__h1 {
  font-size: clamp(2.5rem, 4.4vw, 4.25rem);
  line-height: 1.02;
  letter-spacing: -0.04em;
  margin-bottom: 34px;
}

/* Copy left, video right. The video column STRETCHES to the copy's full
   height and the frame fills it, so the box is exactly as tall as the
   text beside it rather than a short 16:9 panel floating in whitespace. */
.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(28px, 3.5vw, 56px);
  align-items: center;
}

/* The hero is a still of the plugin. It fills the column width, keeps its
   own aspect ratio, and the grid centres it against the copy. */
.hero__shot { margin: 0; }
.hero__shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line-2);
  border-radius: 4px;
}

/* Extend the image leftward into the empty space beside the paragraph,
   right edge pinned: width grows and a matching negative margin shifts it
   left, so only the left edge moves. Wide screens only. */
@media (min-width: 1200px) {
  .hero__shot {
    --hv-extend: clamp(30px, 3.5vw, 80px);
    width: calc(100% + var(--hv-extend));
    margin-left: calc(-1 * var(--hv-extend));
  }
}

/* The hero paragraph is a full 60 words, so it runs at body size on a
   wider measure. At lede size it would be ten lines and tower over the
   video next to it. */
.hero__copy .lede {
  max-width: 56ch;
  margin-bottom: 36px;
  font-size: clamp(0.9375rem, 1.15vw, 1.0625rem);
  line-height: 1.7;
  color: var(--fg-2);
}

/* The big price sign: the old $79 scratched out in red, the $39 large
   beside it. Sits below the buttons. */
.hero__price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 16px;
  margin: 26px 0 0;
  font-family: var(--f-mono);
  line-height: 1;
}
.hero__price-was {
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  color: var(--fg-dim);
  text-decoration: line-through;
  text-decoration-color: var(--sale);
  text-decoration-thickness: 3px;
}
.hero__price-now {
  font-size: clamp(2.5rem, 4.6vw, 3.75rem);
  letter-spacing: -0.03em;
  color: var(--fg);
}
.hero__trust {
  margin: 18px 0 0;
  font-size: var(--t-xs);
  letter-spacing: 0.04em;
  color: var(--fg-3);
  line-height: 1.7;
}



/* ═══ 8 ═══ Proof — one box, three sources ════════════════════════ */

.proof { padding-block: 72px; }

/* Four outcomes as one strip. It opens this section rather than closing
   the hero — it's the first thing you meet after scrolling, and keeping
   it out of the hero bought that section ~130px of breathing room. */
.points {
  list-style: none;
  margin: 0 0 64px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.points li {
  padding: 18px 24px 20px 0;
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--fg-2);
}

.points__n {
  display: block;
  margin-bottom: 8px;
  font-family: var(--f-mono);
  font-size: var(--t-xs);
  color: var(--fg-dim);
}

.proof__in {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 80px);
  align-items: start;
}

/* This column is short copy in a wide half, so it runs bigger than a
   normal section heading — but still under the hero h1, which has to
   stay the largest thing on the page. */
.proof__lede .h2 { font-size: clamp(2.25rem, 4.2vw, 4rem); }

.proof__lede > p {
  margin: 34px 0 0;
  font-size: clamp(1.125rem, 1.6vw, 1.4375rem);
  line-height: 1.55;
  color: var(--fg-2);
  max-width: 38ch;
}

/* States the colour rule once, in plain words, then never again. */
.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
  margin: 34px 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--t-md);
  letter-spacing: 0.03em;
  color: var(--fg-3);
}
.legend li { display: flex; align-items: center; gap: 10px; }
.legend i {
  width: 11px; height: 11px;
  border-radius: 50%;
  flex: none;
}
.legend .is-dry { background: var(--dry); }
.legend .is-wet { background: var(--wet); }

/* One box, three subsections. Each .ab row is a separate [data-ab] pair
   so main.js wires them unchanged, and only one ever plays at a time. */
.abox {
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: 3px;
  overflow: hidden;
}

.abox__head,
.abox__foot {
  margin: 0;
  padding: 11px 18px;
  font-family: var(--f-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.14em;
  color: var(--fg-dim);
  background: rgba(255, 255, 255, .015);
}
.abox__head { border-bottom: 1px solid var(--line-2); color: var(--fg-3); }
.abox__foot { border-top: 1px solid var(--line-2); letter-spacing: 0.08em; }

.ab { padding: 14px 18px 16px; }
.ab + .ab { border-top: 1px solid var(--line-2); }

.ab__head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

.ab__tag { font-size: var(--t-xs); letter-spacing: 0.16em; color: var(--fg); }
.ab__note { font-size: var(--t-xs); color: var(--fg-dim); }

/* Transport and the two source buttons on one line. */
.ab__row {
  display: flex;
  align-items: center;
  gap: 12px;
}

.ab__play {
  flex: none;
  width: 34px; height: 34px;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: 50%;
  cursor: pointer;
  transition: border-color .18s var(--ease);
}
.ab__play:hover { border-color: var(--fg-3); }

/* Play triangle / pause bars, drawn in CSS so there's no icon request. */
.ab__icon {
  width: 0; height: 0;
  margin-left: 2px;
  border-left: 9px solid var(--fg);
  border-block: 6px solid transparent;
}
.ab.is-playing .ab__icon {
  width: 9px; height: 11px;
  margin-left: 0;
  border: 0;
  background:
    linear-gradient(var(--fg), var(--fg)) 0    0 / 3px 100% no-repeat,
    linear-gradient(var(--fg), var(--fg)) 100% 0 / 3px 100% no-repeat;
}

.ab__seek {
  flex: 1;
  min-width: 0;
  height: 3px;
  appearance: none;
  -webkit-appearance: none;
  background: var(--surface-2);
  border-radius: 2px;
  cursor: pointer;
}
.ab__seek::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--fg);
  border: 0;
}
.ab__seek::-moz-range-thumb {
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--fg);
  border: 0;
}

.ab__time {
  flex: none;
  font-size: var(--t-xs);
  color: var(--fg-3);
  font-variant-numeric: tabular-nums;
}
.ab__slash { margin-inline: 5px; color: var(--fg-dim); }

/* Violet is the dry signal, pink is the delay. Same as in the plugin. */
.ab__sources { display: flex; gap: 6px; flex: none; }

.ab__src {
  min-width: 62px;
  padding: 7px 10px;
  font-size: var(--t-xs);
  letter-spacing: 0.1em;
  background: transparent;
  color: var(--fg-3);
  border: 1px solid var(--line-2);
  border-radius: 2px;
  cursor: pointer;
  transition: color .16s var(--ease),
              border-color .16s var(--ease),
              background-color .16s var(--ease);
}
.ab__src:hover { color: var(--fg); }

.ab__src--dry.is-active {
  color: var(--dry);
  border-color: var(--dry);
  background: var(--dry-soft);
}
.ab__src--wet.is-active {
  color: var(--wet);
  border-color: var(--wet);
  background: var(--wet-soft);
}

.ab__status {
  margin: 10px 0 0;
  font-size: var(--t-xs);
  letter-spacing: 0.04em;
  color: var(--fg-dim);
}
.ab__status:empty { margin: 0; }


/* ═══ 9 ═══ Sections 01–03 ════════════════════════════════════════ */

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 80px);
  align-items: start;
}

.split__l { position: sticky; top: 92px; }

/* Deliberately uneven. Density sets the spacing, not a global value. */
.mech    { padding-block: 96px; }
.rhythm  { padding-block: 80px; }
.sound   { padding-block: 96px; }
.reviews { padding-block: 88px; }
.specs   { padding-block: 80px; }
.buy     { padding-block: 80px; }

/* Copy left, video right, video vertically centred against the copy — the
   same shape as the hero. Centring keeps the frame from stranding at the
   bottom of a tall text column. */
/* Both feature videos (01 and 02) run large: even columns, a 3:2 frame
   (taller than the default 16:9), and a left extension into the space
   beside the copy on wide screens. The extension is capped so it never
   reaches the heading next to it — verified for both headings, of which
   01's ("Each listens to the dry.") is the longer and tighter. */
.feature {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}

/* Sized to fit the half-width column at every width down to the 900px
   collapse, so no line of the decaying heading ever wraps. */
.feature__h2 { font-size: clamp(2rem, 3.4vw, 3.25rem); margin-bottom: 26px; }
.feature__copy .prose p { max-width: 52ch; }


@media (min-width: 1200px) {
  .feature__video {
    --fv-extend: clamp(40px, 5vw, 100px);
    width: calc(100% + var(--fv-extend));
    margin-left: calc(-1 * var(--fv-extend));
  }
}

/* — 04, the sound — */

.models {
  list-style: none;
  margin: 40px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border: 1px solid var(--line);
  border-radius: 2px;
  overflow: hidden;
}
.models li {
  padding: 18px 18px 20px;
  border-right: 1px solid var(--line);
  background: var(--surface);
}
.models li:last-child { border-right: 0; }
.models__n {
  display: block;
  font-size: var(--t-xs);
  letter-spacing: 0.16em;
  color: var(--fg);
  margin-bottom: 10px;
}
.models__d { display: block; font-size: var(--t-sm); color: var(--fg-3); line-height: 1.5; }

.ticks { list-style: none; margin: 28px 0 0; padding: 0; }
.ticks li {
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--fg-2);
}
.ticks li:first-child { border-top: 1px solid var(--line); }
.ticks__k {
  display: inline-block;
  min-width: 84px;
  margin-right: 12px;
  font-size: var(--t-xs);
  letter-spacing: 0.14em;
  color: var(--fg-dim);
}


/* ═══ 10 ═══ See it, reviews ═════════════════════════════════════ */

.vf__btn {
  display: block;
  position: relative;
  width: 100%;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}

.vf__play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 56px; height: 56px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-2);
  border-radius: 50%;
  background: rgba(11, 14, 17, 0.7);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  transition: border-color .18s var(--ease);
}
.vf__play::after {
  content: "";
  margin-left: 3px;
  border-left: 12px solid var(--fg);
  border-block: 8px solid transparent;
}
.vf__btn:hover .vf__play { border-color: var(--fg); }

/* THE BOX is the button, given a fixed 3:2 ratio. The thumbnail then
   absolutely fills it, so the frame height is pinned by the container and
   nothing — not the grid, not the image's own width/height attributes —
   can stretch it. This is the reliable fixed-ratio pattern; putting the
   ratio on the <img> alone is not, because the image's attributes fight it. */
/* 16:9 — the native ratio of the YouTube video, so the preview poster and
   the player that replaces it on click are exactly the same size (a 16:9
   thumbnail fills it with no crop, and the player has no black bars). */
.feature__video .vf__btn {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border: 1px solid var(--line-2);
  border-radius: 2px;
  background: var(--surface);
}
.vf__poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.feature__video .vf__btn:hover { border-color: var(--fg-3); }

/* The play button owns the centre of a video frame, so the placeholder
   copy moves to the foot of it rather than sitting underneath. */

.vf__cap { margin: 14px 0 0; font-size: var(--t-xs); letter-spacing: 0.04em; color: var(--fg-3); }
.vf__status { margin: 6px 0 0; font-size: var(--t-xs); color: var(--fg-dim); }
.vf__status:empty { margin: 0; }

.vf iframe {
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line-2);
  border-radius: 2px;
}

/* A reserved section, held for producer reviews. Dashed frame and a
   centred label so it reads as deliberately-empty rather than broken.
   Replace the whole block with review cards — see NOTES.md §6. */
.reviews__reserved {
  margin: 36px 0 0;
  min-height: 300px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
  padding: 48px 24px;
  border: 1px dashed var(--line-2);
  border-radius: 3px;
  background:
    repeating-linear-gradient(
      -45deg,
      transparent 0 9px,
      rgba(255, 255, 255, 0.014) 9px 10px
    );
}
.reviews__label {
  margin: 0;
  font-family: var(--f-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.16em;
  color: var(--fg-3);
}
.reviews__note { margin: 0; font-size: var(--t-sm); color: var(--fg-dim); line-height: 1.6; max-width: 52ch; }


/* ═══ 11 ═══ Specs and buy ════════════════════════════════════════ */

.spectable {
  margin: 36px 0 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  column-gap: 56px;
  border-top: 1px solid var(--line);
}

.spec {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 18px;
  align-items: baseline;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
}
.spec dt { font-size: var(--t-sm); color: var(--fg-3); }
.spec dd { margin: 0; font-size: var(--t-sm); color: var(--fg); }

.buy__in {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}

.price {
  margin: 0;
  font-size: clamp(3rem, 8vw, 5.5rem);
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--fg);
  display: flex;
  align-items: baseline;
  gap: 18px;
}
/* The old price, struck. It's a real regular price ($79), not an invented
   anchor — shown quietly so it informs without shouting a discount. */
.price__was {
  font-size: 0.32em;
  letter-spacing: 0.02em;
  color: var(--fg-dim);
  text-decoration: line-through;
  text-decoration-color: var(--sale);
  text-decoration-thickness: 3px;
}
.price__note { margin: 12px 0 26px; font-size: var(--t-sm); color: var(--fg-3); }

/* Struck old price in the sticky bar — same red scratch as everywhere else. */
.buybar__price s { color: var(--fg-dim); text-decoration-color: var(--sale); text-decoration-thickness: 2px; }
.buy__line { margin: 20px 0 0; font-size: var(--t-sm); color: var(--fg-3); }

/* Big manual button above the objections in the buy block's right column. */
.buy__manual {
  width: 100%;
  padding-block: 20px;
  font-size: var(--t-sm);
  margin-bottom: 28px;
}

.faq { margin: 0; border-top: 1px solid var(--line-2); }
.faq__row { padding: 15px 0; border-bottom: 1px solid var(--line-2); }
.faq__row dt { font-size: var(--t-sm); font-weight: 500; color: var(--fg); margin-bottom: 7px; }
.faq__row dd { margin: 0; font-size: var(--t-sm); color: var(--fg-3); line-height: 1.6; }


/* ═══ 12 ═══ Footer ═══════════════════════════════════════════════ */

.foot { border-top: 1px solid var(--line); padding-block: 32px 40px; }

.foot__in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px 40px;
}

.foot__line { margin: 0; font-size: var(--t-sm); color: var(--fg-3); }

.foot__links { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 24px; }
.foot__links a {
  font-size: var(--t-sm);
  color: var(--fg-3);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color .18s var(--ease), border-color .18s var(--ease);
}
.foot__links a:hover { color: var(--fg); border-bottom-color: var(--fg-4); }

.foot__copy { margin: 0; font-size: var(--t-xs); letter-spacing: 0.06em; color: var(--fg-dim); }


/* ═══ 12b ═══ Cursor glow + curve divider ═════════════════════════ */

/* Ported from the Viscera template's blob, scaled down and recoloured.
   z-index -1 keeps it on the page ground, so it paints over the empty
   plum-dark areas but never over the opaque image / video / card
   surfaces, which all sit at the content level above it. It's ambient,
   so the alpha is kept low — this is the one place pink isn't a signal. */
.glow {
  position: fixed;
  top: 0;
  left: 0;
  width: 240px;
  height: 240px;
  border-radius: 50%;
  pointer-events: none;
  z-index: -1;
  opacity: 0;
  background: radial-gradient(circle,
    rgba(255, 95, 168, 0.11) 0%,
    rgba(255, 95, 168, 0) 70%);
  transition: transform .1s ease-out, opacity .3s ease-out;
  will-change: transform;
}
.glow.is-on { opacity: 1; }

/* The rhythm curve as a hairline divider. Thin, low-opacity, pink
   because it's the delay's level over time — the product's own line,
   used sparingly as the page's one recurring motif. */
.rule-curve {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gut);
  opacity: .5;
}
.rule-curve svg {
  display: block;
  width: 100%;
  height: 16px;
  overflow: visible;
}
.rule-curve path {
  fill: none;
  stroke: var(--wet);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}


/* ═══ 13 ═══ Reveals ══════════════════════════════════════════════
   Only applied when .js is present, so the page is fully readable if
   the script never loads. One short move — no scale, no rotation.  */

/* The section slide — the "page slides into place" motion as you move from
   one section to the next. The whole content block rises and fades as a
   unit; the heading lines and finer details animate within it. This is the
   template's container reveal (y then settle) at section scale. */
.js .sl {
  opacity: 0;
  transform: translateY(72px);
  transition: opacity 1s var(--ease-gz), transform 1s var(--ease-gz);
  will-change: transform;
}
.js .sl.is-in { opacity: 1; transform: none; }

/* Per-element fade-up, ported from the template. Kept gentle (20px) because
   it now settles *inside* a section that's already sliding — the two read
   as one move with detail, not two competing ones. */
.js .rv {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .7s var(--ease-gz) .05s, transform .7s var(--ease-gz) .05s;
}
.js .rv.is-in { opacity: 1; transform: none; }

/* staggerChildren: 0.08 — the same cascade the template runs inside a
   group. Applied only to the small at-once groups; the long spec list
   stays un-staggered so it doesn't crawl in. */
.js .models li.rv:nth-child(2),
.js .ticks li.rv:nth-child(2),
.js .faq__row.rv:nth-child(2) { transition-delay: .07s; }
.js .models li.rv:nth-child(3),
.js .ticks li.rv:nth-child(3),
.js .faq__row.rv:nth-child(3) { transition-delay: .14s; }
.js .models li.rv:nth-child(4),
.js .ticks li.rv:nth-child(4),
.js .faq__row.rv:nth-child(4) { transition-delay: .21s; }
.js .ticks li.rv:nth-child(5) { transition-delay: .28s; }
.js .ticks li.rv:nth-child(6) { transition-delay: .35s; }

/* Heading lines reveal in sequence on scroll — the template's staggered
   text move. The hero h1 keeps its own one-time settle instead. */
.js .rvh .ln {
  opacity: 0;
  transform: translateY(0.7em);
  transition: opacity .7s var(--ease-gz), transform .7s var(--ease-gz);
}
.js .rvh.is-in .ln { opacity: 1; transform: none; }
.js .rvh .ln--2 { transition-delay: .1s; }
.js .rvh .ln--3 { transition-delay: .2s; }

/* The headline decay. Each line arrives a beat after the one above it
   and lands one step quieter — the page performing the product. Runs
   once, on load. Nothing else on the page is animated like this. */
.js .hero__h1 .ln {
  opacity: 0;
  transform: translateY(0.14em);
  animation: settle .9s var(--ease) forwards;
}
.js .hero__h1 .ln--1 { animation-delay: .05s; }
.js .hero__h1 .ln--2 { animation-delay: .19s; }
.js .hero__h1 .ln--3 { animation-delay: .33s; }

@keyframes settle { to { opacity: 1; transform: none; } }


/* ═══ 14 ═══ Responsive ═══════════════════════════════════════════ */

@media (max-width: 1080px) {
  .models { grid-template-columns: repeat(2, 1fr); }
  .models li:nth-child(2n) { border-right: 0; }
  .models li:nth-child(-n+2) { border-bottom: 1px solid var(--line); }
  .points { grid-template-columns: repeat(2, 1fr); }
  .points li:nth-child(-n+2) { border-bottom: 1px solid var(--line); }
}

@media (max-width: 900px) {
  .hero__grid,
  .proof__in,
  .split,
  .feature,
  .buy__in { grid-template-columns: 1fr; }

  .hero__grid { align-items: start; gap: 32px; }
  .hero__copy .lede { max-width: 52ch; }
  .split__l { position: static; }
  .spectable { grid-template-columns: 1fr; column-gap: 0; }

  /* Loosens rather than collapsing to one value. */
  .mech, .sound { padding-block: 72px; }
  .specs { padding-block: 64px; }
  .hero { padding-block: 40px 48px; }
}

@media (max-width: 720px) {
  .head__nav { gap: 18px; }
  .head__nav a:nth-child(2) { display: none; }
  .models { grid-template-columns: 1fr; }
  .models li { border-right: 0; border-bottom: 1px solid var(--line); }
  .models li:last-child { border-bottom: 0; }
  .spec { grid-template-columns: 1fr; gap: 4px; }
  .btn-row .btn { flex: 1 1 100%; }
  .ticks__k { display: block; margin-bottom: 4px; }

  .points { grid-template-columns: 1fr; }
  .points li { padding-right: 0; }
  .points li:nth-child(-n+3) { border-bottom: 1px solid var(--line); }

  /* The transport wraps onto two lines rather than crushing the seek bar. */
  .ab__row { flex-wrap: wrap; }
  .ab__seek { flex: 1 1 120px; }
  .ab__sources { flex: 1 1 100%; }
  .ab__src { flex: 1; }

  /* The desktop bar gives way to the thumb-reach bar. */
  .buybar { display: none; }
  .thumb { display: flex; }
  body { padding-bottom: 68px; }
}


/* ═══ 15 ═══ Reduced motion, print ════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }

  .js .sl { opacity: 1; transform: none; }
  .js .rv { opacity: 1; transform: none; }
  .js .rvh .ln { opacity: 1; transform: none; }
  .js .hero__h1 .ln { opacity: 1; transform: none; animation: none; }
  .glow { display: none; }
}

@media print {
  .buybar, .thumb, .dots, .vf__play, .glow, .rule-curve { display: none !important; }
  body { background: #fff; color: #000; }
  .sec { padding-block: 24px !important; }
}


/* ═══ 16 ═══ Copilot widget ═══════════════════════════════════════
   Floating "Ask the manual" chat, backed by the Hugging Face Space.
   Uses the page tokens so it reads as native. Markup + chat.js at the
   bottom of index.html. */

.edc-toggle {
  position: fixed; right: 20px; bottom: 20px; z-index: 900;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 11px 16px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--fg);
  font-family: var(--f-mono); font-size: var(--t-sm); cursor: pointer;
  box-shadow: 0 8px 30px rgba(0,0,0,.4); transition: transform .2s var(--ease), border-color .2s;
}
.edc-toggle:hover { transform: translateY(-2px); border-color: var(--dry); }
.edc-toggle__dot { width: 8px; height: 8px; border-radius: 50%;
  background: linear-gradient(135deg, var(--dry), var(--wet)); }

.edc-panel {
  position: fixed; right: 20px; bottom: 78px; z-index: 901;
  width: min(380px, calc(100vw - 40px)); height: min(560px, calc(100vh - 120px));
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg); border: 1px solid var(--line); border-radius: 16px;
  box-shadow: 0 24px 70px rgba(0,0,0,.55);
  opacity: 0; transform: translateY(12px) scale(.98); pointer-events: none;
  transition: opacity .22s var(--ease), transform .22s var(--ease);
}
.edc-panel.edc-open { opacity: 1; transform: none; pointer-events: auto; }

.edc-head { display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px; border-bottom: 1px solid var(--line); }
.edc-title { font-family: var(--f-display); font-size: var(--t-md); }
.edc-close { background: none; border: 0; color: var(--fg-dim); font-size: 22px;
  line-height: 1; cursor: pointer; padding: 0 4px; }
.edc-close:hover { color: var(--fg); }

.edc-log { flex: 1; overflow-y: auto; padding: 16px; display: flex;
  flex-direction: column; gap: 12px; }
.edc-msg { max-width: 85%; padding: 10px 13px; border-radius: 12px;
  font-size: var(--t-sm); line-height: 1.5; white-space: pre-wrap; word-wrap: break-word; }
.edc-user { align-self: flex-end; background: var(--dry-soft);
  border: 1px solid var(--dry); color: var(--fg); }
.edc-bot  { align-self: flex-start; background: var(--surface);
  border: 1px solid var(--line); color: var(--fg); }
.edc-cites { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line);
  font-family: var(--f-mono); font-size: var(--t-xs); color: var(--wet); }

.edc-form { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--line); }
.edc-input { flex: 1; background: var(--surface); border: 1px solid var(--line);
  border-radius: 999px; padding: 10px 14px; color: var(--fg);
  font-family: var(--f-body); font-size: var(--t-sm); }
.edc-input:focus { outline: none; border-color: var(--dry); }
.edc-send { width: 40px; border: 0; border-radius: 999px; cursor: pointer;
  background: linear-gradient(135deg, var(--dry), var(--wet)); color: #0b0e11;
  font-size: 18px; font-weight: 600; }
.edc-send:hover { filter: brightness(1.1); }

/* This site already has a fixed mobile thumb-bar (Buy / Try) at the very
   bottom below 720px. Lift the toggle and panel above it so they don't
   stack on top of each other. */
@media (max-width: 720px) {
  .edc-toggle { bottom: 84px; }
  .edc-panel  { bottom: 142px; height: min(520px, calc(100vh - 200px)); }
}
