/* ============================================================================
   site-sheet.css — the ONE intake sheet, and the helpers its markup uses.

   WHY THIS FILE EXISTS. site.js carries the single lead-intake door the whole
   public site posts through (`POST /v1/leads/demo`). Its styling used to sit in
   the middle of site.css, which only the four HAND-AUTHORED pages load — so a
   page rendered from the design drop (render-site-pages.py emits its own canon
   head, with no site.css link) could not host that sheet without either pulling
   in the whole of site.css or growing a second copy of these rules.

   Both alternatives are worse than a file. Loading site.css on a generated page
   collides on `*`, `:root`, `html`, `body`, `a` and `.eyebrow` — measured, and
   `a { color: inherit }` alone would strip the link colour off every link on the
   page. A second copy is the drift this platform refuses everywhere else: one
   consent sentence, one rate limit, one erasure path — ONE set of styles for the
   form that collects the data.

   So the rules were MOVED here byte-for-byte, not rewritten. The four
   hand-authored pages link this file beside site.css; the generated trial page
   gets the same bytes inlined by the renderer, which READS THIS FILE rather than
   carrying a transcription of it.

   CASCADE, and why the move was safe: this block shares NO selector with the
   rest of site.css — checked in both directions before the cut, which is what
   makes the link order on those four pages a non-question. Keep it that way. A
   selector that appears both here and there would make load order load-bearing,
   and nothing tests load order.
   ============================================================================ */

/* ---- helpers the sheet's own markup uses ----------------------------------
   .serif and .mono are the sheet body's type switches and .mark is the lockup in
   .sheet__hd. They are general helpers the hand-authored pages use elsewhere
   too, which is exactly why they travel WITH the sheet instead of being copied
   for it: those pages load this file, so nothing they had is lost. */
.serif { font-family: var(--font-display); font-weight: 600; letter-spacing: -.02em; }
.mono { font-family: var(--font-mono); }

.mark { color: var(--accent); display: grid; place-items: center; flex: none; }
/* The mark is now an <img> of the committed tier (site.js MARK), not an inline SVG, so it
   must be told to fill its box: an SVG file with only a viewBox has no intrinsic size, and
   an unsized <img> would fall back to the 300x150 default rather than the 30-56px the
   placement asks for. Every .mark box is square, so the aspect ratio is preserved. */
.mark .mark__img { width: 100%; height: 100%; display: block; }

/* ---- checkout modal ------------------------------------------------------ */
/* ---- provisioning / renewal sheet — a NATIVE <dialog> (2026-08-23) ---------------
   This was a `<div hidden>` with a hand-rolled click-outside handler and a global
   `keydown` Escape listener at the bottom of site.js. Everything that makes a modal a
   MODAL had to be written by hand, and four of those were never written: focus was not
   trapped, the page behind stayed reachable by Tab and by screen reader, focus was not
   restored to the trigger on close, and the sheet sat at z-index 100 in the ordinary
   stacking context — one `position: fixed` descendant with a larger z-index away from
   being painted over. `showModal()` supplies all four from the platform, and the
   Escape listener is DELETED rather than reimplemented.

   'The UA reset is load-bearing.' A dialog is hidden by the UA rule
   `dialog:not([open]) { display: none }` — but an AUTHOR `display: flex` beats any UA
   rule regardless of specificity, so keeping the old `.modal { display: flex }` on its
   own would leave the closed dialog painted across the viewport forever. The
   `:not([open])` line below is what makes it close at all. The rest of the reset undoes
   the UA's centred, size-capped, bordered box so the element can go on being the
   full-bleed flex scroller `.sheet` already expects to sit in. */
.modal { position: fixed; inset: 0; z-index: 100; display: flex; align-items: flex-start; justify-content: center; padding: 6vh 20px; overflow-y: auto;
         width: 100%; max-width: 100%; height: 100%; max-height: 100%; border: 0; background: transparent; color: inherit; }
.modal:not([open]) { display: none; }
/* The dim moves to ::backdrop, which the top layer paints beneath the dialog — so it
   now covers the sticky nav (z-index 50) that the old in-flow overlay merely out-
   stacked. The token carries a literal fallback because ::backdrop only began
   inheriting custom properties from its originating element in recent engines; without
   it the dim resolves to nothing on an older one and the sheet floats over a page that
   still looks live. */
.modal::backdrop { background: color-mix(in srgb, var(--hearth-text, #221C14) 32%, transparent); backdrop-filter: blur(5px); }
.sheet { width: min(540px, 96vw); background: var(--hearth-raised); border: 1px solid var(--hearth-border); border-radius: var(--radius-2xl); box-shadow: var(--shadow-xl); overflow: hidden; animation: pop .2s var(--ease-standard); }
@keyframes pop { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: none; } }
.sheet__hd { display: flex; align-items: center; gap: 12px; padding: 20px 24px; border-bottom: 1px solid var(--hearth-border-subtle); }
.sheet__hd .e { font-family: var(--font-display); font-size: var(--text-md); font-weight: 600; }
.sheet__hd .x { margin-left: auto; width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--hearth-border-strong); background: var(--hearth-surface); cursor: pointer; display: grid; place-items: center; color: var(--hearth-text-secondary); }
.sheet__bd { padding: 24px; }
.steps { display: flex; gap: 8px; margin-bottom: 20px; }
.steps .s { flex: 1; height: 4px; border-radius: 2px; background: var(--hearth-sunken); }
.steps .s.on { background: var(--accent); }
.field { margin-bottom: 14px; }
.field label { display: block; font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--hearth-text-muted); margin-bottom: 6px; }
.field input, .field select { width: 100%; border: 1px solid var(--hearth-border-strong); border-radius: var(--radius-md); padding: 11px 13px; font: inherit; font-size: var(--text-sm); background: var(--hearth-surface); color: var(--hearth-text); outline: none; }
.field input:focus, .field select:focus { border-color: var(--accent-border); box-shadow: var(--focus-ring); }
.field--row { display: flex; gap: 12px; } .field--row .field { flex: 1; }

