/* HeadHoncho marketing site — the 2026-08 design language, revised 2026-08-18.
   Light everywhere: the near-black band is retired by owner direction (black
   reads as void, not as a marketing app) — ink is for type and small marks
   only, and depth comes from tinted glows and card shadows on a cloud canvas.
   The color code is semantic and site-wide: blue = spend/marketing, orange =
   the work, green = the money. Rules: Conventions/Marketing Visual Language.
   Values mirror the hh-core tokens so the site and the app read as one
   company; the web type scale is the one Marketing Site Conventions §7 sets
   (display 52 / h2 34 / h3 20 / lead 19 / body 17 / small 14 / micro 12).
   Content width 1140, margin auto. */

:root {
  --ink: #0b0c0e;
  --font-display: "Figtree", "Open Sans", -apple-system, sans-serif;
  --font-text: "Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --primary: #2563eb;
  --primary-deep: #1d4fd7;
  --primary-soft: #eff4ff;
  --canvas: #f7f8f9;
  --surface: #ffffff;
  --subtle: #f2f3f5;
  --border: #e8eaed;
  --muted: #5f6673;
  /* Was #9aa1ab (2.61:1 on white) — it carried the Google citation, the proof
     line, the overage prices and the footer, all of it below the AA floor.
     #6b7280 clears 4.83:1 on white and 4.55:1 on the cloud canvas. */
  --faint: #6b7280;
  /* The brand colours have two jobs and they need two values. --good/--warn
     are FILLS: icon tiles, marks, illustration, the logo's own palette. The
     -text variants are TYPE: they are the same hue darkened until a reader
     can actually read them (5.02:1 and 5.18:1 on white; 4.55:1 and 4.58:1 on
     their own washes). Never set type in a fill colour. */
  --good: #16a34a;
  --good-text: #15803d;
  --good-bg: #e7f8ee;
  --warn: #ff751f;
  --warn-text: #c2410c;
  --warn-bg: #ffeee2;
  --bad: #dc2626;
  --bad-bg: #fdecec;
  --shadow-1: 0 1px 2px rgba(11, 12, 14, 0.05);
  --shadow-2: 0 2px 6px rgba(11, 12, 14, 0.05), 0 12px 28px rgba(11, 12, 14, 0.07);
  --shadow-cta: 0 1px 2px rgba(11, 12, 14, 0.12), 0 6px 16px rgba(37, 99, 235, 0.28);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* The type pairing (owner standard, revised 2026-08-20): Figtree carries the
   titles and anything that must grab the eye; Open Sans carries the reading.
   The pairing is DELIBERATELY swappable: change the two --font-* variables
   below plus the single Google Fonts <link> in each page head (and the same
   line in scripts/build_marketing_legal.py) and the whole site follows. */
h1, h2, h3, .cta, .price, .tier .price, .badge, .specimen-chip, nav.site a.cta {
  font-family: var(--font-display);
}


html { scroll-behavior: smooth; }

body {
  font-family: var(--font-text), "Segoe UI",
    Helvetica, Arial, sans-serif;
  color: var(--ink);
  background: var(--surface);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--primary); color: #fff; }

a:focus-visible, button:focus-visible, .cta:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: 4px;
}

.wrap { max-width: 1140px; margin: 0 auto; padding: 0 24px; }

/* Inline Material icons inherit text colour. */
.ic { width: 20px; height: 20px; fill: currentColor; flex: none; vertical-align: -4px; }
.ic-tile {
  width: 40px; height: 40px; border-radius: 10px; display: inline-flex;
  align-items: center; justify-content: center; margin-bottom: 14px;
}
.ic-tile .ic { width: 22px; height: 22px; }
.ic-tile.blue { background: var(--primary-soft); color: var(--primary); }
.ic-tile.green { background: var(--good-bg); color: var(--good-text); }
.ic-tile.orange { background: var(--warn-bg); color: var(--warn-text); }
.ic-tile.gray { background: var(--subtle); color: var(--muted); }

/* ------------------------------------------------------------------ header */
header {
  border-bottom: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.86);
  -webkit-backdrop-filter: saturate(1.4) blur(12px);
  backdrop-filter: saturate(1.4) blur(12px);
  position: sticky; top: 0; z-index: 50;
}
.header-row { display: flex; align-items: center; justify-content: space-between; height: 72px; }
.brand { font-size: 20px; font-weight: 700; color: var(--ink); text-decoration: none; letter-spacing: -0.01em; display: inline-flex; align-items: center; }
.brand img { display: block; }
nav.site { display: flex; gap: 26px; align-items: center; }
nav.site a {
  color: var(--muted); text-decoration: none; font-size: 14px; font-weight: 500;
  transition: color 0.15s ease;
}
nav.site a:hover { color: var(--ink); }
nav.site a.cta, nav.site a.cta:hover { color: #fff; }
.nav-toggle {
  display: none; background: none; border: 1px solid var(--border);
  border-radius: 10px; width: 44px; height: 44px; color: var(--ink);
  align-items: center; justify-content: center; cursor: pointer;
}

.cta, a.cta {
  background: var(--primary); color: #fff; text-decoration: none; font-weight: 600;
  font-size: 14px; padding: 10px 18px; border-radius: 10px; display: inline-flex;
  align-items: center; gap: 8px; border: 1px solid transparent;
  box-shadow: var(--shadow-cta);
  transition: background 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.cta:hover { background: var(--primary-deep); transform: translateY(-1px); }
.cta:active { transform: translateY(0); }
.cta.ghost {
  background: transparent; color: var(--primary); border: 1px solid var(--primary);
  box-shadow: none;
}
.cta.ghost:hover { background: var(--primary-soft); }
.cta.dark { background: var(--ink); box-shadow: var(--shadow-1); }

/* -------------------------------------------------------------------- hero
   Light, per the 2026-08-18 revision: depth from soft brand-color tints on
   the cloud canvas, never dark territory. Blue leads; orange and green
   whisper from the corners in their loop roles (the work, the money). */
.hero {
  background:
    radial-gradient(46% 60% at 84% 0%, rgba(37, 99, 235, 0.10), transparent 70%),
    radial-gradient(30% 44% at 2% 100%, rgba(234, 122, 26, 0.07), transparent 70%),
    radial-gradient(26% 40% at 60% 108%, rgba(22, 163, 74, 0.06), transparent 70%),
    radial-gradient(rgba(11, 12, 14, 0.05) 1px, transparent 1.5px) 0 0 / 26px 26px,
    linear-gradient(180deg, #ffffff, var(--canvas));
  color: var(--ink); padding: 88px 0 96px;
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}
.hero h1 { font-size: 52px; line-height: 1.12; font-weight: 700; max-width: 820px; letter-spacing: -0.02em; text-wrap: balance; }
.hero .lead { font-size: 19px; color: var(--muted); margin-top: 22px; max-width: 660px; }
/* A row of actions, anywhere. This lived under .hero only, which meant every
   cta-row in a <section> fell back to display:block and the button and its
   microcopy rendered touching. It is a global component now. */
.cta-row { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.cta-row .quiet { flex: 1 1 240px; min-width: 0; }
.hero .cta-row { margin-top: 36px; }
.hero .quiet { color: var(--faint); font-size: 14px; }

/* Home hero: copy left, the closed-loop visual right. */
.hero-grid { display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 64px; align-items: center; }
.hero-visual img { width: 100%; height: auto; display: block; }
.flow-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px; padding: 26px 26px 22px;
  box-shadow: var(--shadow-2);
}
.flow-title {
  font-size: 11px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 18px;
}
.flow-row { display: flex; align-items: center; gap: 14px; padding: 4px 0; }
.flow-ic {
  width: 38px; height: 38px; border-radius: 10px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
}
.flow-ic .ic { width: 20px; height: 20px; }
.flow-ic.blue { background: var(--primary-soft); color: var(--primary); }
.flow-ic.orange { background: var(--warn-bg); color: var(--warn-text); }
.flow-ic.green { background: var(--good-bg); color: var(--good-text); }
.flow-row strong { display: block; font-size: 15px; font-weight: 600; color: var(--ink); line-height: 1.3; }
.flow-row span { display: block; font-size: 12px; color: var(--muted); margin-top: 1px; }
.flow-link { width: 2px; height: 18px; background: var(--border); margin-left: 18px; border-radius: 2px; }
.flow-row.result {
  margin-top: 4px; padding: 14px; border-radius: 12px;
  background: var(--good-bg); border: 1px solid #bfe8cf;
}

/* The specimen report in its delivery moment — the hero artifact.
   An HTML card, not an image: the numbers stay crisp, the copy stays
   editable, and the SPECIMEN chip keeps it honest (Marketing Messaging
   Plan stage 2.1 — the artifact is proven, no customer is claimed). */
.report-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 16px; padding: 24px 26px; box-shadow: var(--shadow-2);
}
.report-meta {
  display: flex; align-items: center; gap: 8px; font-size: 12.5px;
  color: var(--faint);
}
.report-meta .ic { width: 15px; height: 15px; }
.report-subject {
  font-size: 17px; font-weight: 600; letter-spacing: -0.01em;
  margin-top: 6px; color: var(--ink);
}
.specimen-chip {
  display: inline-block; margin-top: 10px; font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--faint);
  border: 1px dashed var(--faint); border-radius: 999px; padding: 3px 10px;
}
.report-rows { margin-top: 16px; }
.report-row {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 10px 0; border-bottom: 1px solid var(--subtle); font-size: 14px;
  color: var(--muted);
}
.report-row .val { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.report-row.total {
  border: 1px solid #bfe8cf; border-radius: 12px; background: var(--good-bg);
  padding: 14px; margin-top: 12px; color: var(--good);
}
.report-row.total .val { color: var(--good-text); font-size: 24px; font-weight: 700; letter-spacing: -0.01em; }
.report-foot { margin-top: 12px; font-size: 12px; color: var(--faint); }

/* The loop animates: each stage lights in order, then the loop rests.
   Pure decoration — reduced motion switches it off entirely. */
html.js .flow-row .flow-ic { animation: flow-pulse 7s ease-in-out infinite; }
html.js .flow-row:nth-of-type(2) .flow-ic { animation-delay: 0.0s; }
html.js .flow-row:nth-of-type(4) .flow-ic { animation-delay: 0.9s; }
html.js .flow-row:nth-of-type(6) .flow-ic { animation-delay: 1.8s; }
html.js .flow-row.result .flow-ic { animation-delay: 2.7s; }
@keyframes flow-pulse {
  0%, 12.8%, 100% { box-shadow: 0 0 0 0 rgba(37, 99, 235, 0); transform: scale(1); }
  6.4% { box-shadow: 0 0 0 6px rgba(37, 99, 235, 0.12); transform: scale(1.08); }
}
@media (prefers-reduced-motion: reduce) {
  html.js .flow-row .flow-ic { animation: none; }
}


/* -------------------------------------------------- home hero (2026-08-19)
   The monday-style rebuild: one centered content column, one big product
   video below it in a browser frame that straddles the section boundary.
   Scoped to .hero-home so the subpage heroes keep the old geometry. The
   type pairing holds (--font-display / --font-text); only the home
   display size steps past the §7 scale — recorded in Marketing Site
   Conventions the day it shipped. */
.hero.hero-home {
  overflow: visible;
  padding-bottom: 0;
  text-align: center;
}
.hero-center { max-width: 880px; margin: 0 auto; }
.eyebrow {
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--muted);
}
.hero-home h1 {
  font-size: clamp(42px, 6.2vw, 72px); line-height: 1.06; font-weight: 700;
  letter-spacing: -0.02em; max-width: none; margin-top: 18px;
}
.hero-home .lead { font-size: 20px; margin: 18px auto 0; max-width: 640px; }

.chip-row {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 10px;
  margin-top: 26px;
}
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13.5px; font-weight: 500; color: var(--ink);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 999px; padding: 7px 14px; box-shadow: var(--shadow-1);
  white-space: nowrap;
}
.chip .ic { width: 15px; height: 15px; color: var(--good-text); vertical-align: 0; }

/* The one action: a single click into the real register flow. No email
   field — the static site never captured it, only carried it along. */
.hero-signup {
  display: flex; gap: 10px; justify-content: center; align-items: stretch;
  margin: 32px auto 0; max-width: 560px;
}
.hero-signup .cta {
  font-size: 15.5px; padding: 0 24px; height: 54px; border-radius: 12px;
  cursor: pointer; font-family: var(--font-display);
}
.hero-signup .cta:hover { transform: translateY(-1px); box-shadow: 0 2px 4px rgba(11,12,14,0.12), 0 10px 24px rgba(37,99,235,0.32); }
.cta .ic.arrow {
  width: 0; opacity: 0; margin-left: -8px;
  transition: width 0.18s ease, opacity 0.18s ease, margin 0.18s ease;
}
.cta:hover .ic.arrow { width: 17px; opacity: 1; margin-left: 0; }
.hero-home .trust { margin-top: 14px; }
.hero-home .trust .ic.star {
  width: 15px; height: 15px; color: var(--warn-text);
  margin: 0 10px; vertical-align: -2px;
}

/* The stage: the frame overlaps into the section below, monday-style. */
.hero-stage {
  position: relative; max-width: 960px; margin: 56px auto -76px;
  z-index: 2;
}
.browser-frame {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 18px; overflow: hidden;
  box-shadow: 0 2px 6px rgba(11, 12, 14, 0.06), 0 32px 80px rgba(11, 12, 14, 0.16);
}
.browser-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 12px 16px; border-bottom: 1px solid var(--border);
  background: var(--canvas);
}
.browser-bar .dot { width: 10px; height: 10px; border-radius: 50%; background: var(--border); }
.browser-url {
  margin: 0 auto; font-size: 12px; color: var(--faint);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 999px; padding: 3px 14px;
}
.browser-frame video {
  display: block; width: 100%; height: auto;
  aspect-ratio: 16 / 10; object-fit: cover;
}

/* Chapter nav riding the film: pills across the frame's top, under the
   chrome bar, mirroring the film's own step chips. State follows playback:
   done = blue, current = green at full size (everything else runs smaller),
   unstarted = white and gray, any hover = orange. JS-only. */
