/* Wattlas — editorial styles for the navigation/landing layer.
 * Loaded only by the chrome pages: the home page (index.html), the five long-scroll
 * section hubs (/rhythm, /grid, …) and the seven standard pages (/about, …), all
 * generated by pipeline/build_html.py. The 23 view pages keep their own internal
 * styles; site chrome (sidebar, footer, mobile bars) is injected by nav.js.
 *
 * Tokens (--bg/--text/--muted/--hint/--border, --s-* accents, --serif) come
 * from the page <head> + nav.js. This file styles only the editorial content. */

@import url("tokens.css");
@import url("layout.css"); /* first-paint geometry, #370 */

* { box-sizing:border-box; }
body { margin:0; background:var(--bg); color:var(--text);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  line-height:1.6; -webkit-font-smoothing:antialiased; }

/* Editorial content gutter (overrides nav.js .main-inner defaults) */
.wx-page .main { padding:0 48px 110px; }
.wx-page .main-inner { max-width:min(1220px,100%); margin:0 auto; padding-top:40px; }

/* Wrap policy.
   Every block runs to the edge of its container, so `balance` is off on body text —
   it would pull lines back in from the edge they are meant to reach. Headings keep
   it: a headline that fills one line and drops two words onto the next is the break
   that reads as broken. Chrome implements `text-wrap: pretty` as a no-op on these
   blocks, so `balance` is the only declaration that actually does anything. */

/* shared bits */
.btn { display:inline-flex; align-items:center; gap:7px; background:var(--text); color:var(--bg);
  text-decoration:none; font-size:var(--fs-ui); font-weight:500; padding:11px 18px; border-radius:999px; }
.btn:hover { background:var(--ink-strong); }
.btn.ghost { background:transparent; color:var(--muted); border:.5px solid var(--border); }
.btn.ghost:hover { color:var(--text); border-color:var(--hint); }
/* The one small-label style: eyebrow, "Seven questions" rule, chip labels, "Next question",
   the standard page kicker. They used to be five copies with tracking from .09em to .13em. */
.eyebrow, .sections-head, .chips-lbl, .ns-lbl, .page-hero .pk {
  font-size:var(--fs-label); font-weight:600; letter-spacing:.1em; text-transform:uppercase; color:var(--hint); }
.eyebrow { margin:0 0 14px; }
.crumb { display:flex; align-items:center; gap:8px; font-size:var(--fs-caption); color:var(--hint); margin-bottom:26px; flex-wrap:wrap; }
.crumb a { color:var(--muted); text-decoration:none; }
.crumb a:hover { color:var(--text); }
.crumb span { color:var(--hint); }

/* ---------- HOME ---------- */
/* The hero (#278): words standing on the horizon. Headline, lead and the single action,
   stacked, and beneath them the plate — the site's whole cast on one ground line. The
   words take the whole content width and scale with it (the owner's call over a
   two-column split): the headline sets in two lines on a wide monitor and three on a
   laptop, and the lead grows with it so its measure stays readable as it widens. The ask
   box that stood beside the headline (#228) is the eighth tile of the grid instead. */
.home-hero { max-width:none; margin:6px 0 0; }
.home-hero h1 { font-family:var(--serif); font-weight:500; font-size:clamp(36px,4.1vw,76px); line-height:1.06; letter-spacing:-.018em; margin:0 0 22px; text-wrap:balance; }
.home-hero h1 em { font-style:italic; color:var(--s-amber); }
.home-hero .lead { font-size:clamp(17px,1.5vw,25px); color:var(--muted); max-width:92ch; margin:0 0 28px; line-height:1.5; }
.hero-actions { display:flex; gap:12px; flex-wrap:wrap; }
.hero-actions .btn { min-height:44px; }
.hero-actions .btn svg { flex:none; }
/* The monthly newsletter band under the home plate (#503): flat, one hairline, one row on a
   wide screen (words left, field and button right); on a phone the field row takes the full
   width under the words. 16px in the field so iOS does not zoom on focus. */
.home-news { position:relative; margin:22px 0 30px; padding:12px 12px 12px 18px; display:flex; flex-wrap:wrap; align-items:center;
  justify-content:space-between; gap:10px 24px; background:var(--surface); border:.5px solid var(--border); border-radius:var(--radius); }
