/* Shared styles for the self-serve scanner (scan.html).

   Sept 2026: the confirm/test/report flow (step-flow, "ss-" prefixed
   classes below) was rebuilt to match the "InView Scan Flow" design
   handoff (design_handoff_scan_flow/) pixel-for-pixel — a persistent
   split shell (fixed left context panel + single-focus right pane),
   its own colour/type/spacing tokens (--ss-*, copied verbatim from that
   handoff's DESIGN_SYSTEM.md), replacing the previous scan-split,
   scan-journey, scan-phase, scan-platform, and scan-analyse layout
   classes. step-url, step-manual-info and step-failed are untouched —
   not part of that redesign — and keep using the original tokens
   below. */

:root {
  --paper: #F7F6F2;
  --surface: #FFFFFF;
  --surface-2: #F0EFE9;
  --citron: #C3ED55;
  --citron-soft: #EAF7C9;
  --citron-text: #67722E;
  --teal: #2F8E97;
  --teal-text: #25717A;
  --ink-950: #0C0E10;
  --ink: #16181A;
  --ink-body: #3D423D;
  --ink-soft: #4E544E;
  --ink-faint: #666B63;
  --warn-text: #8D5E14;
  --alert: #C24A2E;
  --line: #E2E0D8;
  --line-strong: #CFCCC1;

  --font-display: 'Space Grotesk', sans-serif;
  --font-text: 'Instrument Sans', sans-serif;
  --font-mono: 'JetBrains Mono', monospace;

  /* ---- "ss-" design tokens — InView Scan Flow handoff, authoritative
     from design_handoff_scan_flow/DESIGN_SYSTEM.md. Scoped to the new
     step-flow shell only; the rest of this file is untouched. ---- */
  --ss-paper: #FAFAF9;
  --ss-paper-2: #F4F4F1;
  --ss-line: #E4E4DE;
  --ss-line-pending: #D8D8D1;
  --ss-ink: #141719;
  --ss-ink-soft: #5C625C;
  --ss-muted: #6F776F;
  --ss-disabled: #9A988B;
  --ss-disabled-2: #B4B2A8;
  --ss-citron: #C3ED55;
  --ss-citron-hover: #D3F27E;
  --ss-citron-print: #A8D63A;
  --ss-citron-on: #0B1004;
  --ss-chip-wash: #EFF7DC;
  --ss-chip-text: #4F5A22;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: var(--paper);
  color: var(--ink-body);
  font-family: var(--font-text);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--teal-text); text-decoration: none; }
a:hover { text-decoration: underline; }

.scan-container {
  max-width: 640px;
  margin: 0 auto;
  padding: 0 24px 96px;
}
/* Full-width shell for the redesigned confirm/test/report flow — the
   ss-shell below draws its own edges, so no extra side padding here. */
.scan-container.is-flow { max-width: 1180px; padding: 0 24px 96px; }

.scan-nav {
  padding: 28px 0;
}
.scan-nav a.back {
  font-family: var(--font-text);
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-soft);
}

.scan-header {
  text-align: center;
  margin-bottom: 40px;
}
.scan-header h1 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 38px;
  letter-spacing: -0.025em;
  line-height: 1.08;
  color: var(--ink);
  margin-bottom: 12px;
}
.scan-header p {
  color: var(--ink-soft);
  font-size: 17px;
  max-width: 44ch;
  margin: 0 auto;
}
@media (max-width: 640px) {
  .scan-header h1 { font-size: 28px; }
  .scan-header p { font-size: 15.5px; }
}

/* ===== Step reveal ===== */
@media (prefers-reduced-motion: no-preference) {
  .scan-step {
    animation: scan-step-in 480ms cubic-bezier(.2,.8,.2,1);
  }
  @keyframes scan-step-in {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
  }
}

.scan-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 36px;
  margin-bottom: 24px;
}
@media (max-width: 640px) { .scan-card { padding: 24px 20px; } }

/* The redesigned flow draws its own shell (ss-shell) — strip the
   generic card treatment so it isn't double-boxed. */