.video-chapters {
  display: none;
  position: absolute; left: 0; right: 0; top: 56px; z-index: 3;
  justify-content: center; align-items: center; gap: 8px; padding: 0 12px;
}
html.js .video-chapters { display: flex; }
.vchap {
  font: inherit; font-family: var(--font-display);
  font-size: 11px; font-weight: 600; color: var(--muted);
  background: rgba(255, 255, 255, 0.9);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  border: 1px solid var(--border); border-radius: 999px;
  padding: 5px 11px; cursor: pointer;
  box-shadow: 0 2px 8px rgba(11, 12, 14, 0.10);
  transition: font-size .2s ease, padding .2s ease, color .15s ease,
              background-color .15s ease, border-color .15s ease, transform .15s ease;
}
.vchap.done { color: #fff; background: var(--primary); border-color: transparent; }
.vchap.on {
  color: #fff; background: var(--good); border-color: transparent;
  font-size: 13px; padding: 7px 14px;
  animation: hh-chip-pop .38s cubic-bezier(0.2, 0, 0, 1.4);
}
.vchap:hover {
  color: #fff; background: var(--warn); border-color: transparent;
  transform: translateY(-2px);
}
@keyframes hh-chip-pop {
  from { transform: scale(0.92); }
  60%  { transform: scale(1.08); }
  to   { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .vchap.on { animation: none; }
  .vchap:hover { transform: none; }
}

/* The result cards floating on the frame's corners — sample numbers, and
   they say so. Decoration for sighted skimmers; aria-hidden for the rest. */
.result-card {
  position: absolute; display: flex; align-items: center; gap: 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px; padding: 14px 18px; box-shadow: var(--shadow-2);
  text-align: left;
}
.result-card .ic-tile { margin-bottom: 0; }
.result-card strong {
  display: block; font-size: 20px; font-weight: 700; letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums; line-height: 1.15;
  font-family: var(--font-display);
}
.result-card span + div, .result-card div span {
  display: block; font-size: 12px; color: var(--muted);
}
.rc-jobs { top: 52px; left: -60px; }
.rc-margin { bottom: 46px; right: -60px; }

.proof-line {
  text-align: center; font-size: 12.5px; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint);
  margin-bottom: 56px;
}
section.after-hero { padding-top: 132px; }

/* Entrance: fade+rise, staggered by the d1–d4 classes; the frame settles
   from 0.985. Opacity/transform only, starting immediately — nothing here
   waits on anything, so the LCP paint is the first animation frame. */
html.js .hero-home .rise { opacity: 0; animation: hero-rise 0.55s ease forwards; }
html.js .hero-home .d1 { animation-delay: 0.06s; }
html.js .hero-home .d2 { animation-delay: 0.14s; }
html.js .hero-home .d3 { animation-delay: 0.22s; }
html.js .hero-home .d4 { animation-delay: 0.3s; }
html.js .hero-home .chip-row .chip { opacity: 0; animation: hero-rise 0.4s ease forwards; }
html.js .hero-home .chip-row .chip:nth-child(1) { animation-delay: 0.26s; }
html.js .hero-home .chip-row .chip:nth-child(2) { animation-delay: 0.3s; }
html.js .hero-home .chip-row .chip:nth-child(3) { animation-delay: 0.34s; }
html.js .hero-home .chip-row .chip:nth-child(4) { animation-delay: 0.38s; }
html.js .hero-home .chip-row .chip:nth-child(5) { animation-delay: 0.42s; }
html.js .hero-home .chip-row .chip:nth-child(6) { animation-delay: 0.46s; }
html.js .browser-frame { transform: scale(0.985); opacity: 0; animation: hero-settle 0.7s ease 0.2s forwards; }
/* The result cards used to land at 0.85s and 1.05s, which made a decorative
   corner card the last thing to move — so the eye's resting point after load
   was the corner opposite the button. They now settle inside the copy's own
   window and the CTA is the last thing that changes. */
html.js .result-card { opacity: 0; animation: hero-rise 0.55s ease forwards; }
html.js .rc-jobs { animation-delay: 0.5s; }
html.js .rc-margin { animation-delay: 0.58s; }
@keyframes hero-rise {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}
@keyframes hero-settle {
  from { opacity: 0; transform: scale(0.985) translateY(10px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  html.js .hero-home .rise, html.js .hero-home .chip-row .chip,
  html.js .browser-frame, html.js .result-card {
    animation: none; opacity: 1; transform: none;
  }
}


/* The stacked, centred hero is the truth below 1081px; the wide two-column
   arrangement lives in the @media (min-width: 1081px) block further down.
   A second, near-identical block at 1100px used to fight it for the same
   properties — it is gone. */

/* ----------------------------------------------------------------- sections */
section { padding: 76px 0; }
section.alt { background: var(--canvas); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
section.alt + footer, section.alt + section.alt { border-top: none; }
h2 { font-size: 34px; font-weight: 700; line-height: 1.22; max-width: 780px; letter-spacing: -0.015em; text-wrap: balance; }
h3 { font-size: 20px; font-weight: 600; margin-bottom: 8px; letter-spacing: -0.01em; }
.lead { font-size: 19px; color: var(--muted); margin-top: 14px; max-width: 720px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 20px; margin-top: 44px; }
.card {
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  padding: 26px; box-shadow: var(--shadow-1);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.card:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); border-color: #dde1e6; }
.card p { color: var(--muted); font-size: 16px; line-height: 1.6; }
.badge {
  display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600;
  letter-spacing: 0.05em; text-transform: uppercase; border-radius: 999px;
  padding: 4px 11px; margin-bottom: 12px;
}
.badge .ic { width: 13px; height: 13px; vertical-align: 0; }
.badge.built { background: var(--good-bg); color: var(--good-text); }
.badge.soon { background: var(--warn-bg); color: var(--warn-text); }

/* Checklist rows with SVG checks instead of pseudo-element glyphs. */
ul.checks { list-style: none; margin: 26px 0; text-align: left; }
ul.checks li {
  padding: 9px 0; border-bottom: 1px solid var(--subtle); font-size: 15px;
  display: flex; align-items: flex-start; gap: 10px;
}
ul.checks li .ic { width: 18px; height: 18px; color: var(--good-text); margin-top: 3px; }

/* ------------------------------------------------------------------- pricing */
.price-card {
  max-width: 500px; margin: 44px auto 0; text-align: center;
  border: 1px solid var(--border); border-radius: 16px; padding: 40px 32px;
  background: var(--surface); box-shadow: var(--shadow-2);
}
.price-card.primary { border: 2px solid var(--primary); }
.price { font-size: 48px; font-weight: 700; letter-spacing: -0.02em; }
.price small { font-size: 17px; color: var(--muted); font-weight: 500; }

/* The two-ladder pricing (ADR-004). Quota and its overage share a cell so
   the price of one more unit is visible before anyone hits a fence. */
.tier-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: 20px; margin-top: 44px; align-items: stretch; }
.tier {
  background: var(--surface); border: 1px solid var(--border); border-radius: 16px;
  padding: 28px 26px; box-shadow: var(--shadow-1); display: flex; flex-direction: column;
}
.tier.recommended { border: 2px solid var(--primary); box-shadow: var(--shadow-2); position: relative; }
.tier.recommended::before {
  content: "Recommended"; position: absolute; top: -12px; left: 50%; transform: translateX(-50%);
  background: var(--primary); color: #fff; font-size: 11px; font-weight: 600;
  letter-spacing: 0.05em; text-transform: uppercase; border-radius: 999px; padding: 4px 12px;
}
.tier h3 { font-size: 17px; color: var(--muted); font-weight: 600; }
.tier .price { font-size: 40px; margin-top: 4px; }
.tier ul { list-style: none; margin-top: 18px; }
.tier li {
  display: flex; justify-content: space-between; gap: 12px; padding: 8px 0;
  border-bottom: 1px solid var(--subtle); font-size: 14px;
}
.tier li:last-child { border-bottom: none; }
.tier li .q { color: var(--ink); font-weight: 600; text-align: right; white-space: nowrap; }
.tier li .q small { display: block; color: var(--faint); font-weight: 500; font-size: 11.5px; }
.tier li.absent { color: var(--faint); }
.tier .cta { margin-top: auto; justify-content: center; }
/* The three buttons dock at the same line whatever a card carries above
   them — the ceiling block made the cards uneven, and a button floating
   mid-card reads as an unfinished tier. `auto` does the docking; the
   margins below are the floor under the gap on the tallest card. */
.tier > ul, .tier > .ceiling { margin-bottom: 20px; }

/* The entry rung. Base is a real plan at a real price, so it keeps its card,
   its quotas and its button — what it does not keep is the visual weight of a
   recommendation. No shadow, a muted price, and a note beside the name. */
.tier.entry { box-shadow: none; background: #fbfbfc; }
.tier.entry .price { color: var(--muted); }
.tier-note {
  display: block; margin-top: 2px; font-size: 11.5px; font-weight: 500;
  color: var(--faint); text-transform: none; letter-spacing: 0;
}

/* "Where Base stops" — the ceiling block (Plan Fit §7e). Every rung below the
   top carries one, so it reads as the ladder explaining itself rather than as
   an argument against the cheap plan. Quiet ink, never a warning colour: a
   ceiling is a fact about the tier, not an alarm about the reader. */
.tier .ceiling {
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border);
}
.tier .ceiling h4 {
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--faint);
}
.tier .ceiling ul { margin-top: 8px; }
.tier .ceiling li {
  display: list-item; list-style: none; border-bottom: none;
  padding: 3px 0 3px 14px; font-size: 13px; line-height: 1.45;
  color: var(--muted); position: relative;
}
.tier .ceiling li::before {
  content: ""; position: absolute; left: 0; top: 12px;
  width: 6px; height: 1px; background: var(--faint);
}
.ladder-note {
  max-width: 620px; margin: 20px auto 0; text-align: center;
  font-size: 14px; line-height: 1.6; color: var(--muted);
}
.ladder-note strong { color: var(--ink); }
.outcome-strip {
  margin-top: 20px; padding: 14px 20px; border-radius: 12px; text-align: center;
  background: var(--good-bg); color: var(--good-text); font-weight: 600; font-size: 15px;
  border: 1px solid #bfe8cf;
}
.rate-table { width: 100%; max-width: 560px; margin: 36px auto 0; border-collapse: collapse; font-size: 15px; }
.rate-table th, .rate-table td { padding: 12px 16px; border-bottom: 1px solid var(--border); text-align: left; }
.rate-table th { font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--faint); }
.rate-table td:last-child, .rate-table th:last-child { text-align: right; font-variant-numeric: tabular-nums; }
.rate-table td strong { font-size: 17px; }
.founding {
  max-width: 720px; margin: 44px auto 0; text-align: center;
  border: 2px solid var(--warn); border-radius: 16px; padding: 36px 32px;
  background: var(--surface); box-shadow: var(--shadow-2);
}
.founding .badge { margin-bottom: 8px; }

/* --------------------------------------------------------------------- faq */
.faq-item { border-bottom: 1px solid var(--border); padding: 22px 0; max-width: 820px; }
.faq-item h3 { font-size: 17px; }
.faq-item p { color: var(--muted); font-size: 15px; margin-top: 8px; }
.no { color: var(--bad); font-weight: 600; }
.yes { color: var(--good-text); font-weight: 600; }
.notyet { color: var(--warn-text); font-weight: 600; }

/* ------------------------------------------------------------------- steps */
.step { display: flex; gap: 22px; padding: 26px 0; max-width: 860px; position: relative; }
.step-num {
  flex: none; width: 44px; height: 44px; border-radius: 12px; background: var(--primary-soft);
  color: var(--primary); font-weight: 700; display: flex; align-items: center; justify-content: center;
  position: relative; z-index: 1;
}
/* The rail that joins the step numbers into one loop. */
.step::before {
  content: ""; position: absolute; left: 21px; top: 70px; bottom: -26px;
  width: 2px; background: var(--border);
}
.step:last-of-type::before { display: none; }
.step p { color: var(--muted); font-size: 15px; }
.step .badge { margin: 8px 8px 0 0; }

/* ------------------------------------------------------------------- legal */
.legal-body { max-width: 780px; white-space: pre-wrap; font-size: 15px; color: var(--ink); }
.draft-note {
  background: var(--warn-bg); color: var(--warn-text); border-radius: 10px; padding: 12px 16px;
  font-size: 14px; font-weight: 600; margin: 24px 0; max-width: 780px;
}

/* ------------------------------------------------------------------ footer */
footer { background: var(--canvas); color: var(--muted); padding: 56px 0 48px; font-size: 14px; border-top: 1px solid var(--border); }
footer .cols { display: flex; justify-content: space-between; gap: 32px; flex-wrap: wrap; }
footer strong { letter-spacing: 0.02em; color: var(--ink); }
footer a { color: var(--muted); text-decoration: none; display: block; margin-top: 8px; transition: color 0.15s ease; }
footer a:hover { color: var(--ink); }
footer .fine { margin-top: 36px; padding-top: 20px; border-top: 1px solid var(--border); font-size: 12px; color: var(--faint); }

/* ------------------------------------------------- reveal-on-scroll (site.js)
   site.js stamps <html class="js"> and flips .reveal → .shown as cards enter
   the viewport. Without JS (or with reduced motion) everything is simply
   visible — the animation is decoration, never a gate. */
html.js .reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.5s ease, transform 0.5s ease; }
html.js .reveal.shown { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html.js .reveal { opacity: 1; transform: none; transition: none; }
  .card, .cta { transition: none; }
  .card:hover, .cta:hover { transform: none; }
}

/* ------------------------------------------------------------------ mobile */
@media (max-width: 980px) {
  .hero-grid { grid-template-columns: 1fr; gap: 48px; }
  .hero-visual { max-width: 400px; }
}

/* The chrome bar occupies the frame's first ~49px and the chapter pills the
   next ~40px. Both cards used to be dropped straight onto that band — at
   1280 the jobs card covered the traffic-light dots outright. They clear it
   now, on every arrangement. */
@media (max-width: 1080px) {
  .rc-jobs { left: 12px; top: 108px; }
  .rc-margin { right: 12px; bottom: -18px; }
}