/* Desktop: title over hint, field beside them. On a phone the field goes underneath, so the
   title and hint share one line there (owner, 27 September 2026). */
.home-news .hn-text { flex:1 1 200px; display:grid; gap:2px; min-width:0; }
.home-news .hn-title { margin:0; font-family:var(--serif); font-size:19px; font-weight:500; line-height:1.3; color:var(--text); }
.home-news .hn-hint { margin:0; font-size:var(--fs-caption); color:var(--hint); }
.home-news .hn-hint a { color:var(--text); text-decoration:none; border-bottom:1px solid var(--border); }
.home-news .hn-hint a:hover { border-color:var(--text); }
.home-news .hn-row { display:flex; gap:8px; flex:0 1 380px; min-width:0; }
.home-news input[type=email] { flex:1 1 auto; min-width:0; min-height:44px; box-sizing:border-box; padding:10px 16px; font:inherit;
  font-size:16px; color:var(--text); background:var(--bg); border:1px solid var(--hint); border-radius:999px; }
.home-news input[type=email]:focus-visible { outline:2px solid var(--text); outline-offset:1px; }
.home-news .btn { flex:none; min-height:44px; border:0; cursor:pointer; font:inherit; font-size:var(--fs-ui); font-weight:500; }
.home-news .btn[disabled] { opacity:.6; cursor:default; }
.home-news .hn-status { flex-basis:100%; margin:0; font-size:var(--fs-emph); color:var(--text); }
.home-news .hn-status:empty { display:none; }
@media (max-width:640px) {
  /* 16px title, 6px gap, 12px sides: title and hint fit one line at 390px; narrower wraps. */
  .home-news { padding:14px 12px; }
  .home-news .hn-text { display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 6px; }
  .home-news .hn-title { font-size:16px; }
  .home-news .hn-row { flex:1 1 100%; }
}
@media (max-width:380px) {
  .home-news .hn-title { font-size:15px; }
  .home-news .hn-hint { font-size:11px; }
}
/* The plate sits directly under the words and directly over the "Seven questions" rule,
   so its ground line reads as the seam between the two. Transparent ground, no box, no
   cap: the strip is 4.4:1 by construction, so it is never taller than the slot. */
.home-plate { margin:4px 0 22px; line-height:0; }
.home-plate img { width:100%; height:auto; display:block; }
/* The plate is also the way into /adayonthegrid (the deck tells the site as one day on
   this horizon). It is captioned like a printed plate: a serif line saying what the drawing
   is, then the link. The link's ::after covers the figure, so the strip itself is clickable
   with one tab stop, and hovering anywhere on it lifts the caption. */
.home-plate { position:relative; }
.home-plate figcaption { line-height:1.45; margin-top:12px; display:flex; flex-wrap:wrap; align-items:baseline; gap:4px 7px; }
.plate-sub { font-family:var(--serif); font-style:italic; font-size:16px; color:var(--muted); }
.plate-link { display:inline-flex; align-items:center; gap:6px; font-size:var(--fs-ui); font-weight:500; color:var(--text);
  text-decoration:underline; text-decoration-color:var(--border); text-decoration-thickness:1px; text-underline-offset:4px;
  transition:text-decoration-color .18s ease-out; }
.plate-link::after { content:""; position:absolute; inset:0; }
.plate-link svg { flex:none; transition:transform .18s ease-out; }
.home-plate:hover .plate-link { text-decoration-color:currentColor; }
.home-plate:hover .plate-link svg { transform:translateX(3px); }
.plate-link:focus-visible { outline:none; }
.plate-link:focus-visible::after { outline:2px solid var(--text); outline-offset:4px; border-radius:4px; }
@media (prefers-reduced-motion:reduce) { .plate-link, .plate-link svg { transition:none; } }
.sections-head { display:flex; align-items:center; gap:16px; margin:0 0 18px; }
.sections-head .rule { flex:1; height:.5px; background:var(--border); }
/* Seven questions and the ask box: eight tiles, four across on a wide screen, two on a
   laptop, one on a phone. Plate first, on a faint ground in the section's own accent, so
   the seven read apart at a glance; then the question, the title, the lede, the views. */
.sgrid { display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); gap:18px; }
.scard { display:flex; flex-direction:column; background:var(--surface); border:.5px solid var(--border);
  border-radius:var(--radius); padding:0 0 20px; transition:box-shadow .16s ease,transform .16s ease; position:relative; overflow:hidden; }
