/* GENERATED by build-site.py — do not edit, and do not let the model write here.
   palette: accent=#fb23c2 dark=#090a0a light=#16181a
   page ground: #090a0a  → DARK, light-side tokens aliased to the dark scale
   Tokens are solved against WCAG targets, not declared; see scripts/css_tokens.py. */
:root{--accent:#fb23c2;--accent-ink:#000000;--accent-line:#821666;--accent-tint:#2d192b;--accent-tint-2:#3f1a38;--accent-text:#fb23c2;--accent-text-dark:#fb23c2;--light:#16181a;--ink:#ffffff;--surface:#191b1d;--surface-2:#1e2022;--surface-3:#26282a;--muted:#8d8e8f;--faint:#747576;--line:#292b2c;--line-strong:#3e4041;--dark-1:#090a0a;--dark-2:#141515;--dark-3:#1f2020;--dark-ink:#ffffff;--muted-dark:#868787;--faint-dark:#6e6e6e;--line-dark:#383939;--e-accent:0 8px 26px -10px #c22098;--s1:.25rem;--s2:.5rem;--s3:.75rem;--s4:1rem;--s5:1.5rem;--s6:2rem;--s7:3rem;--s8:4rem;--s9:clamp(5.5rem,7vw,7.5rem);--gutter:clamp(18px,3.9vw,56px);--r-sm:6px;--r:14px;--r-lg:20px;--r-pill:999px;--t-cap:.75rem;--t-eyebrow:.8125rem;--t-sm:.9375rem;--t-body:1.0625rem;--t-lead:1.1875rem;--t-h3:1.0625rem;--t-h2:clamp(1.75rem,3vw,2.5rem);--t-h1:clamp(2.5rem,4.6vw,4rem);--tr-tight:-.015em;--tr-wide:.12em;--measure:68ch;--ease:cubic-bezier(.22,1,.36,1);--e1:0 1px 2px rgb(0 0 0/.04),0 1px 3px rgb(0 0 0/.06);--e2:0 2px 4px rgb(0 0 0/.04),0 8px 20px -6px rgb(0 0 0/.10);}
:root{--ink:#ffffff;--surface:#141515;--surface-2:#141515;--surface-3:#1f2020;--muted:#868787;--faint:#6e6e6e;--line:#383939;--line-strong:#383939;--accent-text:#fb23c2;}
/* B — COMPONENT LAYER for C1..C12. Emitted verbatim by build-site.py, identical on every site.
   These are the nine components plan-pages.py asks for that today have no class at all. */

/* --- A0: the heading scale. The hole this fills was the biggest one in the whole floor ---
   A sub-page emits a BARE <h1> with no class, and site.css only ever styles `.hero h1`. So on
   topazlabs.site every one of the 126 sub-pages rendered its h1 at the browser default 2em/32px
   — smaller than several of its own h2s — and the same was true of every site before it. The
   most important type on the page had never been designed on any of them.
   Scoped to `main` so it cannot fight the nav/footer, and it loses to site.css on source order,
   so a site that genuinely styled its headings keeps its own design. */
main h1{font-size:var(--t-h1);line-height:1.04;font-weight:700;
  letter-spacing:var(--tr-tight);margin:0 0 var(--s5);text-wrap:balance}
main h2{font-size:var(--t-h2);line-height:1.12;font-weight:700;
  letter-spacing:var(--tr-tight);margin:0 0 var(--s4);text-wrap:balance}
main h3{font-size:var(--t-h3);line-height:1.22;font-weight:700;
  letter-spacing:var(--tr-tight);margin:0 0 var(--s2)}
/* An h1 must never be out-sized by an h2 below it. `.hero h1` on the landing sets its own, larger
   size and wins on specificity; this is the floor for everything that does not. */
main>*>h1+p,main h1+p{font-size:var(--t-lead);color:var(--muted);max-width:var(--measure)}

/* --- A0b: COMPOSITION. The three defects that only exist once components sit together ---
   Measured on viduai.site's 12 sub-pages, 2026-08-27. None of these is a broken component; each
   is what happens when correct components are stacked and nobody looks at the result. They are
   fixed here rather than by a reviewing pass because they are systematic: one rule closes 29
   instances at once, where a per-page review rediscovers them every build and never the same way.

   1. MEASURE. Body copy ran the full 1240px container — over 100 characters a line, which reads
      as a grey slab however good the leading is. 29 paragraphs across 7 pages, 15 of them a bare
      <p>. Components that manage their own width opt out below. */
main p{max-width:var(--measure)}
.card p,.spec p,.spec td,.spec th,.split dd,.versus li,.metric span,.calc p,td p,th p{max-width:none}

/* 2. RHYTHM. Median gap between stacked blocks was 16px and 13 pairs sat under 12px — the top
      offender by far being `.ba` against its own `.ba-note` (5 of 13), which this file owns. A
      caption touching the figure it describes reads as a collision, not as a pair. */
.ba-note{margin-top:var(--s4)}
main section>*+*,main section>*>*+*{margin-top:max(var(--s4),0px)}
.card>*+*,.spec tr>*,.steps>*,.cases>*,.versus>*,.limits>*,.split>*{margin-top:0}

/* 3. IMAGE CEILING. A figure with no height limit produced a 114vh image — taller than the
      viewport, so the page opened on a picture with no way to see what it belonged to. The cap is
      generous on purpose: it disallows "taller than the screen", not "large". */
main img{max-height:80vh}
.ba img,.card img{max-height:none}
/* 3b. WIDTH. `.ba img` got `width:100%` and nothing else did, so an image alone in a card rendered
      at its own intrinsic width inside a wider box — heygen-ai-avatar's `.object-card` held a
      900px picture in a 1240px bordered card and the right third was blank white. It reads as a
      broken media slot, not as a margin. Scoped to :only-child so an image that is one of several
      things in a card keeps whatever layout put it there. */
main figure>img:only-child,.card>img:only-child,.object-card>img:only-child{
  width:100%;height:auto;display:block}

/* --- A1: depth. Flat-on-flat is what makes a dark page read as unfinished --- */
/* A single hairline card on a near-black band has no light in it at all. These give a surface an
   actual top-lit edge and a soft contact shadow, which is what "光影" means in practice: a
   1px inset highlight along the top, a wide ambient shadow under it. Cheap, and it is the
   difference between a card and a rectangle. */
.card,.spec-wrap,.faq details{position:relative}
.card::before,.faq details::before{content:"";position:absolute;inset:0;border-radius:inherit;
  pointer-events:none;background:linear-gradient(180deg,rgb(255 255 255/.055),transparent 38%)}
.band-dark .card,.band-dark .faq details{box-shadow:0 1px 0 rgb(255 255 255/.04) inset,
  0 18px 40px -24px rgb(0 0 0/.9)}
.band-dark .card:hover{box-shadow:0 1px 0 rgb(255 255 255/.07) inset,
  0 26px 56px -26px rgb(0 0 0/.95);border-color:var(--accent-line)}

/* --- the classes build-site.py INJECTS, which no stylesheet ever styled ---
   Measured 2026-08-27: pbn-lang, pbn-langbar, breadcrumb and pbn-crumb appear on every page of
   every site and are defined nowhere — our own script emits them and then leaves them to whatever
   the model happened to write. A generated element with no rule is an element that renders however
   the surrounding cascade feels. */
.pbn-crumb,.breadcrumb{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s2);
  font-size:var(--t-cap);color:var(--muted);margin:0 0 var(--s4)}
/* --muted (solved to 4.5:1), not whatever the page happens to inherit. The breadcrumb was picking
   up --faint, which css_tokens solves to a 3.2:1 target — right for a decorative eyebrow, wrong
   for functional navigation text at 13px, where AA wants 4.5:1. Measured on lumalabs.pro:
   rgb(95,93,89) on rgb(5,6,7) = 3.09:1. visual-check reported dim=0 for that page because its
   contrast selector list had no a/span in it; both halves are fixed together. */
.pbn-crumb,.breadcrumb{color:var(--muted)}
.pbn-crumb a,.breadcrumb a{color:inherit;text-decoration:none;border-bottom:1px solid var(--line)}
.pbn-crumb a:hover,.breadcrumb a:hover{border-bottom-color:var(--accent)}
.pbn-langbar,.pbn-lang{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3);
  font-size:var(--t-cap)}
