/* == GridReady client portal - component CSS ==========================
   Layout and component rules for the public client portal: header, rail,
   screen form, readiness readout, sub-scores, next-best-action, curated
   sites, deep-dossier view and the feedback card. Tokens (the Spruce
   colour/type/spacing foundation) and the base reset live in
   ui/shared/tokens.css, linked alongside this file, not here. Lifted from
   design/pages/client.html (already IP-safe) and extended for the working
   app: dynamic bar/needle widths are never set here as a fixed value,
   client.js sets them via the CSSOM (element.style.width/left) once the
   score is known, so a strict style-src 'self' CSP never needs an inline
   style attribute. */

a{color:var(--accent)}

/* -- header -------------------------------------------------------- */
header{position:sticky;top:0;z-index:20;background:var(--bg);border-bottom:1px solid var(--border)}
.hbar{max-width:1200px;margin:0 auto;padding:var(--s4) var(--s5);display:flex;align-items:center;gap:var(--s4);flex-wrap:wrap}
.brand{display:flex;align-items:baseline;gap:var(--s3)}
.wordmark{font-family:var(--font-display);font-weight:700;font-size:var(--fs-md);letter-spacing:-.03em}
.wordmark b{color:var(--accent)}
.eyebrow{font-family:var(--font-mono);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.18em;color:var(--muted)}
.hmeta{margin-left:auto;display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
.chips{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
.chip{font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--muted);border:1px solid var(--border-strong);
  border-radius:var(--r-pill);padding:5px 11px;white-space:nowrap}
.chip b{color:var(--text);font-weight:600}
.chip.state{color:var(--accent-deep);background:var(--accent-tint);border-color:var(--accent-subtle);text-transform:uppercase;letter-spacing:.1em}
.mode{cursor:pointer;background:none;color:var(--muted);border:1px solid var(--border-control);border-radius:var(--r-pill);
  padding:6px 12px;font-family:var(--font-mono);font-size:var(--fs-xs);letter-spacing:.06em;min-height:40px;
  display:inline-flex;align-items:center;gap:7px}
.mode:hover{border-color:var(--accent);color:var(--text)}
.mode svg{width:15px;height:15px}

/* -- layout ---------------------------------------------------------- */
.wrap{max-width:1200px;margin:0 auto;padding:var(--s6) var(--s5) var(--s9)}
.grid{display:grid;grid-template-columns:340px 1fr;gap:var(--s6);align-items:start}
@media(max-width:900px){.grid{grid-template-columns:1fr}}
.rail{display:flex;flex-direction:column;gap:var(--s4);position:sticky;top:88px}
@media(max-width:900px){.rail{position:static}}
/* surface: paper. Flat, no fill, no shadow: a hairline top rule stands in
   for the card border everywhere a card would otherwise sit. */
.panel{background:none;border:0;border-top:1px solid var(--border-strong);border-radius:0;padding:var(--s5) 0}
.panel h2{font-family:var(--font-mono);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.16em;color:var(--muted);font-weight:500;margin:0 0 var(--s4)}
label.f{display:block;font-size:var(--fs-sm);color:var(--muted);margin:var(--s3) 0 6px}
input,select{width:100%;background:var(--bg);color:var(--text);border:1px solid var(--border-control);border-radius:var(--r-sm);
  padding:10px 12px;font-family:var(--font-body);font-size:var(--fs-sm);min-height:44px}
input:focus,select:focus{outline:2px solid var(--accent);outline-offset:1px;
  border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-tint)}
.row2{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3)}
/* field wrapper: a flex column so a wrapping label pushes its input down
   without disturbing the row2 sibling. .row2 is a grid, whose items
   stretch to equal height by default, so when one label wraps to a second
   line the taller .fld stretches its sibling to match; margin-top:auto on
   the input/select then pins it to the wrapper's bottom edge, so the two
   inputs in a row still line up even though the labels do not. */