.scard:hover { box-shadow:0 6px 26px rgba(43,42,39,.09); transform:translateY(-2px); }
.thumb-wrap { display:block; line-height:0; padding:22px 26px 6px; background:color-mix(in oklch,var(--a) 6%,var(--surface)); }
.scard .thumb { width:100%; height:auto; aspect-ratio:3/2; display:block; }
.scard-htext { display:block; text-decoration:none; padding:14px 22px 0; position:relative; }
.scard .new { position:absolute; right:20px; top:14px; font-size:var(--fs-label); font-weight:600; letter-spacing:.04em; color:var(--a);
  border:1px solid color-mix(in oklch,var(--a) 45%,transparent); border-radius:999px; padding:2px 8px; }
.scard .sn { display:block; font-variant-numeric:tabular-nums; font-size:var(--fs-caption); font-weight:600; color:var(--a); letter-spacing:.1em; margin-bottom:6px; }
.scard .sq { font-size:var(--fs-ui); font-weight:600; color:var(--a); margin:0 0 5px; }
.scard h2 { font-family:var(--serif); font-weight:500; font-size:clamp(21px,1.5vw,25px); line-height:1.08; margin:0; text-wrap:balance; }
.scard-htext:hover h2 { text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:3px; }
.scard .sl { font-size:var(--fs-ui); color:var(--muted); margin:10px 0 12px; line-height:1.55; padding:0 22px; }
.chips-lbl { margin:0 0 8px; }
.scard .chips-lbl, .scard .chips { padding:0 22px; }
.chips { display:flex; flex-wrap:wrap; gap:6px; }
a.chip { font-size:var(--fs-caption); color:var(--muted); background:var(--surface-2); border:.5px solid var(--border-2); border-radius:999px;
  padding:5px 11px; white-space:nowrap; text-decoration:none; transition:background .14s,color .14s,border-color .14s; }
/* Grouped chips (ia.json chip_groups): a labelled row per group, at most four chips each. */
.chips-grouped { flex-direction:column; gap:8px; }
.chip-row { display:flex; flex-wrap:wrap; align-items:center; gap:6px; }
.chip-row-lbl { font-size:var(--fs-caption); color:var(--hint); margin-right:2px; }
a.chip:hover { color:var(--a); background:color-mix(in oklch,var(--a) 12%,var(--surface-2)); border-color:color-mix(in oklch,var(--a) 40%,transparent); }
/* The eighth tile. Blue, not a section accent: the front page belongs to no section, and
   blue is the colour the widget itself uses. The .secq frame inside would be a card in a
   card, so it gives up its border here; the widget takes the one-column layout the hubs
   use on a phone, because the tile is a column wide. */
.scard-ask { padding:20px 22px 18px; min-width:0; }
.scard-ask .secq { margin:0; padding:0; border:0; background:none; }
.scard-ask .secq .wx-assistant-block { grid-template-columns:1fr; grid-template-areas:"h" "controls" "list" "note"; }
.scard-ask .secq .wx-assistant-h { white-space:normal; font-size:var(--fs-emph); margin-bottom:10px; }
.home-note { margin-top:40px; padding:26px 28px; background:var(--surface-2); border-radius:var(--radius); }
.home-note h3 { font-family:var(--serif); font-weight:500; font-size:20px; margin:0 0 8px; text-wrap:balance; }
.home-note p { font-size:var(--fs-ui); color:var(--muted); margin:0; max-width:var(--measure-text); }
.home-note a { color:var(--text); font-weight:500; text-decoration:none; border-bottom:1px solid var(--border); }

/* ---------- SECTION HUB ---------- */
/* The hub header (#278): words left, the section's plate right, seated on the same
   baseline band as the lede. The accent lives in the number and the question; there is no
   bar — the words carry it. */
.sec-hero { position:relative; padding:6px 0 30px; margin-bottom:6px; display:grid;
  grid-template-columns:minmax(0,1fr) clamp(250px,32%,400px); gap:36px; align-items:center; }