@media (max-width: 720px) {
  .hero { padding: 44px 0 56px; }
  .hero h1 { font-size: 32px; }
  .hero.hero-home { padding-top: 28px; }
  /* Was 42px over six hard-broken lines: 267px of headline, which pushed the
     only button to y=823 in an 844px viewport and the product past the
     second screen. */
  .hero-home h1 { font-size: 33px; line-height: 1.14; }
  .hero-home h1 br { display: none; }
  .hero-home .lead { font-size: 16.5px; margin-top: 14px; }
  .hero-home .lead .line { display: inline; }
  /* The stack that fits: pitch, ask, reassurance, then the qualifier chips —
     the trades list is a filter, and a filter belongs after the offer. */
  .hero-center { display: flex; flex-direction: column; }
  /* A flex item's min-width is `auto`, so the horizontally-scrolling chip
     row grew to its content width (~700px) and took the page with it. */
  .hero-center > * { min-width: 0; max-width: 100%; }
  .hero-center .eyebrow { order: 0; }
  .hero-center h1 { order: 1; }
  .hero-center .lead { order: 2; }
  .hero-center .hero-signup { order: 3; margin-top: 22px; }
  .hero-center .trust { order: 4; margin-top: 12px; }
  /* The store row is a flex item with no order of its own, which would
     park it at 0 beside the eyebrow. It sits where it reads: under the
     reassurance, above the trades filter. */
  .hero-center .store-line { order: 5; margin-top: 18px; }
  .hero-center .chip-row { order: 6; margin-top: 20px; }
  /* Chips scroll sideways instead of stacking six deep. */
  .chip-row { flex-wrap: nowrap; overflow-x: auto; justify-content: flex-start;
    padding-bottom: 6px; margin-left: -24px; margin-right: -24px;
    padding-left: 24px; padding-right: 24px; scrollbar-width: none; }
  .chip-row::-webkit-scrollbar { display: none; }
  .hero-signup { flex-direction: column; gap: 12px; }
  .hero-signup .cta { justify-content: center; }
  .hero-stage { margin: 28px auto -48px; }
  .rc-jobs { display: none; }
  /* Chapters flow between the chrome bar and the video instead of covering
     it: the frame becomes a column and the nav slots in at order 1. */
  .browser-frame { display: flex; flex-direction: column; }
  .browser-frame video { order: 2; }
  /* Owner direction 2026-08-23: on a phone the five chapters are one long
     bullet list, not a ragged wrap. They were wrapping into 10px pills with
     no usable tap target — a control smaller than a thumb is decoration. Full
     width, one per row, 40px high, and the type is readable again. */
  .video-chapters {
    position: static; order: 1; display: flex; flex-direction: column;
    flex-wrap: nowrap; padding: 12px 10px 4px; gap: 8px;
  }
  html.js .video-chapters { display: flex; }
  .vchap { width: 100%; min-height: 40px; font-size: 13.5px; padding: 10px 14px; }
  .vchap.on { font-size: 13.5px; padding: 10px 14px; }
  /* The card floats over the video's lower-right, clear of the pill row. */
  .rc-margin { right: 8px; bottom: 72px; padding: 10px 14px; }
  .rc-margin strong { font-size: 16px; }
  section.after-hero { padding-top: 96px; }
  h2 { font-size: 26px; }
  section { padding: 56px 0; }

  .nav-toggle { display: inline-flex; }
  nav.site {
    display: none; position: absolute; top: 72px; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--surface); border-bottom: 1px solid var(--border);
    padding: 8px 24px 16px; box-shadow: var(--shadow-2);
  }
  /* 44px is the tap-target floor; 12px of padding on a 16px line left
     these at 42px. */
  nav.site a { padding: 13px 0; font-size: 16px; min-height: 44px;
    display: flex; align-items: center; border-bottom: 1px solid var(--subtle); }
  nav.site a.cta { margin-top: 12px; justify-content: center; border-bottom: none; }
  body.nav-open nav.site { display: flex; }
  body.nav-open { overflow: hidden; }
}

/* ---- Hero highlights and the animated CTA (owner, 2026-08-20) ----
   The semantic triad lands on the exact words: blue = spend, orange = the
   work, green = the money. The hero CTA rests blue, sweeps an orange
   gradient once per cycle (the monday-style shimmer), and pops green on
   hover. Motion is removed for reduced-motion users. */
.hl-blue { color: var(--primary); }
.hl-orange { color: var(--warn-text); }
.hl-green { color: var(--good-text); }

/* The flash is ORANGE again — owner decision 2026-08-23, reversing the
   2026-08-20 sheen — but in the palette's TYPE orange. The original failure
   was the fill orange: white on #ff751f is 2.69:1. The band that travels now
   is --warn-text #c2410c, which holds white at 5.18:1 at the deepest point,
   so the flash reads as orange without the label ever dropping below AA.
   With the green hover below, the button walks the site's whole semantic
   arc: rests blue (spend) → flashes orange (the work) → lands green on
   hover (the money). The button is the thread in miniature. */
/* a.cta's `background:` shorthand is (0,1,1) and pending-substitution wipes
   every background longhand — a bare .cta-pulse (0,1,0) silently loses and
   the flash never renders. Found 2026-08-23; both selectors below outrank it. */
a.cta-pulse, .cta.cta-pulse {
  background-image: linear-gradient(100deg,
    var(--primary) 0%, var(--primary) 38%,
    var(--warn-text) 50%,
    var(--primary) 62%, var(--primary) 100%);
  background-size: 300% 100%;
  background-position: 100% 0;
  animation: hh-cta-sweep 7s ease-in-out infinite;
  transition: transform .18s ease, box-shadow .18s ease, background-color .18s ease;
}
/* Percentage background-position runs the band opposite to the numbers:
   100% -> 0% is what travels left-to-right. */
@keyframes hh-cta-sweep {
  0%, 70% { background-position: 100% 0; }
  90%, 100% { background-position: 0% 0; }
}
/* Hover is GREEN and grows — owner decision 2026-08-23, reversing the
   2026-08-20 revert. The old failure was the fill green (#16a34a, 3.30:1);
   the hover now lands on --good-text #15803d, white at 5.02:1 — AA holds.
   Semantically deliberate: the press is the moment the money starts. */
a.cta-pulse:hover, .cta.cta-pulse:hover {
  animation-play-state: paused;
  background-image: none;
  background: var(--good-text);
  transform: translateY(-1px) scale(1.06);
  box-shadow: 0 12px 30px rgba(21, 128, 61, 0.38);
}
.hero-home .trust .trust-bit {
  font-weight: 700; color: transparent;
  background-image: linear-gradient(100deg,
    var(--ink) 0%, var(--ink) 38%,
    var(--warn-text) 50%,
    var(--ink) 62%, var(--ink) 100%);
  background-size: 300% 100%;
  background-position: 100% 0;
  -webkit-background-clip: text;
  background-clip: text;
  animation: hh-cta-sweep 7s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  a.cta-pulse, .cta.cta-pulse { animation: none; }
  a.cta-pulse:hover, .cta.cta-pulse:hover { transform: none; }
  .hero-home .trust .trust-bit { animation: none; color: var(--ink); background: none; }
}

/* ---- Wide two-column hero (owner, 2026-08-20) ----
   "Too much dead space left and right — monday has it almost smushed to
   the screen edge." Desktop-only: the hero becomes a near-full-bleed grid,
   copy left, video right, and the CTA row is pinned so its bottom edge
   lines up with the bottom of the browser frame (both columns stretch;
   each pins its last element to the baseline). Below 1081px the stacked
   centered hero above stays exactly as it was. */
@media (min-width: 1081px) {
  .hero.hero-home { padding: 44px 0 64px; text-align: left; }
  /* Every hero shares this container, home and interior alike. The site used
     to change width when you navigated — 1760px on the home hero, 1140px
     everywhere else — which read as two different sites. */
  .hero > .wrap {
    max-width: 1760px;
    padding: 0 clamp(28px, 2.5vw, 44px);
  }
  .hero.hero-home .wrap {
    display: grid;
    grid-template-columns: minmax(400px, 42fr) minmax(0, 58fr);
    gap: clamp(28px, 2.4vw, 56px);
    /* Was `stretch`. Stretching tied the copy column's height to the film's,
       and `margin-top: auto` on the trust line then dumped all the slack in
       the middle of the argument — a ~180px hole at 1920, right where the
       decision forms. The columns are centred against each other now and the
       copy keeps its own natural rhythm. */
    align-items: center;
  }
  .hero-center {
    max-width: none; margin: 0;
    display: flex; flex-direction: column; align-items: flex-start;
  }
  /* Was clamp(32px, 3vw, 52px) -> 43px at 1440, smaller than the 52px the
     interior pages carry. The page doing the hardest selling had the
     smallest headline. */
  /* Sized so the three authored clauses each hold their own line at the
     width this column actually gets. The bold accent words are 800 and
     run wider than the 500 base, which is what pushed the first clause
     onto a second line at 49px. */
  .hero-home h1 { font-size: clamp(40px, 3.27vw, 54px); }
  .hero-home .lead { margin: 16px 0 0; max-width: 600px; }
  .chip-row { justify-content: flex-start; }
  .hero-signup { margin: 28px 0 0; max-width: 560px; width: 100%; justify-content: flex-start; }
  /* Reassurance belongs UNDER the ask, not over it: it answers the objection
     the click creates. It used to sit above via order:1/order:2. */
  .hero-home .trust { margin-top: 14px; }
  .hero-stage { margin: 0; max-width: none; }
  /* The film is 16:10 now, so the same vertical budget buys a 20% wider
     frame — which is what actually makes the UI inside it readable. */
  .browser-frame {
    width: 100%;
    max-width: min(100%, calc((100svh - 200px) * 1.6));
    margin-left: auto;
  }
  .rc-jobs { left: -48px; top: 116px; }
  .rc-margin { right: -22px; bottom: 40px; }
  section.after-hero { padding-top: 84px; }
}

/* ---- h1 v2 weight logic + the animated underscore (owner, 2026-08-20) ----
   Only the colored words are bold; the rest of the headline runs light.
   ACTUALLY carries an orange underscore that draws in after the headline
   rises, then shimmers on the same 7s rhythm as the CTA sweep. */
/* Was 300/700. Figtree at Light loses its terminals above 40px and the base
   line read as caption-grade, so the emphasis was a cliff between two
   apparent fonts rather than a step. 500 -> 800 keeps "only the semantic
   words are bold" while giving the rest of the line a spine. */
.hero-home h1 { font-weight: 500; letter-spacing: -0.02em; }
/* The headline's line breaks are authored: one clause per line, each ending
   on its semantic colour. `text-wrap: balance` (inherited from .hero h1) was
   re-breaking clauses that already fit the column, turning a deliberate
   three-line headline into a ragged four. Below 721px the <br>s are off and
   balance is what keeps the wrap tidy, so it only steps aside above that. */
@media (min-width: 721px) {
  .hero-home h1 { text-wrap: wrap; }
}
.hero-home h1 .hl-orange, .hero-home h1 .hl-blue, .hero-home h1 .hl-green { font-weight: 800; }
.hero-home .lead .hl-orange, .hero-home .lead .hl-blue, .hero-home .lead .hl-green { font-weight: 600; }
.hero-home .lead .line { display: block; }

.hl-underscore { position: relative; white-space: nowrap; }
.hl-underscore::after {
  content: ""; position: absolute; left: 0.02em; right: 0.02em; bottom: -0.04em;
  height: 0.085em; border-radius: 999px;
  background: linear-gradient(90deg, var(--warn), #ffa768 50%, var(--warn));
  animation: hh-underscore-loop 7s ease-in-out infinite;
}
/* The loop: draws in from the left, holds through the read, wipes out to the
   right just as the CTA sweep fires (same 7s clock), then redraws. The
   transform-origin flip happens at full scale, where it is invisible. */
@keyframes hh-underscore-loop {
  0%       { transform: scaleX(0); transform-origin: left; }
  9%       { transform: scaleX(1); transform-origin: left; }
  62%      { transform: scaleX(1); transform-origin: left; }
  63%      { transform: scaleX(1); transform-origin: right; }
  72%      { transform: scaleX(0); transform-origin: right; }
  100%     { transform: scaleX(0); transform-origin: right; }
}
@media (prefers-reduced-motion: reduce) {
  .hl-underscore::after { animation: none; }
}


/* ============================================================================
   CONVERSION FURNITURE (2026-08-20, from the visual review)

   The page had one rhythm — h2, gray lead, three identical white cards — for
   four sections running, so nothing on it was ever more important than
   anything else. These components exist to give the page a crescendo, and to
   serve the reader who skims for an outcome at the same time as the one who
   verifies the mechanism. Every one of them is measured by
   scripts/check_marketing_ui.py.
   ========================================================================== */

/* Screen-reader-only text: the comparison table's cells are icons, and an
   icon with no name is an empty cell to a screen reader. */
.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ------------------------------------------------------------- proof band */
.proof-band {
  padding: 40px 0;
  background: var(--primary-soft);
  border-bottom: 1px solid var(--border);
  text-align: center;
}
.proof-band .wrap { display: flex; flex-direction: column; align-items: center; gap: 14px; }
/* Was 12.5px uppercase in --faint (2.45:1) — disclaimer typography on the
   site's strongest claim. */
.proof-line {
  font-family: var(--font-display);
  font-size: 21px; font-weight: 700; line-height: 1.3;
  letter-spacing: -0.01em; color: var(--ink); max-width: 720px;
  text-transform: none; margin: 0;
}
.cohort-count {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 15px; color: var(--primary);
  background: var(--surface); border: 1px solid #c7d9fb;
  border-radius: 999px; padding: 8px 18px;
}
.cohort-count .ic { width: 17px; height: 17px; }
.cohort-count strong { font-weight: 700; }
.proof-cite { font-size: 14px; color: var(--muted); max-width: 640px; }
.proof-cite strong { color: var(--ink); font-weight: 600; }
.proof-cite .src { color: var(--faint); }

/* -------------------------------------------------------- the number strip */
.kpi-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: 20px; margin-top: 40px;
}
.kpi {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 16px; padding: 26px 24px; box-shadow: var(--shadow-1);
  display: flex; flex-direction: column; gap: 6px;
}
.kpi-fig {
  font-family: var(--font-display);
  font-size: 42px; font-weight: 800; line-height: 1.05;
  letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}
.kpi-fig.blue { color: var(--primary); }
.kpi-fig.orange { color: var(--warn-text); }
.kpi-fig.green { color: var(--good-text); }
.kpi-label { font-size: 15px; color: var(--muted); }
.kpi-delta {
  font-size: 13px; font-weight: 600; color: var(--good-text);
  background: var(--good-bg); border-radius: 999px; padding: 3px 10px;
  align-self: flex-start; margin-top: 4px;
}
.specimen-note { margin-top: 20px; }

/* ------------------------------------------------ the before/after report */
.ba-compare {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: 24px; margin-top: 40px; align-items: stretch;
}
.ba-col {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 18px; padding: 28px 26px; display: flex; flex-direction: column;
}
.ba-col.after { border: 2px solid var(--good); box-shadow: var(--shadow-2); }
.ba-head { margin-bottom: 18px; }
.ba-tag {
  display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted); background: var(--subtle);
  border-radius: 999px; padding: 4px 11px;
}
.ba-tag.good { color: var(--good-text); background: var(--good-bg); }
.ba-head strong {
  display: block; margin-top: 10px; font-family: var(--font-display);
  font-size: 20px; font-weight: 700; letter-spacing: -0.01em;
}
.ba-col ul { list-style: none; }
.ba-col li {
  display: flex; justify-content: space-between; gap: 16px; align-items: baseline;
  padding: 11px 0; border-bottom: 1px solid var(--subtle); font-size: 15px;
  color: var(--muted);
}
.ba-col li .v { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.ba-col li.absent { color: var(--faint); }
.ba-col li.absent .v { color: var(--faint); }
.ba-col li.total {
  border: 1px solid #bfe8cf; border-radius: 12px; background: var(--good-bg);
  padding: 14px; margin-top: 10px; color: var(--good-text); font-weight: 600;
}
.ba-col li.total .v { color: var(--good-text); font-size: 22px; font-weight: 800; }
.ba-foot { margin-top: auto; padding-top: 18px; font-size: 14px; color: var(--muted); }
.ba-col.after .ba-foot { color: var(--good-text); font-weight: 600; }

/* Four cards, two at a time — a three-up auto-fit left the fourth alone. */
.grid.two { grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr)); }