.fld{display:flex;flex-direction:column;min-width:0}
.fld input,.fld select{margin-top:auto}
/* narrow phones: two 1fr columns in .row2 leave roughly 180px per field
   right at this width (2x180 plus the row gap plus the wrap's two side
   paddings: 2*180 + var(--s3) 12px + 2*var(--s5) 24px = 420px), too tight
   for a select's chevron and label to sit comfortably, so collapse to
   one column and give the content a little of the wrap's padding back. */
@media(max-width:420px){
  .wrap{padding-left:var(--s4);padding-right:var(--s4)}
  .row2{grid-template-columns:1fr}
}
.btn{margin-top:var(--s4);width:100%;border:none;border-radius:var(--r-pill);cursor:pointer;background:var(--accent);
  color:var(--on-accent);font-family:var(--font-body);font-weight:600;font-size:var(--fs-sm);padding:12px;min-height:44px}
.btn:hover{background:var(--accent-deep)}
.btn[disabled]{opacity:.6;cursor:progress}
.hint{font-size:var(--fs-xs);color:var(--muted);margin-top:var(--s3);line-height:1.5}
.sec-h{font-family:var(--font-mono);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.14em;color:var(--muted);margin:var(--s5) 0 var(--s2)}
.section{border-top:1px solid var(--border);padding-top:var(--s3);margin-top:var(--s4)}
/* required-field marker: decorative only (aria-hidden), so a screen reader
   never hears "asterisk" -- the requirement itself rides on the input's own
   required attribute, which is what actually reaches the accessible name. */
.req{color:var(--secondary);font-weight:700;margin-left:1px}
.legend{display:flex;font-size:var(--fs-xs);color:var(--muted);line-height:1.5;margin:0 0 var(--s4);padding:8px 10px;background:var(--secondary-tint);border-radius:var(--r-sm)}
.legend .req{margin:0}

/* -- content head ------------------------------------------------- */
.content{min-width:0}
.sitebar{display:flex;align-items:baseline;gap:var(--s3);flex-wrap:wrap}
.sitebar h1{font-family:var(--font-display);font-weight:600;font-size:var(--fs-2xl);letter-spacing:-.02em;margin:0}
.loc{font-family:var(--font-mono);font-size:var(--fs-sm);color:var(--muted)}
.runline{font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--muted);margin-top:6px}
.runline b{color:var(--text);font-weight:500}

/* -- tabs (readiness / evidence and memo, shown once a deep run is done) */
.tabs{display:flex;gap:var(--s5);border-bottom:1px solid var(--border);margin:var(--s5) 0 var(--s6);flex-wrap:wrap}
.tab{background:none;border:none;cursor:pointer;color:var(--muted);font-family:var(--font-body);font-weight:600;
  font-size:var(--fs-sm);padding:10px 0;position:relative;min-height:44px}
.tab:hover{color:var(--text)}
.tab.on{color:var(--text)}
.tab.on::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--accent)}
.view{display:none}
.view.on{display:block}

/* -- readiness readout: the mockup's two-column hero card wins over the
   option-A headline-first layout it briefly shipped as (Jan's decision,
   26 Jul 2026). The score numeral leads at page scale in its own left
   cell; verdict, scale and stats sit in the right cell. Values below are
   copied verbatim from design/pages/client.html lines 98-116, not
   invented near-misses; colours resolve through the shared tokens, so
   the mockup's own stale inline palette never leaks in here. Continuous
   scale throughout: no numeric band cut-offs anywhere below. ---------- */
.readout{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);box-shadow:var(--shadow);
  padding:var(--s7);margin-top:var(--s5);display:grid;grid-template-columns:auto 1fr;gap:var(--s7);align-items:center}
