/* ============================================================
   LAUNCH7 — COMPONENTS
   Every rule reads semantic tokens only. Adding a component?
   Document it in _internal/docs/design-system.md in the same commit.

   Order: elements → chrome → page components → demos
   ============================================================ */

/* ============================================================
   ELEMENTS
   ============================================================ */

/* ---------- button ----------
   Three levels, and only three. One primary per view.
   States: default / hover / focus / active / disabled. */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--space-2);
  min-height:48px;padding:var(--space-3) var(--space-6);
  border:1.5px solid transparent;border-radius:var(--radius-pill);
  font-size:var(--step-sm);font-weight:600;line-height:1;
  text-align:center;text-decoration:none;cursor:pointer;
  transition:background var(--dur-base) var(--ease),
             color var(--dur-base) var(--ease),
             border-color var(--dur-base) var(--ease),
             transform var(--dur-fast) var(--ease),
             box-shadow var(--dur-base) var(--ease);
}
.btn:hover{text-decoration:none;transform:translateY(-1px)}
/* A real press, not a reset. Touch has no hover state, so the press IS the
   only feedback the buyer on a phone ever gets — it has to be felt. */
.btn:active{transform:scale(.98)}
.btn[disabled],.btn[aria-disabled="true"]{
  opacity:.5;cursor:not-allowed;transform:none;box-shadow:none;
}

.btn-primary{background:var(--btn-primary-bg);color:var(--btn-primary-text);box-shadow:var(--shadow-ambient)}
.btn-primary:hover{background:var(--btn-primary-hover);color:var(--btn-primary-text);box-shadow:var(--shadow-lift)}

/* Sheen sweep. Drawn with a pseudo-element rather than a child <div> so it
   costs no markup on the ~40 primary buttons across the site. It sits at
   z-index:-1 inside an isolated stacking context, which puts it above the
   button's background and below its label. Transform-only, so it composites
   on the GPU and cannot drop frames on a mid-range phone. */
.btn-primary{position:relative;isolation:isolate;overflow:hidden}
.btn-primary::after{
  content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.18),transparent);
  transform:translateX(-100%);
  transition:transform 700ms ease-in-out;
}
.btn-primary:hover::after{transform:translateX(100%)}
@media(prefers-reduced-motion:reduce){
  .btn-primary::after{display:none}
  .btn:active{transform:none}
}

.btn-secondary{background:var(--btn-secondary-bg);color:var(--btn-secondary-text)}
.btn-secondary:hover{background:var(--btn-secondary-hover);color:var(--btn-secondary-text)}

.btn-ghost{background:transparent;color:var(--btn-ghost-text);border-color:var(--btn-ghost-border)}
.btn-ghost:hover{background:var(--btn-ghost-hover-bg);color:var(--btn-ghost-text)}

.btn-lg{min-height:56px;padding:var(--space-4) var(--space-7);font-size:var(--step-body)}
/* A block button takes its width from the container, so the generous inline
   padding of .btn/.btn-lg only squeezes the label — at 375px it wrapped
   "Get a free teardown" onto two lines. Keep the vertical padding, drop the
   horizontal to the point where it is just breathing room. */
.btn-block{width:100%;padding-inline:var(--space-4)}

/* reassurance line — always directly under a CTA, never floating */
.reassure{margin-top:var(--space-4);font-size:var(--step-xs);color:var(--text-muted)}

/* ---------- text link with arrow ----------
   min-height is the 44px tap floor. It reads as an inline text link but it
   is a primary route out of most cards, and on a phone it has to be hittable
   without precision. */
.link-arrow{
  display:inline-flex;align-items:center;gap:var(--space-2);min-height:44px;
  font-weight:600;font-size:var(--step-sm);color:var(--text-accent);
}
.link-arrow span{transition:transform var(--dur-base) var(--ease)}
.link-arrow:hover span{transform:translateX(3px)}
.link-arrow:active{opacity:.65}
@media(prefers-reduced-motion:reduce){.link-arrow:hover span{transform:none}}

/* ---------- metric chip ----------
   Mono numeral, small label under it. The site's proof unit. */
.chip{display:flex;flex-direction:column;gap:var(--space-1)}
.chip .n{
  font-family:var(--font-mono);font-weight:700;
  font-size:var(--step-metric);line-height:1;
  letter-spacing:-.03em;color:var(--text-primary);
  font-variant-numeric:tabular-nums;
}
.chip .n.accent{color:var(--text-accent)}
.chip .l{font-size:var(--step-xs);color:var(--text-secondary);line-height:1.3}
.chip-row{display:flex;flex-wrap:wrap;gap:var(--space-6) var(--space-8)}
.chip-sm .n{font-size:1.5rem}

/* ---------- tag pill ---------- */
.tag{
  display:inline-flex;align-items:center;
  padding:var(--space-1) var(--space-3);
  border:1px solid var(--border);border-radius:var(--radius-pill);
  background:var(--bg-surface);
  font-family:var(--font-mono);font-size:var(--step-eyebrow);
  letter-spacing:.06em;color:var(--text-secondary);
}
.tag-accent{background:var(--bg-accent-soft);border-color:var(--l7-blue-100);color:var(--text-accent)}
.tag-row{display:flex;flex-wrap:wrap;gap:var(--space-2)}