.pbn-langbar a,.pbn-lang a{color:var(--muted);text-decoration:none}
.pbn-langbar a[aria-current],.pbn-lang a[aria-current]{color:var(--ink);font-weight:600}
/* the generated footer rail — every sub-page, on every page */
.pbn-sublinks{display:flex;flex-wrap:wrap;gap:var(--s2) var(--s4);margin-top:var(--s5);
  padding-top:var(--s4);border-top:1px solid var(--line);font-size:var(--t-cap)}
.pbn-sublinks a{color:var(--muted);text-decoration:none}
.pbn-sublinks a:hover{color:var(--accent)}
.band-dark .pbn-sublinks,footer .pbn-sublinks{border-top-color:var(--line-dark)}
.band-dark .pbn-sublinks a,footer .pbn-sublinks a{color:var(--muted-dark)}

/* --- band rhythm: every <section> gets it, class or not (fixes the 6 classless pages) --- */
/* The horizontal gutter lives on the SECTION, not on a wrapper class, because the wrapper class
   is whatever the model decided to call it that day. Measured 2026-08-27: elevenlabsai.pro's
   sub-pages wrap content in `class="shell"`, `container`, `band-shell` and `band-inner` — none of
   which any stylesheet defines — so every line of prose started at x=0 at both 1440px and 390px.
   A section is where the band background lives, so insetting it costs nothing visually and cannot
   be missed by naming something differently. A model wrapper with its own max-width still wins;
   this only decides where the edge is when nothing else does. */