@media(max-width:720px){.readout{grid-template-columns:1fr;gap:var(--s5);padding:var(--s5)}}
.score{font-family:var(--font-display);font-weight:600;font-size:7.5rem;line-height:.84;letter-spacing:-.045em;font-variant-numeric:tabular-nums}
.scoreof{font-family:var(--font-mono);font-size:var(--fs-sm);color:var(--muted);margin-top:var(--s2)}
.bandtag{display:inline-flex;align-items:center;gap:8px;margin-top:var(--s4);font-family:var(--font-mono);font-size:var(--fs-xs);
  text-transform:uppercase;letter-spacing:.12em;color:var(--accent-deep);background:var(--accent-tint);
  border:1px solid var(--accent-subtle);border-radius:var(--r-pill);padding:6px 13px;white-space:nowrap}
.verdict{font-size:var(--fs-md);line-height:1.4;max-width:36ch;margin:0 0 var(--s5)}
.scalerow{position:relative}
.scale-continuous{height:13px;border-radius:var(--r-pill);border:1px solid var(--border);
  background:linear-gradient(90deg,var(--seq1),var(--seq2),var(--seq3),var(--seq4),var(--seq5))}
.needle{position:absolute;top:-5px;bottom:-5px;width:2px;background:var(--text);border-radius:2px;left:0;transition:left 1.1s cubic-bezier(.2,.7,.2,1)}
.needle::after{content:"";position:absolute;left:-3px;top:-3px;width:8px;height:8px;border-radius:50%;background:var(--text)}
.scaleends{display:flex;justify-content:space-between;margin-top:9px;font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--muted)}
.stats{display:flex;gap:var(--s7);margin-top:var(--s5)}
.stat .sl{font-family:var(--font-mono);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.14em;color:var(--muted)}
.stat .sv{font-family:var(--font-display);font-weight:600;font-size:var(--fs-lg);font-variant-numeric:tabular-nums;margin-top:3px}

/* -- sub-scores, client variant: no weight chip, no contribution ---- */
.subs{margin-top:var(--s7)}
/* m9: this was a <div class="h">, invisible to heading navigation; a
   screen-reader user reached "Next best action" (an <h2 class="sec-h">
   below) but never this section. Now an <h2 class="sec-h"> too, with its
   top margin zeroed here since .subs already supplies the space above it. */
.subs>.sec-h{margin-top:0}
.sub{padding:var(--s4) 0;border-top:1px solid var(--border)}
.sub .top{display:flex;align-items:baseline;gap:var(--s3)}
.sub .nm{font-weight:600}
/* lever-ico: decorative glyph beside a criterion's name, rendered by the
   custom element in ui/shared/lever-icons.js. The element carries no
   style of its own (a script-injected <style> would be silently dropped
   by the style-src 'self' CSP on public pages), so its geometry lives
   here instead. */
lever-ico{display:inline-flex;align-items:center;justify-content:center;color:var(--accent);vertical-align:-.16em;margin-right:.42em;flex:none}
lever-ico svg{width:1.05em;height:1.05em;display:block}
.sub .val{margin-left:auto;font-family:var(--font-display);font-weight:600;font-size:var(--fs-lg);font-variant-numeric:tabular-nums}
.sub .val.unknown{font-family:var(--font-mono);font-size:var(--fs-sm);color:var(--muted);font-weight:400;text-transform:uppercase;letter-spacing:.06em}
.sbar{height:6px;background:var(--border);border-radius:var(--r-pill);margin-top:var(--s3);overflow:hidden}
.sbar>i{display:block;height:100%;background:var(--seq3);border-radius:var(--r-pill);width:0;transition:width .9s cubic-bezier(.2,.7,.2,1)}
.sbar.unknown{background:repeating-linear-gradient(90deg,var(--border) 0 7px,transparent 7px 14px)}
.sub .meta{display:flex;align-items:center;gap:var(--s3);margin-top:var(--s3);flex-wrap:wrap}
.conf{font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--muted)}
.conf b{color:var(--text);font-weight:600}
/* .why: a per-criterion reason sentence. Rendered only for the unknown
   case (subRowHtml in client.js), from a static per-criterion sentence
   (_WHY_UNKNOWN), never assembled from a specific dossier's inputs list.
   The sentence differs by criterion because the cause differs: grid
   feasibility has no public declaration path at all, so its unknown is
   always a data gap, while land control and permit pathway are
   declaration-only, so "not declared" is genuinely their only cause. There
   is no reason field on a scored sub-score, so nothing here is ever
   synthesised for a known one either. */
