/* =============================================================================
   Foldnine — scroll scenes (home page)

   Every scene has two layouts. Without .js-scrub (reduced motion, no script)
   it is an ordinary section: captions stacked, every chip and facet in its
   final state, nothing hidden. With .js-scrub the section is several screens
   tall, its stage sticks, and each element computes its own state from --p,
   the section's scroll progress, which scrub.js keeps current.

   The motion tokens (140/620 ms) do not apply here: nothing below has a
   duration. The scrollbar is the clock.

   A caption's window is --a..--b on --p, with a fade of --f at each end:

     --o = clamp(0, min((p - a) / f, (b - p) / f), 1)
   ========================================================================== */

/* --- scene scaffolding --------------------------------------------------- */

.scene { position: relative; border-block-start: 0; padding: 0; }
.scene-stage { position: relative; padding-block: clamp(4rem, 12vh, 8rem); }

.js-scrub .scene { --p: 0; }
.js-scrub .scene-fold   { block-size: 420svh; }
.js-scrub .scene-swap   { block-size: 360svh; }
.js-scrub .scene-facets { block-size: 380svh; }
.js-scrub .scene-stage {
  position: sticky; inset-block-start: 0;
  block-size: 100svh; overflow: hidden;
  /* the masthead is sticky too, and sits over the top of every stage */
  padding-block: 4.5rem 0;
  display: grid; align-items: center;
}

.js-scrub .cap {
  --f: .06;
  --o: clamp(0, min((var(--p) - var(--a)) / var(--f), (var(--b) - var(--p)) / var(--f)), 1);
  opacity: var(--o);
  transform: translateY(calc((1 - var(--o)) * 1.25rem));
}

/* =============================================================================
   1. The fold
   ========================================================================== */

.scene-fold { overflow: clip; }
/* The point the fan folds to, read by fold-scrub.js and by .fold-mark. On a
   wide screen it sits right of the copy, as the apex does in the mark. */
/* On a phone the finished hero copy fills the lower two thirds, so the mark
   waits above it. */
.scene-fold .scene-stage { --apex-x: .5; --apex-y: .16; }
.cap em { font-style: normal; color: var(--muted); }
@media (min-width: 58rem) {
  .scene-fold .scene-stage { --apex-x: .76; --apex-y: .46; }
}
.scene-canvas { position: absolute; inset: 0; display: block; }
.scene-canvas canvas { display: block; inline-size: 100%; block-size: 100%; }

.caps { position: relative; display: grid; gap: 3rem; inline-size: 100%; }
.caps .display { max-inline-size: 14ch; }

.fold-eyebrow { display: flex; align-items: center; gap: .6rem; margin-block-end: 1.5rem; color: var(--muted); }
.fold-final .hero-title { margin-block-end: 0; }
.fold-lede { margin-block-start: 1.75rem; }
.fold-final .hero-actions { margin-block-start: 2.25rem; }

/* The mark the fan folds into. Static layout: it stands above the hero copy. */
.fold-mark { inline-size: 3.5rem; block-size: auto; margin: 0 auto 2rem; }
.scroll-hint { display: none; }

.js-scrub .caps { grid-template-areas: "cap"; }
.js-scrub .caps > * { grid-area: cap; align-self: end; }
.js-scrub .scene-fold .scene-stage { align-items: end; padding-block-end: clamp(3rem, 12vh, 7rem); }
.js-scrub .cap-a { --a: -1;  --b: .26; }
.js-scrub .cap-b { --a: .30; --b: .58; }
.js-scrub .cap-c { --a: .80; --b: 2; }

/* The mark takes over from the fan at its apex, the same point fold-scrub.js
   draws to. */
.js-scrub .fold-mark {
  --m: clamp(0, (var(--p) - .74) / .14, 1);
  position: absolute; margin: 0;
  inset-inline-start: calc(var(--apex-x) * 100%);
  inset-block-start: calc(var(--apex-y) * 100%);
  inline-size: clamp(3.5rem, 9vw, 9rem);
  opacity: var(--m);
  transform: translate(-50%, -50%) scale(calc(.4 + var(--m) * .6));
}
.js-scrub .scroll-hint {
  display: block; position: absolute;
  inset-block-end: 1.25rem; inset-inline-start: 50%;
  translate: -50% 0;
  color: var(--muted);
  opacity: clamp(0, 1 - var(--p) * 12, 1);
}

