/* /audit — the presence-audit funnel.

   Deliberately its own stylesheet: styles.css drives the TikTok-style home page
   and locks the body to a single non-scrolling screen, which is the opposite of
   what a long streaming report needs.

   Two palettes, one page, because the page does two jobs. Steps 1 and 2 are a
   landing page — a cold visitor arriving from a campaign, who has to get as far
   as typing their business name. Step 3 is a document: read closely,
   screenshotted, and forwarded to whoever runs their website. Those want
   opposite treatments.

   The report is on paper for three reasons, none of them taste. Severity needs
   somewhere to go: on the near-black ground below, `--bad` is about the only
   red that stays legible and it still reads muddy, so a failing pillar can only
   whisper. Screenshots of this get pasted into a text thread or an email, and a
   light one survives that. And forty-odd evidence rows at 14px is a long read
   that low contrast makes longer.

   `body.on-report` does the switch — see `show()` in audit.js. Both palettes
   live here; nothing is duplicated per component. */

:root {
  /* The hero. Dark, and continuous with the home page. */
  --bg: #07100f;
  --panel: rgba(255, 255, 255, 0.04);
  --border: rgba(255, 255, 255, 0.11);
  --border-strong: rgba(90, 189, 178, 0.45);
  --text: #f2f7f6;
  --muted: #9bb0ad;
  /* Raised from #6b807d, which was ~4.3:1 here and carried every 12px label
     and the whole of the legal fine print. */
  --dim: #8aa3a0;
  --accent: #5ABDB2;
  --accent-ink: #04100e;
  --accent-soft: rgba(90, 189, 178, 0.14);
  --warn: #e8a838;
  --bad: #e2604f;
  --good: #5ABDB2;

  --radius: 14px;
  --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --hero-bg:
    radial-gradient(900px 500px at 12% -8%, rgba(90, 189, 178, 0.16), transparent 62%),
    radial-gradient(700px 420px at 92% 6%, rgba(90, 189, 178, 0.07), transparent 60%);
}

/* The report. Warm off-white rather than pure white — it reads as a document,
   and the teal sits better on it. `--accent` darkens to #0F6F65 anywhere it is
   a word: #5ABDB2 is about 2.1:1 on paper and fails every contrast test it
   meets, so the bright teal survives only as fills, bars and rules. */
body.on-report {
  --bg: #FBFAF7;
  --panel: #FFFFFF;
  --border: #E6E2D8;
  --border-soft: #F0EDE5;
  --border-strong: #5ABDB2;
  --text: #0E1A18;
  --soft: #3B4A47;
  --muted: #4E5D5A;
  --dim: #62726F;
  --accent: #0F6F65;
  --accent-ink: #04100e;
  --accent-bright: #5ABDB2;
  --accent-soft: rgba(90, 189, 178, 0.12);
  --warn: #96690C;
  --bad: #B0402C;
  --bad-soft: #FBEFEC;
  --good: #0F6F65;
  --hero-bg: none;
}

* { box-sizing: border-box; }

/* The page hides and reveals steps with the `hidden` attribute, and the UA rule
   for it (`display: none`) loses to any class that sets `display` — which is how
   the manual-entry form came to sit under the candidate list it is the
   alternative to. One rule beats chasing it per component. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  background-image: var(--hero-bg);
  background-attachment: fixed;
  color: var(--text);
  font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  transition: background-color .5s ease, color .5s ease;
}

a { color: inherit; text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ------------------------------------------------------------------- chrome */

.nav {
  display: flex; align-items: center; justify-content: space-between;
  padding: 20px clamp(18px, 5vw, 56px);
  position: sticky; top: 0; z-index: 20;
  background: linear-gradient(180deg, rgba(7, 16, 15, 0.92), rgba(7, 16, 15, 0));
  backdrop-filter: blur(8px);
}
body.on-report .nav {
  background: linear-gradient(180deg, rgba(251, 250, 247, 0.95), rgba(251, 250, 247, 0));
  border-bottom: 1px solid transparent;
}
/* The fade works over the roomy desktop layout, where the nav mostly floats
   above whitespace. On a phone it sits directly on top of body copy for the
   whole scroll, and a gradient to fully transparent plus an 8px backdrop blur
   turns that copy into a smear under the wordmark — the page reading as
   half-rendered rather than as a page with a sticky header. So: solid, with a
   hairline to say where it ends. */
@media (max-width: 620px) {
  .nav { background: var(--bg); border-bottom: 1px solid var(--border); }
  body.on-report .nav { background: var(--bg); border-bottom-color: var(--border); }
}