.why{margin:var(--s3) 0 0;font-size:var(--fs-sm);color:var(--muted);line-height:1.5;max-width:72ch}
.whylink{font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--accent);text-decoration:none;
  border-bottom:1px solid var(--accent-subtle);white-space:nowrap}
.whylink:hover{border-bottom-color:var(--accent)}

/* -- next-best-action ledger: its own section below Sub-scores, a row
   per suggested action -- an index marker, the action text, and an
   availability badge only. No estimated delta and no price ever appear
   here, in either portal: that numeric detail stays server-side.
   Structure and values lifted from design/pages/client.html, where the
   page mockup's flat DOM (idx and act as siblings, not idx nested
   inside act) is the shape components/nba.html's own markup agrees
   with. -------------------------------------------------------------- */
.nba-list{border-top:1px solid var(--border);margin-top:var(--s3)}
.nba-row{display:flex;align-items:baseline;gap:var(--s3);border-bottom:1px solid var(--border);padding:var(--s3) 0}
.nba-row:last-child{border-bottom:0;padding-bottom:0}
.act{flex:1 1 auto;min-width:0;font-size:var(--fs-sm);color:var(--text)}
.nba-row .idx{font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--muted);flex:none;min-width:1.7em}
.nba-row.ok .idx{color:var(--success)}
.avail{margin-left:auto;flex:none;display:inline-flex;align-items:center;gap:7px;font-size:var(--fs-sm);white-space:nowrap}
.avail .mk{width:8px;height:8px;border-radius:50%;flex:none}
.avail.ok{color:var(--text)}.avail.ok .mk{background:var(--success)}
/* m10: --border-strong is 1.44:1 on light, well under the 3:1 WCAG 1.4.11
   floor for a control boundary that carries state (test_a11y_tokens.py);
   --border-control exists for exactly this and clears 3.07:1+ in both modes. */
.avail.na{color:var(--muted)}.avail.na .mk{background:transparent;box-shadow:inset 0 0 0 1.5px var(--border-control)}
.pill{font-family:var(--font-mono);font-size:var(--fs-xs);letter-spacing:.08em;text-transform:uppercase;padding:3px 9px;border-radius:var(--r-pill);display:inline-flex;align-items:center;gap:5px}
.pill.ok{color:var(--success);border:1px solid var(--success)}
.pill.unknown{color:var(--warning);border:1px solid var(--warning)}
.pill.na{color:var(--muted);border:1px solid var(--border-control)}

/* -- trust strip: attribution, reassurance, rubric+hash -------------- */
.attrib{margin-top:var(--s6);font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--muted);line-height:1.7}
.glass-intro{color:var(--muted);font-size:var(--fs-sm);line-height:1.6;max-width:66ch;margin:var(--s3) 0 0}
.glass-intro b{color:var(--text)}
.rubricline{font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--muted);margin-top:var(--s2)}
.rubricline b{color:var(--text)}

/* -- method disclosure: collapsed by default, holds the rubric hash and
   the engine/model detail. Jan's decision, 26 Jul 2026, overrides the
   design mockup, which put the attribution and the honesty paragraph
   above inside this same disclosure: those stay always visible, only the
   hash and the engine line collapse here. A <details> element is
   keyboard-accessible on its own (Enter/Space toggles a focused summary),
   so this adds no click handler and no button.
   The summary carries class="sec-h" for the same mono-cap heading
   treatment as the page's other section headings; the mockup reached for
   an inline style="margin:0" to win the resulting margin conflict, which
   is blocked outright under this page's style-src 'self'. No inline style
   is needed: .disclose>summary (one class plus one type selector) already
   outranks the plain .sec-h rule (one class alone) by specificity, so its
   margin:0 wins on its own. */