main>section,section.band{padding:var(--s9) var(--gutter)}
section.band-tint{background:var(--surface-2);color:var(--ink);border-block:1px solid var(--line);padding:var(--s9) var(--gutter)}
/* INK, not ground. `--light` names the light BACKGROUND, and using it here for text on the
   dark band overloaded one token with two opposite meanings — which broke the moment the
   dark-page override re-pointed it: viduai.site rendered #020b13 headings on a #020b13
   band, contrast 1.00:1. `--dark-ink` is ink_on(dark) and means exactly this. */
section.band-dark{background:var(--dark-1);color:var(--dark-ink);padding:var(--s9) var(--gutter)}
section.band-dark h2,section.band-dark h3{color:var(--dark-ink)}
section.band-dark p{color:var(--muted-dark)}

/* C1 — a component that paints its own BACKGROUND must paint its own FOREGROUND.
   Eight rules here set a background and left `color` to inherit. A component cannot know which
   band it will be dropped into, so an inherited colour is a colour chosen by whoever wrote the
   section wrapper. Measured on elevenlabsai.pro 2026-08-27: `.checklist li` sits on
   background:var(--surface) (#f9f8f8) inside the model's own `.section-dark{color:#fff}` and
   rendered white on near-white at 1.06:1 — with NO rule matching the <li> at all. Same mechanism
   produced the 1.2:1 limits cards and, on other sites, four completely blank comparison tables. */
/* --- shared card primitive; every component card composes it --- */
.card{background:var(--surface);color:var(--ink);border:1px solid var(--line);border-radius:var(--r);
  padding:var(--s5);box-shadow:var(--e1);transition:box-shadow .25s var(--ease),
  border-color .25s var(--ease),transform .25s var(--ease)}