.wordmark { font-weight: 800; letter-spacing: -0.02em; font-size: 19px; }

.nav-tool {
  font-size: 14px; font-weight: 500; color: var(--muted);
  border: 1px solid var(--border); border-radius: 999px; padding: 8px 16px;
  transition: color .2s, border-color .2s;
  background: none; font-family: inherit; cursor: pointer;
}
.nav-tool:hover { color: var(--text); border-color: var(--border-strong); }
/* Three controls share the bar on the report, and at 390px "Save as PDF" broke
   over two lines inside its own pill. Neither label may wrap: a pill taller
   than the one beside it is the first thing that reads as unfinished. */
.nav-tool, .nav-cta { white-space: nowrap; }
@media (max-width: 620px) {
  .nav { padding-left: 16px; padding-right: 16px; }
  .nav-right { gap: 8px; }
  .nav-tool, .nav-cta { padding: 8px 13px; font-size: 13px; }
  .wordmark { font-size: 17px; }
}

/* Filled, where "Save as PDF" beside it stays a ghost. Two identical outlined
   pills asked the visitor to work out which one the page wanted, and the answer
   is never "save a PDF" — that is a thing you do to a report you already have.
   Bright teal reads as a fill on both palettes, which is the one job §the
   report palette leaves it (as a word on paper it fails contrast outright), so
   it is the same treatment as .cta-primary at the foot of the report. */
.nav-cta {
  font-size: 14px; font-weight: 600; font-family: inherit;
  color: #04100e; background: var(--accent-bright, var(--accent));
  border: 1px solid transparent; border-radius: 999px; padding: 8px 16px;
  transition: transform .15s, box-shadow .2s;
  box-shadow: 0 6px 18px -8px rgba(90, 189, 178, .75);
}
.nav-cta {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
}
.nav-cta:hover { color: #04100e; transform: translateY(-1px); }
.nav-right { display: flex; gap: 10px; align-items: center; }
/* The nav's menu hangs off the right edge — anchored left it would run off the
   side of a phone, which is the width it matters most at. */
.nav-pick .cta-menu { left: auto; right: 0; }
@media (max-width: 620px) {
  /* And here it cannot drop into flow the way the offer's does: the nav is
     sticky, so an in-flow panel would stretch the bar itself. */
  .nav-pick .cta-menu {
    position: absolute; margin-top: 0; min-width: 240px;
    box-shadow: 0 18px 40px -18px rgba(0, 0, 0, .65);
  }
}

main { padding: 0 clamp(18px, 5vw, 56px) 80px; }

.stage {
  max-width: 760px; margin: 0 auto;
  animation: rise .5s cubic-bezier(.16, 1, .3, 1) both;
}
.stage.wide { max-width: 1080px; }
.stage[hidden] { display: none; }

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--accent); font-weight: 500;
  margin: clamp(28px, 7vh, 72px) 0 18px;
}
.dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 0 rgba(90, 189, 178, .55);
  animation: pulse 2.2s infinite;
}
@keyframes pulse {
  70%  { box-shadow: 0 0 0 9px rgba(90, 189, 178, 0); }
  100% { box-shadow: 0 0 0 0 rgba(90, 189, 178, 0); }
}