.disclose{margin-top:var(--s5)}
.disclose>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:9px;margin:0;padding:var(--s2) 0;min-height:44px}
.disclose>summary::-webkit-details-marker{display:none}
.disclose>summary:hover{color:var(--text)}
.disclose .caret{width:0;height:0;border-left:5px solid currentColor;border-top:4px solid transparent;
  border-bottom:4px solid transparent;transition:transform .15s ease}
.disclose[open] .caret{transform:rotate(90deg)}
.disclose-body{padding-top:var(--s2)}
.hashbox{background:var(--bg);border:1px solid var(--border);border-radius:var(--r-md);padding:var(--s4) var(--s5);
  font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--muted);line-height:1.9;max-width:76ch}
.hashbox b{color:var(--text)}

/* -- curated-sites strip ---------------------------------------------- */
.stripwrap{margin-top:var(--s8)}
.strip{display:flex;gap:var(--s4);flex-wrap:wrap;margin-top:var(--s3)}
.stripitem{position:relative;flex:1 1 220px;display:flex;align-items:center;gap:var(--s3);text-align:left;cursor:pointer;background:none;
  border:0;border-top:1px solid var(--border-strong);border-radius:0;padding:var(--s4) 0;color:var(--text)}
.stripitem:hover{color:var(--accent)}
/* selected: colour alone is not the cue (a hover would look identical). A
   top rule, positioned over the existing border rather than widening it
   (no layout shift, same discipline as .tab.on::after above), plus a
   bold title, so the state reads without relying on colour perception. */
.stripitem.on{background:none;color:var(--accent)}
.stripitem.on::before{content:"";position:absolute;left:0;right:0;top:-1px;height:2px;background:var(--accent)}
.stripitem.on .pt{font-weight:700}
.stripitem .bl{font-family:var(--font-display);font-weight:700;font-size:var(--fs-lg);line-height:1;width:26px;text-align:center;color:var(--accent);flex:none}
.stripitem .pt{font-size:var(--fs-sm);font-weight:600;display:block}
.stripitem .ps{font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--muted)}

/* -- deep-dossier view: verbatim claims, memo, countersign ----------- */
.claim{border-left:2px solid var(--accent-subtle);padding:8px 12px;margin:10px 0}
.claim .span{font-style:italic;color:var(--muted);display:block;margin:4px 0;quotes:'\201C' '\201D'}
.claim .span:before{content:open-quote}
.claim .span:after{content:close-quote}
.muted{color:var(--muted);font-size:var(--fs-sm)}
.cite{font-family:var(--font-mono);font-size:.72rem;color:var(--accent);white-space:nowrap}
.memo{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--s6);max-width:760px;margin-top:var(--s5)}
.memo-md h3{margin:14px 0 6px}
.memo-md h4{margin:10px 0 4px}
.memo-md p{margin:6px 0;color:var(--text)}
.runbadge{display:inline-block;font-family:var(--font-mono);font-size:.7rem;padding:2px 10px;border:1px solid var(--accent-subtle);border-radius:var(--r-pill);background:var(--accent-tint);margin:0 0 var(--s4)}
.prov{margin-top:var(--s3);padding-top:var(--s3);border-top:1px solid var(--border);font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--muted);line-height:1.65}
/* countersign: the human review outcome. A distinct class from the
   next-best-action ledger rows above, so the two never share a
   selector: this block stacks its lines, a ledger row stays a flex
   line. */
.countersign{display:flex;flex-direction:column;gap:2px;font-size:var(--fs-sm);color:var(--text);
  background:var(--accent-tint);border:1px solid var(--accent-subtle);border-left:3px solid var(--accent);
  border-radius:var(--r-sm);padding:9px 12px;margin-top:var(--s3)}