.card:hover{box-shadow:var(--e2);border-color:var(--line-strong);transform:translateY(-2px)}
/* line-height is the load-bearing half. Measured on pencilai.site, card titles rendered at
   17.6px/lh 1.60 next to 18px/lh 1.60 body copy — a heading SMALLER than the text beside it and
   just as loose reads as a bolded first line, not a heading. 1.22 is what makes it a label. */
.card h3{font-size:var(--t-h3);line-height:1.22;font-weight:700;letter-spacing:var(--tr-tight);
  margin:0 0 var(--s2)}
.card p{color:var(--muted);font-size:var(--t-sm);margin:0}
.band-dark .card{background:var(--dark-2);color:var(--dark-ink);border-color:var(--line-dark);box-shadow:none}
.band-dark .card:hover{border-color:var(--accent-line)}

/* --- C1 SpecTable --- */
.spec,.compare{width:100%;border-collapse:collapse;background:var(--surface);color:var(--ink);border:1px solid var(--line);
  border-radius:var(--r);overflow:hidden}
.spec-wrap{overflow-x:auto;border-radius:var(--r);box-shadow:var(--e1)}
.spec th,.spec td,.compare th,.compare td{padding:var(--s3) var(--s4);text-align:left;font-size:var(--t-sm);
  border-bottom:1px solid var(--line)}
.spec thead th,.compare thead th{background:var(--surface-3);font-weight:600;font-size:var(--t-cap);
  text-transform:uppercase;letter-spacing:var(--tr-wide);color:var(--faint)}
.spec tbody tr:last-child td,.compare tbody tr:last-child td{border-bottom:0}
.spec td:first-child,.compare td:first-child{font-weight:600}
.spec .yes::before{content:"✓";color:var(--accent-ink);background:var(--accent);
  border-radius:var(--r-pill);display:inline-grid;place-items:center;width:1.1em;height:1.1em;
  font-size:.72em;margin-right:.4em;vertical-align:.05em}
.spec .no::before{content:"—";color:var(--faint);margin-right:.4em}

/* --- names the generator uses for components this file already has ---------------------------
   Found by audit-site.py's undefined-class check, which exists because `.ba-divider` was unstyled
   and silently broke a two-column grid. These three are milder — an unstyled class renders as
   DEFAULT, not as nothing — but default is what a designed page is trying not to be: `.compare`
   was a bare collapsed-border table on luma-ray-3, `.lead` was body copy, and `.verdict` read as
   the first bullet of the list under it rather than as the judgement above it.
   `.section-lead` is here because only ONE of the two sites had it in its own site.css. */
.lead,.section-lead{font-size:var(--t-lead);line-height:1.6;color:var(--muted);max-width:62ch}
/* Not `color:var(--ink)`: on a dark band `section.band-dark p` (0,1,2) already wins, and stating
   the light-band ink here only adds a rule that loses. Weight is what makes it a verdict. */
.verdict,.card-verdict{font-weight:700;margin:0 0 var(--s3)}

/* --- C2 VersusCards --- */
.versus{display:grid;gap:var(--s4);grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
.versus .card{display:flex;flex-direction:column;gap:var(--s3)}
.versus .card.is-win{border-color:var(--accent-line);box-shadow:var(--e2)}
.versus ul{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:var(--s2)}
.versus li{font-size:var(--t-sm);color:var(--muted);padding-left:1.4em;position:relative}
.versus li.pro::before{content:"✓";position:absolute;left:0;color:var(--accent-ink);font-weight:700}
.versus li.con::before{content:"✕";position:absolute;left:0;color:var(--faint)}

/* --- C3 DecisionSplit --- */
.split{display:grid;gap:var(--s4);grid-template-columns:repeat(auto-fit,minmax(16rem,1fr))}
.split .card{border-top:3px solid var(--accent)}
.split dt{font-weight:700;font-size:var(--t-sm);margin-bottom:var(--s1)}
.split dd{margin:0 0 var(--s3);color:var(--muted);font-size:var(--t-sm)}

/* --- C4 StepFlow --- */
/* list-style:none is NOT optional here, and it was missing. The component paints its own
   "01 02 03" from a CSS counter, and the generator quite correctly reaches for <ol class="steps">
   because a how-it-works strip IS an ordered list — so the browser painted its native "1. 2. 3."
   as well, right next to the big amber numeral, on 282 pages across five live sites. .versus ul,
   .checklist and .timeline all remembered this reset; only C4 forgot. padding/margin go with it:
   a native <ol> also carries 40px of inline start padding, which pushed the whole strip out of
   alignment with every other band on the page. */
/* margin-top, not margin:0. Killing the native <ol> margin outright closed the gap between the
   section's lead paragraph and the strip to ZERO — measured on lumalabs.pro right after the
   list-style fix, so this component has now caused two collisions in one day. Remove the native
   margin's left/right/bottom, keep a real gap above. */
.steps{display:grid;gap:var(--s4);grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));
  counter-reset:step;list-style:none;padding:0;margin:var(--s7) 0 0}