.scan-card.ss-flow-card { border: none; background: transparent; padding: 0; margin-bottom: 0; text-align: left; }

.scan-field { margin-bottom: 18px; }
.scan-field:last-child { margin-bottom: 0; }
.scan-field label {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 8px;
}
.scan-field input,
.scan-field textarea {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 12px 14px;
  color: var(--ink);
  font-family: var(--font-text);
  font-size: 16px; /* >=16px: stops iOS Safari zooming the page on focus */
}
.scan-field input { height: 46px; }
.scan-field textarea { min-height: 90px; resize: vertical; line-height: 1.5; }
.scan-field input:focus,
.scan-field textarea:focus {
  outline: none;
  border-color: var(--citron-text);
}
.scan-field .hint {
  font-size: 12.5px;
  color: var(--ink-faint);
  margin-top: 6px;
}

.scan-btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  height: 54px;
  background: var(--citron);
  color: var(--ink-950);
  font-family: var(--font-text);
  font-weight: 600;
  font-size: 15.5px;
  border-radius: 8px;
  border: none;
  cursor: pointer;
  transition: filter 0.12s ease, transform 0.12s ease;
}
.scan-btn-primary:disabled { opacity: 0.55; cursor: not-allowed; }
.scan-btn-primary:hover:not(:disabled) { filter: brightness(0.97); }
.scan-btn-primary:active:not(:disabled) { transform: scale(0.99); }

.scan-btn-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 48px;
  background: transparent;
  color: var(--ink-soft);
  font-family: var(--font-text);
  font-weight: 600;
  font-size: 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
  margin-top: 10px;
}
.scan-btn-secondary:hover { border-color: var(--line-strong); }

.scan-btn-text {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: none;
  padding: 0;
  font-family: var(--font-text);
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--line-strong);
  padding-bottom: 2px;
  cursor: pointer;
}
.scan-btn-text:hover { color: var(--ink); border-color: var(--ink-soft); }

.scan-badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--citron-text);
  background: rgba(195, 237, 85, 0.16);
  border-radius: 4px;
  padding: 4px 9px;
  margin-bottom: 14px;
}

.scan-error {
  background: rgba(194, 74, 46, 0.08);
  border: 1px solid rgba(194, 74, 46, 0.25);
  color: var(--alert);
  border-radius: 6px;
  padding: 14px 16px;
  font-size: 14px;
  margin-bottom: 18px;
}

.scan-note {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--ink-soft);
  border-radius: 6px;
  padding: 14px 16px;
  font-size: 13.5px;
  line-height: 1.6;
}
.scan-note-alert {
  background: rgba(194, 74, 46, 0.06);
  border-color: rgba(194, 74, 46, 0.2);
}

.scan-hidden { display: none !important; }

/* ===== Manual-info fallback headline/subcopy (still used there only) ===== */
.confirm-headline {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 32px;
  color: var(--ink);
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-bottom: 10px;
}
.confirm-subcopy {
  font-size: 15.5px;
  color: var(--ink-soft);
  line-height: 1.5;
  max-width: 48ch;
  margin-bottom: 28px;
}
.scan-edit-toggle-row { text-align: center; margin-top: 14px; }

/* ===== Rate-limit state — reused inside the new Confirm screen (ss-)
   below, and (by the same markup pattern) available anywhere else in
   this file. A temporary product constraint, not an error: no red box,
   no disabled button repeating the same message. ===== */
.confirm-rate-limit {
  text-align: center;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 22px 20px;
}
.confirm-rate-limit-timer {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 17px;
  color: var(--ink);
  margin-bottom: 6px;
}
.confirm-rate-limit-copy {
  font-size: 14px;
  color: var(--ink-soft);
  line-height: 1.5;
}
/* Inside the new left-aligned Confirm screen, not centered. */
.ss-screen .confirm-rate-limit { text-align: left; }