h1 {
  font-size: clamp(38px, 7.2vw, 68px);
  line-height: 1.03; letter-spacing: -0.035em; font-weight: 800;
  margin: 0 0 22px; text-wrap: balance;
}
h1 em {
  font-style: normal;
  background: linear-gradient(100deg, var(--accent), #9fe6dd);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
h2 { font-size: clamp(26px, 4vw, 38px); letter-spacing: -0.03em; margin: 0 0 14px; font-weight: 700; }
h3 { font-size: 19px; letter-spacing: -0.01em; margin: 0 0 12px; font-weight: 600; }

.lede { color: var(--muted); font-size: clamp(17px, 2vw, 20px); max-width: 44ch; margin: 0 0 34px; }
.lede.small { font-size: 17px; }

/* --------------------------------------------------------------- the form */

#lookup { margin-bottom: 44px; }

.field-row { display: flex; gap: 10px; flex-wrap: wrap; }

input {
  flex: 1 1 220px; min-width: 0;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px 18px; font: inherit; font-size: 17px;
  transition: border-color .2s, background .2s, box-shadow .2s;
}
input::placeholder { color: var(--dim); }
input:focus {
  outline: none; border-color: var(--border-strong);
  background: rgba(90, 189, 178, 0.06);
  box-shadow: 0 0 0 4px rgba(90, 189, 178, 0.12);
}
/* Narrower than the name on a row they share, because "City, State" is the
   shorter answer and the optional one. */
#biz-loc { flex: 0 1 190px; }
@media (max-width: 620px) {
  /* Once the row wraps, that 190px is not a proportion any more — it is one
     field two-thirds the width of the one above it and a button two-thirds the
     width of that, which reads as three controls nobody lined up. Stack them. */
  .field-row { display: grid; grid-template-columns: 1fr; gap: 10px; }
  #biz-loc { flex: auto; }
}

button[type="submit"] {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  background: var(--accent); color: var(--accent-ink);
  border: none; border-radius: var(--radius);
  padding: 16px 26px; font: inherit; font-weight: 600; font-size: 17px;
  cursor: pointer; transition: transform .15s, box-shadow .2s, opacity .2s;
  box-shadow: 0 8px 26px -10px rgba(90, 189, 178, .8);
}
button[type="submit"]:hover { transform: translateY(-1px); box-shadow: 0 14px 34px -12px rgba(90, 189, 178, .9); }
button[type="submit"]:active { transform: translateY(0); }
button[type="submit"][disabled] { opacity: .55; cursor: progress; transform: none; }

.spinner {
  width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid rgba(4, 16, 14, .3); border-top-color: #04100e;
  animation: spin .7s linear infinite;
}
.spinner[hidden] { display: none; }
@keyframes spin { to { transform: rotate(360deg); } }

.form-note { color: var(--dim); font-size: 14px; margin: 12px 2px 0; }
.form-note.bad { color: var(--bad); }

.ghost {
  background: none; border: 1px solid var(--border); color: var(--muted);
  border-radius: 999px; padding: 10px 20px; font: inherit; font-size: 15px;
  cursor: pointer; transition: color .2s, border-color .2s;
}
.ghost:hover { color: var(--text); border-color: var(--border-strong); }
.restart { margin: 42px auto 0; display: block; }

/* ------------------------------------------------------------ the teaser */

.pillars-teaser { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--border); }
.pillars-teaser li {
  display: grid; grid-template-columns: 44px 190px 1fr; gap: 14px; align-items: baseline;
  padding: 16px 2px; border-bottom: 1px solid var(--border);
  color: var(--muted); font-size: 15px;
}
.pillars-teaser .n { font-family: var(--mono); font-size: 12px; color: var(--accent); }
.pillars-teaser strong { color: var(--text); font-weight: 600; font-size: 16px; }
.pillars-teaser .q { color: var(--muted); }
@media (max-width: 620px) {
  /* Number in the gutter, label and question stacked beside it. Both of the
     latter need placing explicitly — auto-placement puts the second one back
     under the number, which is the 34px column. */
  .pillars-teaser li { grid-template-columns: 30px 1fr; row-gap: 3px; gap: 10px; }
  .pillars-teaser li strong, .pillars-teaser li .q { grid-column: 2; }
  .pillars-teaser li .q { font-size: 14.5px; line-height: 1.45; }
}

/* ------------------------------------------------------------ candidates */

.candidates { display: grid; gap: 12px; margin-bottom: 22px; }

.candidate {
  text-align: left; width: 100%; cursor: pointer;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 18px 20px; color: inherit; font: inherit;
  display: flex; justify-content: space-between; align-items: center; gap: 18px;
  transition: border-color .2s, background .2s, transform .15s;
}
.candidate:hover { border-color: var(--border-strong); background: rgba(90, 189, 178, .06); transform: translateY(-1px); }
.candidate strong { display: block; font-size: 18px; font-weight: 600; margin-bottom: 3px; }
.candidate .facts { color: var(--muted); font-size: 14px; }
.candidate .pick { color: var(--accent); font-size: 14px; white-space: nowrap; }
@media (max-width: 620px) {
  /* Side by side, the address wraps to four lines against a "That's us →" that
     will not wrap at all, so the facts get squeezed into two thirds of a phone
     and the tap target floats in the middle of them. Stacked, the whole card is
     the tap target and the facts get the full width. */
  .candidate { flex-direction: column; align-items: flex-start; gap: 10px; }
  .candidate .pick { align-self: flex-end; }
}

.manual { display: grid; gap: 10px; margin-top: 18px; max-width: 460px; }
.manual button { border-radius: var(--radius); }

/* ==========================================================  THE REPORT  ==
   Order is verdict → hook → what to fix → who you lose to → evidence → offer.
   The five pillars used to come before the fix list, which put five cards and
   up to forty evidence rows between the visitor and the section the whole page
   exists to deliver. The pillars are proof; proof goes after the claim. */

/* ------------------------------------------------------------ verdict band */

.report-head { padding: clamp(20px, 5vh, 44px) 0 0; }

.bizline {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 14px; flex-wrap: wrap;
}
.report-head h2 { font-size: clamp(21px, 2.6vw, 26px); margin: 0; }
.report-meta { color: var(--dim); font-size: 14px; margin: 3px 0 0; }
.report-stamp {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 3px; text-align: right;
}
.report-when {
  font-family: var(--mono); font-size: 11px; color: var(--dim);
  letter-spacing: .05em; text-transform: uppercase;
}
/* On the page the code is redundant — the "text us" button already carries it.
   It is here for the printed copy, which is where it stops being redundant:
   somebody who saved the PDF and texts a fortnight later has no deep link
   left, and this is the only thing that finds their run again. */
.report-code {
  font-family: var(--mono); font-size: 11px; color: var(--muted);
  letter-spacing: .05em;
}

.verdict {
  display: grid; grid-template-columns: minmax(190px, 250px) 1fr;
  gap: clamp(20px, 4vw, 44px); align-items: start;
  margin: 26px 0 0; padding-bottom: 28px; border-bottom: 1px solid var(--border);
}
@media (max-width: 760px) { .verdict { grid-template-columns: 1fr; gap: 20px; } }

/* ---------------------------------------------------------------- working
   The score's slot, before there is a score. Same grid as .verdict so the
   header does not jump when one replaces the other. */
.working {
  display: grid; grid-template-columns: minmax(190px, 250px) 1fr;
  gap: clamp(20px, 4vw, 44px); align-items: center;
  margin: 26px 0 0; padding-bottom: 28px; border-bottom: 1px solid var(--border);
}
.working[hidden] { display: none; }
@media (max-width: 760px) {
  .working { grid-template-columns: auto 1fr; gap: 18px; align-items: start; }
}

.ring { position: relative; width: clamp(96px, 13vw, 124px); aspect-ratio: 1; }
.ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 9; stroke-linecap: round; }
.ring-track { stroke: var(--border); }
/* r=52 → circumference 326.7. The arc is drawn by shortening the dash, so JS
   only ever sets one number and the transition does the rest. */
