/* Video Editing service page: everything unique to prototype/services/video-editing.html.
   Loads after tokens.css, sarafi.css, site.css and service.css, and reuses their pieces: the split hero and its stack,
   .final, .fit-cards, .connected, .checklist and the .sc-track / .sc-playhead timeline parts. Page-scoped: every class
   starts with ve-. Mobile-first min-width steps (360, 480, 560, 700, 768, 900, 1024, 1280, and 1440 for the hero's
   bleed); the only max-width queries are the landscape-phone sticky offset and .ve-hide-sm in part 00. No infinite
   animation: every decorative one is .ve-anim, and the loops inherited from site.css (hero aurora and stack bob, final
   box blobs) are off (parts 01, 13).
   The spec is design/video-editing-redesign/blueprint.md: the §, R and N codes in the comments point into it, and C
   (claims to confirm), P (proof to supply) and D (owner decisions) are the open items in its §7.
   Parts, in page order: 00 Shared helpers · 01 Hero + method rail · 02 Platforms and proof strip · 03 What we do ·
   04 The problem · 05 How it works · 06 Nine video types · 07 Monthly editing + custom projects · 08 Why Sarafi ·
   09 Sarafi vs other options · 10 Case study · 11 Works best with · 12 FAQ · 13 Final CTA. */

/* ======================================================================
   00 Shared helpers: the pieces more than one section uses
   ====================================================================== */
/* Everything reads Sarafi tokens, so it flips with the surface and the theme. The only hard-coded colours are inside
   .ve-screen / .ve-stage devices, which are pictures of screens (like .stack__card), built from the brand hexes. */

/* ---------- Sticky offsets ----------
   --ve-sticky-top: the sticky line under the capsule header. Landscape phones: the header scrolls away (sarafi.css),
   so 0. --ve-types-bar: the outer height of the sticky type nav in 06 (border-box). While that nav is stuck (from
   768px), video-editing.js adds .ve-types-stuck to <html>, so focus scrolling and anchor jumps clear the bar as well
   as the header (WCAG 2.2 2.4.11). html has scroll-padding-top: header + 16px in sarafi.css; this rule is 0,1,1 and
   wins. */
:root { --ve-sticky-top: var(--sf-header-height); --ve-types-bar: 56px; }
@media screen and (max-width: 1023px) and (max-height: 500px) { :root { --ve-sticky-top: 0px; } }
html.ve-types-stuck { scroll-padding-top: calc(var(--ve-sticky-top) + var(--ve-types-bar) + 16px); }

/* ---------- Split section head (the reference's .split-head) ----------
   <div class="ve-head" data-sf-reveal>
     <div class="ve-head__main"><span class="sf-eyebrow">…</span><h2 class="sf-h2" id="…">Main clause <span class="sf-serif">serif clause.</span></h2></div>
     <p class="sf-lead">…</p>
   </div>
   One column below 1024px. From 1024px: heading left, lead right on the heading's baseline; the serif clause takes its
   own line (the reference's two-tone H2). --std is the narrower heading column; --long is for a long lead (below);
   --center is the services head. */
.ve-head { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: 18px; margin-bottom: clamp(40px, 5vw, 64px); }
.ve-head .sf-h2 { margin-top: 14px; }
.ve-head > .sf-lead { margin: 0; }
@media (min-width: 1024px) {
  .ve-head { grid-template-columns: minmax(0, 1.65fr) minmax(0, 1fr); column-gap: 64px; align-items: end; }
  .ve-head--std { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
  .ve-head > .sf-lead { padding-bottom: 6px; }
  .ve-head .sf-h2 .sf-serif { display: block; }
}
/* --long: a lead that runs far longer than its heading (03, the owner's 4-sentence intro: 7 lines beside a 2-line heading
   at 1440, 10 at 1024). Split and bottom-aligned, the heading would sit under an empty block. 1024-1279: stacked, the
   lead under the heading at a 62ch measure. From 1280: a split top-aligned, with the lead's first line level with the
   heading's (the eyebrow, its 14px gap, and the difference in half-leading). 1.2fr and a 56px gap keep 03's first
   clause ("Everything between the idea", 617px at 1280) on one line. */
@media (min-width: 1024px) {
  .ve-head--long { grid-template-columns: minmax(0, 1fr); }
  .ve-head--long > .sf-lead { max-width: 62ch; padding-bottom: 0; }
}
@media (min-width: 1280px) {
  .ve-head--long { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); column-gap: 56px; align-items: start; }
  .ve-head--long > .sf-lead { max-width: none; padding-top: 32px; }
}
.ve-head--center { max-width: 880px; margin-inline: auto; text-align: center; }
@media (min-width: 1024px) { .ve-head--center { grid-template-columns: minmax(0, 1fr); } }
.ve-head--center > .sf-lead { max-width: 40em; margin-inline: auto; }
/* Print: a head is never split, nor left at the foot of a page without what follows it. */
@media print { .ve-head { break-inside: avoid; break-after: avoid; } }

/* ---------- Card headings: balanced lines ----------
   Short headings on narrow cards otherwise end on one word ("Polished, but it doesn't say / anything" at 320,
   "Formats for every / platform" at 1024, "Brand Identity & / Design" at 768). Balance evens the lines out; browsers
   without it keep the normal wrap. */
:is(.ve-what__title, .ve-problem__title, .ve-process__title, .ve-why__title, .ve-plans__custom-title, .ve-plans__step h4,
  .ve-faq__contact-title, .ve-related .connected__title) { text-wrap: balance; }

/* ---------- Running text: no lone last word ----------
   Paragraphs, list items, table cells and captions otherwise end on one word ("… production and / editing." in the
   compare table at 1440, "… before any work / starts." at 320). pretty re-wraps only a block's last lines. It is set
   on the sections and inherited, so every balance or nowrap rule on an element still wins; browsers without it keep
   the normal wrap. */
#main > section { text-wrap: pretty; }

/* ---------- Micro labels and numbers (the reference's mono labels, in Manrope) ---------- */
.ve-label { display: block; margin: 0; font-size: var(--sf-fs-label); line-height: var(--sf-lh-label); font-weight: var(--sf-fw-semibold);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--sf-fg-muted); }
.ve-label--accent { color: var(--sf-fg-accent); }
.ve-num { font: var(--sf-fw-semibold) 0.8125rem/1 var(--sf-font-sans); letter-spacing: 0.1em; font-variant-numeric: tabular-nums; color: var(--sf-fg-accent); }
.ve-num--muted { color: var(--sf-fg-muted); }

/* ---------- Tint: text on a tinted inner panel (R1) ----------
   Slate (#7F879B) on a white-6% panel over a dark card measures 4.10:1 (Night Soft) and 4.24:1 (Deep Blue): below AA.
   Any element whose own fill is a tint (var(--sf-hover), a well, a wash) gets .ve-tint: on dark surfaces its muted and
   running text become Slate 85% on white (#9299AA), 5.17-5.35:1 on the tint. Built from the primitives: a variable
   that reads itself on the same element is a cycle. Dark surfaces only: the dark theme, and the .sf-dark sections of
   the default mix (no data-theme, the no-JS view; body is .sf-dark there, so the selector names the section). Not inside
   an .sf-glow (hero, final box): those already run a lighter slate. Light surfaces pass as they are (5.78:1 at worst). */
:root[data-theme="dark"] :is(.ve-tint, .ve-well):not(.sf-glow *),
:root:not([data-theme]) section.sf-dark:not(.sf-glow) :is(.ve-tint, .ve-well) {
  --sf-fg-muted: color-mix(in srgb, var(--sf-slate) 85%, var(--sf-white));
  --sf-fg-body: color-mix(in srgb, var(--sf-slate) 85%, var(--sf-white));
}

/* ---------- Well: a quiet inner panel for an illustration on a sheet (follows the surface; carries the tint) ---------- */
.ve-well { position: relative; border: 1px solid var(--sf-border); border-radius: var(--sf-radius-sm);
  background: radial-gradient(circle, color-mix(in srgb, var(--sf-fg) 10%, transparent) 1px, transparent 1.5px) 0 0 / 16px 16px, var(--sf-hover); }

/* ---------- Screen and stage ----------
   .ve-screen: a picture of a screen (a device), dark in both themes. Text inside is white, never below white 62%
   (.ve-screen-muted: 5.5:1 at the brightest point of the fill, 6.8:1 typical).
   .ve-stage (R9): the media box that holds devices (06 type cards). Dark theme and default mix: the same dark picture.
   Light theme: a light stage (the --sf-well wash and a dot grid on white), so a long run of type cards does not read as
   a second dark chapter; only the devices on it stay dark. Rule for everything in a stage: text lives inside a device
   (.ve-screen, .ve-phone, .ve-viewer), a .ve-float or the .art__tag, never loose on the stage. */
.ve-screen, .ve-stage { position: relative; overflow: hidden; isolation: isolate; border: 1px solid rgba(255, 255, 255, 0.1); border-radius: var(--sf-radius-sm);
  color: var(--sf-white);
  background:
    radial-gradient(60% 55% at var(--ve-glow-x, 72%) var(--ve-glow-y, 18%), rgba(140, 77, 255, 0.30), transparent 70%),
    radial-gradient(55% 50% at 12% 92%, rgba(70, 119, 255, 0.22), transparent 70%),
    linear-gradient(160deg, #1A2142 0%, #0D1122 100%);
  -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.ve-screen::before, .ve-stage::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px);
  background-size: 32px 32px; }
:root[data-theme="light"] .ve-screen { border-color: rgba(255, 255, 255, 0.08); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06); }
:root[data-theme="light"] .ve-stage { border-color: var(--sf-border);
  background: radial-gradient(circle, rgba(36, 60, 160, 0.10) 1px, transparent 1.5px) 0 0 / 16px 16px, var(--sf-well), var(--sf-white); }
:root[data-theme="light"] .ve-stage::before { display: none; }
:root[data-theme="light"] .ve-stage :is(.ve-screen, .ve-viewer) { box-shadow: 0 18px 36px -20px rgba(9, 11, 20, 0.45); }
.ve-screen-muted { color: rgba(255, 255, 255, 0.62); }

/* Tag position (R2). site.css pins .art__tag bottom-left, where it lands on timelines and floats. In a screen, a stage or
   the hero stack it sits top-right, 12px in: every mock keeps its top-right 140 x 40px free (the tag zone). A mock with
   a title bar (the hero editor, the pipeline head) puts the tag in the bar instead: .art__tag.ve-tag-inline. */
:is(.ve-screen, .ve-stage) > .art__tag, .ve-hero .stack__card > .art__tag { left: auto; right: 12px; top: 12px; bottom: auto; border: 1px solid rgba(255, 255, 255, 0.14); }
.art__tag.ve-tag-inline { position: static; flex: none; border: 1px solid rgba(255, 255, 255, 0.14); }

/* Brand pieces only inside pictures (R3). The site's ok icon is success green and its pill is the CTA gradient; on this
   page a done state is lavender and an in-mock button is a white (or ghost) pill, so neither the reference's green checks
   nor a second gradient appear in a mock. The music waveform turns lavender for the same reason. */
:is(.ve-screen, .ve-stage, .ve-hero) .sc-note__icon--ok { background: rgba(200, 183, 255, 0.16); color: var(--sf-soft-lavender); }
:is(.ve-screen, .ve-stage, .ve-hero) .sc-pill:not(.sc-pill--ghost) { background: var(--sf-white); color: var(--sf-midnight); }
:is(.ve-screen, .ve-stage, .ve-hero) .sc-track--music i { background: rgba(200, 183, 255, 0.5); }

/* Tag on a screen: dark glass pill (a tag, so a pill is allowed). --plain drops the dot. 8.1:1 even on a light stage. */
.ve-float { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--sf-radius-pill); background: rgba(9, 11, 20, 0.72); color: var(--sf-white);
  font-size: 0.6875rem; font-weight: var(--sf-fw-semibold); line-height: 1.2; white-space: nowrap; }
.ve-float::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--sf-soft-lavender); }
.ve-float--plain::before { display: none; }

/* Viewer (16:9 programme monitor) and phone (9:16) frames, plus the pieces that go in them. */
.ve-viewer { position: relative; aspect-ratio: 16 / 9; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 6px;
  background: radial-gradient(42% 58% at 50% 36%, rgba(200, 183, 255, 0.30), transparent 70%), linear-gradient(170deg, #2A356B 0%, #1A1440 70%, #0E1224 100%); }
.ve-phone { position: relative; aspect-ratio: 9 / 16; overflow: hidden; padding: 8px; border: 1px solid rgba(255, 255, 255, 0.16); border-radius: 14px;
  color: var(--sf-white);
  background: radial-gradient(circle at 60% 32%, rgba(200, 183, 255, 0.42), transparent 45%), linear-gradient(170deg, #2A356B 0%, #1A1440 70%, #0E1224 100%);
  box-shadow: 0 24px 48px -24px rgba(0, 0, 0, 0.7); -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.ve-safe { position: absolute; inset: 9% 7%; border: 1px dashed rgba(255, 255, 255, 0.3); border-radius: 4px; pointer-events: none; }
.ve-subject { position: absolute; left: 50%; bottom: 0; width: 34%; aspect-ratio: 1 / 1.1; translate: -50% 0; pointer-events: none;
  background: radial-gradient(circle at 50% 30%, rgba(9, 11, 20, 0.85) 0 21%, transparent 22%),
    radial-gradient(ellipse 50% 42% at 50% 100%, rgba(9, 11, 20, 0.85) 0 98%, transparent 100%); }
.ve-caption { position: absolute; left: 8%; right: 8%; bottom: 9%; z-index: 1; display: flex; flex-wrap: wrap; justify-content: center; gap: 4px;
  margin: 0; font-size: 0.75rem; font-weight: var(--sf-fw-bold); line-height: 1.25; text-align: center; }
.ve-caption span { padding: 3px 6px; border-radius: 4px; background: rgba(9, 11, 20, 0.78); color: var(--sf-white); }

/* ---------- Timeline kit (R4): one look for every timeline (hero editor, core card, talking head, YouTube) ----------
   <div class="ve-timeline">
     <div class="ve-timeline__ruler"><span>00:00</span><span>00:10</span>…</div>            optional
     <div class="ve-timeline__beats"><span style="--w:20%">Hook</span>…</div>               optional
     <div class="ve-timeline__tracks">
       <div class="sc-track sc-track--video"><em>V1</em><span><i style="--w:30%"></i>…</span></div>
       <div class="sc-track sc-track--text"><em>Caps</em><span><i style="--x:10%;--w:24%"></i></span></div>
       <div class="sc-track sc-track--music"><em>A1</em><span><i style="--h:40%"></i>…</span></div>
       <div class="ve-timeline__lane"><span class="sc-playhead ve-anim"></span></div>     optional playhead
     </div>
   </div>
   Lives inside a dark device. --compact makes 14px tracks. The ruler and beats line up with the clip lane, after the
   label column. The playhead rests at --ve-play (52%); .ve-anim scrubs it once from 8% (see Motion). */
.ve-timeline { --ve-tl-label: 36px; display: grid; gap: 6px; min-width: 0; }
@media (min-width: 560px) { .ve-timeline { --ve-tl-label: 44px; } }
.ve-timeline .sc-track { grid-template-columns: var(--ve-tl-label) minmax(0, 1fr); }
.ve-timeline--compact .sc-track > span { height: 14px; }
.ve-timeline--compact .sc-track--text i { top: 2px; height: 10px; }
.ve-timeline__ruler, .ve-timeline__beats { display: flex; min-width: 0; margin-left: calc(var(--ve-tl-label) + 8px); }
.ve-timeline__ruler { justify-content: space-between; font-size: 10px; line-height: 1; font-variant-numeric: tabular-nums; color: rgba(255, 255, 255, 0.62); }
.ve-timeline__beats { gap: 3px; }
.ve-timeline__beats > span { flex: 0 1 var(--w, 25%); min-width: 0; overflow: hidden; padding: 4px 6px 3px; border-top: 2px solid rgba(200, 183, 255, 0.55);
  border-radius: 0 0 3px 3px; background: rgba(200, 183, 255, 0.10); color: rgba(255, 255, 255, 0.86);
  font-size: 10px; font-weight: var(--sf-fw-semibold); line-height: 1.2; white-space: nowrap; text-overflow: ellipsis; }
.ve-timeline__tracks { position: relative; display: grid; gap: 5px; }
.ve-timeline__lane { position: absolute; top: -6px; bottom: -2px; left: calc(var(--ve-tl-label) + 8px); right: 0; pointer-events: none; }
.ve-timeline__lane .sc-playhead { top: 0; bottom: 0; left: var(--ve-play, 52%); }

/* ---------- Price block (R5): one switch for every price on the page ----------
   D1 is open, so each block carries both versions. [data-ve-prices="off"] on <main> swaps every "Starting from [$ price]" for the quote line; the basis line shows in both.
   <div class="ve-price">
     <div class="ve-price__on"><span class="ve-label">Starting from</span>
       <p class="ve-price__value">[$ price] <span class="ve-price__unit">/ video</span></p></div>
     <div class="ve-price__off"><span class="ve-label">Pricing</span>
       <p class="ve-price__value ve-price__value--text">Priced per project</p></div>
     <p class="ve-price__basis">Depends on …</p>
   </div> */
.ve-price { display: grid; gap: 6px; margin: 0; }
.ve-price__on, .ve-price__off { display: grid; gap: 4px; }
.ve-price__off { display: none; }
[data-ve-prices="off"] .ve-price__on { display: none; }
[data-ve-prices="off"] .ve-price__off { display: grid; }
/* Copy that only holds while prices show, such as the hero's "See video types and pricing": with the switch off the
   link reads "See video types". */
[data-ve-prices="off"] .ve-if-prices { display: none; }
.ve-price__value { margin: 2px 0 0; font-size: clamp(1.5rem, 1.3rem + 0.6vw, 2rem); font-weight: var(--sf-fw-extrabold); line-height: 1.1;
  letter-spacing: -0.02em; color: var(--sf-fg); }
.ve-price__value--text { font-size: 1.25rem; font-weight: var(--sf-fw-bold); letter-spacing: -0.01em; }
/* The unit follows a real space in the text ("[$ price] / video"), so copy-paste and screen readers get the spacing
   too. The space is 4-5px at the value's size; 2px of margin keeps the old 6-7px gap. */
.ve-price__unit { margin-left: 2px; font-size: 0.9375rem; font-weight: var(--sf-fw-medium); letter-spacing: 0; color: var(--sf-fg-muted); }
.ve-price__basis { margin: 0; max-width: 44ch; font-size: var(--sf-fs-small); line-height: var(--sf-lh-small); color: var(--sf-fg-muted); }

/* ---------- Phone trims (R15, R16) ----------
   Decoration that only earns its space on wider screens: hidden below 560px. Never on text the page needs. */
@media (max-width: 559px) { .ve-hide-sm { display: none !important; } }

/* ---------- Placeholders (N10) ----------
   Every block that must go before launch carries data-ve-placeholder and an HTML comment naming its decision
   (P1, P4, P5 ...). At launch each one still empty is removed from the page with its comment (blueprint §6); the
   attribute itself has no style, except the hatched placeholder bars in part 10. */

/* ---------- Motion: the .ve-anim contract (R21) ----------
   Any decorative animation gets .ve-anim and follows four rules:
   1. It ends within 5s of starting (delay + duration x iterations), so WCAG 2.2.2 needs no pause control. No infinite
      loops on this page: the loops it inherits from site.css (the hero aurora and stack bob, the final box's blobs) are
      switched off in parts 01 and 13, and rest in their `from` state.
   2. It runs once, when its card or block gets .is-revealed (sarafi.js), or at load in the hero.
   3. Its resting, un-animated state is the final state, so no JS, reduced motion and print show the finished picture.
      Write the keyframes with only a `from` (or `from` + mid steps) and animation-fill-mode: both.
   4. Reduced motion switches it off (below). .is-offscreen pauses it (sections with data-sf-parallax). */
@keyframes ve-scrub { from { left: 8%; } }
.ve-hero .ve-timeline__lane .sc-playhead.ve-anim,
.sf-js .is-revealed .ve-timeline__lane .sc-playhead.ve-anim { animation: ve-scrub 4200ms var(--sf-ease-out) 400ms both; }
.is-offscreen .ve-anim, .is-offscreen .ve-anim::before, .is-offscreen .ve-anim::after { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .ve-anim, .ve-anim::before, .ve-anim::after { animation: none !important; transition: none !important; }
}

/* ---------- Reveal on focus (WCAG 2.4.7) ----------
   A reveal block that holds keyboard focus shows at once, without the fade, even when sarafi.js has not revealed it yet
   (it can sit in the bottom 10% of the window, below the reveal line); video-editing.js then marks it revealed for good.
   0,3,0: it beats sarafi.css's hidden state and depth pose (0,2,0). The states that wait for .is-revealed inside a block
   (brief rows, case bars, rail fill) print and show without it: see each part's print block. */
.sf-js [data-sf-reveal]:focus-within { opacity: 1; translate: none; rotate: none; transition: none; }

/* ======================================================================
   01 Hero + method rail (blueprint §3 01)
   ====================================================================== */
/* The site's split hero (site.css) with this page's own stack: an editing window (A), the brief's objective (B) and the
   export queue (C). No stack--* modifier: the tablet rules in service.css key on one and would fight this layout,
   and its generic .stack__layer--a/b/c rules are overridden here, under .ve-hero. Mobile-first: the base is the phone
   layout, and each step (768, 1024, 1280) overrides the one before it. */

/* ---------- Section ---------- */
/* The rail closes the hero, so the bottom padding is short (site.css: 64-112px). */
.split-hero.ve-hero { padding-bottom: 40px; }

/* ---------- Copy column: the micro line and the jump to the types, then the proof line (site.css) ---------- */
.ve-hero__meta { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; margin-top: 18px; }
.ve-hero__micro { margin: 0; font-size: var(--sf-fs-small); line-height: var(--sf-lh-small); color: var(--sf-fg-muted); }
.ve-hero__jump { font-size: var(--sf-fs-small); }
@media (min-width: 768px) { .ve-hero__meta { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: 6px 20px; } }

/* ---------- Grid ---------- */
/* 1024: two near-equal columns (site.css has 7fr / 5fr). At exactly 1:1 the copy column is 448px at 1024 and the two large
   CTAs (454px together) wrap, so the copy takes 1.05fr until 1280. 1280: the reference's 1 : 1.06, centred. */
@media (min-width: 1024px) { .ve-hero .ve-hero__grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); gap: 48px; } }
@media (min-width: 1280px) { .ve-hero .ve-hero__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.06fr); gap: 64px; align-items: center; } }

/* ---------- The stack ----------
   Phones (base): a flow, not a composition. The editor is full width, the objective note is dropped (the copy already
   says it) and the export queue sits under the editor. This also beats service.css's fixed stack heights at 389px and
   below. The cards never bob on this page: site.css's stack-bob loops without end (WCAG 2.2.2 Pause, Stop, Hide), and
   on phones two cards in a column that bob out of step read as jitter. The depth and the parallax stay. */
