/* ============================================================
   /voice-ai/ — THE BODY SECTIONS.

   ⚠️ A DESIGN PER SECTION, NOT ONE GRAMMAR FOR ALL OF THEM. Founder: "have
   different section designs, use extraordinary section designs and not same
   ones". An earlier pass gave every section the same sticky-rail-and-column
   layout; it fixed the dead space and made the page read as five copies of one
   idea. This site's home page does the opposite — a pinned horizontal slide, a
   fanned hand, an ink dashboard, a pinned vertical slide — and that is the
   language this page has to be in.

   ⚠️ THE MECHANISM IS THE SITE'S OWN. `view-timeline` + `animation-timeline`
   pinned with `position: sticky`, exactly as home's §01 and §04 do it: the
   browser maps scroll to the animation on the compositor, so there is no
   scroll listener, nothing to jank, nothing to throttle. Everything scroll-
   driven here has a `@supports not (animation-timeline: view())` fallback to
   the plain readable version, which is also what `prefers-reduced-motion` gets.
   ============================================================ */

/* ═══════════════════════════════════════════════════════════════
   01 — SCRUB THE CALL.

   The hero is a recording scrolling past a playhead. Here the reader DRIVES
   that playhead: scroll advances the call, the marker moves along the bar, the
   clock counts, and the line being spoken at that moment is the only one on
   screen, set large. Same recording, opened up — and the one thing on this page
   that could not have been a screenshot.

   ⚠️ ONE LINE AT A TIME IS THE WHOLE POINT. As a list, a transcript is
   something you skim and a reader takes the gist. One line at a time is a
   reader hearing the call at its own pace, and it makes the two green rows —
   the diary being read mid-sentence, the job being created — impossible to
   scroll past, which is the only reason the transcript is on the page.
   ═══════════════════════════════════════════════════════════════ */
/* The warm ground is on `body`, further down — see the note there for why it
   is NOT a list of sections. */

.vs { position: relative; height: 420vh;
  view-timeline-name: --vs; view-timeline-axis: block; }
.vs__pin { position: sticky; top: max(var(--s3), calc(50vh - 250px));
  min-height: 500px; display: grid; align-content: center; }
/* ⚠️ `width: 100%`, AND WITHOUT IT THE SECTION IS 661px WIDE. `.wrap` carries
   `margin-inline: auto`, and a grid item with auto inline margins is sized to
   its CONTENT, not stretched — so the scrub bar and the transcript were laid
   out against the longest line rather than against the column. The same trap
   caught section 02's rail earlier in this build; it is worth knowing that
   `margin: auto` opts an item OUT of stretching in both flex and grid. */
.vs__pin > .wrap { width: 100%; }