.sec-hero-text { min-width:0; }
.sec-plate { width:100%; height:auto; aspect-ratio:3/2; display:block; justify-self:end; }
.sec-n { font-variant-numeric:tabular-nums; font-size:var(--fs-ui); font-weight:600; color:var(--a); letter-spacing:.08em; }
.sec-q { font-size:var(--fs-emph); font-weight:600; color:var(--a); margin:6px 0 6px; }
/* "Data updated <date>" beside the section number, filled by nav.js from the site manifest —
   the same stamp the view kicker carries, so a hub says how old its figures are at the top,
   not only in the footer. Empty (and invisible) until the manifest has loaded. */
.sec-fresh { margin-left:12px; font-size:var(--fs-caption); font-weight:400; color:var(--hint); letter-spacing:0; }
.sec-fresh:empty { display:none; }
.sec-hero h1 { font-family:var(--serif); font-weight:500; font-size:clamp(32px,3.6vw,50px); line-height:1.08; letter-spacing:-.015em; margin:0 0 14px; text-wrap:balance; }
.sec-lede { font-size:clamp(16px,1.4vw,19px); color:var(--muted); max-width:var(--measure-lede); margin:0; }
/* .vtag / .vone / .vstat are used by the long-scroll hub's per-view headings (see the
   "Long-scroll section hub" block at the foot of this file). */
.vtag { font-size:var(--fs-label); font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--muted);
  background:var(--surface-2); border-radius:999px; padding:4px 9px; white-space:nowrap; flex:none; }
.vtag.map { color:var(--s-amber); background:color-mix(in oklch,var(--s-amber) 12%,var(--surface-2)); }
/* Basis pills (#314): what kind of number the view's headline figure is. `measured` is the
   baseline and stays neutral; the other four take a colour so a departure reads as one. */
.vtag.basis-measured { color:var(--muted); background:var(--surface-2); border:.5px solid var(--border-2); }
.vtag.basis-estimate { color:var(--s-plum); background:color-mix(in oklch,var(--s-plum) 12%,var(--surface-2)); }
.vtag.basis-scenario { color:var(--s-red); background:color-mix(in oklch,var(--s-red) 12%,var(--surface-2)); }
.vtag.basis-self-reported { color:var(--s-amber); background:color-mix(in oklch,var(--s-amber) 12%,var(--surface-2)); }
.vtag.basis-target { color:var(--s-blue); background:color-mix(in oklch,var(--s-blue) 12%,var(--surface-2)); }
.vone { font-size:var(--fs-ui); color:var(--muted); margin:0 0 16px; line-height:1.5; max-width:var(--measure-text); }
.vstat { display:flex; flex-direction:column; gap:1px; margin-top:auto; padding-top:14px; border-top:.5px solid var(--border-2); }
.vstat .vs-val { font-family:var(--serif); font-size:24px; font-weight:500; color:var(--a); line-height:1; }
.vstat .vs-lbl { font-size:var(--fs-caption); color:var(--hint); }
.next-sec { display:flex; flex-direction:column; gap:3px; text-decoration:none; margin-top:34px; padding:22px 24px;
  border:.5px solid var(--border); border-radius:var(--radius); background:var(--surface); position:relative; overflow:hidden; }
.next-sec:hover { background:var(--surface-2); }
.ns-lbl { display:block; }
.ns-title { font-family:var(--serif); font-size:22px; font-weight:500; color:var(--text); text-wrap:balance; }
.ns-sub { font-size:var(--fs-ui); color:var(--a); font-weight:600; }

/* ---------- STANDARD PAGE ---------- */
.page-hero { max-width:960px; margin-bottom:30px; }
.page-hero .pk { margin:0 0 12px; }
.page-hero h1 { font-family:var(--serif); font-weight:500; font-size:clamp(32px,3.4vw,48px); line-height:1.1; letter-spacing:-.01em; margin:0; text-wrap:balance; }
/* Fluid reading column (issue #144): was a fixed 680px on every screen. The measure is
   in ch on a fluid font size, so lines lengthen with the viewport but stay readable. */
