/* ── pages.css ──────────────────────────────────────────────────────────────
   The simple pages: FAQ, Contact, Login, Subscribe, Bundles. All of them open
   with the same header band used elsewhere (.section-head from sheet.css) and
   a short intro line, then a single content block. No new layout language —
   this file only adds what those five pages need beyond sheet.css,
   product.css's form and section patterns, and forms.css.
   ───────────────────────────────────────────────────────────────────────── */

.page-intro {
  padding: var(--s6) var(--gutter) var(--s7);
  border-bottom: 1px solid var(--rule);
  max-width: 62ch;
}
/* The section-index mark (sheet.css), used everywhere else as a chapter
   band, doesn't fit these pages as a full inverted band — there's no second
   section to divide it from. A plain kicker line carries the same mark. */
.page-kicker {
  display: block;
  margin-bottom: var(--s3);
}
.page-intro-title {
  font-family: var(--font-display);
  font-size: clamp(3.6rem, 7vw, 6rem);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-tight);
}
.page-intro-sub {
  margin-top: var(--s4);
  color: var(--fg-muted);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
}
/* Desktop gets --gutter's own escalation (already 3.2rem here) rather than
   a flat --s5 cap, plus one step of extra vertical air — this was capping
   below what the token already provides and never grew vertical rhythm. */
@media (min-width: 48em) { .page-intro { padding: var(--s7) var(--gutter) var(--s8); } }

/* A narrow, centred content well for forms — Contact, Login. */
.page-well { padding: var(--s7) var(--gutter); }
.page-well-inner { max-width: 52rem; display: grid; gap: var(--s5); }
@media (min-width: 48em) { .page-well { padding: var(--s8) var(--gutter); } }

/* Contact, Login, All-Access (Subscribe), Success: the only pages that are a
   single centred column start to finish, not a full-bleed list (FAQ,
   Bundles) — so the intro and the well both centre only here. */
#contact .page-intro, #login .page-intro, #subscribe .page-intro, #success .page-intro,
#contact .page-well-inner, #login .page-well-inner, #subscribe .page-well-inner {
  margin-inline: auto;
}
#contact .page-intro, #login .page-intro, #subscribe .page-intro, #success .page-intro { text-align: center; }
/* success.js's "Back home" link sits outside .page-intro (it's not a form
   well) — centre the whole container so that inline link centres too, or
   the confirmation box centres while it stays pinned left underneath. */
#success { text-align: center; }
/* Success is a single confirmation line, not a section with content below
   it to divide from — drop the rule .page-intro carries everywhere else. */
#success .page-intro { border-bottom: none; }

/* A banner that carries an inline error/notice, e.g. Login's expired-link
   message. Same device as the section header's inverted band, at rest. */
.page-notice {
  padding: var(--s4) var(--s5);
  border: 1px solid var(--rule);
  color: var(--fg-muted);
  font-size: var(--fs-small);
}

/* ══ FAQ ══════════════════════════════════════════════════════════════════ */
.faq-body { padding-block: var(--s5); }
@media (min-width: 48em) { .faq-body { padding-block: var(--s6); } }

/* ══ Contact ══════════════════════════════════════════════════════════════ */
.contact-fallback { color: var(--fg-faint); font-size: var(--fs-small); }
.contact-fallback a { color: inherit; text-decoration: underline; }

/* ══ Login ════════════════════════════════════════════════════════════════ */
.login-hint a { color: var(--accent); text-decoration: underline; }

/* ══ Bundles: the picker ═════════════════════════════════════════════════
   Replaces four hardcoded bundle cards with one live selector. Every 2/3/4
   -item combination has a real backend bundle product and Stripe price
   (js/bundles.js's BUNDLE_IDS/BUNDLE_PRICES) — checkout is real, not a
   placeholder.
   ═════════════════════════════════════════════════════════════════════ */
.bundle-picker { display: grid; }
.bundle-row {
  display: flex; align-items: center; gap: var(--s4);
  padding: var(--s5) var(--gutter);
  border-top: 1px solid var(--rule);
  cursor: pointer;
}
.bundle-row:last-child { border-bottom: 1px solid var(--rule); }
.bundle-check {
  flex: none; width: 2rem; height: 2rem;
  border: 1px solid var(--rule);
  display: flex; align-items: center; justify-content: center;
}
/* A real child rather than ::after: attribute-triggered transitions on
   generated content did not reliably repaint in testing, so this uses an
   element that unambiguously re-renders when its class changes. */
.bundle-check-fill {
  width: 1rem; height: 1rem; background: var(--accent);
  transform: scale(0); transition: transform var(--dur-throw) var(--ease-throw);
}
.bundle-row[aria-checked="true"] .bundle-check-fill { transform: scale(1); }
.bundle-shot { flex: none; width: 6.4rem; height: 6.4rem; object-fit: contain; }
.bundle-info { display: grid; gap: var(--s1); flex: 1; }
.bundle-name { font-family: var(--font-display); letter-spacing: var(--track-display); font-size: var(--fs-h3); }
.bundle-tag { color: var(--fg-muted); }
.bundle-price { font-family: var(--font-data); font-size: var(--fs-text); }
.bundle-price-was { color: var(--fg-faint); text-decoration: line-through; margin-right: var(--s2); }

.bundle-summary {
  display: grid; gap: var(--s3);
  padding: var(--s6) var(--gutter);
  border-top: 1px solid var(--rule);
  background: var(--surface); color: var(--fg);
}
.bundle-summary-row { display: flex; justify-content: space-between; font-size: var(--fs-text); }
.bundle-summary-row.is-total {
  font-family: var(--font-display); letter-spacing: var(--track-display); font-size: var(--fs-h3);
  padding-top: var(--s3); border-top: 1px solid var(--rule-strong);
}
.bundle-savings { font-weight: 600; }
.bundle-summary .form-submit { margin-top: var(--s3); }
#bundle-buy-row .p-buy-row { margin-top: var(--s3); }

