/* app.css. Owner: S6. The funnel pages' look (merge plan 3.3, "Flow pages"):
   the three start forms, the order page, hosting and hosting's own start
   form.

   CSS only. The markup of these five pages is locked (flow.mjs, order.mjs,
   hosting.mjs) and every id, class and data attribute their scripts look up
   keeps working exactly as it does today. Nothing here adds, removes or
   renames an element.

   Converted 2026-09-25 (S6) from the scaffold O2 left in place: the funnel
   block website-draft/public/site.css carried at lines 36 to 145, kept
   verbatim so these pages stayed laid out while every other page was
   rebuilt. Every rule below now reads from base.css: square corners (the
   global reset already zeroes border-radius everywhere, so nothing here
   sets one), 2px solid ink rules in place of the old translucent --rule
   hairline, Archivo's two shipped weights (400 body, 800 for anything that
   was reading as a heading, a label or a live status), and Red 700 held for
   the one place that needed it reserved, the template cards' match-quality
   tag. --muted, --rule and --pad still live in components.css for markup
   this file does not reach, but nothing below reads --rule or --pad any
   more, and --muted is kept exactly where it was: components.css already
   holds it above 4.5:1 on white, ground and surface.

   Contents
     1  consent and plan radios: the one live fix left from the draft's
        global width:100%;min-height:52px rule, now that components.css
        carries the rest of it
     2  the Personalize wizard: the sticky progress bar, its jump links,
        each question group, the shape and template cards
     3  the review table, shared by the Personalize read-back and every
        plain pricing table on these pages
     4  the order page: progress bar, stage list, live feed, preview frame,
        what we could not fix, the editor hand-off, the hosting offer

   Loaded on the flow page type only, after fonts, base, chrome, buttons and
   components (CONTRACTS.md section 2), so every rule here can rely on every
   shared token and component class. Scope a new rule to one page the way
   flow.js already does, with body[data-page="..."]; scope it to all five
   pages here with body[data-type="flow"].
   ────────────────────────────────────────────────────────────────────────── */

/* ── 1. consent and plan radios ────────────────────────────────────────────
   components.css already excludes type=checkbox and type=radio from the
   site's global input,select,textarea{width:100%;min-height:52px} rule and
   sets them to a plain 20px square, and its own .field-check already gives
   every checkbox() field (flow.mjs: every consent box on these pages) a
   flex row with a 3px top nudge so the box lines up with the first line of
   its label instead of floating above it. That covers every checkbox here,
   and the old duplicate of it that used to live in this file is gone.

   Three radio groups are not wrapped in .field-check, because each one
   chooses between two or three short lines rather than confirming one long
   one: the hosting plan on the Personalize start form's second step, the
   same choice on the order page's hosting offer, and "None of these, just
   use the shape I picked" under the template cards. All three still want
   the same 3px nudge. */
fieldset.field:not(.flow-choice) input[type="radio"],
.flow-none input[type="radio"] {
  margin: 3px 0 0;
}

/* A hint that sits inside a .field, after its input, as a plain sibling
   span rather than a paragraph: the revamp intake's page-count note, the
   business plan and business type hints, the hosting order id hint. Left at
   its default inline display it would run on the same line as the input
   instead of reading as a line of its own underneath it. */
.flow-step .field > .small-note,
.flow-step .field > span.small-note {
  display: block;
  color: var(--muted);
  margin-top: 8px;
}

/* ── 2. the Personalize wizard ─────────────────────────────────────────────
   One page, twenty-odd questions in groups, added 2026-09-25 when the
   wizard moved off one question per screen. The sticky progress bar sits
   flush under the site's own top bar, which is a constant var(--bar-h) at
   every width (chrome.css: .bar never changes height in a media query), so
   the progress bar needs no breakpoint of its own for its position either. */
.flow-long { max-width: 1080px; }

.flow-sticky {
  position: sticky; top: var(--bar-h); z-index: 40;
  background: var(--ground);
  border-bottom: 2px solid var(--ink);
  padding: 12px 0 10px;
  margin: 0 0 28px;
}
.flow-sticky p { margin: 0 0 8px; font-weight: 800; font-size: 0.92rem; }
.flow-jump { display: flex; gap: 18px; overflow-x: auto; white-space: nowrap; font-size: 0.85rem; padding-bottom: 4px; }
.flow-jump a { text-decoration: underline; text-underline-offset: 4px; }

/* The jump row scrolls sideways instead of wrapping, so the bar's own
   rendered height holds at about 81px regardless of width (measured at 390
   and 1440, 2026-09-25). scroll-padding and scroll-margin reserve the top
   bar's height plus a rounded 90px for it, so a jump link or a focused
   field never lands underneath either sticky bar. */
.flow-section { border-top: 2px solid var(--ink); padding: 26px 0 8px; scroll-margin-top: calc(var(--bar-h) + 90px); }
.flow-section h3 { font-size: 1.25rem; margin: 0 0 20px; }
.flow-q, .flow-shapes { scroll-margin-top: calc(var(--bar-h) + 90px); }
.flow-q label, .flow-shapes legend { display: block; }
html:has(.flow-long:not([hidden])) { scroll-padding-top: calc(var(--bar-h) + 90px); }
.flow-long input, .flow-long textarea { scroll-margin-top: calc(var(--bar-h) + 90px); }