/* --------------------------------------------------------- the three steps */
.step-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: 24px; margin-top: 40px;
}
.sstep { position: relative; padding-top: 8px; }
.sstep-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 12px; margin-bottom: 14px;
  background: var(--primary); color: #fff;
  font-family: var(--font-display); font-size: 18px; font-weight: 700;
}
.sstep p { color: var(--muted); font-size: 16px; }

/* ------------------------------------------------------ comparison table */
.cmp-wrap {
  margin-top: 40px; overflow-x: auto; max-width: 100%;
  /* Positioned so the .sr labels inside the cells resolve against
     this scroller instead of the initial containing block — as
     static, they escaped the clip and widened the whole page. */
  position: relative;
}
.cmp-table {
  width: 100%; min-width: 720px; border-collapse: collapse;
  background: var(--surface); border: 1px solid var(--border); border-radius: 16px;
}
.cmp-table th, .cmp-table td {
  padding: 15px 16px; border-bottom: 1px solid var(--border);
  font-size: 15px; text-align: center; vertical-align: middle;
}
.cmp-table thead th {
  font-family: var(--font-display); font-size: 13px; font-weight: 700;
  color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em;
  background: var(--canvas);
}
.cmp-table thead th span { font-weight: 500; text-transform: none; letter-spacing: 0; }
.cmp-table thead th.us { color: var(--primary); background: var(--primary-soft); }
.cmp-table tbody th {
  text-align: left; font-weight: 600; font-size: 15.5px; color: var(--ink);
  min-width: 260px;
}
.cmp-table td.y { color: var(--good-text); }
.cmp-table td.y .ic { width: 22px; height: 22px; vertical-align: -5px; }
.cmp-table td.n { color: var(--faint); font-weight: 500; }
.cmp-table td.part { color: var(--warn-text); font-size: 13.5px; font-weight: 600; }
.cmp-table td.us { background: var(--primary-soft); }
.cmp-table tbody tr:last-child th, .cmp-table tbody tr:last-child td { border-bottom: none; }

/* ------------------------------------------------------- the worked example */
.worked-example {
  margin-top: 40px; background: var(--surface); border: 1px solid var(--border);
  border-radius: 18px; padding: 32px; box-shadow: var(--shadow-1);
  max-width: 760px;
}
.worked-steps { list-style: none; counter-reset: w; }
.worked-steps li {
  display: flex; justify-content: space-between; gap: 20px; align-items: baseline;
  padding: 12px 0; border-bottom: 1px solid var(--subtle); font-size: 16px;
}
.w-label { color: var(--muted); }
.w-val {
  font-family: var(--font-display); font-weight: 700; font-size: 19px;
  font-variant-numeric: tabular-nums; color: var(--ink); white-space: nowrap;
}
.w-val.blue { color: var(--primary); }
.w-val.orange { color: var(--warn-text); }
.w-val.green { color: var(--good-text); }
.worked-steps li.w-total {
  border: 1px solid #bfe8cf; border-radius: 12px; background: var(--good-bg);
  padding: 16px; margin-top: 12px; border-bottom: none;
}
.worked-steps li.w-total .w-label { color: var(--good-text); font-weight: 600; }
.worked-steps li.w-total .w-val { font-size: 28px; font-weight: 800; }
.worked-read { margin-top: 20px; font-size: 16px; color: var(--muted); }
.worked-read strong { color: var(--good-text); font-weight: 700; }
.worked-example .specimen-chip { margin-top: 16px; }

/* ------------------------------------------------------- data-handling strip */
.trust-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 28px;
}
.ts-item { display: flex; gap: 16px; align-items: flex-start; }
.ts-item .ic-tile { margin-bottom: 0; flex: none; }
.ts-item strong { display: block; font-size: 17px; font-weight: 700; margin-bottom: 4px; }
.ts-item span { display: block; font-size: 15px; color: var(--muted); line-height: 1.55; }

/* --------------------------------------------------------------- home FAQ */
.home-faq {
  margin-top: 36px;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
  gap: 0 48px;
}
.home-faq .faq-item { max-width: none; }
.home-faq .faq-item p { font-size: 16px; }

/* ------------------------------------------------------- the closing ask */
.closing {
  /* Distinct from every band above it: this is the moment, and it used to be
     styled exactly like the four sections that preceded it. */
  background:
    radial-gradient(40% 70% at 90% 0%, rgba(37, 99, 235, 0.10), transparent 70%),
    radial-gradient(34% 60% at 4% 100%, rgba(22, 163, 74, 0.08), transparent 70%),
    linear-gradient(180deg, var(--canvas), #eef1f6);
  background-color: #eef1f6;
  border-top: 1px solid var(--border);
  padding: 84px 0 92px;
}
.closing-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) 400px;
  gap: 64px; align-items: center;
}
.closing h2 { font-size: 40px; }
.closing-price {
  margin-top: 26px; display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap;
}
.closing-price .price {
  font-family: var(--font-display); font-size: 44px; font-weight: 800;
  letter-spacing: -0.02em; color: var(--ink);
}
.closing-price .price small { font-size: 16px; font-weight: 600; color: var(--muted); }
.price-note { font-size: 14px; color: var(--muted); max-width: 300px; }
.cta-lg { font-size: 16.5px; height: 58px; padding: 0 28px; border-radius: 12px; }

/* -------------------------------------------------------- the sticky bar */
.sticky-cta {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  background: rgba(255, 255, 255, 0.94);
  -webkit-backdrop-filter: saturate(1.4) blur(12px);
  backdrop-filter: saturate(1.4) blur(12px);
  border-top: 1px solid var(--border);
  box-shadow: 0 -6px 24px rgba(11, 12, 14, 0.08);
  transform: translateY(100%);
  transition: transform 0.28s cubic-bezier(0.2, 0, 0, 1);
}
.sticky-cta.on { transform: none; }
.sticky-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; padding-top: 12px; padding-bottom: 12px;
}
.sticky-copy { font-size: 15px; color: var(--muted); min-width: 0; }
.sticky-copy strong { color: var(--ink); font-weight: 700; }
.sticky-copy span { color: var(--muted); }
.sticky-cta .cta { flex: none; height: 46px; padding: 0 20px; font-size: 15px; }
@media (prefers-reduced-motion: reduce) {
  .sticky-cta { transition: none; }
}
@media (max-width: 720px) {
  .sticky-copy span { display: none; }
  .sticky-copy { font-size: 14px; }
  .sticky-inner { gap: 14px; }
  .sticky-cta .cta { padding: 0 16px; font-size: 14px; }
  .closing-grid { grid-template-columns: 1fr; gap: 40px; }
  .closing h2 { font-size: 28px; }
  .proof-line { font-size: 18px; }
  .kpi-fig { font-size: 34px; }
  /* The sticky bar covers the last of the page otherwise. */
  footer { padding-bottom: 96px; }
}
@media (max-width: 980px) {
  .closing-grid { grid-template-columns: 1fr; gap: 40px; }
}

/* ==========================================================================
   The 2026-08-23 homepage rewrite — sections below the hero.
   Owner-set order: service advertisers, campaign optimisation, automation,
   the questions, the money and the people. The hero above is untouched.
   Every rule below reuses the §1 semantic code: blue = ad spend, orange =
   the work, green = the money. Nothing here introduces a new colour.
   ========================================================================== */

/* The small uppercase mark above an h2. Not .eyebrow — that one is the
   hero's and is muted; these carry the section's semantic colour. */
.sect-mark {
  font-size: 12px; font-weight: 700; letter-spacing: 0.14em;
  text-transform: uppercase; margin-bottom: 12px;
}
.sect-mark.blue { color: var(--primary); }
.sect-mark.green { color: var(--good-text); }
.sect-mark.orange { color: var(--warn-text); }

/* The three readers, named without labelling anyone. This page serves a
   single-business owner, a service advertiser and an agency at once, and it
   never says which one you are — so the chips carry the whole audience
   strategy and the line under them states the shared problem. */
.reader-chips {
  list-style: none; display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px;
}
.reader-chips li {
  border: 1px solid var(--warn); background: var(--surface); color: var(--ink);
  border-radius: 999px; padding: 10px 20px; font-size: 15px; font-weight: 600;
}
.reader-note { margin-top: 16px; color: var(--faint); font-size: 15px; max-width: 720px; }

/* Benefit rows: a coloured dot, a claim, and the reason. Used by the map
   section and by automation, so the colour is per-item. */
.benefit-list { list-style: none; }
.benefit-list li { position: relative; padding-left: 26px; }
.benefit-list li + li { margin-top: 26px; }
.benefit-list li::before {
  content: ""; position: absolute; left: 0; top: 12px;
  width: 10px; height: 10px; border-radius: 50%; background: var(--good);
}
.benefit-list li.bl-orange::before { background: var(--warn); }
.benefit-list li.bl-blue::before { background: var(--primary); }
.benefit-list li.bl-green::before { background: var(--good); }
.benefit-list h3 { font-size: 18px; margin-bottom: 6px; }
.benefit-list p { color: var(--muted); font-size: 15.5px; line-height: 1.6; }

/* The one literal thing on the page: a website with call tracking on it. */
.site-mock { display: block; margin-bottom: 14px; }
.sm-url {
  display: block; border: 1px solid var(--border); background: var(--subtle);
  border-radius: 5px; padding: 5px 8px; font-size: 9.5px; color: var(--primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sm-body {
  display: block; border: 1px solid var(--border); background: var(--canvas);
  border-radius: 5px; padding: 10px; margin-top: 6px;
}
.sm-bar { display: block; height: 6px; border-radius: 3px; background: var(--border); margin-bottom: 6px; }
.sm-bar.w60 { width: 60%; } .sm-bar.w90 { width: 90%; } .sm-bar.w75 { width: 75%; }
.sm-phone {
  display: inline-block; background: var(--warn-bg); color: var(--warn-text);
  border-radius: 4px; padding: 3px 7px; font-size: 10.5px; font-weight: 700; font-style: normal;
}

/* The wall. It is a rule with a label in it, not a card — the point is that
   it cuts the row of steps in two. */


/* --------------------------------------------------------- the money strip */
.money-strip {
  margin-top: 40px; background: var(--good-bg); border: 1px solid var(--good);
  border-radius: 16px; padding: 34px; display: grid; gap: 32px;
  grid-template-columns: minmax(0, 1fr) minmax(0, 420px); align-items: center;
}
.money-strip h3 { font-size: 26px; color: var(--good-text); margin-bottom: 10px; }
.money-strip p { color: var(--good-text); font-size: 15.5px; line-height: 1.6; max-width: 560px; }
.ms-bars {
  display: flex; align-items: flex-end; gap: 10px; height: 132px; position: relative;
  padding-bottom: 22px;
}
.ms-bars i { flex: 1; background: var(--good); border-radius: 4px 4px 0 0; }
.ms-from, .ms-to {
  position: absolute; bottom: 0; font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--good-text);
}
.ms-from { left: 0; } .ms-to { right: 0; }

/* ------------------------------------------------------------- automation */
.auto-grid {
  display: grid; grid-template-columns: 320px minmax(0, 1fr);
  gap: 56px; align-items: center; margin-top: 44px;
}
.phone {
  border: 1px solid var(--border); border-radius: 26px; background: var(--surface);
  padding: 34px 14px 16px; box-shadow: var(--shadow-2); position: relative;
}
.ph-notch {
  position: absolute; top: 14px; left: 50%; transform: translateX(-50%);
  width: 96px; height: 12px; border-radius: 999px; background: var(--subtle);
}
.ph-screen { background: var(--canvas); border: 1px solid var(--border); border-radius: 14px; padding: 14px 12px; }
.ph-head {
  font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 12px;
}
.bub {
  border-radius: 12px; padding: 10px 12px; font-size: 13px; line-height: 1.45;
  margin-bottom: 9px; max-width: 86%;
}
/* Only the opening line of a ticket is its own line. A blanket block rule
   here split "Status moved to <strong>On site</strong>. Photo attached."
   into three lines with an orphaned full stop. */
.bub strong { font-weight: 700; }
.bub > strong:first-child { display: block; }
.bub.in { background: var(--surface); border: 1px solid var(--border); color: var(--muted); }
.bub.out { background: var(--good-bg); border: 1px solid var(--good); color: var(--good-text); margin-left: auto; }

/* -------------------------------------------------------- the question grid */
.qa-grid {
  list-style: none; display: grid; gap: 20px; margin-top: 44px;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}
.qa-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  padding: 24px; box-shadow: var(--shadow-1); position: relative;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.qa-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); }
.qa-card::before {
  content: ""; display: block; width: 10px; height: 10px; border-radius: 50%;
  margin-bottom: 14px; background: var(--good);
}
.qa-card.qa-orange::before { background: var(--warn); }
.qa-card.qa-blue::before { background: var(--primary); }
.qa-card h3 { font-size: 18px; line-height: 1.35; margin-bottom: 14px; }
.qa-card p {
  color: var(--muted); font-size: 14.5px; line-height: 1.55;
  border-top: 1px solid var(--subtle); padding-top: 14px;
}

/* ------------------------------------------- the money and the people (5) */
.sub-mark {
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--good-text); margin-top: 64px;
}
.sub-head { font-size: 26px; font-weight: 700; margin: 8px 0 28px; letter-spacing: -0.01em; }