.ring-arc {
  stroke: var(--accent); stroke-dasharray: 326.7;
  stroke-dashoffset: 326.7; transition: stroke-dashoffset .7s cubic-bezier(.16,1,.3,1);
}
/* The part that is always moving. A tenth of the circle, turning once every
   1.4s, so the ring is alive during the thirty-second stretches where no
   stage completes and the arc above it does not move at all. */
.ring-spin {
  stroke: var(--accent-bright, var(--accent)); stroke-dasharray: 33 293.7;
  transform-origin: 60px 60px; animation: spin 1.4s linear infinite;
}
.ring-count {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--mono); font-size: clamp(15px, 2.2vw, 18px); font-weight: 500;
  color: var(--text); letter-spacing: -.02em;
}

.working-title {
  font-size: clamp(18px, 2.4vw, 22px); font-weight: 600; margin: 0;
  letter-spacing: -.02em; display: flex; align-items: baseline; gap: 2px;
}
/* Three dots keeping time with nothing in particular — the point is that the
   header is never completely still while a run is open. */
.dots { display: inline-flex; gap: 3px; padding-left: 3px; }
.dots i {
  width: 4px; height: 4px; border-radius: 50%; background: var(--accent);
  animation: dot 1.2s ease-in-out infinite;
}
.dots i:nth-child(2) { animation-delay: .15s; }
.dots i:nth-child(3) { animation-delay: .3s; }
@keyframes dot { 0%, 60%, 100% { opacity: .2; } 30% { opacity: 1; } }

.working-now {
  margin: 7px 0 0; font-size: 15px; color: var(--accent); font-weight: 500;
}
.working-note {
  margin: 8px 0 0; font-size: 13.5px; color: var(--dim); max-width: 46ch;
  line-height: 1.5;
}

.score-num { display: flex; align-items: baseline; gap: 10px; }
.score-num strong {
  font-size: clamp(52px, 8vw, 66px); font-weight: 800; letter-spacing: -.045em;
  line-height: .9; font-variant-numeric: tabular-nums;
}
.score-num span { font-size: 14px; color: var(--dim); }

/* A number with a named band is interpretable at a glance. "62 · presence
   score" was not: no scale, no direction, no idea whether it is good. */