/* =====================================================================
   Redesigned scan flow shell ("ss-" prefix) — InView Scan Flow handoff.
   Persistent left context panel + single-focus right pane, one step
   visible at a time (Understand / Confirm / Test / Your report), thin
   progress bar across the top of the right pane. Every dynamic value
   is driven by scan.js from real state: extraction output, /api/scan/
   status polling, or the report-readiness gate's status="complete" —
   never a timer standing in for backend progress, never a number this
   app hasn't actually computed.
   ===================================================================== */

.ss-shell {
  display: grid;
  grid-template-columns: 440px 1fr;
  min-height: 620px;
  background: var(--ss-paper);
  border: 1px solid var(--ss-line);
  border-radius: 8px;
  overflow: hidden;
}
@media (max-width: 1024px) {
  .ss-shell { display: flex; flex-direction: column; min-height: 0; }
}

/* ---- Left panel: pure brand atmosphere. No page copy lives here any
   more — it's been consolidated into the right pane's own screens (see
   the Understand/Confirm markup) so it's said once, where it's
   genuinely new, rather than repeated on every screen. Dark ground +
   one large centred mark is the entire content, throughout Understand/
   Confirm/Analysis alike. ---- */
.ss-left {
  background: var(--ink-950);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
}
@media (max-width: 1024px) {
  .ss-left { padding: 28px 24px; }
}

.ss-brand-large { display: flex; flex-direction: column; align-items: center; gap: 26px; }
.ss-brand-word-large { font-family: var(--font-display); font-weight: 500; font-size: 28px; letter-spacing: -0.02em; color: var(--ss-paper); }
@media (max-width: 1024px) { .ss-brand-word-large { font-size: 20px; } }

/* Persistent animated brand mark — a ring with a citron dot wandering
   inside it (v3-final's "InView Loading Screen" component, scaled up
   from its original 320px splash size to a 300px mark that dominates
   this panel; motion values scaled by the same ratio: ring radius
   146->137, stroke 26->24, dot 44->41, bounce amplitude 76->71). Two
   independent-period bounces (2.6s on X, 1.7s on Y) compose into a
   wandering, non-repeating-looking path rather than a simple back-and-
   forth — purely decorative, real state is never carried by this mark. */
.ss-brand-mark { position: relative; width: 300px; height: 300px; flex: none; display: flex; align-items: center; justify-content: center; }
.ss-brand-mark svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.ss-brand-mark-x { display: flex; align-items: center; justify-content: center; }
.ss-brand-mark-y { display: flex; align-items: center; justify-content: center; }
.ss-brand-mark-dot { width: 41px; height: 41px; border-radius: 999px; background: var(--ss-citron-print); }
@media (prefers-reduced-motion: no-preference) {
  .ss-brand-mark-x { animation: ss-brand-bx 2.6s cubic-bezier(.42,0,.58,1) infinite alternate; }
  .ss-brand-mark-y { animation: ss-brand-by 1.7s cubic-bezier(.42,0,.58,1) infinite alternate; }
}
@keyframes ss-brand-bx { from { transform: translateX(-71px); } to { transform: translateX(71px); } }
@keyframes ss-brand-by { from { transform: translateY(-71px); } to { transform: translateY(71px); } }
@media (max-width: 1024px) {
  .ss-brand-mark { width: 100px; height: 100px; }
  .ss-brand-mark-dot { width: 14px; height: 14px; }
  @keyframes ss-brand-bx { from { transform: translateX(-24px); } to { transform: translateX(24px); } }
  @keyframes ss-brand-by { from { transform: translateY(-24px); } to { transform: translateY(24px); } }
}

/* Domain fact on Confirm — the one screen where it's genuinely
   decision-relevant (was previously shown persistently in the left
   panel's domain card). */
.ss-confirm-domain { font-family: var(--font-mono); font-size: 13px; color: var(--ss-muted); }

/* ---- Right pane ---- */
.ss-right { position: relative; display: flex; flex-direction: column; min-width: 0; }

.ss-content { padding: 88px 72px 56px; max-width: 820px; }
@media (max-width: 1024px) { .ss-content { padding: 32px 24px 40px; } }