.ve-hero .ve-hero__stack { width: 100%; height: auto; aspect-ratio: auto; transform: none; }
.ve-hero .stack__layer { position: static; inset: auto; width: auto; transform: none; translate: none; }
.ve-hero .stack__layer--b { display: none; }
.ve-hero .stack__layer--c { margin-top: 14px; }
.ve-hero .stack__card { animation: none; }
/* The aurora behind the hero (site.css) drifts in infinite 17-31s loops. Here it rests where site.css places it (each
   loop's `from` state, which is also the reduced-motion and print picture), so the page has no motion that runs longer
   than 5s and needs no pause control (WCAG 2.2.2). It still shifts with the scroll parallax (data-sf-depth). */
.ve-hero :is(.hero__blob, .hero__beam) { animation: none; }

/* 768: a composition in depth, with the site's tablet rotation. The note and the queue overlap the editor's corners. */
@media (min-width: 768px) {
  .ve-hero .ve-hero__stack { width: min(560px, 100%); aspect-ratio: 1 / 0.82; margin-inline: auto; transform: rotateY(-8deg) rotateX(6deg); }
  .ve-hero .stack__layer { position: absolute; }
  .ve-hero .stack__layer--a { left: 0; top: 6%; width: 100%; transform: translateZ(10px); }
  .ve-hero .stack__layer--b { display: block; left: 0; right: auto; top: -2%; width: 44%; transform: translateZ(60px); }
  .ve-hero .stack__layer--c { left: auto; right: 0; top: auto; bottom: -4%; width: 46%; margin-top: 0; transform: translateZ(110px); }
}
/* 1024: beside the copy. The column is about 425px, so the editor drops its bins (container query below) and grows
   taller than it is wide: the stack takes a taller ratio, so the queue still lands on the timeline, not the viewer. */
@media (min-width: 1024px) {
  .ve-hero .ve-hero__stack { width: min(480px, 100%); aspect-ratio: 1 / 1.1; transform: rotateY(-12deg) rotateX(6deg); }
  .ve-hero .stack__layer--b { width: 62%; }
  .ve-hero .stack__layer--c { width: 56%; }
}
/* 1280: the full editor, a gentler angle, and the two floats bleed past its edges. The export queue's full -5% bleed
   waits for 1440: below that the stack reaches the container's edge and #top clips at the viewport (overflow: hidden),
   so -5% cut the card's right edge off at 1280-1365. Flush (right: 0) left it 4-6px past the editor, which read as a
   slip. So it bleeds by a clear, smaller amount: -12px up to 1366 (about 16px past the editor, 13px or more inside the
   viewport), growing with the window to meet the -5% at 1440. */
@media (min-width: 1280px) {
  .ve-hero .ve-hero__stack { width: min(620px, 100%); aspect-ratio: 1 / 0.82; transform: rotateY(-10deg) rotateX(6deg); }
  .ve-hero .stack__layer--a { top: 6%; }
  .ve-hero .stack__layer--b { left: -4%; top: -2%; width: 44%; }
  .ve-hero .stack__layer--c { right: clamp(-5%, calc(-12px - (100vw - 1366px) / 4), -12px); bottom: -4%; width: 46%; }
}
@media (min-width: 1440px) { .ve-hero .stack__layer--c { right: -5%; } }

/* ---------- A: the editor window ----------
   A picture of a screen, dark in both themes (the .stack__card fill). It is a size container: its bins column shows
   only when the window is at least 520px wide. */
.ve-hero__editor { container-type: inline-size; padding: 0; overflow: hidden; }
.ve-hero__bar { display: flex; align-items: center; gap: 8px; min-width: 0; padding: 9px 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.08); background: rgba(255, 255, 255, 0.03); }
.ve-hero__dots { display: inline-flex; flex: none; gap: 5px; }
.ve-hero__dots i { width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, 0.2); }
.ve-hero__file { min-width: 0; overflow: hidden; margin-left: 4px; font-size: 0.6875rem; white-space: nowrap; text-overflow: ellipsis; }
.ve-hero__bar .art__tag { margin-left: auto; padding: 3px 7px; font-size: 11px; }
.ve-hero__tc { flex: none; font-size: 0.6875rem; font-weight: var(--sf-fw-semibold); font-variant-numeric: tabular-nums; letter-spacing: 0.04em; color: var(--sf-soft-lavender); }
.ve-hero__body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; padding: 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.08); }
.ve-hero__bins { display: none; }
@container (min-width: 520px) {
  .ve-hero__body { grid-template-columns: 124px minmax(0, 1fr); }
  .ve-hero__bins { display: flex; flex-direction: column; gap: 9px; min-width: 0; padding: 2px 12px 0 2px; border-right: 1px solid rgba(255, 255, 255, 0.08); }
}
.ve-hero__bins-title { font-size: 10px; font-weight: var(--sf-fw-semibold); letter-spacing: 0.1em; text-transform: uppercase; color: rgba(255, 255, 255, 0.62); }
.ve-hero__bin { display: flex; align-items: center; gap: 8px; min-width: 0; overflow: hidden; font-size: 11px; line-height: 1.2; white-space: nowrap; text-overflow: ellipsis; color: rgba(255, 255, 255, 0.72); }
/* Clip thumbnails in the brand tints. */
.ve-hero__thumb { flex: none; width: 16px; height: 11px; border-radius: 2px; background: linear-gradient(135deg, #4677FF, #2A356B); }
.ve-hero__thumb--purple { background: linear-gradient(135deg, #8C4DFF, #3B2A6B); }
.ve-hero__thumb--lavender { background: linear-gradient(135deg, #C8B7FF, #6B5BB0); }
.ve-hero__thumb--deep { background: linear-gradient(135deg, #2A356B, #11172A); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18); }
/* The timeline is the shared kit (part 00). Here: a faint lane under each track, and the graphics (V3) and
   B-roll (V2) clips in single brand tints so the three video tracks read apart. Clips sit at --ve-x from the one before. */
.ve-hero__timeline { padding: 10px 12px 12px; }
.ve-hero__timeline .sc-track > span { border-radius: 4px; background: rgba(255, 255, 255, 0.03); }
.ve-hero__timeline .sc-track--video i { margin-left: var(--ve-x, 0px); }
.ve-hero__timeline .ve-hero__track--gfx i { background: rgba(140, 77, 255, 0.6); }
.ve-hero__timeline .ve-hero__track--broll i { background: rgba(70, 119, 255, 0.45); }
/* Audio: thin bars spread across the lane, so the tracks read as a waveform. */
.ve-hero__timeline .sc-track--music > span { justify-content: space-between; gap: 1px; padding-inline: 2px; }
.ve-hero__timeline .sc-track--music i { flex: 0 1 3px; }
/* Phones: 14px tracks (the kit's --compact size) and no second audio track keep the editor short. */
.ve-hero__timeline .sc-track > span { height: 14px; }
@media (min-width: 560px) { .ve-hero__timeline .sc-track > span { height: 22px; } }

/* ---------- B: the objective note ---------- */
.ve-hero__objective { padding: 12px 16px 12px 12px; }
.ve-hero__objective .sc-note__text > span { font-size: 10px; font-weight: var(--sf-fw-semibold); letter-spacing: 0.1em; text-transform: uppercase; color: rgba(255, 255, 255, 0.66); }
.ve-hero__objective .sc-note__text strong { font-weight: var(--sf-fw-semibold); line-height: 1.25; }

/* ---------- C: the export queue ----------
   Rows: an outlined ratio glyph, the name, the ratio and the state. Done is the lavender tick (part 00);
   rendering is a short bar with a lavender fill. */
.ve-hero__export { padding: 14px 16px 16px; }
.ve-hero__export .sc-head { margin: 0 0 10px; font-size: 0.75rem; }
.ve-hero__queue { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.ve-hero__queue li { display: grid; grid-template-columns: 14px minmax(0, 1fr) auto auto; align-items: center; gap: 10px; padding: 7px 8px; border-radius: 6px; background: rgba(255, 255, 255, 0.05); font-size: 0.8125rem; color: var(--sf-white); }
.ve-hero__queue em { font-style: normal; font-size: 0.6875rem; font-variant-numeric: tabular-nums; color: rgba(255, 255, 255, 0.62); }
.ve-hero__ratio { justify-self: center; border: 1.5px solid rgba(255, 255, 255, 0.5); border-radius: 2px; }
.ve-hero__ratio--916 { width: 8px; height: 14px; }
.ve-hero__ratio--45 { width: 11px; height: 14px; }
.ve-hero__ratio--169 { width: 14px; height: 8px; }
.ve-hero__queue .sc-note__icon { width: 18px; height: 18px; }
.ve-hero__queue .sc-note__icon .sf-icon { width: 11px; height: 11px; stroke-width: 3; }
.ve-hero__progress { display: block; width: 44px; height: 5px; overflow: hidden; border-radius: 5px; background: rgba(255, 255, 255, 0.12); }
.ve-hero__progress i { display: block; width: 60%; height: 100%; border-radius: inherit; background: var(--sf-soft-lavender); }

/* ---------- The method rail ----------
   A real ordered list. Phones: a 2 (then 3) column grid of nodes with no lines. From 768px, six columns joined by a
   2px track, and a fill in the accent that draws left to right when the rail reveals (1.5s in all). The last step,
   the business result, is the inverted node. No gradient here: the headline word is this screen's moment.
   Margin-top is 48px at every width (the blueprint's fallback): with clamp(48-80px) the nodes fell below a 1440 x 900 fold. */
.ve-hero__flow { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 12px; margin: 48px 0 0; padding: 28px 0 0; border-top: 1px solid var(--sf-border); list-style: none; }
@media (min-width: 360px) { .ve-hero__flow { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.ve-hero__item { position: relative; display: flex; flex-direction: column; align-items: center; min-width: 0; text-align: center; }
.ve-hero__node { position: relative; z-index: 1; display: grid; place-items: center; width: 40px; height: 40px; border: 1px solid var(--sf-border-strong); border-radius: 50%; background: var(--sf-bg-raised); color: var(--sf-fg-muted); }
.ve-hero__node .sf-icon { width: 18px; height: 18px; }
.ve-hero__step { margin-top: 12px; font-size: 0.875rem; font-weight: var(--sf-fw-semibold); line-height: 1.3; color: var(--sf-fg); }
.ve-hero__item--result .ve-hero__node { border-color: var(--sf-fg); background: var(--sf-fg); color: var(--sf-bg); }
.ve-hero__item--result .ve-hero__step { font-weight: var(--sf-fw-bold); }
@media (min-width: 768px) {
  .ve-hero__flow { grid-template-columns: repeat(6, minmax(0, 1fr)); column-gap: 0; }
  .ve-hero__item:not(:last-child)::before,
  .ve-hero__item:not(:last-child)::after { content: ""; position: absolute; top: 19px; left: calc(50% + 28px); right: calc(-50% + 28px); height: 2px; border-radius: 2px; }
  .ve-hero__item:not(:last-child)::before { background: var(--sf-border-strong); }
  .ve-hero__item:not(:last-child)::after { background: var(--sf-fg-accent); transform-origin: left center; transition: transform 600ms var(--sf-ease-out) calc(var(--i, 0) * 220ms); }
  .sf-js .ve-hero__flow:not(.is-revealed) .ve-hero__item::after { transform: scaleX(0); }
}
@media (prefers-reduced-motion: reduce) { .ve-hero__item::after { transition: none; } }
/* Print: the editor mock is decorative (aria-hidden) and split across two pages, so it is left out. */
/* The rail's fill waits for the reveal, which never runs for a block the visitor did not scroll to: print it drawn. */
/* The result node is inverted with a fill, which print drops (backgrounds off): its white icon vanished on white paper.
   It prints as a 2px ring in the ink with the icon in the ink, still set apart from the other nodes' hairline rings. */
@media print {
  .ve-hero__flow { break-inside: avoid; }
  .ve-hero__item--result .ve-hero__node { border-width: 2px; background: none; color: var(--sf-fg); }
  .sf-js .ve-hero__flow:not(.is-revealed) .ve-hero__item::after { transform: none; }
  .ve-hero .split-hero__visual { display: none; }
}

/* ======================================================================
   02 Platforms and proof strip (blueprint §3 02)
   ====================================================================== */
/* Not an .sf-section: the site's trust strip, continuing the hero's surface (Paper in light, Midnight in dark). It reuses
   the shared pieces as they are: the eyebrow (h2.sf-eyebrow.trust__title, with its Electric Blue dash in light, site.css),
   the platform tiles (site.css .platforms / .platform: boxed tiles in dark, an unboxed row between hairlines in light)
   and the home page's sf-stat strip (home.css .stats-row, which this page does not load, so its look is repeated here
   under .ve-proof__stats). Five tiles, not eight: on phones a centred wrap of text-width tiles (3 + 2 at 390, 2 + 3 at
   320), so no tile sits alone at full width; 5 across from 768.
   The stats are placeholders (P4 / D5): plain figures, no gradient, no count-up and no tilt. They are static, so in light
   the sheet is flat on a hairline ring (the page's shadow rule: a shadow means actionable). Phones: the three in one row
   (the strip is about 405px at 390, budget 380 + 10%). Mobile-first: base, 480 (the stats), 768. */

/* ---------- Band ---------- */
.ve-proof { padding-block: 28px; }
@media (min-width: 768px) { .ve-proof { padding-block: clamp(40px, 5vw, 64px); } }

/* ---------- Head: the eyebrow, and the captions tag on the right from 560 ---------- */
.ve-proof__head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 24px; }
.ve-proof__lang { margin: 0; }
/* A static tag is filled, never outlined (an outline means "press me"). sarafi.css fills it in light; this is the dark
   theme and the default mix. */
.ve-proof span.sf-chip { border-color: transparent; background-color: var(--sf-hover); }

/* ---------- Platform tiles (site.css) ----------
   Phones: a centred wrap of 44px tiles as wide as their names. Dark: the site's boxed tiles. Light: unboxed names between
   the two hairlines of the 768 row (site.css rules each phone row instead, which suits a column, not a wrap). The tiles
   flow in at most 360px (side padding; the hairlines keep the full width), so at 420-559 they wrap 3 + 2, not 4 + 1.
   560: all five fit on one line. */
.ve-proof .ve-proof__platforms { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin-top: 12px;
  padding-inline: max(0px, calc((100% - 360px) / 2)); }
@media (min-width: 560px) { .ve-proof .ve-proof__platforms { padding-inline: 0; } }
.ve-proof .ve-proof__platforms > .platform { height: 44px; padding-inline: 10px; gap: 8px; font-size: 0.875rem; }
.ve-proof .ve-proof__platforms .platform__icon { width: 20px; height: 20px; }
:root[data-theme="light"] .ve-proof .ve-proof__platforms { gap: 0 4px; padding-block: 2px; box-shadow: inset 0 1px 0 var(--sf-hairline), inset 0 -1px 0 var(--sf-hairline); }
:root[data-theme="light"] .ve-proof .ve-proof__platforms > .platform { box-shadow: none; }
@media (min-width: 768px) {
  .ve-proof .ve-proof__platforms { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; margin-top: 16px; }
  .ve-proof .ve-proof__platforms > .platform { height: 72px; padding-inline: 12px; gap: 10px; font-size: 0.9375rem; }
  .ve-proof .ve-proof__platforms .platform__icon { width: 22px; height: 22px; }
  :root[data-theme="light"] .ve-proof .ve-proof__platforms { gap: 12px; padding-block: 0; }
}

/* ---------- Stats (placeholders): the home page's sf-stat strip ----------
   A definition list. Each cell shows its value first (column-reverse keeps dt before dd in the source). Three across at
   every width; phones get compact cells (24-32px figures, 11px labels). Labels never hyphenate, as on the home page.
   Below 480 the third cell, which holds the longest label, is 1.3 times as wide (1.4 below 360, with 8px side padding
   and 0.03em tracking) and never narrower than its longest word, and the tracking is 0.04em: so "[engagement" never
   breaks, and the label takes 3 lines from 320 instead of 4-5 hyphenated ones. Dark: separate raised tiles (sarafi.css .sf-stat). Light: one sheet with 1px
   dividers drawn by each cell and a hairline ring, as on the home page, without its shadow. */
.ve-proof__proof { margin-top: 20px; }
.ve-proof__stats { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(min-content, 1.4fr); gap: 8px; margin: 0; }
.ve-proof__stat { display: flex; flex-direction: column-reverse; justify-content: flex-end; min-width: 0; }
.ve-proof__stats .ve-proof__stat { padding: 12px 8px; }
.ve-proof__stat dd { margin: 0; font-size: clamp(1.5rem, 0.9rem + 3vw, 2rem); font-variant-numeric: tabular-nums; color: var(--sf-fg); }
.ve-proof__stat dt { margin-top: 8px; font-size: 0.6875rem; letter-spacing: 0.03em; overflow-wrap: break-word; hyphens: manual; text-wrap: balance; }
@media (min-width: 360px) {
  .ve-proof__stats { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(min-content, 1.3fr); }
  .ve-proof__stats .ve-proof__stat { padding-inline: 10px; }
  .ve-proof__stat dt { letter-spacing: 0.04em; }
}
@media (min-width: 480px) {
  .ve-proof__stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ve-proof__stat dt { letter-spacing: 0.06em; }
}
@media (min-width: 768px) {
  .ve-proof__proof { margin-top: clamp(28px, 4vw, 40px); }
  .ve-proof__stats { gap: 12px; }
  .ve-proof__stats .ve-proof__stat { padding: 18px 20px; }
  .ve-proof__stat dd { font-size: clamp(2rem, 1.7rem + 1.2vw, 3rem); }
  .ve-proof__stat dt { margin-top: 10px; font-size: 0.75rem; letter-spacing: 0.08em; }
}
:root[data-theme="light"] .ve-proof__stats { gap: 1px; overflow: hidden; border-radius: var(--sf-radius-md); background: var(--sf-white); box-shadow: 0 0 0 1px var(--sf-hairline); }
/* 0,4,0 and later than sarafi.css, so it also takes the place of the light .sf-stat shadow-1. */
:root[data-theme="light"] .ve-proof__stats .ve-proof__stat { border-color: transparent; border-radius: 0;
  box-shadow: 1px 0 0 var(--sf-hairline), 0 1px 0 var(--sf-hairline), 1px 1px 0 var(--sf-hairline); }
/* The source line: meta, under the strip. It is part of the placeholder block, so it is filled or removed with it. */
.ve-proof__source { margin: 12px 0 0; font-size: var(--sf-fs-small); line-height: var(--sf-lh-small); color: var(--sf-fg-muted); text-wrap: balance; }

@media print {
  .ve-proof__stats, .ve-proof__platforms { break-inside: avoid; }
  :root[data-theme="light"] .ve-proof__stats { box-shadow: none; border: 1px solid var(--sf-hairline); }
}

/* ======================================================================
   03 What we do: the bento (blueprint §3 03)
   ====================================================================== */
/* Five capability cards on Cloud / Night Soft. Each card is a picture on top (a tinted well, or a dark screen for the
   core card) and its copy below. The pictures are aria-hidden illustrations and use tokens, so they follow the theme;
   the only hard-coded colours are inside the .ve-screen device. No card numbers (N6); the core card is a plain sf-card
   with an accent label (R7). Mobile-first: base (one column), 560, 768 (two columns), 1280 (the bento). */

/* ---------- Grid ---------- */
/* Before they reveal, the cards hold the site's depth pose (pushed back and tilted in the grid's perspective). With
   WCAG 1.4.12 text spacing the cards are taller and Chrome counts the posed boxes 5-8px past the viewport at 1280-1439,
   a sideways scroll until the bento reveals. The section is full width, so clipping it on x only drops that off-screen
   overflow; clip (not hidden) makes no scroll container, and the cards, rings and shadows sit inside its padding. */
.ve-what { overflow-x: clip; }
.ve-what__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; margin: 0; padding: 0; list-style: none; }
@media (min-width: 768px) {
  .ve-what__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ve-what__card--core { grid-column: 1 / -1; }
}
/* 1280: the reference bento. The core card takes the wide middle column over both rows; DOM order stays
   Brief, Script, Core, Formats, Revisions. It starts at 1280, not 1024: at 1024-1279 the side columns were 222px wide,
   so the mock rows wrapped to three and four lines and the core monitor stretched into a 290 x 470 portrait frame. Until
   1280 the 768 layout holds: two small cards per row, the core card full width between them. */
@media (min-width: 1280px) {
  .ve-what__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr) minmax(0, 1fr); }
  .ve-what__card--brief { grid-column: 1; grid-row: 1; }
  .ve-what__card--script { grid-column: 1; grid-row: 2; }
  .ve-what__card--core { grid-column: 2; grid-row: 1 / span 2; }
  .ve-what__card--formats { grid-column: 3; grid-row: 1; }
  .ve-what__card--revisions { grid-column: 3; grid-row: 2; }
}
/* 768: the small cards' pictures and headings line up across a row. Each card spans two rows of the grid and shares
   them (subgrid): the picture well takes the taller of the two (its content centred), so both headings start on one
   line (they were 29-61px apart at 768-1024, and 22-58px in the bento). The core card spans the same two rows. From
   1280 each small card spans two of the bento's four rows. Without subgrid: the placements above. */
@media (min-width: 768px) {
  @supports (grid-template-rows: subgrid) {
    .ve-what__card { grid-row: span 2; }
    .ve-what__card:not(.ve-what__card--core) { display: grid; grid-template-rows: subgrid; }
  }
}
@media (min-width: 1280px) {
  @supports (grid-template-rows: subgrid) {
    .ve-what__card--brief, .ve-what__card--formats { grid-row: 1 / span 2; }
    .ve-what__card--script, .ve-what__card--revisions { grid-row: 3 / span 2; }
    .ve-what__card--core { grid-row: 1 / span 4; }
  }
}

/* ---------- Card anatomy ---------- */
.ve-what__card { display: flex; flex-direction: column; gap: 14px; padding: 12px 12px 20px; }
.ve-what__visual { position: relative; display: grid; place-items: center; min-height: 120px; padding: 14px; border-radius: var(--sf-radius-sm); }
@media (min-width: 560px) {
  .ve-what__card { gap: 18px; padding-bottom: 24px; }
  .ve-what__visual { padding: 18px; }
}
/* Phones (R15, height budget): the wells keep their main piece and drop the extras (.ve-hide-sm in the markup: the
   brief's Offer row, the script's skeleton lines, the formats legend and one done comment); the monitor crops to 2:1;
   the craft chips are 28px. */
.ve-what__card--core .ve-viewer { aspect-ratio: 2 / 1; }
.ve-what__chips .sf-chip { min-height: 28px; }
@media (min-width: 560px) {
  .ve-what__card--core .ve-viewer { aspect-ratio: 16 / 9; }
  .ve-what__chips .sf-chip { min-height: 32px; }
}
@media (min-width: 768px) { .ve-what__card:not(.ve-what__card--core) .ve-what__visual { min-height: 184px; } }
.ve-what__body { display: flex; flex: 1; flex-direction: column; gap: 8px; padding: 0 10px; }
.ve-what__title { font-size: 1.25rem; font-weight: var(--sf-fw-bold); line-height: 1.25; letter-spacing: -0.01em; }
.ve-what__text { margin: 0; font-size: 0.9375rem; line-height: 1.6; color: var(--sf-fg-body); }
.ve-what__tag { margin-bottom: 2px; }
/* Static tags are filled, never outlined (an outline means "press me"): sarafi.css fills them in light; this is the dark
   theme and the default mix. */
.ve-what span.sf-chip { border-color: transparent; background-color: var(--sf-hover); }

/* ---------- The core card ----------
   Light theme: the core card leads the bento on a pale Growth Purple sheet (the purple wash token, 8% on white) with a
   purple-tinted hairline, while its four neighbours stay Paper. A flat tint, not a gradient: this section has no
   gradient moment to spend (R8), and it is not a featured card, so no lavender badge either.
   768-1279: full width, so the screen and the copy sit side by side instead of a 600px-tall screen over the copy.
   1280: one column again; the screen grows to fill the two rows it spans. */
:root[data-theme="light"] .ve-what__card--core { border-color: color-mix(in srgb, var(--sf-growth-purple) 20%, var(--sf-hairline)); background: var(--sf-purple-wash); }
.ve-what__card--core .ve-what__title { font-size: 1.5rem; }
.ve-what__chips { --sf-cluster-gap: 8px; margin: 10px 0 0; padding: 0; list-style: none; }
.ve-what__card--core .ve-what__visual { place-items: stretch; align-content: center; gap: 10px; padding: 14px; }
@media (min-width: 768px) {
  .ve-what__card--core { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); align-items: center; column-gap: 24px; padding: 12px 20px 12px 12px; }
  .ve-what__card--core .ve-what__body { padding: 12px 0; }
}
@media (min-width: 1280px) {
  .ve-what__card--core { display: flex; align-items: stretch; padding: 12px 12px 24px; }
  /* The screen spans both bento rows, so it is taller than its content. The monitor stays 16:9 (it is labelled 4K and
     carries a 16:9 safe area; stretched, it was 1.13:1 at 1280) and the timeline takes the spare height: its tracks
     share it equally (20px at the least, about 40px at 1280 and 31px at 1440), as an editor's taller tracks. */
  .ve-what__card--core .ve-what__visual { flex: 1 0 auto; display: flex; flex-direction: column; }
  .ve-what__card--core .ve-viewer { flex: none; aspect-ratio: 16 / 9; }
  .ve-what__card--core .ve-subject { width: auto; height: 50%; max-width: 72%; }
  .ve-what__card--core .ve-what__timeline { flex: 1 0 auto; grid-template-rows: auto minmax(0, 1fr); }
  .ve-what__card--core .ve-timeline__tracks { grid-auto-rows: minmax(20px, 1fr); }
  .ve-what__card--core .ve-what__timeline .sc-track { align-items: stretch; }
  .ve-what__card--core .ve-what__timeline .sc-track em { align-self: center; }
  .ve-what__card--core .ve-what__timeline .sc-track > span { height: auto; }
  .ve-what__card--core .ve-what__timeline .sc-track--text i { top: 50%; height: 12px; translate: 0 -50%; }
  .ve-what__card--core .ve-what__body { flex: none; padding: 0 10px; }
}

/* ---------- Visual: the creative brief (a sheet in a well) ----------
   On reveal the four rows slide in, 80ms apart, after the card has risen. Hidden only under .sf-js, so without script
   and with reduced motion the rows simply show. */
.ve-what__sheet { width: 100%; max-width: 420px; padding: 14px; border: 1px solid var(--sf-border); border-radius: var(--sf-radius-sm); background: var(--sf-bg-raised); }
.ve-what__sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 0; font-size: 0.8125rem; font-weight: var(--sf-fw-bold); color: var(--sf-fg); }
.ve-what__card--brief .ve-what__sheet-head > span:first-child::before { content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 8px; border-radius: 50%; background: var(--sf-fg-accent); vertical-align: 0.15em; }
.ve-what__rows { margin-top: 10px; }
/* The sheet is a size container: in a narrow well (a small phone) each label sits over its value; from 250px the
   reference's two columns (84px labels). */
.ve-what__card--brief .ve-what__sheet { container-type: inline-size; }
.ve-what__row { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px; padding: 8px 0; border-top: 1px solid var(--sf-border); }
@container (min-width: 250px) { .ve-what__row { grid-template-columns: 84px minmax(0, 1fr); align-items: center; gap: 10px; padding: 9px 0; } }
.ve-what__row:last-child { padding-bottom: 0; }
.ve-what__value { font-size: 0.8125rem; font-weight: var(--sf-fw-semibold); line-height: 1.35; color: var(--sf-fg); }
.ve-what__nowrap { white-space: nowrap; }
.ve-what__value--chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ve-what__value--chips .sf-chip { min-height: 24px; padding: 0 9px; font-size: 0.75rem; }
.ve-what__row { transition: opacity 450ms var(--sf-ease-out), translate 450ms var(--sf-ease-out); }
.ve-what__row:nth-child(1) { transition-delay: calc(var(--sf-reveal-delay, 0ms) + 400ms); }
.ve-what__row:nth-child(2) { transition-delay: calc(var(--sf-reveal-delay, 0ms) + 480ms); }
.ve-what__row:nth-child(3) { transition-delay: calc(var(--sf-reveal-delay, 0ms) + 560ms); }
.ve-what__row:nth-child(4) { transition-delay: calc(var(--sf-reveal-delay, 0ms) + 640ms); }
.sf-js .ve-what__card--brief:not(.is-revealed) .ve-what__row { opacity: 0; translate: -12px 0; }

/* ---------- Visual: the script (hook options) ---------- */
.ve-what__doc { padding: 12px 12px 14px; }
.ve-what__doc .ve-what__sheet-head { padding: 0 4px 10px; }
.ve-what__file { font-size: 0.6875rem; font-weight: var(--sf-fw-medium); color: var(--sf-fg-muted); }
.ve-what__doc-tag { display: inline-flex; align-items: center; min-height: 20px; padding: 0 8px; border-radius: var(--sf-radius-pill); background: var(--sf-hover); font-size: 0.6875rem; font-weight: var(--sf-fw-semibold); color: var(--sf-fg-body); }
.ve-what__hook { display: grid; grid-template-columns: 54px minmax(0, 1fr); align-items: baseline; gap: 8px; padding: 8px 10px; border-radius: 6px; }
.ve-what__hook + .ve-what__hook { margin-top: 4px; }
.ve-what__hook .ve-label { font-size: 0.625rem; }
.ve-what__hook p { margin: 0; font-size: 0.8125rem; font-weight: var(--sf-fw-semibold); line-height: 1.35; color: var(--sf-fg); }
.ve-what__hook--picked { background: var(--sf-hover); box-shadow: inset 2px 0 0 var(--sf-fg-accent); }
.ve-what__hook--picked .ve-label { color: var(--sf-fg-accent); }
.ve-what__line { display: block; height: 6px; margin: 10px 10px 0; border-radius: 3px; background: var(--sf-border); }
.ve-what__line--short { width: 58%; margin-top: 6px; }

/* ---------- Visual: the programme monitor and timeline (core card, a .ve-screen) ---------- */
.ve-what__monitor { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-width: 0; font-size: 11px; font-weight: var(--sf-fw-semibold); line-height: 1.2; font-variant-numeric: tabular-nums; color: rgba(255, 255, 255, 0.86); }
.ve-what__pgm { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.ve-what__pgm::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--sf-soft-lavender); }
.ve-what__monitor-end { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.ve-what__monitor .art__tag { padding: 3px 7px; font-size: 11px; }
/* 320-359: the bar has room for the timecode and the tag only. */
.ve-what__fps { display: none; }
@media (min-width: 360px) { .ve-what__fps { display: inline; } }
/* The timeline kit (part 00), with sparse graphics and B-roll clips (placed --ve-x after the one before) in single
   brand tints, and the audio as thin waveform bars. Phones: compact tracks, and GFX, B-roll and Voice go (.ve-hide-sm). */
.ve-what__timeline .sc-track > span { border-radius: 4px; background: rgba(255, 255, 255, 0.03); }
.ve-what__timeline .sc-track--video i { margin-left: var(--ve-x, 0px); }
.ve-what__timeline .ve-what__track--gfx i { background: rgba(140, 77, 255, 0.6); }
.ve-what__timeline .ve-what__track--broll i { background: rgba(70, 119, 255, 0.45); }
.ve-what__timeline .sc-track--music > span { justify-content: space-between; gap: 1px; padding-inline: 2px; }
.ve-what__timeline .sc-track--music i { flex: 0 1 3px; }
.ve-what__timeline .sc-track > span { height: 14px; }
.ve-what__timeline .sc-track--text i { top: 2px; height: 10px; }
@media (min-width: 560px) {
  .ve-what__timeline .sc-track > span { height: 20px; }
  .ve-what__timeline .sc-track--text i { top: 4px; height: 12px; }
}

/* ---------- Visual: one edit, four frames ----------
   Nested outline frames on one baseline. The resting state is 9:16 lit. On reveal, one pass lights 9:16, 4:5, 1:1 and
   16:9 in turn (900ms each) and settles back on 9:16: 400ms + 4.5s, once (.ve-anim, part 00). The legend sits
   beside the frames when the well is wide enough (a container query), and under them otherwise. */
.ve-what__card--formats .ve-what__visual { container-type: inline-size; }
.ve-what__ratios { display: grid; grid-template-columns: minmax(0, 1fr); justify-items: center; gap: 16px; width: 100%; }
/* Frame sizes follow --ve-fh, the tallest (9:16) frame: 104px on phones (the legend is hidden there), 120px stacked
   over the legend from 560, 104px beside it. */
.ve-what__frames { --ve-fh: 104px; position: relative; width: calc(var(--ve-fh) * 1.1); height: calc(var(--ve-fh) + 2px); }
@media (min-width: 560px) { .ve-what__frames { --ve-fh: 120px; } }
@container (min-width: 300px) {
  .ve-what__ratios { grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 16px; }
  .ve-what__frames { --ve-fh: 104px; }
}
.ve-what__frame { position: absolute; left: 50%; bottom: 0; translate: -50% 0; z-index: 1; box-sizing: border-box; border: 1.5px solid var(--sf-border-strong); border-radius: 6px; background: color-mix(in srgb, var(--sf-bg-raised) 45%, transparent); }
.ve-what__frame--916 { width: calc(var(--ve-fh) * 0.5625); height: var(--ve-fh); }
.ve-what__frame--45 { width: calc(var(--ve-fh) * 0.733); height: calc(var(--ve-fh) * 0.917); }
.ve-what__frame--11 { width: calc(var(--ve-fh) * 0.767); height: calc(var(--ve-fh) * 0.767); }
.ve-what__frame--169 { width: calc(var(--ve-fh) * 1.1); height: calc(var(--ve-fh) * 0.619); }
/* The lit frame: a 2px accent edge, a soft accent halo and a faint accent fill, drawn above the others. */
.ve-what__frame--916 { z-index: 2; border: 2px solid var(--sf-fg-accent); background: color-mix(in srgb, var(--sf-fg-accent) 8%, transparent);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--sf-fg-accent) 14%, transparent); }
@keyframes ve-what-f916 { 18% { z-index: 2; border: 2px solid var(--sf-fg-accent); } 22%, 78% { z-index: 1; border: 1.5px solid var(--sf-border-strong); background: color-mix(in srgb, var(--sf-bg-raised) 45%, transparent); box-shadow: none; } 82% { z-index: 2; border: 2px solid var(--sf-fg-accent); } }
@keyframes ve-what-f45 { 18%, 42% { z-index: 1; } 22%, 38% { z-index: 2; border: 2px solid var(--sf-fg-accent); background: color-mix(in srgb, var(--sf-fg-accent) 8%, transparent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--sf-fg-accent) 14%, transparent); } }
@keyframes ve-what-f11 { 38%, 62% { z-index: 1; } 42%, 58% { z-index: 2; border: 2px solid var(--sf-fg-accent); background: color-mix(in srgb, var(--sf-fg-accent) 8%, transparent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--sf-fg-accent) 14%, transparent); } }
@keyframes ve-what-f169 { 58%, 82% { z-index: 1; } 62%, 78% { z-index: 2; border: 2px solid var(--sf-fg-accent); background: color-mix(in srgb, var(--sf-fg-accent) 8%, transparent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--sf-fg-accent) 14%, transparent); } }
.sf-js .is-revealed .ve-what__frame.ve-anim { animation: 4500ms linear 400ms both; }
.sf-js .is-revealed .ve-what__frame--916.ve-anim { animation-name: ve-what-f916; }
.sf-js .is-revealed .ve-what__frame--45.ve-anim { animation-name: ve-what-f45; }
.sf-js .is-revealed .ve-what__frame--11.ve-anim { animation-name: ve-what-f11; }
.sf-js .is-revealed .ve-what__frame--169.ve-anim { animation-name: ve-what-f169; }
.ve-what__legend { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.ve-what__legend li { display: flex; align-items: center; gap: 8px; font-size: 0.75rem; line-height: 1.3; color: var(--sf-fg-body); }
.ve-what__legend .sf-chip { flex: none; justify-content: center; min-width: 42px; min-height: 22px; padding: 0 6px; font-size: 0.6875rem; font-weight: var(--sf-fw-semibold); font-variant-numeric: tabular-nums; }

/* ---------- Visual: the revision thread ---------- */
.ve-what__thread { display: grid; gap: 8px; width: 100%; max-width: 420px; margin: 0; padding: 0; list-style: none; }
.ve-what__comment { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 10px; padding: 9px 10px; border: 1px solid var(--sf-border); border-radius: var(--sf-radius-sm); background: var(--sf-bg-raised); }
.ve-what__comment p { margin: 0; font-size: 0.8125rem; font-weight: var(--sf-fw-medium); line-height: 1.3; color: var(--sf-fg); }
.ve-what__time { padding: 3px 6px; border-radius: var(--sf-radius-xs); background: var(--sf-fg); color: var(--sf-bg); font-size: 11px; font-weight: var(--sf-fw-bold); line-height: 1.2; font-variant-numeric: tabular-nums; }
.ve-what__comment--done p { font-weight: var(--sf-fw-regular); color: var(--sf-fg-muted); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--sf-fg-muted) 60%, transparent); }
.ve-what__comment .sf-icon { width: 18px; height: 18px; color: var(--sf-fg-accent); }
.ve-what__comment .sf-badge { white-space: nowrap; }