.countersign.returned{background:var(--secondary-tint);border-color:var(--secondary);border-left-color:var(--secondary)}
.stageflow{display:flex;gap:var(--s2);flex-wrap:wrap;margin-top:var(--s5)}
.stg{font-family:var(--font-mono);font-size:var(--fs-xs);padding:7px 11px;border-radius:var(--r-sm);border:1px solid var(--border);color:var(--muted)}
.stg.done{color:var(--on-accent);background:var(--accent);border-color:var(--accent)}
.stg.next{color:var(--text);border-color:var(--border-strong)}

/* -- loading / error states ------------------------------------------ */
.loading{display:flex;align-items:center;gap:var(--s3);color:var(--muted);font-family:var(--font-mono);font-size:var(--fs-sm);padding:var(--s6) 0}
.spin{width:16px;height:16px;border:2px solid var(--border-strong);border-top-color:var(--accent);border-radius:50%;animation:sp .7s linear infinite}
@keyframes sp{to{transform:rotate(360deg)}}
.errbox{background:var(--surface);border:1px solid var(--error);color:var(--text);border-radius:var(--r-md);padding:var(--s4) var(--s5);font-size:var(--fs-sm);font-family:var(--font-mono);margin-top:var(--s3)}

/* -- feedback card ----------------------------------------------------- */
.fbpanel{background:none;border:0;border-top:1px solid var(--border-strong);border-radius:0;padding:var(--s5) 0;max-width:420px;margin-top:var(--s6)}
.fbpanel h2{font-family:var(--font-mono);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.16em;color:var(--muted);font-weight:500;margin:0 0 var(--s4)}
textarea{width:100%;background:var(--bg);color:var(--text);border:1px solid var(--border-control);border-radius:var(--r-sm);
  padding:10px 12px;font-family:var(--font-body);font-size:var(--fs-sm);min-height:88px;resize:vertical;line-height:1.5}
textarea:focus{outline:2px solid var(--accent);outline-offset:1px;
  border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-tint)}
.stars{display:flex;gap:6px;margin:2px 0 var(--s2)}
.star{width:28px;height:28px;padding:0;background:none;border:none;cursor:pointer;color:var(--border-control)}
.star svg{width:100%;height:100%;display:block}
.star .ic-filled{display:none}
.star.on{color:var(--secondary)}
.star.on .ic-filled{display:block}
.star.on .ic-outline{display:none}
.consent{display:flex;align-items:flex-start;gap:9px;margin-top:var(--s4)}
.consent input{width:auto;min-height:auto;margin-top:3px;accent-color:var(--accent)}
.consent label{font-size:var(--fs-xs);color:var(--muted);line-height:1.5}

/* -- privacy notice page (see ui/privacy.html) ------------------------ */
.privacy,.about{max-width:46rem;margin:0 auto;padding:var(--s7) var(--s5) var(--s9)}
.privacy h1,.about h1{font-family:var(--font-display);font-weight:600;font-size:var(--fs-2xl);letter-spacing:-.02em;margin:0 0 var(--s2)}
.privacy h2,.about h2{font-family:var(--font-display);font-weight:600;font-size:var(--fs-md);margin:var(--s6) 0 var(--s2);color:var(--accent)}
.privacy h3,.about h3{font-family:var(--font-display);font-weight:600;font-size:var(--fs-base);margin:var(--s5) 0 var(--s1)}
.privacy p,.about p{margin:var(--s2) 0}
.privacy .lead,.about .lead{color:var(--muted)}
.privacy footer,.about footer{margin-top:var(--s7);border-top:1px solid var(--border);padding-top:var(--s4);color:var(--muted);font-size:var(--fs-sm)}

/* Visually hidden, still read aloud. Two uses: the one-line live region (the
   result container is repainted wholesale, and a role="status" on it would
   announce the entire dossier as one utterance, since role="status" implies
   aria-atomic="true"), and the state word on each deep-run stage chip, whose
   state was otherwise carried by fill colour alone. */
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