.score-band {
  display: inline-block; margin-top: 10px; font-size: 12px; font-weight: 600;
  letter-spacing: .05em; text-transform: uppercase;
  border: 1px solid currentColor; border-radius: 999px; padding: 3px 11px;
}
.score-track { margin-top: 15px; }
.score-bar { display: flex; height: 7px; border-radius: 4px; overflow: hidden; }
.score-bar i { display: block; height: 100%; opacity: .85; }
.s-bad-bg  { background: var(--bad); }
.s-mid-bg  { background: var(--warn); }
.s-ok-bg   { background: var(--dim); }
.s-good-bg { background: var(--accent-bright, var(--accent)); }
.score-marker { position: relative; height: 0; }
.score-marker span {
  position: absolute; top: -3px; transform: translateX(-50%);
  width: 3px; height: 13px; background: var(--text); border-radius: 2px;
  box-shadow: 0 0 0 2px var(--bg);
  transition: left 1.1s cubic-bezier(.16, 1, .3, 1);
}
.score-ticks {
  display: flex; flex-wrap: wrap; gap: 3px 10px; margin: 14px 0 0;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .04em;
  color: var(--dim); text-transform: uppercase;
}
.score-ticks i { font-style: normal; }
.score-ticks i.here { color: var(--text); font-weight: 500; }

.verdict-line {
  font-size: clamp(19px, 2.6vw, 26px); line-height: 1.32; letter-spacing: -.02em;
  margin: 0 0 14px; font-weight: 600; text-wrap: balance;
}
.verdict-line mark {
  background: none; color: inherit;
  box-shadow: inset 0 -.42em 0 var(--accent-soft);
}

/* The credibility claim, where the credibility claim belongs. This used to be
   an 11px uppercase line at the bottom of the progress sidebar. */
.receipts {
  display: flex; flex-wrap: wrap; gap: 7px 20px;
  font-family: var(--mono); font-size: 11.5px; color: var(--dim);
  letter-spacing: .03em;
}
.receipts b { color: var(--text); font-weight: 600; }

/* ---------------------------------------------------------------- the run */

.report-grid {
  display: grid; grid-template-columns: 1fr 236px; gap: 34px; padding-top: 28px;
  align-items: start;
}
@media (max-width: 940px) { .report-grid { grid-template-columns: 1fr; gap: 24px; } }

/* The progress console. Meaningful for ninety seconds; on `done` it collapses
   into `.contents` below, because a 236px sticky column of finished checkmarks
   is the most valuable space on the page spent on nothing. It sits second in
   the source so a phone shows findings first — it used to be first, so the
   first thing a phone visitor saw after confirming their business was a list
   of our internal stage names. */
.console {
  position: sticky; top: 84px; grid-column: 2;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px 18px;
}
@media (max-width: 940px) {
  .console { position: static; grid-column: 1; grid-row: 1; }
  /* One line on a phone rather than a list of six. */
  .console.running ul li:not(.running) { display: none; }
  .console.running .console-title { display: none; }
}
.console-title {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--dim); margin: 0 0 12px;
}
.console ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.console li {
  display: flex; align-items: center; gap: 10px;
  font-size: 14px; color: var(--muted);
  animation: rise .3s ease both;
}
.console li .tick {
  width: 14px; flex: 0 0 14px; color: var(--dim);
  font-family: var(--mono); font-size: 12px;
  display: inline-flex; align-items: center; justify-content: center;
}
.console li.running { color: var(--text); font-weight: 500; }
.console li.done .tick { color: var(--accent); }
/* A blinking "›" was the only thing saying "this one is in flight", and at
   14px of grey chevron on a fading duty cycle it read as a rendering artifact
   — the item people asked about was the one they thought had stalled. A
   turning ring is the shape everything else on the web uses for the same
   claim. */
.tick .spin {
  width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: var(--accent);
  animation: spin .8s linear infinite;
}
/* Reduced motion kills every animation on the page (see the block near the
   end), which would leave a running item with a still, near-invisible ring.
   Give it back the contrast the movement was carrying. */
@media (prefers-reduced-motion: reduce) {
  .tick .spin { border-color: var(--accent); border-top-color: transparent; }
}

/* What the column becomes once the run finishes: the five pillars with their
   scores and the weights behind them. docs/audit.md promises the weights
   travel with the number; until now they travelled in one grey sentence. */