/* ---------- The fit pair (site.css .fit-cards) ---------- */
.ve-what__fit { margin-top: 16px; }
.ve-what__fit .fit-card__text { font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem); }
.ve-what__fit-link { margin: 20px 0 0; }

/* Print: the brief's rows wait for the reveal, which never runs for a card the visitor did not scroll to, so they print
   shown (the "Creative brief" sheet printed with only its header). */
@media print {
  .sf-js .ve-what__card--brief:not(.is-revealed) .ve-what__row { opacity: 1; translate: none; }
  .ve-what__grid { display: flex; flex-direction: column; }
  .ve-what__card { break-inside: avoid; }
}

/* ======================================================================
   04 The problem (blueprint §3 04)
   ====================================================================== */
/* Six static cards, each a symptom (the H3) over its usual cause, on Paper / Night, then the fix strip. No red and no
   numbers: the cross is a quiet outlined tile. The cards are static, so they rest flat on their hairline in light.
   Mobile-first: base (a swipe row), 768 (two columns), 1024 (three columns). */

/* ---------- The list ----------
   Phones: the home .problem-cards pattern. The row bleeds to the screen edges, snaps card by card, and the next card
   peeks in to show there is more. sarafi.js makes it focusable only while it scrolls, and reveals the whole row at once. */
.ve-problem__grid { display: flex; gap: 12px; margin: 0 calc(-1 * var(--sf-gutter-sm)); padding: 4px var(--sf-gutter-sm) 12px; list-style: none;
  overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; scroll-padding-inline: var(--sf-gutter-sm); scrollbar-width: thin; }
.ve-problem__card { display: flex; flex: 0 0 82%; flex-direction: column; max-width: 340px; padding: 20px; scroll-snap-align: start; }
/* The row shares its lines too: a grid of three rows flowing in columns (one card per column, the same 82% / 340px
   width), each card spanning the three rows as a subgrid. So the dashed rule and its label sit on one line in every
   card, however many lines the symptom takes; the spare height falls under the cause. Without subgrid: the flex row. */
@supports (grid-template-rows: subgrid) {
  .ve-problem__grid { display: grid; grid-auto-flow: column; grid-template-rows: auto auto 1fr; grid-auto-columns: min(82%, 340px); gap: 0 12px; }
  .ve-problem__card { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0; max-width: none; }
}
@media (min-width: 768px) {
  .ve-problem__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: none; grid-auto-flow: row; grid-auto-columns: auto;
    gap: 14px; margin-inline: 0; padding: 0; overflow: visible; }
  .ve-problem__card { max-width: none; padding: 24px; }
}
@media (min-width: 1024px) { .ve-problem__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; } }

/* ---------- Card ---------- */
.ve-problem__mark { display: grid; place-items: center; flex: none; width: 36px; height: 36px; border: 1px solid var(--sf-border-strong); border-radius: var(--sf-radius-sm); color: var(--sf-fg-muted); }
.ve-problem__mark .sf-icon { width: 16px; height: 16px; stroke-width: 2; }
.ve-problem__title { margin: 16px 0; font-size: 1.1875rem; font-weight: var(--sf-fw-bold); line-height: 1.3; letter-spacing: -0.01em; }
/* Without subgrid, the cause sits at the foot of each card of the phone row. With it (the phone row and the 768 grid),
   it starts on the shared third line. */
.ve-problem__cause { margin-top: auto; padding-top: 14px; border-top: 1px dashed var(--sf-border-strong); }
@supports (grid-template-rows: subgrid) { .ve-problem__cause { margin-top: 0; } }
/* 768 (the grid): the dashed rule and its label line up across a row, not the ends of the causes. Each card spans three
   rows of the list and shares them (subgrid), so the mark, the symptom and the cause start on the same lines in every
   card of a row; a one-line symptom next to a two-line one no longer drops its rule 24px. The list has no row gap (it
   would open inside the cards); the cards' bottom margin spaces the rows instead, and the list's negative bottom margin
   takes the last row's back. */
@media (min-width: 768px) {
  @supports (grid-template-rows: subgrid) {
    .ve-problem__grid { --ve-row-gap: 14px; row-gap: 0; margin-bottom: calc(-1 * var(--ve-row-gap)); }
    .ve-problem__card { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0; margin-bottom: var(--ve-row-gap); }
    .ve-problem__cause { margin-top: 0; }
  }
}
@media (min-width: 1024px) { .ve-problem__grid { --ve-row-gap: 16px; } }
.ve-problem__text { margin: 8px 0 0; font-size: 0.9375rem; line-height: 1.55; color: var(--sf-fg-body); text-wrap: balance; }

/* ---------- The fix strip (an sf-callout: its 3px gradient bar is this screen's moment) ---------- */
.ve-problem__fix { display: flex; align-items: flex-start; gap: 16px; margin-top: 16px; padding: 20px; }
.ve-problem__fix-icon { flex: none; display: grid; place-items: center; width: 32px; height: 32px; color: var(--sf-fg-accent); }
.ve-problem__fix-icon .sf-icon { width: 32px; height: 32px; }
.ve-problem__fix p { margin: 0; font-size: var(--sf-fs-body-lg); line-height: var(--sf-lh-body-lg); color: var(--sf-fg-body); text-wrap: pretty; }
.ve-problem__fix strong { font-weight: var(--sf-fw-bold); color: var(--sf-fg); }
@media (min-width: 768px) { .ve-problem__fix { align-items: center; padding: 22px 26px; } }
/* The strip is static, so in light it rests flat on its hairline like the cards above it (the page's rule: a shadow
   means actionable). sarafi.css gives every light .sf-callout shadow-1 at 0,4,0; this is 0,5,0. */
:root[data-theme="light"] .ve-problem .ve-problem__fix.sf-callout { box-shadow: none; }

/* Print: the row prints as a two-column grid, as on the homepage, with plain cards (no shared rows, which a page break
   could split). */
@media print {
  .ve-problem__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: none; grid-auto-flow: row; grid-auto-columns: auto;
    gap: 12px; margin: 0; padding: 0; overflow: visible; }
  .ve-problem__card { display: flex; grid-row: auto; max-width: none; margin-bottom: 0; break-inside: avoid; }
  .ve-problem__cause { margin-top: auto; }
}

/* ======================================================================
   05 How it works: the Midnight chapter band (blueprint §3 05)
   ====================================================================== */
/* .sf-band makes this the page's one Midnight chapter in the light theme (tokens.css + site.css): white headings,
   #D9DBE1 running text, #B9BDC8 meta, lavender accent, and every sf-card on it turns into a paper sheet. In the dark
   theme it is the Midnight feature band. The band's one gradient is the timeline: the line fill and the final node.
   Mobile-first (R25): a vertical timeline at the base, a two-column card inside from 768, the horizontal track from 1280.
   The lighting (video-editing.js) only ever runs under .ve-process__track--armed: without it (no script, reduced motion)
   every step shows lit. */

/* ---------- The board: a glass stage on the band ----------
   Slate on it measures 5.18:1 in the dark theme, so the meta needs no .ve-tint. */
.ve-process__board { padding: clamp(18px, 3vw, 36px); border: 1px solid var(--sf-border); border-radius: var(--sf-radius-md); background: color-mix(in srgb, var(--sf-fg) 3%, transparent); }

/* ---------- Phase row (Plan / Produce / Deliver): only over the horizontal track ---------- */
.ve-process__phases { display: none; }

/* ---------- The track: a vertical timeline ----------
   Each step is a node column and its card. A 2px line runs from under each node to the next one; its fill (the brand
   gradient) is the same box, scaled from the top. */
.ve-process__track { display: grid; gap: 14px; margin: 0; padding: 0; list-style: none; }
.ve-process__step { --ve-node: 36px; position: relative; display: grid; grid-template-columns: var(--ve-node) minmax(0, 1fr); align-items: start; column-gap: 14px; }
.ve-process__step:not(:last-child)::before,
.ve-process__step:not(:last-child)::after { content: ""; position: absolute; left: calc(var(--ve-node) / 2 - 1px); top: calc(var(--ve-node) + 4px); bottom: -10px; width: 2px; border-radius: 2px; }
.ve-process__step:not(:last-child)::before { background: var(--sf-border-strong); }
.ve-process__step:not(:last-child)::after { background: var(--sf-gradient-brand); transform-origin: 50% 0; transition: transform 500ms var(--sf-ease-out); }
@media (min-width: 360px) { .ve-process__step { --ve-node: 44px; } }

/* ---------- Nodes ----------
   Lit (the default): a 2px accent ring and a white numeral; the final step is the gradient disc with a white check.
   At rest (armed and not yet lit): Deep Blue with a hairline ring and a muted numeral. */
.ve-process__node { position: relative; z-index: 1; display: grid; place-items: center; box-sizing: border-box; width: var(--ve-node); height: var(--ve-node); border: 2px solid var(--sf-fg-accent); border-radius: 50%;
  background: var(--sf-bg-raised); color: var(--sf-fg); font-size: 0.8125rem; font-weight: var(--sf-fw-bold); line-height: 1; letter-spacing: 0.04em; font-variant-numeric: tabular-nums;
  transition: border-color 400ms var(--sf-ease-out), background-color 400ms var(--sf-ease-out), color 400ms var(--sf-ease-out); }
.ve-process__node .sf-icon { width: 18px; height: 18px; stroke-width: 2.25; }
.ve-process__step--final .ve-process__node { border-color: transparent; background: var(--sf-gradient-brand) border-box; color: var(--sf-white); }
.ve-process__track--armed .ve-process__step:not(.is-lit) .ve-process__node { border: 1px solid var(--sf-border-strong); background: var(--sf-bg-raised); color: var(--sf-fg-muted); }
.ve-process__track--armed .ve-process__step:not(.is-lit)::after { transform: scaleY(0); }