/* 12-7 · lead form — mobile number, validation, consent.
   The dial code is a fixed-width leader so the number itself stays the wide field: the
   country is picked once, the digits are what the visitor actually types. It wraps to its
   own row under 380px rather than squeezing a 10-digit number into a third of the sheet. */
.tel { display: flex; gap: 8px; }
.tel select { flex: 0 0 42%; max-width: 190px; }
.tel input { flex: 1 1 auto; min-width: 0; }
@media (max-width: 380px) { .tel { flex-wrap: wrap; } .tel select { flex: 1 1 100%; max-width: none; } }
.fld-hint { font-size: var(--text-xs); color: var(--hearth-text-muted); margin-top: 6px; }
/* Never colour-alone (WCAG 2.2 / the Hearth rule): the invalid state carries a glyph and a
   sentence saying what to do, and the red border is only the third signal. */
.fld-err { display: flex; align-items: center; gap: 6px; font-size: var(--text-xs); font-weight: 600; color: var(--status-down-fg); margin-top: 6px; }
.fld-err svg { flex: 0 0 auto; }
.field.is-bad input, .field.is-bad select { border-color: var(--status-down-fg); }
.consent { display: flex; align-items: flex-start; gap: 10px; font-size: var(--text-xs); line-height: 1.5; color: var(--hearth-text-secondary); background: var(--hearth-sunken); border: 1px solid transparent; border-radius: var(--radius-md); padding: 12px 14px; cursor: pointer; }
.consent input { flex: 0 0 auto; width: 16px; height: 16px; margin-top: 1px; accent-color: var(--accent); cursor: pointer; }
.consent.is-bad { border-color: var(--status-down-fg); }
/* §12-7 mobile rule 4 — the WHOLE row is the target, not the 16px box. The <label for> was
   already doing that; this pins the row to the 44px minimum so a future padding change
   cannot quietly drop the one control on this sheet that must be a deliberate act. */
.consent { min-height: 44px; align-items: center; }
/* Rule 5's keyboards are attributes on the inputs (inputmode/autocomplete in site.js);
   rule 2's bottom-sheet anchoring is the modal's, not this block's. */
@media (max-width: 380px) { .field input, .field select, .tel select, .tel input { min-height: 44px; } }
.summary { background: var(--hearth-sunken); border-radius: var(--radius-md); padding: 14px 16px; margin-bottom: 18px; }
.summary .ln { display: flex; justify-content: space-between; font-size: var(--text-sm); padding: 5px 0; color: var(--hearth-text-secondary); }
.summary .ln.tot { border-top: 1px solid var(--hearth-border); margin-top: 6px; padding-top: 10px; font-size: var(--text-base); font-weight: 700; color: var(--hearth-text); }
.summary .ln .mono { font-family: var(--font-mono); }
.pg-pick { display: flex; gap: 10px; margin-bottom: 16px; }
.pg-pick button { flex: 1; border: 1.5px solid var(--hearth-border-strong); background: var(--hearth-surface); border-radius: var(--radius-md); padding: 12px; font: inherit; font-size: var(--text-sm); font-weight: 600; cursor: pointer; color: var(--hearth-text-secondary); }
.pg-pick button.on { border-color: var(--accent); color: var(--accent-text); background: var(--accent-subtle-bg); }

/* invoice (generated) */
.inv { border: 1px solid var(--hearth-border); border-radius: var(--radius-lg); overflow: hidden; }
.inv__hd { padding: 18px 20px; background: var(--hearth-surface); border-bottom: 1px solid var(--hearth-border-subtle); display: flex; align-items: flex-start; gap: 12px; }
.inv__hd .mark { width: 34px; height: 34px; } .inv__hd .mark svg { width: 34px; height: 34px; }
.inv__hd .meta { margin-left: auto; text-align: right; font-size: var(--text-xs); color: var(--hearth-text-muted); }
.inv__bd { padding: 18px 20px; }
.inv__row { display: flex; justify-content: space-between; font-size: var(--text-sm); padding: 7px 0; }
.inv__row .mono { font-family: var(--font-mono); }
.inv__tot { border-top: 1px solid var(--hearth-border); margin-top: 8px; padding-top: 12px; display: flex; justify-content: space-between; align-items: baseline; }
.inv__tot b { font-family: var(--font-display); font-size: var(--text-xl); font-weight: 600; color: var(--accent-text); }
.paid { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-xs); font-weight: 700; color: var(--status-healthy-fg); background: var(--status-healthy-bg); padding: 4px 11px; border-radius: var(--radius-full); }
.center { text-align: center; }
.center .ok { width: 72px; height: 72px; border-radius: 50%; background: var(--status-healthy-bg); color: var(--status-healthy-fg); display: grid; place-items: center; margin: 4px auto 0; }
.center .ok svg { width: 38px; height: 38px; }