/* ---------- status dot ----------
   Never carries meaning alone — the adjacent word does. */
.status{display:inline-flex;align-items:center;gap:var(--space-2);font-family:var(--font-mono);font-size:var(--step-eyebrow);color:var(--text-secondary)}
.status::before{
  content:"";width:7px;height:7px;border-radius:50%;
  background:var(--text-accent);flex:none;
}

/* ---------- card ---------- */
.card{
  background:var(--bg-surface);
  border:1px solid var(--border);
  border-radius:var(--radius-card);
  padding:var(--space-6);
  box-shadow:var(--shadow-ambient);
  transition:box-shadow var(--dur-base) var(--ease),transform var(--dur-base) var(--ease),border-color var(--dur-base) var(--ease);
}
.card-hover:hover{box-shadow:var(--shadow-lift);transform:translateY(-2px);border-color:var(--border-strong)}
.card-hover:active{transform:translateY(0);box-shadow:var(--shadow-ambient)}
@media(prefers-reduced-motion:reduce){.card-hover:hover,.card-hover:active{transform:none}}
.card h3{margin-bottom:var(--space-3)}
.card p{color:var(--text-secondary)}

/* ---------- feature list ---------- */
.ticks{display:grid;gap:var(--space-3)}
.ticks li{display:flex;gap:var(--space-3);align-items:flex-start;color:var(--text-secondary);font-size:var(--step-sm)}
.ticks li::before{
  content:"";flex:none;width:18px;height:18px;margin-top:2px;border-radius:50%;
  background:var(--bg-accent-soft);
  background-image:linear-gradient(var(--text-accent),var(--text-accent));
  background-size:8px 2px;background-position:center;background-repeat:no-repeat;
}