/* ---------- Cards (paper sheets on the band in light) ---------- */
.ve-process__card { padding: 20px; }
/* The step label never wraps ("STEP 02 · / PLAN" at 320). Below 360 the card is too narrow for the icon and the longest
   label ("Step 04 · Produce", 128px) side by side, so every label sits under its icon; from 360 they share a line. */
.ve-process__card-top { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
@media (min-width: 360px) { .ve-process__card-top { flex-direction: row; align-items: center; justify-content: space-between; gap: 12px; } }
.ve-process__card-top .sf-icon-tile { width: 40px; height: 40px; }
.ve-process__card-top .sf-icon-tile .sf-icon { width: 20px; height: 20px; }
.ve-process__meta { margin: 0; white-space: nowrap; font-size: var(--sf-fs-label); line-height: var(--sf-lh-label); font-weight: var(--sf-fw-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--sf-fg-muted); }
.ve-process__title { margin-top: 16px; font-size: 1.125rem; font-weight: var(--sf-fw-bold); line-height: 1.3; letter-spacing: -0.01em; }
.ve-process__text { margin: 6px 0 0; font-size: 0.9375rem; line-height: 1.55; color: var(--sf-fg-body); text-wrap: balance; }
.ve-process__output { display: grid; gap: 4px; margin: 14px 0 0; padding-top: 12px; border-top: 1px dashed var(--sf-border-strong); }
.ve-process__output strong { font-size: 0.9375rem; font-weight: var(--sf-fw-bold); line-height: 1.3; color: var(--sf-fg); }

/* The last step is the finish line (the reference's featured final card, in Sarafi terms): a 3px rule along its top in
   Soft Lavender (Growth Purple on the paper sheets of the light band), echoing the check node. A solid colour, so the
   band's one gradient stays the timeline. ::after, because the tilt light uses ::before. */
.ve-process__step--final .ve-process__card { position: relative; overflow: hidden; }
.ve-process__step--final .ve-process__card::after { content: ""; position: absolute; inset: 0 0 auto; height: 3px; background: var(--sf-soft-lavender); pointer-events: none; }
:root[data-theme="light"] .ve-process__step--final .ve-process__card::after { background: var(--sf-growth-purple); }

/* 768: the card uses its width: the step on the left, its output on the right behind a dashed rule. */
@media (min-width: 768px) {
  .ve-process__card { display: grid; grid-template-columns: minmax(0, 1fr) 200px; grid-template-rows: auto auto 1fr; column-gap: 24px; }
  .ve-process__card > :not(.ve-process__output) { grid-column: 1; }
  .ve-process__output { grid-column: 2; grid-row: 1 / span 3; align-self: center; margin: 0; padding: 4px 0 4px 20px; border-top: 0; border-left: 1px dashed var(--sf-border-strong); }
}

/* ---------- 1280: the horizontal track ----------
   Five equal columns under the phase brackets. The line runs from each node's right edge to the next node and draws
   left to right in one pass (220ms apart, 1.4s in all). The card's meta line is hidden visually (the phase row says it)
   but still read. */
@media (min-width: 1280px) {
  .ve-process__phases { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 14px; margin-bottom: 20px; }
  .ve-process__phase { display: flex; align-items: center; gap: 10px; min-width: 0; }
  .ve-process__phase::after { content: ""; flex: 1; height: 7px; margin-top: 7px; border-top: 1px solid var(--sf-border-strong); border-right: 1px solid var(--sf-border-strong); }
  .ve-process__phase--plan { grid-column: 1 / span 3; }
  .ve-process__phase--produce { grid-column: 4; }
  .ve-process__phase--deliver { grid-column: 5; }

  .ve-process__track { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 14px; }
  .ve-process__step { grid-template-columns: minmax(0, 1fr); grid-template-rows: var(--ve-node) minmax(0, 1fr); row-gap: 18px; }
  .ve-process__step:not(:last-child)::before,
  .ve-process__step:not(:last-child)::after { left: calc(var(--ve-node) + 8px); right: -6px; top: calc(var(--ve-node) / 2 - 1px); bottom: auto; width: auto; height: 2px; }
  .ve-process__step:not(:last-child)::after { transform-origin: 0 50%; transition-delay: calc(var(--i, 0) * 220ms); }
  .ve-process__node { transition-delay: calc(var(--i, 0) * 220ms); }
  .ve-process__track--armed .ve-process__step:not(.is-lit)::after { transform: scaleX(0); }

  .ve-process__card { display: flex; flex-direction: column; height: 100%; padding: 22px 20px 18px; }
  .ve-process__meta { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  .ve-process__output { align-self: stretch; margin-top: auto; padding: 14px 0 0; border-top: 1px dashed var(--sf-border-strong); border-left: 0; }
  .ve-process__text { margin-bottom: 16px; }
}

/* ---------- What we need from you ---------- */
.ve-process__needs { display: grid; gap: 16px; margin-top: 32px; padding-top: 28px; border-top: 1px solid var(--sf-border); }
.ve-process__needs-list { display: grid; gap: 16px; margin: 0; padding: 0; list-style: none; }
.ve-process__needs-list li { display: flex; align-items: flex-start; gap: 12px; min-width: 0; }
.ve-process__need-icon { display: grid; place-items: center; flex: none; width: 40px; height: 40px; border: 1px solid var(--sf-border-strong); border-radius: 50%; color: var(--sf-fg-accent); }
.ve-process__need-icon .sf-icon { width: 18px; height: 18px; }
.ve-process__needs-list p { display: grid; gap: 2px; margin: 0; padding-top: 1px; text-wrap: balance; }
.ve-process__needs-list strong { font-size: 0.9375rem; font-weight: var(--sf-fw-bold); line-height: 1.35; color: var(--sf-fg); }
.ve-process__needs-list span { font-size: 0.8125rem; line-height: 1.45; color: var(--sf-fg-muted); }
@media (min-width: 560px) { .ve-process__needs-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; } }
@media (min-width: 1024px) {
  .ve-process__needs { grid-template-columns: 150px minmax(0, 1fr); align-items: center; gap: 20px; }
  .ve-process__needs-list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ---------- The quiet next step ----------
   A secondary button, full width on phones. In the light theme the paper-button rule (sarafi.css) would put a white
   sheet on the Midnight band; here it is the band's dark outline instead (as on Growth Review's band: transparent with
   a white 50% edge, 5.12:1). */
.ve-process__cta { margin: 28px 0 0; }
.ve-process__cta .sf-btn { width: 100%; }
@media (min-width: 560px) { .ve-process__cta .sf-btn { width: auto; } }
:root[data-theme="light"] .ve-process__cta .sf-btn--secondary { background-color: transparent; border-color: rgba(255, 255, 255, 0.5); box-shadow: none; }
:root[data-theme="light"] .ve-process__cta .sf-btn--secondary:hover { background-color: var(--sf-hover); border-color: rgba(255, 255, 255, 0.75); }

@media (prefers-reduced-motion: reduce) {
  .ve-process__node, .ve-process__step::after { transition: none; }
}
/* Print: the band is paper; the line prints flat and the steps stay whole. Every step prints lit (the finished state
   no-JS and reduced motion show), including the steps that 05's scroll lighting has not reached. The final node's
   gradient disc is a background, which print drops (backgrounds off), leaving a white check on white paper: in every
   state it prints as the accent ring with an accent check instead. */
@media print {
  .ve-process__track--armed .ve-process__step:not(.is-lit) .ve-process__node { border: 2px solid var(--sf-fg-accent); color: var(--sf-fg); }
  .ve-process__step--final .ve-process__node,
  .ve-process__track--armed .ve-process__step--final:not(.is-lit) .ve-process__node { border: 2px solid var(--sf-fg-accent); background: none; color: var(--sf-fg-accent); }
  .ve-process__track--armed .ve-process__step:not(.is-lit)::after { transform: none; }
  :root[data-theme="light"] .ve-process__cta .sf-btn--secondary { border-color: currentColor; }
  .ve-process__step { break-inside: avoid; }
}

/* ======================================================================
   06 Nine video types (blueprint §3 06)
   ====================================================================== */
/* The depth section: a centred head, a type nav (labelled chips at every width, sticky bar from 768px)
   and nine type cards, each a small sales page (what, included, best for, price, CTA) beside an aria-hidden picture.
   Surface: .sf-section.sf-light (Cloud in light, Night Soft in dark). Cards are sf-card sheets (white with the
   actionable shadow in light, because each holds a button; Night Soft raised in dark). Card 04 is the featured card:
   the brand hairline is this section's one gradient moment, and its lavender badge is the one span.sf-chip.
   Media are .ve-stage (part 00): a light stage carrying dark devices in light, the dark screen picture in dark.
   Mobile-first min-width steps: base (320), 560, 768, 1024 (the no-JS chip fade only), 1280. Container queries only
   inside a card (the lists). */

/* ---------- Type navigation ----------
   Base (<768): a plain "Jump to a type" label over wrapped chips, centred under the centred head. No counter.
   768: the nav sticks under the header as a full-bleed bar (the nav is a direct child of the section, so it sticks
   only while the section is on screen; with JS only, see below); the chips run in one scrolling row whose current chip
   video-editing.js keeps in view (without JS they wrap instead). 1280: the counter shows, JS only (R22). */
.ve-types__now { display: none; margin: 0; }
.ve-types__jump { margin-bottom: 10px; text-align: center; }
.ve-types__links { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin: 0 0 24px; padding: 0; list-style: none; }
.ve-types__links > li { display: flex; }
.ve-types__link { gap: 7px; }
/* The number is meta at rest and takes the chip's own ink when the chip is current (it would fail on the fill). */
.ve-types__n { font-size: 0.75rem; font-weight: var(--sf-fw-bold); letter-spacing: 0.02em; font-variant-numeric: tabular-nums; color: var(--sf-fg-muted); }
.ve-types__link[aria-current="true"] .ve-types__n { color: inherit; }
.ve-types__count { flex: none; font-size: 0.8125rem; font-weight: var(--sf-fw-semibold); font-variant-numeric: tabular-nums; color: var(--sf-fg-muted); }
.ve-types__count b { font-weight: var(--sf-fw-bold); color: var(--sf-fg-accent); }
.ve-types__name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 0.9375rem; font-weight: var(--sf-fw-semibold); color: var(--sf-fg); }

@media (min-width: 768px) {
  .ve-types__nav {
    position: sticky; top: var(--ve-sticky-top); z-index: calc(var(--sf-z-sticky) - 1);
    box-sizing: border-box; height: var(--ve-types-bar); margin-bottom: 16px;
    border-block: 1px solid var(--sf-border);
    background: color-mix(in srgb, var(--sf-bg) 90%, transparent);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  }
  .ve-types__bar { display: flex; align-items: center; gap: 24px; height: 100%; }
  .ve-types__jump { display: none; }
  /* One row that scrolls sideways; 4px of padding keeps the focus ring inside the scroller. */
  /* The end scroll padding is 44px, so a chip that focus scrolls into view from the right lands clear of the fade
     (below); snapping aligns chip starts, so it uses the 4px start padding only. */
  .ve-types__links { flex-wrap: nowrap; justify-content: flex-start; min-width: 0; margin: 0 -4px; padding: 4px;
    overflow-x: auto; scroll-snap-type: x proximity; scroll-padding-inline: 4px 44px; scrollbar-width: none; overscroll-behavior-x: contain; }
  .ve-types__links::-webkit-scrollbar { display: none; }
  .ve-types__links > li { flex: none; scroll-snap-align: start; }
  /* Scroll cue: while chips are cut off at an edge, that edge fades out over 40px (a mask, so it works on every
     surface). video-editing.js sets .ve-fade-start / .ve-fade-end from the row's scroll position. */
  .ve-types__links { --ve-fade-s: 0px; --ve-fade-e: 0px;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--ve-fade-s), #000 calc(100% - var(--ve-fade-e)), transparent);
    mask-image: linear-gradient(90deg, transparent, #000 var(--ve-fade-s), #000 calc(100% - var(--ve-fade-e)), transparent); }
  .ve-types__links.ve-fade-start { --ve-fade-s: 40px; }
  .ve-types__links.ve-fade-end { --ve-fade-e: 40px; }
  /* The mask would fade the row's own focus ring too (it is drawn inside the row, at -2px): while the row itself has
     keyboard focus the fade goes, so the ring shows whole on all four sides. */
  .ve-types__links:focus-visible { -webkit-mask-image: none; mask-image: none; }
}
/* Without JS nothing adds html.ve-types-stuck, so the scroll padding could not clear a stuck bar and a focused element
   could sit under it (WCAG 2.2 2.4.11). The bar stays in flow instead; the chips still jump. Nothing keeps a focused chip
   clear of the row's edge either (scroll snapping pulled '07 Corporate' back under the edge at 768), so the chips wrap
   onto a second line where they do not fit (768-1023): no sideways scroll, no fade, every chip whole. */
/* top: auto drops the sticky offset: a relative box keeps it as a shift, which drew the bar 76px below its slot, over
   the top of card 01. */
@media (min-width: 768px) {
  html:not(.sf-js) .ve-types__nav { position: relative; top: auto; height: auto; }
  html:not(.sf-js) .ve-types__bar { height: auto; padding-block: 6px; }
  html:not(.sf-js) .ve-types__links { flex-wrap: wrap; overflow: visible; scroll-snap-type: none; --ve-fade-e: 0px; }
}
/* While the bar is stuck, the strip above it (the header's band, 0 to --ve-sticky-top) takes the section's surface, so
   the page no longer scrolls through the gaps around the floating capsule only to be cut off by the bar. The capsule
   floats over this band as it floats over content. Opaque: the bar's backdrop blur does not reach a child's backdrop.
   It also covers the bar's top hairline, so the band and the bar read as one surface with one rule under it. */
@media (min-width: 768px) {
  .ve-types__nav::before { content: ""; position: absolute; left: 0; right: 0; top: calc(-1px - var(--ve-sticky-top)); height: calc(var(--ve-sticky-top) + 1px);
    background: var(--sf-bg); opacity: 0; pointer-events: none; }
  html.ve-types-stuck .ve-types__nav::before { opacity: 1; }
}
@media (min-width: 768px) and (prefers-reduced-motion: no-preference) { .ve-types__nav::before { transition: opacity var(--sf-dur-fast) var(--sf-ease-out); } }
@media (min-width: 768px) and (prefers-reduced-motion: no-preference) { .ve-types__links { scroll-behavior: smooth; } }
@media (min-width: 1280px) {
  /* All nine chips fit from 1280 (about 880px of 1200), so the counter takes the free space on the left. */
  .sf-js .ve-types__now { display: flex; align-items: baseline; gap: 12px; flex: 1 1 220px; min-width: 0; }
  .sf-js .ve-types__links { margin-left: auto; }
}

/* ---------- Cards ---------- */
.ve-types__list { display: grid; gap: 16px; }
.ve-types__card { display: flex; flex-direction: column; gap: 16px; padding: 12px; }
.ve-types__media { aspect-ratio: 2 / 1; min-height: 0; container-type: size; }
.ve-types__body { display: flex; flex-direction: column; gap: 16px; min-width: 0; padding: 0 4px 4px; container-type: inline-size; }
/* Source order is the reading order at every width: top, price, the lists, the CTA (WCAG 1.3.2). From 768 the grid
   areas below put the price beside the CTA, under the lists. */
.ve-types__cta { margin: 0; }
.ve-types__cta .sf-btn { width: 100%; }

/* Meta line: the number, the category and (card 04) the badge, which drops under them on phones. */
.ve-types__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0; }
.ve-types__meta .ve-label { display: inline; }
/* The badge may wrap (sarafi.css chips are nowrap): at 320 with WCAG 1.4.12 text spacing its label is wider than the
   card. One line, it is the same 26px chip. */
.ve-types__meta > .sf-chip { max-width: 100%; min-height: 26px; padding: 4px 10px; font-size: 0.75rem; font-weight: var(--sf-fw-semibold); line-height: 1.25; white-space: normal; }
/* Dark theme: the featured card's one badge is filled lavender too (sarafi.css does the light one). Soft Lavender on its
   16% wash over Deep Blue / Night Soft raised: 8.9:1. Not in the default mix (no data-theme, the no-JS view): this
   section is Off-White there, so sarafi.css's own chip stays. */
:root[data-theme="dark"] .ve-types__card--feature .ve-types__meta > .sf-chip { border-color: transparent; background: rgba(200, 183, 255, 0.16); color: var(--sf-soft-lavender); }
.ve-types__title { margin-top: 10px; font-size: var(--sf-fs-h3); line-height: var(--sf-lh-h3); font-weight: var(--sf-fw-bold); letter-spacing: -0.015em; color: var(--sf-fg); text-wrap: balance; }
.ve-types__lead { max-width: 40em; margin-top: 12px; font-size: 0.9375rem; line-height: 1.6; color: var(--sf-fg-body); text-wrap: pretty; }
.ve-types__kpis { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin-top: 14px; font-size: 0.875rem; font-weight: var(--sf-fw-semibold); line-height: 1.45; color: var(--sf-fg); }
.ve-types__kpis .ve-label { display: inline; }

/* Included and best for. The summary is the phone's 44px disclosure row (video-editing.js closes the lists below 768). */
/* Each summary also names its type in a visually hidden span, so the nine disclosures are told apart in a screen
   reader's list of controls (WCAG 2.4.6); "it's for" is joined by a no-break space, so no line ends on one word. */
.ve-types__summary { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 44px;
  border-top: 1px solid var(--sf-border); font-size: 0.9375rem; font-weight: var(--sf-fw-semibold); color: var(--sf-fg); cursor: pointer; list-style: none; text-wrap: balance; }
.ve-types__summary::-webkit-details-marker { display: none; }
.ve-types__summary::marker { content: ""; }
.ve-types__summary:hover { text-decoration: underline; text-underline-offset: 4px; }
.ve-types__summary .sf-icon { flex: none; width: 18px; height: 18px; color: var(--sf-fg-muted); transition: rotate var(--sf-dur-base) var(--sf-ease-out); }
.ve-types__details[open] > .ve-types__summary { margin-bottom: 8px; }
.ve-types__details[open] > .ve-types__summary .sf-icon { rotate: 180deg; }
.ve-types__lists { display: grid; gap: 16px; }
.ve-types__included { gap: 8px; margin: 10px 0 0; font-size: 0.9375rem; line-height: 1.45; }
.ve-types__included li { gap: 10px; }
.ve-types__included .sf-icon { width: 18px; height: 18px; margin-top: 1px; }
.ve-types__best { display: grid; gap: 6px; margin: 10px 0 0; padding: 0; list-style: none; font-size: 0.9375rem; line-height: 1.45; color: var(--sf-fg-body); }
.ve-types__best li { position: relative; padding-left: 18px; }
/* No list item ends on a lone word ("Graphics and animated / explanations"); pretty left some, balance none. */
:is(.ve-types__included, .ve-types__best) li { text-wrap: balance; }
/* A hyphenated compound stays whole: balancing broke "call-to- / action" at its hyphen (types 03 and 04). */
.ve-types__nowrap { white-space: nowrap; }
.ve-types__best li::before { content: ""; position: absolute; left: 5px; top: 0.6em; width: 5px; height: 5px; border-radius: 50%; background: var(--sf-fg-muted); }
/* Two lists side by side once the body is 460px wide (the body is 460-1150px wide from 560 up). */
@container (min-width: 460px) { .ve-types__lists { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); column-gap: 24px; } }
/* The price's [To confirm] marker stays visible in the prototype (C11); it carries data-ve-placeholder, so it goes at launch. */
.ve-types__confirm { color: var(--sf-fg); }

@media (min-width: 560px) {
  .ve-types__card { padding: 16px; }
  .ve-types__media { aspect-ratio: 16 / 10; }
  .ve-types__lead { font-size: 1rem; }
}
@media (min-width: 768px) {
  .ve-types__list { gap: 24px; }
  .ve-types__media { aspect-ratio: 16 / 9; max-height: 420px; }
  /* The reference body grid: top, lists, then price and CTA on one hairline. */
  .ve-types__body { display: grid; grid-template-areas: "top top" "lists lists" "price cta"; grid-template-columns: minmax(0, 1fr) auto;
    row-gap: 22px; column-gap: 26px; align-items: end; padding: 8px 8px 4px; }
  .ve-types__top { grid-area: top; }
  .ve-types__details { grid-area: lists; }
  .ve-types__price { grid-area: price; align-self: stretch; }
  .ve-types__cta { grid-area: cta; align-self: stretch; display: flex; align-items: flex-end; }
  .ve-types__price, .ve-types__cta { padding-top: 18px; border-top: 1px solid var(--sf-border); }
  /* One hairline across the row: the price's rule runs on through the 26px column gap to meet the CTA's (each block
     drew its own, so the rule broke at the gap). The padding keeps the price's content where it was. */
  .ve-types__price { margin-right: -26px; padding-right: 26px; }
  .ve-types__cta .sf-btn { width: auto; }
  .ve-types__lists { gap: 24px; }
  /* The lists always show from 768 (video-editing.js keeps them open), so the disclosure row goes. */
  .ve-types__summary { display: none; }
  /* R20: a jump from outside the section lands clear of the bar that sticks on arrival. While the bar is stuck,
     html.ve-types-stuck already pads the scroll by the bar (part 00). */
  html:not(.ve-types-stuck) .ve-types__card { scroll-margin-top: var(--ve-types-bar); }
}
/* A card that has not been revealed yet still sits 20px low (sarafi.css reveal: translate 0 20px), and a jump aligns
   that shifted box, so after the reveal the card would end up 20px too high, its top edge under the bar. The card that
   is the URL's target (a chip, a link or a deep link) does not rise at all: it only fades in, so every jump aligns its
   real box. A scroll margin could not cover a deep link: Chrome re-anchors the fragment during load, after the reveal
   has dropped the margin but while the card is still rising (it landed 4px under the header, or under the stuck bar).
   Any other scroll to an unrevealed card keeps the 20px of extra margin. Reduced motion has no shift. */
html.sf-js .ve-types__card[data-sf-reveal]:target { translate: none;
  transition: opacity var(--sf-reveal-dur) var(--sf-ease-out) var(--sf-reveal-delay), transform 500ms var(--sf-ease-out),
    border-color var(--sf-dur-fast) var(--sf-ease-out), box-shadow 500ms var(--sf-ease-out); }
@media (prefers-reduced-motion: no-preference) {
  html.sf-js .ve-types__card[data-sf-reveal]:not(.is-revealed, :target) { scroll-margin-top: 20px; }
}
@media (min-width: 768px) and (prefers-reduced-motion: no-preference) {
  html.sf-js:not(.ve-types-stuck) .ve-types__card[data-sf-reveal]:not(.is-revealed, :target) { scroll-margin-top: calc(var(--ve-types-bar) + 20px); }
}
/* 1280: the picture beside the copy. Until then the card keeps the 768 stack (picture over copy), as the reference does
   at 1024: split at 1024-1279, each picture was a 395px-wide, 600-710px-tall box with the device small in its middle
   and the lists squeezed into a narrow column. */