/* padding-top must CLEAR the numeral. ::before is 2.4rem at line-height 1 = 38.4px and sits at
   top:0, while padding-top was --s6 (2rem = 32px) — so the number overlapped the <h3> beneath it
   by 6px on every step of every site using C4. --s7 (3rem = 48px) leaves 10px of air. */
.steps>*{counter-increment:step;position:relative;padding-top:var(--s7)}
.steps>*::before{content:counter(step,decimal-leading-zero);position:absolute;top:0;left:0;
  font-size:2.4rem;font-weight:800;line-height:1;letter-spacing:var(--tr-tight);
  color:var(--accent);opacity:.9}
.steps h3{font-size:var(--t-h3);margin:0 0 var(--s2)}
.steps p{color:var(--muted);font-size:var(--t-sm);margin:0}

/* --- C5 MetricStrip --- */
.metrics{display:grid;gap:var(--s5);grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));
  border-block:1px solid var(--line);padding:var(--s6) 0}
.metric b{display:block;font-size:clamp(1.9rem,3.4vw,2.7rem);font-weight:800;line-height:1;
  letter-spacing:var(--tr-tight)}
.metric span{display:block;margin-top:var(--s2);font-size:var(--t-cap);color:var(--muted)}
.band-dark .metrics{border-color:var(--line-dark)}
.band-dark .metric span{color:var(--muted-dark)}

