/* Chair Cost Analyzer — visual system.

   Ported from docs/mockup/cca-final.html (the reviewed, authoritative design —
   see docs/DECISIONS.md's prompt 29 entry and this pass's own entry) onto the
   app's EXISTING class names and template structure. Where the mockup and the
   app's current markup structurally diverge (the review grid, the wizard's
   schema-driven step count), this file restyles what's actually rendered
   rather than assuming a 1:1 markup port — see this pass's DECISIONS.md entry
   for the reasoning.

   Every class below is either purely visual (no JS ever selects it) or purely
   behavioral (no CSS rule here ever targets it) — never both. See the
   standing rule: a class used for styling must never double as a JS
   selector. .wizard-required-field is the existing example this file follows
   (behavioral only, zero rules below); .field-echo is the same
   (chair_cost/forms/html.py's share_echo_message and static/js/
   extraction_form.js both target it by id, not by this class). */

:root {
  --blue: #1D8EC6;
  --deep: #12587C;
  --wash: #EFF7FC;
  --green: #84C53F;
  --yellow: #E8AF3E;
  --orange: #C84F3E;
  --ink: #16242D;
  --slate: #61727D;
  --hair: #E6ECF0;
  --white: #fff;

  /* Legacy aliases -- code and comments elsewhere may still reference the
     old --ppp-* names; keep them pointed at the ported palette rather than
     hunting down every reference in one pass. */
  --ppp-primary: var(--blue);
  --ppp-text: var(--ink);
  --ppp-border: var(--hair);
  --ppp-error: #b3261e;
  --ppp-warn: #8a5a00;
}

* { box-sizing: border-box; }

body {
  background: var(--white);
  color: var(--ink);
  font-family: 'Plus Jakarta Sans', system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: 17px;
  line-height: 1.65;
  margin: 0;
  -webkit-font-smoothing: antialiased;
}

.num, code, pre {
  font-family: 'IBM Plex Mono', monospace;
  font-variant-numeric: tabular-nums;
}

/* Prompt 119, item 8 (owner ruling): brand-styled links on every page a
   doctor can reach -- never the browser's default blue, nor its purple once
   visited. :where() keeps these at zero specificity, so any link styled as
   something else (a .btn, the session bar's own links) keeps its own
   colours; an author rule of any weight still overrides the browser's. */
:where(a) { color: var(--blue); text-underline-offset: 2px; }
:where(a):hover { color: var(--deep); }
:where(button, input, select, textarea) { font-family: inherit; }

h1 {
  font-size: clamp(2rem, 4.8vw, 2.9rem);
  font-weight: 700;
  letter-spacing: -.03em;
  line-height: 1.12;
  margin: 0 0 1.4rem;
}

h2 {
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: -.02em;
  margin: 0 0 .6rem;
  color: var(--ink);
}

h3 {
  font-size: 1.05rem;
  font-weight: 600;
  margin: 0 0 .35rem;
  color: var(--ink);
}

p { color: var(--slate); }
p b, p strong { color: var(--ink); font-weight: 600; }
.small { font-size: .95rem; }

main {
  max-width: 760px;
  margin: 0 auto;
  padding: clamp(2rem, 6vw, 3.5rem) clamp(1.25rem, 6vw, 2rem) 6rem;
}

main.wide { max-width: 940px; }

/* header / footer */

.ppp-header {
  display: flex;
  align-items: center;
  gap: .85rem;
  padding: 1rem clamp(1.25rem, 6vw, 4.5rem);
  border-bottom: 1px solid var(--hair);
  background: var(--white);
  color: var(--ink);
}

.ppp-logo { height: 46px; width: auto; display: block; }

.ppp-header h1 {
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -.01em;
  line-height: 1.25;
  margin: 0;
}

.ppp-header .byline {
  font-size: .74rem;
  color: var(--slate);
  line-height: 1.25;
  margin: 0;
}

.ppp-footer {
  text-align: center;
  color: var(--slate);
  font-size: .8rem;
  padding: 0 1rem 3.5rem;
}

/* buttons */

.btn, a.btn, button[type="submit"] {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  background: var(--blue);
  color: #fff;
  border: 0;
  border-radius: 100px;
  font-family: inherit;
  font-size: 1rem;
  font-weight: 600;
  padding: .85rem 1.6rem;
  cursor: pointer;
  text-decoration: none;
  transition: background .18s;
}

.btn:hover, a.btn:hover, button[type="submit"]:hover { background: var(--deep); }
.btn:focus-visible, button[type="submit"]:focus-visible { outline: 3px solid var(--yellow); outline-offset: 3px; }

.btn:disabled, button[type="submit"]:disabled {
  background: var(--hair);
  color: #98A6AE;
  cursor: not-allowed;
}