.page-body { max-width:var(--measure-text); font-size:clamp(16px, 0.25vw + 13px, 18px); }
.page-body h2, .page-body h3 { font-family:var(--serif); font-weight:500; font-size:21px; margin:30px 0 8px; text-wrap:balance; }
.page-body p { font-size:var(--fs-emph); color:var(--muted); line-height:1.65; margin:0 0 6px; }
.page-body p a, .page-body li a { color:var(--text); text-decoration:none; border-bottom:1px solid var(--border); }
.page-body p a:hover, .page-body li a:hover { border-color:var(--text); }
.page-body code { font-family:ui-monospace,Menlo,monospace; font-size:var(--fs-ui); background:var(--surface-2); padding:1px 6px; border-radius:4px; color:var(--text); }
.page-body ul { margin:10px 0 6px; padding:0; list-style:none; display:flex; flex-direction:column; gap:9px; }
.page-body li { position:relative; padding-left:20px; font-size:var(--fs-emph); color:var(--muted); line-height:1.55; }
.page-body li::before { content:""; position:absolute; left:3px; top:9px; width:6px; height:6px; border-radius:50%; background:var(--s-amber); }
.page-body li b { color:var(--text); font-weight:600; }

/* ---------- mobile editorial step-downs ---------- */
@media (max-width:900px) {
  .wx-page .main { padding:0 18px calc(96px + env(safe-area-inset-bottom)); }
  .wx-page .main-inner { padding-top:24px; }
  .home-hero h1 { font-size:33px; }
  .home-hero .lead { font-size:var(--fs-emph); }
  .hero-actions .btn { flex:1 1 auto; justify-content:center; }
  .sgrid { grid-template-columns:1fr; }
  .sec-hero h1 { font-size:30px; }
  .sec-hero { grid-template-columns:1fr; gap:18px; }
  .sec-plate { justify-self:start; max-width:320px; }
  /* On a phone the full strip would be 80px tall and its icons unreadable, so show its
     middle at a squarer ratio: the ground line stays at the bottom edge. */
  .home-plate { margin:0 0 18px; }
  .home-plate img { aspect-ratio:2.2/1; object-fit:cover; object-position:50% 100%; }
  .plate-sub { font-size:var(--fs-emph); }
  .scard h2 { font-size:24px; }
  .next-sec { margin-bottom:0; }
}
@media (max-width:380px) {
  .home-hero h1 { font-size:29px; }
}

/* ---- Long-scroll section hub -------------------------------------------------
   The hub reads as one page: every view of a section, in order, each composed as a
   same-origin iframe (nav.js drops its chrome when embedded). The heading, one-liner
   and headline stat of each view are server-rendered above its frame, so the page
   still says something with JavaScript off — and to a crawler, which never sees
   inside an iframe. See pipeline/build_html.py. */
.vnav { position:sticky; top:var(--wx-topbar-h, 0px); z-index:20; display:flex; gap:6px; flex-wrap:wrap;
  padding:10px 0; margin-bottom:4px; background:var(--bg); border-bottom:.5px solid var(--border); }
.vnav a { font-size:var(--fs-ui); text-decoration:none; color:var(--muted);
  padding:5px 11px; border-radius:999px; border:1px solid transparent; white-space:nowrap; }
.vnav a:hover { color:var(--text); }
.vnav a.active { background:var(--surface-2); color:var(--text); font-weight:600; }

/* One block, three groups, in reading order (#260): what the view is — heading,
   one-liner, what else is inside — set tight as one thought; the question it answers,
   with air on both sides, because it is the reason to stay and not more description;
   then the figure sitting directly on the chart it summarises. The block used to
   space all six lines 3–6px apart, so nothing led. The intervals now do the grouping,
   and the blocks stand further from each other than anything inside them. */
.vblock { margin:0 0 48px; scroll-margin-top:62px; }
/* After the rule it overrides, not in the phone block higher up: same specificity,
   so source order decides, and there the 48px won on a phone. */
@media (max-width:900px) { .vblock { margin-bottom:40px; } }
/* Four type styles on the whole hub below the hero, and no more: the block heading
   (19/600), body (UI-small, 13.5/400 — description, question, ask box, chips near
   enough), small (caption, 12 — labels and notices) and figures (17/500 in the strip,
   21 serif for the hub's own). Everything that used to be its own size — 13 catchphrase,
   15.5 question, 11.5 labels — now sits on one of those four (#260); #404 moved the
   body step from 14 to the site-wide 13.5, because 14 is the card title's alone. */
.vhead { margin:20px 0 12px; }
.vhead h2 { font-size:19px; font-weight:600; margin:0; text-wrap:balance; }
.vhead h2 a { color:inherit; text-decoration:none; }
.vhead h2 a:hover { text-decoration:underline; text-underline-offset:3px; }
.vhead h2 .vtag { margin-left:6px; vertical-align:2px; }
.vhead .vone { color:var(--muted); font-size:var(--fs-ui); line-height:1.5; margin:5px 0 0;
  max-width:var(--measure-lede); }