/* --- C6 UseCaseGrid --- */
.cases{display:grid;gap:var(--s4);grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
.cases .card{display:flex;flex-direction:column;gap:var(--s2)}
.cases .card a{color:inherit;text-decoration:none;font-weight:600;font-size:var(--t-sm);
  margin-top:auto;padding-top:var(--s2);border-bottom:1px solid var(--accent-line);
  align-self:flex-start;transition:border-color .2s var(--ease)}
.cases .card a:hover{border-bottom-color:var(--accent)}

/* --- C7 LimitationGrid --- */
.limits{display:grid;gap:var(--s4);grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
/* `.limits .card` forces a LIGHT surface, and `section.band-dark h2,h3` paints its headings with
   the dark band's ink. Inside a dark band those two meet: white on #ebeaea, 1.2:1, on every
   .limits block of every page — measured on elevenlabsai.pro 2026-08-27. A band-scoped colour
   rule must never reach inside an element that redeclared its own background, so the card follows
   the band it is in and re-states its own foreground rather than inheriting one. */
.limits .card{background:var(--surface-3);color:var(--ink);box-shadow:none}
.band-dark .limits .card{background:var(--dark-2);color:var(--dark-ink);border-color:var(--line-dark)}
.band-dark .limits .card h3{color:var(--dark-ink)}
.band-dark .limits .fix,.band-dark .limits .card p{color:var(--muted-dark)}
.limits .card h3::before{content:"!";display:inline-grid;place-items:center;width:1.35em;
  height:1.35em;margin-right:.5em;border-radius:var(--r-pill);background:var(--accent-tint-2);
  font-size:.8em;vertical-align:.08em}
/* `.fix` holds a sentence ("Workaround: split the story into scenes"), not a label. --faint is
   solved to a 3.2:1 EYEBROW target on purpose, so using it here put real prose at 3.2:1 on every
   .limits block of every site — 11 instances on viduai.site, 12 on elevenlabsai.pro, and the
   single largest remaining contrast failure on both. Prose gets the 4.5:1 token. */
.limits .fix{margin-top:var(--s2);font-size:var(--t-cap);color:var(--muted)}

/* --- C8 ChecklistReq --- */
.checklist{list-style:none;padding:0;margin:0;max-width:var(--measure);
  display:flex;flex-direction:column;gap:var(--s2)}
.checklist li{display:flex;gap:var(--s3);align-items:flex-start;padding:var(--s3) var(--s4);
  background:var(--surface);color:var(--ink);border:1px solid var(--line);border-radius:var(--r-sm);
  font-size:var(--t-sm)}
.checklist li::before{content:"✓";flex:none;display:grid;place-items:center;width:1.35em;
  height:1.35em;border-radius:var(--r-pill);background:var(--accent);color:var(--accent-ink);
  font-size:.78em;font-weight:700}
.checklist li.optional::before{content:"○";background:transparent;border:1px solid var(--line-strong);
  color:var(--faint)}

/* --- C9 CompareVisual --- */
.ba{display:grid;gap:var(--s3);grid-template-columns:1fr 1fr;align-items:start}
/* A `→` between the two halves is a shape the generator emits and this file never defined, so it
   landed in the two-column grid as a third item: figure, divider, figure means the SECOND figure
   starts a new row. Measured on heygen-ai-for-real-estate: both images 614px wide at x=100, one
   column doing the work of two, with the arrow floating beside the upper one. A before/after that
   reads as two stacked thumbnails is not a before/after. */
.ba:has(>.ba-divider){grid-template-columns:1fr auto 1fr}
.ba-divider{align-self:center;justify-self:center;color:var(--muted);font-size:1.5rem;
  line-height:1;-webkit-user-select:none;user-select:none}
.ba figure{margin:0;position:relative}
.ba img{width:100%;height:auto;display:block;border-radius:var(--r);border:1px solid var(--line);
  box-shadow:var(--e2)}
.ba figcaption{position:absolute;top:var(--s3);left:var(--s3);padding:.25rem .6rem;
  border-radius:var(--r-pill);background:var(--accent);color:var(--accent-ink);
  font-size:var(--t-cap);font-weight:700;letter-spacing:.02em}
.ba-note{grid-column:1/-1;text-align:center;color:var(--muted);font-size:var(--t-cap);
  margin-top:var(--s2)}

/* --- C10 CalcWidget --- */
.calc{max-width:34rem;margin:0 auto;padding:var(--s6);background:var(--surface);color:var(--ink);
  border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--e2)}
.calc label{display:block;font-size:var(--t-cap);font-weight:600;color:var(--faint);
  text-transform:uppercase;letter-spacing:var(--tr-wide);margin-bottom:var(--s3)}
.calc input[type=range]{width:100%;accent-color:var(--accent);margin-bottom:var(--s5)}
.calc-out{display:grid;gap:var(--s4);grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));
  border-top:1px solid var(--line);padding-top:var(--s4)}
.calc-out b{display:block;font-size:1.6rem;font-weight:800;letter-spacing:var(--tr-tight)}
.calc-out span{font-size:var(--t-cap);color:var(--muted)}

/* --- C11 Timeline --- */
.timeline{list-style:none;margin:0;padding:0 0 0 var(--s5);max-width:var(--measure);
  border-left:2px solid var(--line)}