.vs__head-row { display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s4); padding-bottom: var(--s3); border-bottom: 1px solid var(--line); }
.vs__meta { font-family: var(--mono); font-size: 11px; letter-spacing: 0.09em;
  text-transform: uppercase; color: #4E4E4E; }

/* ---- the scrub bar ---------------------------------------------------
   ⚠️ THE TICKS ARE AT THEIR REAL SECONDS, not spaced evenly. The call's lines
   are 2, 3, 6, 6, 3, 9, 2, 5, 5, 7 seconds apart — an even row of marks would
   be a decoration, and these are a readout. The gaps between them ARE the
   pauses in the call. */
.vs__bar { position: relative; height: 3px; margin-top: var(--s5);
  background: var(--line-2); }
.vs__bar i { position: absolute; left: var(--x); top: -3px; width: 1px; height: 9px;
  background: var(--line-2); }
.vs__head { position: absolute; top: -7px; bottom: -7px; left: 0; width: 2px;
  background: var(--ink);
  animation: vs-head linear both; animation-timeline: --vs;
  animation-range: contain 0% contain 100%; }
@keyframes vs-head { from { left: 0; } to { left: 100%; } }
/* the played part of the bar darkens behind the head, so the bar reads as
   progress rather than as a rule with a marker on it */
.vs__bar::after { content: ''; position: absolute; inset: 0 auto 0 0; background: var(--ink);
  animation: vs-fill linear both; animation-timeline: --vs;
  animation-range: contain 0% contain 100%; }
@keyframes vs-fill { from { right: 100%; } to { right: 0; } }

/* ---- the lines -------------------------------------------------------
   All eleven share one grid cell, so the block never resizes as the call
   advances — a section that changes height while it is pinned drags every
   other line on screen with it. */
.vs__lines { display: grid; margin-top: var(--s6); min-height: 260px; align-content: start; }
.vs__l { grid-area: 1 / 1; opacity: 0;
  animation-duration: 1s; animation-fill-mode: both; animation-timing-function: linear;
  animation-timeline: --vs; animation-range: contain 0% contain 100%; }
.vs__t { font-family: var(--mono); font-size: var(--t-sm); color: #4E4E4E;
  font-variant-numeric: tabular-nums; }
.vs__w { font-family: var(--mono); font-size: 10px; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--brand); margin-left: var(--s3); }
.vs__l--ev .vs__p { font-family: var(--mono); font-size: var(--t-sm);
  letter-spacing: 0.08em; text-transform: uppercase; color: #4E4E4E; }
.vs__p { margin-top: var(--s3); font-family: var(--display); font-weight: var(--w-display);
  font-size: clamp(24px, 2.9vw, 42px); line-height: 1.12; letter-spacing: -0.024em;
  color: var(--ink); max-width: 24ch; }
.vs__d { display: inline-flex; align-items: center; gap: 10px; margin-top: var(--s4);
  font-family: var(--mono); font-size: 11px; line-height: 1.5; color: #4E4E4E; }
.vs__d::before { content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--brand); flex: 0 0 auto; }

/* ⚠️ THE FALLBACK IS A REAL TRANSCRIPT, not a broken pin. Without scroll-driven
   animation every line is `opacity: 0` and the section is blank — so the
   fallback restores them all and stacks them, which is the version this page
   shipped with and is perfectly readable. Same for reduced motion: a reader who
   asked for less movement should not be made to scroll a section to read it. */
@supports not (animation-timeline: view()) {
  .vs { height: auto; }
  .vs__pin { position: static; }
  .vs__lines { display: block; min-height: 0; }
  .vs__l { opacity: 1; animation: none; grid-area: auto;
    padding-block: var(--s4); border-top: 1px solid var(--line); }
  .vs__p { font-size: var(--t-md); max-width: 62ch; }
  .vs__bar { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .vs { height: auto; }
  .vs__pin { position: static; }
  .vs__lines { display: block; min-height: 0; }
  .vs__l { opacity: 1; animation: none; grid-area: auto;
    padding-block: var(--s4); border-top: 1px solid var(--line); }
  .vs__p { font-size: var(--t-md); max-width: 62ch; }
  .vs__bar { display: none; }
}
/* below 900 there is no room to pin a 42px line beside anything, and a phone
   scrolling a pinned section is the thing the founder took off this site */
@media (max-width: 900px) {
  .vs { height: auto; }
  .vs__pin { position: static; }
  .vs__lines { display: block; min-height: 0; }
  .vs__l { opacity: 1; animation: none; grid-area: auto;
    padding-block: var(--s4); border-top: 1px solid var(--line); }
  .vs__p { font-size: var(--t-md); max-width: none; }
  .vs__bar { display: none; }
}

/* ⚠️ A VERBATIM DUPLICATE OF THE `.vln` BLOCK FURTHER DOWN WAS DELETED HERE.
   Two identical copies of every `.vln__*` rule were in this file — same banner,
   same declarations, byte for byte — so the second silently re-applied the
   first, and an edit to one copy would have been overwritten by the other on
   load. Found while renumbering the sections. */

/* The guardrails block (`.vgr`) was DELETED with section 04 — founder-directed,
   "remove 04 section". Its rules went with it rather than being left behind as
   selectors with nothing to select; the page's history is in git, not in dead
   CSS. */

/* ═══════════════════════════════════════════════════════════════
   05 — THE LINE.

   ⚠️ A SEQUENCE DRAWN AS ONE. Three cards say "here are three things"; a line
   with three stops on it says "this, then this, then this" — which is the
   actual claim, and the objection being answered is not what the steps ARE but
   how few of them there are.

   The rule draws in on the section's own view-timeline, so the order is read
   left to right rather than inferred from three numbers.
   ═══════════════════════════════════════════════════════════════ */
.vln__h { font-size: clamp(28px, 2.8vw, 40px); line-height: 1.08; letter-spacing: -0.026em;
  max-width: 18ch; }
.vln__track { position: relative; margin-top: var(--s7);
  view-timeline-name: --vln; view-timeline-axis: block; }
.vln__rule { position: absolute; left: 0; right: 0; top: 26px; height: 1px;
  background: var(--line); }
.vln__rule span { position: absolute; inset: 0 auto 0 0; background: var(--ink);
  animation: vln-draw linear both; animation-timeline: --vln;
  animation-range: entry 20% cover 55%; }
@keyframes vln-draw { from { right: 100%; } to { right: 0; } }
.vln__stops { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s6);
  position: relative; }
@media (max-width: 860px) { .vln__stops { grid-template-columns: 1fr; gap: var(--s5); }
  .vln__rule { display: none; } }
.vln__s { padding-top: var(--s6); }
/* the station: a tick that sits ON the rule, drawn from the stop rather than
   from the rule, so it cannot drift out of alignment with its own column */
.vln__s { position: relative; }
.vln__s::before { content: ''; position: absolute; left: 0; top: 22px; width: 9px; height: 9px;
  border-radius: 50%; background: var(--paper); border: 2px solid var(--ink); }
@media (max-width: 860px) { .vln__s::before { display: none; } }
.vln__n { font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em; color: var(--brand); }
.vln__s b { display: block; margin-top: var(--s3); font-family: var(--display); font-weight: 600;
  font-size: var(--t-md); letter-spacing: -0.02em; line-height: 1.2; color: var(--ink); }
.vln__s p { margin-top: 10px; font-size: var(--t-sm); line-height: 1.55; color: var(--ink-3); }
@supports not (animation-timeline: view()) { .vln__rule span { right: 0; animation: none; } }
@media (prefers-reduced-motion: reduce) { .vln__rule span { right: 0; animation: none; } }

/* ═══════════════════════════════════════════════════════════════
   02 — THE PATH A CALL TAKES (the older rail; see "THE PIPELINE, DRAWN" below
   for what actually renders).

   Founder-directed. Scroll walks the signal from the ring to the answer. Same
   mechanism as §01's scrub, deliberately: a page with two different pinned
   behaviours reads as two pages, and this one is the same gesture applied to a
   different subject — there you drive a recording, here you drive a route.

   ⚠️ THE LABELS LIGHT AND STAY LIT. A spotlight that moves and leaves darkness
   behind it says "here is where you are"; a path that fills says "here is how
   far the call has got", which is the thing being explained. It also means a
   reader who stops halfway can still see what has happened so far.
   ═══════════════════════════════════════════════════════════════ */
.vp { position: relative; height: 340vh;
  view-timeline-name: --vp; view-timeline-axis: block; }
.vp__pin { position: sticky; top: max(var(--s3), calc(50vh - 230px));
  min-height: 460px; display: grid; align-content: center; }
.vp__pin > .wrap { width: 100%; }
.vp__h { font-size: clamp(26px, 2.6vw, 38px); line-height: 1.1; letter-spacing: -0.026em;
  max-width: 22ch; margin-bottom: var(--s6); }

/* ---- the rail ---------------------------------------------------------
   The six labels sit ON the line at even spacing — unlike §01's ticks, which
   are at their real seconds. These are stages, not times: there is no honest
   duration to place them by, and spacing them by a guess would be a chart of
   invented data. */
.vp__rail { position: relative; display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  padding-top: var(--s4); border-top: 1px solid var(--line); }
.vp__fill { position: absolute; left: 0; top: -1px; height: 1px; background: var(--ink);
  animation: vp-fill linear both; animation-timeline: --vp;
  animation-range: contain 0% contain 100%; }
@keyframes vp-fill { from { right: 100%; } to { right: 0; } }
.vp__k { font-family: var(--mono); font-size: 10px; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--ink-4);
  animation-duration: 1s; animation-fill-mode: both; animation-timing-function: linear;
  animation-timeline: --vp; animation-range: contain 0% contain 100%; }