/* The figure, directly above the chart. A step larger than it was: it is the block's
   one number and the only accented figure on the page, so it can carry that. */
.vhead .vstat { flex-direction:row; align-items:baseline; gap:10px; margin-top:14px;
  padding-top:0; border-top:0; }
.vhead .vstat .vs-val { font-size:21px; }
.vhead .vstat .vs-lbl { font-size:var(--fs-caption); }
.vhead .vstat .vs-val { font-size:21px; }
/* Once the frame has arrived carrying the view's own KPI strip (hub.js marks the block),
   the same number would be on screen twice a few lines apart. The hub's copy retires;
   it stays in the markup for a crawler and for a reader with JavaScript off. */
.vblock.has-kpis .vhead .vstat { display:none; }
/* The caveat under the figure — Spread's "upper bound only", the modelled views. Part
   of the answer, so it stays; small and quiet, not an italic second one-liner. */
.vcaveat { margin:8px 0 0; font-size:var(--fs-caption); line-height:1.45; color:var(--muted);
  max-width:var(--measure-text); }
.vcaveat .vmethod{display:block;margin-top:2px;color:var(--hint)}
.mlist{list-style:none;padding:0;margin:0 0 20px}
.mlist li{padding:6px 0;border-bottom:0.5px solid var(--border-2)}
.mlist li a{font-weight:600;margin-right:6px}

/* No border of its own: the frame is a transparent window. The lead card inside it used
   to draw the border; since #343 the lead stands on the paper on the view page too, so a
   hub block reads heading → figure → chart with nothing boxed, the same as the view. */
.vframe { width:100%; border:0; background:transparent; display:block; }
/* The 300px floor only holds while a frame has no src yet (hub.js sets src only once it
   loads a frame) — it reserves space before content arrives, and shows a surface where
   the chart will land. Once loaded, some lead cards render genuinely shorter than 300px
   (issue #220 finding 2); the floor must not pad a short card with blank surface, so
   neither it nor the placeholder surface applies past load. */
.vframe:not([src]) { min-height:300px; background:var(--surface-2); border-radius:var(--radius); }
/* The link under each frame to the full view. A real element, not a <noscript> fallback,
   so it is there with JavaScript on too. 44px tall on a phone: it is the block's tap target. */
/* The assistant at the top of a hub (#223). It closes the header rather than opening the
   list of views: a reader who knows what they want scrolls past it to the chips, and one
   who does not has somewhere to ask. assistant.js replaces #wx-assistant when it boots,
   so the static question list below is the no-JavaScript fallback, not a second copy. */
/* Compact (#260, #308): the heading on the left, the input on the right, the offered
   question underneath and the small print last — three rows, not five. The same
   hairline card as the charts below it, so the hub has one kind of box. */
.secq { margin:16px 0 4px; padding:12px 16px; border:.5px solid var(--border);
  border-radius:var(--radius); background:var(--surface); }
.secq-h { font-size:var(--fs-ui); font-weight:600; margin:0 0 2px; }
.secq-lede { font-size:var(--fs-ui); color:var(--muted); margin:0 0 10px; max-width:var(--measure-text); }
.secq-list { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:2px; }
.secq-q { display:flex; align-items:center; min-height:44px; font-size:var(--fs-emph); color:var(--text);
  border-top:.5px solid var(--border-2); text-wrap:balance; }
.secq-list .secq-q:first-child { border-top:none; }
/* Once assistant.js has mounted it owns the block's interior, and its own rows replace
   these. Hiding the fallback here rather than removing it in JS keeps the markup crawlable. */
.secq:has(.wx-assistant-block) .secq-h,
.secq:has(.wx-assistant-block) .secq-lede,
.secq:has(.wx-assistant-block) .secq-list { display:none; }
/* The swap without the jump (#377). On a hub the static block (heading + three questions,
   186px) was replaced by the widget at 95px, which then grew to 128px when its question
   arrived: the first view section moved twice, ~0.07 CLS on /rhythm and /grid. With
   JavaScript on (html.wx-js, set just before this block by build_html.py) the static list
   is hidden and the block holds the widget's final height from the first paint; the
   widget's empty list holds its one row. Hubs only: the home page's block sits in a card
   below the fold and settles taller. If the widget never mounts, the list comes back after
   8s rather than leave an empty box. */