.btn.plain, a.btn.plain {
  background: none;
  color: var(--slate);
  padding-left: .25rem;
  font-weight: 500;
}
.btn.plain:hover, a.btn.plain:hover { background: none; color: var(--ink); }

/* Prompt 118, item 6: the secondary action beside a primary one (the
   wizard's Back) -- a quiet outlined button, never the primary blue. */
.btn.secondary, a.btn.secondary {
  background: var(--white);
  color: var(--slate);
  border: 1px solid var(--hair);
  font-weight: 500;
}
.btn.secondary:hover, a.btn.secondary:hover { background: var(--wash); color: var(--ink); border-color: var(--slate); }

.acts { display: flex; align-items: center; gap: 1rem; margin-top: 3rem; flex-wrap: wrap; }

/* fieldset / form fields */

fieldset {
  border: 0;
  border-top: 1px solid var(--hair);
  margin: 2rem 0 0;
  padding: 1.5rem 0 0;
}

legend {
  font-weight: 700;
  font-size: 1.02rem;
  color: var(--ink);
  padding: 0;
}

.field-row { margin: 1.1rem 0; }
.field-row.hidden { display: none; }

.field-row label {
  display: block;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: .3rem;
}

.field-code { color: var(--slate); font-weight: 400; }

.field-row input[type="text"],
.field-row input[type="number"],
.field-row input[type="date"] {
  border: 1px solid var(--hair);
  border-radius: 11px;
  padding: .75rem .95rem;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 1.02rem;
  color: var(--ink);
  background: #FCFDFE;
  min-width: 12rem;
}

.field-row input:focus { outline: 0; border-color: var(--blue); background: #fff; }
/* Prompt 118, item 7: red only once the doctor has pressed Next and left
   the question open -- the server marks exactly those (aria-invalid, from
   app.py's _wizard_render). Never :invalid, which marks every blank
   required field the moment the page loads. */
.field-row input[aria-invalid="true"] { border-color: var(--ppp-error); }

.computed-field {
  background: var(--wash);
  color: var(--deep);
  font-weight: 600;
}

.unit-suffix {
  margin-left: .5rem;
  color: var(--slate);
  font-size: .92rem;
}

.field-optional { color: var(--slate); font-weight: 400; font-size: .88rem; }

.help-text {
  margin: .35rem 0 0;
  font-size: .92rem;
  color: var(--slate);
  max-width: 56ch;
}

/* live conversational echo -- optical_staff_wages / optical_health_insurance
   (chair_cost/forms/html.py::share_echo_message). Behavioral id (echo-<field>)
   is separate from this purely-visual class, per the standing rule. */
.field-echo { color: var(--deep); font-weight: 500; min-height: 1.3em; }
.field-echo:empty { margin: 0; }

/* tables */

.matrix-table, .array-table, .results-table {
  border-collapse: collapse;
  margin: .75rem 0 1.25rem;
  width: 100%;
  font-size: .95rem;
}

.matrix-table th, .matrix-table td,
.array-table th, .array-table td,
.results-table th, .results-table td {
  border-bottom: 1px solid var(--hair);
  padding: .55rem .6rem .55rem 0;
  text-align: left;
}

.matrix-table input, .array-table input { width: 5.5rem; }

.results-table th {
  width: 40%;
  font-size: .72rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--slate);
  font-weight: 600;
  background: none;
}

.results-table tr.headline-row th,
.results-table tr.headline-row td {
  font-weight: 700;
  background: var(--wash);
}