.fin-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 48px; align-items: start;
}
.fin-report, .stat-card, .fullpic {
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  padding: 28px; box-shadow: var(--shadow-1);
}
.fr-title { font-size: 18px; font-weight: 700; }
.fr-sub { font-size: 12.5px; color: var(--faint); margin-top: 5px; }
.fr-foot { font-size: 13px; color: var(--faint); margin-top: 18px; }
.fr-rows { margin-top: 22px; }
.fr-rows > div {
  display: flex; justify-content: space-between; align-items: center; gap: 16px;
  padding: 11px 0 11px 14px; border-bottom: 1px solid var(--subtle); position: relative;
}
/* The three lines nothing else can fill in. The marker is the argument. */
.fr-rows .fr-only::before {
  content: ""; position: absolute; left: 0; top: 8px; bottom: 8px;
  width: 3px; border-radius: 2px; background: var(--good);
}
.fr-rows dt { color: var(--muted); font-size: 15px; }
.fr-rows dd { font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
.fr-rows dd.blue { color: var(--primary); }
.fr-rows dd.green { color: var(--good-text); }
.fr-total {
  display: flex; justify-content: space-between; align-items: center;
  background: var(--good-bg); border-radius: 10px; padding: 16px 18px; margin-top: 18px;
}
.fr-total span {
  font-size: 13px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--good-text);
}
.fr-total strong {
  /* The page's one biggest green moment (Homepage Scroll Story §1.3) — the
     display size the review set for the film's figures, not card-copy size. */
  font-family: var(--font-display); font-size: 36px; color: var(--good-text);
  font-variant-numeric: tabular-nums;
}
.fin-note h4 { font-family: var(--font-display); font-size: 21px; line-height: 1.3; margin-bottom: 12px; }
.fin-note p { color: var(--muted); font-size: 15.5px; line-height: 1.6; }
.fn-cap {
  font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--faint); margin-top: 30px;
}
.camp-bars { list-style: none; margin-top: 16px; }
/* Explicit placement, not auto-flow: the bar spans both columns, so with
   source order name -> bar -> value the value was pushed onto a third row
   underneath the bar instead of sitting beside the name. */
.camp-bars li {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: 6px 14px; margin-bottom: 18px;
}
.cb-name { grid-area: 1 / 1; }
.cb-val  { grid-area: 1 / 2; }
.camp-bars i { grid-area: 2 / 1 / 3 / 3; }
.cb-name { font-size: 14.5px; }
.cb-val { font-size: 14.5px; font-weight: 600; color: var(--good-text); font-variant-numeric: tabular-nums; }
.camp-bars i { height: 14px; border-radius: 4px; background: var(--good); }

.stat-two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; }
.perf-list { list-style: none; margin-top: 20px; }
.perf-list li {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 12px;
  border-radius: 10px; padding: 12px 14px; margin-bottom: 10px;
}
.perf-list li.ok { background: var(--good-bg); }
.perf-list li.bad { background: var(--bad-bg); }
.pf-name { font-size: 15.5px; font-weight: 600; }
.pf-val { font-family: var(--font-display); font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums; }
.pf-note { grid-column: 1 / -1; font-size: 12px; }
.perf-list li.ok .pf-val, .perf-list li.ok .pf-note { color: var(--good-text); }
.perf-list li.bad .pf-val, .perf-list li.bad .pf-note { color: var(--bad); }

.closer { width: 100%; border-collapse: collapse; margin-top: 20px; font-size: 14px; }
.closer th, .closer td { padding: 9px 8px; text-align: center; }
.closer thead th { font-size: 11.5px; color: var(--faint); font-weight: 600; }
.closer tbody th { text-align: left; font-weight: 600; }
.closer td {
  background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
  color: var(--muted); font-variant-numeric: tabular-nums;
}
.closer td.hi { background: var(--good-bg); border-color: var(--good); color: var(--good-text); font-weight: 700; }

.fullpic { padding: 0; overflow: hidden; }
.fp-head {
  display: flex; justify-content: space-between; align-items: center; gap: 20px;
  background: var(--canvas); border-bottom: 1px solid var(--border); padding: 20px 28px;
}
.fp-title { font-size: 17px; font-weight: 700; }
.fp-total { text-align: right; }
.fp-total span {
  display: block; font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--faint);
}
.fp-total strong { font-family: var(--font-display); font-size: 26px; color: var(--good-text); }
.fp-scroll { overflow-x: auto; }
.fp-table { width: 100%; border-collapse: collapse; min-width: 640px; }
.fp-table th, .fp-table td { padding: 14px 12px; text-align: left; font-size: 14px; }
.fp-table thead th {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--faint); padding-top: 18px;
}
.fp-table th:first-child, .fp-table td:first-child { padding-left: 28px; }
.fp-table th:last-child, .fp-table td:last-child { padding-right: 28px; text-align: right; }
.fp-table tbody tr { border-top: 1px solid var(--subtle); }
.fp-table tbody th { font-weight: 600; font-size: 15px; }
.fp-table td { color: var(--muted); font-variant-numeric: tabular-nums; }
.fp-table .fb { display: block; height: 10px; border-radius: 3px; margin-bottom: 6px; }
.fp-table .fb.blue { background: var(--primary); }
.fp-table .fb.green { background: var(--good); }
.fp-left { font-family: var(--font-display); font-size: 17px; font-weight: 700; color: var(--good-text) !important; }
.fullpic .fr-foot { padding: 0 28px 22px; }

/* ------------------------------------------------------------- responsive */
@media (max-width: 1080px) {
  .net-grid, .fin-grid { grid-template-columns: 1fr; gap: 40px; }
  .auto-grid { grid-template-columns: 280px minmax(0, 1fr); gap: 36px; }
  .money-strip { grid-template-columns: 1fr; }
  .ms-bars { height: 110px; }
}
@media (max-width: 860px) {
  .stat-two { grid-template-columns: 1fr; }
  .auto-grid { grid-template-columns: 1fr; }
  .phone { max-width: 320px; margin: 0 auto; }
}
@media (max-width: 720px) {
  .sect-mark { font-size: 11px; }
  .reader-chips { gap: 10px; }
  .reader-chips li { width: 100%; font-size: 14.5px; padding: 12px 18px; }
  .money-strip { padding: 24px; }
  .money-strip h3 { font-size: 22px; }
  .sub-mark { margin-top: 48px; }
  .sub-head { font-size: 22px; }
  .fin-report, .stat-card { padding: 22px; }
  .fr-total strong { font-size: 24px; }
  .fp-head { padding: 16px 20px; }
  .fp-total strong { font-size: 21px; }
  .fp-table th:first-child, .fp-table td:first-child { padding-left: 20px; }
  .fp-table th:last-child, .fp-table td:last-child { padding-right: 20px; }
  .fullpic .fr-foot { padding: 0 20px 18px; }
}
@media (prefers-reduced-motion: reduce) {
  .qa-card { transition: none; }
  .qa-card:hover { transform: none; }
}

/* ==========================================================================
   The scroll story (2026-08-23) — Homepage Scroll Story.md is the spec.
   The law it obeys is Motion Design for Attention: one onset per beat, on
   the key element, in a calm frame; green is spent once per act; entrances
   decelerate; transform/opacity only; reduced motion stops everything.
   ========================================================================== */

/* ---- The scan layer ------------------------------------------------------
   Three skimmable objects per section: the mark, the h2, and the payoff —
   the benefit in one bold colored sentence, always the section's last
   element. The 3-second read of the whole page is the payoffs in sequence. */
.payoff {
  font-family: var(--font-display); font-size: 21px; font-weight: 700;
  letter-spacing: -0.01em; margin-top: 40px;
}
.pf-blue { color: var(--primary); }
.pf-green { color: var(--good-text); }
.pf-orange { color: var(--warn-text); }

/* The proof band's number at display size — the page's first live figure. */
.proof-fig {
  font-family: var(--font-display); font-size: 42px; font-weight: 800;
  letter-spacing: -0.02em; color: var(--good-text); margin-top: 10px;
}
.qa-card p strong { color: var(--ink); font-weight: 700; }

/* ---- The thread ----------------------------------------------------------
   One thin line runs down the page between acts: blue at the top (spend),
   orange through the middle (the work), green at the climax (the money).
   Each segment draws itself as its section arrives. Static (fully drawn)
   wherever scroll-driven animations are unsupported or motion is reduced. */
.thread { display: flex; justify-content: center; height: 96px; margin: -20px 0 8px; }
.thread svg { height: 96px; width: 8px; overflow: visible; }
.thread path { fill: none; stroke-width: 2.5; stroke-linecap: round; }
.th-blue path { stroke: var(--primary); }
.th-orange path { stroke: var(--warn); }
.th-green path { stroke: var(--good); }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    html.js .thread path {
      stroke-dasharray: 96; stroke-dashoffset: 96;
      animation: th-draw linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 90%;
    }
  }
}
@keyframes th-draw { to { stroke-dashoffset: 0; } }

/* ---- Quiet reveals for the new furniture --------------------------------
   Rows, bars and cells enter with the same .reveal/.shown contract the
   cards already use (site.js owns the IO). Bars grow from zero when their
   row lands; the transition, not a keyframe, so reduced-motion (which never
   adds .reveal) shows everything at rest. */
html.js .camp-bars li.reveal i,
html.js .fp-table tr.reveal .fb { transform: scaleX(0); transform-origin: 0 50%; }
html.js .camp-bars li.reveal.shown i,
html.js .fp-table tr.reveal.shown .fb {
  transform: scaleX(1);
  transition: transform 0.7s cubic-bezier(0.16, 1, 0.3, 1) 0.15s;
}
html.js .fr-rows > div.reveal::before { transform: scaleY(0); transform-origin: 0 0; }
html.js .fr-rows > div.reveal.shown::before {
  transform: scaleY(1); transition: transform 0.45s cubic-bezier(0.16, 1, 0.3, 1) 0.2s;
}
html.js .ms-bars i { transform: scaleY(1); transform-origin: 50% 100%; }
html.js .money-strip.reveal .ms-bars i { transform: scaleY(0); }
html.js .money-strip.reveal.shown .ms-bars i {
  transform: scaleY(1); transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
html.js .money-strip.reveal.shown .ms-bars i:nth-child(2) { transition-delay: 70ms; }
html.js .money-strip.reveal.shown .ms-bars i:nth-child(3) { transition-delay: 140ms; }
html.js .money-strip.reveal.shown .ms-bars i:nth-child(4) { transition-delay: 210ms; }
html.js .money-strip.reveal.shown .ms-bars i:nth-child(5) { transition-delay: 280ms; }
html.js .money-strip.reveal.shown .ms-bars i:nth-child(6) { transition-delay: 350ms; }
html.js .money-strip.reveal.shown .ms-bars i:nth-child(7) { transition-delay: 420ms; }
html.js .money-strip.reveal.shown .ms-bars i:nth-child(8) { transition-delay: 490ms; }

/* The discord note: the one red onset on the page. The $0.80 row waits for
   the two green rows to settle, then enters alone. site.js sets the delay. */

/* The single overshoot a scene is allowed (≤4%): the reader chips. */
html.js .reader-chips li.reveal { opacity: 0; transform: translateY(10px); }
html.js .reader-chips li.reveal.shown {
  opacity: 1; transform: none;
  transition: opacity 0.4s ease, transform 0.5s cubic-bezier(0.34, 1.4, 0.64, 1);
}

/* ---- Act 2: the report run (owner, 2026-08-23 — replaces the station
   journey). The page's ONE pin. While the stage holds, ~200vh of scroll
   drives: the paid rows pop → the table compresses into the export file →
   the file flies to the Google Ads node → it lands, "Received" → the money
   bars grow. Everywhere the pin does not run (small screens, no
   scroll-timeline, reduced motion, no JS) the scene is static and complete:
   full table, no chip, node and bars at rest. */
.xf-file { display: none; }
.xf-recv { display: block; font-size: 12px; color: var(--good-text); margin-top: 4px; }
.xf-recv .ic { width: 13px; height: 13px; vertical-align: -2px; }
@supports (animation-timeline: view()) {
  @media (min-width: 1081px) and (min-height: 640px) and (prefers-reduced-motion: no-preference) {
    html.js .opt-track { height: 260vh; view-timeline: --opt block; }
    html.js .opt-stage {
      position: sticky;
      top: max(84px, calc(50vh - 380px));
    }
    html.js .opt-track .xfer { position: relative; }
    /* 1 · the paid rows pop, one at a time */
    html.js .opt-track .xr-win {
      animation-name: opt-winpop; animation-timing-function: cubic-bezier(0.34, 1.4, 0.64, 1);
      animation-fill-mode: both; animation-timeline: --opt;
    }
    html.js .opt-track .xr-win:nth-of-type(2) { animation-range: contain 6% contain 12%; }
    html.js .opt-track .xr-win:nth-of-type(5) { animation-range: contain 11% contain 17%; }
    html.js .opt-track .xr-win:nth-of-type(7) { animation-range: contain 16% contain 22%; }
    /* 2 · the table compresses into the file */
    html.js .opt-track .xfer-card {
      transform-origin: 50% 42%;
      animation-name: opt-squash; animation-timing-function: cubic-bezier(0.6, 0, 0.8, 1);
      animation-fill-mode: both; animation-timeline: --opt;
      animation-range: contain 26% contain 36%;
    }
    html.js .opt-track .xf-file {
      display: inline-flex; align-items: center; gap: 8px;
      position: absolute; left: 50%; top: 34%; z-index: 3;
      font-family: var(--font-display); font-weight: 700; font-size: 15px;
      color: var(--ink); background: var(--surface);
      border: 1px solid var(--good); border-radius: 999px;
      padding: 10px 18px; box-shadow: var(--shadow-2);
      animation-name: opt-fly; animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
      animation-fill-mode: both; animation-timeline: --opt;
      animation-range: contain 28% contain 58%;
    }
    /* Google comes UP to the file (owner, 2026-08-23): dropping the chip
       toward the node ran it into the sticky ask at the bottom. Instead the
       node column rides up to meet the chip where the table stood, receives,
       and then dims as the strip takes the stage. The arrow keeps pointing
       DOWN even while the column rides up: the reader is scrolling down, and
       the story flows with the scroll. */
    html.js .opt-track .xfer-fly {
      animation-name: opt-meet; animation-timing-function: cubic-bezier(0.3, 0, 0.4, 1);
      animation-fill-mode: both; animation-timeline: --opt;
      animation-range: contain 36% contain 76%;
    }
    html.js .opt-track .xf-file .ic { width: 17px; height: 17px; color: var(--good-text); }
    /* 3 · the arrow draws under the flight */
    html.js .opt-track .xf-line {
      stroke-dasharray: 1; stroke-dashoffset: 1;
      animation: th-draw linear both; animation-timeline: --opt;
      animation-range: contain 34% contain 50%;
    }
    /* 4 · Google receives */
    html.js .opt-track .xf-node {
      animation: opt-recv linear both; animation-timeline: --opt;
      animation-range: contain 52% contain 60%;
    }
    html.js .opt-track .xf-recv {
      animation: stk-fade linear both; animation-timeline: --opt;
      animation-range: contain 54% contain 62%;
    }
    /* 5 · the money grows — the act's green finale */
    html.js .opt-track .money-strip.reveal .ms-bars i,
    html.js .opt-track .money-strip.reveal.shown .ms-bars i {
      transition: none;
      transform: scaleY(0); transform-origin: 50% 100%;
      animation-name: opt-bar;
      animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
      animation-fill-mode: both;
      animation-timeline: --opt;
    }
    html.js .opt-track .money-strip .ms-bars i:nth-child(1) { animation-range: contain 78% contain 86%; }
    html.js .opt-track .money-strip .ms-bars i:nth-child(2) { animation-range: contain 80% contain 88%; }
    html.js .opt-track .money-strip .ms-bars i:nth-child(3) { animation-range: contain 82% contain 90%; }
    html.js .opt-track .money-strip .ms-bars i:nth-child(4) { animation-range: contain 84% contain 92%; }
    html.js .opt-track .money-strip .ms-bars i:nth-child(5) { animation-range: contain 86% contain 94%; }
    html.js .opt-track .money-strip .ms-bars i:nth-child(6) { animation-range: contain 88% contain 96%; }
    html.js .opt-track .money-strip .ms-bars i:nth-child(7) { animation-range: contain 90% contain 97%; }
    html.js .opt-track .money-strip .ms-bars i:nth-child(8) { animation-range: contain 92% contain 98%; }
    /* Pinned, the whole column must fit one viewport: the stage compacts
       (paddings, arrow, type) to ~900px. The static/mobile layout keeps its
       comfortable spacing — these rules live only inside the pin. */
    html.js .opt-stage { top: max(56px, calc(50vh - 470px)); }
    html.js .opt-track .xfer { gap: 10px; margin-top: 24px; }
    html.js .opt-track .xfer-card { padding: 12px 18px; }
    html.js .opt-track .xfer-table th, html.js .opt-track .xfer-table td { padding: 6px 10px; font-size: 13.5px; }
    html.js .opt-track .xfer-table tbody th span { font-size: 11px; }
    html.js .opt-track .xfer-card .fr-foot { margin-top: 6px; font-size: 12px; }
    html.js .opt-track .xfer-card .specimen-chip { margin-top: 4px; }
    html.js .opt-track .xf-arrow { height: 56px; margin-bottom: 6px; }
    html.js .opt-track .xf-cap { margin-top: 8px; font-size: 12.5px; max-width: 320px; }
    html.js .opt-track .money-strip { margin-top: 14px; padding: 20px 26px; }
    html.js .opt-track .money-strip h3 { font-size: 20px; margin-bottom: 6px; }
    html.js .opt-track .money-strip p { font-size: 13.5px; }
    html.js .opt-track .ms-bars { height: 96px; }
  }
}
@keyframes opt-winpop {
  0% { background: var(--good-bg); }
  55% { transform: scale(1.015); background: #d3f2df; }
  100% { transform: none; background: var(--good-bg); }
}
@keyframes opt-squash {
  0% { transform: none; opacity: 1; }
  85% { opacity: 0.35; }
  100% { transform: scaleY(0.04); opacity: 0; }
}
@keyframes opt-fly {
  0% { opacity: 0; transform: translate(-50%, 0) scale(1.3); }
  16% { opacity: 1; transform: translate(-50%, 0) scale(1); }
  78% { opacity: 1; transform: translate(-50%, 0) scale(1); }
  100% { opacity: 0; transform: translate(-50%, 0) scale(0.9); }
}
@keyframes opt-meet {
  0% { transform: none; opacity: 1; }
  38%, 62% { transform: translateY(clamp(-360px, -32vh, -220px)); opacity: 1; }
  100% { transform: translateY(calc(clamp(-360px, -32vh, -220px) - 14px)); opacity: 0.12; }
}
@keyframes opt-clear { to { opacity: 0.12; transform: translateY(-14px); } }
@keyframes opt-center { to { transform: translateY(clamp(-460px, -44vh, -260px)); } }
@keyframes opt-recv {
  0% { border-color: var(--border); }
  50% { transform: scale(1.08); }
  100% { border-color: var(--good); transform: none; }
}
@keyframes opt-bar { from { transform: scaleY(0); } to { transform: scaleY(1); } }
/* ---- Act 3: the conversation plays as you scroll through it -------------
   Scrub-lite: each bubble's entrance is mapped to the phone's own travel
   through the viewport — scroll back and it replays. No pin. The typing
   dots exist only in the animated world (display:none outside it). */
.bub-typing { display: none; }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    html.js .phone .bub {
      animation: bub-in linear both;
      animation-timeline: view();
    }
    /* nth 1 is the typing dots — visible only in the animated world, on
       early, gone before the first message lands. nth 2–6 are the thread. */
    html.js .phone .bub-typing {
      display: block;
      animation: bub-dots linear both;
      animation-timeline: view();
      animation-range: entry 10% entry 55%;
    }
    html.js .phone .bub:nth-of-type(2) { animation-range: entry 30% entry 55%; }
    html.js .phone .bub:nth-of-type(3) { animation-range: entry 55% entry 75%; }
    html.js .phone .bub:nth-of-type(4) { animation-range: entry 75% entry 95%; }
    html.js .phone .bub:nth-of-type(5) { animation-range: entry 95% cover 40%; }
    html.js .phone .bub:nth-of-type(6) { animation-range: cover 40% cover 52%; }
  }
}
@keyframes bub-dots {
  0% { opacity: 0; } 25% { opacity: 1; } 75% { opacity: 1; }
  100% { opacity: 0; height: 0; padding: 0; margin: 0; border-width: 0; }
}
@keyframes bub-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* ---- Act 4: the featured question --------------------------------------- */
.qa-feature { border-left: 3px solid var(--primary); }
.qa-feature h3 { font-size: 21px; }
@media (min-width: 721px) { .qa-feature { grid-column: span 2; } }
.tw.typing { border-right: 2px solid var(--primary); padding-right: 2px; }


