/* PREVIEW v3 2026-09-16 · scroll-scrubbed motion. scrub.js writes --p (0..1) per element.
 * Every rule falls back to var(--p, 1), the finished state, so JS-off and reduced motion show everything.
 * transform + opacity (and stroke-dashoffset on tiny icons) only.
 */

/* ---------- generic blocks: rise and fade in with scroll ---------- */
html.scrub .rv.rv, html.scrub .rv.rv.in {
  opacity: calc(0.08 + 0.92 * var(--p, 1));
  transform: translate3d(0, calc((1 - var(--p, 1)) * 44px), 0) scale(calc(0.975 + 0.025 * var(--p, 1)));
  transition: none;
  will-change: transform, opacity;
}
/* a block that holds a headline stays solid; the words carry the motion */
html.scrub .rv.rv:has(> h2.sh), html.scrub .rv.rv.in:has(> h2.sh) { opacity: 1; }

/* ---------- headlines light up word by word ---------- */
html.scrub h2.sh .sw {
  display: inline-block;
  --w: clamp(0, calc(var(--p, 1) * (var(--n, 4) + 2) - var(--i, 0)), 1);
  opacity: calc(0.14 + 0.86 * var(--w));
  transform: translate3d(0, calc((1 - var(--w)) * 0.35em), 0);
}

/* ---------- hairlines grow in ember with scroll, then settle ---------- */
html.scrub .sys::before, html.scrub .qa::before, html.scrub .fact::before {
  transform: scaleX(var(--p, 1));
  opacity: calc(1 - 0.65 * clamp(0, calc((var(--p, 1) - 0.85) * 6.67), 1));
  transition: none;
}

/* ---------- icons draw with scroll ---------- */
html.scrub .sys .ico * {
  stroke-dashoffset: calc(1 - clamp(0, calc((var(--p, 1) - 0.05) * 2.4), 1));
  transition: none;
}

/* ---------- how it works: the timeline fills as you scroll ---------- */
html.scrub .steps .step::before {
  opacity: 1;
  transform: scaleX(clamp(0, calc(var(--tp, 1) * 3.3 - var(--k, 0)), 1));
  transition: none;
}
html.scrub .steps .step::after {
  transform: scale(clamp(0, calc((var(--tp, 1) * 3.3 - var(--k, 0)) * 5), 1));
  transition: none;
}
html.scrub .steps .step .sno { opacity: calc(0.3 + 0.7 * clamp(0, calc((var(--tp, 1) * 3.3 - var(--k, 0)) * 3), 1)); }

/* ---------- forms: fields settle in with the card ---------- */
html.scrub .form-card .form-grid > div, html.scrub .form-card.in .form-grid > div {
  --f: clamp(0, calc((var(--p, 1) * 1.25 - var(--k, 0) / 20) * 8), 1);
  opacity: calc(0.1 + 0.9 * var(--f));
  transform: translate3d(0, calc((1 - var(--f)) * 14px), 0);
  transition: none;
}

/* ---------- construction funnel builds in stages ---------- */
html.scrub .funnel.rv { opacity: 1; transform: none; }
html.scrub .funnel .f-src {
  --q: clamp(0, calc((var(--p, 1) - 0.02 - var(--k, 0) * 0.07) * 7), 1);
  opacity: var(--q);
  transform: translate3d(calc((1 - var(--q)) * -40px), 0, 0);
}
html.scrub .funnel .f-src:nth-child(1) { --k: 0; }
html.scrub .funnel .f-src:nth-child(2) { --k: 1; }
html.scrub .funnel .f-src:nth-child(3) { --k: 2; }
html.scrub .funnel .f-wires:nth-child(2) { opacity: clamp(0, calc((var(--p, 1) - 0.28) * 7), 1); }
html.scrub .funnel .f-core {
  --q: clamp(0, calc((var(--p, 1) - 0.38) * 6), 1);
  opacity: var(--q);
  transform: scale(calc(0.55 + 0.45 * var(--q))) rotate(calc((1 - var(--q)) * -25deg));
}
html.scrub .funnel .f-wires:nth-child(4) { opacity: clamp(0, calc((var(--p, 1) - 0.52) * 8), 1); }
html.scrub .funnel .f-out {
  --q: clamp(0, calc((var(--p, 1) - 0.56) * 7), 1);
  opacity: var(--q);
  transform: translate3d(calc((1 - var(--q)) * 40px), 0, 0);
}
html.scrub .funnel .f-slot, html.scrub .funnel .f-slot.on {
  --q: clamp(0, calc((var(--p, 1) - 0.68 - var(--k, 0) * 0.08) * 12), 1);
  opacity: calc(0.25 + 0.75 * var(--q));
  transition: none;
}
html.scrub .funnel .f-slot .tag, html.scrub .funnel .f-slot.on .tag {
  opacity: var(--q); transform: translate3d(calc((1 - var(--q)) * -10px), 0, 0); transition: none;
}
html.scrub .funnel .f-slot:nth-of-type(1) { --k: 0; }
html.scrub .funnel .f-slot:nth-of-type(2) { --k: 1; }
html.scrub .funnel .f-slot:nth-of-type(3) { --k: 2; }
@media (max-width: 920px) {
  html.scrub .funnel .f-src { transform: translate3d(0, calc((1 - var(--q)) * 24px), 0); }
  html.scrub .funnel .f-out { transform: translate3d(0, calc((1 - var(--q)) * 24px), 0); }
}

/* ---------- missed-call phone: brief sticky pin while the chat plays ---------- */
html.scrub .callsec.pinned .split-demo { align-items: start; }
html.scrub .callsec.pinned .phone-track { height: calc(640px + 70vh); }
html.scrub .callsec.pinned .phone { position: sticky; top: calc(50vh - 320px); }
html.scrub .callsec.pinned .split-demo > .rv { position: sticky; top: calc(50vh - 260px); }
@media (max-width: 600px) {
  html.scrub .callsec.pinned .phone-track { height: calc(512px + 80vh); }
  html.scrub .callsec.pinned .phone { top: calc(50vh - 256px + 30px); }
  html.scrub .callsec.pinned .split-demo > .rv { position: static; }
}
@media (max-width: 920px) {
  html.scrub .callsec.pinned .phone-track { order: 2; }
  html.scrub .callsec.pinned .split-demo > .rv { position: static; }
}
@media (max-height: 700px) and (min-width: 601px) {
  html.scrub .callsec.pinned .phone { top: 80px; }
}
.phone-track { width: 100%; }

/* ---------- video cards tilt and scale into place ---------- */
html.scrub .reel .frame {
  transform: perspective(1200px)
    rotateY(var(--ry, 0deg))
    rotateX(calc(var(--rx, 0deg) + (1 - var(--p, 1)) * 18deg))
    scale(calc(0.86 + 0.14 * var(--p, 1)));
  opacity: calc(0.35 + 0.65 * var(--p, 1));
  transition: transform 0.12s linear;
}
html.scrub .reel.rv.rv { transform: none; opacity: 1; }

/* phones: shorter travel, same story */
@media (max-width: 600px) {
  html.scrub .rv.rv, html.scrub .rv.rv.in { transform: translate3d(0, calc((1 - var(--p, 1)) * 28px), 0); }
}