.ss-screen { display: flex; flex-direction: column; gap: 34px; }
@media (prefers-reduced-motion: no-preference) {
  .ss-screen:not(.scan-hidden) { animation: ss-screen-in 400ms cubic-bezier(.2,.8,.2,1) both; }
  @keyframes ss-screen-in {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
  }
}

.ss-screen-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; }
.ss-screen-head-text, .ss-screen-head-stack { display: flex; flex-direction: column; gap: 10px; }
.ss-eyebrow { font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.14em; color: var(--ss-muted); }
.ss-h2 { font-family: var(--font-display); font-weight: 500; font-size: 34px; line-height: 1.1; letter-spacing: -0.03em; color: var(--ss-ink); }
@media (max-width: 640px) { .ss-h2 { font-size: 26px; } }
.ss-sub { font-size: 17px; color: var(--ss-ink-soft); }

.ss-chip {
  flex: none; display: inline-flex; align-items: center; gap: 7px; height: 28px; padding: 0 11px;
  border-radius: 999px; font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.12em;
  font-variant-numeric: tabular-nums;
}
.ss-chip-neutral { align-self: flex-start; background: var(--ss-chip-wash); color: var(--ss-chip-text); }

.ss-card { border: 1px solid var(--ss-line); border-radius: 3px; background: #fff; }

/* Confirm — profile card + edit fields + email.

   #confirm-form wraps every section of this screen in a <form>, which
   is itself the ONE flex child of .ss-screen — .ss-screen's own
   `gap: 34px` therefore never reaches the form's real children (the
   head text, the profile card, the email/CTA panel), so without this
   rule they stack with no intentional space between them at all. Every
   other screen (no <form> wrapper) already gets that gap for free; this
   just gives the confirm screen the same rhythm. */
.ss-screen #confirm-form { display: flex; flex-direction: column; gap: 34px; }
/* Real mobile stress test (5 real-length business descriptions at
   390x844) found the email/CTA panel sitting 145-200px below the fold
   with the desktop rhythm carried over unchanged. Tightened here only
   (desktop keeps its original spacing) — this is spacing only, no
   content removed. Combined with the tighter WHAT_YOU_DO_MAX_CHARS
   clamp and the mobile-only chip hide below, this reliably brings the
   CTA back near/within the fold for real-length descriptions. */
@media (max-width: 640px) { .ss-screen #confirm-form { gap: 20px; } }

/* The "Business understood" badge restates what the domain card
   directly above (in the persistent left panel) and the "We found X"
   heading right below it already convey — on mobile, where that
   redundancy costs real fold space, it's dropped; the confirmation
   itself is unaffected; desktop is unchanged. */
@media (max-width: 640px) { #ss-confirm .ss-chip-neutral { display: none; } }

/* Same reasoning for the explanatory subcopy ("Check this before we
   run the scan…") — real, useful context, but not one of the three
   things this screen must communicate at a glance on mobile (correct
   business / enter email / Run my free analysis), and it was the
   single largest remaining contributor once the badge above was
   already removed. Desktop keeps it; a mobile user who wants it can
   still find it after the small scroll to the edit/detail area. */
@media (max-width: 640px) { #ss-confirm .ss-screen-head-stack .ss-sub { display: none; } }

/* Groups the confirmed business card with its own edit affordance, kept
   visually apart from the email/CTA panel below so "here's what to
   check" and "here's what to do next" read as two distinct beats
   instead of one flat stack of controls. */
.ss-confirm-check { display: flex; flex-direction: column; gap: 14px; }
.ss-edit-link { align-self: flex-start; font-size: 13px; }

/* The one obvious next action on this screen: work email -> Run. A
   tinted, bordered panel (existing --ss-chip-wash/--ss-citron-print
   tokens, not new colours) separates it from the "check this" card
   above so the email field and primary CTA read as unmistakably the
   thing to do next, not one more field among several. */
.ss-next-step {
  display: flex; flex-direction: column; gap: 18px;
  background: var(--ss-chip-wash);
  border: 1px solid var(--ss-citron-print);
  border-radius: 6px;
  padding: 28px 30px;
}
@media (max-width: 640px) { .ss-next-step { padding: 20px; } }

#ss-email-field label { font-size: 14px; font-weight: 700; }
#ss-email-field input { height: 52px; font-size: 16.5px; background: #fff; border-color: var(--ss-citron-print); }

/* The single dominant action on this screen — citron (this flow's own
   "go forward" colour, already used for the stepper/progress fill and
   the final report link) rather than the plain ink button every other
   control on this screen could otherwise be confused with. */
.ss-btn-run { flex: none; height: 52px; padding: 0 30px; font-size: 16px; font-weight: 700; }
.ss-run-timing { font-family: var(--font-mono); font-size: 12px; color: var(--ss-ink-soft); }
@media (max-width: 640px) {
  .ss-next-step .ss-action-row { flex-direction: column; align-items: stretch; gap: 10px; }
  .ss-btn-run { width: 100%; }
  .ss-run-timing { text-align: center; }
}

/* Compressed confirm card (see item 1 of the scan-journey redesign):
   two lines only — a small mono meta line (category · market) and one
   clamped description line — confirmable at a glance instead of a
   multi-row profile table. */
.ss-profile-card { padding: 22px 26px; display: flex; flex-direction: column; gap: 8px; }
@media (max-width: 640px) { .ss-profile-card { padding: 16px 18px; } }
.ss-profile-meta { font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--ss-muted); }
.ss-profile-desc { font-size: 16px; line-height: 1.55; color: var(--ss-ink); }

.ss-input-field { margin-bottom: 18px; display: flex; flex-direction: column; gap: 6px; }
.ss-input-field:last-child { margin-bottom: 0; }
.ss-input-field label { font-size: 13px; font-weight: 600; color: var(--ss-ink); }
.ss-input-field input, .ss-input-field textarea {
  height: 44px; padding: 0 14px; border-radius: 6px; background: #fff; border: 1px solid var(--ss-line); color: var(--ss-ink);
  font-family: var(--font-text); font-size: 16px;
}
.ss-input-field textarea { height: auto; min-height: 90px; padding: 12px 14px; resize: vertical; line-height: 1.5; }
.ss-input-field input:focus, .ss-input-field textarea:focus { outline: 2px solid var(--ss-citron); outline-offset: 2px; border-color: var(--ss-citron-print); }
.ss-input-helper { font-family: var(--font-mono); font-size: 11px; color: var(--ss-muted); }

.ss-edit-fields { margin-top: 4px; padding: 24px 0; border-top: 1px solid var(--ss-line); border-bottom: 1px solid var(--ss-line); }

.ss-action-row { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }

.ss-btn {
  height: 44px; padding: 0 22px; border-radius: 6px; font-family: var(--font-text); font-size: 15px; font-weight: 500;
  cursor: pointer; border: none; display: inline-flex; align-items: center; justify-content: center; text-decoration: none;
}
.ss-btn:hover { text-decoration: none; }
.ss-btn:focus-visible { outline: 2px solid var(--ss-citron); outline-offset: 2px; }
.ss-btn-ink { background: var(--ss-ink); color: var(--ss-paper); }
.ss-btn-ink:hover { background: #000; }
.ss-btn-ink:disabled { opacity: .55; cursor: not-allowed; }
.ss-btn-citron { background: var(--ss-citron); color: var(--ss-citron-on); }
.ss-btn-citron:hover { background: var(--ss-citron-hover); }
.ss-btn-tertiary { background: none; color: var(--ss-ink-soft); padding: 0; height: auto; }
.ss-btn-tertiary:hover { color: var(--ss-ink); }

/* ===================================================================
   Screens 01 & 03 — Understand & Analysis, per the v3-final handoff:
   "one active thing, a small amount of real evidence, a quiet history
   of completed work." Understand (a single atomic call, no sub-states)
   stays a bare title + one line; Analysis adds the bordered "active
   card" below, exactly one at a time. Every value is real — see
   updateAnalysisScreen in scan.js, a pure function of currentStage/
   progress polled from /api/scan/status, rebuilt from scratch on every
   poll so a refresh reconstructs it exactly. The only two purely
   decorative, non-backend-driven motions in this whole screen are the
   active card's status dot and its travelling top edge — both stop the
   instant the card's real state completes. ===================== */

.ss-activity-title { font-family: var(--font-display); font-weight: 500; font-size: 38px; line-height: 1.08; letter-spacing: -0.03em; color: var(--ss-ink); }
@media (max-width: 640px) { .ss-activity-title { font-size: 28px; } }

/* Business logo (item 2, 2026-09) — best-effort, never blocking: the
   <img> is only given a src once a real logoUrl is known, and its own
   onerror handler (scan.js) swaps to the plain initials/name fallback
   badge below rather than ever showing a broken-image icon. Sized to
   sit inline with the activity title without shifting its baseline. */
.ss-analysis-head { display: flex; align-items: center; gap: 14px; }
.ss-business-logo {
  flex: none; width: 44px; height: 44px; border-radius: 8px;
  background: var(--ss-paper-2); border: 1px solid var(--ss-line);
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.ss-business-logo img { width: 100%; height: 100%; object-fit: contain; padding: 6px; }
.ss-business-logo-fallback { font-family: var(--font-display); font-weight: 600; font-size: 15px; color: var(--ss-ink-soft); }
@media (max-width: 640px) { .ss-business-logo { width: 36px; height: 36px; border-radius: 7px; } .ss-business-logo-fallback { font-size: 13px; } }

/* Status row beneath the title — a real status word only, no visible
   counter/timer (customers don't need to see a ticking number). Past 3
   minutes elapsed (tracked purely client-side, never rendered as a
   number) it shifts amber, because at that point it's paired with the
   active card's own real, saved-response-count reassurance sentence —
   not decoration. */
.ss-status-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.ss-status-word { font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.14em; color: var(--ss-muted); }
.ss-status-row.is-slow .ss-status-word { color: var(--warn-text); }

/* Quiet history — compact, static, real. Rebuilt from scratch on every
   poll (never appended-to incrementally, except the one final tick at
   settle — see appendHistoryLine), so a refresh reconstructs exactly the
   right set of ticks with no risk of duplicates or replay. Each item
   gets one, one-time entrance transition (450ms, one row at a time,
   never batched) — motion here marks a genuine state change, unlike the
   active card's decorative motion below. */
.ss-history { display: flex; flex-direction: column; gap: 12px; margin-bottom: 2px; }
.ss-history-item { display: flex; flex-direction: column; gap: 8px; }
@media (prefers-reduced-motion: no-preference) {
  .ss-history-item { animation: ss-history-in 450ms cubic-bezier(.2,.8,.2,1) both; }
  @keyframes ss-history-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
}
.ss-history-text { display: flex; align-items: baseline; gap: 8px; font-size: 16px; font-weight: 400; color: var(--ss-ink-soft); }
.ss-history-text::before { content: "✓"; color: var(--ss-citron-print); font-weight: 700; flex: none; }

/* The one active card — always exactly one, ink-bordered, the largest
   type on the screen after the title itself. Its own quiet, one-time
   entrance (rise into the space the previous card vacated) is separate
   from the two decorative loops inside it (dot + travelling edge),
   which are the only elements on this whole surface not driven by a
   real state change. */
.ss-active-card { position: relative; overflow: hidden; border: 1.5px solid var(--ss-ink); border-radius: 4px; background: #fff; padding: 26px 28px; display: flex; flex-direction: column; gap: 14px; }
@media (max-width: 640px) { .ss-active-card { padding: 20px 20px; } }
@media (prefers-reduced-motion: no-preference) {
  .ss-active-card { animation: ss-card-in 450ms cubic-bezier(.2,.8,.2,1) both; }
  @keyframes ss-card-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
}

/* Travelling edge — a 2px citron segment sweeping across the card's top
   border, continuously, only while this card is genuinely active.
   Purely decorative (see the block comment above); removed instantly
   (not faded) the moment the real state it represents completes. */
.ss-active-card::before {
  content: ""; position: absolute; top: 0; left: -30%; width: 30%; height: 2px; background: var(--ss-citron-print);
}
@media (prefers-reduced-motion: no-preference) {
  .ss-active-card::before { animation: ss-edge-travel 2.4s ease-in-out infinite; }
  @keyframes ss-edge-travel { from { left: -30%; } to { left: 100%; } }
}
@media (prefers-reduced-motion: reduce) { .ss-active-card::before { left: 0; width: 100%; opacity: .5; } }

.ss-active-eyebrow { display: flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.14em; color: var(--ss-muted); }
.ss-active-dot { width: 8px; height: 8px; border-radius: 999px; background: var(--ss-citron-print); flex: none; }
@media (prefers-reduced-motion: no-preference) { .ss-active-dot { animation: ss-pulse 1.6s ease-in-out infinite; } }
@media (prefers-reduced-motion: reduce) { .ss-active-dot { opacity: .8; } }
@keyframes ss-pulse { 0%, 100% { opacity: .45; transform: scale(.85); } 50% { opacity: 1; transform: scale(1); } }

.ss-active-sentence { font-family: var(--font-display); font-weight: 500; font-size: 21px; line-height: 1.35; letter-spacing: -0.015em; color: var(--ss-ink); }
@media (max-width: 640px) { .ss-active-sentence { font-size: 18px; } }
.ss-active-desc { font-size: 15px; line-height: 1.55; color: var(--ss-ink-soft); }

/* Rotating buyer-question display (item 6, 2026-09) — one real, already-
   generated question at a time, auto-advanced in scan.js. A fixed
   min-height (2 lines at this font/line-height) plus vertical centring
   is what actually prevents the layout jump a shorter/longer question
   would otherwise cause on swap — the requirement isn't just "don't
   animate the height", the box must never change size at all. */
.ss-active-question-wrap {
  min-height: 44px; display: flex; align-items: center;
  background: var(--ss-paper-2); border-radius: 4px; padding: 10px 14px;
}
.ss-active-question { font-size: 14.5px; line-height: 1.5; font-style: italic; color: var(--ss-ink-soft); margin: 0; }
@media (prefers-reduced-motion: no-preference) {
  .ss-active-question { transition: opacity 260ms ease; }
  .ss-active-question.is-swapping { opacity: 0; }
}

/* Per-platform hairline rows — truthful three-state model only (Asking /
   Testing / Complete — see the V1 fallback: no fraction, since real
   per-question-level events aren't available today, only per-platform
   aggregate counts refreshed on each poll). Rows, not cards: the
   sentence above is the object, these are its footnote. */
.ss-platform-rows { display: flex; flex-direction: column; }
.ss-platform-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 10px 0; border-top: 1px solid var(--ss-line); font-size: 16px; }
.ss-platform-row:first-child { border-top: none; }
.ss-platform-name { font-weight: 600; color: var(--ss-ink); }
.ss-platform-state { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ss-muted); }
.ss-platform-state.is-complete { color: var(--ss-ink); font-weight: 600; }

/* Evidence strip — small, real, mono facts only (question count,
   platforms-complete count) — never a percentage or an estimate. */
.ss-evidence { font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--ss-muted); }

/* Collapse: when three platform rows resolve into one ticked history
   line, the outgoing rows fade+collapse over 350ms before the new
   history line's own entrance — the screen only ever loses elements
   from here on, never gains a new kind of element. */
.ss-collapsing { overflow: hidden; }
@media (prefers-reduced-motion: no-preference) {
  .ss-collapsing { animation: ss-collapse 350ms cubic-bezier(.4,0,.2,1) both; }
  @keyframes ss-collapse { from { opacity: 1; max-height: 200px; } to { opacity: 0; max-height: 0; } }
}
@media (prefers-reduced-motion: reduce) { .ss-collapsing { display: none; } }

/* ---- Settle: the authoritative reportReadyAt gate has fired. 900ms,
   same URL, same DOM — paper crossfades to ink, the active card and
   history fade together, then a small real evidence line lifts into
   view before the existing navigate-to-report fires. Scoped to the
   right pane only (not the whole page) so the surrounding nav/header
   is undisturbed. ---- */
.ss-right.is-settling { background: var(--ink-950); transition: background 500ms ease; min-height: 500px; display: flex; align-items: center; justify-content: center; }
.ss-settle-evidence {
  font-family: var(--font-mono); font-size: 13px; text-transform: uppercase; letter-spacing: 0.14em; color: var(--ss-paper);
  opacity: 0; text-align: center; transition: opacity 500ms ease 200ms;
}
.ss-settle-evidence p:first-child { font-size: 20px; letter-spacing: 0.02em; margin-bottom: 10px; }
.ss-right.is-settling .ss-settle-evidence { opacity: .95; }
@media (prefers-reduced-motion: reduce) {
  .ss-right.is-settling, .ss-settle-evidence { transition: none; }
}

@media (max-width: 640px) {
  .ss-screen-head { flex-direction: column; }
}

@media (prefers-reduced-motion: reduce) {
  .ss-shell * { animation: none !important; }
}

/* ===================================================================
   Failure + retry — "the truthful V1 state" (v3-final frame 08).
   Declining to publish a partial answer is a trust signal, not an
   apology: what's kept (business details + questions) and what's
   charged (nothing — this scan is free) are stated as plainly as the
   failure itself. Not part of the ss-shell split (kept as its own
   simple card, matching step-manual-info/step-failed's existing
   precedent), just restyled to carry the same real-history + plain-
   facts language as the rest of this redesign. ===================== */
.ss-failed-title { font-family: var(--font-display); font-weight: 500; font-size: 30px; letter-spacing: -0.02em; line-height: 1.15; color: var(--ink); margin-bottom: 10px; }
.ss-failed-sentence { font-size: 16px; line-height: 1.55; color: var(--ink-body); margin-bottom: 22px; }
.ss-failed-facts { display: flex; flex-direction: column; gap: 16px; margin-bottom: 26px; }
.ss-failed-fact-label { font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.12em; color: var(--ink-faint); margin-bottom: 4px; }
.ss-failed-fact-value { font-size: 15px; color: var(--ink-body); }
.ss-failed-actions { display: flex; flex-direction: column; gap: 10px; }

/* Discovery-failure "Try again" (scan.html #manual-info-retry): separate it from the manual form below. */
#manual-info-retry { margin: 0 0 24px; }

/* Public-sources fallback (2026-09-27): status on the manual step and
   the source list on the confirm screen. Existing tokens only. */
.scan-public-status { display: flex; gap: 12px; align-items: flex-start; margin: 0 0 24px; }
.scan-public-status .ss-active-dot { margin-top: 7px; }
.scan-public-status-body { flex: 1; min-width: 0; }
.scan-public-status-text { color: var(--ink); font-size: 14.5px; }
.scan-public-status-hint { margin-top: 4px; font-size: 13px; color: var(--ink-faint); }
.scan-public-status-hint:empty { display: none; }
.scan-public-status .scan-btn-secondary { margin-top: 12px; background: var(--surface); }
.scan-public-status.is-idle .ss-active-dot { display: none; }
.ss-public-sources { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.ss-public-sources-note { font-size: 14px; line-height: 1.5; color: var(--ss-ink-soft); }
.ss-public-sources-details summary { cursor: pointer; font-size: 13px; font-weight: 600; color: var(--ss-ink-soft); }
.ss-public-sources-list { list-style: none; display: grid; gap: 8px; margin-top: 10px; }
.ss-public-sources-list a { display: block; font-size: 13.5px; line-height: 1.4; color: var(--teal-text); overflow-wrap: anywhere; }
.ss-public-sources-path { display: block; font-family: var(--font-mono); font-size: 12px; color: var(--ss-muted); overflow-wrap: anywhere; }
