/**
 * forge-funnel-blocks.css — the shared BLOCK LIBRARY (proven, brand-adaptive).
 * Loaded after forge-funnel.css and before a funnel's own custom_css. Everything the
 * blocks in lib/funnel-blocks.ts need to look like the real funnels lives here, styled
 * ONCE and driven by --f-* brand variables. Promoted from the Sanionair build so every
 * funnel inherits the same tuned look. No review block (dropped by decision).
 * Plan: plans/2026-07-18-funnel-block-library-bulk-duplicate.md
 */

/* tighter, mobile-first column + top breathing room */
/* v15.3: this used to be `.f-funnel { max-width: 480px; padding: 30px 18px 24px }`,
   which is where the real width and rhythm lived — outside .f-page, so the Layout could
   never be full-bleed and its pad sliders had nothing to override. Split by role:
   the Layout owns the vertical rhythm (the pad classes further down override it), the
   Column owns the width and the side inset.
   v15.4: the split kept a hidden `30px 0 24px` default here, so with the Layout pad
   sliders at 0 the Column still sat 30px below the Layout's top edge (Jelle, 2026-09-01).
   The Layout carries NO padding of its own — Column top = Layout top; ALL vertical
   rhythm comes from the f-pt-*/f-pb-* classes the sliders set. */
.f-page { padding: 0; }
/* Part 9 (2026-09-15): stacked Layouts — a page with layout markers is `.f-page.f-multi`
   (a plain stack, no paint of its own) holding one `.f-sec` per Layout; the Column rules
   apply inside each. Placed BEFORE the f-pt-*/f-pb-* rules on purpose (same specificity,
   source order) so a section's own pads win. `.f-lay` is the inert marker element — it
   only ever renders when a page could not be sectioned, and then it must be invisible. */
.f-page.f-multi { padding: 0; background: none; }
.f-sec { padding: 0; }
.f-lay { display: none; }
/* v16.1: gutters calibrated to Perspective (comp video, 2026-09-02): their 375px card
   runs ~22px column gutters, and the FORM frame sits a further ~8px in with its fields
   nearly touching the frame. 18px wall-to-wall left no bare column to click, so the
   Layout was unreachable by mouse. */
.f-col { max-width: 480px; padding: 0 22px; }
/* Frame: pull in a little further and take a background of its own. Deliberately NO
   border and no shadow — those drew visible edges around the column on the served page,
   which is not what this does (Jelle, 2026-08-31). Narrower + a background, nothing else. */
.f-col-frame { margin-left: 10px; margin-right: 10px; padding: 0 14px; border-radius: 16px; }

/* ── v2 scale (Part 8, 2026-09-15): Perspective's exact Layout/Column geometry, on when
   funnels.settings.scale = 'v2' (`f-v2` on main.f-funnel). Scoped :where(.f-v2) so a
   clone's own stylesheet still wins by source order. Measured on Perspective's published
   pages (outputs/forge-funnels/perspective-layout-measurements-2026-09-15.md): Layout
   gutter 16 → Column box 358 @390 (radius 12, painted only with Frame) → framed inner
   padding 16 (<640) / 40 (≥640) → content 326; unframed padding 8 / 24, and on the
   phone only, media in an unframed column bleeds to the screen edge (square corners);
   column caps 448 / 576 (≥640) / 768 (≥768) / 896 (≥1024). */
:where(.f-v2) .f-page:not(.f-multi), :where(.f-v2) .f-sec { padding-left: 16px; padding-right: 16px; }
:where(.f-v2) .f-col { max-width: 448px; margin: 0 auto; padding: 0 8px; }
:where(.f-v2) .f-col-frame { margin-left: auto; margin-right: auto; padding: 0 16px; border-radius: 12px; }
@media (max-width: 639px) {
  :where(.f-v2) .f-col:not(.f-col-frame) > .f-media, :where(.f-v2) .f-col:not(.f-col-frame) > .f-media-hero, :where(.f-v2) .f-col:not(.f-col-frame) > .f-vsl { margin-left: -24px; margin-right: -24px; border-radius: 0; }
  :where(.f-v2) .f-col:not(.f-col-frame) > .f-media img, :where(.f-v2) .f-col:not(.f-col-frame) > .f-media-hero img { border-radius: 0; }
}
@media (min-width: 640px) {
  :where(.f-v2) .f-col { max-width: 576px; padding: 0 24px; }
  :where(.f-v2) .f-col-frame { padding: 0 40px; }
}
@media (min-width: 768px) { :where(.f-v2) .f-col { max-width: 768px; } }
@media (min-width: 1024px) { :where(.f-v2) .f-col { max-width: 896px; } }
/* ── Part 10 (2026-09-15): several Columns in one Layout — Perspective's row, measured on
   its published two-column page: a grid with gap 16, padding 16 (48 ≥1024), capped
   448 / 576 (≥640) and full width from 768, where the columns go side by side (2–4);
   below 768 they stack left-first. Columns are grid-stretched to equal height and
   their content sits in the vertical middle. The row IS the section's gutter, so a
   section holding a row carries none of its own. v2 only. */