@media (min-width: 1280px) {
  .ve-types__card { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr); gap: 44px; align-items: stretch; padding: 18px; }
  .ve-types__card--flip { grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr); }
  .ve-types__card--flip .ve-types__media { order: 2; }
  .ve-types__media { aspect-ratio: auto; max-height: none; min-height: 480px; height: 100%; }
  .ve-types__body { align-content: center; padding: 18px 18px 14px 8px; }
  .ve-types__card--flip .ve-types__body { padding: 18px 8px 14px 18px; }
}

/* ---------- Stage scenes (the pictures) ----------
   Every mock is drawn in em inside .ve-types__scene, a box of --sw x --sh em that is scaled to fit the stage (a size
   container) and centred in it, like an SVG with "meet". The scene never enters the tag zone: it fits below a 44px
   top band (--zt) or, for the phone mocks on phones, left of a 144px right band (--zr), so the .art__tag keeps the top-
   right 140 x 40px to itself at every width. Three compositions per mock: base (phones: the main device and at most one
   float; the rest is .ve-hide-sm), 560 (the full picture, landscape stage) and 1280 (the full picture, portrait stage).
   Text lives only in devices (.ve-screen, .ve-phone, .ve-viewer) and .ve-floats. Colours inside devices are brand hexes. */
.ve-types__scene {
  --sw: 36; --sh: 20; --zt: 44px; --zr: 0px;
  /* Device shades, mixed from the brand hexes only (no one-off hues). */
  --vt-night: color-mix(in srgb, var(--sf-deep-blue) 70%, var(--sf-midnight));
  --vt-ink: color-mix(in srgb, var(--sf-electric-blue) 6%, var(--sf-midnight));
  --vt-blue: color-mix(in srgb, var(--sf-electric-blue) 28%, var(--sf-deep-blue));
  --vt-blue-soft: color-mix(in srgb, var(--sf-electric-blue) 18%, var(--sf-deep-blue));
  --vt-blue-hi: color-mix(in srgb, var(--sf-electric-blue) 55%, var(--sf-deep-blue));
  --vt-purple: color-mix(in srgb, var(--sf-growth-purple) 20%, var(--sf-midnight));
  --vt-purple-hi: color-mix(in srgb, var(--sf-growth-purple) 30%, var(--sf-midnight));
  position: absolute; top: var(--zt); right: var(--zr); bottom: 0; left: 0; z-index: 1; margin: auto;
  width: calc(var(--sw) * 1em); height: calc(var(--sh) * 1em);
  font-size: min(calc((100cqw - var(--zr)) * 0.92 / var(--sw)), calc((100cqh - var(--zt)) * 0.9 / var(--sh)));
  line-height: 1.2;
}
.ve-types__scene p { margin: 0; }
.ve-types__scene .ve-float { position: absolute; z-index: 4; }
/* A float keeps the shared 11px type, so its own em is not the scene's: floats are placed with percentages of the scene
   box instead, written as calc(100% * <scene em> / var(--sw or --sh)). */
/* Devices scale with the scene. */
.ve-types__scene .ve-phone { position: absolute; padding: 0.45em; border-radius: 1.15em; }
.ve-types__scene .ve-phone .ve-subject { width: 74%; }
.ve-types__scene .ve-caption { font-size: 0.8em; gap: 0.3em; }
.ve-types__scene .ve-caption span { padding: 0.24em 0.5em; border-radius: 0.3em; }
.ve-types__scene .ve-screen { position: absolute; }
.ve-types__scene .sc-pill { height: 2.3em; padding: 0 1em; gap: 0.35em; font-size: 0.62em; }
.ve-types__scene .sc-pill .sf-icon { width: 1.1em; height: 1.1em; }
/* In-mock gaps between clips, and cut marks on an A-roll track. */
.ve-types__scene .sc-track i.ve-types__gap { background: none; }
.ve-types__cuts i { position: relative; }
.ve-types__cuts i + i::before { content: ""; position: absolute; left: -2px; top: -3px; bottom: -3px; width: 1px; background: var(--sf-soft-lavender); }
/* A white lower third with a 3px lavender bar (talking head, corporate). */
.ve-types__lower { position: absolute; left: 5%; bottom: 25%; z-index: 1; display: grid; gap: 0.15em; max-width: 72%; padding: 0.45em 0.8em 0.5em 0.7em;
  border-left: 3px solid var(--sf-soft-lavender); border-radius: 0 0.3em 0.3em 0; background: rgba(255, 255, 255, 0.95); color: var(--sf-midnight); }
.ve-types__lower b { font-size: 0.72em; font-weight: var(--sf-fw-bold); line-height: 1.2; }
.ve-types__lower span { font-size: 0.56em; line-height: 1.25; color: rgba(9, 11, 20, 0.72); }
.ve-types__sub { bottom: 6%; }

/* 01 Reels: the centre phone with a safe zone and a word caption; two fanned phones behind from 560.
   Phones (base): the phone and the hook float are one group, centred in the stage like the other mocks. The scene is
   exactly that group (the 11.25em phone, 8px, then the float pinned right), so centring the scene centres the pair;
   the float sits low, below the tag zone, and the phone stays left of it (6px clear at 320, 32px at 390). */
.ve-types__media--reels .ve-types__scene { --sw: 22; --sh: 20; --zt: 0px; --zr: 0px; width: calc(11.25em + 102px); }
.ve-types__media--reels .ve-types__phone { left: 0; top: 0; z-index: 2; height: 20em; }
.ve-types__media--reels .ve-types__f1 { left: auto; right: 0; top: calc(100% * 12.5 / var(--sh)); }
.ve-types__ghost { opacity: 0.7; }
.ve-types__media--reels .ve-types__ghost { top: 2.4em; height: 16em; }
.ve-types__media--reels .ve-types__ghost--l { left: 4.6em; rotate: -8deg; }
.ve-types__media--reels .ve-types__ghost--r { right: 4.6em; rotate: 8deg; }
.ve-types__media--reels .ve-types__f2 { right: 0; top: calc(100% * 9 / var(--sh)); }
.ve-types__media--reels .ve-types__f3 { left: calc(100% * 0.6 / var(--sw)); top: calc(100% * 16.4 / var(--sh)); }
.ve-types__bars { position: absolute; left: 0.8em; right: 0.8em; top: 0.9em; z-index: 1; display: flex; gap: 0.25em; }
.ve-types__bars i { flex: 1; height: max(2px, 0.16em); border-radius: 1em; background: rgba(255, 255, 255, 0.3); }
.ve-types__bars i:first-child { background: var(--sf-white); transform-origin: 0 50%; }
.ve-types__scene .ve-types__phone .ve-safe { inset: 11% 9% 15%; }
.ve-types__safe-label, .ve-types__scene .ve-safe b { position: absolute; left: 0.5em; top: 0.4em; font-size: clamp(6px, 0.5em, 9px); font-weight: var(--sf-fw-semibold);
  letter-spacing: 0.08em; text-transform: uppercase; color: rgba(255, 255, 255, 0.72); }
.ve-types__rail { position: absolute; right: 0.7em; bottom: 38%; z-index: 1; display: grid; gap: 0.5em; }
.ve-types__rail i { width: 1.2em; height: 1.2em; border: 1px solid rgba(255, 255, 255, 0.28); border-radius: 50%; background: rgba(255, 255, 255, 0.16); }
.ve-types__words { bottom: 24%; flex-direction: column; align-items: center; font-size: 0.86em; }
.ve-types__words b { font-weight: var(--sf-fw-extrabold); color: var(--sf-soft-lavender); }
@media (min-width: 560px) {
  .ve-types__media--reels .ve-types__scene { --sw: 36; --sh: 20; --zt: 44px; --zr: 0px; width: calc(var(--sw) * 1em); }
  .ve-types__media--reels .ve-types__phone { left: 12.4em; }
  .ve-types__media--reels .ve-types__f1 { left: calc(100% * 0.8 / var(--sw)); right: auto; top: calc(100% * 4.2 / var(--sh)); }
}
@media (min-width: 1280px) {
  .ve-types__media--reels .ve-types__scene { --sw: 34; --sh: 34; }
  .ve-types__media--reels .ve-types__phone { left: 9.4em; top: 2em; height: 27em; }
  .ve-types__media--reels .ve-types__ghost { top: 5.5em; height: 22em; }
  .ve-types__media--reels .ve-types__ghost--l { left: 1.6em; }
  .ve-types__media--reels .ve-types__ghost--r { right: 1.6em; }
  .ve-types__media--reels .ve-types__f1 { left: 0; top: calc(100% * 8.4 / var(--sh)); }
  .ve-types__media--reels .ve-types__f2 { right: calc(100% * -0.4 / var(--sw)); top: calc(100% * 17.5 / var(--sh)); }
  .ve-types__media--reels .ve-types__f3 { left: calc(100% * 0.6 / var(--sw)); top: calc(100% * 29.8 / var(--sh)); }
}

/* 02 Talking head: a panel with the programme monitor (lower third, caption), then its compact timeline from 560. */
.ve-types__media--talking-head .ve-types__scene { --sw: 26; --sh: 15.4; }
.ve-types__panel { left: 0; top: 0; right: 0; display: grid; gap: 0.7em; padding: 0.55em; }
.ve-types__viewer { position: relative; }
.ve-types__scene .ve-types__viewer .ve-subject { width: 30%; }
.ve-types__cam { left: 3.5%; top: 6%; }
.ve-types__media--talking-head .ve-types__f1 { right: calc(100% * -0.3 / var(--sw)); top: calc(100% * -0.9 / var(--sh)); }
.ve-types__media--talking-head .ve-types__f2 { left: calc(100% * 1 / var(--sw)); bottom: calc(100% * -1.1 / var(--sh)); }
.ve-types__tl { padding: 0 0.2em 0.2em; }
@media (min-width: 560px) {
  .ve-types__media--talking-head .ve-types__scene { --sw: 30; --sh: 21; }
  .ve-types__media--talking-head .ve-types__panel { right: 4em; }
  .ve-types__media--talking-head .ve-types__f1 { right: calc(100% * 4.9 / var(--sw)); top: calc(100% * 0.9 / var(--sh)); }
  .ve-types__media--talking-head .ve-types__f2 { left: auto; right: 0; bottom: auto; top: calc(100% * 4.2 / var(--sh)); }
}
@media (min-width: 1280px) {
  .ve-types__media--talking-head .ve-types__scene { --sw: 30; --sh: 26; }
  .ve-types__media--talking-head .ve-types__panel { top: 2.2em; right: 0; }
  .ve-types__media--talking-head .ve-types__f1 { right: calc(100% * 1 / var(--sw)); top: 0; }
  .ve-types__media--talking-head .ve-types__f2 { left: calc(100% * 1 / var(--sw)); right: auto; top: auto; bottom: 0; }
}

/* 03 UGC and product: the phone with the hook and a white Shop now pill; the 1:1 end card and beats from 560.
   Phones (base): as in 01 Reels, the phone and one float (the beats row in short) are one group, centred in the stage.
   The scene is exactly that group (the 11.25em phone, 8px, then the float pinned right: 132px wide), so centring the
   scene centres the pair; the float sits low, below the tag zone, and the phone stays left of it. The phone alone,
   pushed left of the tag zone, sat 24-50px off centre. */
.ve-types__media--ugc .ve-types__scene { --sw: 22; --sh: 20; --zt: 0px; --zr: 0px; width: calc(11.25em + 140px); }
.ve-types__media--ugc .ve-types__f1 { right: 0; top: calc(100% * 12.5 / var(--sh)); }
.ve-types__media--ugc .ve-types__phone { left: 0; top: 0; height: 20em; z-index: 2;
  background: radial-gradient(circle at 50% 62%, rgba(200, 183, 255, 0.45), transparent 50%), linear-gradient(170deg, var(--vt-blue) 0%, var(--vt-purple) 70%, var(--vt-night) 100%); }
.ve-types__product { position: absolute; left: 50%; bottom: 20%; width: 26%; aspect-ratio: 1 / 2; translate: -50% 0; rotate: -6deg;
  border-radius: 0.9em 0.9em 0.6em 0.6em; background: linear-gradient(90deg, color-mix(in srgb, var(--sf-soft-lavender) 40%, var(--sf-off-white)), var(--sf-off-white) 40%, color-mix(in srgb, var(--sf-soft-lavender) 55%, var(--sf-off-white))); box-shadow: 0 1em 1.6em -0.8em rgba(0, 0, 0, 0.6); }
.ve-types__product::before { content: ""; position: absolute; left: 50%; top: -14%; width: 62%; height: 16%; translate: -50% 0; border-radius: 0.3em 0.3em 0.15em 0.15em; background: var(--sf-midnight); }
.ve-types__product i { position: absolute; left: 0; right: 0; top: 36%; height: 28%; background: linear-gradient(90deg, color-mix(in srgb, var(--sf-growth-purple) 86%, var(--sf-midnight)), var(--sf-growth-purple) 45%, color-mix(in srgb, var(--sf-growth-purple) 78%, var(--sf-midnight))); }
.ve-types__hook { position: absolute; left: 0.6em; right: 0.6em; top: 12%; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 0.2em;
  font-size: 0.8em; font-weight: var(--sf-fw-bold); line-height: 1.2; text-align: center; color: var(--sf-midnight); }
.ve-types__hook span { padding: 0.2em 0.45em; border-radius: 0.3em; background: var(--sf-white); }
.ve-types__shop { position: absolute; left: 0.7em; right: 0.7em; bottom: 0.8em; z-index: 1; }
.ve-types__end { right: 1em; top: 1.6em; width: 11em; aspect-ratio: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 0.5em;
  padding: 1em; rotate: 3deg; text-align: center; }
.ve-types__end b { font-size: 0.8em; font-weight: var(--sf-fw-bold); }
.ve-types__ratio { position: absolute; left: 0.8em; top: 0.8em; padding: 0.3em 0.5em; border-radius: 0.3em; background: rgba(255, 255, 255, 0.1); font-size: 0.56em; font-weight: var(--sf-fw-semibold); }
.ve-types__product--sm { position: relative; left: auto; bottom: auto; width: 2.4em; margin-bottom: 0.6em; translate: none; }
.ve-types__beats { position: absolute; left: 13.5em; top: 16.6em; z-index: 4; display: flex; gap: 0.35em; margin: 0; padding: 0; list-style: none; }
.ve-types__scene .ve-types__beats .ve-float { position: static; }
.ve-types__beats .ve-types__beat--on { border-color: var(--sf-soft-lavender); background: rgba(91, 43, 196, 0.85); }
@media (min-width: 560px) {
  .ve-types__media--ugc .ve-types__scene { --sw: 34; --sh: 20; --zt: 44px; --zr: 0px; width: calc(var(--sw) * 1em); }
  .ve-types__media--ugc .ve-types__f1 { display: none; }
  .ve-types__media--ugc .ve-types__phone { left: 1em; }
  .ve-types__media--ugc .ve-types__end { right: 1.5em; }
  .ve-types__media--ugc .ve-types__beats { left: auto; right: 0; top: 15.4em; }
}
@media (min-width: 1280px) {
  .ve-types__media--ugc .ve-types__scene { --sw: 30; --sh: 34; }
  .ve-types__media--ugc .ve-types__phone { left: 1em; top: 1em; height: 27em; }
  .ve-types__media--ugc .ve-types__end { right: 0.4em; top: 3.4em; width: 13em; }
  .ve-types__media--ugc .ve-types__beats { left: auto; right: 0; top: 30.4em; }
}

/* 04 Video ads (feature): three variants by hook type, the result hook leading; the creative test plan from 560. */
.ve-types__media--ads .ve-types__scene { --sw: 26; --sh: 17.4; }
.ve-types__ads { position: absolute; left: 0; right: 0; bottom: 0; display: flex; align-items: flex-end; justify-content: center; gap: 1em; }
.ve-types__ad { position: relative; display: flex; flex-direction: column; align-items: center; }
.ve-types__scene .ve-types__ad .ve-phone { position: relative; height: 12.6em; border-radius: 0.9em; }
.ve-types__scene .ve-types__ad--lead .ve-phone { height: 15.6em; box-shadow: 0 0 0 2px var(--sf-soft-lavender), 0 24px 48px -24px rgba(0, 0, 0, 0.7); }
.ve-types__scene .ve-types__ad .ve-subject { width: 80%; }
.ve-types__ad:first-child .ve-phone { background: radial-gradient(circle at 60% 30%, rgba(70, 119, 255, 0.5), transparent 50%), linear-gradient(170deg, var(--vt-blue) 0%, var(--vt-blue-soft) 70%, var(--vt-night) 100%); }
.ve-types__ad:last-child .ve-phone { background: radial-gradient(circle at 40% 30%, rgba(140, 77, 255, 0.45), transparent 50%), linear-gradient(170deg, var(--vt-purple-hi) 0%, var(--vt-purple) 70%, var(--vt-night) 100%); }
.ve-types__scene .ve-types__vtag { left: 50%; top: -11px; translate: -50% 0; padding: 4px 8px; font-size: 10px; }
.ve-types__adhook { position: absolute; left: 0.7em; right: 0.7em; top: 2.2em; z-index: 1; font-size: 0.66em; font-weight: var(--sf-fw-extrabold); line-height: 1.2; text-shadow: 0 0.1em 0.4em rgba(0, 0, 0, 0.7); }
.ve-types__scene .ve-types__adcta { position: absolute; left: 0.5em; right: 0.5em; bottom: 0.6em; z-index: 1; height: 2.1em; font-size: 0.56em; }
.ve-types__plan { right: 0; top: 4em; display: grid; gap: 0.5em; padding: 0.8em 0.9em; }
.ve-types__plan-title { font-size: max(8px, 0.58em); font-weight: var(--sf-fw-bold); letter-spacing: 0.12em; text-transform: uppercase; color: var(--sf-soft-lavender); }
.ve-types__plan-row { display: flex; align-items: center; gap: 0.3em; }
.ve-types__plan-row em { width: 5.4em; font-size: max(8px, 0.58em); font-style: normal; font-weight: var(--sf-fw-semibold); letter-spacing: 0.06em; text-transform: uppercase; color: rgba(255, 255, 255, 0.66); }
.ve-types__scene .ve-types__plan .sc-pill { height: 2em; padding: 0 0.65em; font-size: 0.56em; }
@media (min-width: 560px) {
  .ve-types__media--ads .ve-types__scene { --sw: 37; --sh: 18.4; }
  .ve-types__media--ads .ve-types__ads { right: auto; gap: 0.8em; }
  .ve-types__scene .ve-types__ad .ve-phone { height: 12.8em; }
  .ve-types__scene .ve-types__ad--lead .ve-phone { height: 16em; }
  .ve-types__media--ads .ve-types__plan { top: auto; bottom: 1.4em; }
}
@media (min-width: 1280px) {
  .ve-types__media--ads .ve-types__scene { --sw: 30; --sh: 29; }
  .ve-types__media--ads .ve-types__ads { right: 0; bottom: auto; top: 1.6em; }
  .ve-types__scene .ve-types__ad .ve-phone { height: 15em; }
  .ve-types__scene .ve-types__ad--lead .ve-phone { height: 18em; }
  .ve-types__media--ads .ve-types__plan { left: 3em; right: 3em; bottom: 0; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 1.4em; }
  .ve-types__media--ads .ve-types__plan-title { grid-column: 1 / -1; }
}

/* 05 Podcast to clips: the full episode, its waveform with three picked moments and the clip list. */
.ve-types__media--podcast .ve-types__scene { --sw: 30; --sh: 12.4; }
.ve-types__media--podcast .ve-types__panel { gap: 0.9em; padding: 0.9em 1em 1em; }
.ve-types__ep { display: flex; align-items: center; justify-content: space-between; gap: 1em; font-size: 0.66em; font-weight: var(--sf-fw-semibold); }
.ve-types__ep-name { display: inline-flex; align-items: center; gap: 0.5em; }
.ve-types__ep-name i { width: 0.6em; height: 0.6em; border-radius: 50%; background: var(--sf-soft-lavender); }
.ve-types__wave { position: relative; height: 3em; margin-top: 0.7em; }
.ve-types__wave-bars { position: absolute; inset: 0; display: flex; align-items: center; gap: 2px; }
.ve-types__wave-bars i { flex: 1; height: var(--h); border-radius: 2px; background: rgba(200, 183, 255, 0.5); }
.ve-types__pick { position: absolute; top: -0.25em; bottom: -0.25em; left: var(--x); width: var(--w); border: 1px solid var(--sf-soft-lavender); border-radius: 0.3em; background: rgba(200, 183, 255, 0.2); }
.ve-types__pick b { position: absolute; left: -1px; bottom: calc(100% + 0.3em); padding: 0.25em 0.45em; border-radius: 0.3em; background: var(--sf-soft-lavender); color: var(--sf-midnight);
  font-size: 0.5em; font-weight: var(--sf-fw-bold); white-space: nowrap; }
.ve-types__clips { display: grid; gap: 0.5em; margin: 0; padding: 0; list-style: none; }
.ve-types__clips li { display: flex; align-items: center; gap: 0.7em; padding: 0.45em; border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 0.45em; background: rgba(255, 255, 255, 0.04); }
.ve-types__thumb { flex: none; width: 1.7em; aspect-ratio: 9 / 16; border-radius: 0.25em; background: radial-gradient(circle at 50% 40%, rgba(200, 183, 255, 0.55), transparent 60%), linear-gradient(170deg, var(--vt-blue), var(--vt-purple)); }
.ve-types__clip { display: grid; gap: 0.2em; min-width: 0; }
.ve-types__clip b { overflow: hidden; font-size: 0.66em; font-weight: var(--sf-fw-bold); white-space: nowrap; text-overflow: ellipsis; }
.ve-types__clip .ve-screen-muted { font-size: 0.54em; font-variant-numeric: tabular-nums; }
@media (min-width: 560px) { .ve-types__media--podcast .ve-types__scene { --sw: 30; --sh: 21.5; } }
@media (min-width: 1280px) { .ve-types__media--podcast .ve-types__scene { --sw: 28; --sh: 22; } }

/* 06 YouTube long-form: the monitor with a chapter card and chapter bar, then the edit timeline with its markers. */
.ve-types__media--youtube .ve-types__scene { --sw: 26; --sh: 15.4; }
.ve-types__chapter { position: absolute; right: 4%; top: 7%; z-index: 1; display: grid; gap: 0.3em; width: 44%; padding: 0.6em 0.7em 0.7em;
  border: 1px solid rgba(255, 255, 255, 0.14); border-radius: 0.45em; background: rgba(9, 11, 20, 0.72); }