.form-errors {
  background: #FDF1EE;
  border-radius: 16px;
  padding: 1.4rem 1.6rem;
  margin-bottom: 1.5rem;
  color: #8C3624;
}
.form-errors h2 { color: #8C3624; font-size: 1.1rem; }

.block-results {
  background: #FDF1EE;
  border-radius: 16px;
  padding: 1.4rem 1.6rem;
  color: #8C3624;
}
.block-results h3 { color: #8C3624; }

.warn-results {
  background: #FDF7EC;
  border-radius: 16px;
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.5rem;
}

.disclosure-note { font-style: italic; color: var(--slate); }

/* ---- welcome (s1) / what-you'll-need (s2) ---- */

.outs { margin-top: 2.5rem; }
.out {
  display: flex;
  gap: 1.1rem;
  padding: 1.15rem 0;
  border-top: 1px solid var(--hair);
}
.out .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; margin-top: .62rem; }
.out h3 { font-size: 1.02rem; margin-bottom: .15rem; }
.out p { font-size: .97rem; margin: 0; }

.figure { margin: 3rem 0; }
.figure svg { width: 100%; height: auto; display: block; }
.fl { stroke: var(--blue); stroke-width: 1.1; fill: none; opacity: .3; }
@keyframes cca-drift { to { stroke-dashoffset: -16; } }
.fl.anim { stroke-dasharray: 2 6; stroke-linecap: round; animation: cca-drift 2.2s linear infinite; }
.in-t { font-size: 12.5px; fill: var(--slate); font-family: 'Plus Jakarta Sans'; }
.o-n { font-size: 19px; font-weight: 500; fill: var(--deep); font-family: 'IBM Plex Mono', monospace; }
.o-l { font-size: 11.5px; fill: var(--slate); font-family: 'Plus Jakarta Sans'; }
.cap { font-size: .78rem; color: var(--slate); text-align: center; margin-top: 1rem; }
@media (prefers-reduced-motion: reduce) { .fl.anim { animation: none; } }

.pl-moment {
  background: var(--wash);
  border-radius: 16px;
  padding: 2rem;
  margin-top: 2.5rem;
  display: flex;
  gap: 2rem;
  align-items: center;
  flex-wrap: wrap;
}
.pl-moment > div { flex: 1; min-width: 240px; }
.pl-moment h2 { margin-bottom: .4rem; }
.pl-moment .big { text-align: center; flex: none; min-width: 0; }
.pl-moment .big em {
  display: block; font-style: normal; font-size: 2.6rem; font-weight: 500;
  color: var(--blue); line-height: 1; font-family: 'IBM Plex Mono', monospace;
}
.pl-moment .big span { font-size: .82rem; color: var(--slate); display: block; margin-top: .4rem; }

.beat { margin-top: 3.5rem; }

.intro-supply-group { margin-top: 2.4rem; }
.intro-supply-group-h {
  display: flex; align-items: center; gap: .65rem; margin-bottom: .7rem;
}
.intro-supply-group-h .tick { width: 20px; height: 3px; border-radius: 2px; }
.intro-supply-group-h h3 { font-size: 1rem; margin: 0; }
.intro-supply-group ul { list-style: none; margin: 0; padding: 0; }
.intro-supply-group li {
  font-size: 1rem; color: var(--slate); padding: .3rem 0 .3rem 1.5rem; position: relative;
}
.intro-supply-group li::before {
  content: ""; position: absolute; left: .4rem; top: .95rem; width: 6px; height: 6px;
  border-radius: 50%; background: var(--hair);
}
.intro-supply-group li b { color: var(--ink); font-weight: 600; }
.intro-supply-group p { font-size: 1rem; color: var(--slate); margin: 0; }

.aside {
  margin-top: 3rem; padding-left: 1.1rem; border-left: 3px solid var(--yellow);
  font-size: .97rem; color: var(--slate); max-width: 60ch;
}

.intro-cta {
  display: inline-flex; align-items: center; gap: .5rem;
  background: var(--blue); color: #fff; border-radius: 100px;
  padding: .85rem 1.6rem; font-size: 1rem; font-weight: 600; text-decoration: none;
}
.intro-cta:hover { background: var(--deep); }

/* ---- entry page (s4) ---- */

.entry-drop {
  position: relative;
  border: 2px dashed var(--hair); border-radius: 16px; padding: 2.5rem 2rem;
  text-align: center; margin-top: 1.5rem; cursor: pointer; transition: border-color .18s, background .18s;
}
.entry-drop:hover, .entry-drop:focus-within { border-color: var(--blue); background: var(--wash); }
.entry-drop .ic { font-size: 1.6rem; line-height: 1; }
.entry-drop h3 { margin: .7rem 0 .3rem; }
.entry-drop p { font-size: .92rem; margin: 0 auto; }

/* Prompt 99 deliverable 4: a chosen file gets its own solid border and
   green tint so the zone reads as "loaded," not identical to empty. */
.entry-drop.has-file { border-style: solid; border-color: var(--green); background: var(--wash); }
.entry-drop.has-file h3 { word-break: break-word; }

/* A moving spinner inside the submit button -- the only sign of life
   during the twenty-to-thirty-second extraction call. .is-busy keeps
   the button's own blue instead of the :disabled grey below, which on
   its own reads as broken rather than working. */
button[type="submit"].is-busy {
  display: inline-flex; align-items: center; gap: .55rem;
}
button[type="submit"]:disabled.is-busy {
  background: var(--blue); color: #fff; cursor: wait;
}
button[type="submit"] .spinner {
  width: 14px; height: 14px; flex: none; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .4); border-top-color: #fff;
  animation: cca-spin .7s linear infinite;
}
@keyframes cca-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  button[type="submit"] .spinner { animation: none; opacity: .8; }
}