.contents { display: grid; gap: 3px; }
.contents-note {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .04em;
  color: var(--dim); margin: 12px 0 0; line-height: 1.5;
}
.jump {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 10px;
  align-items: center; width: 100%; text-align: left;
  background: none; border: 0; border-radius: 8px; padding: 7px 8px;
  color: inherit; font: inherit; font-size: 13.5px; cursor: pointer;
}
.jump:hover { background: var(--accent-soft); }
/* The row carries the band colour so the number and the bar can inherit it —
   the label must not, or five pillar names read as five errors. */
.jump b { font-weight: 500; color: var(--text); }
.jump .n { font-weight: 700; font-variant-numeric: tabular-nums; }
.jump .wbar {
  grid-column: 1 / -1; height: 3px; border-radius: 2px;
  background: var(--border); overflow: hidden;
}
.jump .wbar i { display: block; height: 100%; background: currentColor; }
.jump .w {
  grid-column: 1 / -1; font-family: var(--mono); font-size: 9.5px;
  color: var(--dim); letter-spacing: .04em;
}

/* ---------------------------------------------------------------- the hook */

.report-body { grid-column: 1; min-width: 0; }

.hook {
  border: 1px solid var(--border); background: var(--panel);
  padding: 22px 24px; border-radius: var(--radius);
  margin-bottom: 34px;
}
body:not(.on-report) .hook {
  border: 0; border-left: 2px solid var(--accent);
  background: linear-gradient(90deg, var(--accent-soft), transparent 70%);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.hook p {
  margin: 0; font-size: clamp(17px, 2vw, 19px); line-height: 1.58;
  color: var(--soft, var(--muted)); letter-spacing: -0.004em;
}
.hook p::after {
  content: '▌'; color: var(--accent); animation: blink 1s steps(2) infinite;
  margin-left: 2px;
}
.hook.settled p::after { content: none; }

/* --------------------------------------------------------------- sections */

.sec { margin-bottom: 34px; }
.sec-title {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--dim); margin: 0 0 13px;
  padding-bottom: 7px; border-bottom: 1px solid var(--border);
}

/* ------------------------------------------------------------- fix list */

.actions ol { list-style: none; counter-reset: a; margin: 0; padding: 0; display: grid; gap: 10px; }
.actions li {
  counter-increment: a;
  display: grid; grid-template-columns: 26px 1fr auto; gap: 14px;
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 17px 19px; background: var(--panel);
  animation: rise .4s ease both;
}
.actions li::before {
  content: counter(a); font-family: var(--mono); font-size: 13px; color: var(--accent);
  padding-top: 3px;
}
.actions strong { display: block; font-size: 16.5px; margin-bottom: 5px; font-weight: 600; }
.actions li:first-child strong { font-size: 18.5px; }
.actions p { margin: 0; color: var(--muted); font-size: 14.5px; }
.actions .effort {
  font-family: var(--mono); font-size: 10px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--dim);
  border: 1px solid var(--border); border-radius: 999px; padding: 3px 9px;
  white-space: nowrap; align-self: start; margin-top: 2px;
}
.actions li:first-child {
  border-color: var(--border-strong);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
@media (max-width: 560px) {
  .actions li { grid-template-columns: 22px 1fr; }
  .actions .effort { grid-column: 2; justify-self: start; margin-top: 9px; }
}

/* --------------------------------------------------------------- rivals */

.rivals-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); }
.rivals { border-collapse: collapse; width: 100%; font-size: 13.5px; min-width: 540px; }
.rivals th {
  font-family: var(--mono); font-size: 10px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--dim); font-weight: 500; text-align: left; padding: 9px 14px;
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
.rivals td {
  padding: 10px 14px; border-bottom: 1px solid var(--border-soft, var(--border));
  color: var(--muted); font-variant-numeric: tabular-nums;
}
.rivals tbody tr:last-child td { border-bottom: 0; }
.rivals th.n, .rivals td.n { text-align: right; }
.rivals tr.you td { background: var(--accent-soft); color: var(--text); font-weight: 600; }
.rivals .weak { color: var(--bad); }

/* --------------------------------------------------------------- pillars */

.pillars { display: grid; gap: 10px; }

.pillar {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--panel); overflow: hidden;
  border-left-width: 3px; border-left-style: solid;
  animation: rise .45s cubic-bezier(.16, 1, .3, 1) both;
  scroll-margin-top: 84px;
}
/* Severity in the shape of the card, not only in the number on it — five cards
   should scan as a pattern rather than as five numbers to read. */
.b-good { border-left-color: var(--good); }
.b-mid  { border-left-color: var(--warn); }
.b-bad  { border-left-color: var(--bad); }
.b-none { border-left-color: var(--border); }