.timeline li{position:relative;padding:0 0 var(--s5) var(--s4)}
.timeline li::before{content:"";position:absolute;left:calc(-1 * var(--s5) - 5px);top:.45em;
  width:10px;height:10px;border-radius:var(--r-pill);background:var(--accent);
  box-shadow:0 0 0 4px var(--accent-tint)}
.timeline time{display:block;font-size:var(--t-cap);color:var(--faint);font-weight:600;
  letter-spacing:.04em}
.timeline h3{font-size:var(--t-h3);margin:var(--s1) 0 var(--s2)}
.timeline p{color:var(--muted);font-size:var(--t-sm);margin:0}

/* --- C12 RelatedRail (pill row) --- */
.rail{display:flex;flex-wrap:wrap;gap:var(--s2);padding:var(--s4) 0;margin:var(--s5) 0;
  border-block:1px solid var(--line)}
.pill{display:inline-flex;align-items:center;gap:var(--s2);padding:.4rem .85rem;
  border:1px solid var(--line-strong);border-radius:var(--r-pill);font-size:var(--t-cap);
  text-decoration:none;color:inherit;background:var(--surface);
  transition:background .2s var(--ease),border-color .2s var(--ease)}
.pill:hover{background:var(--accent-tint);color:var(--accent-text);border-color:var(--accent-line)}
.pill::after{content:"→";opacity:.5}

/* --- buttons: three variants, one shape --- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  padding:.85rem 1.6rem;border-radius:var(--r-pill);font-weight:700;font-size:var(--t-body);
  line-height:1;text-decoration:none;border:1px solid transparent;cursor:pointer;
  transition:transform .2s var(--ease),box-shadow .2s var(--ease),background .2s var(--ease)}
.btn-primary{background:var(--accent);color:var(--accent-ink)}
.btn-primary:hover{transform:translateY(-2px);box-shadow:var(--e-accent)}
.btn-ghost{background:transparent;border-color:currentColor;opacity:.85}
.btn-ghost:hover{opacity:1;background:var(--accent-tint);color:var(--accent-text)}
.btn-sm{padding:.5rem 1rem;font-size:var(--t-cap)}
.btn-lg{padding:1rem 2rem;font-size:var(--t-lead)}

/* --- section head, shared by all 12 --- */
.section-head{max-width:44rem;margin:0 auto var(--s7);text-align:center}
.eyebrow{text-transform:uppercase;letter-spacing:var(--tr-wide);font-size:var(--t-eyebrow);
  font-weight:600;color:var(--faint);margin:0 0 var(--s3)}
.band-dark .eyebrow{color:var(--accent)}
/* scoped, NOT a bare `h2` — base.css loads BEFORE site.css, and a bare element
   selector here would still beat nothing while silently fighting a landing that
   styles its own h2. Sub-page sections carry .section-head; the landing does not. */
.section-head h2{font-size:var(--t-h2);line-height:1.15;letter-spacing:var(--tr-tight);
  text-wrap:balance;margin:0}
.section-sub{color:var(--muted);margin:var(--s3) auto 0;max-width:var(--measure);
  text-wrap:balance}

/* --- accessibility + motion --- */
:where(a,button,summary,[tabindex]):focus-visible{outline:3px solid var(--accent);
  outline-offset:3px;border-radius:var(--r-sm);
  box-shadow:0 0 0 6px color-mix(in srgb,var(--ink) 55%,transparent)}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
  .card:hover,.btn:hover{transform:none}
}

/* --- responsive: one place, not per-component --- */
@media (max-width:900px){
  /* both selectors, or the 3-column `:has` rule above wins here and the pair stays side by side
     at phone width. The arrow has to turn with the axis it points along. */
  .ba,.ba:has(>.ba-divider){grid-template-columns:1fr}
  .ba-divider{transform:rotate(90deg)}
  main>section,section.band,section.band-tint,section.band-dark{padding:var(--s8) 0}
}
@media (max-width:640px){
  .spec-wrap{margin-inline:calc(-1 * var(--s5))}
  .rail{gap:var(--s1)}
}