/* =============================================================================
   2. By hand → system
   ========================================================================== */

.swap-inner {
  display: grid; gap: clamp(2rem, 5vw, 5rem); inline-size: 100%;
  grid-template-columns: repeat(auto-fit, minmax(min(24rem, 100%), 1fr));
  align-items: center;
}
.swap-head .label { margin-block-end: 1.25rem; }
.swap-head .display { margin-block-end: 1.5rem; }

.swaps { display: grid; border-block-start: 1px solid var(--rule); }
.swap {
  --s: 1;
  display: grid; grid-template-columns: 2.5rem minmax(0, 1fr) auto; gap: 1rem;
  align-items: center;
  padding-block: clamp(.7rem, 1.6vh, 1.1rem);
  border-block-end: 1px solid var(--rule);
  position: relative;
}
.swap-no { color: var(--muted); font-size: var(--step--1); }
.swap-text { color: color-mix(in oklab, var(--ink) calc(var(--s) * 100%), var(--muted)); }
.swap-state { display: grid; justify-items: end; }
.swap-state > * { grid-area: 1 / 1; }
.swap-hand { border-style: dashed; opacity: calc(1 - var(--s)); }
.swap-sys  { opacity: var(--s); }
/* a firm rule drawn under the row as it turns over */
.swap::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-end: -1px;
  block-size: 1px; background: var(--edge);
  transform-origin: left; transform: scaleX(var(--s));
}

.js-scrub .swap { --s: clamp(0, (var(--p) - var(--t)) / .07, 1); }
.js-scrub .swap-1 { --t: .10; }
.js-scrub .swap-2 { --t: .22; }
.js-scrub .swap-3 { --t: .34; }
.js-scrub .swap-4 { --t: .46; }
.js-scrub .swap-5 { --t: .58; }
.js-scrub .swap-6 { --t: .70; }

/* =============================================================================
   3. Three facets: the mark is three shapes, and the practice is three stages.
   ========================================================================== */

.facets-inner {
  display: grid; gap: clamp(2rem, 6vw, 6rem); inline-size: 100%;
  grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
  align-items: center;
}
.facets-art { display: grid; place-items: center; }
.facets-mark { inline-size: min(100%, 26rem, 42svh); block-size: auto; overflow: visible; }
.facet { fill: var(--ink); }

.facets-copy .label { margin-block-end: 1.25rem; }
.facets-title { margin-block-end: 2rem; }
.facet-steps { display: grid; gap: 2rem; }
.step-no { color: var(--muted); font-size: var(--step--1); letter-spacing: var(--track-mono); text-transform: uppercase; margin-block-end: .5rem; }
.step .subhead { margin-block-end: .75rem; }

/* Scrubbed: the facets light one at a time and stay lit, so the finished
   mark is the finished engagement. The steps replace each other in place. */
.js-scrub .facet {
  --l: clamp(0, (var(--p) - var(--fa)) / .08, 1);
  opacity: calc(.1 + var(--l) * .9);
  transform-box: fill-box; transform-origin: center;
  transform: translate(calc((1 - var(--l)) * var(--dx)), calc((1 - var(--l)) * var(--dy)));
}
.js-scrub .facet-1 { --fa: .08; --dx: -2rem; --dy: 0rem; }
.js-scrub .facet-2 { --fa: .38; --dx: 2rem;  --dy: 1rem; }
.js-scrub .facet-3 { --fa: .66; --dx: 0rem;  --dy: -2rem; }

.js-scrub .facet-steps { grid-template-areas: "step"; }
.js-scrub .step { grid-area: step; }
.js-scrub .step-1 { --a: -1;  --b: .36; }
.js-scrub .step-2 { --a: .40; --b: .64; }
.js-scrub .step-3 { --a: .68; --b: 2; }