.flow-num { display: inline-block; min-width: 1.6em; color: var(--muted); font-variant-numeric: tabular-nums; }
.flow-req { display: inline-block; margin-left: 6px; font-size: 0.75rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }

/* The shape and template pickers: a grid of cards, each its own label
   wrapping a radio, a thumbnail and a name. An unselected card reads as a
   plain ink outline like everything else on the site. The checked card and
   its focus ring both move to var(--red), the accent token base.css
   reserves for rules and large type, since ink alone could not tell the two
   states apart once both are a 2px solid border. */
.flow-card-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.flow-step .flow-card {
  display: grid; grid-template-columns: auto minmax(0, 150px) minmax(0, 1fr);
  gap: 14px; align-items: start;
  margin: 0; padding: 12px;
  border: 2px solid var(--ink);
  background: var(--ground);
}
.flow-step .flow-card:has(input:checked) { border-color: var(--red); box-shadow: inset 0 0 0 1px var(--red); }
.flow-step .flow-card:focus-within { outline: 3px solid var(--red); outline-offset: 2px; }
.flow-card-media { display: block; background: var(--surface); aspect-ratio: 36 / 25; }
.flow-card-media img { display: block; width: 100%; height: auto; }
.flow-card-text { display: block; min-width: 0; }
.flow-card-text strong { display: block; font-size: 1rem; color: var(--ink); }
.flow-card-text .small-note { display: block; margin-top: 4px; color: var(--muted); font-size: 0.85rem; line-height: 1.45; }
.flow-card-tag { display: block; margin-bottom: 4px; font-size: 0.72rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: var(--red-700); }

.flow-template-pick { margin-top: 18px; }
.flow-none { margin-top: 12px; }
.flow-missing { margin-top: 10px; color: var(--muted); }
.flow-review { margin-top: 8px; }
.flow-review-table td { overflow-wrap: anywhere; }

@media (max-width: 800px) {
  .flow-card-grid { grid-template-columns: minmax(0, 1fr); }
  .flow-step .flow-card { grid-template-columns: auto minmax(0, 112px) minmax(0, 1fr); gap: 10px; padding: 10px; }
}

/* O5, 2026-09-25. Inside the form's reading measure (components.css,
   .prose > * at 62ch) two cards a row left the text beside a 150px
   thumbnail about one word wide at 1024 and 1440 (ops/S6/
   1440-personalize-start-wizard-cards.png). From 801px the thumbnail sits
   above the text, and the text runs the full width of the card under it.
   The phone layout above is unchanged. */
@media (min-width: 801px) {
  .flow-step .flow-card {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas: "pick media" "text text";
    row-gap: 12px;
  }
  .flow-step .flow-card > input { grid-area: pick; }
  .flow-step .flow-card-media { grid-area: media; }
  .flow-step .flow-card-text { grid-area: text; }
}
@media (max-width: 600px) {
  .flow-review-table.order-totals-table thead { display: none; }
  .flow-review-table.order-totals-table tr {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 12px; align-items: start;
    border-bottom: 2px solid var(--ink);
    padding: 10px 0;
  }
  .flow-review-table.order-totals-table th,
  .flow-review-table.order-totals-table td { display: block; border: 0; padding: 0; }
  .flow-review-table.order-totals-table th { grid-column: 1; grid-row: 1; }
  .flow-review-table.order-totals-table td:nth-child(2) { grid-column: 1 / -1; grid-row: 2; margin-top: 4px; }
  .flow-review-table.order-totals-table td:nth-child(3) { grid-column: 2; grid-row: 1; }
  .flow-review-table .text-button { padding: 0 0 6px; }
}

/* ── 3. the review table ───────────────────────────────────────────────────
   Shared by the Personalize read-back (flow.mjs adds class flow-review-table
   to it) and the plain pricing tables on the order and hosting pages
   (order-totals-table alone). Archivo 800 on the header row: a bare <th> is
   only browser-bold otherwise, a weight this site never uses elsewhere. */
.flow-price { margin-bottom: 28px; font-size: 1.05rem; }
.order-totals-table { border-collapse: collapse; width: 100%; margin: 18px 0; font-size: 0.92rem; }
.order-totals-table th, .order-totals-table td { border-bottom: 2px solid var(--ink); padding: 12px 10px; text-align: left; }
.order-totals-table th { font-weight: 800; }

/* Found 2026-09-25: hosting.mjs's two DNS tables (the static "bring your own
   domain" rows and renderRecords's verification result, both four columns,
   one holding a full host name such as apex-loadbalancer.netlify.com) do not
   fit 390px however the type is sized, and this table has no narrow-width
   reflow of its own the way the review table does above (its first cell is
   a row <th>, not a <td>, so the same nth-child stacking would misread it).
   Letting the table itself scroll sideways, capped to its own box, is the
   standard fix and reads better than either shrinking the words past
   comfort or letting the whole page scroll sideways, which the review table
   never needed and keeps its own treatment. */