html.wx-js body[data-wx="section"] .secq:not(:has(.wx-assistant-block)) { min-height:128px; }
html.wx-js body[data-wx="section"] .secq:not(:has(.wx-assistant-block)) .secq-list {
  display:none; animation:wx-secq-fallback 0s 8s forwards; }
@keyframes wx-secq-fallback { to { display:flex; } }
body[data-wx="section"] .secq .wx-assistant-list:empty { min-height:33px; }
@media (max-width:760px) {
  /* The widget stacks its heading over the input here: 162px. */
  html.wx-js body[data-wx="section"] .secq:not(:has(.wx-assistant-block)) { min-height:162px; }
}
/* One box, not two. assistant.js draws its own card — surface, hairline border,
   radius, padding — because on a view page it stands alone among the cards. Inside
   this block it was a card inside a card. .secq keeps the frame and the section
   accent; the widget gives its up. */
.secq .wx-assistant-block { background:none; border:0; border-radius:0;
  padding:0; margin:0; display:grid; grid-template-columns:auto minmax(0,1fr);
  grid-template-areas:"h controls" "list list" "note note";
  column-gap:22px; align-items:center; }
.secq .wx-assistant-h { grid-area:h; font-size:var(--fs-ui); font-weight:500; margin:0; white-space:nowrap; }
.secq .wx-assistant-note { grid-area:note; font-size:var(--fs-caption); margin:6px 0 0; }
.secq .wx-assistant-controls { grid-area:controls; }
.secq .wx-assistant-list { grid-area:list; margin-top:4px; }
@media (max-width:760px) {
  .secq .wx-assistant-block { grid-template-columns:1fr;
    grid-template-areas:"h" "controls" "list" "note"; }
  .secq .wx-assistant-h { white-space:normal; margin-bottom:8px; }
}
/* No rules between the rows. On a view page they separate a list of three; here
   there is one question and an input, and a divider between two things is a line
   drawn for its own sake. */
.secq .wx-assistant-list,
.secq .wx-assistant-item { border:0; }
.secq .wx-assistant-q { padding-top:6px; padding-bottom:6px; font-size:var(--fs-ui); }

/* The question under the description (#220, #260): the reason to stay, and the way in.
   A link to the view's own question list, where the assistant answers it from that
   page's data — not a <details> with a precomputed answer, an AI tag and a second link
   folded into every block. One link style for the whole block: this and the one at
   the foot. 44px tall so it is a real tap target on a phone. */
.vq { display:inline-flex; align-items:baseline; gap:6px; min-height:44px; margin:2px 0 0;
  font-size:var(--fs-ui); font-weight:500; color:var(--a); text-decoration:none; text-wrap:balance; }
.vq:hover { text-decoration:underline; text-underline-offset:3px; }
.vq-arrow { flex:none; transition:transform .15s ease-out; }
.vq:hover .vq-arrow { transform:translateX(2px); }

/* What else the view holds: the second sentence of the description, not a line of its
   own. A reader decides whether a block is worth their attention at the top of it, so
   it stays above the question; it used to carry the section accent, and was the second
   blue line in a header with a blue figure, a blue marker and two blue links (#260). */
.vmore { color:inherit; }

/* The link at the foot of a block, always there, after the chart: the block's tap
   target once the reader has seen the evidence. Same style as the question above. */
.vend { display:inline-flex; align-items:center; min-height:44px; margin:6px 0 0;
  font-size:var(--fs-ui); font-weight:500; color:var(--a); text-decoration:none; }
.vend:hover { text-decoration:underline; text-underline-offset:3px; }

/* Contact form (#498): flat at rest, hairline borders, tokens only (DESIGN.md).
   The sign-up form (#503) shares every rule — same fields, same flatness — so it rides
   the same selectors rather than duplicating them. */
.wx-contact, .wx-subscribe { display:grid; gap:14px; margin:18px 0 26px; max-width:var(--measure-text); }
.wx-contact label, .wx-subscribe label { display:grid; gap:6px; font-size:var(--fs-ui); color:var(--text); }
/* Form fields need a visible edge (WCAG 1.4.11) — the one deliberate exception to the
   hairline rule; --border alone falls below 3:1 contrast against --surface. */