/* No 48em override here: these already use --gutter directly, so its own
   1.6rem→3.2rem step applies for free — no need to re-cap it smaller. */

/* Subscribe's "What's included" grid: 4 items, so 2 columns divides evenly
   and never leaves a partial final row exposing the grid's rule colour. */
@media (min-width: 48em) {
  .p-more-row--2up { grid-template-columns: repeat(2, 1fr) !important; }
}

/* Compare plans: the generic section-head band (sheet.css) is a 66/34 split
   that has nothing to do with this row's two 50/50 cards, and crossing the
   two patterns read as a checkerboard — the band's dark third landed over
   the light All-Access card, and its light two-thirds landed over the dark
   Individual card. Instead this band is split exactly where the cards
   split below it, dark into light left-to-right, so the colour runs straight
   through from header into table instead of criss-crossing it — and the
   light half, sitting over All-Access both here and in the row beneath,
   is what does the highlighting. */
.p-compare .section-head {
  background: linear-gradient(90deg, var(--ground) 0 50%, var(--fg) 50% 100%);
  color: var(--fg);
}
.p-compare .section-meta { color: var(--ground); }
@media (max-width: 47.99em) {
  /* Below the cards' own 2-column breakpoint, Individual stacks above
     All-Access rather than sitting beside it — an even vertical split no
     longer echoes anything, so the header falls back to a plain dark row. */
  .p-compare .section-head { background: var(--ground); color: var(--fg); }
  .p-compare .section-meta { color: var(--fg-muted); }
}

/* ══ 404 ══════════════════════════════════════════════════════════════════
   Four small, unrelated treatments of the same idea rather than one
   committed design — [data-404] on <html> (labbar.js) picks which shows.
   ═════════════════════════════════════════════════════════════════════ */
.nf-variant { display: none; padding: var(--s7) var(--gutter); }
[data-404="flatline"]   [data-nf="flatline"],
[data-404="no-input"]   [data-nf="no-input"],
[data-404="ledger"]     [data-nf="ledger"],
[data-404="patch-miss"] [data-nf="patch-miss"] {
  display: grid; gap: var(--s5); justify-items: start;
}
@media (min-width: 48em) { .nf-variant { padding: var(--s8) var(--gutter); } }

.nf-line { font-size: var(--fs-lead); color: var(--fg-muted); }

/* ── flatline ──────────────────────────────────────────────────────────── */
.nf-wave { width: 100%; max-width: 40rem; height: 4rem; }
.nf-wave path { fill: none; stroke: var(--fg-faint); stroke-width: 1.5; }

/* ── no-input — the terminal decode from the buy button and the form
   readouts (product.css, forms.css), reused rather than reinvented. Plays
   once on load; nothing to re-trigger, so no JS needed here. ──────────── */
.nf-terminal {
  font-family: var(--font-data); font-size: var(--fs-h3);
  letter-spacing: var(--track-data); text-transform: uppercase;
}
.nf-terminal-text { display: inline-block; overflow: hidden; white-space: nowrap; vertical-align: bottom; }
.nf-cursor {
  display: inline-block; width: 0.5em; height: 0.9em; margin-left: 2px;
  background: currentColor; vertical-align: text-bottom;
}
@media (prefers-reduced-motion: no-preference) {
  .nf-terminal-text { animation: buy-decode var(--dur-detect) steps(19, end) forwards; }
  .nf-cursor { animation: buy-cursor-blink 0.8s step-end infinite; animation-delay: var(--dur-detect); }
}

/* ── patch-miss — a signal chain with the connector missing, echoing the
   rack motif rather than an illustrated break. ──────────────────────────── */
.nf-chain { display: flex; align-items: center; width: 100%; max-width: 24rem; height: 1px; }
.nf-chain-seg { flex: 1; height: 1px; background: var(--rule); }
.nf-chain-gap { flex: none; width: var(--s6); border-top: 1px dashed var(--rule-strong); }

/* Entrance motion for the FAQ list is the stroke-draw primitive now
   (base.css, js/motion.js) — each item's own top rule draws itself in, then
   the question text settles. Scoped to #faq via [data-stroke-draw] set only
   in js/faq.js's standalone-page render, same reasoning as before: the same
   rows embedded low on a product page would just finish playing invisibly
   before anyone scrolled to them, so they keep a plain static border there. */

/* ══ Terms / Privacy ══════════════════════════════════════════════════════
   Real copy, ported verbatim from the live site — the only thing new here
   is the shell. Numbered sections read like the FAQ's index, not prose
   with headings, since that's already this site's device for "a list of
   discrete points" (faq.js, pages.css's #faq block above).
   ═════════════════════════════════════════════════════════════════════ */
.legal-body { max-width: 68ch; padding: var(--s6) var(--gutter) var(--s8); }
.legal-item { padding-block: var(--s5); border-top: 1px solid var(--rule); }
.legal-item:last-child { padding-bottom: 0; }
.legal-item-title {
  font-family: var(--font-display);
  letter-spacing: var(--track-display);
  font-size: var(--fs-h3);
  margin-bottom: var(--s3);
}
.legal-item-text { color: var(--fg-muted); line-height: var(--lh-snug); }
.legal-item-text + .legal-item-text { margin-top: var(--s3); }
.legal-item-list { color: var(--fg-muted); line-height: var(--lh-snug); padding-left: 1.4em; }
.legal-item-list li + li { margin-top: var(--s2); }
.legal-link { color: var(--accent); text-decoration: underline; }
@media (min-width: 48em) { .legal-body { padding: var(--s7) var(--gutter) var(--s9); } }