.ve-types__chapter span { font-size: 0.54em; font-weight: var(--sf-fw-bold); letter-spacing: 0.12em; text-transform: uppercase; color: var(--sf-soft-lavender); }
.ve-types__chapter b { font-size: 0.66em; font-weight: var(--sf-fw-bold); line-height: 1.2; }
.ve-types__chapter i { height: 0.22em; border-radius: 1em; background: rgba(255, 255, 255, 0.2); }
.ve-types__chapter i:last-child { width: 60%; }
.ve-types__chbar { position: absolute; left: 3.5%; right: 3.5%; bottom: 5%; z-index: 1; display: flex; gap: 0.2em; }
.ve-types__chbar i { flex: var(--w) 1 0; height: max(3px, 0.24em); border-radius: 1em; background: rgba(255, 255, 255, 0.3); }
.ve-types__chbar i:first-child, .ve-types__chbar i:nth-child(2) { background: rgba(255, 255, 255, 0.85); }
.ve-types__chbar .ve-types__seg--now { background: linear-gradient(90deg, var(--sf-soft-lavender) 55%, rgba(255, 255, 255, 0.3) 55%); }
/* Markers sit on the clip lane (after the label column): --x is a 0-1 fraction of the lane. */
.ve-types__marker { position: absolute; top: -1.35em; left: calc(var(--ve-tl-label) + 8px + (100% - var(--ve-tl-label) - 8px) * var(--x)); z-index: 2; }
.ve-types__marker::after { content: ""; position: absolute; left: 0; top: 100%; height: 5.4em; width: 1px; background: rgba(200, 183, 255, 0.7); }
.ve-types__scene .ve-types__marker .ve-float { position: relative; translate: calc(-100% + 6px) 0; font-size: 10px; padding: 3px 8px; }
.ve-types__scene .ve-types__marker--end .ve-float { translate: -6px 0; }
.ve-types__media--youtube .ve-types__tl { padding-top: 1.7em; }
/* 560-1023 (a landscape stage): the editor layout, a smaller programme monitor centred over a full-width timeline. */
@media (min-width: 560px) {
  .ve-types__media--youtube .ve-types__scene { --sw: 34; --sh: 25; }
  .ve-types__media--youtube .ve-types__viewer { width: 58%; justify-self: center; }
}
@media (min-width: 1280px) {
  .ve-types__media--youtube .ve-types__scene { --sw: 28; --sh: 27.5; }
  .ve-types__media--youtube .ve-types__viewer { width: auto; justify-self: stretch; }
}

/* 07 Corporate: the company-profile monitor with a title plate; the brand kit card from 560. */
.ve-types__media--corporate .ve-types__scene { --sw: 24; --sh: 13.5; }
.ve-types__media--corporate .ve-types__viewer { position: absolute; left: 0; top: 0; width: 24em;
  background: radial-gradient(60% 70% at 70% 20%, rgba(70, 119, 255, 0.55), transparent 70%), linear-gradient(180deg, var(--vt-blue-hi) 0%, var(--vt-blue) 55%, var(--vt-blue-soft) 100%); }
.ve-types__skyline { position: absolute; left: 0; right: 0; bottom: 0; width: 100%; height: 48%; }
.ve-types__skyline path { fill: var(--vt-ink); opacity: 0.92; }
.ve-types__media--corporate .ve-types__lower { bottom: 28%; }
.ve-types__kit { right: 0; top: 3em; display: grid; gap: 0.6em; width: 11.5em; padding: 0.9em; box-shadow: 0 1.5em 3em -1.5em rgba(0, 0, 0, 0.8); }
.ve-types__kit-title { font-size: max(8px, 0.56em); font-weight: var(--sf-fw-bold); letter-spacing: 0.12em; text-transform: uppercase; color: var(--sf-soft-lavender); }
.ve-types__swatches { display: flex; gap: 0.35em; }
.ve-types__swatches i { flex: 1; height: 1.5em; border-radius: 0.3em; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14); background: var(--sf-midnight); }
.ve-types__swatches i:nth-child(2) { background: var(--sf-electric-blue); }
.ve-types__swatches i:nth-child(3) { background: var(--sf-growth-purple); }
.ve-types__swatches i:nth-child(4) { background: var(--sf-soft-lavender); }
.ve-types__aa { display: flex; align-items: center; gap: 0.6em; padding: 0.45em 0; border-block: 1px solid rgba(255, 255, 255, 0.1); }
.ve-types__aa b { font-size: 1.5em; font-weight: var(--sf-fw-extrabold); letter-spacing: -0.03em; line-height: 1; }
.ve-types__aa span { font-size: max(8px, 0.58em); line-height: 1.35; color: rgba(255, 255, 255, 0.7); }
.ve-types__kit-row { display: flex; align-items: center; justify-content: space-between; min-height: 1.3em; font-size: max(8px, 0.62em); color: rgba(255, 255, 255, 0.86); }
.ve-types__kit .sc-note__icon { width: 2.1em; height: 2.1em; }
.ve-types__kit .sc-note__icon .sf-icon { width: 1.3em; height: 1.3em; }
@media (min-width: 560px) {
  .ve-types__media--corporate .ve-types__scene { --sw: 34; --sh: 19; }
  .ve-types__media--corporate .ve-types__viewer { top: 1.2em; width: 26em; }
}
@media (min-width: 1280px) {
  .ve-types__media--corporate .ve-types__scene { --sw: 30; --sh: 30; }
  .ve-types__media--corporate .ve-types__viewer { top: 9em; width: 30em; }
  .ve-types__media--corporate .ve-types__kit { top: 0.6em; right: 0.6em; width: 13em; }
}

/* 08 Product demo (the one SaaS example): an app window, a 2x zoom lens on Connect data and the cursor.
   Below 1280 the scene is exactly the app plus the lens (the lens's right edge 0.11-0.18em inside the scene), so centring
   the scene centres the picture; it reserved about 5em on the right that nothing filled. The stage is height-bound
   there, so the narrower scene keeps the same scale. */
.ve-types__media--demo .ve-types__scene { --sw: 23; --sh: 15.4; }
.ve-types__app { left: 0; top: 0; width: 23em; height: 13.6em; display: flex; flex-direction: column; }
.ve-types__scene .ve-types__app .sc-browser__bar { padding: 0.55em 0.8em; gap: 0.35em; }
.ve-types__scene .ve-types__app .sc-browser__bar span { width: 0.45em; height: 0.45em; }
.ve-types__scene .ve-types__app .sc-browser__bar em { margin-left: 0.6em; font-size: 0.56em; }
.ve-types__app-body { flex: 1; display: flex; min-height: 0; }
.ve-types__side { display: grid; align-content: start; gap: 0.6em; width: 2.6em; padding: 0.9em 0.7em; border-right: 1px solid rgba(255, 255, 255, 0.08); }
.ve-types__side i { height: 1.2em; border-radius: 0.3em; background: rgba(255, 255, 255, 0.12); }
.ve-types__side i:nth-child(2) { background: rgba(200, 183, 255, 0.55); }
.ve-types__app-main { position: relative; flex: 1; display: grid; grid-template-rows: auto auto minmax(0, 1fr) auto; gap: 0.7em; min-width: 0; padding: 0.9em; }
.ve-types__app-head { display: grid; gap: 0.35em; }
.ve-types__app-head i { height: 0.45em; width: 44%; border-radius: 1em; background: rgba(255, 255, 255, 0.3); }
.ve-types__app-head i + i { width: 28%; background: rgba(255, 255, 255, 0.14); }
.ve-types__tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.5em; }
.ve-types__tiles i { height: 2.2em; border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 0.4em; background: rgba(255, 255, 255, 0.06); }
.ve-types__chart { display: flex; align-items: flex-end; gap: 0.4em; min-height: 0; padding: 0.6em 0.6em 0; border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 0.4em; }
.ve-types__chart i { flex: 1; height: var(--h); border-radius: 0.2em 0.2em 0 0; background: rgba(70, 119, 255, 0.55); }
.ve-types__chart i:last-child { background: rgba(200, 183, 255, 0.7); }
/* The in-app action sits in the window's footer row; the 2x lens is centred on it, so the lens reads as a zoom on it. */
.ve-types__scene .ve-types__connect { justify-self: end; }
.ve-types__lens { position: absolute; right: 0.18em; bottom: 0.06em; z-index: 3; display: grid; place-items: center; width: 7em; aspect-ratio: 1; overflow: hidden; border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, var(--vt-blue-soft), var(--vt-night) 75%); box-shadow: 0 0 0 3px var(--sf-soft-lavender), 0 1.5em 3em -1em rgba(0, 0, 0, 0.8); }
.ve-types__scene .ve-types__lens .sc-pill { height: 2.4em; padding: 0 1.1em; font-size: 0.74em; box-shadow: 0 0 0 0.3em rgba(200, 183, 255, 0.28); }
.ve-types__lens em { position: absolute; left: 50%; bottom: 1em; translate: -50% 0; font-size: 0.56em; font-style: normal; font-weight: var(--sf-fw-bold); color: rgba(255, 255, 255, 0.72); }
.ve-types__cursor { position: absolute; left: 58%; top: 52%; width: 1.9em; height: 1.9em; filter: drop-shadow(0 0.15em 0.25em rgba(0, 0, 0, 0.5)); }
.ve-types__cursor path { fill: var(--sf-white); stroke: var(--sf-midnight); stroke-width: 1.4; stroke-linejoin: round; }
.ve-types__media--demo .ve-types__f1 { left: calc(100% * 1 / var(--sw)); bottom: calc(100% * 0.4 / var(--sh)); }
@media (min-width: 560px) {
  .ve-types__media--demo .ve-types__scene { --sw: 29; --sh: 21; }
  .ve-types__app { top: 1.8em; width: 28em; height: 16em; }
  .ve-types__lens { right: 0.11em; bottom: 0.39em; width: 9em; }
  .ve-types__scene .ve-types__lens .sc-pill { font-size: 0.9em; }
  .ve-types__media--demo .ve-types__f1 { left: calc(100% * 1 / var(--sw)); bottom: auto; top: 0; }
}
@media (min-width: 1280px) {
  .ve-types__media--demo .ve-types__scene { --sw: 30; --sh: 30; }
  .ve-types__app { top: 2.4em; width: 28.5em; height: 20em; }
  .ve-types__lens { right: -0.15em; bottom: 4.02em; width: 10.5em; }
  .ve-types__media--demo .ve-types__f1 { left: calc(100% * 0.4 / var(--sw)); }
}

/* 09 Motion graphics: a canvas with kinetic type and keyframe lanes; the ease curve from 560. */
.ve-types__media--motion .ve-types__scene { --sw: 28; --sh: 15.4; }
.ve-types__canvas { left: 0; top: 0; right: 0; bottom: 0;
  background: radial-gradient(70% 90% at 22% 26%, rgba(140, 77, 255, 0.38), transparent 70%), linear-gradient(160deg, var(--vt-purple) 0%, var(--vt-ink) 100%); }
.ve-types__kinetic { position: absolute; left: 1em; top: 0.9em; font-size: 2.3em; font-weight: var(--sf-fw-extrabold); letter-spacing: -0.04em; line-height: 1; }
.ve-types__kinetic span { display: inline-block; }
.ve-types__kinetic .ve-types__accent { color: var(--sf-soft-lavender); }
.ve-types__path { position: absolute; right: 1.2em; top: 3.8em; width: 9em; height: 4.5em; overflow: visible; }
.ve-types__path path { fill: none; stroke: rgba(255, 255, 255, 0.4); stroke-width: 1.5; stroke-dasharray: 3 4; vector-effect: non-scaling-stroke; }
.ve-types__path circle { fill: var(--sf-soft-lavender); }
.ve-types__keys { position: absolute; left: 1em; right: 1em; bottom: 0.9em; display: grid; gap: 0.35em; padding: 0.6em 0.7em; border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 0.45em; background: rgba(9, 11, 20, 0.55); }
.ve-types__key { display: grid; grid-template-columns: 4.6em minmax(0, 1fr); align-items: center; gap: 0.5em; }
.ve-types__key em { font-size: 0.54em; font-style: normal; font-weight: var(--sf-fw-semibold); letter-spacing: 0.06em; text-transform: uppercase; color: rgba(255, 255, 255, 0.66); }
.ve-types__key > span { position: relative; height: 1em; border-radius: 0.2em; background: linear-gradient(rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.14)) 0 50% / 100% 1px no-repeat; }
.ve-types__key i { position: absolute; left: var(--x); top: 50%; width: 0.62em; height: 0.62em; translate: -50% -50%; rotate: 45deg; border-radius: 0.1em; background: var(--sf-soft-lavender); }
.ve-types__ease { right: 0; bottom: 0; display: grid; grid-template-rows: auto minmax(0, 1fr); gap: 0.4em; width: 9em; height: 8.4em; padding: 0.7em; box-shadow: 0 1.5em 3em -1.5em rgba(0, 0, 0, 0.8); }
.ve-types__ease-label { font-size: max(8px, 0.58em); font-weight: var(--sf-fw-bold); letter-spacing: 0.12em; text-transform: uppercase; color: var(--sf-soft-lavender); }
.ve-types__ease svg { display: block; width: 100%; height: 100%; min-height: 0; overflow: visible; }
.ve-types__ease-grid { fill: none; stroke: rgba(255, 255, 255, 0.12); stroke-width: 1; vector-effect: non-scaling-stroke; }
.ve-types__ease-curve { fill: none; stroke: var(--sf-soft-lavender); stroke-width: 2.5; stroke-linecap: round; vector-effect: non-scaling-stroke; }
@media (min-width: 560px) {
  .ve-types__media--motion .ve-types__scene { --sw: 34; --sh: 20; }
  .ve-types__canvas { right: 5em; bottom: 1.4em; }
  .ve-types__kinetic { font-size: 2.8em; }
  .ve-types__keys { right: 5em; }
}
@media (min-width: 1280px) {
  .ve-types__media--motion .ve-types__scene { --sw: 30; --sh: 27; }
  .ve-types__canvas { right: 0; bottom: 8.4em; top: 0; }
  .ve-types__ease { width: 11em; height: 10em; right: 0.8em; }
  .ve-types__media--motion .ve-types__keys { right: 13em; bottom: 1em; }
}

/* ---------- One-pass decorative motion (.ve-anim, R21) ----------
   From-only keyframes, so the resting state is the final picture (no JS, reduced motion and print show it). They run
   once when the card is revealed (sarafi.js) and end within 5s. The timeline playheads use the shared ve-scrub. */
@keyframes ve-types-fill { from { transform: scaleX(0.06); } }
@keyframes ve-types-rise { from { opacity: 0; transform: translateY(0.4em); } }
@keyframes ve-types-point { from { transform: translate(2.2em, 2em); } }
.sf-js .is-revealed .ve-types__bars i.ve-anim { animation: ve-types-fill 3200ms var(--sf-ease-out) 400ms both; }
.sf-js .is-revealed .ve-types__kinetic .ve-anim { animation: ve-types-rise 900ms var(--sf-ease-out) 300ms both; }
.sf-js .is-revealed .ve-types__kinetic .ve-anim:nth-child(2) { animation-delay: 450ms; }
.sf-js .is-revealed .ve-types__kinetic .ve-anim:nth-child(3) { animation-delay: 600ms; }
.sf-js .is-revealed .ve-types__cursor.ve-anim { animation: ve-types-point 1400ms var(--sf-ease-out) 500ms both; }

/* ---------- Print: one column, no sticky nav, lists open (video-editing.js opens closed details on beforeprint) ---------- */
@media print {
  .ve-types__nav { display: none; }
  .ve-types__card { display: block; break-inside: avoid; }
  .ve-types__media { display: none; }
  .ve-types__summary { display: none; }
}

/* ======================================================================
   07 Monthly editing + custom projects (blueprint §3 07)
   ====================================================================== */
/* Two panels on Paper / Night. The monthly panel is the section's featured sheet (sf-card--featured: the gradient
   hairline is this screen's moment; in light, the purple top light and the lavender badge). The custom panel is a
   plain card with a button, so it takes shadow-1 in light by itself. The price block is the shared .ve-price with both
   states (D1). Mobile-first: base, 360, 480, 560, 768, 1024. */

/* ---------- Monthly panel ---------- */
.ve-plans__monthly { padding: 20px; }
@media (min-width: 360px) { .ve-plans__monthly { padding: clamp(24px, 4.5vw, 56px); } }
.ve-plans__top { display: grid; grid-template-columns: minmax(0, 1fr); gap: 32px; }
@media (min-width: 1024px) { .ve-plans__top { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 64px; align-items: center; } }

.ve-plans__kicker { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; margin: 0; }
/* The badge in the dark theme: sarafi.css fills it with lavender only in light, so here it takes a Soft Lavender tint
   (lavender on its own tint over Deep Blue, about 8:1). Light keeps sarafi.css's badge (purple ink on lavender, 6.7:1). */
:root[data-theme="dark"] .ve-plans__kicker span.sf-chip { border-color: transparent; background-color: color-mix(in srgb, var(--sf-soft-lavender) 16%, transparent); color: var(--sf-soft-lavender); font-weight: var(--sf-fw-semibold); }
.ve-plans__title { margin-top: 14px; }
@media (min-width: 1024px) { .ve-plans__title .sf-serif { display: block; } }
.ve-plans__lead { margin-top: 18px; }

/* Foot: the price, then the CTA with WhatsApp under it. Phones: stacked, full-width primary. From 768: side by side
   on a hairline, the CTAs aligned to the price's baseline. */
