/* ████████████████████████████████████████████████████████████████████████████████████████████████████████████
   READ THIS FIRST — THIS FILE IS v20 "TYPESET" (2026-08-17).

   It is v19 "GOLDEN HOUR / PORCELAIN" in full, with the TYPESET section appended at the end. v19 is kept
   whole and is NOT commented out: it carries the structural vocabulary (bands, the dashed motif, the flow
   device, the nav's two declared states) and a run of hard-won contrast fixes, and deleting the parts TYPESET
   overrides would strand every one of those fixes on a selector nobody could find again. Later rules of equal
   specificity win on order, so the appended section is the effective answer wherever the two disagree.

   WHAT THAT MEANS WHEN YOU READ DOWNWARDS: the colour, typeface, radius and elevation values in v19's own
   sections below are HISTORY. The live values are at the bottom, under "v20 · TYPESET". If you change one,
   change it there. The v19 prose is preserved because it explains WHY each token exists and what breaks if
   it moves — `--cream` being the sharpest example — and that reasoning survives the re-skin even where the
   value does not.
   ████████████████████████████████████████████████████████████████████████████████████████████████████████████ */

/* ════════════════════════════════════════════════════════════════════════════════════════════════════════════
   Hermoso — marketing design system · v19 "GOLDEN HOUR", re-tempered to PORCELAIN 2026-08-06
   ⚠ SUPERSEDED BY THE v20 · TYPESET SECTION AT THE END OF THIS FILE — see the banner above.
   Reference: Getharvest (styles.refero.design/style/1eee9aa2-1e23-4675-9f6e-fb98c93969bd), read live 2026-08-05.
   Their sentence, verbatim: "Golden hour workbench — warm cream canvas, white floating cards, and one vivid
   orange flame." That is the whole brief — a warm canvas (never #ffffff), white cards that float on it
   by shadow rather than by contrast, 16px/20px soft radii, and one vivid orange that carries every CTA, link
   and active state.

   ══ PORCELAIN — THE NEUTRAL RAMP IS NO LONGER PARCHMENT (2026-08-06) ═══════════════════════════════════════
   Dave, on this page and on the app's Connectors screen the same morning: "i dont love this background
   yellowish color … i think the orange/brownish hues are what im not liking, it looks like old faded paper."

   The GOLDEN HOUR *structure* is untouched and still right — warm canvas, white cards floating on shadow, one
   flame. What is wrong is the TEMPERATURE of the neutrals, and it is measurable. "Aged paper" in a near-white
   is the signature G-B > R-G: blue falls away while green holds, which is the definition of yellow. The old
   chip #f7ecdd was R-G 11 / G-B 15 at OKLCh hue 76°, and --bg-2 / --line / --hair were the same shape.

   THE TRANSFORM, in OKLCh: HOLD L · C × 0.55 · h → 48°. Holding L means contrast is a pure function of
   luminance, so every ratio quoted in this file survives to within ±0.05 — a re-skin is exactly when controls
   go invisible, and this one structurally cannot move a ratio (tools/interactive-contrast-check.mjs measures
   it on painted pixels rather than trusting this paragraph). 48° is chosen, not arbitrary: the flame itself is
   OKLCh h=41°, so the neutrals become a heavily desaturated TINT OF THE BRAND rather than an unrelated beige —
   ddna's "a single temperature of pigment" (refero, warm museum vitrine on raw linen: Linen Cream #efe3dc
   h53, Warm Sand #dacabf h57). Chroma halves rather than vanishing, so the result is porcelain/plaster, not
   grey: Bang & Olufsen's canvas is literally #ffffff and Poly's #f4f4f4 is achromatic, and both were rejected
   as the sterile end of the same axis, which is the half of the brief that says "warm, not white".

   THE ATMOSPHERE MOVED WITH IT, and it had to. The marigold wash #fee3b5 is hue 81° — a butter yellow — and
   at full-bleed hero scale it IS a "background yellowish colour" no token change would have fixed. It and the
   amber card glow rotate to the flame's own hue at reduced chroma (peach #ffdecd / rgba(237,167,137)), and
   the sepia elevation shadows rgba(146,94,20) / rgba(120,78,20) — a tea stain under every card — become warm
   stone at identical alphas, so elevation strength is byte-for-byte what it was.

   WHAT IS DELIBERATELY UNTOUCHED: --coral / --cta / --ember / --coral-line and every radius, type and spacing
   value. The complaint was the background family; the flame is settled ([[cta-green-not-coral]]) and gets
   HOTTER for free, because a quieter canvas is what a single accent needs. --coral-text is the one accent
   that moved, and only by one step (#bb4600 → #b84400): it measured 4.49 on the new deepest chip and had
   already been sitting on the 4.5 line at 4.51 before this pass — a token that passes by rounding is a defect
   waiting for the next re-skin.

   WHY THIS REPLACES v18 "DARKROOM". v18 was ORYZO — a warm near-black canvas — and Dave's verdict was "It's
   so dark, and I don't love all the brown." The pass before it (Apple España) failed the opposite way:
   near-monochrome, "it doesn't look like you redesigned the website at all." Getharvest sits between them by
   construction: it KEEPS the warmth of the darkroom and DROPS the darkness, and cream + white + a hot orange
   cannot be mistaken for an un-redesigned page.

   WHY THIS IS STILL A LAYER AND NOT A REWRITE. The site ships FOUR generation stylesheets — site.v12 (404),
   v13 (128 blog pages), v15 (271 landers/pricing/tools/mcp) and v17 (the 32 homepages) — and all four declare
   the SAME :root token names. One file appended after whichever version a page already loads re-skins all 446
   pages at once. v18 proved the mechanism; this file inherits it, keeps its section order, and changes values
   rather than structure. The type scale, spacing, dashed-rule motif and the flow/console/video devices are
   untouched.

   THE ONE STRUCTURAL INVERSION, and it is deliberate: v18 zeroed elevation (`--el-1: none`) because ORYZO
   rejects shadows and builds depth from a luminance step. Getharvest is the opposite and says so — their
   feature card is "fill #fff8f1, same as canvas — depth comes from shadow not contrast", with a warm
   rgba(250,166,0,.25) glow — THEIR values, quoted, and deliberately left at their originals here even though
   ours have since moved (a vendor quotation rewritten to our numbers stops being evidence of anything).
   A white card on cream is a 1.05:1 step, so on THIS system the shadow is not
   decoration, it IS the card boundary. Elevation comes back, warm-tinted, and their "never use cool
   blue-tinted shadows" rule is why every shadow here carries an amber hue instead of grey.

   WHAT WAS DELIBERATELY NOT TAKEN FROM GETHARVEST — each a documented refusal, not an omission:
     · Their brand LINK colour, #fa5d00 on cream. MEASURED at 3.01:1 — it fails AA for body text on their own
       canvas. Links here take --coral-text #b84400 (5.16:1), the same hue deepened. The vivid flame is kept
       for FILLS and large display moments, where 3:1 is the right floor.
     · Their CTA spec, which CONTRADICTS ITSELF: the Components section says "Fill #fa5d00, Text #ffffff"
       (3.17:1 — under AA for the 16px/600 label they specify) while their Agent Prompt Guide says
       "#fa5d00 background, #1d1e1c text" (5.28:1). We take the ink, i.e. the half of their own doc that is
       accessible.
     · Their input border "Bone" #c0bbb6 — 1.81:1, far under the 3:1 WCAG 1.4.11 asks of a control outline.
       --line-2 is #8e8784 instead.
     · MuotoWeb + Monarch. We keep Fraunces + Hanken Grotesk: they are self-hosted, already preloaded, and a
       new font host would need a CSP change. Their TRACKING rule is adopted (positive 0.015em on UI text,
       which is the opposite of the negative display tracking v17 shipped).
     · Their "one peach card per page" scarcity rule for the marigold wash is kept in spirit — the wash is
       atmosphere here and never a text surface, because ink is the only thing readable on it.
     · Uppercase. NOT extended, exactly as in v18: we ship 32 locales, and uppercasing breaks Greek
       final-sigma and Turkish dotted/dotless i, is meaningless in ja/zh/ko/th, and inflates German ~30%.
       Uppercase survives ONLY where it already lived — mono eyebrows, plaques, labels, the film slate.

   EVERY RATIO BELOW IS COMPUTED (WCAG 2.x), against the WORST surface each token actually lands on, and the
   light mid-tones are where this palette fails if you trust the reference: three of Getharvest's own published
   neutrals (Ash #777571, Driftwood #8e8b87, Bone #c0bbb6) do not reach AA on their own cream.
   ═══════════════════════════════════════════════════════════════════════════════════════════════════════════ */

:root{
  /* ── the surface stack. Getharvest's own is only two deep (cream canvas, white card) because a marketing
        page has no dense chrome; a lander has cards inside bands inside a page, so this keeps v18's four
        steps and re-points them upward. Each is one small WARM step — the hue never leaves the cream family. */
  --bg:        #fdf8f6;   /* Porcelain Canvas — Getharvest cream, de-yellowed (was #fff8f1). "the warmth IS the system identity", and it survives the rotation. NEVER #fff. */
  --bg-2:      #faf1ec;   /* the alternating band — one step down the porcelain ramp. */
  --surface:   #ffffff;   /* Paper White — Getharvest exact. The card that floats. */
  --surface-2: #fcf6f3;   /* card hover / inset. */
  --surface-3: #f5ebe6;   /* chips, filled controls, the deepest step. */
  --ink-well:  #ffffff;   /* v13/v15 alias for a card fill. */

  /* ── hairlines. The DASHED motif is v18's and it survives the inversion intact — it is the one structural
        move that stops a page reading as a generic SaaS template, and it reads on cream exactly as it read on
        walnut. Only the hue moves. --driftwood is the line that has to READ (3.34:1, over the 1.4.11 floor). */
  --line:      #e9dfda;   /* the quiet dashed edge. Decorative — always paired with a step or a shadow. */
  --line-2:    #8e8784;   /* a control's own edge, and any line that must be SEEN: 3.35:1 on the canvas. */
  --hair:      #f2e9e4;   /* barely-there. */
  --hairline:  #e9dfda;   /* v15 alias — .ui-frame/.tease/.mcpw name this one. */
  --cork:      #e9dfda;
  --driftwood: #8e8784;   /* STRUCTURAL ONLY: dividers, diagram strokes. NOT TEXT (Getharvest's own #8e8b87
                             measures 3.22:1 on cream and would fail as body copy). */

  /* ── ink. Ratios quoted against the four surfaces above, worst last:
           --text   15.90 / 15.05 / 16.74 / 14.34   (canvas / band / card / deepest chip)
           --muted   8.01 /  7.59 /  8.43 /  7.22
           --faint   5.04 /  4.77 /  5.30 /  4.54   ← the worst pair on the site, and still AA at any size. */
  --text:   #1d1e1c;   /* Ink Black — Getharvest exact. Warm near-black, never #000. */
  --muted:  #4f4d49;
  --faint:  #6e6b67;
  --ink:    #1d1e1c;   /* v15 alias. */
  --cream:  #1d1e1c;   /* STILL INVERTED, and for the same reason v18 inverted it: in v13/v15/v17 --cream meant
                          "the ink that sits ON a filled accent control". On the flame that ink is Ink Black
                          (5.28:1); white on the same fill is 3.17:1 and misses. Every rule that says
                          color:var(--cream) keeps working and comes out correct. */

  /* ── THE ACCENT. Getharvest: "Use #fa5d00 exclusively for primary actions, active states, and brand moments
        — never for body text", and "don't introduce a second accent colour — the system's discipline is one
        orange against warm neutrals." That is a stricter rule than ORYZO's and it is followed literally: the
        flame is the ONLY chromatic decision on the page.
        THE SPLIT IS A MEASUREMENT, not a preference. The flame is 3.01:1 on cream — correct for a FILL or a
        large display word (3:1 floor for a UI object / large text), wrong for a 16px link (4.5). So:
           --coral       #fa5d00  fills, active surfaces, display emphasis, the bloom
           --coral-text  #b84400  links and any text under 24px — 5.00 / 4.73 / 5.26 / 4.51
           --coral-line  #d24e00  focus rings and strokes — 3.73:1 at worst, with margin for the wash */
  --coral:       #fa5d00;
  --coral-text:  #b84400;
  --coral-line:  #d24e00;
  --coral-hot:   #d24e00;   /* hover on a text link — deeper, not lighter, because the page is light now. */
  --coral-deep:  #a33d00;   /* pressed. */
  --coral-solid: #fa5d00;   /* fill, when a fill is genuinely the flame (the "most popular" tag). */
  --ember:       #fa5d00;
  --marigold:    #ffdecd;   /* Marigold Glow, rotated off butter-yellow to the flame's hue. ATMOSPHERIC ONLY, never a text surface. */
  --plum:        #7a4d63;
  --gold:        #8a5a00;

  /* ── THE PRIMARY CTA, AND THE DIVERGENCE THAT JUST DISAPPEARED.
        v18 had to make the site's CTA CREAM, because ORYZO's rule is that the accent never touches a button
        and their own Bark-Brown fill measured 1.35:1 on the walnut canvas. That forced the site and the app
        to disagree about what a primary button looks like, and v18 called the divergence out as a compromise.
        Getharvest's accent IS the button — their primary CTA is a filled flame pill — so the compromise is
        gone and both surfaces now say the same thing: a flame fill with Ink Black on it, 5.28:1.
        This does not reopen [[cta-green-not-coral]]. That rule settled MEANING — green = go, red =
        destructive, coral/orange = BRAND — and Dave chose "the CTA is the brand colour" on 2026-07-25. The
        brand colour moved; the CTA follows it. The site has no destructive actions to stay distinct from. */
  --cta:      #fa5d00;
  --cta-hot:  #e05300;
  --cta-ink:  #1d1e1c;

  /* ELEVATION IS BACK — see the header note. Getharvest's own two shadows, hue-matched to the cream base
     ("the shadow hue is not neutral gray but matches the cream base" — kept, but matched to the PORCELAIN base rather than to their parchment, so the halo is warm stone and not a tea stain). */
  --el-1: 0 1px 2px rgba(123,101,92,.08), 0 6px 16px -8px rgba(123,101,92,.14);
  --el-2: 0 2px 5px rgba(123,101,92,.10), 0 18px 40px -18px rgba(102,84,76,.22);
  --el-glow: 0 10px 40px -18px rgba(237,167,137,.35);

  /* Getharvest's shape vocabulary, near-whole: "Apply 16px radius to all buttons and inputs, 20px to all
     cards — these two values are the system", and "don't use sharp 0-4px corner radii". */
  --r-sm: 12px;
  --r:    16px;
  --r-lg: 20px;
  --r-xl: 24px;
  --pill: 999px;

  --glow:   rgba(250,93,0,.16);
  --glow-2: rgba(255,222,205,.55);

  /* ── THE ORPHANED ALIASES FROM THE OLDER SHEETS. v13 and v15 declare four colour tokens that appear nowhere
     in the list above, so a token override alone never reaches them — v18 found this by DIFFING every `--x:`
     declared in v12/v13/v15/v17 against the set it declared, not by looking, and two of them are BACKGROUNDS,
     which do not announce themselves in a token file. They are re-pointed again here rather than given new
     values, so they move with the stack from now on.
       --ink-muted  is the BODY COPY colour on 28 rules across v13+v15 — hero leads, paragraphs, tooltips, the
                    model row, pull quotes, the MCP wizard's tabs and its copy button.
       --paper / --paper-2 are FILLS: .filmstrip, .ui-frame .ui-bar, .agentdemo, .mcpw-tabs, .mcpw-code.
     (--cinema / --cinema-ink are deliberately NOT touched: they are a matched dark-surface + light-ink pair,
     and the film-strip device stays a dark plate on purpose — it is a cinema screen, not a page surface.) */
  --ink-muted: #4f4d49;   /* = --muted. 8.01:1 on the canvas, 7.22:1 on the deepest chip. */
  --paper:     #faf1ec;   /* = --bg-2, the alternating band. */
  --paper-2:   #ffffff;   /* = --surface, a card plane. */
}