/* ---- The line-broken lead (owner, 2026-08-23) ---------------------------
   Short lines, varied length, one colored anchor per line, marker highlight
   on the landing phrase. Each line reveals in sequence (site.js), so the
   seven-second reader gets the argument as beats, not as a paragraph. */
.lead-lines span { display: block; }
.lead-lines span + span { margin-top: 4px; }
.lead-lines strong { font-weight: 700; }
.mk-green {
  color: var(--good-text); font-weight: 700;
  background: linear-gradient(transparent 60%, var(--good-bg) 60%);
  padding: 0 2px;
}
.mk-blue {
  color: var(--primary); font-weight: 700;
  background: linear-gradient(transparent 60%, var(--primary-soft) 60%);
  padding: 0 2px;
}
.mk-orange {
  color: var(--warn-text); font-weight: 700;
  background: linear-gradient(transparent 60%, var(--warn-bg) 60%);
  padding: 0 2px;
}

/* ---- Act 1: the stack that builds itself (owner concept, 2026-08-23) ----
   One centered column. Each reader chip lights as its icons pop into the
   canvas, the product frame rises around all three, and the benefits land
   inside it as rows. Everything below is VISIBLE BY DEFAULT — the
   choreography exists only inside the @supports + no-preference + .js
   block, so no-JS, old browsers and reduced motion all get the finished
   frame, still and complete. */
.reader-chips { justify-content: center; }
.stack { max-width: 760px; margin: 40px auto 0; }
.stack-frame {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 16px; box-shadow: var(--shadow-2); overflow: hidden;
}
.sf-chrome {
  display: flex; gap: 6px; align-items: center; height: 34px;
  padding: 0 14px; background: var(--subtle); border-bottom: 1px solid var(--border);
}
.sf-chrome i { width: 9px; height: 9px; border-radius: 50%; background: var(--border); }
.stack-canvas { display: block; width: 100%; height: auto; padding: 10px 8px 0; }
/* Top-down pipeline with the commentary beside it (owner, 2026-08-23). The
   canvas keeps its aspect, so each note aligns to its stage by percentage
   of the column height — true at every width. */
.pipe-grid {
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 0 30px; padding: 16px 24px 4px; align-items: stretch;
}
.pipe-canvas { padding: 0; }
.pipe-notes { list-style: none; position: relative; }
.pc { position: absolute; left: 0; right: 0; }
.pc-1 { top: 2%; } .pc-2 { top: 28%; } .pc-3 { top: 55%; } .pc-4 { top: 76%; }
.pc strong {
  display: block; font-family: var(--font-display); font-size: 17px;
  font-weight: 700; color: var(--ink); margin-bottom: 4px;
}
.pc span { font-size: 14px; line-height: 1.5; color: var(--muted); }
.pipe-dock { display: none; }
/* The pipeline (owner concept, 2026-08-23 evening): many ads, many sources,
   one central place with YOU in the middle of it, assignment to the crews,
   the money locking in and paying out evenly, and the loop back to the ads.
   Semantic throughout: blue in, orange through you and the work, green out. */
.stack-canvas .src { fill: var(--primary-soft); stroke: var(--primary); stroke-width: 2; }
.stack-canvas .srcbar { fill: var(--primary); opacity: 0.5; }
.stack-canvas .ad { fill: var(--primary); }
.stack-canvas .fl { fill: none; stroke-width: 1.75; stroke-linecap: round; }
.stack-canvas .fl.b { stroke: var(--primary); opacity: 0.45; }
.stack-canvas .fl.o { stroke: var(--warn); opacity: 0.55; }
.stack-canvas .fl.g { stroke: var(--good); opacity: 0.55; }
.stack-canvas .hub { fill: var(--surface); stroke: var(--ink); stroke-width: 2.5; }
.stack-canvas .you-ring { fill: var(--warn-bg); }
.stack-canvas .you-head, .stack-canvas .you-body { fill: var(--warn); }
.stack-canvas .sub-head, .stack-canvas .sub-body {
  fill: var(--warn-bg); stroke: var(--warn-text); stroke-width: 1.75;
}
.stack-canvas .vault { fill: var(--good-bg); stroke: var(--good); stroke-width: 2; }
.stack-canvas .vault-shackle { fill: none; stroke: var(--good); stroke-width: 2.5; }
.stack-canvas .dollar { font: 700 17px var(--font-display); fill: var(--good-text); }
.stack-canvas .pay { fill: var(--good); }
.stack-canvas .loop { fill: none; stroke: var(--good); stroke-width: 2; }
.stack-canvas .loop-tip { fill: var(--good); }
.stack-canvas .cap {
  font-family: var(--font-text); font-size: 13px; font-weight: 600;
  fill: var(--faint); letter-spacing: 0.04em;
}
.stack-canvas .cap-you { fill: var(--warn-text); font-weight: 700; }
.stack-rows { list-style: none; border-top: 1px solid var(--subtle); }
.srow {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 13px 22px; font-size: 15.5px; color: var(--muted);
}
.srow + .srow { border-top: 1px solid var(--subtle); }
.srow .ic { width: 18px; height: 18px; color: var(--good-text); margin-top: 3px; }
.srow strong { color: var(--ink); font-weight: 700; }