/* The real file input stays in the DOM, focusable and reachable by a
   screen reader (never display:none) -- it's stretched invisibly over
   the whole drop zone, so a native click/tap/keyboard-Enter anywhere in
   the zone opens the file picker directly (no JS needed for this part);
   only its own default "Choose File" chrome is hidden. */
.entry-drop input[type="file"] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer; margin: 0;
}

.entry-or {
  display: flex; align-items: center; gap: 1rem; margin: 1.75rem 0;
  color: var(--slate); font-size: .85rem;
}
.entry-or::before, .entry-or::after { content: ""; flex: 1; height: 1px; background: var(--hair); }

.entry-paste, .entry-upload, .entry-manual {
  margin: 0;
}

.statement-textarea {
  width: 100%; min-height: 190px; border: 1px solid var(--hair); border-radius: 14px;
  padding: 1.1rem 1.2rem; font-family: 'IBM Plex Mono', monospace; font-size: .86rem;
  color: var(--ink); resize: vertical; background: #FCFDFE; margin-bottom: .75rem;
}
.statement-textarea:focus { outline: 0; border-color: var(--blue); background: #fff; }

.tiny { font-size: .88rem; color: var(--slate); margin-top: .5rem; }

/* Extracted-field marking on the form (Prompt 20b) */

.field-row.extracted {
  background: var(--wash);
  border-left: 3px solid var(--green);
  padding-left: .75rem;
  border-radius: 4px;
}

.extracted-badge {
  display: inline-block;
  background: var(--green);
  color: #fff;
  font-size: .68rem;
  font-weight: 600;
  border-radius: 3px;
  padding: .05rem .4rem;
  margin-left: .5rem;
  vertical-align: middle;
}

.extraction-summary {
  background: var(--wash);
  border-radius: 12px;
  padding: 1rem 1.25rem;
  margin-bottom: 1.5rem;
}

/* ---- review screen (s5) ---- */

.review-tally { display: flex; gap: 2.5rem; flex-wrap: wrap; margin: 1.5rem 0 .5rem; }
.review-tally .n {
  font-family: 'IBM Plex Mono', monospace; font-size: 2.1rem; font-weight: 500; line-height: 1;
  color: var(--ink);
}
.review-tally .n.ok { color: var(--green); }
.review-tally .n.need { color: var(--orange); }
.review-tally .t { font-size: .9rem; color: var(--slate); margin-top: .2rem; }

.review-rule { height: 1px; background: var(--hair); margin: 2.5rem 0; }

/* Prompt 118, item 4: lines the statement's own arithmetic placed without
   asking, said one sentence each -- a settled fact, so the green of "done",
   not a question's wash. */
.review-settled {
  background: #F1F8E8; border-radius: 16px; padding: 1.2rem 1.5rem; margin: 1.5rem 0 0;
}
.review-settled h3 { color: #3F6B15; }
.review-settled ul { margin: .4rem 0 0; padding-left: 1.1rem; }
.review-settled li { font-size: .95rem; color: var(--ink); margin: .3rem 0; }

/* Prompt 118, item 5: a Special Deposits row's own suggestion, in plain
   view above its choices (never a selection). */
.ask > p.deposit-suggestion { color: var(--deep); font-weight: 500; }

/* Each suspicious-absence / statement-period question ("Where does [line] --
   [amount] belong?"-shaped, but "supply a known field's missing amount," not
   "categorize this ambiguous line") gets this wash-card look. */
.review-ask {
  background: var(--wash);
  border-radius: 16px;
  padding: 1.4rem 1.5rem;
  margin-top: 1rem;
}
.review-ask h4 {
  font-size: 1.05rem; font-weight: 600; margin: 0 0 .35rem; color: var(--ink);
}
.review-ask .amt { font-family: 'IBM Plex Mono', monospace; font-weight: 500; color: var(--ink); }
.review-ask p { font-size: .97rem; margin: 0 0 1rem; }

/* Visually hidden but still focusable/readable by a screen reader or a
   keyboard-only user tabbing through -- the ONE pattern this file uses to
   keep a real form control as the source of truth (review.js's existing
   .unmatched-target-select[data-amount][data-index] contract, untouched)
   while a nicer control sits visually on top of it. Not display:none or
   visibility:hidden, both of which would also remove it from the tab order
   and from assistive tech. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* Prompt 79: the unmatched-item card docs/mockup/cca-final.html's s5 always
   specified -- an "our guess" pick, one-click alternatives, a type-to-filter
   panel for the rest, and a park (not waive) skip. Deferred out of an
   earlier pass's scope (this file's own prior comment on this spot, and
   docs/DECISIONS.md's record of why) specifically because deriving a fixed
   short pick-list from an open, arbitrary-N category set was ruled out of
   scope THEN -- this pass's own report (DECISIONS.md) is what that earlier
   deferral was waiting on. The real <select> review.js already drives
   (.unmatched-target-select, now also .sr-only) stays the actual form
   control; every button below only ever sets that control's value and
   dispatches a change event, so review.js's recompute()/assignment-preview/
   undecided-count logic needed no changes at all. */
.ask {
  background: var(--wash);
  border-radius: 16px;
  padding: 1.4rem 1.5rem;
  margin-top: 1rem;
}
.ask h3 { font-size: 1.05rem; font-weight: 600; margin: 0 0 .35rem; color: var(--ink); }
.ask > p { font-size: .97rem; margin: 0 0 1rem; color: var(--slate); }
.ask .amt { font-family: 'IBM Plex Mono', monospace; font-weight: 500; color: var(--ink); }

.picks { display: flex; gap: .5rem; flex-wrap: wrap; }
.pick {
  background: #fff; border: 1px solid var(--hair); border-radius: 100px;
  padding: .5rem 1.05rem; font-family: inherit; font-size: .92rem; color: var(--ink);
  cursor: pointer;
}
.pick:hover { border-color: var(--blue); color: var(--deep); }
.pick:focus-visible { outline: 3px solid var(--yellow); outline-offset: 2px; }
.pick.sel { background: var(--blue); border-color: var(--blue); color: #fff; font-weight: 600; }
.pick.alt { color: var(--slate); }
.pick.sug { border-color: var(--blue); color: var(--deep); position: relative; padding-right: 1.05rem; }
.pick.sug i {
  font-style: normal; font-size: .7rem; color: var(--blue); opacity: .75;
  margin-left: .4rem; text-transform: uppercase; letter-spacing: .04em;
}
.pick.sel i { color: #fff; opacity: .8; }

.more {
  display: none; margin-top: 1rem; background: #fff; border: 1px solid var(--hair);
  border-radius: 12px; padding: 1rem 1.1rem;
}
.more.open { display: block; }
.more h4 {
  font-size: .86rem; font-weight: 600; color: var(--slate); margin: 0 0 .7rem;
  text-transform: uppercase; letter-spacing: .04em;
}
.more input {
  width: 100%; border: 1px solid var(--hair); border-radius: 9px; padding: .65rem .85rem;
  font-family: inherit; font-size: .95rem; margin-bottom: .7rem; box-sizing: border-box;
}
.more input:focus { outline: 0; border-color: var(--blue); }
.lines { list-style: none; max-height: 220px; overflow: auto; margin: 0; padding: 0; }
.lines li {
  display: flex; justify-content: space-between; gap: 1rem; padding: .5rem .55rem;
  border-radius: 8px; cursor: pointer; font-size: .93rem; color: var(--ink);
}
.lines li:hover { background: var(--wash); }
.lines li span:last-child { font-family: 'IBM Plex Mono', monospace; color: var(--slate); }
.more p.none { display: none; margin: .5rem .1rem 0; font-size: .88rem; color: var(--slate); }
.more p.none.on { display: block; }

/* Prompt 113 item 2: the expense-side "more" panel's own flip-to-income
   choices -- a rare correction, so visually quieter than the panel's
   primary expense-category list below it, never competing with it. */
.more-flip-heading {
  font-size: .82rem; color: var(--slate); margin: 0 0 .5rem; font-style: italic;
}
.picks-flip { margin-bottom: 1rem; padding-bottom: 1rem; border-bottom: 1px solid var(--hair); }
.picks-flip .pick { font-size: .86rem; padding: .4rem .7rem; }

.skip {
  background: none; border: 0; color: var(--slate); font-family: inherit; font-size: .9rem;
  cursor: pointer; margin-top: .9rem; padding: 0; text-decoration: underline;
}
.skip:hover { color: var(--ink); }
.skip:focus-visible { outline: 3px solid var(--yellow); outline-offset: 2px; }

.ask.parked { background: #FDF7EC; }
.parkflag {
  display: none; align-items: center; gap: .5rem; font-size: .9rem; color: #8A6410;
  margin-top: .9rem;
}
.ask.parked .parkflag { display: flex; }
.ask.parked .picks, .ask.parked .more, .ask.parked > .skip { display: none; }
.parkflag .unpark { margin-top: 0; }

details {
  margin-top: 1.5rem;
  border-top: 1px solid var(--hair);
  padding-top: 1.25rem;
}
summary {
  cursor: pointer; font-weight: 600; font-size: 1rem; list-style: none;
  display: flex; align-items: center; gap: .5rem; color: var(--ink);
}
summary::-webkit-details-marker { display: none; }
summary::before {
  content: "\203A"; display: inline-block; transition: transform .18s;
  color: var(--blue); font-size: 1.3rem; line-height: 1;
}
details[open] summary::before { transform: rotate(90deg); }
summary em { font-style: normal; font-weight: 400; color: var(--slate); font-size: .92rem; }
.tblwrap { max-height: 460px; overflow: auto; margin-top: 1rem; border-radius: 10px; }

.provenance-table { color: var(--slate); font-size: .8rem; }
.provenance-judgment { color: #8A6410; font-weight: 600; font-size: .8rem; }

.verification-note { margin: 0; font-size: .82rem; color: var(--orange); font-weight: 400; }

tr.mismatch-row { background: #FDF1EE; }
tr.mismatch-note-row td { background: #FDF1EE; padding: .5rem 1rem .7rem; }

.notes { font-size: .93rem; color: var(--slate); margin: 0; padding: 0; }
.notes li { margin: .5rem 0 .5rem 1.1rem; }

tr.unmatched-row.has-proposal { border-left: 4px solid var(--yellow); }

.unmatched-target-select { margin-right: .4rem; }

/* The suggestion lives inside the select itself now (prompt 39, Ruling
   1) -- marked with this class on its own <option>, never pre-selected
   (see review.html's own comment at the call site). Option styling is
   inconsistent across browsers, so the marking leans on the option's own
   text ("— suggested") for legibility everywhere; this rule is a
   progressive enhancement where the browser honors it. */
option.option-suggested { font-weight: 700; }

.bulk-accept-btn {
  display: inline-flex; align-items: center; gap: .4rem;
  background: var(--white); color: var(--blue); border: 2px solid var(--blue);
  border-radius: 100px; font-family: inherit; font-weight: 600; font-size: .92rem;
  padding: .55rem 1.1rem; cursor: pointer; margin: .75rem 0;
}
.bulk-accept-btn:hover { background: var(--wash); }
.bulk-accept-btn:focus-visible { outline: 3px solid var(--yellow); outline-offset: 3px; }

.assignment-preview { margin: .3rem 0 0; font-size: .82rem; color: var(--deep); font-style: italic; }

.review-table tr.assignment-target { background: var(--wash); outline: 2px solid var(--green); }

.review-figures {
  background: var(--wash); border-radius: 12px; padding: .75rem 1.1rem; margin: .5rem 0 .75rem;
  font-size: .95rem;
}

tr.excluded-row { background: #F0F0F0; color: var(--slate); text-decoration: line-through; }
tr.excluded-row td { color: var(--slate); }

/* Component breakdown (prompt 38, Ruling D): the statement rows summed
   onto one matched line, shown so the total stays auditable rather than
   bare, and each individually excludable. */
tr.component-breakdown-row td { background: var(--wash); padding: .5rem 1rem .7rem; }
.component-breakdown-label { margin: 0 0 .35rem; font-size: .82rem; color: var(--slate); }
.component-breakdown-list { list-style: none; margin: 0; padding: 0; }
.component-breakdown-list li { font-size: .88rem; padding: .15rem 0; }
.component-breakdown-list label { cursor: pointer; }
.component-breakdown-list input[type="checkbox"] { margin-right: .5rem; }
.component-breakdown-list .component-excluded { color: var(--slate); text-decoration: line-through; }
.review-amount-input[readonly] { background: var(--wash); color: var(--deep); }

/* Statement-period ask card (prompt 37) reuses .review-ask's wash-card
   look; .fld is its own two-input row, generic enough to reuse anywhere
   a label+input pair needs to sit inline rather than stacked. */
.fld { display: flex; align-items: flex-start; gap: 1.75rem; flex-wrap: wrap; margin-top: 1rem; }
.fld label { display: flex; flex-direction: column; gap: .35rem; font-weight: 600; color: var(--ink); font-size: .92rem; }
.fld label input { font-weight: 400; }

/* ---- post-extraction wizard (s7-s10) ---- */

.wizard-progress-bar { display: flex; gap: .4rem; margin-bottom: 1.5rem; }
.wizard-progress-bar span { height: 4px; flex: 1; border-radius: 2px; background: var(--hair); }
.wizard-progress-bar span.done { background: var(--blue); }
.wizard-progress-bar span.now { background: var(--blue); opacity: .45; }

.wizard-progress {
  font-size: .82rem; color: var(--slate); margin-bottom: 1.5rem;
  font-family: 'IBM Plex Mono', monospace; letter-spacing: .04em; font-weight: 400;
  text-transform: uppercase;
}

.wizard-step-fields { border-top: 0; padding-top: 0; }

.field-row.wizard-question {
  padding: 1.9rem 0; border-top: 1px solid var(--hair); margin: 0;
}
.field-row.wizard-question:first-of-type { border-top: 0; padding-top: .5rem; }
.field-row.wizard-question label { font-size: 1.22rem; font-weight: 600; letter-spacing: -.015em; }
.field-row.wizard-question .help-text { max-width: 56ch; margin-bottom: 1.1rem; font-size: .98rem; }

.wizard-stepdiv { margin: 3.2rem 0 0; padding-top: 1.6rem; border-top: 2px solid var(--ink); }
.wizard-stepdiv h2 { font-size: 1.02rem; font-weight: 700; letter-spacing: -.01em; margin-bottom: .3rem; }
.wizard-stepdiv p { font-size: .95rem; color: var(--slate); max-width: 56ch; }

.payroll-carry-row {
  padding: 1.9rem 0; border-top: 1px solid var(--hair); margin: 0;
}
.payroll-carry-row:first-of-type { border-top: 0; padding-top: .5rem; }
.payroll-carry-row label { font-size: 1.22rem; font-weight: 600; }

.wizard-outstanding {
  background: #FDF1EE; border-radius: 16px; padding: 1.6rem 1.75rem; margin-top: 2rem;
}
.wizard-outstanding h3 { font-size: 1.1rem; font-weight: 700; color: #8C3624; margin-bottom: .4rem; }
.wizard-outstanding p { font-size: .98rem; color: #8C3624; opacity: .85; }
.wizard-outstanding ul { list-style: none; margin-top: 1.1rem; padding: 0; }
.wizard-outstanding li {
  display: flex; justify-content: space-between; gap: 1rem; align-items: baseline;
  padding: .7rem 0; border-top: 1px solid #F2D9D2; font-size: .97rem;
}
.wizard-outstanding-label { font-weight: 600; color: #8C3624; }
/* Prompt 118: why an answered question is still open -- the rule's own
   plain words and figures. */
.wizard-outstanding-detail { display: block; font-weight: 400; font-size: .92rem; color: #8C3624; margin-top: .2rem; }
.field-from-statement { color: var(--deep); }
.wizard-jump-link {
  background: none; border: 0; color: var(--deep); font-family: inherit;
  font-size: .9rem; font-weight: 600; padding: 0; cursor: pointer; text-decoration: none;
}
.wizard-jump-link:hover { text-decoration: underline; }

/* Prompt 118, item 6: Back on the left, Next (or Calculate) on the right.
   row-reverse, because the forward action stays FIRST in DOM order -- Enter
   in a field fires the first submit button (extraction_form.html's own
   comment) -- while it sits on the right. */
.wizard-nav {
  display: flex; flex-direction: row-reverse; justify-content: space-between; align-items: center;
  gap: 1rem; margin-top: 3rem; flex-wrap: wrap;
}
.wizard-nav button { margin: 0; }

/* Owner request, prompt 111: the page's one primary action (confirming
   review, or the wizard's Next/Calculate) used to sit at the bottom of a
   long page, easy to scroll past without noticing. Sticks to the bottom
   of the viewport once the page is tall enough to scroll -- CSS only, no
   JS observes or toggles it, and it stays a plain block (identical to
   today's layout) on a page short enough that it never needs to stick.
   Presentational only: this class is never selected from JS anywhere in
   the codebase (static/js/review.js and extraction_form.js target
   #confirm-button/#calculate-btn by id, not by their containing class),
   and must stay that way -- a styling class doubling as a JS hook is
   exactly the coupling this rule exists to avoid. Hidden on print
   (print.css already hides every submit button; this drops the now-
   empty bar around it too). */
.sticky-cta {
  position: sticky;
  bottom: 0;
  z-index: 5;
  background: var(--white);
  padding-top: 1rem;
  padding-bottom: 1rem;
  border-top: 1px solid var(--hair);
  box-shadow: 0 -6px 14px -8px rgba(22, 36, 45, .12);
}

.wizard-review-link { margin-top: 1rem; font-size: .9rem; }
.wizard-review-link a { color: var(--slate); text-decoration: none; }
.wizard-review-link a:hover { color: var(--deep); text-decoration: underline; }

.stop-clear {
  background: #F1F8E8; border-radius: 16px; padding: 1.4rem 1.6rem;
  margin-top: 2rem; font-size: 1rem; color: #3F6B15; max-width: 62ch;
}

.zero-ok { color: var(--green); font-weight: 600; font-size: .9rem; }

/* Intro page (Prompt 22) */

.intro-what, .intro-produces, .intro-gather { margin: 1.25rem 0; }

/* Account creation and sign-in (docs/mockup/cca-final.html s12).
   Ported from the mockup's own rules; .af-error and .af-optional are new --
   the mockup has no error state, because nothing in it submits anywhere. */

.acct-pane { max-width: 640px; }
.acct-sec { margin-top: 2.6rem; padding-top: 1.5rem; border-top: 1px solid var(--hair); }
.acct-sec:first-of-type { margin-top: 2rem; border-top: 0; padding-top: 0; }
.acct-sec h2 { font-size: 1.02rem; font-weight: 700; margin-bottom: .25rem; }
.acct-sec > p { font-size: .94rem; color: var(--slate); max-width: 54ch; margin-bottom: 1.2rem; }

.af { margin-bottom: 1.15rem; }
.af label { display: block; font-size: .92rem; font-weight: 600; margin-bottom: .35rem; }
.af input, .af select {
  width: 100%; max-width: 420px; border: 1px solid var(--hair); border-radius: 11px;
  padding: .7rem .85rem; font-family: inherit; font-size: 1rem; background: var(--wash);
}
.af input:focus, .af select:focus { outline: 0; border-color: var(--blue); background: #fff; }
.af .note { display: block; font-size: .87rem; color: var(--slate); margin-top: .35rem; max-width: 52ch; }
.af-optional { font-weight: 400; color: var(--slate); }
.af-error { display: block; font-size: .87rem; color: var(--orange); font-weight: 600; margin-top: .35rem; }
.af-row { display: flex; gap: .9rem; flex-wrap: wrap; }
.af-row .af { flex: 1; min-width: 150px; margin-bottom: 1.15rem; }
.af-row .af input, .af-row .af select { max-width: none; }

/* Prompt 113 item 7: the account-creation consent checkbox -- a plain
   flex row, not the generic .af label's block layout above (that one is
   built for a text input's own label, not a checkbox sitting beside its
   own sentence). */
.af-consent { margin-bottom: 1.4rem; }
.af-checkbox { display: flex; align-items: flex-start; gap: .6rem; font-size: .92rem; font-weight: 400; cursor: pointer; }
.af-checkbox input[type="checkbox"] { margin-top: .2rem; flex-shrink: 0; width: 1.05rem; height: 1.05rem; }
.af-checkbox span { color: var(--ink); }
.af-checkbox a { color: var(--blue); }

.acct-switch { margin-top: 1.6rem; font-size: .95rem; color: var(--slate); }
.acct-switch a { color: var(--deep); font-weight: 600; text-decoration: none; }
.acct-switch a:hover { text-decoration: underline; }

/* The signed-in strip in the header: who you are, and the way out. */
.session-bar {
  display: flex; align-items: center; justify-content: flex-end; gap: 1rem;
  font-size: .88rem; color: var(--slate); padding: .5rem 0 0;
}
.session-bar form { display: inline; margin: 0; }
.session-bar button, .session-bar a {
  background: none; border: 0; color: var(--deep); font-family: inherit;
  font-size: .88rem; font-weight: 600; padding: 0; cursor: pointer; text-decoration: none;
}
.session-bar button:hover, .session-bar a:hover { text-decoration: underline; }

/* A stored run re-rendered under a schema or engine it was not computed
   under -- disclosed, never silently recomputed. */
.run-provenance {
  background: #FDF7EC; border-radius: 12px; padding: 1rem 1.2rem;
  margin: 1.2rem 0; font-size: .92rem; color: #8A6410; max-width: 62ch;
}

/* Prompt 113 item 6: the "while we read your statement" progress screen.
   A plain checklist -- pending / active (spinning) / done (checked) --
   never a percentage or a bar. static/js/progress.js only ever toggles
   .active/.done; every visual state below is driven by those two classes
   alone, so a styling rule here can never double as the JS selector
   (review.html's own standing rule, applied here too). */
.progress-stages {
  list-style: none; margin: 2rem 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 1.1rem;
}
.progress-stages .stage {
  display: flex; align-items: center; gap: .9rem;
  font-size: 1.05rem; color: var(--slate);
}
.progress-stages .stage.active { color: var(--ink); font-weight: 600; }
.progress-stages .stage.done { color: var(--slate); }
.stage-icon {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  border: 2px solid var(--hair); box-sizing: border-box; position: relative;
}
.stage.active .stage-icon {
  border-color: var(--blue); border-top-color: transparent;
  animation: cca-spin .8s linear infinite;
}
.stage.done .stage-icon {
  border-color: var(--green); background: var(--green);
}
.stage.done .stage-icon::after {
  content: ""; position: absolute; left: 7px; top: 3px;
  width: 6px; height: 11px; border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
@media (prefers-reduced-motion: reduce) {
  .stage.active .stage-icon { animation: none; border-color: var(--blue); }
}
.progress-note {
  margin-top: 2rem; min-height: 2.6em; color: var(--slate); font-size: .95rem;
  max-width: 52ch; border-left: 3px solid var(--yellow); padding-left: 1rem;
}