/* ---- the stages -------------------------------------------------------
   One grid cell for all six, so the block never resizes as the call advances —
   a pinned section that changes height drags everything on screen with it. */
.vp__stages { display: grid; margin-top: var(--s6); min-height: 200px; align-content: start; }
.vp__s { grid-area: 1 / 1; opacity: 0;
  animation-duration: 1s; animation-fill-mode: both; animation-timing-function: linear;
  animation-timeline: --vp; animation-range: contain 0% contain 100%; }
.vp__n { font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em; color: var(--brand); }
.vp__t { margin-top: var(--s3); font-family: var(--display); font-weight: var(--w-display);
  font-size: clamp(24px, 2.6vw, 38px); line-height: 1.12; letter-spacing: -0.024em;
  color: var(--ink); max-width: 20ch; }
.vp__b { margin-top: var(--s3); font-size: var(--t-md); line-height: 1.5; color: #4E4E4E;
  max-width: 54ch; }
.vp__end { margin-top: var(--s6); padding-top: var(--s4); border-top: 1px solid var(--line);
  font-size: var(--t-sm); color: #4E4E4E; }
.vp__end b { color: var(--ink); font-variant-numeric: tabular-nums; }

/* the same three fallbacks as §01 — no support, reduced motion, and phones,
   where a pinned section is the thing that came off this site */
@supports not (animation-timeline: view()) {
  .vp { height: auto; } .vp__pin { position: static; }
  .vp__stages { display: block; min-height: 0; }
  .vp__s { opacity: 1; animation: none; grid-area: auto;
    padding-block: var(--s4); border-top: 1px solid var(--line); }
  .vp__t { font-size: var(--t-md); } .vp__k { color: var(--ink); animation: none; }
  .vp__fill { right: 0; animation: none; }
}
@media (prefers-reduced-motion: reduce) {
  .vp { height: auto; } .vp__pin { position: static; }
  .vp__stages { display: block; min-height: 0; }
  .vp__s { opacity: 1; animation: none; grid-area: auto;
    padding-block: var(--s4); border-top: 1px solid var(--line); }
  .vp__t { font-size: var(--t-md); } .vp__k { color: var(--ink); animation: none; }
  .vp__fill { right: 0; animation: none; }
}
@media (max-width: 900px) {
  .vp { height: auto; } .vp__pin { position: static; }
  .vp__rail { display: none; }
  .vp__stages { display: block; min-height: 0; }
  .vp__s { opacity: 1; animation: none; grid-area: auto;
    padding-block: var(--s4); border-top: 1px solid var(--line); }
  .vp__t { font-size: var(--t-md); max-width: none; }
}

/* ============================================================
   THE PAGE'S SURFACES, CARDS AND TYPE.

   ⚠️ THE WHOLE MIDDLE OF THIS PAGE WAS GREY TEXT ON GREY PAPER. Founder: "there
   is a lot of text, no brand colors of that gradient we use everywhere, no
   cards nothing". Three things follow from that, applied to every section
   except 01 and 06 (which he kept):

     · THE GRADIENT IS A SURFACE, not an accent. `.vramp` paints the site's own
       four-stop ramp behind a whole section, so the page alternates warm and
       paper down its length and has a rhythm instead of one flat field.
     · CONTENT SITS ON CARDS. A claim on a card is an object; the same claim as
       a paragraph on the page ground is prose to be waded through.
     · THE COPY IS CUT TO A TITLE AND ONE LINE. Every body here was 30-40 words
       and is now under 15. Nothing true was dropped — what went was the second
       sentence restating the first, which is what made it feel like a lot of
       text.
   ============================================================ */

/* ⚠️ THE WARM WHITE IS THE PAGE'S GROUND, AND IT GOES ON `body` — NOT ON A
   LIST OF SECTIONS. Founder, across two instructions: 01 onto the lightest warm
   white, then "make 03,05 and 06 have the light warm white shade we use
   everywhere in bg". That is every non-ramp section, so it is the ground.

   ⚠️ AND PAINTING IT SECTION-BY-SECTION SHIPPED A VISIBLE BUG. `.crumb-row`
   also carries `.wrap` — it is 1200px wide, not full-bleed — so its warm fill
   painted a white block down the middle of the seam while the body's cool
   `--paper` (#F6F7F8) showed either side of it. Two cold panels flanking the
   divider waveform, which read as a leftover section and were reported as one.
   The cause was the METHOD: a ground asserted on n elements is wrong the first
   time one of them is not full width, and it will be wrong again on the next
   section added. On `body` there is nothing left to get wrong, sections need no
   background at all, and the crumb rule that caused it is deleted rather than
   corrected.

   `body`, not `html`: `html` carries the overscroll canvas (`--slab`) and
   base.css documents why. This is page-scoped because `vsec.css` loads on this
   page only. */
body { background: var(--paper-warm); }

/* ⚠️ THE RAMP IS NOW 02'S ALONE, AND IT ENDS ON THE MOCHA. Founder: "end the
   gradint bg on 02", then "fix the gradient". Section 04 carried the same class
   — so the gradient did not end on 02, it came back forty percent further down.
   That is gone.

   The first attempt at "ending" it made it a SWELL that resolved back to the
   warm white, which was the wrong reading and looked it: the colour peaked
   behind the cards, died before the bottom, and then the band started a second
   white → mocha of its own a few pixels below. Two gradients arguing, neither
   arriving anywhere.

   It now DESCENDS: warm white at the top, deepest mocha at the bottom, ending
   exactly at the band. The white cards gain contrast on the way down, and the
   section has a destination instead of a bulge. */
.vramp { background: linear-gradient(180deg,
    var(--paper-warm) 0%, #F8F0E8 26%, #EFE0D0 62%, #DECBB6 100%); }

/* ⚠️ THE BAND GOES TRANSPARENT HERE, AND KEEPS ITS EDGE AT THE BOTTOM. Its own
   90deg white → mocha exists because on home it sits on flat paper and has to
   supply its own warmth. Here the section arrives at the mocha already, so the
   band lets the ramp through and becomes the last 53px of it — one gradient,
   finishing on a logo strip.
   The hairline moves top → bottom for the same reason: the top is now a seam
   that must not exist, and the bottom is where the warm run genuinely stops
   and the page returns to `--paper-warm`. A logo strip closed by a rule reads
   as a deliberate edge; the same strip open at the bottom reads as a colour
   that ran out. */
.vramp .mq--edge { background: none; border-top: 0;
  border-bottom: 1px solid rgba(15,15,15,0.10);
  /* ⚠️ THE SECTION'S BOTTOM PADDING LIVES HERE. Founder: "add some padding
     bottom to 02". `.sec--band` sets `padding-bottom: 0` because the band has
     to reach the section's edge — so the space the section owes its content
     cannot be padding on the section, or the band stops being flush. It is the
     band's own top margin instead: the ramp keeps running behind it, the gap
     is warm rather than a void, and the band still finishes the section. 128px
     over the inherited 96px, because on home the band follows a full-bleed
     artefact and here it follows a line of text. */
  margin-top: var(--s9); }

/* ⚠️ 02 RUNS TALLER THAN A STANDARD SECTION, AND THE RAMP IS WHY. Founder: "add
   more padding top and bottom to this section". `.sec`'s 128px is set for a
   block on flat paper; here it is also the run-up a 180deg gradient needs to
   travel from warm white to the mocha. At 128px the colour arrives too fast —
   the heading already sits in the tint, so the section reads as a coloured box
   rather than as a page warming up into one. 176px gives the ramp somewhere to
   start.
   The bottom stays 0 because the band has to REACH the section's edge; the
   room below the content is the band's own top margin instead (below). */
.sec--band { padding-top: var(--s9); padding-bottom: 0; }

/* ⚠️ THE PAGE'S OWN SECTION RHYTHM, 96px NOT 128. Founder: "fix the section top
   and bottom paddings here". `.sec`'s site-wide 128 puts 256px of nothing
   between two sections — right on home, where the blocks are dense artefacts
   that need air to separate them, and much too much here, where 03 is one
   diagram and 04 is six short rules. The gap stopped reading as separation and
   started reading as the page having lost its place.

   ⚠️ 01 AND 02 KEEP THEIRS, and that is not an oversight. 01 is a 420vh scrub
   and 02 owns its top pad as the ramp's run-up; both were set deliberately and
   neither is a rhythm value. The close keeps 128 as well — it is the finale and
   wants the extra beat before it. */
/* ⚠️ ON A CLASS, NOT ON IDS, AND THAT IS LOAD-BEARING. Written as
   `#live, #limits, .vln` it was (1,0,0), which silently outranked the band
   exception below it — the exception was in the file, correct, and had no
   effect. Two rules of the SAME specificity, ordered, is the only version where
   "general rhythm, then the one exception" actually behaves that way. */
.sec.vsec { padding-block: var(--s7); }

/* ⚠️ THE SECTION AFTER THE BAND NEEDS MORE, BECAUSE THE BAND GIVES IT NOTHING.
   Founder: "add some section padding top". Every other boundary on this page is
   two paddings meeting — 96 + 96 = 192px. The band is `padding-bottom: 0` by
   necessity (it has to reach 02's edge), so 03 was inheriting a 96px boundary
   where the rest of the page has 192 — AND it is following a full-bleed logo
   strip, which is a hard horizontal edge rather than a soft end of text, so it
   needs at least as much air as an ordinary join, not half of it.

   Keyed off `.sec--band +` rather than off `#live`, so it stays right if a
   section is ever inserted between them. */
.sec--band + .vsec { padding-top: var(--s9); }

/* ═══════════════════════════════════════════════════════════════════════════
   02 — THE PIPELINE, DRAWN.

   ⚠️ THE SIGNAL CHANGES FORM ALONG THE ROW; NOTHING DESCRIBES IT. Founder:
   "make 02 the section defining the pipeline instead of cards saying what no
   one will reads". Every station carries the DATA at that point — a waveform,
   the sentence, the diary rows, a waveform again, the job line — and the only
   prose is a two-word label above each.

   ⚠️ THE TWO WAVEFORMS DIFFER IN COLOUR, DELIBERATELY, and this is the one
   place on the page where that is right. The divider's colour was held fixed
   because it is one continuous recording; here the ink wave is the CALLER and
   the mocha wave is the ANSWER, and telling them apart is the whole point of
   drawing both.

   ⚠️ THE ARROWS CARRY A TOP PAD EQUAL TO THE LABEL. Boxes stretch to a common
   height, so an arrow centred in the full column would sit high by half a
   label. `--vpk` is that offset and it is used in exactly one place. */
/* ⚠️ THE COLUMNS ARE NOT EQUAL, AND THAT IS THE FIX. Five equal boxes gave the
   sentence 188px and broke it over four lines while the two waveforms sat in
   half-empty boxes the same size. Each station holds a different KIND of thing,
   so each gets the width that thing needs — the row still reads as one path
   because the boxes share a height and a baseline, which is what carries the
   sequence, not equal widths. */
.vpipe { --vpk: 25px;
  display: grid; align-items: stretch; margin-top: var(--s6);
  /* ⚠️ RE-BALANCED WHEN THE TYPE GREW. Founder: "make the carrds and content
     slightly bigger here". Scaling the content inside fixed columns re-wrapped
     the two that hold words — the sentence went to three lines, "Dai · Thursday"
     broke in half — because the boxes did not grow with what was in them. The
     waveform columns give the width back: a wave is a graphic and reads at any
     size, a sentence has a length. */
  grid-template-columns: 0.85fr auto 1.5fr auto 1.15fr auto 0.85fr auto 1.35fr; }
.vpipe__s { min-width: 0; display: flex; flex-direction: column; }
.vpipe__k { font-family: var(--mono); font-size: 11px; line-height: 1;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent-ink);
  margin-bottom: 14px; }
.vpipe__box { flex: 1; min-height: 150px; display: flex; flex-direction: column;
  justify-content: center; gap: 8px;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: var(--s4) calc(var(--s4) + 4px);
  box-shadow: 0 1px 2px rgba(31,26,22,0.04), 0 20px 44px -32px rgba(31,26,22,0.35); }

/* the connector — a rule with a head, centred on the boxes */
.vpipe__a { width: clamp(18px, 2.3vw, 38px);
  padding-top: var(--vpk); display: flex; align-items: center; }
.vpipe__a { --wire: rgba(138,106,66,0.42); }
.vpipe__a::before { content: ''; flex: 1; height: 1px; background: var(--wire); }
.vpipe__a::after { content: ''; width: 0; height: 0; margin-left: -1px;
  border-left: 5px solid var(--wire);
  border-top: 3.5px solid transparent; border-bottom: 3.5px solid transparent; }

/* the artefacts */
.vpw { display: flex; align-items: center; gap: 3px; height: 68px; }
.vpw i { flex: 1 1 0; height: calc(var(--h) * 100%); }
/* ⚠️ BOTH WAVES ARE `--accent-ink`, NOT INK AND NOT `--brand`. The caller's
   wave was black and the answer's mocha, to tell the two apart; founder: "make
   it not black and like the it answers one". They are the same voice channel
   drawn twice and the labels above already say which is which, so the colour
   was carrying a distinction the row did not need.
   ⚠️ AND IT IS `--accent-ink`, NOT `--accent`. `--accent` (#DECBB6) is the
   mocha itself but measures 2.1:1 on white — on 5px bars that is the token's
   own documented failure case. `--accent-ink` is the same mocha built to read.
   Not `--brand` either: green is the brand signal and would say "a Levrg
   thing" where the drawing says "the caller" and "the reply". */
.vpw i { background: var(--accent-ink); }

.vpipe__box q { font-family: var(--display); font-weight: 500; quotes: none;
  font-size: clamp(15px, 1.28vw, 18px); line-height: 1.35; letter-spacing: -0.015em; color: var(--ink); }
.vpipe__row { font-family: var(--mono); font-size: clamp(13px, 1.09vw, 15.5px); color: #4E4E4E;
  font-variant-numeric: tabular-nums; }
.vpipe__row b { color: var(--ink); font-weight: 600; }
.vpipe__row--dim { opacity: 0.42; }
.vpipe__row--hd { font-size: clamp(11px, 0.93vw, 13px); letter-spacing: 0.04em; color: var(--ink-4); }
.vpipe__row--ok { color: var(--accent-ink); }
.vpipe__box--job { border-left: 2px solid var(--accent); }
/* ⚠️ THE WAVE BOXES TAKE LESS SIDE PADDING, and without it the wave is a
   hairline. 36px each side out of a 141px box leaves 69px of drawing — the bars
   end up under 2px and the thing stops reading as audio. Text boxes keep the
   full padding because text needs the margin; a graphic that touches nothing
   does not. */
.vpipe__box--wave { padding-inline: var(--s3); }

/* ⚠️ IT TURNS, IT DOES NOT WRAP. Five boxes reflowed to two rows would put the
   arrows in the wrong places and break the one thing the section says: that
   this is a single path. Below the width where five columns hold their words,
   the row becomes a column and the arrows rotate with it. */
@media (max-width: 1080px) {
  .vpipe { flex-direction: column; gap: 0; }
  .vpipe__box { min-height: 0; }
  .vpipe__a { width: 100%; height: 30px; padding-top: 0;
    flex-direction: column; align-items: center; margin-left: var(--s5); }
  .vpipe__a::before { width: 1px; height: auto; }
  .vpipe__a::after { margin: -1px 0 0; border-left: 3.5px solid transparent;
    border-right: 3.5px solid transparent; border-top: 5px solid var(--wire);
    border-bottom: 0; }
  .vpipe__k { margin-top: var(--s3); }
}

.vh2 { font-size: clamp(26px, 2.6vw, 38px); line-height: 1.1; letter-spacing: -0.026em;
  max-width: 20ch; }
/* ⚠️ THE HEADING AND THE LEDE SHARE A ROW. Founder: "what if you move the
   description to the right?" Stacked, they left the whole top-right of the
   section empty above a full-width block, which is the same unowned emptiness
   the diagram below it was just fixed for — the heading was doing the work of
   one column in a two-column section.

   ⚠️ `align-items: baseline`, NOT `start`. A 37px heading and a 24px lede
   aligned at the TOP put their first lines 13px out of register, which reads as
   a mistake at a glance; aligned on the first baseline they sit on one line and
   the pairing looks intended. */
.vhd { display: grid; grid-template-columns: 1fr 1fr; column-gap: var(--s7);
  align-items: baseline; }
/* ⚠️ THE COLUMN IS THE MEASURE NOW, SO THE 32ch CAP COMES OFF. It was derived
   for a lede stacked UNDER the heading, where nothing else constrained it; in
   the right-hand column it only makes the text narrower than the space it has
   and pushes it onto an extra line. Founder: "fix the height arrangement" — a
   two-line heading beside a three-line lede hangs 30px past it, and both halves
   of a baseline-aligned pair should end near each other as well as start
   together. The cap off plus a shorter sentence is what gets both to two
   lines; the cap alone would not. */
.vhd .vlede { margin-top: 0; max-width: none; }
@media (max-width: 900px) {
  .vhd { grid-template-columns: 1fr; row-gap: var(--s4); }
  .vhd .vlede { margin-top: 0; }
}

/* ⚠️ THE LEDE MUST NOT OUT-RUN ITS OWN HEADING. At 50ch it measured 693px of
   text under a 300px heading — more than twice as wide — so the biggest, boldest
   element on the block looked like a caption on top of the paragraph. The
   inversion is the bug; the heading was never the problem.

   32ch is the `.vh2` measure expressed in the lede's own font (20ch at 37.44px
   is 494px; 494 / the lede's ch is ~32), so the two share ONE column edge and
   read as a block. It is stated in ch rather than px so it survives the clamp
   on either font size. */
.vlede { margin-top: var(--s4); font-size: var(--t-md); line-height: 1.5; color: #4E4E4E;
  max-width: 32ch; }
.vfoot { margin-top: var(--s5); font-size: var(--t-sm); color: #4E4E4E; }
.vfoot b { color: var(--ink); font-variant-numeric: tabular-nums; }

.vnote { margin-top: var(--s5); font-size: var(--t-sm); line-height: 1.55;
  color: var(--ink-4); max-width: 68ch; }
/* ---- THE CLOSE --------------------------------------------------------
   ⚠️ THE RAMP, NOT AN INK CARD. The close was a black block, and it drew the
   same objection as section 05: a dark box on a light, warm site. The page now
   ends on the colour it opened with. */
.vclose { background: linear-gradient(180deg,
    #FFFFFF 0%, #FCF9F6 22%, #F1E4D8 62%, #DECBB6 100%); }
/* ⚠️ CENTRED, AND THE MEASURE COMES DOWN WITH IT. Founder: "center the things
   and also make the description shorter". Centred text needs a NARROWER column
   than left-aligned — both edges are ragged, so a long line gives the eye no
   fixed return point and the block reads as drifting. 62ch was set for a
   left-aligned close; at that width, centred, the lede was four ragged lines.
   Shortening the copy is half the fix and this is the other half.
   `margin-inline: auto` on `.wrap` is already there; what is added is the
   centring of the row of actions, which is a flex row and does not follow
   `text-align`. */
.vclose__in { text-align: center; }
/* ⚠️ THE MEASURE IS ON THE TEXT, NOT ON THE CONTAINER — and putting it on the
   container broke the actions. At `max-width: 46ch` the whole block was 46
   characters wide, so the button and the link had no room to sit side by side
   and stacked into a column: a primary action with an orphaned link under it,
   which is not what the row is. The text needs the narrow measure; the row
   needs the column. */
.vclose h2 { max-width: 34ch; margin-inline: auto; }
.vclose p  { max-width: 52ch; margin-inline: auto; }
/* ⚠️ CENTRED COPY HAS TO GET BIGGER TO HOLD A WIDE COLUMN. Founder: "make it
   cover more width, its compressed is what it looks like". Centring a 44px
   heading and a 16px lede inside a 1200px column leaves most of the row empty
   and the block reads as a narrow strip floating in it — compressed, exactly.
   ⚠️ THE WIDTH COMES FROM THE LINE RUNNING LONG, NOT FROM HUGE TYPE. The first
   attempt took the heading to 72px, which filled the column and was immediately
   too big — founder: "bruh, this is too big in font size now". The sentence is
   34 characters: at a moderate 52px it spans ~880px of the 1200 column on ONE
   line, which is the same coverage without shouting. So the measure is set to
   the sentence's own length rather than a narrow wrap, and it breaks to two
   lines on its own once the viewport can no longer hold it. */
.vclose h2 { font-size: clamp(30px, 3.6vw, 52px); line-height: 1.06; letter-spacing: -0.032em; }
/* ⚠️ THE GAP IS SET IN `em` OF THE HEADING, NOT IN A SPACING STEP. Founder:
   "the title is far away from description". It was `--s5` (48px), which is
   correct under a 44px heading and wrong under a 52px one — the heading grew
   when the close was widened and the fixed gap did not, so the lede came loose
   from the thing it belongs to. `0.62em` of the H2 keeps the pair together at
   every step of its own clamp, which is the only version that stays right the
   next time the heading is resized. */
.vclose h2 + p { margin-top: 0.62em; }
.vclose p { font-size: clamp(16px, 1.42vw, 21px); line-height: 1.5; color: #4A4038; }
.vclose__acts { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--s4);
  margin-top: var(--s6); }
.vclose__alt { font-size: var(--t-sm); font-weight: 600; color: var(--ink);
  border-bottom: 1px solid rgba(31,26,22,0.28);
  display: inline-flex; align-items: center; min-height: 24px; }
.vclose__alt:hover { border-bottom-color: var(--ink); }
@media (pointer: coarse) { .vclose__alt { min-height: 44px; } }

/* ═══════════════════════════════════════════════════════════════════════════
   03 — ONE LOOKUP, DRAWN IN FLIGHT.

   ⚠️ ONE, NOT SIX. Founder: "visual representation as in caller asking for …
   then a line node on the right with the google calendar logo and a text of
   'checking' and then a replying thing… just one not 6". Six cards each naming
   a system was a LIST of integrations; what a reader needs to believe is that a
   lookup happens INSIDE the call, and a list cannot show a thing happening. So
   the section is a single round trip: the question, the wire out, the tool, the
   wire back, the answer.

   ⚠️ THE NODE IS VERTICALLY CENTRED BETWEEN THE TWO TURNS, which is what makes
   the shape read as a detour rather than as three stacked rows. The turns take
   grid rows 1 and 2 in the left column; the wire and the node span both.

   ⚠️ THE DASH TRAVELS OUT, THEN BACK, and the delay is not decoration: the two
   curves are one gesture and simultaneous motion on both would read as two
   wires rather than as a trip. `--flow` is the duration of one leg; the return
   starts exactly when the outbound ends.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ⚠️ IT IS A PANEL, BECAUSE A DIAGRAM NEEDS A SURFACE. Founder: "not the best
   section layout here". Laid out loose on the page, the exchange put the
   heading, both turns and the note in a narrow left column and left the whole
   top-right of the section empty — the wire then ran 590px across that hole,
   which drew attention to it rather than crossing it. The emptiness was never
   the problem; unowned emptiness was. Inside a bordered panel the same gap is
   deliberate space within an object, and the section gets the full-width block
   under a left-aligned heading that 02, 04 and 05 all have — so it reads as the
   page's rhythm rather than as a section built differently.

   The wash is the site's own warm ramp on the diagonal, which is also the only
   ground the white node card can sit on and still read as a card. */
.vtc { --flow: 1.5s;
  background: linear-gradient(135deg, #FFFEFC 0%, #FBF3EA 62%, #F3E5D6 100%);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: var(--s6) var(--s6) calc(var(--s6) + 4px);
  display: grid; align-items: center; margin-top: var(--s6);
  /* ⚠️ COLUMN 1 IS THE TEXT'S WIDTH, NOT THE COLUMN'S, AND THE WIRE TAKES THE
     SLACK. At `1fr` the turns' column ran the full 618px while the words stopped
     around 460 — so the curve began 150px past the end of the sentence and read
     as a squiggle floating beside it rather than as a line leaving it. Pinning
     column 1 near the text measure and giving the wire `1fr` puts the start of
     the curve just past the longest line and still lands the node flush right,
     at every width. */
  grid-template-columns: clamp(220px, 24vw, 350px) 1fr minmax(0, 330px);
  grid-template-rows: auto auto; column-gap: 0; row-gap: var(--s6); }

.vtc__turn { grid-column: 1; grid-row: 1; }
.vtc__turn--out { grid-row: 2; }
.vtc__who { display: block; font-family: var(--mono); font-size: 11px; line-height: 1;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent-ink);
  margin-bottom: 14px; }
.vtc__turn p { font-family: var(--display); font-weight: 500;
  font-size: clamp(19px, 1.95vw, 28px); line-height: 1.22; letter-spacing: -0.022em;
  color: var(--ink); max-width: 20ch; }

/* ⚠️ THE SVG IS ABSOLUTELY POSITIONED INSIDE A BOX, AND IT HAS TO BE. As a
   grid item it carried its viewBox's aspect ratio into row sizing: at 388px
   wide, 120:230 asked for 744px of HEIGHT, and the two rows stretched to give
   it — a 400px gap between two sentences that are 90px tall. Nothing in the
   rules said "make this section tall"; an intrinsic ratio did it silently.
   Inside a relatively-positioned box the svg contributes nothing to layout and
   the rows size from the turns and the node, which is what defines them. */
.vtc__wirebox { grid-column: 2; grid-row: 1 / 3; position: relative; align-self: stretch; }
.vtc__wire { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.vtc__w { fill: none; stroke: rgba(138,106,66,0.34); stroke-width: 1.25; }
.vtc__f { fill: none; stroke: var(--accent-ink); stroke-width: 1.6; stroke-linecap: round;
  stroke-dasharray: 5 260; stroke-dashoffset: 265;
  animation: vtc-flow calc(var(--flow) * 2) linear infinite; }
.vtc__f--b { animation-delay: var(--flow); }
@keyframes vtc-flow {
  0%   { stroke-dashoffset: 265; opacity: 0; }
  4%   { opacity: 1; }
  46%  { stroke-dashoffset: 0;   opacity: 1; }
  50%, 100% { stroke-dashoffset: 0; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .vtc__f { animation: none; opacity: 0; } }

.vtc__node { grid-column: 3; grid-row: 1 / 3;
  display: flex; flex-direction: column; gap: 9px;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: var(--s4) calc(var(--s4) + 4px);
  box-shadow: 0 1px 2px rgba(31,26,22,0.04), 0 20px 44px -32px rgba(31,26,22,0.35); }
.vtc__nh { display: flex; align-items: center; gap: 11px; margin-bottom: 3px; }
/* ⚠️ MONOCHROME, AND IT IS THE SITE'S RULE. home.css states it for the
   Built-using band: this page "has no colour outside the green signal", and a
   full-colour brand mark on a warm white card would be the loudest thing on the
   page. The calendar tile's shape carries the recognition on its own. */
.vtc__mk { width: 21px; height: 21px; flex: 0 0 auto; fill: var(--ink-4); opacity: 0.62; }
.vtc__k { font-family: var(--mono); font-size: 11px; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--accent-ink); }
.vtc__row { font-family: var(--mono); font-size: clamp(13px, 1.09vw, 15.5px);
  color: #4E4E4E; font-variant-numeric: tabular-nums; }
.vtc__row b { color: var(--ink); font-weight: 600; }
.vtc__row--dim { opacity: 0.42; }

/* ⚠️ THE WIRE GOES, IT DOES NOT ROTATE. Below the width where three columns
   hold their words, a curve drawn for a horizontal detour is wrong in every
   direction — so the diagram becomes what it always was underneath: ask, tool,
   answer, in order down the page. */
@media (max-width: 900px) {
  .vtc { grid-template-columns: minmax(0, 1fr); row-gap: var(--s5);
    padding: var(--s5) var(--s4); }
  .vtc__wire { display: none; }
  .vtc__turn, .vtc__turn--out, .vtc__node { grid-column: 1; grid-row: auto; }
  .vtc__turn p { max-width: none; }
}