/* ── 1 · THE CANVAS ──────────────────────────────────────────────────────────────────────────────────────
   Getharvest's hero sits on a "decorative flowing gradient wash of #fa5d00, #ffdecd and warm peach tones …
   that suggest movement without ever competing with content", and their own guard-rail is "don't apply
   saturated colours to large background fills". So: a marigold pool entering from the top-right like light
   through a window, one whisper of flame at the far left, and the fine grain kept so cream has a surface
   rather than reading as a flat fill. The `!important` is inherited from v18 and is not a specificity fight —
   v17's gallery layer explicitly disabled these with `display:none !important`. */
html{ background:var(--bg); color-scheme:light; }
body{ background:var(--bg); color:var(--text); }
body::before{
  content:"" !important; display:block !important; position:fixed; inset:0; z-index:0; pointer-events:none;
  opacity:.5; mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.045'/></svg>");
}
body::after{
  content:"" !important; display:block !important; position:fixed; inset:0; z-index:0; pointer-events:none;
  background:
    radial-gradient(58% 42% at 88% -6%, rgba(255,222,205,.62), transparent 66%),
    radial-gradient(46% 34% at 4% 2%, rgba(250,93,0,.05), transparent 62%);
}
::selection{ background:rgba(250,93,0,.22); color:var(--text); }
::-webkit-scrollbar{ width:11px; height:11px; }
::-webkit-scrollbar-track{ background:var(--bg); }
::-webkit-scrollbar-thumb{ background:#dfd0bd; border-radius:999px; border:3px solid var(--bg); }
::-webkit-scrollbar-thumb:hover{ background:#c9b79f; }

/* ── 2 · BANDS. Two adjacent bands are never the same value, so the divider between them is redundant —
      except that the dashed rule is a MOTIF, so it comes back in §4 where it separates ideas rather than
      colours. The direction inverts from v18: on darkness a card was LIGHTER than its band; on cream a card
      is WHITER, which is the same "one step toward the light source" rule seen from the other side. ────── */
main > section{ background:var(--bg); }
main > section:nth-child(even){ background:var(--bg-2); }
.hero{ background:transparent; }
.cinema, .formats, .trust{ background:var(--bg-2); border-top:0; border-bottom:0; }
.footer{ background:var(--bg-2); border-top:1px dashed var(--line); }
.page-hero, .page-hero-in{ background:transparent; }

/* ── 3 · TYPE. Getharvest's typographic law is the opposite of v17's and the same as v18's in sign but not in
      size: "use 0.015em POSITIVE letter-spacing on all text — this tracks-wide feel softens the geometric
      sans". v17 had pushed display type to -.028em to make a near-white page feel tight; v18 relaxed it to
      -.006em for cream-on-black. On cream-with-black ink the reference's own answer applies directly. ──── */
h1,h2,h3,.tt,.h1,.h2,.h3,.display,.pullq,.big-quote{ letter-spacing:-.004em; }
.hero h1{ letter-spacing:-.006em; }
h1,h2,h3,.tt{ color:var(--text); }
h2 i,.tt i,h1 em,.pullq i,.serif-i{ color:var(--coral-text); font-style:italic; font-weight:400; }
/* the gradient wordplay survives. On cream a warm gradient must DARKEN rather than lighten, or the word
   disappears — the stops run flame → deep flame → gold, all of which are ≥3:1 at display size. */
h1 em.key, .closer h2 em.key, .hero h1 em.key .rotw-in{
  background:linear-gradient(100deg, var(--coral), #d24e00 52%, #8a5a00) !important;
  -webkit-background-clip:text !important; background-clip:text !important; color:transparent !important;
}
p,.lead{ color:var(--muted); }
.dim,.faint,.meta,.updated,.price-note{ color:var(--faint); }
.eyebrow,.eyebrow13,.mono,.slate,.fstep-n,.install-lbl,.rail-kind,.plaque,.t-name,.fmt-name,.foot-col h3,
.trust-label,.fs-label,.ftool-lab{ color:var(--faint); }
.eyebrow,.eyebrow13{ color:var(--coral-text); }
.mono .dot{ background:var(--coral); box-shadow:0 0 14px 2px var(--glow); opacity:1; animation:pulse 2.6s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce){ .mono .dot{ animation:none; } }
.slate::before{ background:var(--coral); box-shadow:0 0 12px var(--glow); }
.stat b,.num,.big,.amt,.price,.t-amt{ color:var(--text); }
.stat:nth-child(2) b{ color:var(--coral-text); }
code,kbd,.kbd{ color:var(--muted); }
a{ color:inherit; }
.prose a,.post-dek a,.callout a,.flow-note a,.cc-msg a{ color:var(--coral-text); }
.prose a:hover,.flow-note a:hover{ color:var(--coral-deep); }
.flow-note a{ border-bottom-color:rgba(250,93,0,.42); }
.flow-note a:hover{ border-bottom-color:var(--coral); }

/* ── 4 · THE DASHED HAIRLINE. Kept exactly as v18 built it — this is the structural motif the redesign
      carries forward, and it belongs to Hermoso now rather than to ORYZO. A control's own edge stays SOLID,
      because a dashed button outline reads as a dropzone. ──────────────────────────────────────────────── */
.move + .move,
.install-row + .install-row,
.install-foot,
.toolfam > code,
.qa,
.foot-bottom,
.post-card + .post-card,
.compare-row,
.credits-row,
.checklist li + li,
.steps .step + .step,
.blog-list li + li{
  border-top:0; border-bottom:0;
  border-block-start:1px dashed var(--line);
}
.qa{ border-block-start:0; border-block-end:1px dashed var(--line); }
.foot-bottom{ border-block-start:1px dashed var(--line); }
.ticker{ border-top:1px dashed var(--line); border-bottom:1px dashed var(--line); }
main > section + section{ position:relative; }
main > section:nth-child(even) + section:not(:nth-child(even))::before,
main > section:not(:nth-child(even)) + section:nth-child(even)::before{ content:none; }

/* ── 5 · SURFACES. Every card in every one of the four stylesheets, resolved to one plane vocabulary.
      THE DEPTH MODEL INVERTS HERE and it is the heart of the reference: a white card on cream is a 1.05:1
      luminance step, so the SHADOW is the card boundary, not the fill difference. Getharvest are explicit
      ("depth comes from shadow not contrast") and their shadow is amber, not grey. ────────────────────── */
.toolfam,.tease,.fmt-mini,.install,.promptcard,.ad-log,.ui-frame,.langmenu,.fstep,.rail,.flow-entry,.pcard,
.tile,.plan,.post-card,.card,.mcpw,.band,.cta-band,.ftool-card,.ftool-stage,.callout,.model-chip,.feature,
.shot,.stage-wrap,.media-frame,.gallery,.bento,.split,.compare,.credits,.chan-tools,.ftool{
  background:var(--surface);
  border-color:var(--line);
  box-shadow:var(--el-1);
}
/* inside an already-tinted band a card stays WHITE — the step is always toward the light, in one direction,
   exactly as v18 kept it always toward the dark. */
main > section:nth-child(even) :is(.toolfam,.tease,.fmt-mini,.install,.promptcard,.ad-log,.fstep,.rail,
  .flow-entry,.pcard,.tile,.plan,.post-card,.card,.mcpw,.ftool-card,.callout,.model-chip){
  background:var(--surface);
}
.toolfam:hover,.fmt-mini:hover,.tile:hover,.post-card:hover,.model-chip:hover{ background:var(--surface); box-shadow:var(--el-2); }
main > section:nth-child(even) :is(.toolfam,.fmt-mini,.tile,.post-card,.model-chip):hover{ background:var(--surface); }
.surface,.surface-2,.chrome{ background:var(--surface); }
.copyline,.ftool-seg,.mcpw-tabs,.ftool-drop{ background:var(--surface-3); border-color:var(--line); }
main > section:nth-child(even) .copyline{ background:var(--surface-3); }
.copyline{ color:var(--text); }
.copyline-x{ background:var(--surface); color:var(--muted); }
.copyline:hover{ border-color:var(--coral); }
.copyline:hover .copyline-x{ background:var(--coral); color:var(--cta-ink); }
.copyline.copied .copyline-x{ background:#146c3a; color:#fff; }
.copyline-pre{ color:var(--coral-text); }
.ui-bar{ background:var(--surface-3); border-bottom:1px dashed var(--line); }
.ui-bar i{ background:var(--line-2); }
.ui-bar i:first-child{ background:var(--coral); }
.ui-frame{ border:1px solid var(--line); }
img.pshield{ background:var(--surface-3); }
.hero-float,.reel-card,.fmt-media,.shot,.ad-out .th,.tile-media,.stage{
  background:var(--surface); border:1px solid var(--line); box-shadow:var(--el-1);
}
/* the framed print floating on the workbench — a warm glow, which on cream is the amber shadow the reference
   specifies rather than the light source v18 used it as. */
.hero-float{ box-shadow:var(--el-2), 0 0 90px -30px rgba(237,167,137,.45); }
.reel-card:hover,.fmt-card:hover .fmt-media,.ad-out .th:hover{ border-color:var(--coral); }

/* ── 6 · CONTROLS. One filled flame pill, one outlined ghost, one bare underline link — and Getharvest's
      restraint rule, which matches ORYZO's: only one filled button per section. ──────────────────────── */
.btn{ border-radius:var(--r); letter-spacing:.015em; }
.btn-primary,.cc-accept,.btn.primary,.plan .btn-primary{
  background:var(--cta); color:var(--cta-ink);
  border:1px solid transparent;
  box-shadow:0 1px 4px rgba(0,0,0,.2);
}
.btn-primary:hover,.cc-accept:hover,.btn.primary:hover{
  background:var(--cta-hot); color:var(--cta-ink); transform:translateY(-1px);
  box-shadow:0 6px 20px -6px rgba(250,93,0,.5);
}
.btn-primary:active,.cc-accept:active{ background:var(--coral-deep); color:#fff; transform:none; box-shadow:none; }
.btn-ghost,.btn-text,.cc-btn,.btn.ghost{
  background:transparent; color:var(--text); border:1px solid var(--line-2);
}
.btn-ghost:hover,.cc-btn:hover,.btn.ghost:hover{ background:transparent; color:var(--text); border-color:var(--text); }
.nav-cta .btn-ghost{ border-color:var(--line-2); }
/* the focus ring is --coral-line, not --coral: the vivid flame is 3.01:1 on cream and DROPS below 3 on every
   other surface, so a ring painted in the accent itself fails 1.4.11 on exactly the filled controls that most
   need a visible focus state. */
:focus-visible{ outline:2px solid var(--coral-line); outline-offset:3px; }
/* THE ELEMENT-SPECIFIC FOCUS RULES IN THE OLDER SHEETS MUST BE NAMED, NOT INHERITED. v12/v13/v15 each carry
   their own `.nav-toggle:focus-visible`, `.mcpw-code:focus-visible` and `.ftool-*:focus-visible` painted in
   --coral, and those are (0,2,0) — they OUTRANK the (0,1,0) default above, so re-pointing only the default
   leaves them on the vivid flame. Measured on the composited pixel, the mobile Menu button's ring came out at
   2.98:1 — under the 1.4.11 floor by two hundredths, on the one control a phone user needs most, and on the
   ~400 pages that are NOT the homepage. Same selector, later sheet, so source order settles it without
   !important. */
.btn:focus-visible{ outline:2px solid var(--coral-line); outline-offset:3px; }
.nav-toggle:focus-visible{ outline:2px solid var(--coral-line); outline-offset:2px; }
.mcpw-code:focus-visible{ outline:2px solid var(--coral-line); outline-offset:2px; }
.ftool-field select:focus-visible,.ftool-field input:focus-visible,.ftool textarea:focus-visible{
  outline:2px solid var(--coral-line); outline-offset:1px; }
.skip{ background:var(--cta); color:var(--cta-ink); }
.move-link,.t-go,.pc-more,.fmt-mini--cta,.post-cta,.fk-go,.btn-text{ color:var(--coral-text); }
.move-link:hover,.t-go:hover,.post-cta:hover{ color:var(--coral-deep); }
.tease:hover .t-go{ color:var(--coral-deep); }

/* form controls (the free-tools pages are 40+ of the 446) */
.ftool-field select,.ftool-field input[type=text],.ftool textarea,.ftool input.ftool-line,
.hero-form input,.field input,.field textarea,input[type=email],input[type=url]{
  background:var(--surface); color:var(--text); border:1px solid var(--line-2); border-radius:var(--r);
}
.ftool-field select:focus,.ftool textarea:focus,.ftool input.ftool-line:focus,
.field input:focus,input[type=email]:focus{ border-color:var(--coral); outline:none; box-shadow:0 0 0 3px rgba(250,93,0,.18); }
::placeholder{ color:var(--faint); opacity:1; }
.ftool-seg button.on,.mcpw-tabs button.on{ background:var(--surface); color:var(--text); box-shadow:var(--el-1); }
.ftool-cell .fc-d{ background:var(--surface-3); color:var(--text); border-color:var(--line-2); }
.ftool-out,.ftool-rows,.ftool-line{ color:var(--muted); }

/* ── 7 · NAV. Transparent over the cream; on scroll a warm frosted pane, not a grey bar.
   THE RESTING STATE IS DECLARED EXPLICITLY, and that is not tidiness — v18's own note records that it forgot
   to, so v15's `.nav{ background:rgba(250,248,243,.72) }` survived at desktop width un-scrolled and the whole
   top navigation of ~275 pages measured 1.12:1. It is the ONE state a screenshot of a scrolled page never
   shows. Both states are written here, in both directions. ─────────────────────────────────────────────── */
.nav{ background:transparent; -webkit-backdrop-filter:none; backdrop-filter:none; border-bottom:1px solid transparent; }
.nav.scrolled{
  background:rgba(253,248,246,.82);
  -webkit-backdrop-filter:blur(16px) saturate(1.1); backdrop-filter:blur(16px) saturate(1.1);
  border-bottom:1px dashed var(--line);
}
.nav-links a{ color:var(--muted); }
.nav-links a:hover{ color:var(--text); }
.nav-links a::after{ background:var(--coral); }
.nav-toggle span,.nav-toggle::before,.nav-toggle::after{ background:var(--text); }
.nav-toggle{ background:transparent; border-color:var(--line-2); }
.brand,.brand b{ color:var(--text); }
.bloom{ filter:none; }
@media (max-width:860px){
  .nav{ background:rgba(253,248,246,.90); -webkit-backdrop-filter:blur(16px); backdrop-filter:blur(16px); }
}
/* ── THE MOBILE MENU CONTAINING-BLOCK FIX, carried forward verbatim in intent. `backdrop-filter` — like
      `transform`, `filter` and `perspective` — makes an element the containing block for fixed-position
      descendants, so `.mobile-menu`'s `inset:0` resolved against the 73px header instead of the viewport and
      the panel opened UNDER the page. While the menu is open the nav is not a glass pane (an opaque panel
      covers it anyway), so it stops being a containing block. `body.menu-open .nav` is (0,2,0) so it outranks
      the (0,1,0) @media rule above without !important. ────────────────────────────────────────────────── */
body.menu-open .nav{ -webkit-backdrop-filter:none; backdrop-filter:none; }
.mobile-menu{ background:#fdf8f6; }
.mobile-menu.open{ top:0; left:0; width:100vw; height:100vh; height:100dvh; }
/* `:not(.btn)` IS LOAD-BEARING and is the site's permanent contrast fixture. The menu's last row is the real
   Login / Sign-up pair, and a bare `.mobile-menu a` is (0,2,0) — it outranks `.btn-primary` (0,1,0) and
   repainted the CTA's ink to match the panel, i.e. an INVISIBLE Sign-up button on every phone (1.00:1).
   Caught by measuring, never by looking: the panel is opacity:0 until it opens. */
.mobile-menu a:not(.btn){ border-bottom:1px dashed var(--line); color:var(--text); }

/* ── THE CTA INK MOVED AND `--cream` DID NOT FOLLOW IT (found 2026-08-06 by the contrast sweep; PRE-EXISTING
      on origin/marketing-site, and verified there byte-for-byte before being fixed here rather than assumed
      to be collateral from the porcelain pass).
      v13/v15/v17 spell "the ink that sits ON a filled accent control" as `--cream`, and three of their rules
      use it to rescue a `.btn-primary` whose colour a higher-specificity ancestor selector had captured:
        v15 496   .prose a.btn-primary
        v15 615   .mobile-menu .m-actions .btn-primary  (inside its @media, so it only ever fired on phones)
        v15 1085  .prose .ftool a.btn-primary
      When the CTA flipped to WHITE-on-#c74800 on 2026-08-05, only `--cta-ink` was updated. `--cream` stayed
      inverted at #1d1e1c, so those three rules kept painting INK on the deepened flame: 3.47:1, under AA, on
      the pricing page's mobile Sign-up and on /mcp's "Start free →" at every width.
      `--cream` is deliberately NOT redefined: `.fmt-mini.is-new` (v15 978) uses it as a BACKGROUND, so moving
      it to white would silently flip that chip from a dark plate to a light one — a second, invisible change
      riding on a contrast fix. The three ink rules are re-pointed at `--cta-ink` instead, which is the token
      that actually means what they want. Equal specificity, later sheet, so each wins on order. ────────── */
.prose a.btn-primary,
.prose .ftool a.btn-primary,
.mobile-menu .m-actions .btn-primary,
.mobile-menu .m-actions .btn-primary:hover,
.mobile-menu .m-actions .btn-primary:active{ color:var(--cta-ink); }

/* ── 8 · THE HERO. v17 scrimmed the montage to .14 and washed it out with near-white gradients so type could
      win on paper; v18 let it breathe on darkness at .30. On cream we are back to needing a scrim, but a WARM
      one — the montage sits under cream veils rather than black ones, so the page still reads as one
      temperature. The five-act hero video is untouched; only what is painted over it changes. ──────────── */
.hero-stage video,.hero-stage img{ opacity:.22; }
.hero-stage::after{
  background:
    radial-gradient(88% 68% at 50% 42%, transparent 26%, rgba(253,248,246,.88) 78%),
    linear-gradient(180deg, rgba(253,248,246,.66), rgba(253,248,246,.32) 34%, rgba(253,248,246,.97) 90%);
}
.hero-stage::before{ background:radial-gradient(46% 36% at 50% 2%, rgba(255,222,205,.45), transparent 72%); }
.rc-brand{ background:rgba(255,255,255,.82); color:var(--text);
  -webkit-backdrop-filter:blur(7px); backdrop-filter:blur(7px); }
.hero-note{ color:var(--faint); }

/* ── 9 · PRICING. v17 inverted the featured plan to an ink fill so it would read on white; v18 made it the
      LIT one on darkness. On cream it becomes the WARM one — a marigold wash inside a flame border, which is
      the only place the reference's Marigold Glow appears at any size. Ink on that wash is 13.44:1. ────── */
.tease.feat, .tease.feat:hover,
main > section:nth-child(even) .tease.feat,
main > section:nth-child(even) .tease.feat:hover,
.plan.pop{
  background:linear-gradient(180deg, rgba(255,222,205,.55), rgba(255,222,205,.14) 58%), var(--surface);
  border:1px solid var(--coral);
  box-shadow:var(--el-2);
}
.tease.feat .t-amt,.tease.feat .t-go,.plan.pop .price{ color:var(--text); }
.tease.feat p,.tease.feat .t-name,.tease.feat .t-ads,.tease.feat .t-credits,.tease.feat .t-amt small{ color:var(--muted); }
.tease.feat .t-ads b{ color:var(--text); }
/* The featured plan's ribbon. v17 inverted it to white-on-ink, v18 to coral-on-walnut; either way the rule
   that matters is that the badge on the ONE card we most want read must not inherit the page's own ink onto
   the page's own fill. Flame fill, Ink Black on it: 5.28:1. */
.t-tag,.ribbon,.tease .t-tag,
.tease.feat .t-tag,
main > section:nth-child(even) .tease.feat .t-tag{ background:var(--coral); color:var(--cta-ink); }
.t-credits{ color:var(--coral-text); }
.tease.feat .t-credits{ color:var(--coral-deep); }

/* ── 10 · THE FLOW DEVICE. Its strokes are "a graphical object required to understand the content"
      (WCAG 1.4.11, 3:1). On cream the line must be INK-side rather than light-side: --line-2 measures
      3.34:1 on the canvas, comfortably over. ─────────────────────────────────────────────────────────── */
.flowgraph{ --flow-line: #8e8784; }
.flowgraph .fl-spark{ stroke:var(--coral); opacity:1; }
.rail-list .ch{ background:var(--surface); box-shadow:var(--el-1); }
main > section:nth-child(even) .rail-list .ch{ background:var(--surface); }
.rail-list .ch span{ color:var(--muted); }
.rail-list .ch svg{ opacity:1; }
.rail-kind{ color:var(--text); }
.rail-what,.flow-note{ color:var(--faint); }
.flow-say,.flow-return span{ color:var(--muted); }
.flow-say b,.flow-say strong{ color:var(--text); }
.pcard-solo{ color:var(--muted); }
.pcard-solo b{ color:var(--coral-text); }
.pcard code,.toolfam > code{ color:var(--faint); background:none; }

/* ── 11 · MISCELLANEA that would otherwise stay dark. Each of these hard-codes a value in v13/v15/v17 or was
      hard-coded by v18 for darkness, so a token override alone cannot reach them. ─────────────────────── */
.trust{ border-block:1px dashed var(--line); background:var(--bg-2); }
/* v18 inverted the partner logos to make dark marks readable on a dark page. On cream they go back to a plain
   grayscale, which is also Getharvest's own rule: "place trust/partner logos in grayscale so the orange accent
   remains the only chromatic focus". */
.trust-logos img,.prov-logo{ filter:grayscale(1) contrast(1.05); opacity:.62; }
.trust-logos img:hover,.prov-logo:hover{ opacity:.95; }
.langpick > summary,.langpick summary{ background:var(--surface); color:var(--muted); border-color:var(--line); }
.langpick summary:hover{ color:var(--text); border-color:var(--line-2); }
.langmenu{ background:var(--surface); border:1px solid var(--line); box-shadow:var(--el-2); }
.langmenu a{ color:var(--muted); }
.langmenu a:hover{ background:var(--surface-3); color:var(--text); }
.langmenu a.on{ color:var(--coral-text); }
.langmenu .lc{ color:var(--faint); }
.social a{ background:transparent; border:1px solid var(--line-2); color:var(--muted); }
.social a:hover{ color:var(--coral-text); border-color:var(--coral); }
.foot-col a{ color:var(--muted); }
.foot-col a:hover{ color:var(--coral-text); }
.foot-col h3{ color:var(--faint); }
#cookieSettingsLink{ color:var(--faint); }
#cookieSettingsLink:hover{ color:var(--coral-text); }
.cookie-consent{ background:rgba(255,255,255,.97); border:1px solid var(--line-2); box-shadow:var(--el-2);
  -webkit-backdrop-filter:blur(16px); backdrop-filter:blur(16px); }
.cc-msg{ color:var(--muted); }
.cc-btn{ color:var(--muted); border-color:var(--line-2); }
/* a toast is a deliberate INVERSION — it is a transient overlay, not a page surface, and it reads as one
   because it is the only dark object on a cream page. Warm ink, not a cool grey. */
.toast{ background:#2b2721; color:#f8f4ea; }
.qa-q{ color:var(--text); }
.qa-q:hover{ color:var(--coral-text); }
.qa .pm::before,.qa .pm::after{ background:var(--coral); }
.qa-a-in{ color:var(--muted); }
.models-row span{ border:1px solid var(--line-2); color:var(--faint); }
.models-row span:hover{ color:var(--coral-text); border-color:var(--coral); }
.plaque{ color:var(--faint); }
.plaque b{ color:var(--muted); }
.plaque .ai{ color:var(--coral-text); }
.promptline{ border-left:2px solid var(--coral); color:var(--text); }
.promptnote,.mcp-safety,.install-foot,.price-solo{ color:var(--muted); }
/* An INLINE tool name is a chip. The BLOCK-level `> code` at the foot of a family card is a hairline-ruled
   list, not a box (v17 was explicit about that), so the inline rule must exclude the block one or it wins on
   source order and paints a tinted panel across every card. */
.promptnote code,.toolfam code,.act-tool code,.install-foot code,.mcpw-code{
  color:var(--coral-text); background:rgba(250,93,0,.09); }
.toolfam > code,.pcard > code{ background:none; color:var(--faint); }
.ad-log{ color:var(--muted); }
.ad-log b,.ad-log .hl{ color:var(--coral-text); }
.ticker-set span{ color:var(--faint); }
.ticker-set span b{ color:var(--coral-text); }
.fmt-mini--cta{ background:rgba(250,93,0,.08); border-color:var(--coral); color:var(--coral-text); }
.fmt-mini--cta:hover{ background:rgba(250,93,0,.15); color:var(--coral-deep); }
.fmt-mini.is-new{ border-color:rgba(250,93,0,.38); }
.fmt-mini-tag{ color:var(--coral-text); }
.fmt-name{ color:var(--muted); }
.fmt-desc{ color:var(--faint); }
.cinema .reel-card{ border:1px solid var(--line); }
/* the filmstrip stays a dark cinema plate — see the --cinema note in the token block — so its overlaid
   controls keep light ink on a dark base. */
.stage .adc-cta{ background:rgba(29,30,28,.92); color:#fdf8f6; }
.shot .play span{ background:rgba(255,255,255,.96); color:#1d1e1c; }
.ok,.yes{ color:#146c3a; } .no,.bad{ color:#b3172d; } .warn{ color:var(--gold); }
.h-hermoso,.col-hermoso{ color:var(--coral-text); }
.coral-ink{ color:var(--coral-text); } .cream-ink{ color:var(--text); }
.hair-light,.hair-soft{ border-color:var(--hair); }
.field-err{ color:#b3172d; }
.glow,.glow-1,.glow-2,.glow-c,.glow-coral,.glow-plum,.glow-tile,.grad{ opacity:.4; }
.big-quote,.pullq{ color:var(--text); }
.prose{ color:var(--muted); }
.prose h1,.prose h2,.prose h3,.prose h4,.prose strong,.prose b{ color:var(--text); }
.prose blockquote{ border-inline-start:2px solid var(--coral); color:var(--muted); }
.prose hr{ border:0; border-top:1px dashed var(--line); }
.prose code{ background:rgba(250,93,0,.09); color:var(--coral-text); }
.prose pre{ background:var(--surface-3); border:1px solid var(--line); color:var(--muted); }
.post-head,.post-meta,.pc-meta{ color:var(--faint); }
.post-dek{ color:var(--muted); }
.compare-head,.credits-head{ color:var(--faint); border-block-end:1px dashed var(--line); }
.ftool-badge,.fs-tag,.fk-tag,.tag{ background:var(--surface-3); color:var(--muted); }
.ftool-priv,.ftool-hint,.ftool-empty,.ftool-notes,.ftool-meta,.ftool-index{ color:var(--faint); }
.ftool-err{ color:#b3172d; }

/* ── 12 · AIR. Getharvest's rhythm is "64-80px between sections, 32-40px card padding, comfortable density".
      That is TIGHTER than v18's darkroom (which needed the object alone in the frame) and looser than v15's
      original. A lander with fourteen sections cannot use ORYZO's 100vh gaps, and on a light page it does not
      need to — cream gives separation that darkness had to buy with space. ─────────────────────────────── */
.section{ padding:clamp(76px,10vw,120px) 0; }
.section.tight{ padding:clamp(62px,8vw,96px) 0; }
.flowsec{ padding:clamp(76px,10vw,120px) 0; }
.statstrip{ padding:clamp(58px,7vw,92px) 0; }
.cinema{ padding:clamp(74px,9vw,112px) 0; }
.closer{ padding:clamp(92px,13vw,168px) 0; }
.closer .scrim{ display:block; background:radial-gradient(64% 58% at 50% 118%, rgba(255,222,205,.6), transparent 66%); }

/* ── 13 · RESPONSIVE. Nothing structural changes on a phone — the palette does not need a breakpoint. The one
      thing that does: the hero montage must recede further, because a 402px column has no room to lose.
      MUST STAY LAST in this file (the app's own [[ux-batch-2026-07-20]] lesson). ──────────────────────── */
@media (max-width:640px){
  .hero-stage video,.hero-stage img{ opacity:.14; }
  .section{ padding:clamp(60px,12vw,92px) 0; }
  .section.tight{ padding:clamp(50px,10vw,78px) 0; }
  .closer{ padding:clamp(74px,17vw,116px) 0; }
}
@media (prefers-reduced-motion: reduce){
  .mono .dot{ animation:none; }
  .flowgraph .fl-spark{ display:none; }
}

/* ── HERO H1: TWO BALANCED LINES, NO RESERVED SLOT (WIDE VIEWPORTS ONLY) ────────────────────────────────────
   Dave, 2026-08-05: "get rid of the gap its very ugly, you can just make the text 2 lines with a line break" →
   "add the line break before 'marketing' so the 2nd line is 'marketing in X'".

   THE GAP WAS THE ROTATOR'S WIDTH RESERVATION. `.rotw::after{content:"OpenClaw"}` held the widest word so a swap
   could never move the line break — that took mobile CLS from 0.2058 to 0.0009 — and `text-align:end` parked the
   slack BEFORE the word so the trailing tail stayed welded. Correct, and ugly.

   THE MEDIA QUERY IS LOAD-BEARING, and it is here because a check caught the first attempt. Deleting the slot at
   ALL widths regressed exactly what the slot existed to prevent: at 320-430px "marketing in OpenClaw." wraps to a
   third line while "marketing in Claude." does not, so the h1 grew 79.88px -> 119.81px and shoved the page down
   40px — the CLS failure, reintroduced. site-hero-slot-check measured it across every locale x 6 words x 6 widths
   and named it. Above the breakpoint the line has room to stay on one line for every word, so the slot is
   redundant and the gap goes; below it, the slot is still the only thing keeping the height stable, so it stays.
   A gap on a 400px phone is a far smaller cost than a 40px content jump.

   SCOPED TO .h1-2line, added only where the lead is >=2 space-separated words AND >=10 characters. ja/th/zh are
   one unspaced token, and ko's 7-character lead made line 2 long enough to wrap variably even at 1440px — all
   four keep the slot and never see this block. */
@media (min-width: 700px){
  /* The width transition is what makes the re-centre glide instead of snap; the JS sets an explicit px width
     for the incoming word at the same moment the outgoing one starts fading. Safe here and ONLY here: inside
     this media query the slot is gone and the <br> fixes the line count, so width moves ink sideways within
     one line and can never move the paragraph below. */
  .hero h1.h1-2line em.key .rotw{ text-align:start; transition:width .34s cubic-bezier(.4,0,.2,1); }
  .hero h1.h1-2line em.key .rotw::after{ content:none; }
  /* inline-BLOCK, not inline: `transform` does not apply to a non-replaced inline box, so `display:inline`
     silently killed the rotator's translateY and the swap became a hard cut. The transition is restated here
     because the base sheet turns it off (`.rotw, .rotw-in{transition:none}`) for the absolutely-positioned
     variant; this selector is more specific, so the fade comes back only on the lane that can animate. */
  .hero h1.h1-2line em.key .rotw-in{ position:static; display:inline-block;
    transition:opacity .24s ease, transform .24s ease; }
  .hero h1.h1-2line em.key{ white-space:nowrap; }
}
/* The break is a layout device, not content. */
.hero h1.h1-2line .h1br{ line-height:0; }

/* ── …AND ON A PHONE: THE SAME SLOT, THE SAME HOLE, ONE BREAKPOINT DOWN ─────────────────────────────────────
   Dave, 2026-08-06, on a 402px iPhone: "Fix this gap on mobile before the agent name."

   The block above dropped the reservation for wide viewports and said that below 700px the slot was still the
   only thing pinning the line count. That is true only WHILE THE ACCENT PHRASE IS ALLOWED TO SHARE A LINE
   with the words before it. Measured off Dave's own screenshot (1206px at 3x = a 402px viewport): 71.0px of
   dead air between "in" and "Claude", where one word space in that type is 7.3px — a ten-space hole. Swept
   across all 32 homepages the reservation left 58.9px of slack and up to 66.9px of painted gap, and where the
   word fell to a line of its own instead it pushed the visible ink 29.5px off the headline's centre.

   FORCE THE BREAK AND THE RESERVATION IS REDUNDANT. Give the accent phrase a line of its own and make it
   unbreakable and the line count stops depending on the word — it is one line for every one of Claude /
   Codex / Cursor / Cline / OpenClaw / Hermes — so the <h1> box, and everything under it, hold still with the
   slot gone and the word sized to itself. Measured over 6 words x 13 widths from 320 to 699: slack 0, painted
   gap 7.5px (one word space), off-centre 0. `\A` on a ::before is the break rather than a <br> in the markup,
   because it has to be UNDONE above 700px where the two-line design wins, and markup cannot be un-inserted by
   a media query.

   FIVE LOCALES OPT OUT, AND NOT AS A TASTE CALL — the measurement puts them there. fa, hi, ko, tr and ur are
   the five whose headline carries a real WORD after the rotating name ("اجرا کنید", "चलाएं", "실행하세요",
   "yürütün", "چلائیں") where the other 27 carry only a full stop. That tail sits OUTSIDE <em class="key">, so
   it is free to wrap by itself — and it wraps for the long words and not the short ones, which is the 0.2 CLS
   defect all over again (tr @402 renders four lines for five of the words and three for "Cline"). Welding the
   tail into the nowrap run was measured too, and is worse: it overruns a 320px phone by 151px in Turkish and
   174px in Korean, i.e. it clips the headline off the screen. So those five keep the reserved slot and render
   exactly as they do today — no regression, no improvement — and the other 27 lose the hole.

   :lang() AND NOT A CLASS, because the <h1> lives inside <main>, whose skeleton — class attributes included —
   must stay byte-identical across all 32 homepages or site-locale-drift-check fails. Chained simple
   :not(:lang(x)) rather than :not(:is(…)) so the selector is CSS3 and cannot be dropped whole by an older
   Safari, which is the engine this was reported on and the one whose wrapping differs from Chrome's here.
   THE FIVE ARE NOT A HAND-KEPT LIST: tools/site-hero-mobile-gap-check.mjs re-derives them by measurement and
   fails in BOTH directions — a locale carrying the fix that moves, and a locale carrying the hole that would
   not have. Do not edit the set here; run the check and let it tell you what it is. */
@media (max-width: 699.98px){
  /* one line of its own, and unbreakable, so no word can change how many lines the headline takes */
  html:not(:lang(fa)):not(:lang(hi)):not(:lang(ko)):not(:lang(tr)):not(:lang(ur))
    .hero h1.h1-2line em.key{ white-space:nowrap; }
  html:not(:lang(fa)):not(:lang(hi)):not(:lang(ko)):not(:lang(tr)):not(:lang(ur))
    .hero h1.h1-2line em.key::before{ content:"\A"; white-space:pre; }
  /* the slot now sizes to the word in front of it. The width transition is the same one the >=700px lane
     uses and is safe for the same reason: the line count is pinned, so width moves ink sideways inside line
     three and can never move the lead paragraph. Both endpoints of the glide are stable configurations and
     line width is monotonic in slot width, so every intermediate frame is stable too. (It is also moot under
     prefers-reduced-motion: the rotator returns before its first tick there, so the width never changes.) */
  html:not(:lang(fa)):not(:lang(hi)):not(:lang(ko)):not(:lang(tr)):not(:lang(ur))
    .hero h1.h1-2line em.key .rotw{ text-align:start; transition:width .34s cubic-bezier(.4,0,.2,1); }
  html:not(:lang(fa)):not(:lang(hi)):not(:lang(ko)):not(:lang(tr)):not(:lang(ur))
    .hero h1.h1-2line em.key .rotw::after{ content:none; }
  /* inline-BLOCK for the same reason as the lane above: `transform` does not apply to a non-replaced inline
     box, and the swap's translateY is what stops the cross-fade reading as a hard cut. */
  html:not(:lang(fa)):not(:lang(hi)):not(:lang(ko)):not(:lang(tr)):not(:lang(ur))
    .hero h1.h1-2line em.key .rotw-in{ position:static; display:inline-block;
      transition:opacity .24s ease, transform .24s ease; }
}

/* ── CTA: WHITE INK ON A DEEPER FLAME ───────────────────────────────────────────────────────────────────────
   Dave, 2026-08-05: "i dont totally love the black text on the orange button, can we make it white? or does that
   go against the theme guidelines?"

   It does go against them ON THE ORIGINAL FLAME, and by a measured margin rather than a stylistic one: white on
   #fa5d00 is 3.17:1, under the 4.5:1 AA floor for normal-size text. That is exactly why the reference's own
   Components page (which specifies white) was overruled by its Agent Prompt Guide (which specifies ink) when this
   palette shipped — the two halves of their doc disagree and only one of them is accessible.

   But the constraint is the PAIRING, not the ink. Deepening the fill buys the ratio back and keeps white:
     white on #fa5d00  3.17  fails
     white on #d24e00  4.35  still short
     white on #c74800  4.82  PASSES — the shallowest step that does
     white on #b04200  5.79  hover
     white on #a33d00  6.45  active (already白 in the base sheet)
   #c74800 is one step deeper, still unmistakably flame rather than the brown Dave rejected in the ORYZO pass.
   Do not lighten these back toward #fa5d00 without re-measuring: the button is the one place on the site where
   the brand colour carries text. */
:root{
  --cta: #c74800;
  --cta-ink: #ffffff;
  --cta-hot: #b04200;
}

/* ── CHANNEL PROOF ROW, above the fold (2026-08-05) ─────────────────────────────────────────────
   Dave: the two floating AI clips "make it seem like all we do is generated AI content". The fix is
   not to hide the clips — it is to put the OTHER half of the product next to them. Every ad in our
   category that has run for months leads with breadth, not with a pretty render: ElevenLabs' Meta ad
   (live 2026-02 → 2026-08, six months) opens "generate ads & social media posts with AI. Veo, Sora,
   Kling, Wan, Seedance & more—all in one editor", and Postiz puts 30 channel logos above the fold.
   Nobody in the category advertises the output on its own.

   The marks are the SAME inline SVGs the app's connector tiles use, so the logo a visitor sees here
   is the logo they see after signing in. Four of them (TikTok, X, Threads, ChatGPT) are currentColor
   black marks — hence the explicit `color` below; the other eight carry their own brand hexes. */
.chanrow { margin: 22px auto 0; max-width: 680px; text-align: center; }
/* A BARE GLYPH AT TILE HEIGHT LOOKS BIGGER THAN THE TILE (2026-08-17). The channel rail mixes two kinds of mark:
   TILES, whose artwork carries its own padding inside the square (Snapchat, LinkedIn, Pinterest, Reddit), and BARE
   GLYPHS with no background at all. Give both the same 20px box and the bare one wins on sight — it spends the
   whole box on ink where the tile spends part of it on padding. Measured on the live rail, most bare glyphs are
   already inset by their own artwork (YouTube 14.3, Bluesky 15.7, X 16.3, Instagram 18.3), but three run the full
   20 and read oversized beside their neighbours: Apple, ChatGPT and Threads. Dave flagged it as "the app logo
   looks much bigger, see how much lower the bottom of it is" — right about the effect, while the geometry really
   was identical, which is exactly why measuring tops and bottoms kept reporting them flush.
   0.85 is the usual bare-to-tile ratio and lands these three at 17px, inside the band the other bare glyphs
   already occupy. Scaling rather than editing paths keeps every mark's artwork untouched and the layout fixed:
   the 20px box, the gaps and the wrap points do not move.
   ADDING A LOGO? Measure its PAINTED height. A tile may fill the box; a bare glyph that fills it belongs here. */
.chanrow-l [aria-label="Apple Search Ads"] svg,
.chanrow-l [aria-label="ChatGPT Ads"] svg,
.chanrow-l [aria-label="Threads"] svg { transform: scale(.85); transform-origin: 50% 50%; }

.chanrow-l {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: 14px 18px; color: var(--ink, #1a1712);
}
.chan-l { display: inline-flex; line-height: 0; opacity: .92; transition: transform .18s ease, opacity .18s ease; }
.chan-l svg { display: block; width: 20px; height: 20px; }
@media (hover: hover) { .chan-l:hover { opacity: 1; transform: translateY(-2px); } }
/* CENTRE THE BOX, not only the text inside it (Dave 2026-08-14: "why is the text here off center, the text below
   is properly centered"). `text-wrap: balance` deliberately narrows this paragraph to ~438px for even line breaks,
   and `text-align:center` on the parent then centres its LINES inside that box — while the box itself started at
   the parent's left edge, because the margin had no auto. Measured: the icon row above and the Works-in-Claude
   block below both centre at 722px; this centred at 665, 57px out, conspicuous precisely because it sits between
   two correctly-centred things. */
.chanrow-c {
  margin: 12px auto 0; font-size: 13.5px; line-height: 1.5;
  color: var(--ink-muted, #6B645C); text-wrap: balance;
}
.chanrow-c b { color: var(--ink, #1a1712); font-weight: 600; }
/* Phones: the row is the proof, so it must never become a scrollbar or a ragged third line. */
@media (max-width: 560px) {
  .chanrow { margin-top: 18px; }
  .chanrow-l { gap: 12px 14px; }
  .chan-l svg { width: 18px; height: 18px; }
  .chanrow-c { font-size: 12.5px; }
}
@media (prefers-reduced-motion: reduce) { .chan-l { transition: none; } }

/* The hero fine print balances onto two lines on desktop: the agent-client list, then the commercial terms.
   Hidden below 700px because the text already wraps there naturally and a forced break lands mid-phrase — and
   the break point differs per language, so this must never be a hard split of the string itself. The separator
   sits at the END of line one, so with the <br> hidden the sentence still reads "…any MCP client · No credit…". */
.hn-br { display: none; }
@media (min-width: 700px) { .hn-br { display: inline; } }
/* ════════════════════════════════════════════════════════════════════════════════════════════════════════════
   Hermoso — marketing design system · v20 "TYPESET" (2026-08-17)

   THIS FILE EXISTS TO CLOSE A SEAM, NOT TO INVENT A LOOK. The app shipped onto TYPESET on 2026-08-17
   (docs/design-system.md, docs/redesign-spec-2026-08-17.md, public/style.css) and the marketing site did not
   move with it, so hermoso.ai → app.hermoso.ai crossed a visible boundary. Measured in Chrome the same day,
   both surfaces booted locally, at 1440px:

     axis            site (v19 GOLDEN HOUR/PORCELAIN)      app (TYPESET)
     display face    Fraunces (serif)                      Geist 450/500          ← the loudest one
     body face       Hanken Grotesk                        Geist
     canvas          #fdf8f6 cream + peach radial wash     #fafafa, flat, no texture
     band            #faf1ec                               #f5f5f5
     hairline        #e9dfda / --hair #f2e9e4              #ebebeb
     ink             #1d1e1c (warm)                        #171717
     button radius   16px (--r)                            6px
     card radius     20px (--r-lg)                         6px
     elevation       warm blurred drop shadows (--el-1/2)  0 0 0 1px var(--border) — a RING
     announce bar    LIME #c8ff4d                          n/a  ← see §7, this was a bug not a decision
     accent family   #c74800 / #d24e00 / #b84400           identical  ← already agreed, untouched here

   So the accent was ALREADY aligned (v19 line 703 deepened the CTA to #c74800 + white ink, the same pair the
   app moved to). Everything above it in the table is what this file changes. The one thing TYPESET adds to
   Vercel's monochrome is our flame, and it is already correct — this layer takes colour AWAY, it does not add
   any.

   WHY A LAYER AGAIN AND NOT A REWRITE. Unchanged from v18/v19: the site ships four generation stylesheets —
   v12 (404), v13 (128 blog pages), v15 (271 landers/pricing/tools/mcp), v17 (the 32 homepages) — and all four
   declare the SAME :root token names. ONE file appended after whichever version a page already loads re-skins
   every page at once, and it stays exactly one: this section is appended INTO the v19 file rather than shipped
   beside it, so a page still carries two stylesheet links and not three. v19's sections above are inherited
   whole and this one changes values on top of them. Where v19 hard-codes a warm literal that no token can
   reach, the SELECTOR is re-pointed here (§8) rather than the token being blamed.

   ══ THE SWEEP THAT FOUND WHAT A TOKEN PASS CANNOT (2026-08-17) ═══════════════════════════════════════════
   v18's method, re-run: diff every `--x:` DECLARED by v12/v13/v15/v17 against the set the layer declares, and
   separately grep for hex/rgba literals that are not inside a `--x:` declaration. Both halves paid:

     · --display and --body were NEVER overridden by v18 or v19. Every token pass since v17 has re-skinned the
       colour of a page whose TYPEFACE nobody had touched, which is why the serif survived three redesigns.
     · --cinema / --cinema-ink (v13/v15) are a warm near-black plate #14100E on cream ink #F5F1EA. v19
       deliberately left them ("a cinema screen, not a page surface") — correct then, wrong now that the app's
       dark canvas is achromatic #0a0a0a. §5.
     · --sans is referenced by v13/v15 (`.stage .adc-av`) and DECLARED NOWHERE, so that avatar fell back to
       system-ui. Declared in §1.
     · --accent / --accent-ink are referenced by v17's `.announce` and DECLARED NOWHERE — so the top strip of
       every homepage in all 32 locales took the literal fallback `#c8ff4d`, a LIME GREEN. §7.
     · `.lead{ color:#4c473f }` (v13:159, v15:159) is a hard-coded warm brown carrying the BODY COPY of the
       lander hero on ~271 pages. No token pass has ever reached it. §8.
     · `rgba(219,82,56, …)` — the coral the brand used BEFORE Harvest Flame — is written as a literal 55
       times across v12/v13/v15 as icon tints, checklist ticks, a comparison column and a CTA band. §8b.
     · `border-radius:` literals above 6px, 62 of them, none of which move when --r moves. §3b.
     · `<div class="glow glow-coral">` × 400 — a blur(100px) ambient wash that is a DOM ELEMENT, so no
       stylesheet token names it and no computed-style walk sees it (`pointer-events:none`). §6.

   AND ONE THAT IS NOT IN A STYLESHEET AT ALL: `<meta name="theme-color">`, which tints the browser chrome
   on a phone, read `#faf8f3` on 416 pages (the v15 canvas, two generations stale) and `#ffffff` on the 32
   homepages. Nothing in CSS can reach a meta tag, so it had never moved with any re-skin — the address bar
   was cream while the page under it was not. All 448 now declare the canvas, `#fafafa`.

   THE UNDECLARED-VAR CLASS IS THE INTERESTING ONE and it is why §7 declares the tokens rather than only
   restyling the bar: `var(--accent, #c8ff4d)` fails SILENTLY and LOOKS deliberate. A missing token renders as
   a confident colour, not as a broken page — the same shape as [[failed-read-is-not-empty]]. Declaring the
   token fixes the class; restyling the bar fixes the instance. Both are here.

   ══ WHAT IS DELIBERATELY NOT DONE ═══════════════════════════════════════════════════════════════════════
     · `--cream` IS NOT REDEFINED. v19 documents the trap in full at its line 408: v13/v15/v17 spell "the ink
       on a filled accent control" as `--cream`, but `.fmt-mini.is-new` (v15:978) uses the SAME token as a
       BACKGROUND, so moving it to white flips that chip from a dark plate to a light one. v19's fix was to
       re-point the three ink rules at `--cta-ink`; that fix is inherited and left alone.
     · The accent ramp does not move. --coral / --coral-text / --coral-line / --cta / --cta-ink are the app's
       own values already, each measured. Re-deriving them here would be a second opinion on a settled
       measurement ([[cta-green-not-coral]] settled the MEANING; 2026-08-05 settled the VALUE).
     · Uppercase is still not extended — 32 locales, Greek final sigma, Turkish dotted/dotless i.
     · Fraunces and Hanken are NOT deleted from disk. 128 blog pages load v13 and the eyebrow/slate devices
       still name --mono; removing a font file is a separate, riskier change than ceasing to reference it.
   ══════════════════════════════════════════════════════════════════════════════════════════════════════════ */


/* ── 1 · TYPE. The whole seam in one section. ─────────────────────────────────────────────────────────────
   GEIST IS SELF-HOSTED, and that is a CSP decision, not a preference. site/_headers pins `font-src 'self'`
   and says why ("no third-party font CDN"); the app loads Geist from fonts.googleapis.com, which this site
   cannot do without widening the CSP — and the CSP line is already the file's longest, against Cloudflare's
   2000-character silent-drop limit (tools/site-headers-limit-check.mjs). Self-hosting needs NO header change
   at all, so the limit is never approached.

   FIVE SUBSETS, which is strictly MORE coverage than today: Fraunces and Hanken ship latin-only here
   (fraunces-latin.woff2 / hanken-latin.woff2), so ru/uk/vi have been rendering in system-ui for months.
   Geist brings cyrillic, cyrillic-ext and vietnamese with it. Greek (el), Arabic, Hebrew, Thai, Hindi, Urdu,
   Persian, Filipino and CJK have no Geist subset and fall through to system-ui exactly as they do today — no
   locale is made worse, six are made better. Total 75.9 KB across five files against 183.8 KB for the two
   faces it replaces, so the font budget goes DOWN.

   WEIGHTS: the variable face covers 400..700, which contains the 400/450/500 the system specifies. 450 for a
   hero headline is the system's signature — "heavier than a light but lighter than a semibold" — and it is
   only reachable because this is a variable font; a static 400/700 pair would round it to one or the other. */
@font-face{ font-family:'Geist'; font-style:normal; font-weight:400 700; font-display:swap;
  src:url('fonts/geist-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face{ font-family:'Geist'; font-style:normal; font-weight:400 700; font-display:swap;
  src:url('fonts/geist-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face{ font-family:'Geist'; font-style:normal; font-weight:400 700; font-display:swap;
  src:url('fonts/geist-cyrillic.woff2') format('woff2');
  unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116; }
@font-face{ font-family:'Geist'; font-style:normal; font-weight:400 700; font-display:swap;
  src:url('fonts/geist-cyrillic-ext.woff2') format('woff2');
  unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F; }
@font-face{ font-family:'Geist'; font-style:normal; font-weight:400 700; font-display:swap;
  src:url('fonts/geist-vietnamese.woff2') format('woff2');
  unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB; }

/* THE FALLBACK METRICS MATTER MORE THAN USUAL. v17 shipped a 'Fraunces Fallback' with size-adjust so the
   serif swap did not reflow; Geist's natural metrics are close to the system UI stack it falls back to, so
   the equivalent adjustment is a no-op and is deliberately not invented. font-display:swap is kept from v17. */
:root{
  --display:'Geist','Geist Fallback',ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
  --body:'Geist','Geist Fallback',ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
  /* --sans is referenced by v13:725 / v15:762 (`.stage .adc-av`) and declared by nobody. It means "the UI
     face", so it is the body face. Declared rather than left to its system-ui fallback. */
  --sans:var(--body);
  /* --mono is untouched: receipts, eyebrows, the film slate and the ticker are a deliberate third voice, and
     Vercel's own system keeps a mono. */
}
/* v19's `--display` was a SERIF, so several rules asked for a lighter weight to stop it shouting. Geist at
   the same weight reads lighter than Fraunces did, so the display weight comes UP to the system's 450 rather
   than staying where a serif needed it. This is the single line docs/design-system.md calls "the biggest
   change from today's site". */
h1,h2,.h1,.h2,.display,.tt{ font-family:var(--display); font-weight:450; }
h3,h4,h5,.h3{ font-family:var(--display); font-weight:500; }
body,.lead,p,li,input,select,textarea,button{ font-family:var(--body); }

/* TRACKING IS THE SIGNATURE, and it is size-dependent — Vercel: -0.06em at 56-64px, -0.05em at 30px, normal
   at body sizes. v19 set a single flat -.004em for every heading because a serif on cream wanted uniformity;
   a geometric sans at 56px genuinely needs the tight track and at 16px genuinely does not, so this splits.
   Getharvest's POSITIVE 0.015em on UI text is dropped with the rest of that reference: it was chosen to
   soften a warm page, and TYPESET's UI text tracks normal. */
h1,.h1,.display{ letter-spacing:-.06em; }
h2,.h2{ letter-spacing:-.05em; }
h3,.h3,.tt{ letter-spacing:-.03em; }
.btn,.nav-links a,.eyebrow,.label,.chip,.pill,.badge{ letter-spacing:normal; }
.lead,p,li{ letter-spacing:normal; }

/* THE ACCENT PHRASE STOPS BEING ITALIC, and this is a consequence of the font swap rather than a taste call.
   v17:143 sets `h1 em.key{ font-style:italic; font-weight:400 }` — an editorial device that worked because
   Fraunces ships a DRAWN italic (fraunces-italic-latin.woff2, and it is a genuinely different set of
   letterforms). Geist has no italic on Google Fonts at all, so the browser SYNTHESISES one by shearing the
   upright — and at the hero's 80px that is plainly a slanted sans, which is the single most visible "we
   swapped the font and did not look" tell there is.
   The emphasis does not disappear: the phrase is already painted in the flame, which is how the app's own
   hero carries its emphasis ("starts with one line." — coloured, upright, heavier). So the device becomes
   colour + weight instead of colour + slant, on both surfaces, and no synthetic letterform ships.
   NOT DONE: shipping a fourth font file for one phrase, or faking it with `font-synthesis`/skew.

   THE SAME REASONING APPLIES TO THE WHOLE DISPLAY-ITALIC FAMILY, which is bigger than the hero and was
   found by grepping `font-style:italic` in v13/v15/v17 rather than by looking at one page: `.serif-i`/`.key`
   (v15:143), the numbered-step figures (v15:312), the stat gradient (v15:406), the blog dek (v15:518) and
   the lander lead. Every one was a Fraunces italic — genuinely different letterforms — and every one is now
   a sheared upright. The lander lead is the worst of them: it is the second thing read on ~271 pages, set at
   1.3rem, fully italic.

   SCOPE IS THE CAREFUL PART. This turns off italic on DISPLAY DEVICES ONLY. Inline `<em>` inside body prose
   is deliberately left alone: a synthetic oblique at 16px is what every sans-serif site on the web ships,
   it was ALREADY synthetic here (hanken-latin.woff2 has no italic either, so body emphasis never had a
   drawn italic to lose), and removing it would strip real semantic emphasis from the copy. */
h1 em.key, .closer h2 em.key{ font-style:normal; font-weight:500; }
.serif-i, .key, .step .num, .stat .n .grad, .post-dek, .lead, .hero .lead, .hero13 .lead{
  font-style:normal;
}
.post-dek{ font-weight:450; }


/* ── 2 · THE NEUTRAL RAMP GOES ACHROMATIC. ────────────────────────────────────────────────────────────────
   These are the app's light-theme values verbatim (public/style.css, the `body.light` block), so the two
   surfaces are not merely similar — they are the same numbers. That is the point: "similar" is what produced
   a seam three redesigns running.

   THE TRANSFORM IS A CHROMA KILL AT HELD LIGHTNESS, exactly the shape v19 used to de-yellow parchment, taken
   to zero this time. Because L is held, every contrast ratio v19 measured survives to within rounding, and
   the ones that move at all move UP (a neutral #ebebeb is very slightly darker than #e9dfda). Nothing here
   is asserted from that argument, though — tools/interactive-contrast-check.mjs measures the painted pixels,
   and the reason it is trustworthy is that a re-skin is exactly when a control goes invisible.

   RATIOS, computed against the worst surface each token lands on (canvas / band / card / deepest chip):
     --text  #171717   16.94 / 16.28 / 17.61 / 15.55
     --muted #4d4d4d    8.13 /  7.81 /  8.45 /  7.46
     --faint #6b6b6b    5.09 /  4.89 /  5.29 /  4.67   ← the tightest pair on the site, AA at any size */
:root{
  --bg:        #fafafa;   /* Paper White — Vercel's canvas, and the app's. Flat. No wash, no grain (§6). */
  --bg-2:      #f5f5f5;   /* the alternating band — one step. */
  --surface:   #ffffff;   /* Pure White — the elevated card. The one value that survived every pass. */
  --surface-2: #f7f7f7;   /* card hover / inset — a step BELOW the canvas, not beside it. */
  --surface-3: #f0f0f0;   /* chips, filled controls, the deepest step. */
  --ink-well:  #ffffff;   /* v13/v15 alias for a card fill. */

  --line:      #ebebeb;   /* Hairline — Vercel's border value, verbatim, and the app's --border. */
  --hair:      #ebebeb;   /* v19 kept a lighter second hairline; on an achromatic ramp the two were within
                             one step of each other and the distinction bought nothing but a second value. */
  --hairline:  #ebebeb;   /* v15 alias — .ui-frame / .tease / .mcpw name this one. */
  --cork:      #ebebeb;
  --line-2:    #7d7d7d;   /* INTERACTIVE edge. WCAG 1.4.11 wants 3:1 for "visual information required to
                             identify a UI component", and #ebebeb is a decorative value that does not reach
                             it. 4.05:1 on the canvas, 3.63:1 on the deepest chip. This is Vercel's own Slate
                             — the one of their four published greys that clears the bar — and it is the same
                             value the app uses for --border-3. */
  --driftwood: #7d7d7d;   /* STRUCTURAL ONLY: dividers, diagram strokes. Never text. */

  --text:   #171717;      /* the app's --text in light. Near-black, not #000, so a #0a0a0a plate still reads
                             as a distinct darker surface where one is used (§5). */
  --muted:  #4d4d4d;
  --faint:  #6b6b6b;
  --ink:    #171717;      /* v15 alias. */
  --ink-muted: #4d4d4d;   /* = --muted. THE BODY COPY colour on 28 rules across v13+v15 — hero leads,
                             paragraphs, tooltips, the model row, pull quotes, the MCP wizard. v18 found this
                             by diffing, not by looking; carried forward. */
  --paper:     #f5f5f5;   /* = --bg-2, the alternating band. A FILL: .filmstrip, .ui-frame .ui-bar,
                             .agentdemo, .mcpw-tabs, .mcpw-code. */
  --paper-2:   #ffffff;   /* = --surface, a card plane. */

  /* THE DECORATIVE WASH IS NEUTRALISED RATHER THAN DELETED. --marigold was a peach bloom; TYPESET has no
     atmosphere at all ("flat #fafafa, no texture"). Its consumers are re-pointed in §6, but the token is
     kept parseable and achromatic so anything reading it that this sweep did not find degrades to a quiet
     step instead of to nothing. Same treatment the app gave its own --marigold on 2026-08-17. */
  --marigold: #f0f0f0;
  --glow:     rgba(199,72,0,.10);   /* the CTA halo, rationed. Hue follows --cta, never a second colour. */
  --glow-2:   rgba(0,0,0,.04);      /* was a peach veil; now a neutral whisper. */
  --plum:     #4d4d4d;              /* v13/v15 decorative second hue. TYPESET permits ONE accent, so this
                                       becomes ink rather than a colour nobody chose. */
  --gold:     #6b6b6b;              /* same reasoning as --plum. */
}


/* ── 3 · SHAPE. 16/20px → 6px. ────────────────────────────────────────────────────────────────────────────
   Getharvest's "16px buttons, 20px cards, these two values are the system" is replaced wholesale by Vercel's
   "buttons 6px, cards 6px, nav 2px, pills 9999px". These are the app's --radius / --r-card exactly.
   PILLS STAY PILLS: --pill is a shape decision (a badge, a chip, an avatar), not a radius on the ramp, and
   the app keeps its own --r-pill at 999px for the same reason. */
:root{
  --r-sm: 6px;
  --r:    6px;
  --r-lg: 6px;
  --r-xl: 8px;   /* one step past the card, for a modal/panel — the app's --r-modal. */
  --pill: 999px;
}
/* ── 3b · THE 62 RADII THE TOKEN CANNOT REACH. ────────────────────────────────────────────────────────────
   Moving --r from 16px to 6px reaches only the rules that READ it. A sweep of `border-radius:` declarations
   resolving to a literal above 6px — the radius twin of the palette-literal sweep, run the same way — finds
   62 of them across v12 (10), v13 (18), v15 (31) and v17 (3): 20px on the phone stage and the MCP wizard,
   16px on the marquee card, 15px on a gallery shot, 14px on the UI frame, 13/12px on the step and tile
   icons, 11px on the plan chip, and a long tail of 7-10px. None of them moved with the token, so the site
   would have shipped a 6px button sitting inside a 20px card — which reads as an unfinished re-skin rather
   than as a decision, and is exactly the kind of thing a screenshot review calls "looks a bit off".

   A BLANKET `* { border-radius: 6px }` IS THE WRONG FIX, and that is why this is a list. It would flatten
   the avatar circles (50%), the segmented controls and badges (999px — where a pill is the SHAPE of the
   thing rather than a rounding choice) and the media crops. The list below is derived from that sweep and
   split by role: cards and frames take --r, chips and small controls take --r-sm. They hold the same 6px
   today; they are two names because they are two decisions, exactly as in the app. */
.reel-card,.shot,.stage,.ui-frame,.mcpw,.tile-media,.tile .tile-media,.gallery .shot,
.hero-float,.media-frame,.fmt-media,.ad-out .th,.agentdemo,.filmstrip,.band,.cta-band{
  border-radius:var(--r);
}
.step .ico,.tile .ico,.checklist .ck,.social a,.langmenu a,.nav-toggle,.kbd,.plan .plan-ads,
.rail-list .ch,.stage .adc-cta,.mcpw-code,.chan-tools code,.tile .chan-tools code,.film .reel-card{
  border-radius:var(--r-sm);
}

/* v19 rounded the button explicitly at --r; that rule already reads the token, so it moves for free. The
   ones that hard-code a radius are re-pointed above; the ones that hard-code a COLOUR, in §8. */


/* ── 4 · ELEVATION BECOMES A RING. ────────────────────────────────────────────────────────────────────────
   THIS IS THE INVERSION v19 MADE, MADE BACK, and the reason is the canvas rather than taste. v19's argument
   was sound on its own premise: "a white card on cream is a 1.05:1 step, so the SHADOW is the card boundary,
   not the fill difference". On #fafafa the step is 1.02:1 — even smaller — so the boundary still cannot be
   the fill. What changes is WHICH boundary: Vercel's system spells depth as `rgb(235,235,235) 0 0 0 1px`,
   i.e. depth comes from a tonal edge, never from a blur, and the app's --card-shadow is exactly that ring.

   THE DOUBLE-EDGE TRAP, and why §4b exists. v19's card rule sets BOTH `border-color:var(--line)` AND
   `box-shadow:var(--el-1)`. A blur under a border is invisible; a RING under a border is a second 1px line
   sitting immediately outside the first, so the same swap that removes a shadow would silently double every
   hairline on the site to 2px. §4b makes the border transparent on exactly the selectors v19 named, so the
   ring is the single boundary and the border keeps contributing its 1px to the box — no reflow. */
:root{
  --el-1: 0 0 0 1px var(--line);
  --el-2: 0 0 0 1px var(--line-2);
  --el-glow: 0 0 0 1px var(--line);
}
/* §4b — the border yields to the ring. Selector list copied from v19 §5 verbatim so the two cannot drift. */
.toolfam,.tease,.fmt-mini,.install,.promptcard,.ad-log,.ui-frame,.langmenu,.fstep,.rail,.flow-entry,.pcard,
.tile,.plan,.post-card,.card,.mcpw,.band,.cta-band,.ftool-card,.ftool-stage,.callout,.model-chip,.feature,
.shot,.stage-wrap,.media-frame,.gallery,.bento,.split,.compare,.credits,.chan-tools,.ftool,
.hero-float,.reel-card,.fmt-media,.ad-out .th,.tile-media,.stage{
  border-color:transparent;
}
/* ONE SELECTOR NEEDS ITS OWN LINE, and it is worth saying why rather than folding it into the list above.
   v19:557 is `.cinema .reel-card{ border:1px solid var(--line) }` — specificity (0,2,0), which outranks the
   (0,1,0) `.reel-card` in the list, so that one card kept its border, took the ring as well, and painted a
   2px edge where every sibling painted 1px. Measured, not spotted: `getComputedStyle` reported
   borderTopColor rgb(235,235,235) on .reel-card while .hero-float in the same list reported transparent.
   A doubled hairline is the quietest possible regression — it looks like a slightly heavier card. */
.cinema .reel-card{ border-color:transparent; }
/* the framed print on the workbench had a 90px peach bloom bolted onto its shadow. One ring. */
.hero-float{ box-shadow:0 0 0 1px var(--line); }
.ui-frame{ border:1px solid transparent; box-shadow:0 0 0 1px var(--line); }
/* hover is a firmer ring, never a lift: v19 translated cards on hover under a growing shadow, which is the
   blur model again in motion. The app's hover is --card-shadow-hover, one step darker, and nothing moves. */
.toolfam:hover,.fmt-mini:hover,.tile:hover,.post-card:hover,.model-chip:hover,.tease:hover{
  box-shadow:0 0 0 1px var(--line-2); transform:none;
}
.btn-primary,.cc-accept,.btn.primary,.plan .btn-primary{ box-shadow:none; }
.btn-primary:hover,.cc-accept:hover,.btn.primary:hover{ box-shadow:none; transform:none; background:var(--cta-hot); }


/* ── 5 · THE DARK PLATE. ──────────────────────────────────────────────────────────────────────────────────
   --cinema / --cinema-ink are declared by v13 and v15 and were deliberately left alone by v18 and v19 ("a
   cinema screen, not a page surface"). That reasoning held while the dark surface elsewhere in the product
   was warm. The app's dark theme is now achromatic #0a0a0a with #fafafa ink — Arcads' restraint, not
   Vercel's, because Vercel publishes no dark half — so a warm #14100E plate on this site is the only warm
   surface left in the whole system. It matches the app's canvas exactly instead. */
:root{ --cinema:#0a0a0a; --cinema-ink:#fafafa; }


/* ── 6 · TEXTURE OFF. ─────────────────────────────────────────────────────────────────────────────────────
   v19 paints two full-viewport fixed layers on every page: a multiply grain at opacity .5, and a peach
   radial wash (rgba(255,222,205,.62) entering from the top-right). docs/design-system.md replaces "cream
   --paper + grain + ambient glow" with "flat #fafafa, no texture at all", and the redesign spec lists
   "no gradients, no grain, no glow, no ambient anything" as one of the five things BOTH references share.

   `!important` is inherited, not a specificity fight: v17's gallery layer disables these with
   `display:none !important` and v19 had to out-shout it to turn them on. Turning them off has to out-shout
   v19 in turn. content:none is belt-and-braces so the element is never generated at all. */
body::before, body::after{ content:none !important; display:none !important; background:none !important; }

/* the hero scrim washed the montage out with three cream gradients so serif type could win on paper. On a
   flat near-white page with a sans headline the scrim is neutral and much lighter. */
.hero-scrim, .hero-stage::after{
  background:
    radial-gradient(88% 68% at 50% 42%, transparent 26%, rgba(250,250,250,.88) 78%),
    linear-gradient(180deg, rgba(250,250,250,.66), rgba(250,250,250,.32) 34%, rgba(250,250,250,.97) 90%) !important;
}
.hero-stage::before{ background:none !important; }
.closer .scrim{ display:none !important; }
/* `.bloom` IS THE LOGO MARK, NOT A GLOW — the four-petal SVG beside the wordmark (index.html:67) and the
   52px one in the boot identity animation. An earlier draft of this section read `.bloom{display:none}` on
   the assumption that a class called "bloom", swept up in a section named TEXTURE OFF, was ambient
   decoration. It deleted the brand mark from the nav of all 432 pages, and nothing but a screenshot showed
   it — the page still looked deliberate, just wordmark-only. v19 already does the correct thing one section
   up (`.bloom{ filter:none }`, dropping its 10px drop-shadow halo), so there is nothing left to turn off.
   Kept as a comment because the next person sweeping for "glow" will read the same name and reach the same
   wrong conclusion. */
/* THE AMBIENT GLOW DIVS, and how they survived three redesigns: they are DOM ELEMENTS, not styles.
   `<div class="glow glow-coral">` appears 400 times across the site and 32 more as `.glow-c` — a
   `blur(100px)` radial at opacity .5 sitting behind the hero of every lander, blog post and CTA band. Two
   things kept them alive. First, no token names them: v13/v15 hard-code
   `radial-gradient(circle, rgba(219,82,56,.22) …)`, which is the pre-2026-08 CORAL and not a colour that
   exists anywhere in this system any more, so a `--x:` diff could never see it. Second, a warm-colour sweep
   over computed styles skips it if the filter treats "high red, low blue" as the sanctioned flame — mine
   did, on the first pass, and reported the lander CLEAN.
   IT WAS FOUND BY SAMPLING THE PAINTED PIXEL: rgb(248,241,240) at the centre of a lander hero against a
   rgb(250,250,250) canvas 100px to the left. That is the whole argument for measuring the artefact rather
   than the DOM — the DOM was transparent all the way down, because the thing tinting it was
   `pointer-events:none` and elementFromPoint walked straight past it.
   The spec's words are "no gradients, no grain, no glow, no ambient anything", so all of them go. The
   markup is left in place: 432 pages of DOM surgery to delete an element that now paints nothing is a
   worse trade than one rule, and it keeps this reversible. */
.glow, .glow-coral, .glow-plum, .glow-c, .glow-tile{ display:none !important; }

::selection{ background:rgba(199,72,0,.18); color:var(--text); }
::-webkit-scrollbar-track{ background:var(--bg); }
::-webkit-scrollbar-thumb{ background:#d4d4d4; border:3px solid var(--bg); }
::-webkit-scrollbar-thumb:hover{ background:#b8b8b8; }


/* ── 7 · THE LIME BAR. A DEFECT, NOT A DECISION. ──────────────────────────────────────────────────────────
   v17:1172 is `.announce{ background:var(--accent,#c8ff4d); color:var(--accent-ink,#101010) }`. Neither
   token is declared by v12, v13, v15, v17 or v19 — verified by extracting every `--x:` declaration from all
   five files and by grepping for the names — so every homepage in all 32 locales has been shipping a LIME
   GREEN full-bleed strip above the logo, taking the literal fallback. It is the first colour a visitor sees
   and it is a second accent on a system whose one hard rule is that there is exactly one.

   TWO FIXES, because they fix different things. Declaring the tokens closes the CLASS: any other rule that
   reaches for --accent now lands on the flame instead of on whatever literal its author happened to type.
   Restyling the bar closes the INSTANCE — and it does not simply repaint it flame, because a full-bleed
   saturated strip and a filled CTA forty pixels below it are two primary actions on one screen, which is the
   density Dave named ("not too many buttons … optimized for conversion") and which both references solve the
   same way: ONE saturated element per screen, everything else quiet. So the strip becomes a hairlined
   surface with ink copy and the flame carried only by the link, and the hero CTA is left as the only filled
   thing above the fold. */
:root{ --accent:var(--cta); --accent-ink:var(--cta-ink); }
.announce{
  background:var(--surface); color:var(--text);
  border-bottom:1px solid var(--line);
  font-weight:450; letter-spacing:normal;
}
.announce a{ color:var(--coral-text); text-decoration:none; }
.announce:hover{ background:var(--bg-2); }


/* ── 8 · THE LITERALS A TOKEN CANNOT REACH. ───────────────────────────────────────────────────────────────
   Each of these hard-codes a warm value in v13/v15/v17/v19, so no :root override in this file or the two
   before it ever touched them. Found by grepping every hex and rgba that is NOT inside a `--x:` declaration
   and filtering for warm near-whites (R-B >= 6, L > 0.55) and warm near-blacks — the same method v18 used on
   token NAMES, applied to values. Listed with their source so the next pass can re-run the sweep and get an
   empty result rather than re-deriving the list. */

/* v13:159, v15:159 — THE LANDER LEAD PARAGRAPH. This is body copy on ~271 pages in a hard-coded warm brown,
   and it is the most consequential literal in the sweep: it is the second thing read on every lander. */
.lead{ color:var(--ink-muted); }

/* v19:400 — the mobile menu panel, cream. v19:379/391 — the scrolled nav pane and its phone twin, cream at
   .82/.90 alpha. A scrim that does not track the canvas is a second temperature, and the nav is the one
   element on every page, so this is where a stale literal is most visible. */
.mobile-menu{ background:var(--bg); }
.nav.scrolled{ background:rgba(250,250,250,.82); border-bottom:1px solid var(--line); }
@media (max-width:860px){ .nav{ background:rgba(250,250,250,.90); } }

/* v13:467, v15:504, v19:512 — the toast, a warm dark plate with cream ink, three times over. */
.toast{ background:var(--cinema); color:var(--cinema-ink); border-radius:var(--r); }

/* v13/v15:346/373 — the shot tag; v19:543 — the demo CTA's ink. */
.shot .tag{ background:var(--surface); color:var(--text); }
.stage .adc-cta{ color:var(--bg); }
/* v15:877 `.hero-float .rc-brand{ color:#F5F1EA }` IS IN THE SWEEP AND IS DELIBERATELY NOT RE-POINTED.
   A literal being warm is not sufficient reason to move it — the question is whether it is still the rule
   that PAINTS. This one is not: v19:440 already re-points `.rc-brand` to `background:rgba(255,255,255,.82);
   color:var(--text)`, i.e. dark ink on a light chip, which is correct on a light page and was correct
   before this pass too. An earlier draft here "fixed" it to `var(--cinema-ink)` — a (0,2,0) selector that
   outranked v19's (0,1,0) — and painted #fafafa on an 82%-white chip: 1.0:1, the caption on both hero cards
   gone, on every homepage in 32 locales. Caught by measuring the computed colour, not by reading the sweep.
   THE LESSON GENERALISES: a literal-sweep produces CANDIDATES. Each one still has to be checked against the
   cascade before it is touched, because re-pointing a rule that no longer paints can only do harm. */

/* v13:562, v15:599 — a cream-to-cream vertical gradient behind a device frame. */
.agentdemo, .filmstrip{ background:linear-gradient(180deg, var(--surface), var(--bg-2)) !important; }

/* v13:787, v15:825 — .tease:hover borrowed a warm #CDC5B6 edge and a 54px shadow. §4 already re-rings the
   hover; this kills the border colour it would otherwise beat on specificity. */
.tease:hover{ border-color:transparent; }

/* v19:451/464 — THE FEATURED PLAN. v19 made it "the WARM one", a marigold wash inside a flame border, and
   called it "the only place the reference's Marigold Glow appears at any size". With the wash gone from the
   page that argument has nothing left to be consistent with, so the emphasis becomes what it is on every
   other TYPESET surface: the same white card as its siblings, distinguished by a FLAME ring instead of a
   hairline one. That is also the app's own pattern for a selected card, and it keeps the count of saturated
   elements on the pricing page at two (this ring and the Sign-up button).
   THE SELECTOR IS `.tease.feat` / `.plan.pop`, READ OUT OF v19 RATHER THAN GUESSED. An earlier draft wrote
   `.plan.featured, .plan.is-popular` — plausible class names that appear nowhere in this repo, so the rule
   was dead and the peach survived. It was the painted-pixel sweep that said so, not a re-read. */
.tease.feat, .tease.feat:hover,
main > section:nth-child(even) .tease.feat,
main > section:nth-child(even) .tease.feat:hover,
.plan.pop{
  background:var(--surface);
  border-color:transparent;
  box-shadow:0 0 0 1px var(--coral-line);
}

/* v15:687 / v13 — the cursor-following hover bloom on .tile/.step/.plan is a TWO-hue gradient: a coral stop
   and a peach one. The coral is the sanctioned accent; the peach is the second colour TYPESET does not
   allow, and at 5% alpha nobody would ever find it by looking. Re-pointed to a single flame tint so the
   effect survives and the hue count drops to one. */
@media (hover:hover) and (pointer:fine){
  .tile::before, .step::before, .plan::before{
    background:radial-gradient(420px circle at var(--mx,50%) var(--my,50%), rgba(199,72,0,.07), transparent 62%);
  }
}


/* ── 8b · THE ACCENT TINTS ARE STILL THE **OLD** CORAL. ───────────────────────────────────────────────────
   `rgba(219,82,56,…)` — #DB5238, the coral the brand used BEFORE Harvest Flame landed on 2026-08-05 — is
   written as a literal 55 times across v12 (16), v13 (17) and v15 (22). Every one is a low-alpha decorative
   tint: icon tiles, checklist ticks, the comparison column, the CTA band, the free-tool dropzone, a focus
   halo. Because they are literals rather than tokens, the accent migration never reached them and neither
   v18 nor v19 could have: a `--x:` diff sees only names, and at 5-10% alpha a slightly-wrong orange is
   invisible one element at a time and reads as "warm" en masse. Two of them are what the painted-pixel
   sweep caught on /pricing.html and, indirectly, on every lander.

   THE HUE IS THE ONLY THING THAT MOVES. Each alpha below is the one its own rule already used, so no tint
   gets stronger or weaker and nothing about the layout or the contrast changes — this is a hue correction,
   not a restyle. 250,93,0 is --coral (the flame) as a decorative wash; where the original used the coral as
   an INK it takes --coral-text or --coral-deep instead, because a tint and a text colour are different
   tokens for the reason v19 records at length.

   ALREADY HANDLED ELSEWHERE and deliberately not repeated here: .glow-coral (§6, deleted), ::selection and
   --glow (§2/§6), the .tile/.step/.plan hover bloom (§8), .tease.feat / .plan.pop (§8). What is left is
   everything that paints a SURFACE. */
.field:focus-within{ box-shadow:0 0 0 4px rgba(250,93,0,.12); }
.step .ico, .tile .ico{ background:rgba(250,93,0,.09); border-color:rgba(250,93,0,.20); color:var(--coral-text); }
.checklist .ck{ background:rgba(250,93,0,.10); border-color:rgba(250,93,0,.24); color:var(--coral-text); }
.compare-row .col-hermoso{
  background:rgba(250,93,0,.06);
  box-shadow:inset 1px 0 0 rgba(250,93,0,.22), inset -1px 0 0 rgba(250,93,0,.22);
}
/* .tile.feature, .band and .cta-band were multi-stop gradients mixing the old coral with a second warm hue
   (rgba(189,122,52) — an ochre that is not in this system either). TYPESET has no gradients, so they become
   the flat card they already sit among, marked by a ring where the original used colour to mark them. */
.tile.feature{ background:var(--surface); border-color:transparent; box-shadow:0 0 0 1px var(--coral-line); }
.band, .cta-band{ background:var(--surface); border-color:transparent; box-shadow:0 0 0 1px var(--line); }
.plan.pop .plan-ads{ background:var(--surface-2); }
/* the free-tool dropzone: hover, drag-over and focus all painted with the old coral. */
.ftool-drop:hover, .ftool-drop.over, .ftool-drop:focus-within{
  background:rgba(250,93,0,.06); border-color:var(--coral-line);
}
.ftool-err, .ftool-noscript{ background:rgba(250,93,0,.06); border-color:rgba(250,93,0,.22); color:var(--text); }
/* v12/v13/v15:123 — a full-width radial behind the page hero, and :146/148 — a horizontal accent rule. The
   radial is ambient and goes with the rest of the atmosphere (§6); the rule is a real divider and keeps its
   shape at the corrected hue. */
.page-hero, .page-hero-in{ background-image:none !important; }
.rule-hot, .hr-hot, .accent-rule{
  background:linear-gradient(90deg, transparent, rgba(250,93,0,.42) 18%, rgba(250,93,0,.42) 82%, transparent);
}
/* inline <code> carried a 9% flame wash in body prose on /mcp and the landers. On TYPESET a code chip is a
   NEUTRAL surface — which is what /docs already does (`code{ background:var(--surface-3) }`) — so the two
   surfaces stop disagreeing about what inline code looks like, and body copy keeps one accent: the link.
   THE CHIP IS FOR INLINE CODE ONLY (2026-08-17). `.wrap code` also caught the BLOCK-level `<code>` that ends
   every capability card listing the tools it maps to, so the chip fill stretched into a grey slab across the
   foot of each one — Dave: "the bottom bar on each card with the commands looks kinda ugly, were you trying to
   go for a code look or something?" A fill that reads as a chip around three inline words reads as a code
   block around a full-width line. Those footers already asked for `background:none` in TWO places and lost on
   source order, which is the tell that the broad selector was the bug and not their intent.
   Fixed by EXCLUDING them below rather than by narrowing this line: dropping `.wrap code` and relying on
   `p code`/`li code` was tried first and regressed every inline chip on the homepage back to the 9% flame wash
   this rule exists to remove (`.promptnote code` / `.install-foot code` in v17 win once `.wrap code` is gone).
   Broad selector, explicit exception — measured both ways rather than reasoned about. */
.prose code, .wrap code, p code, li code{ background:var(--surface-3); color:var(--text); }
/* The card footer is a FOOTER, not a code block: a hairline rule, the same monospace, no fill. `.toolfam > code`
   already read this way; `.pcard code` had no divider at all, so once the slab came off it floated. Same
   treatment for both, so the two card families stop disagreeing. */
.pcard > code, .toolfam > code{
  background:none; border-top:1px solid var(--hair); padding-top:12px; margin-top:16px; color:var(--faint);
}
.prose a code, p a code, li a code{ color:var(--coral-deep); }
/* the MCP wizard's connector-URL strip is the same decision, under its own class: it carried
   `rgba(250,93,0,.09)` — a flame wash behind the single most-copied string on the site. Neutral, like every
   other code surface, so the only accent in that panel is the copy button. */
.mcpw-code{ background:var(--surface-3); color:var(--text); border-color:var(--line); }
.mcpw-code .copyline-pre, .mcpw-code code{ color:var(--coral-deep); }


/* ── 9 · AIR. ─────────────────────────────────────────────────────────────────────────────────────────────
   The one spacing move. Vercel's card padding is 16px and its section gap 96-128px against Getharvest's
   "32-40px card padding, 64-80px between sections" which v19 §12 adopted. Density is COMPACT on this system
   — 4px grid — and the air goes between sections instead, which is what "big type, few words, lots of air"
   buys. Type scale is untouched: it is set per-page in the base sheets with clamp() and re-deriving it here
   would be a structural change wearing a token's clothes. */
main > section{ padding-block:clamp(72px,9vw,128px); }
.card,.pcard,.plan,.tile,.toolfam,.fmt-mini,.post-card,.ftool-card,.callout{ padding:16px; }
@media (min-width:900px){ .card,.pcard,.plan,.ftool-card{ padding:20px; } }


/* ── 10 · FOCUS. Untouched in value, restated in shape. ───────────────────────────────────────────────────
   v19's focus ring is --coral-line rather than --coral, because the vivid flame is 3.01:1 on the old canvas
   and drops below 3 on darker surfaces; on #fafafa --coral-line #d24e00 measures 4.28:1, so the reasoning
   holds with more margin than before and the value does not move. What moves is the corner: a 16px ring
   around a 6px control is a visible mismatch. */
:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{
  outline:2px solid var(--coral-line); outline-offset:2px; border-radius:var(--r-sm);
}


/* ── 11 · THE DISPLAY ITALIC THAT SURVIVED §1. ────────────────────────────────────────────────────────────
   §1 turned off the synthetic oblique on `h1 em.key`, `.closer h2 em.key` and the `.serif-i/.key/.step .num/
   .stat .n .grad/.post-dek/.lead` family. It did not turn off v19:248 —

       h2 i, .tt i, h1 em, .pullq i, .serif-i { color:var(--coral-text); font-style:italic; font-weight:400 }

   — of which only `.serif-i` was in the off-list. So the accent phrase of EVERY SECTION HEADING on the site
   was still asking for an italic Geist, which does not exist, so Chrome sheared the upright: "Watch a brief
   become an ad. *No hands.*", "One sentence in. *A week of marketing out.*", "Every format your feed knows.
   *Now yours to make.*" and the manifesto pull-quote, at 30-44px, on all 32 homepages. §1's own words for
   this are "the single most visible 'we swapped the font and did not look' tell there is" — it was written
   about the hero and the hero was the one place already fixed. Dave, on the same pass: "not everything on
   the site is updated in the style of fastlane".

   SAME SUBSTITUTION §1 MADE, for the same reason: the emphasis becomes colour + weight, never slant. Colour
   is left to v19's own rule (--coral-text, which is the measured 4.5:1 flame) so this changes one axis only.

   SCOPE IS UNCHANGED AND DELIBERATE: these four selectors are DISPLAY devices — a heading's accent phrase
   and a pull-quote. Inline `<em>`/`<i>` inside body prose keeps its oblique, exactly as §1 says: it was
   already synthetic under Hanken, every sans-serif site on the web ships it, and removing it would strip
   real semantic emphasis from the copy. */
h2 i, .tt i, h1 em, .pullq i{ font-style:normal; font-weight:500; }


/* ── 12 · A CENTRED PARAGRAPH WHOSE BOX WAS NOT CENTRED. ──────────────────────────────────────────────────
   The closing CTA's fine print — "No credit card · Start with 250+ free credits — earn as you go" — rendered
   299px LEFT of the heading and buttons it sits under. Measured on the live page: element centre 420px,
   `.wrap` centre 719px.

   IT IS NOT A text-align BUG, AND THE INLINE `style="text-align:center"` SOMEONE ADDED COULD NEVER HAVE
   FIXED IT. v17 sets `p{ max-width:58ch }` and the reset sets `*{ margin:0 }`, so the paragraph is a 523px
   block with no auto margins inside a 1200px parent: it sits hard against the parent's left edge, and
   `text-align:center` then centres the LINES inside that 523px box. The text is perfectly centred — on the
   wrong box.

   THIS IS THE SECOND INSTANCE OF ONE DEFECT. v19 fixed `.chanrow-c` the same way and left the same note
   ("CENTRE THE BOX, not only the text inside it"); the rule there is `margin:12px auto 0`. The class is
   "a max-width'd <p> in a centred stack", so the fix is applied to the two remaining members rather than to
   the one that was reported — `.hero-note` on both the hero and the closer, and any centred lead in the
   same position. Verified by measurement, not by eye: a sweep of every element whose computed text-align is
   center now reports zero whose centre is more than 4px off its parent's. */
.hero-note, .hero .lead, .closer .lead, .sec-head.center > p{ margin-inline:auto; }


/* ── 13 · THE GOLD GRADIENT ON THE BIGGEST TYPE ON THE SITE. ──────────────────────────────────────────────
   v19:252 paints the hero's accent phrase — "in *Claude*", at 80px, the first thing anyone reads — as

       linear-gradient(100deg, var(--coral), #d24e00 52%, #8a5a00) + background-clip:text, !important

   i.e. flame → deep flame → GOLD. #8a5a00 is a dark yellow-brown, and it is the last stop, so the phrase
   ends browner than it starts. Two TYPESET rules say it cannot stay: there is exactly ONE accent, and there
   are no gradients ("no gradients, no grain, no glow, no ambient anything"). Dave, this pass: "I dont want
   to see this yellowy color anywhere."

   IT WAS NOT FOUND BY GREPPING A TOKEN, and would not have been: §2 already re-points `--gold` to #6b6b6b,
   but this rule hard-codes the literal, so the token move never reached it. It was found by walking the
   painted styles of every element on the rendered page and flagging any fill, ink, border or GRADIENT STOP
   with R-B >= 6 — the same "measure the artefact, not the DOM" method §6 records for the `.glow` divs.
   That sweep now returns nothing but the sanctioned flame.

   §1 already decided what replaces it: the accent phrase carries colour + weight, not a second device. So
   the gradient becomes the flat measured type-flame the rest of the site's accent phrases use, and the
   `background-clip:text` scaffolding goes with it — leaving `color:transparent` behind with no gradient to
   reveal would paint the headline invisible. --coral-text is 5.16:1 on #fafafa.

   THE `!important` IS INHERITED, NOT A SPECIFICITY FIGHT: the rule being turned off carries its own. */
h1 em.key, .closer h2 em.key, .hero h1 em.key .rotw-in{
  background:none !important; -webkit-background-clip:border-box !important; background-clip:border-box !important;
  color:var(--coral-text) !important;
}


/* ── 14 · TWO WARM LITERALS THE PRICING PAGE STILL PAINTED. ───────────────────────────────────────────────
   Found by the same painted-pixel sweep as §13, run over /pricing.html, /mcp/, /blog/, /manifesto.html and a
   lander. Those four came back clean; pricing did not, because both of these are v15 literals rather than
   tokens, so §2's re-pointing never reached them.

   1. `.plan .ribbon` (v15:418) — the "MOST POPULAR" flag over the middle plan: a two-stop gradient from
      #e76a4e (a salmon that is in no version of this system) into --coral-solid, ink on --cream, under a
      22px rgba(200,68,42,.5) bloom. Gradient, second hue and blur, i.e. three separate TYPESET rules at
      once. It becomes what every other filled control on the site is: the flat CTA flame with white on it,
      4.82:1, no shadow. It stays a PILL — that is the shape of a ribbon, not a rounding choice (§3).

   2. `.plan.pop .plan-ads` (v15:427) — border rgba(219,82,56,.22). That is the PRE-2026-08 coral, which
      §6's note already names as "not a colour that exists anywhere in this system any more"; v20:1285
      repainted this element's BACKGROUND and left its BORDER behind, so the highlighted plan carried a
      pink-brown hairline no token could reach. The card is distinguished by being inside `.plan.pop`
      already; the hairline just needs to be a hairline. */
.plan .ribbon{
  background:var(--cta); color:var(--cta-ink); box-shadow:none;
}
.plan.pop .plan-ads{ border-color:var(--line); }


/* ── 15 · THE FORMAT GRID'S "SEE ALL" TILE. ───────────────────────────────────────────────────────────────
   v19:551 fills `.fmt-mini--cta` with `rgba(250,93,0,.08)` — an 8% flame wash over white, which paints
   rgb(245,233,226): a peach chip in the middle of a grid of hairlined white ones. tools/site-palette-pixel-
   check.mjs reports it as warm paint on every homepage (it was already reporting it before this pass — this
   fixes it rather than introducing it).

   §4's whole move is that depth and emphasis come from a RING, never from a fill or a blur, and §8 rations
   the surviving flame washes to controls that need a hit area (the step/tile icons, the checklist tick, the
   focus halo). A link tile is not one of those: it is a card that happens to be a link, so it gets the same
   white surface as its siblings and is distinguished by a FLAME ring — exactly the treatment §8 already gives
   `.tile.feature` ("the same white card as its siblings, distinguished by a FLAME ring"). Ink stays
   --coral-text (5.16:1); the ring is --coral, 2.97:1 on the canvas and the 3:1 floor is for UI edges, which
   is what this is. Hover firms the ring rather than deepening a wash, like every other card on the site. */
.fmt-mini--cta{ background:var(--surface); border-color:var(--coral); color:var(--coral-text); }
.fmt-mini--cta:hover{ background:var(--surface); border-color:var(--coral-deep); color:var(--coral-deep); box-shadow:none; }


/* ═══════════════════════════════════════════════════════════════════════════════════════════════════════════
   v20 · TYPESET · II — "MATERIAL" (2026-08-17, second pass)

   Dave, on the first TYPESET pass: "I think we can still make our website and web app UI a bit nicer, see how
   fastlane is a bit cooler, cleaner, etc.?" and "these apple-esque glass UI items are really nice too."

   Reference: usefastlane.ai + app.usefastlane.ai, read live in Chrome 2026-08-17 at 1440px, every value below
   taken off getComputedStyle rather than off a screenshot. Full study, with the adopt/adapt/skip table and the
   reasoning behind each refusal: docs/fastlane-design-study-2026-08-17.md.

   ══ WHY THIS IS SEVEN RULES AND NOT A RE-SKIN ══════════════════════════════════════════════════════════════
   The study's first move was to diff their token set against ours, and the result is why this section is
   short. Face (Geist), canvas (#fafafa vs #fff), hairline (~8% black) and the one-accent rule were ALREADY
   identical — TYPESET got those right two days ago. Exactly three axes differ, plus one bug:

       axis        Fastlane              TYPESET (as shipped)          this section
       radius      10 / 16 / 24 / 34     6 / 6 / 6                     8 / 12 / 18      II-2
       elevation   soft blur, 3 rungs    0 0 0 1px — a RING, no blur   ring + blur      II-1
       glass       blur+saturate+bevel   none                          rationed         II-3
       h1 tracking -0.04em @ 86px        -0.006em @ 80px  <- A DEFECT  -0.055em         II-0

   So this takes the SHAPE GRAMMAR and leaves the palette alone. Their warm surfaces (--bg-warm #faf8f6,
   --card #f4f2f0) are NOT taken: Dave has rejected warm/cream twice and tools/site-palette-pixel-check.mjs
   enforces it. Their second hue (the orange->purple gradient on the featured plan) is not taken either — one
   accent is this system's one hard rule.

   ── II-0 · THE TRACKING DEFECT. ────────────────────────────────────────────────────────────────────────────
   TYPESET's signature rule is `h1,.h1,.display{ letter-spacing:-.06em }` at specificity (0,1,0). It has never
   once applied to a homepage hero, because `.hero h1{ letter-spacing:-.006em }` — inherited from v17 and
   re-stated EARLIER IN THIS FILE — is specificity (0,1,1) and outranks it. Measured on the booted site:
   getComputedStyle(h1).letterSpacing === "-0.48384px" on an 80.64px headline, i.e. -0.006em, a factor of TEN
   looser than the value the whole pass was written around.

   This is the "later rules of equal specificity win on order" assumption in this file's own banner failing,
   because these two rules are NOT of equal specificity. The fix is to match the winning selector's
   specificity rather than to add !important — an !important here would be beaten by the next (0,1,1) rule
   someone adds, and the defect would come back wearing different clothes.

   -0.055em, not Fastlane's -0.04em: they set -0.04em on 86px, and tracking is a function of optical size.
   Our hero renders at 80.64px in a narrower measure, and -0.055em is where our own display face stops
   looking gappy without the letters touching. Their 0.97 line-height IS taken; ours was ~1.04, which is a
   body-copy leading sitting on a display line. */
.hero h1, .hero13 h1, .lander h1{ letter-spacing:-.055em; line-height:.98; }
.hero h2, .closer h2{ letter-spacing:-.045em; }

/* ── II-1 · ELEVATION GETS ITS BLUR BACK — AND THE RING KEEPS ITS JOB. ─────────────────────────────────────
   Section 4 above replaced every shadow with `0 0 0 1px var(--line)` on Vercel's argument: "depth comes from
   a tonal edge, never from a blur". That argument is sound and is NOT being reversed — the ring stays, and it
   is still the card's boundary. What was missing is that Vercel's system is a DEVELOPER CONSOLE and ours is a
   marketing page selling a visual product. Fastlane sits in our category and spells depth as ring AND blur,
   with all three rungs at <=12% alpha (--shadow-sm/md/lg, read live). A 1px ring with zero blur is what makes
   our cards read inert next to theirs, and "inert" is precisely the note Dave gave.

   THE ORDER MATTERS AND IS THE WHOLE TRICK: the ring is listed FIRST so it paints at the box edge, and the
   blur after so it falls outside the ring. Reversed, the blur draws under the ring and the card gains a muddy
   halo instead of a lift. Section 4b already made these cards' borders transparent so the ring is the single
   edge — that inheritance is what lets this be additive rather than a doubled hairline.

   ACHROMATIC, at their alphas. Fastlane's shadows read warm because #00000014 over cream is warm; ours are
   pure black at the same alphas so the neutral ramp stays neutral. This cannot move a contrast ratio: a
   shadow paints OUTSIDE the box and no text ever sits on it. */
:root{
  --el-1: 0 0 0 1px var(--line), 0 1px 2px rgba(0,0,0,.04), 0 4px 12px -6px rgba(0,0,0,.07);
  --el-2: 0 0 0 1px var(--line), 0 2px 6px rgba(0,0,0,.05), 0 14px 32px -14px rgba(0,0,0,.11);
  --el-glow: 0 0 0 1px var(--line), 0 10px 30px -14px rgba(0,0,0,.10);
}
/* Section 4 pinned three selectors to a bare literal ring, so a token change cannot reach them. Re-pointed. */
.hero-float{ box-shadow:var(--el-2); }
.ui-frame{ border:1px solid transparent; box-shadow:var(--el-1); }

/* HOVER LIFTS AGAIN, BY 1px, AND THAT NUMBER IS DELIBERATE. Section 4 killed the transform ("hover is a
   firmer ring, never a lift") because under a ring-only model a translate has nothing to translate against.
   With a blur underneath, a 1px rise reads as the card coming toward you; 2px+ is the bouncy-SaaS tell that
   Fastlane avoids — their own cards do not move at all, so this is a half-step toward them, not past them. */
.toolfam:hover,.fmt-mini:hover,.tile:hover,.post-card:hover,.model-chip:hover,.tease:hover{
  box-shadow:var(--el-2); transform:translateY(-1px);
}
@media (prefers-reduced-motion:reduce){
  .toolfam:hover,.fmt-mini:hover,.tile:hover,.post-card:hover,.model-chip:hover,.tease:hover{ transform:none; }
}

/* ── II-2 · THE RADIUS LADDER MOVES ONE NOTCH, NOT FOUR. ───────────────────────────────────────────────────
   Fastlane runs 10/16/24/34. Ours runs 6/6/6, which is Vercel's console value and is what makes the page read
   "technical" where Dave wants "clean". The temptation is to match them; the reason not to is that 34px card
   corners ARE their look, and TYPESET's tight geometry is ours and was signed off two days ago. 8/12/18 is one
   notch up the same ladder — visibly softer, still unmistakably this system.

   --r-xl stays one step past the card exactly as section 3 set it up, and PILLS STAY PILLS: 999px is a shape
   decision (badge, chip, avatar, the nav below), never a rung on this ramp. */
:root{
  --r-sm: 8px;
  --r:    12px;
  --r-lg: 18px;
  --r-xl: 22px;
}
/* Section 3b's 62 hard-coded radii were re-pointed at --r / --r-sm and move with the tokens for free. The
   BUTTON families read --r-sm and would jump to 8px with everything else; a button at the same radius as the
   card it sits in is the "unfinished re-skin" tell section 3b warns about, so they take one step down. */
.btn,.btn-primary,.btn-ghost,.cc-accept,.btn.primary{ border-radius:10px; }

/* ── II-3 · GLASS. RATIONED TO FLOATING CHROME. ────────────────────────────────────────────────────────────
   The recipe is Fastlane's `.fl-nav__inner`, read live and quoted in the study section 1:
       backdrop-filter: blur(6px) saturate(1.95) brightness(1.06) contrast(1.05);
       box-shadow: 0 16px 42px rgba(0,0,0,.18), 0 3px 10px rgba(0,0,0,.07),
                   inset 0 1.5px 1px #fff, inset 0 -10px 18px rgba(255,255,255,.18),
                   inset 0 -1px 1px rgba(0,0,0,.06), inset 0 0 0 1px rgba(255,255,255,.2);

   TWO THINGS DO THE WORK AND NEITHER IS THE BLUR. (a) saturate(1.85) brightness(1.04) — the panel AMPLIFIES
   what is behind it instead of fogging it, which is the whole difference between Apple material and frosted
   plastic; a plain blur() reads as a grey scrim. (b) The near-WHITE 1.5px inset top line is the bevel that
   reads as a lit edge. Our ambient alpha is pulled down from theirs (.18 -> .10) because their glass floats
   over a photographic hero and ours floats over flat #fafafa, where their shadow reads as a bruise.

   WHERE IT IS ALLOWED, and this is a rule rather than a preference: FLOATING CHROME ONLY. The nav pill and
   the announce pill are the only two glass objects on their entire marketing site and every static card is
   opaque. Glass on a card that never moves is decoration; glass on chrome you can see the page slide under is
   material. --glass-* are declared as tokens so the app can carry the identical recipe across the seam. */
:root{
  --glass-blur: blur(14px) saturate(1.85) brightness(1.04);
  --glass-bg:   rgba(255,255,255,.72);
  --glass-edge: 1px solid rgba(255,255,255,.65);
  --glass-shadow:
    0 10px 30px rgba(0,0,0,.10),
    0 2px 8px rgba(0,0,0,.05),
    inset 0 1.5px 1px rgba(255,255,255,.95),
    inset 0 -1px 1px rgba(0,0,0,.045),
    inset 0 0 0 1px rgba(255,255,255,.35);
}

/* ── II-4 · THE FLOATING PILL NAV. ─────────────────────────────────────────────────────────────────────────
   Their most recognisable object, and ours is a flat full-width bar with a hairline under it. This is
   CSS-ONLY: `.nav.scrolled` is already toggled by site.v17.js at scrollY > 12, and `.nav-in` is already the
   inner wrapper — so no HTML changes across the 32 locale homepages and nothing for site-locale-sync to
   re-graft. That is why the pill is painted on `.nav-in` and not on `.nav`.

   AT REST the nav stays exactly as section 8 left it: transparent, no border, full width. The pill is the
   SCROLLED state only, which is Fastlane's behaviour too — their bar is transparent over the hero and becomes
   a 620px pill the moment you move.

   THE BACKGROUND MUST MOVE TO THE PILL, NOT SIT BEHIND IT. Section 8 sets
   `.nav.scrolled{ background:rgba(250,250,250,.82) }` on the OUTER element; left in place, the page would
   show a full-width translucent band with a pill floating inside it. It is cleared here and re-declared on
   .nav-in. */
.nav.scrolled{ background:transparent; border-bottom:1px solid transparent; }
.nav.scrolled .nav-in{
  max-width:920px;
  border-radius:var(--pill);
  padding:9px 12px 9px 20px;
  background:var(--glass-bg);
  -webkit-backdrop-filter:var(--glass-blur);
          backdrop-filter:var(--glass-blur);
  border:var(--glass-edge);
  box-shadow:var(--glass-shadow);
}
.nav .nav-in{ transition:max-width .28s cubic-bezier(.4,0,.2,1), padding .28s cubic-bezier(.4,0,.2,1); }
@media (prefers-reduced-motion:reduce){ .nav .nav-in{ transition:none; } }
/* the CTA pair inside the pill goes pill-shaped with it — a 10px rect inside a 999px lozenge is the detail
   that makes a pill nav look bolted on. Scoped to the scrolled state so the resting bar is untouched. */
.nav.scrolled .nav-cta .btn,
.nav.scrolled .nav-cta .btn-primary,
.nav.scrolled .nav-cta .btn-ghost{ border-radius:var(--pill); }

/* BELOW 860px THE PILL IS NOT USED, and the reason is a bug this repo has already paid for once. The mobile
   menu is a `position:fixed` CHILD of .nav, and a backdrop-filter on an ancestor makes that ancestor the
   containing block for fixed descendants — which is what once opened the menu 136px tall instead of 860px.
   Section 8's phone rule paints the full-width bar at .90 alpha with no filter, and narrowing the nav to a
   pill would leave the burger floating in space besides. Full-width bar, exactly as today. */
@media (max-width:860px){
  .nav.scrolled .nav-in{
    max-width:none; border-radius:0; padding:0; background:transparent;
    -webkit-backdrop-filter:none; backdrop-filter:none; border:0; box-shadow:none;
  }
  .nav.scrolled{ background:rgba(250,250,250,.90); border-bottom:1px solid var(--line); }
}

/* ── II-5 · THE ANNOUNCE STRIP BECOMES A PILL. ─────────────────────────────────────────────────────────────
   Section 7 above already rescued this from being a lime full-bleed bar and made it a hairlined white strip —
   the right call at the time, and it fixed a real second-accent defect. It is still a full-width strip pinned
   to the top edge of the page, which is the least premium object we ship, and it takes the top edge away from
   the nav that now wants to float there.

   Fastlane put the same message INSIDE the hero as a glass pill ("New · Create an automation and fill your
   entire content calendar in one click"). Moving ours into the hero would mean HTML on 32 homepages plus a
   locale re-graft; restyling it in place gets the OBJECT right for zero structural risk, and it now reads as
   a floating pill above the nav rather than as browser chrome. The `New` lozenge is their idea and is drawn
   with ::before, so no markup changes. */
.announce{
  display:flex; align-items:center; justify-content:center;
  width:max-content; max-width:calc(100% - 32px); margin:14px auto 0;
  padding:5px 16px 5px 6px; border-radius:var(--pill);
  background:var(--glass-bg);
  -webkit-backdrop-filter:var(--glass-blur);
          backdrop-filter:var(--glass-blur);
  border:var(--glass-edge);
  border-bottom:var(--glass-edge);
  box-shadow:var(--glass-shadow);
  color:var(--text); font-weight:450; font-size:13.5px; letter-spacing:normal;
}
.announce::before{
  content:"New"; flex:none;
  background:var(--cta); color:var(--cta-ink);
  font-size:11px; font-weight:600; letter-spacing:.01em;
  padding:3px 9px; border-radius:var(--pill); margin-right:10px;
}
.announce:hover{ background:rgba(255,255,255,.88); }

/* ── II-6 · THE NUMBERED STEP RAIL. ────────────────────────────────────────────────────────────────────────
   Fastlane's "How it works" runs a track down the column with an accent segment that grows as you scroll, the
   step number set in MONO at 13px/1.3px tracking in muted grey, and the title at 46px/-0.03em. Ours ships
   `.move` blocks with `.move-idx` already carrying the numeral, so the rail is CSS-only: a track drawn with
   ::before on the text column and the accent segment with ::after.

   NO SCROLL-LINKED FILL. Theirs animates the accent segment with scroll position, which needs JS in a file
   several other agents are editing today; a static accent segment sitting at the numeral's own row says "you
   are in a sequence" just as clearly and cannot desynchronise from the DOM. The numeral goes mono because
   that is what makes it read as an INDEX rather than as a heading — the same reason our eyebrows are mono. */
.move{ position:relative; }
.move-idx{
  font-family:var(--mono); font-size:13px; letter-spacing:.1em;
  color:var(--faint); font-weight:400;
}
.move-txt{ position:relative; }
.move-txt::before{
  content:""; position:absolute; left:-22px; top:.3em; bottom:-1em;
  width:2px; border-radius:1px; background:var(--line);
}
.move-txt::after{
  content:""; position:absolute; left:-22px; top:.3em;
  width:2px; height:2em; border-radius:1px; background:var(--coral);
}
@media (max-width:1080px){ .move-txt::before,.move-txt::after{ display:none; } }

/* ── II-7 · THE EYEBROW GETS ITS DOT AND ITS PILL. ─────────────────────────────────────────────────────────
   Fastlane opens a section with a white pill carrying an accent dot and a mono, letterspaced label
   ("• SPOTLIGHT"). Ours is bare mono text. One rule, and every section gains a consistent opener. */
.eyebrow{
  display:inline-flex; align-items:center; gap:7px;
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--pill); padding:4px 12px 4px 10px;
  box-shadow:var(--el-1);
}
.eyebrow::before{
  content:""; width:5px; height:5px; border-radius:50%;
  background:var(--coral); flex:none;
}

/* ── II-8 · THREE THINGS THE FIRST DRAFT GOT WRONG, FOUND BY LOOKING AT IT. ────────────────────────────────
   Each was invisible in the source and obvious in a 1:1 zoom, which is the only reason they are here.

   (a) THE PILL'S TOP CORNERS WERE CLIPPED. `.nav` is `position:sticky; top:0` (v17:172) with a 72px-tall
       `.nav-in`, so the pill's top edge sat exactly on the viewport edge and its two upper corners were cut
       flat — it read as a tab welded to the top of the screen rather than as a floating object. Fastlane
       leaves ~14px of page above theirs. The height comes down by the same amount the margin goes up, so the
       nav's total box is unchanged and nothing below it reflows.

   (b) v17:173 GIVES `.nav.scrolled` ITS OWN backdrop-filter. II-4 cleared that element's BACKGROUND but not
       its filter, so a full-width invisible pane was still blurring the page behind the pill — the band edge
       is faintly visible in a zoom, and it is a compositing layer we pay for and do not want.

   (c) `.eyebrow.center{ display:block }` (v17:153) is specificity (0,2,0) and beat II-7's (0,1,0)
       `display:inline-flex`, so every centred eyebrow was a full-width block: the pill stretched the whole
       column and stopped reading as a pill at all. Matched at (0,2,0) rather than forced with !important,
       for the same reason II-0 gives.
       NOTE for whoever reads this next: v15:167 is `.eyebrow.center::before{ display:none }`, so on the ~271
       LANDERS (which load v15, not v17) the accent dot is suppressed and the eyebrow is a plain pill. That is
       left alone deliberately — the pill still reads, and re-enabling the dot there means overriding a rule
       whose original intent is not recorded. */
.nav.scrolled .nav-in{ margin-top:11px; height:61px; }
.nav.scrolled{ -webkit-backdrop-filter:none; backdrop-filter:none; }
.eyebrow.center{ display:inline-flex; }
/* a centred inline-flex needs its PARENT to do the centring — `text-align:center` on the eyebrow itself
   centres its text, not the box. The wrapper is already centred on these sections, so the eyebrow only needs
   to stop being a block; this keeps the text centred inside the pill for the multi-line phone case. */
.eyebrow.center{ text-align:center; }
@media (max-width:860px){ .nav.scrolled .nav-in{ margin-top:0; height:72px; } }

/* II-8(a), CORRECTED. `margin-top` on `.nav-in` COLLAPSED THROUGH `.nav`. The parent has no padding, no
   border and no formatting context of its own (v17:172 is just `position:sticky; top:0; z-index:100`), so an
   adjoining top margin on the first in-flow child collapses out of the parent and moves nothing — measured:
   marginTop computed as 11px and getBoundingClientRect().y was still 0.

   The fix is to space the pill from the element that OWNS the sticky top edge, which is `.nav` itself. Doing
   it with padding rather than `display:flow-root` on .nav is deliberate: flow-root would also stop the mobile
   menu's fixed positioning from resolving against the viewport, which is the containing-block bug this file
   already warns about twice. Padding creates no containing block and no stacking context. */
.nav.scrolled{ padding-top:11px; }
.nav.scrolled .nav-in{ margin-top:0; }
@media (max-width:860px){ .nav.scrolled{ padding-top:0; } }

/* II-8(d) · THE EYEBROW PILL WAS INVISIBLE ON THE ALTERNATING BAND. A white fill on --bg-2 (#f5f5f5) is a
   1.02:1 step and the --line hairline is 8% black, so on every other section the pill simply was not there —
   correct on the white canvas, absent on the band. Fastlane's sits on pure white throughout, so their single
   treatment works; ours has to survive both surfaces.

   The ring does the work instead of the fill: --el-1 already carries a 1px --line ring plus a soft blur, and
   raising the pill off BOTH surfaces with a slightly firmer shadow makes it read as an object on either. The
   fill stays --surface so the pill is lighter than the band and identical to the card language around it. */
.eyebrow{
  box-shadow:0 0 0 1px var(--line), 0 1px 2px rgba(0,0,0,.05), 0 3px 10px -4px rgba(0,0,0,.10);
}

/* II-7, EXTENDED TO THE CLASS THE HOMEPAGE ACTUALLY USES. II-7 styled `.eyebrow`, which is the LANDER's
   section opener (171 pages) and appears exactly ONCE on the homepage — measured, by enumerating every
   element on the page whose class contains "eyebrow" and whose height is non-zero: one hit, the FAQ's
   "Questions", 15037px down. The homepage's own opener is `.sec-head > .mono`, eight of them, and it already
   carries `<span class="dot">` IN THE MARKUP. So this is a second selector rather than a widening of the
   first, and it deliberately does NOT get the ::before dot — that would paint a second one beside the real
   one. Same pill, same ring, dot supplied by whichever source already has it. */
.sec-head > .mono{
  display:inline-flex; align-items:center; gap:7px;
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--pill); padding:4px 13px 4px 11px;
  box-shadow:0 0 0 1px var(--line), 0 1px 2px rgba(0,0,0,.05), 0 3px 10px -4px rgba(0,0,0,.10);
}
.sec-head > .mono .dot{ width:5px; height:5px; border-radius:50%; background:var(--coral); flex:none; }