/* =============================================================================
   4. A heading, word by word. Native scroll-driven animation, no script: the
   heading's own passage through the viewport is the timeline. Any heading
   with .words and one <span> per word gets it; a <br> between them is fine,
   since the ranges count spans only.
   ========================================================================== */


@supports (animation-timeline: view()) {
  .js-scrub .words { view-timeline-name: --words; }
  .js-scrub .words span {
    animation: word-in linear both;
    animation-timeline: --words;
  }
  .js-scrub .words span:nth-of-type(1)  { animation-range: cover 10% cover 16%; }
  .js-scrub .words span:nth-of-type(2)  { animation-range: cover 13% cover 19%; }
  .js-scrub .words span:nth-of-type(3)  { animation-range: cover 16% cover 22%; }
  .js-scrub .words span:nth-of-type(4)  { animation-range: cover 19% cover 25%; }
  .js-scrub .words span:nth-of-type(5)  { animation-range: cover 22% cover 28%; }
  .js-scrub .words span:nth-of-type(6)  { animation-range: cover 25% cover 31%; }
  .js-scrub .words span:nth-of-type(7)  { animation-range: cover 28% cover 34%; }
  .js-scrub .words span:nth-of-type(8)  { animation-range: cover 31% cover 37%; }
  .js-scrub .words span:nth-of-type(9)  { animation-range: cover 34% cover 40%; }
  .js-scrub .words span:nth-of-type(10) { animation-range: cover 37% cover 43%; }
  .js-scrub .words span:nth-of-type(11) { animation-range: cover 40% cover 46%; }
  .js-scrub .words span:nth-of-type(12) { animation-range: cover 43% cover 49%; }
  .js-scrub .words span:nth-of-type(13) { animation-range: cover 46% cover 52%; }
  .js-scrub .words span:nth-of-type(14) { animation-range: cover 49% cover 55%; }
}
@keyframes word-in { from { opacity: .12; } to { opacity: 1; } }

/* =============================================================================
   5. /work/ai-sales/ - the pipeline, five steps, one number each.

   The steps replace each other in place like the stages on the home page;
   the rail beside the heading fills as each is reached, and stays filled.
   Static layout: the five steps as a list, the rail fully lit.
   ========================================================================== */

.work-hero { padding-block: clamp(5rem, 16vh, 10rem) clamp(4rem, 10vh, 7rem); }
.work-lede { margin-block: 1.75rem 2.5rem; }
.work-facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: 1.25rem 2rem; margin: 0;
  border-block-start: 1px solid var(--rule); padding-block-start: 1.5rem;
}
.work-facts dt { font-family: var(--mono); font-size: var(--step--2); letter-spacing: var(--track-mono); text-transform: uppercase; color: var(--muted); margin-block-end: .35rem; }
.work-facts dd { margin: 0; color: var(--ink); }

.pipe-inner {
  display: grid; gap: clamp(2rem, 6vw, 6rem); inline-size: 100%;
  grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
  align-items: center;
}
.pipe-head .label { margin-block-end: 1.25rem; }
.pipe-head .head { margin-block-end: 2rem; }
.pipe-rail { display: grid; gap: .6rem; margin-block-end: 1.5rem; }
.pipe-rail li {
  --r: 1;
  display: flex; align-items: center; gap: .75rem;
  font-family: var(--mono); font-size: var(--step--1); letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: color-mix(in oklab, var(--ink) calc(var(--r) * 100%), var(--muted));
}
/* hollow until reached, filled after: the site's state language */
.pipe-rail li::before {
  content: ""; inline-size: .6rem; block-size: .6rem; flex: none;
  border: 1px solid var(--edge);
  background: color-mix(in oklab, var(--ink) calc(var(--r) * 100%), transparent);
}
.pipe-asof { color: var(--muted); }