@media (max-width: 800px) {
  .order-totals-table:not(.flow-review-table) { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
}

/* ── 4. the order page ─────────────────────────────────────────────────────
   Progress, the stage list, the live feed, the preview frame, what we could
   not fix, the editor hand-off, and the hosting offer (#order-host and
   #order-site, styled by sections 1 and 3 above). Red is spent once on this
   page, on the stage that is running right now, which is the one thing a
   person watching it is looking for. Every other mark here is ink, ground
   or surface. */
.order-progress { height: 6px; background: var(--surface); margin: 18px 0 8px; max-width: 520px; }
.order-progress-bar { height: 100%; width: 0; background: var(--ink); transition: width 0.3s; }
@media (prefers-reduced-motion: reduce) { .order-progress-bar { transition: none; } }
:root[data-motion="reduce"] .order-progress-bar { transition: none; }

.order-result, #order-host, #order-site { max-width: 980px; padding: 0 var(--gutter) 40px; }
.order-error-section { padding: 0 var(--gutter) 80px; max-width: 980px; }

.order-stages { list-style: none; margin: 14px 0 0; padding: 0; max-width: 520px; border-top: 2px solid var(--ink); }
.order-stage { display: flex; align-items: center; gap: 12px; padding: 9px 0; border-bottom: 2px solid var(--ink); font-size: 0.92rem; }
.order-stage-mark { width: 10px; height: 10px; flex: 0 0 10px; background: var(--surface); border: 2px solid var(--ink); }
.order-stage-name { flex: 1 1 auto; }
.order-stage-time { color: var(--muted); font-variant-numeric: tabular-nums; font-size: 0.85rem; }
.order-stage-done .order-stage-mark { background: var(--ink); border-color: var(--ink); }
.order-stage-done .order-stage-name { color: var(--muted); }
.order-stage-running .order-stage-mark { background: var(--red); border-color: var(--red); }
.order-stage-running .order-stage-name { font-weight: 800; }
.order-stage-waiting .order-stage-name { color: var(--muted); }

.order-feed { max-width: 980px; padding: 0 var(--gutter) 10px; }
/* Capped and scrolled rather than allowed to grow: twenty pages plus eight
   passes is about sixty lines, and sixty lines pushes the download off the
   screen on a phone. */
.order-feed-list { list-style: none; margin: 10px 0 0; padding: 12px; max-height: 280px; overflow-y: auto; border: 2px solid var(--ink); font-size: 0.88rem; }
.order-feed-list li { display: flex; gap: 12px; padding: 5px 0; align-items: baseline; }
.order-feed-kind { flex: 0 0 78px; color: var(--muted); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; }
.order-feed-text { flex: 1 1 auto; word-break: break-word; }
.order-feed-live .order-feed-kind { color: var(--ink); font-weight: 800; }

.order-preview { margin: 24px 0 8px; }
.order-preview-frame { display: block; width: 100%; height: 520px; border: 2px solid var(--ink); background: var(--white); }

.order-fix { max-width: 980px; padding: 0 var(--gutter) 60px; }
.order-fix-list { list-style: none; margin: 10px 0 24px; padding: 0; }
.order-fix-list li { padding: 14px 0; border-bottom: 2px solid var(--ink); }
.order-fix-list strong { display: block; }
.order-fix-why, .order-fix-do { display: block; color: var(--muted); font-size: 0.9rem; margin-top: 5px; }
.order-fix-do { color: var(--ink); }

@media (max-width: 600px) {
  .order-preview-frame { height: 360px; }
  .order-feed-kind { flex: 0 0 62px; }
}

/* The editor hand-off on a finished Personalize order, 2026-09-25. */
.order-editor { margin: 30px 0 8px; padding-top: 22px; border-top: 2px solid var(--ink); }
.order-editor h4 { margin: 18px 0 4px; font-size: 0.95rem; font-weight: 800; }
.order-editor-kept-list { margin: 8px 0 0; padding-left: 20px; font-size: 0.9rem; }

/* O5, 2026-09-25. These sections sat against the window's left edge while the
   page hero above them sits in the site's 1200px column (components.css), so
   at 1440 the error and the results started 120px left of the heading
   (ops/o5/order-personalize-failed-1440.png before this rule). They now share
   that column and keep a reading width inside it. #order-host and #order-site
   are .prose sections, which components.css already lays out that way. */
.order-result, .order-error-section, .order-feed, .order-fix { width: min(1200px, 100%); max-width: none; margin-inline: auto; }
.order-result > *, .order-error-section > *, .order-feed > *, .order-fix > * { max-width: 868px; }
#order-host, #order-site { max-width: none; }

/* O5, 2026-09-25. The order page's status column. order.mjs wraps every
   status line in .order-status, so the heading keeps the hero's left column
   and the lines stack in the right one in every state. Top-aligned, because
   the column grows as the order moves (a stage list, a notice) and bottom
   alignment would push the heading down with it. Below 801px the hero is a
   single column and the wrapper simply follows the heading. */
.order-hero { align-items: start; }
.order-status > * + * { margin-top: 16px; }