.pillar-head {
  display: grid; grid-template-columns: 1fr 72px 84px; gap: 16px; align-items: center;
  padding: 15px 18px; width: 100%; text-align: left;
  background: none; border: none; color: inherit; font: inherit;
}
@media (max-width: 620px) {
  .pillar-head { grid-template-columns: 1fr auto; }
  .pillar-mini { display: none; }
}
.pillar-label {
  font-family: var(--mono); font-size: 10px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--dim); margin-bottom: 5px;
  display: flex; gap: 9px; flex-wrap: wrap;
}
.pillar-label .weight { color: var(--accent); }
.pillar-headline { font-size: 15.5px; line-height: 1.38; margin: 0 0 6px; font-weight: 500; }
/* The counts were already in `stats` and invisible until you opened the card. */
.pillar-count { font-family: var(--mono); font-size: 11.5px; color: var(--dim); }
.pillar-count .hit { color: var(--good); }
.pillar-count .miss { color: var(--bad); }
.pillar-mini { height: 5px; border-radius: 3px; background: var(--border); overflow: hidden; }
.pillar-mini i { display: block; height: 100%; background: currentColor; }
.pillar-score {
  font-size: 25px; font-weight: 800; letter-spacing: -.035em; text-align: right;
  font-variant-numeric: tabular-nums; line-height: 1;
}
.pillar-score small { display: block; font-size: 10px; font-weight: 500; color: var(--dim); letter-spacing: .05em; margin-top: 4px; }
.s-good { color: var(--good); }
.s-mid  { color: var(--warn); }
.s-bad  { color: var(--bad); }
.s-none { color: var(--dim); }

/* Named, counted, and visibly a control. It was a bare button with no chevron
   and no label — and the evidence behind it is the entire credibility argument,
   so nothing on the page suggesting it exists was the worst of the misses. */
.disclose {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 10px 18px; border: 0; border-top: 1px solid var(--border);
  background: none; color: var(--accent); font: inherit; font-size: 13px;
  cursor: pointer; text-align: left;
}
.disclose:hover { background: var(--accent-soft); }
.disclose .chev { font-size: 10px; transition: transform .2s; display: inline-block; }
.pillar.open .disclose .chev { transform: rotate(90deg); }

.pillar-body { display: none; padding: 2px 18px 18px; border-top: 1px solid var(--border); }
.pillar.open .pillar-body { display: block; }
.pillar-method { color: var(--dim); font-size: 13.5px; margin: 14px 0 14px; line-height: 1.55; }

.evidence { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }
.evidence li {
  display: grid; grid-template-columns: 16px 1fr auto; gap: 10px; align-items: baseline;
  font-size: 13.5px; color: var(--muted); line-height: 1.5;
  padding: 7px 8px; border-radius: 6px;
}
body.on-report .evidence li.is-miss { background: var(--bad-soft); }
.evidence .mark { font-family: var(--mono); font-size: 11px; }
.evidence .mark.hit  { color: var(--good); }
.evidence .mark.miss { color: var(--bad); }
.evidence .mark.info { color: var(--dim); }
.evidence b { color: var(--text); font-weight: 600; }
/* Right-aligned at the row end. Inline mid-sentence, it broke every row it
   appeared in. */
.evidence .src {
  color: var(--accent); font-family: var(--mono); font-size: 11px;
  white-space: nowrap; align-self: start;
}
.evidence .src:hover { text-decoration: underline; }

/* "Not scored" was a grey em-dash, which reads as a bug rather than as a
   deliberate refusal to score something we did not measure. */
.unscored {
  font-size: 13px; color: var(--dim); background: var(--accent-soft);
  border-radius: 8px; padding: 10px 13px; margin: 0 18px 16px; line-height: 1.5;
}
.unscored b { color: var(--text); }

/* ------------------------------------------------------------------- cta */