/* The choreography. Chips light with their stage; icons pop; the frame's
   chrome and border arrive around them; rows cascade. One onset per beat. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    html.js .stack { view-timeline: --stk block; }
    html.js .stg, html.js .srow {
      animation-name: stk-pop; animation-timing-function: cubic-bezier(0.34, 1.4, 0.64, 1);
      animation-fill-mode: both; animation-timeline: --stk;
    }
    html.js .stg-1 { animation-range: entry 10% entry 26%; }
    html.js .stg-2 { animation-range: entry 30% entry 46%; }
    html.js .stg-3 { animation-range: entry 50% entry 66%; }
    html.js .stg-4 { animation-range: entry 70% entry 86%; }
    /* each note arrives with its stage */
    html.js .pc {
      animation-name: stk-note; animation-timing-function: ease-out;
      animation-fill-mode: both; animation-timeline: --stk;
    }
    html.js .pc-1 { animation-range: entry 10% entry 26%; }
    html.js .pc-2 { animation-range: entry 30% entry 46%; }
    html.js .pc-3 { animation-range: entry 50% entry 66%; }
    html.js .pc-4 { animation-range: entry 70% entry 86%; }
    /* the loop draws last — the punchline: the money teaches the ads */
    html.js .stg-loop .loop {
      stroke-dasharray: 1; stroke-dashoffset: 1;
      animation: th-draw linear both; animation-timeline: --stk;
      animation-range: entry 92% cover 44%;
    }
    html.js .stg-loop .loop-tip {
      animation: stk-pop cubic-bezier(0.34, 1.4, 0.64, 1) both;
      animation-timeline: --stk; animation-range: cover 42% cover 50%;
    }
    /* rows wait for the frame (entry 70–95% ≈ cover ~30%), then cascade */
    html.js .srow:nth-child(1) { animation-range: cover 36% cover 46%; }
    html.js .srow:nth-child(2) { animation-range: cover 44% cover 54%; }
    html.js .srow:nth-child(3) { animation-range: cover 52% cover 62%; }
    html.js .srow:nth-child(4) { animation-range: cover 60% cover 70%; }
    /* the chrome bar and the rows' shell arrive with the frame, so the
       stages pop against clean space and the "screen" lands as one object */
    html.js .sf-chrome, html.js .stack-rows {
      animation-name: stk-fade; animation-timing-function: linear;
      animation-fill-mode: both; animation-timeline: --stk;
      animation-range: entry 82% entry 97%;
    }
    /* the frame is present all along but transparent; it rises as stage 4 */
    html.js .stack-frame {
      animation-name: stk-frame; animation-timing-function: ease-out;
      animation-fill-mode: both; animation-timeline: --stk;
      animation-range: entry 82% entry 97%;
    }
    /* each chip holds full colour once its stage has landed */
    html.js .reader-chips .rc-1 { animation: stk-chip linear both; animation-timeline: --stk; animation-range: entry 15% entry 28%; }
    html.js .reader-chips .rc-2 { animation: stk-chip linear both; animation-timeline: --stk; animation-range: entry 35% entry 48%; }
    html.js .reader-chips .rc-3 { animation: stk-chip linear both; animation-timeline: --stk; animation-range: entry 55% entry 68%; }
  }
}
@keyframes stk-pop {
  from { opacity: 0; transform: translateY(12px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
@keyframes stk-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes stk-note {
  from { opacity: 0; transform: translateX(14px); }
  to   { opacity: 1; transform: none; }
}
@keyframes pdc-dock { 0% { opacity: 0; } 6%, 94% { opacity: 1; } 100% { opacity: 0; } }
@keyframes pdc-show {
  0%, 100% { opacity: 0; transform: translateY(6px); }
  14%, 86% { opacity: 1; transform: none; }
}
@keyframes stk-frame {
  from { box-shadow: none; border-color: transparent; background: transparent; }
  to   { box-shadow: var(--shadow-2); border-color: var(--border); background: var(--surface); }
}
@keyframes stk-chip {
  from { border-color: var(--border); color: var(--muted); background: var(--surface); }
  to   { border-color: var(--warn); color: var(--ink); background: var(--warn-bg); }
}
@media (max-width: 860px) {
  .pipe-grid { grid-template-columns: 1fr; gap: 18px; padding: 14px 16px 4px; }
  /* Fallback layout: the notes stack under the canvas as a plain list. In
     the animated world below they hide and the dock carries them instead. */
  .pipe-notes { position: static; }
  .pc { position: static; }
  .pc + .pc { margin-top: 14px; }
}
@supports (animation-timeline: view()) {
  @media (max-width: 860px) and (prefers-reduced-motion: no-preference) {
    html.js .pipe-notes { display: none; }
    /* The commentary dock: fixed just above the sticky ask (which stays
       stuck to the bottom, z-index 60). The current step's note swaps in as
       the pipeline scrolls; the dock itself exists only while the section
       is on stage. */
    html.js .pipe-dock {
      display: block; position: fixed; left: 12px; right: 12px; bottom: 86px;
      z-index: 45; min-height: 68px;
      background: rgba(255, 255, 255, 0.96);
      -webkit-backdrop-filter: saturate(1.4) blur(10px);
      backdrop-filter: saturate(1.4) blur(10px);
      border: 1px solid var(--border); border-radius: 14px;
      box-shadow: var(--shadow-2); padding: 12px 16px;
      pointer-events: none;
      animation: pdc-dock linear both;
      animation-timeline: --stk; animation-range: entry 5% cover 80%;
    }
    html.js .pdc {
      position: absolute; inset: 12px 16px;
      animation: pdc-show linear both; animation-timeline: --stk;
    }
    html.js .pdc strong {
      display: block; font-family: var(--font-display); font-size: 15px;
      font-weight: 700; color: var(--ink);
    }
    html.js .pdc span { font-size: 12.5px; color: var(--muted); }
    /* butted windows, no overlap: at any boundary the outgoing note is at
       its 100% keyframe (hidden) and the incoming at 0% (hidden) — so the
       swap is clean and two notes never read at once */
    html.js .pdc-1 { animation-range: entry 8% entry 36%; }
    html.js .pdc-2 { animation-range: entry 36% entry 62%; }
    html.js .pdc-3 { animation-range: entry 62% entry 88%; }
    html.js .pdc-4 { animation-range: entry 88% cover 75%; }
  }
}
@media (max-width: 720px) {
  .srow { padding: 11px 14px; font-size: 14px; }
  .stack { margin-top: 28px; }
  /* SVG text scales with the viewBox: 13 user units render ~6px at 340px
     wide. 24 units render ~11px — the same trap the old map fell into. */
  .stack-canvas .cap { font-size: 24px; }
  .stack-canvas .dollar { font-size: 26px; }
}

/* ---- Act 2's filter table (owner, 2026-08-23) ---------------------------
   Three jobs, one winner. The winning row and its click ID carry the only
   bold and the only green; the arrow beside the table sends exactly that
   row to the Google Ads node. Wording matches the product rule precisely:
   value = money collected, never-paid jobs are never sent. */
/* Top-down at every width (owner, 2026-08-23): table → the file drops →
   Google receives → the money rises → the strip closes the act. One
   vertical composition, which is also exactly what a phone wants. */
.xfer {
  display: flex; flex-direction: column; align-items: center;
  gap: 18px; margin-top: 40px;
}
.xfer-card { width: 100%; max-width: 780px; }
.xfer-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px; padding: 20px 24px; box-shadow: var(--shadow-1);
}
.xfer-fly { display: flex; flex-direction: column; align-items: center; }
.xfer-scroll { overflow-x: auto; }
.xfer-table { width: 100%; border-collapse: collapse; min-width: 480px; }
.xfer-table th, .xfer-table td { padding: 11px 10px; text-align: left; font-size: 14.5px; }
.xfer-table thead th {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--faint);
}
.xfer-table tbody tr { border-top: 1px solid var(--subtle); }
.xfer-table tbody th { font-weight: 600; }
.xfer-table tbody th span { display: block; font-size: 12px; font-weight: 400; color: var(--faint); }
.xf-id { color: var(--muted); letter-spacing: 0.02em; }
.xf-num { font-variant-numeric: tabular-nums; color: var(--muted); }
.xf-num.neg { color: var(--bad); }
.xf-no { color: var(--faint); font-size: 13px; }
.xr-dead th, .xr-dead .xf-id { color: var(--muted); }
.xr-win { background: var(--good-bg); }
.xr-win th { font-weight: 700; }
.xf-id.win, .xf-num.win { font-weight: 700; color: var(--good-text); }
.xf-yes { color: var(--good-text); font-weight: 700; font-size: 13px; white-space: nowrap; }
.xf-yes .ic { width: 15px; height: 15px; vertical-align: -3px; }
.xfer-card .fr-foot { margin-top: 12px; }
.xfer-card .specimen-chip { margin-top: 8px; }

.xfer-fly { text-align: center; }
.xf-arrow { display: block; width: 34px; height: 96px; margin: 0 auto 12px; overflow: visible; }
.xf-line { fill: none; stroke: var(--good); stroke-width: 2.5; stroke-linecap: round; }
.xf-tip { fill: var(--good); }
.xf-node {
  display: inline-block; font-family: var(--font-display); font-weight: 700;
  font-size: 16px; color: var(--ink); background: var(--surface);
  border: 1px solid var(--border); border-radius: 999px; padding: 10px 22px;
  box-shadow: var(--shadow-1);
}
.xf-cap { margin-top: 14px; font-size: 14px; color: var(--muted); max-width: 260px; margin-left: auto; margin-right: auto; }
.xf-cap strong { color: var(--good-text); }

/* The one motion beat: the arrow draws from the winning row to the node,
   and the node lands. Everything else is content, not choreography. */
@supports (animation-timeline: view()) {
  @media (max-width: 1080px) and (prefers-reduced-motion: no-preference) {
    /* below the pin threshold the arrow still draws on its own timeline */
    html.js .xfer { view-timeline: --xfr block; }
    html.js .xf-line {
      stroke-dasharray: 1; stroke-dashoffset: 1;
      animation: th-draw linear both; animation-timeline: --xfr;
      animation-range: entry 55% entry 95%;
    }
    html.js .xf-tip, html.js .xf-node {
      animation: stk-pop cubic-bezier(0.34, 1.4, 0.64, 1) both;
      animation-timeline: --xfr; animation-range: entry 90% cover 30%;
    }
  }
}


/* ---- Scene art + the parallax drift (owner, 2026-08-23) -----------------
   Generated scenes of the system being used, placed where they answer the
   copy beside them. .plx gives a slow counter-scroll drift: the image
   travels ~5% against the scroll direction while crossing the viewport —
   the classic depth cue, cheap and gated like all motion here. */
.scene { margin: 0; border-radius: 16px; overflow: hidden; box-shadow: var(--shadow-2); }
.scene img { display: block; width: 100%; height: auto; }
.scene-wide { margin-top: 44px; }
.steps-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 44px; align-items: center; margin-top: 12px;
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    html.js .plx img {
      animation: plx-drift linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
      scale: 1.08;
    }
  }
}
@keyframes plx-drift {
  from { transform: translateY(3.5%); }
  to   { transform: translateY(-3.5%); }
}
@media (max-width: 860px) {
  .steps-grid { grid-template-columns: 1fr; gap: 28px; }
}

/* ---- The money rises behind Google (owner, 2026-08-23) ------------------
   Cause and effect in one spot: the file lands on the node, and the bars
   climb out from behind it. Static (fully risen) wherever the pin is off.
   The specimen file is a real download — the one true click in the scene. */
.xf-dl {
  display: inline-block; margin-left: 10px; color: var(--primary);
  font-weight: 600; text-decoration: underline;
}
.xfer-table tbody tr { transition: transform 0.15s ease, box-shadow 0.15s ease; }
.xfer-table tbody tr:hover { transform: translateX(3px); }
.xfer-table tbody tr.xr-win:hover { box-shadow: inset 3px 0 0 var(--good); }
@supports (animation-timeline: view()) {
  @media (min-width: 1081px) and (min-height: 640px) and (prefers-reduced-motion: no-preference) {
    /* Google's arrow to the strip draws after Received */
    html.js .opt-track .xf-arrow2 .xf-line {
      animation-range: contain 58% contain 66%;
    }
    /* then the strip takes the stage: everything above it dims and the
       strip rides up to the centre of the viewport — clear of the sticky
       ask at the bottom — where its bars grow month 1 → month 8 */
    html.js .opt-track .xf-arrow2 {
      animation-name: opt-clear; animation-timing-function: linear;
      animation-fill-mode: both; animation-timeline: --opt;
      animation-range: contain 66% contain 76%;
    }
    html.js .opt-track .money-strip {
      animation-name: opt-center; animation-timing-function: cubic-bezier(0.3, 0, 0.4, 1);
      animation-fill-mode: both; animation-timeline: --opt;
      animation-range: contain 64% contain 80%;
    }
  }
}

/* ---- The drawn underscore (owner, 2026-08-23) ---------------------------
   One per heading, on the phrase that carries the claim. It draws left to
   right as the heading enters the viewport — the hero's underscore idea,
   spent once per section instead of looping. Static (fully drawn) without
   scroll-driven support or with reduced motion, so the emphasis never
   depends on the animation existing. */
.us {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 96%;
  background-size: 100% 0.1em;
  padding-bottom: 0.04em;
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    html.js .us {
      background-size: 0% 0.1em;
      animation: us-draw cubic-bezier(0.16, 1, 0.3, 1) both;
      animation-timeline: view();
      animation-range: entry 70% entry 130%;
    }
  }
}
@keyframes us-draw { to { background-size: 100% 0.1em; } }

/* WhatsApp wears WhatsApp's colour — the one brand-hue exception to the
   semantic code (owner, 2026-08-23). The brand green #25D366 fails AA as
   type, so the word is set in the readable deep green instead. */
.hl-wa { color: var(--good-text); font-weight: 700; }

/* ---- Act 4: the question carousel (owner, 2026-08-23) -------------------
   Two tiers so nobody drowns: the big three, then the deep cuts. Each card
   is question → a small visualization → YOU saying the decision in a speech
   bubble — the operator is the one drawing the insight, and the avatar is
   the same orange figure who sits in the pipeline hub. CSS scroll-snap, no
   JS: the peeking next card is the affordance. */
.qtier { margin-top: 34px; }
.qtier-mark {
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 12px;
}
.qcar {
  list-style: none; display: flex; gap: 18px;
  overflow-x: auto; scroll-snap-type: x mandatory;
  padding: 4px 4px 14px; scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.qcard {
  /* ~2.2 cards visible: real travel per tick, so the spin is unmissable */
  flex: 0 0 clamp(330px, 46%, 480px); scroll-snap-align: start;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px; padding: 22px; box-shadow: var(--shadow-1);
}
.qcard h3 { font-size: 17.5px; line-height: 1.3; margin-bottom: 14px; }
.qviz { margin: 0 0 16px; }
.qv-row {
  display: grid; grid-template-columns: 108px 1fr auto; gap: 10px;
  align-items: center; font-size: 12px; color: var(--muted); margin: 7px 0;
}
.qv-row em { font-style: normal; font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }
.qv-bar { display: block; height: 10px; border-radius: 3px; }
.qv-bar.g { background: var(--good); }
.qv-bar.r { background: var(--bad); }
.qv-bar.b { background: var(--primary); }
.qv-dots { display: flex; gap: 4px; }
.qv-dot {
  width: 11px; height: 11px; border-radius: 50%;
  border: 1.5px solid var(--border); background: var(--surface);
}
.qv-dot.on { background: var(--good); border-color: var(--good); }
.qsay { display: flex; gap: 10px; align-items: flex-start; }
.qface { width: 40px; height: 40px; flex: none; }
.qf-ring { fill: var(--warn-bg); }
.qf-head, .qf-body { fill: var(--warn); }
.qbub {
  position: relative; background: var(--canvas); border: 1px solid var(--border);
  border-radius: 12px; padding: 10px 14px; font-size: 13.5px; line-height: 1.5;
  color: var(--muted);
}
.qbub::before {
  content: ""; position: absolute; left: -6px; top: 14px;
  width: 10px; height: 10px; background: var(--canvas);
  border-left: 1px solid var(--border); border-bottom: 1px solid var(--border);
  transform: rotate(45deg);
}
.qbub strong { color: var(--good-text); font-weight: 700; }
.qwho { display: block; margin-top: 5px; font-size: 11px; color: var(--faint); }
@media (max-width: 720px) {
  .qcard { flex-basis: min(84vw, 340px); padding: 18px; }
  .qv-row { grid-template-columns: 88px 1fr auto; }
}

/* Below-the-story sections skip layout and paint until they approach the
   viewport — free rendering budget for the pinned scenes above them. The
   intrinsic size keeps the scrollbar honest. */
.cv-tail { content-visibility: auto; contain-intrinsic-size: auto 640px; }

/* ==========================================================================
   The legibility pass (owner, 2026-08-23): a tall section must say what it
   is at every scroll position, on every width, without scrolling back.
   Two moves: the section's colored mark STAYS PINNED just under the header
   for as long as you are inside its section (so the context never leaves
   the screen), and the tall acts lose the air that made them 1.5–2.4
   screens deep.
   ========================================================================== */
.sect-mark, .sub-mark {
  position: sticky; top: 84px; z-index: 8;
  display: inline-block; width: fit-content;
  padding: 5px 12px; margin-left: -12px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.88);
  -webkit-backdrop-filter: blur(6px) saturate(1.3);
  backdrop-filter: blur(6px) saturate(1.3);
  box-shadow: 0 1px 3px rgba(11, 12, 14, 0.07);
}
/* Act 5's inner chapters pin one row beneath the act's own mark. */
.sub-mark { top: 128px; }

/* --- the air the tall acts lose ------------------------------------------ */
section { padding: 60px 0; }
section.after-hero { padding-top: 104px; }
.lead-lines span + span { margin-top: 3px; }
.reader-chips { margin-top: 22px; }
.reader-note { margin-top: 12px; }
.stack { margin-top: 28px; max-width: 700px; }
.srow { padding: 10px 20px; font-size: 14.5px; }
.auto-grid { gap: 40px; margin-top: 32px; }
.scene-wide { margin-top: 28px; }
.qtier { margin-top: 24px; }
.payoff { margin-top: 28px; }
.sub-mark { margin-top: 40px; }
.sub-head { margin: 8px 0 22px; font-size: 24px; }
.fin-grid { gap: 32px; }
.fin-report, .stat-card { padding: 22px 24px; }
.fr-rows > div { padding: 9px 0 9px 14px; }
.fp-table th, .fp-table td { padding: 10px 12px; }
.camp-bars li { margin-bottom: 13px; }
.perf-list li { padding: 10px 14px; margin-bottom: 8px; }
.grid { margin-top: 34px; }
.steps-grid { margin-top: 4px; }
@media (max-width: 720px) {
  section { padding: 44px 0; }
  section.after-hero { padding-top: 72px; }
  .sect-mark, .sub-mark { top: 68px; }
  .sub-mark { top: 104px; }
}