.wx-contact input, .wx-contact textarea, .wx-subscribe input:not([type=checkbox]), .wx-subscribe textarea { font:inherit; font-size:var(--fs-emph); color:var(--text);
  background:var(--surface); border:1px solid var(--hint); border-radius:var(--radius-sm); padding:10px 12px; }
.wx-contact input:focus-visible, .wx-contact textarea:focus-visible,
.wx-subscribe input:focus-visible, .wx-subscribe textarea:focus-visible { outline:2px solid var(--text); outline-offset:1px; }
.wx-contact textarea { resize:vertical; min-height:140px; }
.wx-contact .btn, .wx-subscribe .btn { justify-self:start; min-height:44px; border:0; cursor:pointer; font:inherit; }
.wx-contact .btn[disabled], .wx-subscribe .btn[disabled] { opacity:.6; cursor:default; }
.wx-contact .hint, .wx-subscribe .hint { color:var(--hint); font-size:var(--fs-caption); }
.wx-contact #contactStatus { color:var(--muted); font-size:var(--fs-ui); }
/* The sign-up's status sentence ("Check your inbox…") is the one thing the visitor must act
   on, so it reads at body size in the text colour; the muted 13.5px line went unseen. */
.wx-subscribe #subscribeStatus { color:var(--text); font-size:var(--fs-emph); }
/* Brevo's redirect lands on /subscribe?confirmed=1: the confirmation sits above the form in a
   flat hairline box, the first thing on the page after the introduction. */
/* .page-body .wx-notice: the page's own paragraph rule sets p to --muted and would win. */
.page-body .wx-notice { margin:18px 0 0; padding:12px 16px; max-width:var(--measure-text); color:var(--text);
  font-size:var(--fs-emph); font-weight:500; background:var(--surface); border:0.5px solid var(--border); border-radius:var(--radius-sm); }
.page-body .wx-notice[hidden] { display:none; }
.wx-hp { position:absolute; left:-10000px; width:1px; height:1px; overflow:hidden; }

/* The sign-up form's extra controls: checkbox rows (#503), one per section, so the box
   offers eight choices and never a flat list of every view on the site; and a quiet
   text button above them that ticks every section. */
.wx-subscribe label.check { display:flex; gap:8px; align-items:baseline; }
.wx-subscribe fieldset { border:0; padding:0; margin:0; display:grid; gap:6px; }
.wx-subscribe legend { font-size:var(--fs-ui); color:var(--text); margin-bottom:6px; }
.wx-subscribe fieldset label.check { padding-left:4px; }
/* Two columns, at every width: eight rows stacked pushed Subscribe below the fold on a
   phone (375 x 740); in two columns the button sits on the first screen. */
.wx-subscribe .sections { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:8px 16px; }
/* Below 900px nav.js pins its tab bar to the bottom of the screen (58px plus the home
   indicator), and at 375 x 740 Subscribe sat behind it. The button bar sticks just above
   that tab bar while the form is in view, on the page background with a hairline over it;
   same breakpoint and height as nav.js, the numbers assistant.js reserves for the same bar. */
@media (max-width: 900px) {
  .wx-subscribe .actions { position:sticky; bottom:calc(58px + env(safe-area-inset-bottom)); z-index:1;
    display:grid; padding:10px 0; background:var(--bg); border-top:0.5px solid var(--border-2); }
  /* A field reached by Tab lands above both bars, not behind them. */
  .wx-subscribe input { scroll-margin-bottom:calc(58px + 70px + env(safe-area-inset-bottom)); }
}
/* Styled as the page's own links (.page-body p a): a standard page sets no --a accent. */
.wx-subscribe #subscribeAll { justify-self:start; min-height:44px; margin-top:-6px; padding:0; border:0; background:none; cursor:pointer;
  font:inherit; font-size:var(--fs-ui); color:var(--text);
  text-decoration:underline; text-decoration-color:var(--border); text-decoration-thickness:1px; text-underline-offset:4px; }
.wx-subscribe #subscribeAll:hover { text-decoration-color:var(--text); }
.wx-subscribe #subscribeAll:focus-visible { outline:2px solid var(--text); outline-offset:2px; }