.ve-plans__foot { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; margin-top: 28px; }
.ve-plans__ctas { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.ve-plans__ctas .sf-btn { width: 100%; }
/* The two large buttons never outgrow their card. The grid tracks above are minmax(0, 1fr), not auto, so a nowrap label
   cannot widen them, and the label may wrap inside the button below 480px (WCAG 1.4.12: text spacing makes both labels
   wider). From 480px it stays on one line. Base (below 360): the regular 48px size, so at 320 both labels still fit on
   one line in the card's 240px of content; from 360 the large size. */
.ve-plans :is(.ve-plans__ctas, .ve-plans__custom-cta) .sf-btn { max-width: 100%; white-space: normal; line-height: 1.25; text-align: center; }
.ve-plans :is(.ve-plans__ctas, .ve-plans__custom-cta) .sf-btn--lg { --sf-btn-h: 48px; padding-inline: 16px; font-size: 0.9375rem; }
@media (min-width: 360px) { .ve-plans :is(.ve-plans__ctas, .ve-plans__custom-cta) .sf-btn--lg { --sf-btn-h: 56px; padding-inline: 24px; font-size: 1rem; } }
@media (min-width: 480px) { .ve-plans :is(.ve-plans__ctas, .ve-plans__custom-cta) .sf-btn { white-space: nowrap; line-height: 1; } }
.ve-plans__wa { display: inline-flex; align-items: center; gap: 8px; justify-self: start; color: var(--sf-link); font-size: 0.9375rem; font-weight: var(--sf-fw-semibold); text-decoration: none; }
.ve-plans__wa .sf-icon { width: 18px; height: 18px; }
.ve-plans__wa:hover { text-decoration: underline; text-underline-offset: 4px; }
@media (pointer: coarse) { .ve-plans__wa { min-height: 44px; } }
@media (min-width: 768px) {
  .ve-plans__foot { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 24px; padding-top: 28px; border-top: 1px solid var(--sf-border); }
  .ve-plans__ctas { justify-items: start; }
  .ve-plans__ctas .sf-btn { width: auto; }
}

/* ---------- The content pipeline (a .ve-screen device) ----------
   Four kanban columns. Phones: 2 x 2 with one card per column and 2:1 thumbnails (the others are .ve-hide-sm), and no
   footer tags (Same editors · Same standards · Same style guide, which the lead already says; R15 height lever). The
   thumbnails are brand-tint frames with the shared subject silhouette; delivered items carry the lavender tick
   (part 00). On reveal, the item in edit nudges twice and settles. */
.ve-plans__pipeline { padding: 20px; }
.ve-plans__pipe-head { display: flex; align-items: center; gap: 10px; min-width: 0; margin-bottom: 14px; font-size: 0.75rem; line-height: 1.2; }
.ve-plans__pipe-title { font-size: 0.8125rem; font-weight: var(--sf-fw-semibold); color: var(--sf-white); }
.ve-plans__pipe-head .art__tag { margin-left: auto; padding: 3px 7px; font-size: 11px; }
.ve-plans__cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
@media (min-width: 560px) {
  .ve-plans__cols { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .ve-plans__thumb { aspect-ratio: 16 / 9; }
}
.ve-plans__col { display: grid; align-content: start; gap: 8px; min-width: 0; padding: 10px; border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 6px; background: rgba(255, 255, 255, 0.02); }
.ve-plans__col-label { font-size: 10px; font-weight: var(--sf-fw-semibold); line-height: 1.2; letter-spacing: 0.1em; text-transform: uppercase; color: rgba(255, 255, 255, 0.62); }
.ve-plans__item { display: grid; gap: 6px; min-width: 0; padding: 6px; border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 6px; background: rgba(255, 255, 255, 0.04);
  font-size: 11px; font-weight: var(--sf-fw-semibold); line-height: 1.25; color: var(--sf-white); overflow-wrap: break-word; }
.ve-plans__thumb { position: relative; display: block; aspect-ratio: 2 / 1; overflow: hidden; border-radius: 4px; background: linear-gradient(150deg, #4677FF, #2A356B); }
.ve-plans__thumb--purple { background: linear-gradient(150deg, #8C4DFF, #3B2A6B); }
.ve-plans__thumb--lavender { background: linear-gradient(150deg, #C8B7FF, #5B4AA8); }
.ve-plans__thumb--deep { background: linear-gradient(150deg, #2A356B, #11172A); }
.ve-plans__thumb .ve-subject { width: 38%; }
.ve-plans__thumb .sc-note__icon { position: absolute; top: 4px; right: 4px; width: 16px; height: 16px; background: rgba(9, 11, 20, 0.72); }
.ve-plans__thumb .sc-note__icon .sf-icon { width: 10px; height: 10px; stroke-width: 3; }
.ve-plans__pipe-foot { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.ve-plans__pipe-foot .sc-pill { height: 26px; padding: 0 11px; font-size: 11px; }
@keyframes ve-plans-nudge { 50% { translate: 6px 0; border-color: rgba(200, 183, 255, 0.5); background-color: rgba(200, 183, 255, 0.1); } }
.sf-js .ve-plans__monthly.is-revealed .ve-plans__item--moving.ve-anim { animation: ve-plans-nudge 1200ms ease-in-out 700ms 2 both; }

/* ---------- Perks ----------
   Phones (R15): plain text rows between hairlines, no tiles, and a tighter 32 / 24px lead-in. From 560: boxed tiles with
   the icon well, 2 across; from 1024: 4 across. Static, so flat. */
.ve-plans__perks { margin-top: 32px; padding-top: 24px; border-top: 1px solid var(--sf-border); }
@media (min-width: 560px) { .ve-plans__perks { margin-top: 40px; padding-top: 32px; } }
.ve-plans__perks-title { margin-bottom: 16px; }
.ve-plans__perk-grid { display: grid; grid-template-columns: minmax(0, 1fr); margin: 0; padding: 0; list-style: none; }
.ve-plans__perk { padding: 10px 0; border-bottom: 1px solid var(--sf-border); }
.ve-plans__perk:last-child { border-bottom: 0; padding-bottom: 0; }
.ve-plans__perk p { display: grid; gap: 2px; margin: 0; }
/* Titles and text balance: at 560-620 the cards are 140-160px wide and pretty still left lone words ("Consistent brand
   / style", "... what's / working."). */
.ve-plans__perk-title { font-size: 0.9375rem; font-weight: var(--sf-fw-bold); line-height: 1.35; color: var(--sf-fg); text-wrap: balance; }
.ve-plans__perk-text { font-size: 0.875rem; line-height: 1.5; color: var(--sf-fg-body); text-wrap: balance; }
@media (min-width: 560px) {
  .ve-plans__perk-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .ve-plans__perk, .ve-plans__perk:last-child { display: flex; align-items: flex-start; gap: 14px; padding: 16px; border: 1px solid var(--sf-border); border-radius: var(--sf-radius-sm); }
  .ve-plans__perk .sf-icon-tile { flex: none; width: 40px; height: 40px; }
  .ve-plans__perk .sf-icon-tile .sf-icon { width: 20px; height: 20px; }
}
/* 1024: four across; until 1280 each tile is about 200px wide, so its icon sits above the text. */
@media (min-width: 1024px) {
  .ve-plans__perk-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .ve-plans__perk, .ve-plans__perk:last-child { flex-direction: column; gap: 12px; }
}
@media (min-width: 1280px) { .ve-plans__perk, .ve-plans__perk:last-child { flex-direction: row; gap: 14px; } }

/* ---------- Custom panel ---------- */
.ve-plans__custom { display: grid; grid-template-columns: minmax(0, 1fr); gap: 28px; margin-top: 24px; padding: 20px; }
@media (min-width: 360px) { .ve-plans__custom { padding: clamp(24px, 4vw, 48px); } }
@media (min-width: 1024px) { .ve-plans__custom { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: 64px; align-items: center; } }
.ve-plans__custom-title { margin-top: 14px; }
.ve-plans__custom-copy .sf-card__text { margin-top: 12px; max-width: 46ch; font-size: var(--sf-fs-body); line-height: var(--sf-lh-body); }
.ve-plans__custom-cta { margin: 24px 0 0; }
.ve-plans__steps { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; margin: 0; padding: 0; list-style: none; }
@media (min-width: 768px) { .ve-plans__steps { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* Each step sits on a tint, so it carries .ve-tint (R1): its muted and running text lift on the dark card. */
/* Phones: the number sits beside the step's title; from 768 (three across) it sits above it. */
.ve-plans__step { display: grid; grid-template-columns: 28px minmax(0, 1fr); column-gap: 8px; padding: 14px 16px; border-radius: var(--sf-radius-sm); background: var(--sf-hover); }
.ve-plans__step .ve-num { grid-row: 1 / span 2; padding-top: 4px; }
.ve-plans__step h4 { margin: 0; font-size: 1rem; font-weight: var(--sf-fw-bold); line-height: 1.3; }
.ve-plans__step p { grid-column: 2; margin: 4px 0 0; font-size: 0.875rem; line-height: 1.5; color: var(--sf-fg-body); text-wrap: balance; }
@media (min-width: 768px) {
  .ve-plans__step { display: block; padding: 16px; }
  .ve-plans__step .ve-num { display: block; padding-top: 0; }
  .ve-plans__step h4 { margin-top: 10px; }
}
.ve-plans__chips-title { margin: 20px 0 10px; }
.ve-plans__chips { --sf-cluster-gap: 8px; margin: 0; padding: 0; list-style: none; }
/* Static tags are filled, never outlined; the featured badge keeps its own look (above, and sarafi.css in light). */
.ve-plans__custom span.sf-chip { border-color: transparent; background-color: var(--sf-hover); }

/* Anchors (#monthly from FAQ 11, #custom, deep links): a panel that has not been revealed yet sits 20px low (sarafi.css
   reveal: translate 0 20px), and a jump aligns that shifted box, so after the reveal the panel ended up 20px high, 4px
   under the header. A scroll margin while unrevealed is not enough: on a deep link Chrome re-anchors the fragment during
   load, after the reveal has dropped the margin but while the panel is still rising. So the panel that is the URL's
   target does not rise at all: it only fades in (the reveal's other transitions stay), and every jump aligns its real
   box, 16px under the header. */
html.sf-js :is(.ve-plans__monthly, .ve-plans__custom)[data-sf-reveal]:target { translate: none;
  transition: opacity var(--sf-reveal-dur) var(--sf-ease-out) var(--sf-reveal-delay), transform 500ms var(--sf-ease-out),
    border-color var(--sf-dur-fast) var(--sf-ease-out), box-shadow 500ms var(--sf-ease-out); }

@media print {
  .ve-plans__monthly, .ve-plans__custom { break-inside: avoid; }
  .ve-plans__top, .ve-plans__custom { display: block; }
}

/* ======================================================================
   08 Why Sarafi (blueprint §3 08)
   ====================================================================== */
/* The reference's asymmetric "why" bento in Sarafi dress: seven sf-cards on a 12-column grid (7|5, 5|7, 4|4|4 from
   1024px), each with a small diagram pinned to the bottom in a tinted .ve-well, then a closing strip with the section's
   primary. Cloud / Night Soft. Every colour is a token, so the diagrams flip with the surface and the theme; the only
   status colour is the QA "Passed" badge (sf-badge--success, a sheet). No numbers on the cards (N6), no gradient (R8).
   Motion (R21): the QA ticks and the scale tiles run once on .is-revealed (.ve-anim, from-only keyframes), and the two
   rotators make one pass in video-editing.js. No JS, reduced motion and print show the resting state. */

/* ---------- Grid ----------
   Base: one column. 768: two columns, with 01, 04 and 07 across both (the reference's 760-1079 layout).
   1024: twelve columns; the width modifiers give the rows 7|5, 5|7 and 4|4|4 (about 740 / 524 / 416px at 1440). */
.ve-why__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; margin: 0; padding: 0; list-style: none; }
@media (min-width: 768px) {
  .ve-why__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ve-why__card:is(:nth-child(1), :nth-child(4), :nth-child(7)) { grid-column: 1 / -1; }
}
@media (min-width: 1024px) {
  .ve-why__grid { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  /* 0,2,0 and later than the 768 spans, so the widths win. */
  .ve-why__grid > .ve-why__card--w7 { grid-column: span 7; }
  .ve-why__grid > .ve-why__card--w5 { grid-column: span 5; }
  .ve-why__grid > .ve-why__card--w4 { grid-column: span 4; }
}

/* ---------- Card: head on top, the diagram below it ----------
   The well grows to the bottom of the card, so the wells in a row end together and no empty band floats above them
   (the reference pins them to the bottom with margin-top: auto; growing reads calmer on the 7|5 rows). */
.ve-why__card { display: flex; flex-direction: column; gap: 18px; min-width: 0; padding: 20px 20px 18px; }
.ve-why__title { font-size: 1.1875rem; font-weight: var(--sf-fw-bold); line-height: 1.3; letter-spacing: -0.01em; color: var(--sf-fg); }
.ve-why__text { margin-top: 8px; max-width: 60ch; font-size: 0.9375rem; line-height: 1.6; color: var(--sf-fg-body); }
.ve-why__visual { flex: 1 0 auto; min-height: 140px; padding: 20px 18px; }
@media (min-width: 768px) { .ve-why__visual { min-height: 176px; } }
@media (min-width: 1024px) {
  .ve-why__card { gap: 22px; padding: 28px 28px 24px; }
  .ve-why__title { font-size: 1.375rem; }
}

/* Small sheets inside the wells: raised paper (light) or raised night (dark) on a hairline. The label is .ve-label
   (12px caps); the value is 13px semibold ink. */
.ve-why__node, .ve-why__stage, .ve-why__qa-item, .ve-why__platform { min-width: 0; border: 1px solid var(--sf-border); border-radius: 6px; background: var(--sf-bg-raised); }
.ve-why__value { display: block; font-size: 0.8125rem; font-weight: var(--sf-fw-semibold); line-height: 1.3; color: var(--sf-fg); }

/* ---------- 01 Objective chain ----------
   The objective node on top, a 1px tree into four decision nodes. Base (the well shows from 560): 2 x 2, joined by a
   centre trunk with a short branch into each node. One row of four under a rail once the well is 520px wide: from
   768 (the card spans the row) and from about 1200 (the 7-column card); the narrower 7-column card at 1024 keeps
   2 x 2 (a container query, so the switch follows the card, not the window). The tree is drawn with pseudo-elements,
   28px between the objective and the row (14px stem + 14px drop). */
.ve-why__visual--chain { display: flex; flex-direction: column; justify-content: center; container-type: inline-size; }
.ve-why__chain { display: grid; gap: 28px; }
.ve-why__node { display: grid; align-content: center; gap: 4px; padding: 10px 12px; }
.ve-why__node--src { position: relative; justify-self: center; min-width: min(240px, 100%); padding: 12px 20px; border-color: var(--sf-fg-accent); text-align: center; }
.ve-why__node--src .ve-why__value { font-size: 0.9375rem; font-weight: var(--sf-fw-bold); }
.ve-why__node--src::after { content: ""; position: absolute; left: 50%; top: 100%; width: 1px; height: 14px; background: var(--sf-border-strong); }
.ve-why__branches { position: relative; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 1fr; gap: 10px 16px; }
.ve-why__branches > .ve-why__node { position: relative; }
/* 2 x 2: the trunk runs down the column gap to the middle of the second row ((height - row gap) / 4 from the bottom). */
.ve-why__branches::before { content: ""; position: absolute; left: 50%; top: -14px; bottom: calc((100% - 10px) / 4); width: 1px; background: var(--sf-border-strong); }
.ve-why__branches > .ve-why__node::before { content: ""; position: absolute; top: 50%; width: 8px; height: 1px; background: var(--sf-border-strong); }
.ve-why__branches > .ve-why__node:nth-child(odd)::before { right: -9px; }
.ve-why__branches > .ve-why__node:nth-child(even)::before { left: -9px; }
@container (min-width: 520px) {
  .ve-why__branches { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
  /* One row: a rail from the first node's centre to the last one's ((column - gap) / 2 in from each side). */
  .ve-why__branches::before { left: calc(12.5% - 3.75px); right: calc(12.5% - 3.75px); bottom: auto; width: auto; height: 1px; }
  .ve-why__branches > .ve-why__node::before,
  .ve-why__branches > .ve-why__node:is(:nth-child(odd), :nth-child(even))::before { left: 50%; right: auto; top: -15px; width: 1px; height: 15px; }
}

/* ---------- 02 Funnel: three centred stages narrowing to 100 / 82 / 64% ---------- */
.ve-why__visual--funnel { display: flex; flex-direction: column; justify-content: center; }
.ve-why__funnel { display: grid; gap: 8px; justify-items: center; }
.ve-why__stage { display: grid; gap: 3px; width: var(--w, 100%); padding: 10px 12px; text-align: center; }
.ve-why__stage--last { border-color: var(--sf-fg-accent); background: color-mix(in srgb, var(--sf-fg-accent) 8%, var(--sf-bg-raised)); }

/* ---------- 03 Goal: "This edit is built to [Hold attention]" + seven static tags ----------
   The tags are filled static tags (an outline means "press me"): sarafi.css fills span chips in light; here they are
   filled in dark and in the default mix too. The tag that matches the word has .is-on, a 1px accent edge. */
.ve-why__visual--goal { display: flex; flex-direction: column; justify-content: center; }
.ve-why__goal { display: flex; align-items: center; gap: 10px; margin: 8px 0 14px; font-size: 1.5rem; font-weight: var(--sf-fw-bold); line-height: 1.2; letter-spacing: -0.015em; color: var(--sf-fg); }
.ve-why__dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--sf-fg-accent); }
.ve-why__tags { display: flex; flex-wrap: wrap; gap: 8px; }
.ve-why__tags .sf-chip { background: var(--sf-hover); border-color: transparent; }
/* 0,5,0: beats the light theme's borderless span-chip fill (0,4,1). */
:root .ve-why .ve-why__tags .sf-chip.is-on { border-color: var(--sf-fg-accent); background: color-mix(in srgb, var(--sf-fg-accent) 12%, transparent); }
/* The rotator's cross-fade (video-editing.js adds .is-swapping for 150ms). */
.sf-js .ve-why [data-ve-rotate] { transition: opacity 150ms var(--sf-ease-out); }
.sf-js .ve-why [data-ve-rotate].is-swapping { opacity: 0; }
.sf-js .ve-why__tags .sf-chip { transition: background-color 150ms var(--sf-ease-out), border-color 150ms var(--sf-ease-out); }

/* ---------- 04 QA panel: head + eight checked items ----------
   2 x 4, then 4 x 2 once the well is 540px wide (a container query: the full-width card from 768, the 7-column card
   from about 1300; the 7-column card at 1024 is too narrow for four labels a row). */
.ve-why__visual--qa { container-type: inline-size; }
/* Without data-theme (the no-JS default mix) body is .sf-dark, so sarafi.css paints the badge in the on-dark green
   even here on a light surface; this restores the light badge ink (the themed views are already right). */
:root:not([data-theme]) .ve-why .sf-badge--success { color: var(--sf-badge-success-text); }
.ve-why__qa-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.ve-why__qa { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
@container (min-width: 540px) { .ve-why__qa { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.ve-why__qa-item { display: flex; align-items: center; gap: 8px; padding: 10px; font-size: 0.8125rem; font-weight: var(--sf-fw-semibold); line-height: 1.3; color: var(--sf-fg); }
.ve-why__tick { display: grid; place-items: center; flex: none; width: 20px; height: 20px; border-radius: 50%; color: var(--sf-fg-accent); background: color-mix(in srgb, var(--sf-fg-accent) 14%, transparent); }
.ve-why__tick .sf-icon { width: 12px; height: 12px; stroke-width: 2.5; }
@keyframes ve-why-pop { from { opacity: 0; transform: scale(0.4); } }
/* One pass on reveal: 360ms in, 90ms apart, 420ms each (about 1.4s in all). */
.sf-js .ve-why__card.is-revealed .ve-why__tick.ve-anim { animation: ve-why-pop 420ms var(--sf-ease-out) calc(360ms + var(--i, 0) * 90ms) both; }

/* ---------- 05 Statement (content) ----------
   "Every [cut] / has a reason." at 1.75rem 800, the word in the accent. The avoid list is three filled static tags,
   struck through (R11); the well's tint keeps their muted ink at AA in dark. */
.ve-why__visual--statement { display: flex; flex-direction: column; justify-content: space-between; gap: 18px; }
.ve-why__statement { font-size: 1.75rem; font-weight: var(--sf-fw-extrabold); line-height: 1.1; letter-spacing: -0.02em; color: var(--sf-fg); }
.ve-why__statement-end { display: block; }
.ve-why__word { color: var(--sf-fg-accent); }
.ve-why__avoid { --sf-cluster-gap: 8px; margin: 0; padding: 0; list-style: none; }
/* The chip's fill sits on the well's tint, so its muted ink moves a fifth towards --sf-fg to stay at AA (5.6:1 in dark,
   where plain tinted muted measured 4.35:1 on the double tint). */
.ve-why__avoid .sf-chip { text-decoration: line-through; text-decoration-thickness: 1px; color: color-mix(in srgb, var(--sf-fg-muted) 80%, var(--sf-fg)); border-color: transparent; background: var(--sf-hover); }

/* ---------- 06 Platform rows (content): a dl of four hairline rows ----------
   Label above value in a narrow well (320px phones, the 4-column card at 1024); label | value once the well is 240px
   wide (a container query, so it follows the card). */
.ve-why__visual--platforms { display: flex; flex-direction: column; justify-content: center; container-type: inline-size; }
.ve-why__platforms { display: grid; gap: 8px; margin: 0; }
.ve-why__platform { display: grid; gap: 3px; padding: 10px 14px; }
@container (min-width: 240px) { .ve-why__platform { grid-template-columns: 76px minmax(0, 1fr); align-items: center; gap: 12px; } }
.ve-why__platform dd { margin: 0; font-size: 0.875rem; font-weight: var(--sf-fw-semibold); line-height: 1.35; color: var(--sf-fg); text-wrap: balance; }

/* ---------- 07 Scale: twelve thumbnails (6 x 2) over a One-off, Monthly, Campaign track ----------
   Flat brand tints only (Electric Blue, Growth Purple and Soft Lavender mixed into the sheet colour; no gradient, so
   nothing reads as a second gradient moment), each with a 3px accent bar. */
.ve-why__visual--scale { display: flex; flex-direction: column; justify-content: center; gap: 16px; container-type: inline-size; }
.ve-why__tiles { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 6px; }
/* A full-width card (560-1023px) would make six columns of tall tiles: the twelve run in one row instead. */
@container (min-width: 460px) { .ve-why__tiles { grid-template-columns: repeat(12, minmax(0, 1fr)); } }
.ve-why__tile { position: relative; aspect-ratio: 4 / 5; overflow: hidden; border-radius: 5px; background: color-mix(in srgb, var(--sf-electric-blue) 26%, var(--sf-bg-raised)); }
.ve-why__tile:nth-child(3n + 2) { background: color-mix(in srgb, var(--sf-growth-purple) 26%, var(--sf-bg-raised)); }
.ve-why__tile:nth-child(3n) { background: color-mix(in srgb, var(--sf-soft-lavender) 44%, var(--sf-bg-raised)); }
.ve-why__tile::after { content: ""; position: absolute; left: 4px; right: 4px; bottom: 4px; height: 3px; border-radius: 2px; background: var(--sf-fg-accent); }
.ve-why__track { display: flex; justify-content: space-between; gap: 8px; padding-top: 10px; border-top: 2px solid color-mix(in srgb, var(--sf-fg-accent) 55%, transparent); }
@keyframes ve-why-fade { from { opacity: 0; translate: 0 6px; } }
.sf-js .ve-why__card.is-revealed .ve-why__tile.ve-anim { animation: ve-why-fade 500ms var(--sf-ease-out) calc(300ms + var(--i, 0) * 60ms) both; }

/* ---------- Closing strip: the line and the primary (full width at the base, auto from 560) ---------- */
.ve-why__cta { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 20px 32px; margin-top: 16px; padding: 20px; }
.ve-why__line { flex: 1 1 30ch; font-size: 1.375rem; font-weight: var(--sf-fw-semibold); line-height: 1.35; letter-spacing: -0.01em; color: var(--sf-fg); text-wrap: pretty; }
/* The reference's two-tone line, in Manrope: the heading ink, then running-text ink. Not the serif, which is kept for
   the one accent phrase in each section heading. */
.ve-why__line-soft { color: var(--sf-fg-body); }
.ve-why__cta .sf-btn { width: 100%; }
@media (min-width: 560px) {
  .ve-why__cta { padding: 24px 28px; }
  .ve-why__cta .sf-btn { width: auto; }
}

@media print {
  .ve-why__card, .ve-why__cta { break-inside: avoid; }
}

/* ======================================================================
   09 Sarafi vs other options (blueprint §3 09)
   ====================================================================== */
/* The reference's three-way comparison as a real table under a new class (never the bare .compare, which is a table on
   home and a wrapper on the WordPress and Shopify pages). Paper / Night.
   Base (below 900px): every row is a card (the reference's phone cards), Sarafi first; 640px at most below 700px. With
   JS, video-editing.js adds .ve-compare--armed and shows a toggle, so a card holds only the area and Sarafi's answer until
   the visitor asks for the other two (R15). Without JS every cell shows and the toggle stays hidden.
   900px: the table. The Sarafi column sits on the purple wash (light) or a purple-tinted sheet (dark) under a 3px brand
   rule: the section's one gradient moment. The wrapper is static, so it is flat on its hairline.
   .ve-tint on the wrapper keeps muted and running text at AA on the tinted header row and row bands in dark (R1). */

/* ---------- Phone toggle ---------- */
.ve-compare__toggle-row { margin: 0 0 16px; }
/* Full width on phones, and its label may wrap inside it (sarafi.css buttons are nowrap; with WCAG 1.4.12 text spacing
   at 320 the label is wider than the screen). */
.ve-compare__toggle { width: 100%; max-width: 640px; white-space: normal; line-height: 1.25; text-align: center; }
.ve-compare__toggle .sf-icon { transition: transform var(--sf-dur-base) var(--sf-ease-out); }
.ve-compare.is-expanded .ve-compare__toggle .sf-icon { transform: rotate(180deg); }
@media (min-width: 560px) { .ve-compare__toggle { width: auto; white-space: nowrap; line-height: 1; } }

/* ---------- Base: row cards ---------- */
.ve-compare__table { width: 100%; border-collapse: collapse; }
.ve-compare__table, .ve-compare__table :is(thead, tbody, tr, th, td) { display: block; }
/* The head row is visually hidden with the clip pattern (not display:none), so the column names stay in the table. */
.ve-compare__table thead { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
.ve-compare__table tbody tr { max-width: 640px; margin-bottom: 12px; overflow: hidden; border: 1px solid var(--sf-border); border-radius: var(--sf-radius-md); background: var(--sf-bg-raised); }
.ve-compare__table tbody tr:last-child { margin-bottom: 0; }
/* 700-899: the cards take the full measure, so their right edge lines up with the quote card and the heading. */
@media (min-width: 700px) { .ve-compare__table tbody tr { max-width: none; } }
.ve-compare__table tbody th { padding: 12px 16px; background: var(--sf-hover); text-align: left; font-size: 1rem; font-weight: var(--sf-fw-bold); line-height: 1.35; color: var(--sf-fg); }
.ve-compare__table td { padding: 12px 16px; font-size: 0.9375rem; line-height: 1.55; color: var(--sf-fg-body); }
.ve-compare__table td + td { border-top: 1px solid var(--sf-border); }
/* The cells are one to four short lines: balance keeps each off a lone last word ("… client / instructions." at 1280). */
.ve-compare__table :is(th, td) { text-wrap: balance; }
/* The column name as a label line above each answer. The second declaration gives it empty alt text where supported,
   so screen readers, which already get the column header, do not hear it twice (N8). */
.ve-compare__table td::before { content: attr(data-label); content: attr(data-label) / ""; display: block; margin-bottom: 4px;
  font-size: var(--sf-fs-label); line-height: var(--sf-lh-label); font-weight: var(--sf-fw-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--sf-fg-muted); }
.ve-compare__table td.ve-compare__us { display: grid; grid-template-columns: 18px minmax(0, 1fr); column-gap: 10px; align-items: start; color: var(--sf-fg); }
.ve-compare__table td.ve-compare__us::before { grid-column: 1 / -1; color: var(--sf-fg-accent); }
.ve-compare__table td.ve-compare__us .sf-icon { width: 18px; height: 18px; margin-top: 2px; stroke-width: 1.75; color: var(--sf-fg-accent); }
/* R15 phone compression (JS only). */
.ve-compare--armed:not(.is-expanded) .ve-compare__table td:not(.ve-compare__us) { display: none; }

/* The Sarafi cells: a purple tint on the sheet. Light: the purple wash token. */
.ve-compare .ve-compare__us { background: color-mix(in srgb, var(--sf-growth-purple) 7%, var(--sf-bg-raised)); }
:root[data-theme="dark"] .ve-compare .ve-compare__us { background: color-mix(in srgb, var(--sf-growth-purple) 12%, var(--sf-bg-raised)); }
:root[data-theme="light"] .ve-compare .ve-compare__us { background: var(--sf-purple-wash); }
/* The no-JS default mix (no data-theme: the Off-White surface with the plain accent): the accent label on the purple
   tint measures 4.21:1, so it moves a quarter towards --sf-fg (AA); the decorative quote mark gets the light theme's
   opacity. The themed views are already right. */
:root:not([data-theme]) .ve-compare .ve-compare__table td.ve-compare__us::before { color: color-mix(in srgb, var(--sf-fg-accent) 75%, var(--sf-fg)); }
:root:not([data-theme]) .ve-compare__claim .quote-mark { opacity: 0.85; }

/* Head cells (shown from 900px). The static "Our approach" tag is filled, not outlined. */
.ve-compare__name { display: block; font-size: 0.9375rem; font-weight: var(--sf-fw-bold); line-height: 1.3; color: var(--sf-fg); }
/* The sub-labels sit on the tinted head row, so their muted ink moves towards --sf-fg (AA on the tint in every mix). */
.ve-compare__sub { display: block; margin-top: 6px; font-size: var(--sf-fs-label); line-height: var(--sf-lh-label); font-weight: var(--sf-fw-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: color-mix(in srgb, var(--sf-fg-muted) 85%, var(--sf-fg)); }
.ve-compare__us .sf-chip { min-height: 26px; margin: 0 8px 0 0; padding: 0 10px; vertical-align: middle; font-size: 0.75rem; font-weight: var(--sf-fw-semibold); border-color: transparent; background: var(--sf-hover); }
.ve-compare thead .ve-compare__us .ve-compare__name { display: inline-block; vertical-align: middle; }
:root[data-theme="light"] .ve-compare thead .ve-compare__us .ve-compare__name { color: var(--sf-purple-ink); }

/* ---------- 900: the table ---------- */
@media (min-width: 900px) {
  .ve-compare__toggle-row { display: none; }
  .ve-compare__wrap { overflow: hidden; border: 1px solid var(--sf-border); border-radius: var(--sf-radius-md); background: var(--sf-bg-raised); }
  .ve-compare__table { display: table; table-layout: fixed; }
  .ve-compare__table thead { display: table-header-group; position: static; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; clip-path: none; white-space: normal; }
  .ve-compare__table tbody { display: table-row-group; }
  .ve-compare__table tr, .ve-compare__table tbody tr { display: table-row; max-width: none; margin: 0; overflow: visible; border: 0; border-radius: 0; background: none; }
  .ve-compare__table :is(th, td), .ve-compare__table td.ve-compare__us,
  .ve-compare--armed:not(.is-expanded) .ve-compare__table td:not(.ve-compare__us) { display: table-cell; }
  .ve-compare__table td::before { content: none; }
  .ve-compare__table thead th { padding: 20px 22px; vertical-align: bottom; text-align: left; background: var(--sf-hover); }
  .ve-compare__table thead th:nth-child(1) { width: 21%; }
  .ve-compare__table thead th:nth-child(2) { width: 31%; }
  .ve-compare__table thead th:nth-child(3), .ve-compare__table thead th:nth-child(4) { width: 24%; }
  .ve-compare__table tbody :is(th, td) { padding: 18px 22px; vertical-align: top; border-top: 1px solid var(--sf-border); }
  .ve-compare__table tbody th { background: none; font-size: 0.9375rem; font-weight: var(--sf-fw-semibold); }
  .ve-compare__table td.ve-compare__us { position: relative; padding-left: 50px; }
  .ve-compare__table td.ve-compare__us .sf-icon { position: absolute; left: 22px; top: 20px; margin: 0; }
  /* The gradient moment: a 3px brand rule on the Sarafi head cell, over its tint. */
  .ve-compare__table thead th.ve-compare__us { background: var(--sf-gradient-brand) top / 100% 3px no-repeat, color-mix(in srgb, var(--sf-growth-purple) 7%, var(--sf-bg-raised)); }
  :root[data-theme="dark"] .ve-compare__table thead th.ve-compare__us { background: var(--sf-gradient-brand) top / 100% 3px no-repeat, color-mix(in srgb, var(--sf-growth-purple) 12%, var(--sf-bg-raised)); }
  :root[data-theme="light"] .ve-compare__table thead th.ve-compare__us { background: var(--sf-gradient-rule) top / 100% 3px no-repeat, var(--sf-purple-wash); }
}
/* Row hover on fine pointers: the other options' cells take the hover tint; Sarafi's keep their wash. */
@media (min-width: 900px) and (hover: hover) and (pointer: fine) {
  .ve-compare__table tbody tr > :not(.ve-compare__us) { transition: background-color var(--sf-dur-fast) var(--sf-ease-out); }
  .ve-compare__table tbody tr:hover > :not(.ve-compare__us) { background: var(--sf-hover); }
}

/* ---------- Foot: the claim and the fairness note ----------
   Base: stacked, gap 20; a narrower quote gutter on phones so the claim keeps a readable measure at 320.
   560: the reference's 72px gutter. 1024: side by side (1.35fr 1fr), centred. */
.ve-compare__foot { display: grid; gap: 20px; margin-top: 20px; }
.ve-compare__claim { position: relative; margin: 0; padding: 24px 20px 22px 56px; }
.ve-compare__claim .quote-mark { position: absolute; left: 16px; top: 14px; height: auto; font-size: 3.5rem; line-height: 1; }
.ve-compare__claim-text { font-size: 1.25rem; font-weight: var(--sf-fw-bold); line-height: 1.3; letter-spacing: -0.01em; color: var(--sf-fg); text-wrap: balance; }
.ve-compare__claim-note { margin-top: 8px; font-size: 0.9375rem; line-height: 1.55; color: var(--sf-fg-body); }
.ve-compare__fair { max-width: 60ch; margin: 0; font-size: 0.875rem; line-height: 1.6; color: var(--sf-fg-muted); }
@media (min-width: 560px) {
  .ve-compare__claim { padding: 28px 28px 26px 72px; }
  .ve-compare__claim .quote-mark { left: 22px; top: 18px; font-size: 4.5rem; }
  .ve-compare__claim-text { font-size: 1.375rem; }
}
@media (min-width: 1024px) {
  .ve-compare__foot { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 48px; align-items: center; }
}

/* Print: every cell, no toggle. */
@media print {
  .ve-compare__toggle-row { display: none !important; }
  .ve-compare--armed:not(.is-expanded) .ve-compare__table td:not(.ve-compare__us) { display: block; }
  .ve-compare__table tbody tr { break-inside: avoid; }
}

/* ======================================================================
   10 Case study (blueprint §3 10)
   ====================================================================== */
/* The reference's one-story case card in Sarafi dress: a hero row (project still + summary with before/after bars),
   four metrics, then Challenge -> What Sarafi did -> Result, and a foot with the disclaimer and the links.
   Mist (the page's one light feature band) / Midnight, with the site's pointer spotlight. One sf-card that holds links
   (shadow-1 in light); its sub-panels are 8px --sf-hover wells with no border and .ve-tint (R1).
   Every figure is a placeholder: the bars use neutral lengths with a hatched fill while [data-ve-placeholder] (R29).
   Gradient moment: the "after" bar only (R8). The metric figures stay --sf-fg. */

/* ---------- Card ---------- */
.ve-case__card { display: grid; gap: 14px; padding: 14px; }
.ve-case__hero { display: grid; gap: 14px; }
.ve-case__summary, .ve-case__metric, .ve-case__step { border-radius: var(--sf-radius-sm); background: var(--sf-hover); }

/* Project still: a 16:10 window on the placeholder art; the industry tag is a dark plate top left (like .art__tag). */
.ve-case__media { position: relative; aspect-ratio: 16 / 10; overflow: hidden; border-radius: var(--sf-radius-sm); isolation: isolate; }
.ve-case__industry { position: absolute; left: 12px; top: 12px; z-index: 3; padding: 4px 8px; border-radius: var(--sf-radius-xs);
  background: rgba(9, 11, 20, 0.72); color: var(--sf-white); font-size: 12px; font-weight: var(--sf-fw-semibold); line-height: 1.4; letter-spacing: 0.02em;
  -webkit-print-color-adjust: exact; print-color-adjust: exact; }

/* Summary: meta tags, the headline result, the bars and the sample note. */
.ve-case__summary { display: flex; flex-direction: column; justify-content: center; min-width: 0; padding: 20px; }
.ve-case__meta { --sf-cluster-gap: 8px; margin: 0; padding: 0; list-style: none; }
/* Static tags are filled (an outline means "press me"); sarafi.css already fills them in light. */
.ve-case__meta li { min-width: 0; max-width: 100%; }
/* A long value wraps inside its tag instead of pushing past the panel at 320px. */
.ve-case__meta .sf-chip { max-width: 100%; padding-block: 6px; white-space: normal; line-height: 1.3; border-color: transparent; background: var(--sf-hover); }
.ve-case__title { margin: 14px 0 18px; font-size: 1.5rem; font-weight: var(--sf-fw-bold); line-height: 1.15; letter-spacing: -0.02em; color: var(--sf-fg); text-wrap: balance; }

/* Before / after bars: label | track | value. The rows share the list's columns (subgrid), so the label column is as
   wide as the longest label ("After [Z] days" wrapped to two lines in a fixed 96px column) and both tracks still start
   and end on the same lines. Without subgrid: the fixed 96px column. */
.ve-case__bars { display: grid; grid-template-columns: minmax(64px, max-content) minmax(0, 1fr) auto; gap: 12px; }
.ve-case__bar { grid-column: 1 / -1; display: grid; grid-template-columns: 96px minmax(0, 1fr) auto; align-items: center; gap: 12px; }
@supports (grid-template-columns: subgrid) { .ve-case__bar { grid-template-columns: subgrid; } }
.ve-case__track { position: relative; height: 8px; overflow: hidden; border-radius: 4px; background: var(--sf-border); }
.ve-case__track i { display: block; width: calc(var(--v, 0.5) * 100%); height: 100%; border-radius: 4px; background: var(--sf-fg-muted);
  transform-origin: left center; transition: transform 1.2s var(--sf-ease-out) 200ms; }
.ve-case__bar--after .ve-case__track i { background: var(--sf-gradient-brand); }
/* Placeholder lengths are hatched, so they read as a sketch, not a result. */
.ve-case__bars[data-ve-placeholder] .ve-case__track i {
  -webkit-mask: repeating-linear-gradient(135deg, #000 0 6px, rgb(0 0 0 / 0.35) 6px 10px);
  mask: repeating-linear-gradient(135deg, #000 0 6px, rgb(0 0 0 / 0.35) 6px 10px); }
/* The bars grow from 0 once the card is revealed (a one-shot transition; static without JS and with reduced motion). */
.sf-js .ve-case__card:not(.is-revealed) .ve-case__track i { transform: scaleX(0); }
.ve-case__val { font-size: 1rem; font-weight: var(--sf-fw-bold); line-height: 1.2; font-variant-numeric: tabular-nums; color: var(--sf-fg); }
.ve-case__bar--after .ve-case__val { color: var(--sf-fg-accent); }
.ve-case__sample { margin-top: 10px; font-size: 0.75rem; line-height: 1.4; color: var(--sf-fg-muted); }

/* ---------- Metrics: value first (column-reverse), 2 x 2, then 4 across from 768 ---------- */
.ve-case__metrics { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin: 0; }
.ve-case__metric { display: flex; flex-direction: column-reverse; justify-content: flex-end; min-width: 0; padding: 16px; }
.ve-case__metric .sf-stat__value { margin: 0; font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.25rem); color: var(--sf-fg); overflow-wrap: anywhere; }
.ve-case__metric .sf-stat__label { margin-top: 8px; }

/* ---------- Story: Challenge -> What Sarafi did -> Result ----------
   One column with a chevron centred in each gap; three columns from 900 with the chevrons turned to point along. */
.ve-case__story { display: grid; gap: 14px; margin: 0; padding: 0; list-style: none; }
.ve-case__step { position: relative; min-width: 0; padding: 20px; }
.ve-case__step p { margin-top: 10px; font-size: 0.9375rem; line-height: 1.6; color: var(--sf-fg-body); text-wrap: balance; }
.ve-case__step--result { border: 1px solid var(--sf-fg-accent); background: color-mix(in srgb, var(--sf-fg-accent) 8%, var(--sf-bg-raised)); }
.ve-case__step--result p { color: var(--sf-fg); }
.ve-case__chev { position: absolute; left: 50%; bottom: -14px; z-index: 1; width: 14px; height: 14px; margin-left: -7px; stroke-width: 2; color: var(--sf-fg-muted); }

/* ---------- Foot: disclaimer, then the links (the primary is full width at the base) ---------- */
.ve-case__foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px 24px; padding: 10px 10px 6px; }
.ve-case__disclaimer { max-width: 60ch; font-size: 0.8125rem; line-height: 1.55; color: var(--sf-fg-muted); }
.ve-case__foot .sf-cluster { gap: 12px 24px; width: 100%; }
/* The full-width button may wrap (the site's .sf-btn is nowrap): with WCAG 1.4.12 text spacing at 320 its one line was
   wider than the card and pushed the card's column, and the hero with it, 13px past the border. */
.ve-case__foot .sf-btn { width: 100%; padding-block: 8px; white-space: normal; text-align: center; }

@media (min-width: 560px) {
  .ve-case__foot .sf-cluster { width: auto; }
  .ve-case__foot .sf-btn { width: auto; white-space: nowrap; }
}
@media (min-width: 768px) {
  .ve-case__metrics { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (min-width: 900px) {
  .ve-case__story { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ve-case__chev { left: auto; right: -14px; top: 50%; bottom: auto; margin: -7px 0 0; rotate: -90deg; }
}
@media (min-width: 1024px) {
  .ve-case__hero { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); }
  .ve-case__summary { align-self: stretch; padding: 24px; }
  .ve-case__title { margin: 14px 0 22px; font-size: clamp(1.75rem, 1.3rem + 1.4vw, 2.625rem); }
}

/* Print: the project still is a placeholder until P5, and printed whole it was pushed to its own page, leaving the
   case head alone on the one before. It is left out; the summary takes the full width. */
@media print {
  /* The bars grow on reveal; one the visitor never scrolled to prints at full length. */
  .sf-js .ve-case__card:not(.is-revealed) .ve-case__track i { transform: none; }
  .ve-case__media { display: none; }
  .ve-case__hero { display: block; }
  .ve-case__card { break-inside: auto; }
  .ve-case__hero, .ve-case__metrics, .ve-case__step { break-inside: avoid; }
}

/* ======================================================================
   11 Works best with (blueprint §3 11, R28)
   ====================================================================== */
/* Everything else comes from service.css (.connected: one column, three from 768px) and sarafi.css (link cards).
   The .ve-head margin already spaces the cards from the heading, so the block's own top margin goes. */

.ve-related .connected { margin-top: 0; }

/* Print: each card prints whole (a split card left its text crossing the border on the next page), so the head's
   break-after: avoid (part 00) can keep the H2 with the first card. */
@media print { .ve-related .connected > .sf-card { break-inside: avoid; } }

/* ======================================================================
   12 FAQ (blueprint §3 12)
   ====================================================================== */
/* The reference's FAQ: an aside (head + contact card) beside topic chips and a numbered list, in Sarafi parts: .split,
   sf-chip toggle buttons (filter.js), the sf-accordion and an sf-card with the secondary and WhatsApp buttons.
   Paper / Night.
   DOM order is head, questions, contact card, which is the phone order: the reference reached it with display:
   contents + order on the aside, which sends keyboard focus to the contact card before the questions it sits under.
   Base (below 1024px): one column, the .split gap of 40px between the three parts. 560: numbers show and answers
   align with the question text. 1024: 4.2fr | 7fr, gap 72: the head and the contact card share the left column (rows
   1 and 2) and the questions span both rows on the right. The contact card is sticky when the window is at least
   760px tall (N5), so the human fallback stays in view beside the questions and a short window never traps it. */

/* ---------- Layout ---------- */
.ve-faq__main { min-width: 0; }
.ve-faq__contact { width: 100%; max-width: 560px; padding: 24px; }
.ve-faq__head .sf-h2 { margin-top: 14px; }
.ve-faq__head .sf-lead { margin-top: 18px; }

/* ---------- Topic chips: toggle buttons with a count (part of each chip's name, e.g. "Services 5") ---------- */
.ve-faq__filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }
/* Without JS the chips would do nothing: hide them, and every question shows. */
:root:not(.sf-js) .ve-faq__filters { display: none; }
.ve-faq__count { display: inline-grid; place-items: center; min-width: 22px; height: 20px; padding: 0 6px; border-radius: 999px;
  background: var(--sf-hover); font-size: 0.75rem; font-weight: var(--sf-fw-semibold); line-height: 1; font-variant-numeric: tabular-nums; color: var(--sf-fg-muted); }
/* On the selected chip the count takes the chip's own ink (inverted in dark, purple ink in light). */
.ve-faq__chip[aria-pressed="true"] .ve-faq__count { color: inherit; background: color-mix(in srgb, currentColor 14%, transparent); }
.ve-faq [data-filter-item][hidden] { display: none; }

/* ---------- Questions ---------- */
.ve-faq__n { display: none; }
/* No question ends on a lone word (8 of the 16 did at 320; pretty still left two). Balanced, like the card headings. */
.ve-faq__q { flex: 1 1 auto; min-width: 0; text-wrap: balance; }
.ve-faq .sf-accordion__panel > * + * { margin-top: 12px; }

/* Answer extras: link chips to the nine types (Q01), static chips (Q02 note, Q14 formats) and the three steps (Q16).
   Static tags are filled, not outlined (sarafi.css fills them in light; this does the same in dark). */
.ve-faq__links, .ve-faq__specs { --sf-cluster-gap: 8px; margin: 14px 0 0; padding: 0; list-style: none; }
.ve-faq .sf-accordion__panel > .ve-faq__links { margin-top: 14px; }
.ve-faq .sf-accordion__panel span.sf-chip { border-color: transparent; background: var(--sf-hover); color: var(--sf-fg); }
.ve-faq__note { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
.ve-faq__steps { display: grid; gap: 12px; margin: 0; padding: 0; list-style: none; counter-reset: ve-faq-step; }
.ve-faq__steps li { display: grid; grid-template-columns: 30px minmax(0, 1fr); column-gap: 8px; counter-increment: ve-faq-step; }
.ve-faq__steps li::before { content: "0" counter(ve-faq-step); grid-row: 1 / span 2; padding-top: 3px;
  font: var(--sf-fw-semibold) 0.8125rem/1.4 var(--sf-font-sans); letter-spacing: 0.1em; font-variant-numeric: tabular-nums; color: var(--sf-fg-accent); }
.ve-faq__steps strong { display: block; font-weight: var(--sf-fw-semibold); color: var(--sf-fg); text-wrap: pretty; }
.ve-faq__steps li > span { display: block; text-wrap: pretty; }

/* ---------- Contact card ---------- */
.ve-faq__contact-title { font-size: 1.25rem; font-weight: var(--sf-fw-bold); line-height: 1.3; color: var(--sf-fg); }
.ve-faq__contact-ctas { display: grid; gap: 10px; margin-top: 20px; }

@media (min-width: 560px) {
  .ve-faq__n { display: block; flex: none; width: 30px; font-size: 0.8125rem; font-weight: var(--sf-fw-semibold); letter-spacing: 0.04em; font-variant-numeric: tabular-nums; color: var(--sf-fg-muted); }
  .ve-faq .sf-accordion__item > summary { gap: 12px; align-items: baseline; }
  .ve-faq .sf-accordion__item > summary::after { align-self: center; }
  .ve-faq .sf-accordion__panel { padding-left: 42px; }
  .ve-faq__contact-ctas { display: flex; flex-wrap: wrap; }
  .ve-faq__contact-ctas .sf-btn { flex: 1 1 200px; width: auto; }
}
@media (min-width: 1024px) {
  /* Row 2 takes whatever height the questions need beyond the head, so the sticky card has room to travel. */
  .ve-faq__grid { grid-template-columns: minmax(0, 4.2fr) minmax(0, 7fr); grid-template-rows: auto 1fr; gap: 0 72px; align-items: start; }
  .ve-faq__head { grid-column: 1; grid-row: 1; }
  .ve-faq__main { grid-column: 2; grid-row: 1 / span 2; }
  .ve-faq__contact { grid-column: 1; grid-row: 2; max-width: none; margin-top: 36px; }
  .ve-faq__head .sf-lead { margin-top: 20px; max-width: 28em; }
  /* As in every .ve-head: the serif clause takes its own line beside the list (the reference's two-tone H2). */
  .ve-faq__head .sf-h2 .sf-serif { display: block; }
  .ve-faq__contact-title { font-size: 1.125rem; }
  .ve-faq__contact-ctas { display: grid; margin-top: 18px; }
  .ve-faq__contact-ctas .sf-btn { width: 100%; }
}
@media (min-width: 1024px) and (min-height: 760px) {
  .ve-faq__contact { position: sticky; top: calc(var(--ve-sticky-top) + 40px); }
}

/* Print: every question, open (video-editing.js opens them on beforeprint), and no chips. The head stays with Q01. */
@media print {
  .ve-faq__head { break-after: avoid; }
  .ve-faq__filters { display: none; }
  .ve-faq [data-filter-item][hidden] { display: block; }
  .ve-faq__contact { position: static; }
  .ve-faq .sf-accordion__item { break-inside: avoid; }
}

/* ======================================================================
   13 Final CTA (blueprint §3 13)
   ====================================================================== */
/* The site's Midnight "Sarafi Box" (.final: glow, blobs, symbol; inset from 768px in light) with the reference's
   two-part close: the copy and both CTAs, beside a "What we'll talk through first" list.
   Base: stacked (gap 32), the copy centred as on every final box, the list block full width with its text left.
   768: the list block is 520px wide and centred. 1024: copy left, list right (1.35fr | 1fr, gap 56), all text left.
   Tokens are dark inside .final in both themes, so the one hard-coded fill here (white 4%) is safe in both. */

/* The box's two blobs (site.css final-drift) loop without end; here they rest in place, as in the hero (part 01), so
   nothing on the page moves for longer than 5s (WCAG 2.2.2). The glow, the symbol and the parallax stay. */
.ve-final .final__blob { animation: none; }
.ve-final__grid { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); gap: 32px; }
.ve-final .sf-h1 { margin-top: 14px; }

/* What we'll talk through first: a quiet glass block on the box. */
.ve-final__next { padding: 24px; border: 1px solid var(--sf-border); border-radius: var(--sf-radius-md); background: rgba(255, 255, 255, 0.04); text-align: left; }
.ve-final__list { gap: 0; margin: 12px 0 0; font-size: 1rem; line-height: 1.5; }
/* text-wrap: pretty keeps a lone word off the last line ("formats you / need" at 390). */
.ve-final__list li { padding: 10px 0; text-wrap: pretty; }
.ve-final__list li + li { border-top: 1px dashed var(--sf-border); }
.ve-final__list .sf-icon { margin-top: 2px; }
.ve-final__note { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--sf-border); font-size: 0.875rem; line-height: 1.6; color: var(--sf-fg-muted); }
/* A static tag, so it is filled, not outlined (an outline means "press me"), like the same tag in the FAQ note.
   0,4,0: beats the light theme's hairline chip (0,3,0), which sarafi.css leaves on in the box (span chips :not(.final *)). */
.ve-final__note .sf-chip { min-height: 26px; margin-right: 6px; padding: 0 10px; font-size: 0.75rem; font-weight: var(--sf-fw-semibold); vertical-align: 1px; }
:root .ve-final .ve-final__note .sf-chip { border-color: transparent; background: var(--sf-hover); color: var(--sf-fg); }

@media (min-width: 768px) {
  .ve-final__next { width: 100%; max-width: 520px; margin-inline: auto; }
}
@media (min-width: 1024px) {
  .ve-final { text-align: left; }
  .ve-final__grid { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 56px; align-items: center; }
  /* The centred .final rules (site.css), set left inside this box only. */
  .ve-final .sf-h1 { margin-inline: 0; }
  .ve-final .sf-lead { margin: 20px 0 0; max-width: 34em; }
  .ve-final .sf-cluster { justify-content: flex-start; margin-top: 28px; }
  .ve-final__next { max-width: none; margin: 0; }
}

@media print {
  .ve-final__next { break-inside: avoid; }
}