/* ---------- form ---------- */
.field{display:grid;gap:var(--space-2);margin-bottom:var(--space-4)}
.field label{font-size:var(--step-xs);font-weight:600;color:var(--text-secondary)}
.field input,.field textarea,.field select{
  width:100%;min-height:48px;padding:var(--space-3) var(--space-4);
  background:var(--bg-surface);color:var(--text-primary);
  border:1.5px solid var(--border-strong);border-radius:var(--radius-sm);
  transition:border-color var(--dur-base) var(--ease);
}
.field input:hover,.field textarea:hover{border-color:var(--text-muted)}
.field input[aria-invalid="true"],.field textarea[aria-invalid="true"]{border-color:#B3261E}
.field .err{font-size:var(--step-xs);color:#B3261E;font-weight:600}
.form-status{margin-top:var(--space-4);font-size:var(--step-sm)}

/* ============================================================
   CHROME — nav + footer
   Edit the markup in partials/ and run tools/sync-partials.js
   ============================================================ */

.site-nav{
  position:sticky;top:0;z-index:120;
  background:var(--bg-page);
  border-bottom:1px solid transparent;
  transition:border-color var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease),background var(--dur-base) var(--ease);
}
.site-nav.stuck{
  border-bottom-color:var(--border);
  background:rgba(255,255,255,.88);
  backdrop-filter:saturate(180%) blur(14px);
  -webkit-backdrop-filter:saturate(180%) blur(14px);
  box-shadow:0 1px 12px rgba(13,13,18,.05);
}
.nav-in{display:flex;align-items:center;justify-content:space-between;gap:var(--space-5);min-height:72px}

.brand{display:inline-flex;align-items:center;gap:var(--space-3);min-height:44px;color:var(--text-primary);font-weight:700;font-size:1.125rem;letter-spacing:-.02em}
.brand:hover{text-decoration:none}
.brand:active{opacity:.65}
.brand svg{width:30px;height:30px;flex:none;border-radius:8px}
.brand i{font-style:normal;color:var(--text-accent)}

.nav-links{display:none;align-items:center;gap:var(--space-6)}
@media(min-width:980px){.nav-links{display:flex}}
.nav-links a{
  display:inline-flex;align-items:center;min-height:44px;
  font-size:var(--step-sm);font-weight:600;color:var(--text-secondary);
  padding-block:var(--space-2);
  transition:color var(--dur-base) var(--ease);
}
.nav-links a:hover{color:var(--text-primary);text-decoration:none}
.nav-links a:active{opacity:.65}
.nav-links a[aria-current="page"]{color:var(--text-primary)}

.nav-actions{display:flex;align-items:center;gap:var(--space-4)}

/* nav call link — secondary to the CTA on purpose. Number in assets/contact.js
   Hidden below 640px: on a phone the bar has room for one action, and that
   action is the teardown. The number is still one tap away in the menu. */
.nav-talk{
  display:none;align-items:center;gap:var(--space-2);flex:none;
  min-height:44px;color:var(--text-secondary);font-weight:600;font-size:var(--step-sm);
  white-space:nowrap;transition:color var(--dur-base) var(--ease);
}
.nav-talk:hover{color:var(--text-primary);text-decoration:none}
.nav-talk svg{width:16px;height:16px;flex:none;fill:none;stroke:var(--text-accent);stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.nav-talk .n{font-family:var(--font-mono);font-size:var(--step-xs);display:none}
@media(min-width:640px){.nav-talk{display:inline-flex}}
@media(min-width:1180px){.nav-talk .n{display:inline}}

/* ---------- petite enquiry button ----------
   The mobile-only expression of .nav-cta. Filled, because it is the primary
   conversion on the site and a ghost button here would read as decoration.
   Petite (40px in a 72px bar) so it sits under the burger's weight rather
   than fighting it. Label shortens rather than truncating, the same
   responsive-span pattern .nav-talk already uses. */
.nav-teardown{
  min-height:44px;padding:0 var(--space-3);
  font-size:var(--step-xs);white-space:nowrap;
}
@media(min-width:560px){.nav-teardown{display:none}}

/* Phone bar: brand, one action, the menu. Nothing else, and the button and
   burger share one 44px height so the row reads as a row rather than a pile.
   44 rather than the old 40 because this is the one bar a phone user actually
   has to hit, and 44px is the tap floor the rest of the site now holds to.
   Both gaps close to 12px so the cluster spaces evenly.
   .site-nav .burger is deliberately over-specific: the base .burger rule is
   further down this file, so an equal-specificity override here would lose
   on source order. */
@media(max-width:559px){
  .nav-in{gap:var(--space-3)}
  .nav-actions{gap:var(--space-3)}
  .site-nav .burger{width:44px;height:44px}
}

/* The wordmark only yields on genuinely tiny screens. Measured: the bar
   needs 347px with it, so every common phone (360 and up) keeps it and
   only the 320px outliers collapse to the mark. Scoped to .site-nav so
   teardown.html keeps its wordmark, where nothing competes for room. */
@media(max-width:359px){.site-nav .brand span{display:none}}

.nav-cta{display:none}
@media(min-width:560px){.nav-cta{display:inline-flex}}

.burger{
  display:inline-flex;align-items:center;justify-content:center;flex:none;
  width:46px;height:46px;padding:0;background:transparent;cursor:pointer;
  border:1.5px solid var(--border-strong);border-radius:var(--radius-pill);
  transition:background var(--dur-base) var(--ease);
}
.burger:hover{background:var(--btn-ghost-hover-bg)}
.burger:active{transform:scale(.94)}
@media(prefers-reduced-motion:reduce){.burger:active{transform:none}}
@media(min-width:980px){.burger{display:none}}
.burger i{display:block;width:18px;height:2px;background:var(--text-primary);position:relative;transition:background var(--dur-fast) var(--ease)}
.burger i::before,.burger i::after{
  content:"";position:absolute;left:0;width:18px;height:2px;background:var(--text-primary);
  transition:transform var(--dur-base) var(--ease),top var(--dur-base) var(--ease);
}
.burger i::before{top:-6px}
.burger i::after{top:6px}
.burger[aria-expanded="true"] i{background:transparent}
.burger[aria-expanded="true"] i::before{top:0;transform:rotate(45deg)}
.burger[aria-expanded="true"] i::after{top:0;transform:rotate(-45deg)}

.nav-panel{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--dur-slow) var(--ease);background:var(--bg-page)}
.nav-panel>div{overflow:hidden}
.nav-panel.open{grid-template-rows:1fr;border-bottom:1px solid var(--border)}
@media(min-width:980px){.nav-panel{display:none}}
.nav-panel a{
  display:flex;align-items:center;gap:var(--space-3);
  padding-block:var(--space-4);border-bottom:1px solid var(--border);
  color:var(--text-primary);font-weight:600;font-size:var(--step-body-lg);
}
.nav-panel a:hover{text-decoration:none;color:var(--text-accent)}
.nav-panel a:active{opacity:.65}
.nav-panel a.btn{border-bottom:0;margin-top:var(--space-5);justify-content:center;color:var(--btn-primary-text)}
.nav-panel svg{width:18px;height:18px;flex:none;fill:none;stroke:var(--text-accent);stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.nav-panel .n{font-family:var(--font-mono);font-size:var(--step-sm);font-weight:400;color:var(--text-secondary)}

/* ---------- footer ---------- */
.site-footer{border-top:1px solid var(--border);padding-block:var(--space-8) var(--space-6);margin-top:var(--space-9)}
.foot-grid{display:grid;gap:var(--space-7)}
@media(min-width:720px){.foot-grid{grid-template-columns:1.6fr 1fr 1fr 1fr}}
.foot-grid h2{font-size:var(--step-xs);font-family:var(--font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--text-muted);margin-bottom:var(--space-4);font-weight:700}
/* The row gap tightens as the links themselves grow to the 44px tap floor,
   so the column ends up the same height it was but every target is hittable. */
.foot-grid ul{display:grid;gap:var(--space-1)}
.foot-grid a{
  display:inline-flex;align-items:center;min-height:44px;
  color:var(--text-secondary);font-size:var(--step-sm);
}
.foot-grid a:hover{color:var(--text-primary)}
.foot-grid a:active{opacity:.65}
.foot-mission{margin-top:var(--space-4);color:var(--text-secondary);font-size:var(--step-sm);max-width:34ch}
.foot-social{display:flex;gap:var(--space-3);margin-top:var(--space-5)}
.foot-social a{
  display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;
  border:1px solid var(--border);border-radius:var(--radius-pill);color:var(--text-secondary);
}
.foot-social a:hover{border-color:var(--border-strong);color:var(--text-primary)}
.foot-social a:active{background:var(--btn-ghost-hover-bg)}
.foot-social svg{width:18px;height:18px;fill:currentColor}
.foot-base{
  display:flex;flex-wrap:wrap;gap:var(--space-3) var(--space-5);justify-content:space-between;
  margin-top:var(--space-8);padding-top:var(--space-5);border-top:1px solid var(--border);
  font-size:var(--step-xs);color:var(--text-muted);
}

/* ============================================================
   PAGE COMPONENTS
   ============================================================ */

/* ---------- hero (split) ---------- */
.hero{padding-block:var(--space-8) var(--section-y)}
.hero-grid{display:grid;gap:var(--space-8);align-items:center}
@media(min-width:980px){.hero-grid{grid-template-columns:1.05fr .95fr;gap:var(--space-9)}}
.hero h1{margin-bottom:var(--space-5)}
.hero .lede{margin-bottom:var(--space-6)}
.hero-actions{display:flex;flex-wrap:wrap;gap:var(--space-3)}
.hero-stats{display:flex;flex-wrap:wrap;gap:var(--space-6) var(--space-7);margin-top:var(--space-7);padding-top:var(--space-6);border-top:1px solid var(--border)}

/* ---------- page head (inner pages) ---------- */
.page-head{padding-block:var(--space-8) var(--space-7)}
.page-head h1{margin-bottom:var(--space-5)}

/* ---------- marquee ----------
   The duplicate track is aria-hidden. Pauses on hover, on focus
   within, and under reduced-motion. */
.marquee{position:relative;overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
}
.marquee-track{display:flex;width:max-content;gap:var(--space-8);animation:l7-marquee var(--marquee-dur) linear infinite}
.marquee:hover .marquee-track,
.marquee:focus-within .marquee-track{animation-play-state:paused}
@keyframes l7-marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media(prefers-reduced-motion:reduce){
  .marquee-track{animation:none;flex-wrap:wrap;width:auto;justify-content:center}
  .marquee{-webkit-mask-image:none;mask-image:none}
}
.logo-tile{
  display:flex;align-items:center;gap:var(--space-3);flex:none;
  padding:var(--space-3) var(--space-5);
  border:1px solid var(--border);border-radius:var(--radius-pill);
  color:var(--text-secondary);font-weight:600;font-size:var(--step-sm);white-space:nowrap;
}
/* A client's own mark sits inside the tile. One file per client
   (assets/<client>-logo.svg) — swapping that file updates every
   place the client appears, and nothing else has to change. */
.logo-tile img{width:24px;height:24px;flex:none;border-radius:7px;object-fit:cover}
.logo-tile-lg{padding:var(--space-3) var(--space-5) var(--space-3) var(--space-3);font-size:var(--step-body)}
.logo-tile-lg img{width:38px;height:38px;border-radius:11px}
.trust-strip{padding-block:var(--space-7)}
.trust-label{font-family:var(--font-mono);font-size:var(--step-eyebrow);letter-spacing:.14em;text-transform:uppercase;color:var(--text-muted);margin-bottom:var(--space-5)}

/* ---------- hero proof ----------
   One measured number, given all three hierarchy levers at once —
   size, weight and colour — because it is the single most important
   claim on the page. Everything beside it is deliberately quiet, and
   the attribution line is mandatory: a number with no source next to
   it is exactly what the rest of this site refuses to print. */
.hero-proof{
  display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-4) var(--space-6);
  margin-top:var(--space-7);padding-top:var(--space-6);
  border-top:1px solid var(--border);
}
.hero-proof .big{
  font-family:var(--font-mono);font-weight:700;
  /* the whitespace around the + is load-bearing: without it the maths
     expression fails to parse and the whole declaration is dropped */
  /* Tops out just above --step-h1 (4rem). It has to be the loudest thing
     on the page without out-shouting the headline that earns it — the
     thesis leads, the proof lands a beat later. */
  font-size:clamp(3.25rem, 2rem + 4.6vw, 5rem);line-height:.82;
  letter-spacing:-.055em;color:var(--text-accent);
  font-variant-numeric:tabular-nums;flex:none;
}
.hero-proof .said{max-width:32ch;min-width:15rem;flex:1}
.hero-proof .said b{display:block;color:var(--text-primary);font-size:var(--step-sm);line-height:1.4}
.hero-proof .said>span{display:block;margin-top:var(--space-2);font-size:var(--step-xs);color:var(--text-muted);line-height:1.5}
.hero-proof .said .link-arrow{margin-top:var(--space-3)}

/* ---------- service block (alternating) ---------- */
.service-block{padding-block:var(--section-y);border-top:1px solid var(--border)}
.service-grid{display:grid;gap:var(--space-7);align-items:center}
@media(min-width:980px){
  .service-grid{grid-template-columns:1fr 1fr;gap:var(--space-9)}
  .service-block:nth-of-type(even) .service-media{order:-1}
}
.service-block h2{margin-bottom:var(--space-4)}
.service-block p{color:var(--text-secondary);margin-bottom:var(--space-5);max-width:52ch}
.service-proof{display:flex;flex-wrap:wrap;gap:var(--space-6) var(--space-7);margin-bottom:var(--space-6)}

/* ---------- benefit card (numbered) ---------- */
.benefit .num{
  display:inline-flex;align-items:center;justify-content:center;
  width:40px;height:40px;margin-bottom:var(--space-4);
  border-radius:var(--radius-pill);background:var(--bg-accent-soft);
  color:var(--text-accent);font-family:var(--font-mono);font-weight:700;font-size:var(--step-sm);
}

/* ---------- case card ---------- */
.case-card{display:grid;gap:var(--space-4)}
.case-card .who{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap}
.case-card .story{color:var(--text-secondary)}
.case-card .metrics{display:flex;flex-wrap:wrap;gap:var(--space-5) var(--space-7);padding-top:var(--space-4);border-top:1px solid var(--border)}

/* ---------- caveat ----------
   The qualifier that has to travel with a number: what it measures,
   what it does not, and who it came from. Lives here rather than in
   pages.css because the work page and the notes page both need it,
   and a claim should not read differently depending on the page it
   lands on. */
.caveat{
  background:var(--bg-tint);border:1px solid var(--border);
  border-radius:var(--radius-sm);padding:var(--space-5);
  font-size:var(--step-sm);color:var(--text-muted);
  max-width:65ch;margin-top:var(--space-5);line-height:1.6;
}
.caveat b{color:var(--text-primary)}

/* ---------- placeholder slot ----------
   Anything not yet supplied renders as this. Deliberately loud:
   a missing asset must never look like a shipped one. */
.slot{
  border:2px dashed var(--border-strong);border-radius:var(--radius-card);
  background:repeating-linear-gradient(135deg,var(--bg-tint),var(--bg-tint) 10px,var(--bg-surface) 10px,var(--bg-surface) 20px);
  padding:var(--space-6);color:var(--text-secondary);
  display:grid;gap:var(--space-2);align-content:center;
}
.slot .k{font-family:var(--font-mono);font-size:var(--step-eyebrow);letter-spacing:.12em;text-transform:uppercase;color:var(--text-muted)}
.slot p{font-size:var(--step-xs);color:var(--text-muted)}

/* ---------- team card ---------- */
.team-card{text-align:left}
.team-photo{
  aspect-ratio:1;border-radius:var(--radius-card);overflow:hidden;
  background:var(--bg-tint);border:1px solid var(--border);
  display:grid;place-items:center;margin-bottom:var(--space-4);
}
.team-photo img{width:100%;height:100%;object-fit:cover}
.team-photo .ph{font-family:var(--font-mono);font-size:var(--step-eyebrow);letter-spacing:.1em;text-transform:uppercase;color:var(--text-muted);text-align:center;padding:var(--space-4)}
.team-card .role{font-size:var(--step-xs);color:var(--text-secondary);margin-bottom:var(--space-3)}
.team-card .tag-row{margin-bottom:var(--space-4)}

/* ---------- timeline ---------- */
.timeline{display:grid;gap:var(--space-5);counter-reset:tl}
@media(min-width:820px){.timeline{grid-template-columns:repeat(3,1fr)}}
.timeline .step{padding-top:var(--space-5);border-top:2px solid var(--border-accent)}
.timeline .yr{font-family:var(--font-mono);font-size:var(--step-eyebrow);letter-spacing:.12em;color:var(--text-accent);margin-bottom:var(--space-2)}
.timeline h3{margin-bottom:var(--space-2)}
.timeline p{color:var(--text-secondary);font-size:var(--step-sm)}

/* ---------- pricing ---------- */
.price-card{display:flex;flex-direction:column;gap:var(--space-4)}
.price-card .amt{font-family:var(--font-mono);font-weight:700;font-size:var(--step-metric);letter-spacing:-.03em;line-height:1}
.price-card .terms{font-size:var(--step-xs);color:var(--text-muted)}
.price-card .ticks{flex:1}
.price-card.featured{border-color:var(--border-accent);box-shadow:var(--shadow-lift)}

/* ---------- FAQ ----------
   Native <details>. Keyboard and screen-reader behaviour comes
   free and correct; do not replace with a div+JS disclosure. */
.faq{display:grid;gap:0;max-width:var(--wrap-narrow)}
.faq details{border-bottom:1px solid var(--border)}
.faq summary{
  display:flex;align-items:flex-start;justify-content:space-between;gap:var(--space-5);
  padding-block:var(--space-5);cursor:pointer;list-style:none;
  font-size:var(--step-h3);font-weight:700;letter-spacing:-.014em;line-height:1.3;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary:active{opacity:.7}
.faq summary::after{
  content:"";flex:none;width:14px;height:14px;margin-top:6px;
  border-right:2px solid var(--text-accent);border-bottom:2px solid var(--text-accent);
  transform:rotate(45deg);transition:transform var(--dur-base) var(--ease);
}
.faq details[open] summary::after{transform:rotate(-135deg)}
.faq .a{padding-bottom:var(--space-6);color:var(--text-secondary);max-width:62ch}
.faq .a p+p{margin-top:var(--space-4)}
@media(prefers-reduced-motion:reduce){.faq summary::after{transition:none}}

/* ---------- comparison (the objection list) ----------
   Five documented pain points, each as what it costs today versus the
   mechanic that replaces it. The design performs the argument: the old
   way is struck through and dimmed, the replacement is the only thing at
   full weight.

   The old way is struck through AT REST, not on hover. On a phone there is
   no hover, so an interaction-only argument would simply not exist for the
   buyer this page is written for. Hover deepens what is already legible;
   it never carries meaning on its own.

   No dark band here, unlike the pattern this borrows from — _internal/docs/design-system.md
   fixes the page background as white everywhere. */
.compare{border-top:1px solid var(--border)}
.compare-row{
  display:grid;gap:var(--space-3);align-items:center;
  padding-block:var(--space-5);
  border-bottom:1px solid var(--border);
  transition:background var(--dur-slow) var(--ease);
}
@media(min-width:820px){
  .compare-row{grid-template-columns:1fr auto 1fr;gap:var(--space-6);padding-block:var(--space-6)}
}
.compare-row:hover{background:var(--bg-tint)}

/* The dim-on-hover is capped by contrast, not by taste. Measured against
   --bg-tint, which is the surface this section actually sits on:

     --text-secondary at rest      7.88:1
     --text-secondary at opacity .8  4.70:1   <- the floor, AA body text is 4.5
     --text-muted     at opacity .8  3.20:1   FAILS
     --text-muted     at opacity .55 2.12:1   FAILS badly

   So the old way starts one step darker than muted and fades to exactly the
   muted value. It still visibly dissolves; it never becomes unreadable. */
.compare-old{
  color:var(--text-secondary);font-size:var(--step-body);line-height:1.45;
  text-decoration:line-through;
  text-decoration-color:var(--border-strong);
  text-decoration-thickness:1.5px;
  transition:opacity var(--dur-slow) var(--ease);
}
.compare-row:hover .compare-old{opacity:.8}

.compare-arrow{
  display:none;flex:none;color:var(--text-muted);
  transition:color var(--dur-slow) var(--ease),transform var(--dur-slow) var(--ease);
}
@media(min-width:820px){.compare-arrow{display:block}}
.compare-arrow svg{width:26px;height:26px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.compare-row:hover .compare-arrow{color:var(--text-accent);transform:translateX(6px)}

/* On mobile the two halves stack, so the replacement needs a mark of its own
   to read as the answer rather than as the next item in a list. */
.compare-new{
  color:var(--text-primary);font-weight:600;
  font-size:var(--step-body);line-height:1.45;
  padding-left:var(--space-4);border-left:2px solid var(--border-accent);
}
@media(min-width:820px){
  .compare-new{padding-left:0;border-left:0;text-align:right}
}

@media(prefers-reduced-motion:reduce){
  .compare-row,.compare-old,.compare-arrow{transition:none}
  .compare-row:hover .compare-arrow{transform:none}
}

/* ---------- CTA band ---------- */
.cta-band{
  background:var(--bg-tint);border:1px solid var(--border);
  border-radius:var(--radius-card);padding:clamp(32px,5vw,64px);
  display:grid;gap:var(--space-6);align-items:center;
}
@media(min-width:900px){.cta-band{grid-template-columns:1.2fr .8fr}}
.cta-band h2{margin-bottom:var(--space-4)}
.cta-band p{color:var(--text-secondary)}

/* ---------- agenda list (contact) ---------- */
.agenda{display:grid;gap:var(--space-6)}
@media(min-width:820px){.agenda{grid-template-columns:repeat(3,1fr)}}
.agenda h3{margin-bottom:var(--space-3)}
.agenda p{color:var(--text-secondary);font-size:var(--step-sm)}
.agenda .n{font-family:var(--font-mono);font-size:var(--step-eyebrow);color:var(--text-accent);letter-spacing:.12em;margin-bottom:var(--space-3);display:block}

/* ---------- steps (2-step expectation setter) ----------
   Scoped to ol.steps: the long-form pages use dl.steps for a
   different component (see assets/pages.css). Same word, two
   patterns, kept apart by element rather than by a rename. */
ol.steps{display:grid;gap:var(--space-5)}
@media(min-width:720px){ol.steps{grid-template-columns:repeat(2,1fr)}}
ol.steps li{display:flex;gap:var(--space-4);align-items:flex-start}
ol.steps .n{
  flex:none;width:36px;height:36px;border-radius:var(--radius-pill);
  display:grid;place-items:center;background:var(--bg-inverse);color:var(--text-on-inverse);
  font-family:var(--font-mono);font-weight:700;font-size:var(--step-xs);
}
ol.steps b{display:block;margin-bottom:var(--space-1)}
ol.steps p{color:var(--text-secondary);font-size:var(--step-sm)}

/* ============================================================
   FAKE-UI DEMOS
   Pure DOM + CSS, no images. Every demo is aria-hidden="true";
   the meaning is carried by the real text beside it. Values are
   illustrative and every demo block says so in visible text.
   ============================================================ */
.demo{
  background:var(--bg-surface);border:1px solid var(--border);
  border-radius:var(--radius-card);box-shadow:var(--shadow-ambient);
  padding:var(--space-5);display:grid;gap:var(--space-3);
}
.demo-bar{display:flex;align-items:center;gap:var(--space-2);padding-bottom:var(--space-3);border-bottom:1px solid var(--border);margin-bottom:var(--space-2)}
.demo-bar .dot{width:9px;height:9px;border-radius:50%;background:var(--border-strong)}
.demo-bar .t{font-family:var(--font-mono);font-size:var(--step-eyebrow);color:var(--text-muted);margin-left:var(--space-2)}
.demo-note{font-size:var(--step-eyebrow);font-family:var(--font-mono);color:var(--text-muted);letter-spacing:.04em}

/* chat */
.bub{max-width:82%;padding:var(--space-3) var(--space-4);border-radius:var(--radius-sm);font-size:var(--step-xs);line-height:1.45}
.bub.them{background:var(--bg-tint);color:var(--text-primary);border-bottom-left-radius:4px}
.bub.us{background:var(--btn-primary-bg);color:var(--text-on-accent);margin-left:auto;border-bottom-right-radius:4px}
.bub .ts{display:block;margin-top:var(--space-1);font-family:var(--font-mono);font-size:10px;opacity:.72}

/* inbox / row list */
.rows{display:grid;gap:var(--space-2)}
.row{
  display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);
  padding:var(--space-3) var(--space-4);border:1px solid var(--border);border-radius:var(--radius-chip);
  font-size:var(--step-xs);
}
.row .id{font-family:var(--font-mono);color:var(--text-muted)}
.row .st{font-family:var(--font-mono);font-size:var(--step-eyebrow)}
.row .st.ok{color:var(--text-accent)}
.row .st.wait{color:var(--text-muted)}
.row .amt{font-family:var(--font-mono);font-weight:700}

/* code editor */
.code{background:var(--bg-tint);border-radius:var(--radius-sm);padding:var(--space-4);font-family:var(--font-mono);font-size:var(--step-eyebrow);line-height:1.85;color:var(--text-secondary);overflow-x:auto}
.code .c{color:var(--text-muted)}
.code .k{color:var(--text-accent)}

/* stat card floating over a demo */
.stat-card{display:flex;flex-wrap:wrap;gap:var(--space-5) var(--space-6);padding:var(--space-4) var(--space-5);border:1px solid var(--border);border-radius:var(--radius-card);background:var(--bg-surface);box-shadow:var(--shadow-ambient)}

/* wide content must scroll inside itself, never the page */
.scroll-x{overflow-x:auto}

/* ============================================================
   HERO PHONE — animated WhatsApp illustration
   Content and timing live in assets/hero-thread.js; this file only
   describes the device and the message shapes.

   The whole thing is aria-hidden. The adjacent .demo-note names
   every scenario it plays, so nothing is only available to people
   who can see the animation. Under reduced-motion the script
   renders one complete conversation and stops.
   ============================================================ */

.phone-wrap{display:grid;justify-items:center;gap:var(--space-5)}

.iphone{
  /* 34vh keeps the whole device (and its caption) above the fold on short
     laptop screens; 300px is the ceiling, 84vw the floor on phones. */
  position:relative;width:min(300px,84vw,34vh);aspect-ratio:390/844;
  background:var(--device-frame);
  border-radius:56px;padding:11px;
  box-shadow:
    0 0 0 1.5px var(--device-edge),
    0 30px 60px -20px rgba(13,13,18,.32),
    0 8px 20px -8px rgba(13,13,18,.18);
}
/* the two rails, drawn rather than imaged */
.iphone::before,.iphone::after{
  content:"";position:absolute;left:-2px;width:2px;border-radius:2px;
  background:var(--device-edge);
}
.iphone::before{top:150px;height:34px}
.iphone::after{top:196px;height:56px}

.ip-screen{
  position:relative;width:100%;height:100%;overflow:hidden;
  border-radius:46px;background:var(--wa-canvas);
  display:flex;flex-direction:column;
  /* WhatsApp's wallpaper, approximated with two cheap gradients */
  background-image:
    radial-gradient(circle at 22% 18%, rgba(17,27,33,.035) 1.5px, transparent 1.6px),
    radial-gradient(circle at 72% 62%, rgba(17,27,33,.03) 1.5px, transparent 1.6px);
  background-size:46px 46px, 62px 62px;
}

.ip-island{
  position:absolute;top:9px;left:50%;transform:translateX(-50%);
  width:82px;height:24px;border-radius:var(--radius-pill);
  background:var(--device-frame);z-index:4;
}

/* ---- status bar ---- */
.ip-status{
  flex:none;display:flex;align-items:center;justify-content:space-between;
  padding:12px 26px 6px;font-size:11.5px;font-weight:700;color:var(--wa-text);
  font-family:var(--font-sans);letter-spacing:.01em;
}
.ip-status .r{display:flex;align-items:center;gap:4px}
.ip-status svg{width:15px;height:11px;fill:var(--wa-text)}

/* ---- chat header ---- */
.wa-top{
  flex:none;display:flex;align-items:center;gap:9px;
  padding:6px 12px 8px;background:var(--wa-bar);
  border-bottom:1px solid var(--wa-line);
}
.wa-back{flex:none;width:9px;height:9px;border-left:2px solid var(--wa-meta);border-bottom:2px solid var(--wa-meta);transform:rotate(45deg)}
.wa-av{
  flex:none;width:32px;height:32px;border-radius:50%;
  background:var(--l7-blue);display:grid;place-items:center;
}
.wa-av svg{width:17px;height:17px}
.wa-id{min-width:0;line-height:1.15}
.wa-name{font-size:13.5px;font-weight:700;color:var(--wa-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.wa-status{font-size:10.5px;color:var(--wa-meta);font-weight:500}
.wa-status.typing{color:var(--l7-blue)}

/* ---- message canvas ----
   Column reversed at the flex level so new messages push older
   ones off the top; no scroll position to manage, no jank. */
.wa-body{
  flex:1;min-height:0;display:flex;flex-direction:column;justify-content:flex-end;
  gap:6px;padding:10px 9px 8px;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 42px);
          mask-image:linear-gradient(180deg,transparent 0,#000 42px);
}

.wa-msg{
  max-width:78%;padding:6px 9px 5px;border-radius:9px;
  font-size:12.5px;line-height:1.38;color:var(--wa-text);
  box-shadow:0 1px .5px rgba(11,20,26,.13);
  position:relative;
  animation:wa-pop .26s var(--ease) both;
}
.wa-msg.biz{align-self:flex-start;background:var(--wa-in);border-top-left-radius:2px}
.wa-msg.me{align-self:flex-end;background:var(--wa-out);border-top-right-radius:2px}

.wa-foot{
  display:flex;align-items:center;justify-content:flex-end;gap:3px;
  margin-top:1px;font-size:9.5px;color:var(--wa-meta);white-space:nowrap;
}
.wa-foot .lag{
  margin-right:auto;font-family:var(--font-mono);font-size:9px;
  color:var(--l7-blue);font-weight:700;letter-spacing:.02em;
}
.wa-tick{width:13px;height:9px;flex:none;fill:none;stroke:var(--wa-tick);stroke-width:2.1;stroke-linecap:round;stroke-linejoin:round}

/* system line — missed call, handover */
.wa-sys{
  align-self:center;background:rgba(255,255,255,.9);
  padding:3px 9px;border-radius:7px;
  font-size:9.5px;color:var(--wa-meta);font-weight:600;
  box-shadow:0 1px .5px rgba(11,20,26,.1);
  animation:wa-pop .26s var(--ease) both;
}

/* typing indicator */
.wa-typing{
  align-self:flex-start;display:flex;gap:3px;align-items:center;
  background:var(--wa-in);padding:9px 11px;border-radius:9px;border-top-left-radius:2px;
  box-shadow:0 1px .5px rgba(11,20,26,.13);
  animation:wa-pop .2s var(--ease) both;
}
.wa-typing i{width:5px;height:5px;border-radius:50%;background:var(--wa-meta);opacity:.4;animation:wa-blink 1s infinite}
.wa-typing i:nth-child(2){animation-delay:.16s}
.wa-typing i:nth-child(3){animation-delay:.32s}

/* ---- composer ---- */
.wa-input{
  flex:none;display:flex;align-items:center;gap:6px;padding:6px 8px 10px;
}
.wa-input .box{
  flex:1;height:30px;border-radius:var(--radius-pill);background:var(--wa-in);
  display:flex;align-items:center;padding:0 11px;
  font-size:11.5px;color:var(--wa-meta);
  box-shadow:0 1px .5px rgba(11,20,26,.1);
}
.wa-input .send{
  flex:none;width:30px;height:30px;border-radius:50%;background:var(--l7-blue);
  display:grid;place-items:center;
}
.wa-input .send svg{width:14px;height:14px;fill:#fff}
.ip-bar{flex:none;width:100px;height:4px;border-radius:var(--radius-pill);background:rgba(17,27,33,.28);margin:0 auto 7px}

/* ---- caption + progress under the phone ---- */
.chat-caption{
  display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap;justify-content:center;
  font-family:var(--font-mono);font-size:var(--step-eyebrow);
  letter-spacing:.1em;text-transform:uppercase;color:var(--text-muted);
  min-height:1.2em;text-align:center;
}
.chat-caption b{color:var(--text-accent);font-weight:700}
.chat-dots{display:flex;gap:5px;justify-content:center}
.chat-dots i{
  width:5px;height:5px;border-radius:50%;background:var(--border-strong);
  transition:background var(--dur-base) var(--ease),transform var(--dur-base) var(--ease);
}
.chat-dots i.on{background:var(--text-accent);transform:scale(1.35)}

@keyframes wa-pop{
  from{opacity:0;transform:translateY(9px) scale(.985)}
  to{opacity:1;transform:none}
}
@keyframes wa-blink{
  0%,60%,100%{opacity:.32;transform:translateY(0)}
  30%{opacity:.9;transform:translateY(-2px)}
}

@media(prefers-reduced-motion:reduce){
  .wa-msg,.wa-sys,.wa-typing{animation:none}
  .wa-typing i{animation:none;opacity:.4}
  .chat-dots i{transition:none}
}