/* ==========================================================================
   THE PHONE — store links and the scan pair (2026-09-05)
   The app shipped to both stores on 2026-08-31, and until now the site never
   said so. Two surfaces:
     · the hero's .store-line — a secondary row under the reassurance, never
       beside the register CTA. The hero keeps ONE action (§ Marketing Visual
       Language); these are a door, so they are outlined, not filled, and they
       are quieter than the ghost CTA on purpose.
     · #get-the-app's .app-get — copy left, the two scan cards right.
   Both platform marks come from the sprite and inherit the button's ink, so
   the row reads as one control pair rather than two vendors' badges.
   ========================================================================== */
.store-line { margin-top: 22px; }
.store-label {
  display: block; font-size: 12.5px; font-weight: 600; letter-spacing: 0.02em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 10px;
}
.store-row { display: flex; gap: 12px; flex-wrap: wrap; }
.hero-center .store-row { justify-content: center; }

.store-btn {
  display: inline-flex; align-items: center; gap: 10px;
  height: 48px; padding: 0 18px 0 15px;
  background: var(--surface); color: var(--ink); text-decoration: none;
  border: 1px solid var(--border); border-radius: 12px;
  box-shadow: var(--shadow-1);
  transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.store-btn:hover {
  border-color: var(--primary); transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(11, 12, 14, 0.06), 0 8px 20px rgba(37, 99, 235, 0.14);
}
.store-btn:active { transform: translateY(0); }
.store-btn .store-mark { width: 22px; height: 22px; color: var(--ink); flex: none; }
.store-lines {
  display: flex; flex-direction: column; line-height: 1.12; text-align: left;
  font-family: var(--font-display); font-size: 16px; font-weight: 700;
}
.store-lines small {
  font-family: var(--font-text); font-size: 11px; font-weight: 500;
  letter-spacing: 0.01em; color: var(--muted); margin-bottom: 2px;
}
.store-row-lg { margin-top: 26px; }
.store-row-lg .store-btn { height: 54px; padding: 0 22px 0 18px; }
.store-row-lg .store-btn .store-mark { width: 25px; height: 25px; }
.store-row-lg .store-lines { font-size: 17px; }

/* --- the section ---------------------------------------------------------- */
.app-get {
  display: grid; grid-template-columns: minmax(0, 1fr) 372px;
  gap: 64px; align-items: center;
}
.app-get h2 { max-width: 21ch; }
/* The register's line-broken beats: one clause per line. `.line` is only a
   block inside the hero, and inheriting the hero's rule here would tie this
   section to the hero's geometry. */
.app-get .lead { margin-top: 18px; max-width: 620px; }
.app-get .lead .line { display: block; }
.app-get .lead .line + .line { margin-top: 3px; }
.app-points { list-style: none; margin: 30px 0 0; display: grid; gap: 18px; }
.app-points li { display: flex; gap: 16px; align-items: flex-start; }
.app-points .ic-tile { margin-bottom: 0; flex: none; }
.app-points strong { display: block; font-size: 17px; font-weight: 700; margin-bottom: 4px; }
.app-points span { display: block; font-size: 15px; color: var(--muted); line-height: 1.55; }
.app-note { margin-top: 16px; color: var(--faint); font-size: 14px; }

/* The scan pair. The card supplies the QR's quiet zone (the SVG is drawn on
   transparency with a 2-module border), which is why the padding is not
   decorative and must not be tightened below 18px. */
.qr-pair {
  display: grid; grid-template-columns: 1fr 1fr; gap: 18px;
  align-content: center;
}
.qr-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 16px; padding: 18px 18px 14px; text-align: center;
  box-shadow: var(--shadow-2);
}
.qr-card img { width: 100%; height: auto; display: block; }
.qr-card figcaption {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--border);
  font-family: var(--font-display); font-size: 14px; font-weight: 700;
}
.qr-card figcaption .ic { width: 16px; height: 16px; color: var(--ink); }
.qr-note {
  grid-column: 1 / -1; text-align: center; margin-top: 2px;
  font-size: 13px; color: var(--faint);
}

/* The wide arrangement left-aligns the copy column, so the store row hangs
   on the same rail as the button above it. It has to live here, after the
   centring rule above: equal specificity, so source order decides. */
@media (min-width: 1081px) {
  .hero-center .store-line { text-align: left; }
  .hero-center .store-row { justify-content: flex-start; }
}

@media (max-width: 1080px) {
  .app-get { grid-template-columns: 1fr; gap: 40px; }
  .qr-pair { max-width: 420px; }
}
/* A phone is the device the QR would send you to. Below 720 the codes are
   pointless furniture and the buttons already do the job, so the pair goes
   away rather than shrinking into an unscannable square. */
@media (max-width: 720px) {
  .qr-pair { display: none; }
  .store-line { margin-top: 18px; }
  .store-btn { flex: 1 1 auto; justify-content: center; }
}

/* ------------------------------------------------------------------- docs
   The documentation surface (/docs and /docs/*), added 2026-09-06 with wave 0
   of the content programme (HeadHoncho/SEO Content Marketing Strategy.md §6).

   A docs page is not a marketing page and does not pretend to be one: no
   hero band, no sticky ask, no film. It is a left rail of every page in the
   set and a reading column, on the same 1140 container every interior page
   uses -- so navigating from /pricing into /docs does not change the width
   of the site (Marketing Site Conventions §7). Type, colour and spacing are
   the site's own tokens; nothing here introduces a value.

   The rail is a <nav>, deliberately: scripts/seo_links.py separates chrome
   from prose, and a repeated set of links to every sibling is chrome. The
   links that count as topical statements are the ones written into the
   sentences (SEO Playbook §10). */

.docs-head {
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, #ffffff, var(--canvas));
  padding: 34px 0 30px;
}
.crumbs { font-size: 13px; color: var(--faint); display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.crumbs a { color: var(--faint); text-decoration: none; }
.crumbs a:hover { color: var(--ink); }
.crumbs .sep { color: var(--border); }
.docs-head h1 {
  font-size: 38px; line-height: 1.18; font-weight: 700; letter-spacing: -0.02em;
  margin-top: 12px; max-width: 820px; text-wrap: balance;
}
.docs-head .lead { font-size: 18px; margin-top: 12px; max-width: 740px; }

/* 236 rail + 56 gutter + 848 column: the reading measure lands near 80
   characters at the body size, which is the width the rest of the site's
   prose already runs at. */
.docs-shell { display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 56px; padding: 40px 0 96px; align-items: start; }
.docs-nav { position: sticky; top: 96px; font-size: 14px; }
.docs-nav .group { margin-bottom: 22px; }
.docs-nav strong {
  display: block; font-size: 11.5px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--faint); font-weight: 700; margin-bottom: 8px;
}
.docs-nav a {
  display: block; color: var(--muted); text-decoration: none; padding: 5px 10px;
  border-left: 2px solid var(--border); line-height: 1.35;
}
.docs-nav a:hover { color: var(--ink); background: var(--subtle); }
.docs-nav a[aria-current="page"] { color: var(--primary); border-left-color: var(--primary); font-weight: 600; background: var(--primary-soft); }

.docs-main { max-width: 780px; }
.docs-main h2 {
  font-size: 25px; line-height: 1.25; margin-top: 46px; padding-top: 4px;
  scroll-margin-top: 96px; letter-spacing: -0.015em;
}
.docs-main h2:first-child { margin-top: 0; }
.docs-main h3 { font-size: 17.5px; margin-top: 28px; margin-bottom: 6px; }
.docs-main p { margin-top: 14px; font-size: 16.5px; line-height: 1.65; }
.docs-main ul, .docs-main ol { margin: 14px 0 0 22px; font-size: 16.5px; line-height: 1.6; }
.docs-main li { margin-top: 7px; }
.docs-main li strong { color: var(--ink); }
.docs-main a { color: var(--primary); text-decoration: none; border-bottom: 1px solid rgba(37, 99, 235, 0.28); }
.docs-main a:hover { border-bottom-color: var(--primary); }
.docs-main code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 14px;
  background: var(--subtle); border: 1px solid var(--border); border-radius: 5px; padding: 1px 5px;
}

.doc-toc { border: 1px solid var(--border); border-radius: 12px; padding: 18px 20px; background: var(--canvas); }
.doc-toc strong { font-size: 11.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--faint); }
.doc-toc ol { list-style: none; margin: 10px 0 0; columns: 2; column-gap: 28px; font-size: 15px; }
.doc-toc li { margin-top: 6px; break-inside: avoid; }
.doc-toc a { color: var(--muted); text-decoration: none; border: 0; }
.doc-toc a:hover { color: var(--primary); }

/* A callout states a rule, a limit, or something the product deliberately
   does not do. Three tones and no others: blue for a rule worth knowing,
   orange for a limit, grey for an aside. Text colours are the -text tokens,
   never the fills (Marketing Visual Language §8.1). */
.doc-note {
  border: 1px solid var(--border); border-left: 3px solid var(--primary);
  background: var(--primary-soft); border-radius: 10px; padding: 16px 18px; margin-top: 22px;
}
.doc-note p { margin-top: 0; font-size: 15.5px; }
.doc-note p + p { margin-top: 10px; }
.doc-note .tag {
  display: block; font-size: 11.5px; letter-spacing: 0.06em; text-transform: uppercase;
  font-weight: 700; color: var(--primary); margin-bottom: 6px;
}
.doc-note.limit { border-left-color: var(--warn-text); background: var(--warn-bg); }
.doc-note.limit .tag { color: var(--warn-text); }
.doc-note.aside { border-left-color: var(--faint); background: var(--canvas); }
.doc-note.aside .tag { color: var(--faint); }

.doc-table { width: 100%; border-collapse: collapse; margin-top: 20px; font-size: 15px; }
.doc-table th, .doc-table td { padding: 10px 14px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; }
.doc-table th { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--faint); font-weight: 700; }
.doc-table td strong { color: var(--ink); }
.doc-table tr:last-child td { border-bottom: none; }
.doc-scroll { overflow-x: auto; }

/* Figures are inline SVG drawn in the site's own tokens: no external asset,
   no fabricated screenshot. Each carries a <title> and a <desc> so it reads
   as a figure to a screen reader rather than as decoration. */
.doc-figure { display: block; width: 100%; height: auto; max-width: 860px; margin: 24px 0 4px; }

/* Screenshots — real captures of the app, from scripts/docs_shots.py.
   The callouts are HTML on top of the picture, not pixels baked into it, so
   the numbers stay crisp at any width and the reasons under the image are
   real text a screen reader reads in order. Positions are percentages the
   capture script measured on the running board. */
.doc-shot { margin: 26px 0 8px; }
.shot-frame {
  position: relative; display: block; border: 1px solid var(--border);
  border-radius: 10px; overflow: hidden; background: var(--surface);
  box-shadow: var(--shadow-1); line-height: 0;
}
.shot-frame img { display: block; width: 100%; height: auto; }
.shot-mark {
  position: absolute; border: 2px solid var(--warn); border-radius: 7px;
  box-shadow: 0 0 0 3px rgba(255, 117, 31, 0.18); pointer-events: none;
}
.shot-mark i {
  position: absolute; top: -11px; left: -11px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--warn); color: #fff; font-style: normal;
  font-family: var(--font-display); font-size: 12.5px; font-weight: 700;
  line-height: 22px; text-align: center;
}
.doc-shot figcaption { margin-top: 10px; font-size: 14px; color: var(--muted); line-height: 1.55; }
.doc-shot .shot-keys { margin: 0; padding: 0; list-style: none; counter-reset: shotkey; }
.doc-shot .shot-keys li { position: relative; padding-left: 30px; margin-top: 7px; counter-increment: shotkey; }
.doc-shot .shot-keys li::before {
  content: counter(shotkey); position: absolute; left: 0; top: 1px;
  width: 20px; height: 20px; border-radius: 50%; background: var(--warn);
  color: #fff; font-family: var(--font-display); font-size: 11.5px;
  font-weight: 700; line-height: 20px; text-align: center;
}
/* A phone capture is 390 CSS px wide; printed across a 780px column it is a
   caricature of itself. */
.doc-shot.shot-phone .shot-frame { max-width: 320px; }
.doc-shot.shot-narrow .shot-frame { max-width: 420px; }
.shot-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: 20px; }
.shot-pair .doc-shot { margin-top: 0; }

/* The hub's page cards, and the two-door footer every page ends on. */
.doc-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr)); gap: 16px; margin-top: 22px; }
.doc-card {
  border: 1px solid var(--border); border-radius: 12px; padding: 18px 20px;
  background: var(--surface); text-decoration: none; display: block; color: var(--ink);
  transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.doc-card:hover { border-color: #dde1e6; transform: translateY(-2px); box-shadow: var(--shadow-2); }
.doc-card strong { display: block; font-size: 16px; font-weight: 600; }
.doc-card span { display: block; color: var(--muted); font-size: 14.5px; margin-top: 5px; line-height: 1.5; }
.doc-next { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 52px; padding-top: 26px; border-top: 1px solid var(--border); }
.doc-next .doc-card { flex: 1 1 260px; }
.doc-updated { margin-top: 30px; font-size: 13px; color: var(--faint); }

@media (prefers-reduced-motion: reduce) {
  .doc-card:hover { transform: none; }
}

/* Below 940 the rail stops being a rail: it becomes an index above the
   reading column. Sticky is dropped with it -- a sticky block that is as
   tall as the viewport pins the page. */
@media (max-width: 940px) {
  .docs-shell { grid-template-columns: 1fr; gap: 34px; padding-top: 28px; }
  /* The rail goes UNDER the reading column on a phone. Twenty links above the
     first sentence is a page you have to scroll past to start reading, and an
     index is the right thing to meet at the foot of a doc rather than at its
     head. Source order is unchanged, so the crawl path is too. */
  .docs-main { order: 1; }
  .docs-nav { order: 2; position: static; border: 1px solid var(--border); border-radius: 12px; padding: 18px 20px; background: var(--canvas); }
  .docs-nav .group { margin-bottom: 16px; }
  .docs-main { max-width: none; }
  .docs-head h1 { font-size: 30px; }
  .doc-toc ol { columns: 1; }
}