.pipe-steps { display: grid; gap: 3rem; }
.pipe-count {
  font-family: var(--sans); font-weight: 600; font-variant-numeric: tabular-nums;
  font-size: var(--step-5); line-height: 1; letter-spacing: var(--track-hero);
  color: var(--ink); margin-block-end: .75rem;
}
.pipe-count span { font-size: .42em; color: var(--muted); letter-spacing: var(--track-sub); }
.pipe-step .subhead { margin-block-end: .9rem; }

.js-scrub .scene-pipe { block-size: 460svh; }
.js-scrub .pipe-steps { grid-template-areas: "step"; }
.js-scrub .pipe-step { grid-area: step; }
.js-scrub .pipe-1 { --a: -1;  --b: .18; }
.js-scrub .pipe-2 { --a: .22; --b: .38; }
.js-scrub .pipe-3 { --a: .42; --b: .58; }
.js-scrub .pipe-4 { --a: .62; --b: .78; }
.js-scrub .pipe-5 { --a: .82; --b: 2; }
.js-scrub .pipe-rail li { --r: clamp(0, (var(--p) - var(--ra)) / .04, 1); }
.js-scrub .rail-1 { --ra: -1; }
.js-scrub .rail-2 { --ra: .20; }
.js-scrub .rail-3 { --ra: .40; }
.js-scrub .rail-4 { --ra: .60; }
.js-scrub .rail-5 { --ra: .80; }

.work-rules { display: grid; gap: 1.25rem; margin-block-start: 2.5rem; max-inline-size: 44rem; }
.work-rules li { display: grid; grid-template-columns: 2.5rem 1fr; gap: 1rem; padding-block-start: 1.25rem; border-block-start: 1px solid var(--rule); }
.work-rules .num { color: var(--muted); font-size: var(--step--1); padding-block-start: .2rem; }
.work-rules strong { color: var(--ink); font-weight: 600; }

@media (max-width: 40rem) {
  .js-scrub .pipe-head .label, .js-scrub .pipe-asof { display: none; }
  .js-scrub .pipe-head .head { font-size: var(--step-2); margin-block-end: 1rem; }
  .js-scrub .pipe-rail { grid-auto-flow: column; gap: .5rem; margin: 0; }
  .js-scrub .pipe-rail li { font-size: 0; gap: 0; }
  .js-scrub .pipe-rail li::before { inline-size: .8rem; block-size: .8rem; }
  .js-scrub .pipe-inner { gap: 1.5rem; }
  .js-scrub .pipe-step .prose { font-size: .95rem; line-height: 1.5; }
}

/* /services/process-audit/ - the price sits with the other facts, set a
   step louder, because it is the one people look for. */
.audit-price { font-weight: 600; }
.audit-terms { margin-block-start: 1.25rem; color: var(--muted); max-inline-size: 40rem; }
.audit-actions { margin-block-start: 2rem; }

@media (max-width: 40rem) {
  .masthead .btn-sm { white-space: nowrap; }
  /* The whole list has to fit one sticky screen, so the chip stays on the
     row and the header gives up its label and lede. */
  .swap { grid-template-columns: 1.5rem minmax(0, 1fr) auto; gap: .6rem; padding-block: .6rem; }
  .swap-text { font-size: .95rem; line-height: 1.3; }
  .swap .chip { padding: .25rem .45rem; }
  .js-scrub .swap-inner { gap: 1.5rem; }
  .js-scrub .swap-head .label,
  .js-scrub .swap-lede { display: none; }
  .js-scrub .swap-head .display { font-size: var(--step-3); margin-block-end: 0; }
  .js-scrub .facets-mark { inline-size: min(52vw, 24svh); }
  .js-scrub .facets-inner { gap: 1.25rem; }
  .js-scrub .facets-copy .label { display: none; }
  .js-scrub .facets-title { font-size: var(--step-2); margin-block-end: .75rem; }
  .js-scrub .step .subhead { margin-block-end: .4rem; }
  .js-scrub .step .prose { font-size: .95rem; line-height: 1.5; }
}

@media (max-width: 24rem) {
  .masthead .btn-sm { display: none; }
}

/* The hero's final frame has to fit the actions on a short phone. */
@media (max-height: 700px) {
  .js-scrub .fold-lede { display: none; }
}