:where(.f-v2) .f-sec:has(> .f-row) { padding-left: 0; padding-right: 0; }
:where(.f-v2) .f-row { display: grid; grid-template-columns: 1fr; gap: 16px; padding: 0 16px; max-width: 448px; margin: 0 auto; }
:where(.f-v2) .f-row > .f-col { max-width: none; margin: 0; display: flex; flex-direction: column; justify-content: center; }
@media (min-width: 640px) { :where(.f-v2) .f-row { max-width: 576px; } }
@media (min-width: 768px) {
  :where(.f-v2) .f-row { max-width: none; }
  :where(.f-v2) .f-row[data-cols="2"] { grid-template-columns: repeat(2, 1fr); }
  :where(.f-v2) .f-row[data-cols="3"] { grid-template-columns: repeat(3, 1fr); }
  :where(.f-v2) .f-row[data-cols="4"] { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 1024px) { :where(.f-v2) .f-row { padding: 0 48px; } }
.f-colbrk { display: none; }

/* headers — landing headline and question headers share the big size */
.f-h1 { text-align: center; font-weight: 800; font-size: 31px; line-height: 1.1; letter-spacing: -.01em; margin: 0 0 12px; }
.f-h2 { font-weight: 800; font-size: 31px; line-height: 1.1; letter-spacing: -.01em; margin: 0 0 8px; }
/* A wrapped headline arrives as several <p> ("Welk type bedrijf" / "heb je?"). They are
   one sentence, so they must not be spaced apart like separate paragraphs. */
.f-h1 > p, .f-h2 > p { margin: 0; }
.f-sub { margin: 0 0 6px; font-size: 14px; }

/* ── size modifiers: ONE ladder for every element (builder v2, re-scaled v14) ──
   S = 0.72x   M = the element's base (no rule)   L = 1.25x   XL = 1.5x

   Why a fixed ratio: before v14 each element had its own hand-picked numbers, so
   "L" meant +2px on a button (17 -> 18, invisible — Jelle: "doesn't do shit") but
   +7px on a heading, and `.f-size-s.f-h2` was 22px against a 21px base, i.e. S made
   an h2 BIGGER. With one multiplier, L looks like L everywhere and the chips can be
   trusted. M is always the untouched base, so every stored page renders unchanged.

     element              S     M(base)   L     XL
     .f-h1 / .f-h2        22      31      39    46
     .f-sub (text)        10      14      18    21
     .f-btn               12      17      21    26
     .f-answer            12      16      20    24
     .f-choice-lbl        13      16      23    27   (base rule is 16 — v14 comment said 18)
     .f-list li           11      15      19    23                                  */
.f-size-s.f-h1, .f-size-s.f-h2 { font-size: 22px; }
.f-size-l.f-h1, .f-size-l.f-h2 { font-size: 39px; }
.f-size-xl.f-h1, .f-size-xl.f-h2 { font-size: 46px; }
.f-sub.f-size-s { font-size: 10px; }
.f-sub.f-size-l { font-size: 18px; }
.f-sub.f-size-xl { font-size: 21px; }

/* funnel header — the client logo band (builder v2; Perspective's Header element)
   v16: the logo ladder rescaled against Perspective's (their M rendered visibly larger
   than our XL with the same logo file — Jelle's header.mp4, 2026-09-01), and the width
   cap relaxed so a wide wordmark can actually reach its height. f-hd-l / f-hd-r align
   the logo inside the band (Header panel); absent = centred, byte-identical. */
.f-header { display: flex; justify-content: center; align-items: center; padding: 14px 16px 2px; }
.f-header.f-hd-l { justify-content: flex-start; }
.f-header.f-hd-r { justify-content: flex-end; }
.f-header img { display: block; max-height: 44px; max-width: 78%; width: auto; height: auto; }
.f-header.f-logo-s img { max-height: 30px; }
.f-header.f-logo-l img { max-height: 58px; }
.f-header.f-logo-xl img { max-height: 74px; }
.f-hint { color: #5a5f66; }
.f-hint .arw { color: #e8830c; font-weight: 700; }

/* hero image — fixed band, faces framed (imgix crop set on the URL by the builder) */
.f-media-hero { margin: 12px 0; }
.f-media-hero img { border-radius: 14px; width: 100%; height: auto; display: block; }

/* text answer bars */
.f-answers { display: grid; gap: 11px; margin-top: 14px; }
.f-answer { display: block; width: 100%; text-align: left; padding: 16px 18px; border: 0; border-radius: 9px;
  background: var(--f-accent, #059669); color: var(--f-accent-fg, #fff); font: inherit; font-size: 16px; font-weight: 700; cursor: pointer; }
.f-answer:active { transform: scale(.99); }
/* v14: the Answer panel's S/M/L/XL + B/I/U finally render (they used to patch the
   BLOCK, and no per-answer size CSS existed at all). Same ladder as everything else. */
.f-answer.f-size-s { font-size: 12px; }
.f-answer.f-size-l { font-size: 20px; }
.f-answer.f-size-xl { font-size: 24px; }
.f-choice-card.f-size-s .f-choice-lbl { font-size: 13px; }
.f-choice-card.f-size-l .f-choice-lbl { font-size: 23px; }
.f-choice-card.f-size-xl .f-choice-lbl { font-size: 27px; }

/* icon answer-cards (the Ja/Nee squares) — icon centered, label bottom-centered */
/* v15: matched to Perspective's cards — the icon sits in the UPPER third with the label
   under it (was: icon dead-centre, label absolutely pinned to the bottom), and the card
   is shorter. The narrower look comes from the Column's side padding, not from here. */
/* v15.1: proportions estimated off Perspective's own builder (Jelle's screen recording,
   2026-08-31): card 147x168 CSS px inside a 310px column, 16px gutter — i.e. clearly
   PORTRAIT, where ours were squat and wide. Expressed as an aspect-ratio so the shape
   survives any column width, with a min-height floor for very narrow columns.
   The icon sits a third down and the label is pinned to the bottom (space-between).
   v17 (Part 7, 2026-09-15): the v1 rules below are kept byte-for-byte for every v1
   funnel and clone; Perspective's REAL card structure (measured on its live page: a 4:3
   image zone with a 64px icon + a 16px-padded label zone that grows with the text) is
   the v2 block further down. */
.f-choice-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 14px 0; }
.f-choice-card { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  aspect-ratio: 147 / 168; min-height: 140px; gap: 8px; padding: 30px 12px 20px;
  background: var(--f-accent, #059669); color: var(--f-accent-fg, #fff); border: 0; border-radius: 12px; cursor: pointer; font: inherit; font-weight: 700; }
.f-choice-card:active { transform: scale(.99); }
.f-choice-ic { width: 50px; height: 50px; flex: none; }
.f-choice-lbl { text-align: center; font-size: 16px; line-height: 1.2; }

/* ── Part 7 (2026-09-15): quiz cards at Perspective's dimensions, v2 only. Measured on
   Perspective's live page at 390 (outputs/forge-funnels/perspective-debug-2026-09-15,
   scripts/scratch/_psp-measure3/4-tmp.ts): grid 326 wide, gap 16, 24px above; card
   155 × 168.25, radius 8, accent bg, overflow hidden; a 4:3 top zone (155 × 116) with a
   64px icon centred; a label zone padded 16px that grows with the text (52 for one line,
   72 for two); label 16px / 20px, 700. The top row is the card's own width × 3/4 —
   (100cqw − 16px) / 2 × 3/4 — so the shape holds at every column width; the label
   row is content-driven so a two-line answer never overflows. The ONE column is
   minmax(0, 1fr) with justify-content normal: the v1 rule's space-between would otherwise
   shrink the implicit column to the icon's 64px and park it at the left edge (Jelle,
   2026-09-15: the icon and Ja/Nee sat left instead of centred). */
:where(.f-v2) .f-choice-grid { gap: 16px; margin: 24px 0 0; container-type: inline-size; }
:where(.f-v2) .f-choice-card { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: calc((100cqw - 16px) * .375) auto; align-items: center; justify-items: center; justify-content: normal;
  height: auto; min-height: 0; aspect-ratio: auto; padding: 0; gap: 0; border-radius: 8px; overflow: hidden; }
@supports not (width: 1cqw) {
  :where(.f-v2) .f-choice-card { grid-template-rows: auto auto; }
  :where(.f-v2) .f-choice-ic { margin: 26px 0; }
}
:where(.f-v2) .f-choice-ic { width: 64px; height: 64px; align-self: center; justify-self: center; }
:where(.f-v2) .f-choice-lbl { padding: 16px; align-self: center; font-size: 16px; line-height: 1.25; }

/* ── Part 5 (2026-09-15): Perspective's type scale, v2 only — measured on its live page at
   390 (scripts/scratch/_psp-measure2/3-tmp.ts): S 16/24 · M 20/25 · L 24/30 · XL 30/34.5
   with -0.02em, weight 700 for titles. ONE ladder for the panel chips, the toolbar's size
   spans and a block's custom px: the chip rules set the block; the ATTRIBUTE rules at the
   end key on the canonical `font-size:Npx` string the sanitizer and styleOf both emit, so
   an inline span never inherits a px line-height meant for another size (that was the
   overlap trap). Legacy titles (.f-h1/.f-h2) keep a ladder above Huge so an existing L
   title does not shrink: S 24/30 · M 30/34.5 · L 40/46 · XL 48/55. A composite question
   title and a form title default to L (Perspective's measured quiz title). */
:where(.f-v2) .f-sub { font-size: 20px; line-height: 25px; }
:where(.f-v2) .f-sub.f-size-s { font-size: 16px; line-height: 24px; }
:where(.f-v2) .f-sub.f-size-l { font-size: 24px; line-height: 30px; }
:where(.f-v2) .f-sub.f-size-xl { font-size: 30px; line-height: 34.5px; letter-spacing: -0.02em; }
:where(.f-v2) .f-hint { font-size: 16px; line-height: 24px; }
:where(.f-v2) .f-h1, :where(.f-v2) .f-h2 { font-size: 30px; line-height: 34.5px; letter-spacing: -0.02em; font-weight: 700; }
:where(.f-v2) .f-quiz .f-h2, :where(.f-v2) .f-form .f-h2, :where(.f-v2) [data-qtitle] { font-size: 24px; line-height: 30px; letter-spacing: normal; }
:where(.f-v2) .f-size-s.f-h1, :where(.f-v2) .f-size-s.f-h2 { font-size: 24px; line-height: 30px; letter-spacing: normal; }
:where(.f-v2) .f-size-l.f-h1, :where(.f-v2) .f-size-l.f-h2 { font-size: 40px; line-height: 46px; }
:where(.f-v2) .f-size-xl.f-h1, :where(.f-v2) .f-size-xl.f-h2 { font-size: 48px; line-height: 55px; }
/* the size in the html decides: toolbar spans, block custom px, and the toolbar's More
   sizes. [style][style*=…] = (0,2,0), so on the same element it beats a chip rule above. */
:where(.f-v2) [style][style*="font-size:14px"] { line-height: 21px; letter-spacing: normal; }
:where(.f-v2) [style][style*="font-size:16px"] { line-height: 24px; letter-spacing: normal; }
:where(.f-v2) [style][style*="font-size:18px"] { line-height: 24px; letter-spacing: normal; }
:where(.f-v2) [style][style*="font-size:20px"] { line-height: 25px; letter-spacing: normal; }
:where(.f-v2) [style][style*="font-size:24px"] { line-height: 30px; letter-spacing: normal; }
:where(.f-v2) [style][style*="font-size:30px"] { line-height: 34.5px; letter-spacing: -0.02em; }
:where(.f-v2) [style][style*="font-size:40px"] { line-height: 46px; letter-spacing: -0.02em; }
:where(.f-v2) [style][style*="font-size:48px"] { line-height: 55px; letter-spacing: -0.02em; }
:where(.f-v2) [style][style*="font-size:64px"] { line-height: 74px; letter-spacing: -0.02em; }

/* v15: the Quiz/Choice composite wrapper — ONE selectable frame in the builder. No
   styling of its own on purpose: the page must render exactly as it did before. */
.f-quiz { display: block; }

/* image answer cards */
.f-answer-media { padding: 0; overflow: hidden; flex-direction: column; align-items: stretch; text-align: center; }
.f-answer-media img { width: 100%; height: 118px; object-fit: cover; display: block; }
.f-answer-media span { padding: 12px 14px; }

/* form fields with a left icon + optional verified badge */
/* v16 calibration vs Perspective side-by-side (Jelle, 2026-09-01): their placeholders
   and field icons render a touch larger — 17px text, 19px emoji, same field height. */
.f-field2 { position: relative; display: flex; align-items: center; background: #fff; border: 1px solid #e6e8ec; border-radius: 12px; padding: 0 14px; margin-bottom: 10px; }
.f-field2 .ic { font-size: 19px; margin-right: 11px; }
/* The field is always white, so its text reads the white-card ink on a dark brand (--f-card-fg, set only
   there): with the brand's own light text it was white on white (MEC Decor / Eco Diamond, 2026-10-21). */
.f-field2 input, .f-field2 select { flex: 1; border: 0; outline: 0; background: transparent; font: inherit; font-size: 17px; padding: 15px 0; color: var(--f-card-fg, var(--f-fg, #111827)); }
.f-field2 input::placeholder { color: #9aa0a6; }

/* SVG leading icon (builder v3) — absolutely positioned; the field pads left for it */
.f-field2.f-field-ico { padding-left: 42px; }
.f-field2 .f-ico { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); display: flex; color: #9ca3af; pointer-events: none; }
.f-field2 .f-ico svg { width: 19px; height: 19px; display: block; }

/* Inputs can NEVER overflow the phone: everything border-boxed and shrinkable.
   Covers both the block-compiled fields (.f-field2) and cloner/legacy markup (.f-input). */
.f-form, .f-field, .f-field2 { box-sizing: border-box; min-width: 0; max-width: 100%; }
.f-field2 { width: 100%; }
.f-field2 input, .f-field2 select { width: 100%; min-width: 0; box-sizing: border-box; }
.f-input { box-sizing: border-box; width: 100%; max-width: 100%; min-width: 0; }

/* CTA button */
.f-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; width: 100%; padding: 17px; border: 0; border-radius: 11px;
  background: var(--f-accent, #059669); color: var(--f-accent-fg, #fff); font: inherit; font-size: 17px; font-weight: 800; cursor: pointer; }
.f-btn[disabled] { opacity: .6; }

/* ── VSL (sales video) ─────────────────────────────────────────────────── */
.f-vsl { margin: 16px 0 18px; }
.f-vsl-box { position: relative; width: 100%; aspect-ratio: 16 / 9; border-radius: 14px; overflow: hidden;
  background: #000; box-shadow: 0 6px 24px rgba(0,0,0,.16); }
.f-vsl-box > video, .f-vsl-box > iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
.f-vsl-empty { display: flex; align-items: center; justify-content: center;
  background: repeating-linear-gradient(45deg, #14161a, #14161a 12px, #1b1e24 12px, #1b1e24 24px); }
.f-vsl-empty span { color: #fff; opacity: .72; font-size: 14px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.f-vsl-cap { margin: 9px 2px 0; font-size: 13.5px; opacity: .72; text-align: center; }
/* the sales player (lib/funnel-blocks.ts salesPlayer; behaviour in forge-funnel.js) — the website's HeroVideo */
.f-vsl-sales .f-vsl-box { user-select: none; -webkit-user-select: none; }
.f-vsl-sales video { object-fit: cover; cursor: pointer; }
.f-vsl-sales button { font: inherit; border: 0; cursor: pointer; padding: 0; }
.f-vsl-unmute { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(180deg, rgba(7,11,9,0) 40%, rgba(7,11,9,.45) 100%); }
.f-vsl-unmute > span { display: flex; align-items: center; gap: 14px; padding: 14px 20px; background: rgba(7,11,9,.86);
  border: 1px solid var(--f-accent, #23cf7c); box-shadow: 0 18px 40px -12px rgba(0,0,0,.8); }
.f-vsl-unmute i { width: 46px; height: 46px; border-radius: 999px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
  background: var(--f-accent, #23cf7c); color: var(--f-accent-fg, #04130b); animation: f-vsl-pulse 1.8s ease-out infinite; }
.f-vsl-unmute b { text-align: left; color: #f4faf6; font-weight: 700; font-size: 17px; line-height: 1.2; letter-spacing: -.01em; }
@keyframes f-vsl-pulse { 0% { box-shadow: 0 0 0 0 rgba(35,207,124,.55); } 100% { box-shadow: 0 0 0 16px rgba(35,207,124,0); } }
.f-vsl-play { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 84px; height: 84px; border-radius: 999px;
  display: none; align-items: center; justify-content: center; background: var(--f-accent, #23cf7c); color: var(--f-accent-fg, #04130b);
  box-shadow: 0 12px 40px -6px rgba(0,0,0,.45); }
.f-vsl-ctl { position: absolute; right: 10px; bottom: 12px; display: none; gap: 6px; }
.f-vsl-ctl button { width: 34px; height: 34px; display: flex; align-items: center; justify-content: center; background: rgba(7,11,9,.65); color: #fff; }
.f-vsl-snd .on { display: none; }
.f-vsl-box[data-sound="on"] .f-vsl-snd .on { display: flex; }
.f-vsl-box[data-sound="on"] .f-vsl-snd .off { display: none; }
.f-vsl-snd svg { width: 17px; height: 17px; }
.f-vsl-bar { position: absolute; left: 0; right: 0; bottom: 0; height: 4px; background: rgba(255,255,255,.15); display: none; }
.f-vsl-bar i { display: block; height: 100%; width: 0; background: var(--f-accent, #23cf7c); transition: width 250ms linear; }
.f-vsl-box[data-mode="watching"] .f-vsl-unmute, .f-vsl-box[data-mode="ended"] .f-vsl-unmute { display: none; }
.f-vsl-box[data-mode="watching"] .f-vsl-ctl, .f-vsl-box[data-mode="watching"] .f-vsl-bar { display: flex; }
.f-vsl-box[data-mode="watching"][data-paused="1"] .f-vsl-play, .f-vsl-box[data-mode="ended"] .f-vsl-play { display: flex; }
@media (prefers-reduced-motion: reduce) { .f-vsl-unmute i { animation: none; } }

/* ── proof / case-study rows ───────────────────────────────────────────── */
.f-proof { list-style: none; margin: 14px 0 18px; padding: 0; display: grid; gap: 9px; }
.f-proof-row { display: flex; flex-direction: column; gap: 2px; padding: 13px 15px; border-radius: 12px;
  background: rgba(127,127,127,.09); border-left: 3px solid var(--f-accent, #059669); }
.f-proof-t { font-size: 14.5px; font-weight: 800; }
.f-proof-b { font-size: 13.5px; opacity: .82; line-height: 1.45; }

/* ── eyebrow ───────────────────────────────────────────────────────────── */
.f-eyebrow { text-align: center; font-size: 12.5px; font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; opacity: .62; margin-bottom: 10px; }

/* ── hold / loader (auto-advancing step) ───────────────────────────────── */
.f-hold { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 26px 0 8px; }
.f-hold-spin { width: 46px; height: 46px; border-radius: 50%; border: 4px solid rgba(127,127,127,.22);
  border-top-color: var(--f-accent, #059669); animation: f-spin .9s linear infinite; }
@keyframes f-spin { to { transform: rotate(360deg); } }
.f-hold-cap { font-size: 13.5px; opacity: .72; text-align: center; margin: 0; }
/* v16: optional text above + a chosen icon instead of the spinner */
.f-hold-title { font-size: 19px; font-weight: 700; line-height: 1.25; text-align: center; margin: 0; }
.f-hold-title > p { margin: 0; }
.f-hold-ic { color: var(--f-accent, #059669); }
.f-hold-ic svg { width: 46px; height: 46px; display: block; }
@media (prefers-reduced-motion: reduce) { .f-hold-spin { animation-duration: 2.4s; } }

/* ── graphic (icon) block — builder v3, Perspective's icon element ─────── */
.f-graphic { display: flex; justify-content: center; margin: 14px 0; color: var(--f-accent, #059669); }
.f-graphic svg { width: 44px; height: 44px; display: block; }
.f-graphic-xs svg { width: 20px; height: 20px; }
.f-graphic-s svg { width: 30px; height: 30px; }
.f-graphic-l svg { width: 60px; height: 60px; }
.f-graphic-xl svg { width: 80px; height: 80px; }

/* ── builder v4 — optional per-element styling utilities ───────────────── */
/* Emitted ONLY when a block explicitly sets align/padTop/padBottom (funnel-page-blocks.ts). */
.f-al-l { text-align: left; }
.f-al-c { text-align: center; }
.f-al-r { text-align: right; }
/* the graphic block is a flex row — text-align does nothing there, justify does */
.f-graphic.f-al-l { justify-content: flex-start; }
.f-graphic.f-al-r { justify-content: flex-end; }
.f-pt-0 { padding-top: 0; }
.f-pt-1 { padding-top: 8px; }
.f-pt-2 { padding-top: 16px; }
.f-pt-3 { padding-top: 28px; }
.f-pt-4 { padding-top: 44px; }
.f-pb-0 { padding-bottom: 0; }
.f-pb-1 { padding-bottom: 8px; }
.f-pb-2 { padding-bottom: 16px; }
.f-pb-3 { padding-bottom: 28px; }
.f-pb-4 { padding-bottom: 44px; }

/* ── Tablet & desktop (2026-09-30) — a block's own values on a wider screen ─────────────
   Perspective gives every element a phone, tablet (≥640) and desktop (≥768) value. The
   compiler (funnel-page-blocks.ts deviceOf) puts a class per overridden property on the
   block plus the value as a custom property (--t-fs:36px, --d-row:4 …); these rules read
   them. Mobile-first: a tablet value carries on up to desktop unless desktop has its own.
   !important because the value is the author's explicit choice for that screen and must
   beat inline selection sizes and a clone's own stylesheet. Text rules reach the spans in
   the block's MAIN size (.f-dsz, marked by the compiler) and answer labels — a smaller line
   inside the same text keeps its own size, like a separate element in Perspective.
   Space above is the block's WHOLE gap to the block before it (its own top margin is reset);
   a negative value pulls it up (margin). */
@media (min-width: 640px) {
  .f-t-fs, .f-t-fs .f-dsz, .f-t-fs .f-answer, .f-t-fs .f-answer > span { font-size: var(--t-fs) !important; }
  .f-t-lh, .f-t-lh .f-dsz, .f-t-lh .f-answer, .f-t-lh .f-answer > span { line-height: var(--t-lh) !important; }
  .f-t-ls, .f-t-ls .f-dsz, .f-t-ls .f-answer, .f-t-ls .f-answer > span { letter-spacing: var(--t-ls) !important; }
  .f-t-al-l { text-align: left !important; }
  .f-t-al-c { text-align: center !important; }
  .f-t-al-r { text-align: right !important; }
  .f-t-mw { max-width: var(--t-mw) !important; margin-left: auto !important; margin-right: auto !important; box-sizing: border-box; }
  .f-t-pt { padding-top: var(--t-pt) !important; margin-top: 0 !important; }
  .f-t-mt { margin-top: var(--t-mt) !important; }
  .f-t-pb { padding-bottom: var(--t-pb) !important; }
  .f-t-mb { margin-bottom: var(--t-mb) !important; }
  .f-t-hide { display: none !important; }
  .f-t-row { display: flex !important; flex-wrap: wrap; justify-content: center; column-gap: 16px; }
  .f-t-row > * { flex: 0 0 calc((100% - (var(--t-row) - 1) * 16px) / var(--t-row)) !important; max-width: calc((100% - (var(--t-row) - 1) * 16px) / var(--t-row)) !important; width: auto !important; min-width: 0; margin-left: 0 !important; margin-right: 0 !important; box-sizing: border-box; }
  :where(.f-v2) .f-t-row.f-choice-grid > .f-choice-card { grid-template-rows: calc((100cqw - (var(--t-row) - 1) * 16px) / var(--t-row) * .75) auto; }
  .f-t-fit { display: flex !important; width: fit-content !important; max-width: 100%; margin-left: auto !important; margin-right: auto !important; padding-left: 32px !important; padding-right: 32px !important; }
  .f-t-full { width: 100% !important; }
}
@media (min-width: 768px) {
  .f-d-fs, .f-d-fs .f-dsz, .f-d-fs .f-answer, .f-d-fs .f-answer > span { font-size: var(--d-fs) !important; }
  .f-d-lh, .f-d-lh .f-dsz, .f-d-lh .f-answer, .f-d-lh .f-answer > span { line-height: var(--d-lh) !important; }
  .f-d-ls, .f-d-ls .f-dsz, .f-d-ls .f-answer, .f-d-ls .f-answer > span { letter-spacing: var(--d-ls) !important; }
  .f-d-al-l { text-align: left !important; }
  .f-d-al-c { text-align: center !important; }
  .f-d-al-r { text-align: right !important; }
  .f-d-mw { max-width: var(--d-mw) !important; margin-left: auto !important; margin-right: auto !important; box-sizing: border-box; }
  .f-d-pt { padding-top: var(--d-pt) !important; margin-top: 0 !important; }
  .f-d-mt { margin-top: var(--d-mt) !important; }
  .f-d-pb { padding-bottom: var(--d-pb) !important; }
  .f-d-mb { margin-bottom: var(--d-mb) !important; }
  .f-d-hide { display: none !important; }
  .f-d-row { display: flex !important; flex-wrap: wrap; justify-content: center; column-gap: 16px; }
  .f-d-row > * { flex: 0 0 calc((100% - (var(--d-row) - 1) * 16px) / var(--d-row)) !important; max-width: calc((100% - (var(--d-row) - 1) * 16px) / var(--d-row)) !important; width: auto !important; min-width: 0; margin-left: 0 !important; margin-right: 0 !important; box-sizing: border-box; }
  :where(.f-v2) .f-d-row.f-choice-grid > .f-choice-card { grid-template-rows: calc((100cqw - (var(--d-row) - 1) * 16px) / var(--d-row) * .75) auto; }
  .f-d-fit { display: flex !important; width: fit-content !important; max-width: 100%; margin-left: auto !important; margin-right: auto !important; padding-left: 32px !important; padding-right: 32px !important; }
  .f-d-full { width: 100% !important; }
}

/* outline CTA variant (Perspective's Filled/Outline toggle) */
.f-btn.f-btn-outline { background: transparent; border: 2px solid var(--f-accent, #059669); color: var(--f-accent, #059669); }

/* ── builder v6 — button parity chips ──────────────────────────────────── */
/* Full-width OFF (Perspective's ↔ toggle): auto-width pill. The button is a block
   ROOT with no wrapper element, so parent text-align is not available — centering is
   done on the button itself: flex + fit-content + auto margins (documented choice). */
.f-btn.f-btn-fit { display: flex; width: fit-content; max-width: 100%; margin-left: auto; margin-right: auto; padding-left: 34px; padding-right: 34px; }
/* ── builder v8 — Button size chips (S/M/L/XL on CTA + form submit) ──────── */
.f-btn.f-size-s { padding: 12px; font-size: 12px; }
.f-btn.f-size-l { padding: 21px; font-size: 21px; }
.f-btn.f-size-xl { padding: 25px; font-size: 26px; }
.f-btn.f-btn-fit.f-size-s { padding-left: 26px; padding-right: 26px; }
.f-btn.f-btn-fit.f-size-l { padding-left: 40px; padding-right: 40px; }
.f-btn.f-btn-fit.f-size-xl { padding-left: 46px; padding-right: 46px; }
/* Align on a fit (auto-width) button re-anchors the pill instead of the label. */
.f-btn.f-btn-fit.f-al-l { margin-left: 0; }
.f-btn.f-btn-fit.f-al-r { margin-right: 0; }

/* Animation chip: subtle attention pulse (1 → 1.03), motion-safe. */
/* v16: Perspective's pulse is a HEARTBEAT — two quick beats, then rest — not a slow
   sine breath (Jelle, 2026-09-01). */
@keyframes f-btn-pulse {
  0%, 28%, 100% { transform: scale(1); }
  7% { transform: scale(1.05); }
  14% { transform: scale(1); }
  21% { transform: scale(1.04); }
}
.f-btn.f-btn-pulse { animation: f-btn-pulse 2.2s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .f-btn.f-btn-pulse { animation: none; } }
/* [data-merge] spans are deliberately UNSTYLED here — on a live page the runtime
   replaces their text with the visitor's answer; the pill look is editor-only. */

/* footer element — muted centered links band (Privacy / Imprint) */
.f-footer { text-align: center; padding: 26px 0 18px; }
.f-footer a { color: inherit; opacity: .6; font-size: 12.5px; text-decoration: underline; margin: 0 8px; }

/* list bullets as inline SVG icons (v4 list.icon) — suppress the CSS ✓, size the svg */
.f-list-ico li::before { content: none; }
/* v14: same ladder on list lines (base 15px lives in forge-funnel.css). */
.f-list.f-size-s li { font-size: 11px; }
.f-list.f-size-l li { font-size: 19px; }
.f-list.f-size-xl li { font-size: 23px; }
.f-li-ic { display: flex; flex: none; color: var(--f-accent, #059669); }
.f-li-ic svg { width: 18px; height: 18px; display: block; }
.f-li-accent .f-li-ic { color: var(--f-accent, #059669); }
.f-li-fg .f-li-ic { color: var(--f-fg, #111827); }
.f-li-muted .f-li-ic { color: #9ca3af; }

/* Forge booking calendar block (OLS Part 1): the loader swaps the placeholder for the widget iframe. */
.f-booking { margin: 14px 0; width: 100%; }
.f-booking-ph { padding: 28px 0; text-align: center; color: #9ca3af; font-size: 14px; }
.f-booking iframe { width: 100%; border: 0; display: block; }

/* Time of day question (plan 2026-09-22-day-part-question-block): the question line and
   2–3 stacked buttons above an Appointment 2.0 block. A tap fills the button with the
   accent (aria-pressed) and the runtime renders the widget below with that window. */
.f-daypart { margin: 14px 0; }
.f-daypart-q { font-size: 18px; font-weight: 700; line-height: 1.25; text-align: center; margin: 0 0 12px; }
.f-daypart-btns { display: flex; flex-direction: column; gap: 10px; }
.f-daypart-btn { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; width: 100%; padding: 15px 18px;
  background: #fff; color: var(--f-accent, #059669); border: 2px solid var(--f-accent, #059669); border-radius: 12px; cursor: pointer; font: inherit; text-align: left; }
.f-daypart-btn:active { transform: scale(.99); }
.f-daypart-btn[aria-pressed="true"] { background: var(--f-accent, #059669); color: var(--f-accent-fg, #fff); }
.f-daypart-lbl { font-size: 17px; font-weight: 800; }
.f-daypart-hrs { font-size: 14px; font-weight: 600; opacity: .8; white-space: nowrap; }
/* The widget waits for the tap: nothing (not even the placeholder) shows before it. */
.f-booking[data-await-part]:not([data-from]) { display: none; }