.cta {
  margin-top: 8px; padding: 28px; border-radius: var(--radius);
  border: 1px solid var(--border-strong);
  background: linear-gradient(140deg, rgba(90, 189, 178, .12), rgba(90, 189, 178, .02));
}
body.on-report .cta {
  border-color: transparent;
  background: linear-gradient(150deg, #0D1A18, #10322D);
  color: #EAF3F1;
}
body.on-report .cta h3 { color: #fff; }
.cta p { color: var(--muted); margin: 0 0 20px; max-width: 52ch; }
body.on-report .cta p { color: #A9C2BE; }
.cta-row { display: flex; gap: 12px; flex-wrap: wrap; }
.cta-primary {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--accent-bright, var(--accent)); color: #04100e; font-weight: 600;
  border: 0; border-radius: 10px; padding: 14px 24px;
  font: inherit; font-weight: 600; font-size: 16px; cursor: pointer;
  box-shadow: 0 8px 26px -10px rgba(90, 189, 178, .8);
  transition: transform .15s;
}
.cta-primary:hover { transform: translateY(-1px); }
.caret { width: 12px; height: 8px; transition: transform .2s; }
.cta-primary[aria-expanded="true"] .caret { transform: rotate(180deg); }

/* The channel menu. Anchored on desktop; on a phone it drops into flow
   instead, because a floating panel near the bottom of a long report is a
   panel half of which is off-screen. */
.cta-pick { position: relative; }
.cta-menu {
  position: absolute; top: calc(100% + 8px); left: 0; z-index: 5;
  min-width: 260px; display: grid; gap: 2px; padding: 6px;
  /* Opaque, not `--panel`: on the dark palette that token is a 4% white wash
     meant to sit on the page background, and a floating menu made of it shows
     whatever it is covering straight through. */
  background: #0E1A18; border: 1px solid var(--border);
  border-radius: 12px; box-shadow: 0 18px 40px -18px rgba(0, 0, 0, .65);
  animation: rise .18s ease both;
}
/* The offer block is dark even on the paper report, and a dark drop shadow on
   a dark ground draws no edge at all — so the panel is separated by a light
   ring instead. Without it the report copy behind the top corners reads as
   part of the menu. */
body.on-report .cta-menu {
  background: #10201D; border-color: rgba(255, 255, 255, .2);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .06),
              0 24px 48px -20px rgba(0, 0, 0, .9);
}
.cta-menu[hidden] { display: none; }
.cta-menu a {
  display: grid; gap: 1px; padding: 11px 14px; border-radius: 8px;
  color: var(--text); transition: background .15s;
}
body.on-report .cta-menu a { color: #F2F7F6; }
.cta-menu a:hover, .cta-menu a:focus-visible { background: var(--accent-soft); }
.cta-menu strong { font-weight: 600; font-size: 15px; }
.cta-menu span { font-size: 13px; color: var(--dim); }
body.on-report .cta-menu span { color: #8AA5A1; }
@media (max-width: 620px) {
  .cta-pick { width: 100%; }
  .cta-primary { width: 100%; justify-content: center; }
  .cta-menu { position: static; min-width: 0; margin-top: 8px; box-shadow: none; }
}
.fine { font-size: 12.5px; color: var(--dim); margin: 20px 0 0; }
body.on-report .fine { color: #8AA5A1; }
.fine a { color: var(--muted); text-decoration: underline; }
body.on-report .fine a { color: #A9C2BE; }

.error {
  margin-top: 26px; padding: 16px 18px; border-radius: var(--radius);
  border: 1px solid rgba(226, 96, 79, .4); background: rgba(226, 96, 79, .08);
  color: #f3b4aa; font-size: 15px;
}
body.on-report .error { color: var(--bad); background: var(--bad-soft); border-color: rgba(176, 64, 44, .3); }

/* -------------------------------------------------------------------- foot */

.foot {
  display: flex; gap: 20px; justify-content: center; flex-wrap: wrap;
  padding: 34px 20px 44px; color: var(--dim); font-size: 14px;
  border-top: 1px solid var(--border);
}
.foot a:hover { color: var(--muted); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ------------------------------------------------------------------ print
   Owners forward this — to a spouse, to whoever built the site, to the person
   they are about to stop paying. A report that prints properly is a
   deliverable; one that prints as a dark rectangle with the nav on top is a
   web page they screenshotted. Everything interactive is opened and flattened,
   because a collapsed pillar prints as a headline with no evidence under it,
   which is exactly the claim-without-proof the whole report refuses to make. */
@media print {
  body, body.on-report {
    background: #fff !important; background-image: none !important;
    color: #000; font-size: 11pt;
  }
  .nav, .foot, .restart, .console, .cta-row, .nav-right { display: none !important; }
  main { padding: 0; }
  .stage.wide { max-width: none; }
  .report-grid { display: block; }
  .pillar-body { display: block !important; }
  .disclose { display: none !important; }
  .pillar, .actions li, .rivals-wrap, .hook {
    break-inside: avoid; border: 1px solid #ccc !important; box-shadow: none !important;
  }
  .hook p::after { content: none; }
  .evidence .src::after { content: ' (' attr(href) ')'; font-size: 8pt; color: #555; }
  .sec-title, .receipts { color: #333 !important; }
}
