/* aisnoopy — measurement instrument, not a dashboard.
   Cool oat paper, cobalt for the brand under test, olive-grey for rivals,
   burnt amber reserved strictly for warnings. */

:root {
  /* Wire: a data publication, not a dashboard. A neutral grey ground with
     neutral ink, and one hot ember that only ever marks the finding — the
     measured number, the subject's own bar, the link worth following. Warnings
     get their own deep brick red so an alert never masquerades as a result.

     The ground and the type are neutral *together*. The paper was warm cream
     with warm ink, which matched; on a neutral ground the old ink read faintly
     brown in body copy, most visibly in a long paragraph. Going half-neutral is
     the version that looks wrong, so every text tone moved with the paper.

     One consequence worth knowing: the colour system is a warm ramp — plasma
     runs violet to ember, the accent is ember, the subject row is an ember
     tint. On a neutral ground every warm element is unambiguously signal
     rather than part of the page. */
  --paper:     #F2F2F2;
  /* Measured things sit on white; written things sit on the page. That is the
     whole rule, and it gives the white a job: if it is on a panel, it is a
     result. Headlines, findings, footnotes and the signup stay on the paper. */
  --surface:   #FFFFFF;
  --surface-e: #D2D2D2;   /* the hairline that defines a panel's edge */
  --paper-2:   #EAEAEA;
  --paper-3:   #DEDEDE;
  --ink:       #141414;
  --ink-mid:   #4A4A4A;  /* secondary prose; #575757 was 6.45:1 and read grey on grey */
  /* 4.76:1 on the paper, 5.33:1 on white. It was #8A8A8A — 3.08:1 — and it
     carries the small type: ranks, domains, percentages, hints, footers. Still
     twenty steps lighter than --ink-mid, so the hierarchy holds. */
  --ink-soft:  #6B6B6B;
  --rule:      #E4E4E4;
  --rule-2:    #C4C4C4;   /* was used in a dozen rules and never defined */
  --tint:      #FBEDE6;   /* the subject row: paper with a trace of ember */
  --tint-2:    #EFDDD2;   /* a track inside that row, one step down */
  --signal:    #3466B2;
  --signal-dark:#2E5B9E;  /* small ember text, and the buttons */
  --signal-deep:#284F8B;  /* a button under the pointer */
  --on-ember:  #0C1A2E;   /* type on an ember fill, where white is too bright */
  --signal-dim:#A4BADB;
  --rival:     #9E9E9E;
  --flag:      #8F1D1D;

  /* The inverted card and everything drawn on it. These were hard-coded in
     seven places, so a change to the card meant hunting for hex values. */
  --card:      #1A1A1A;
  --card-text: #F0F0F0;
  --card-mid:  #B4B4B4;
  --card-soft: #9A9A9A;
  /* Reading on ink. Light-on-dark blooms, so body copy sits brighter than
     --card-mid and labels brighter than --card-soft; both are still below
     --card-text, which is reserved for headings and figures. */
  --card-read:  #CCCCCC;  /* body copy on the ink page, 10.8:1 */
  --card-label: #BEBEBE;  /* its small mono labels, 9.4:1 */
  --ember:     #6B96D7;   /* a shade lighter than --signal, for the dark card */

  /* One superfamily, three roles. Source Serif 4 was drawn for technical and
     scientific publishing, Source Sans 3 and Source Code Pro alongside it — so
     the prose, the figures and the data tables share a skeleton instead of
     three unrelated faces meeting on the page. The serif is variable on an
     optical-size axis, which is why the hero can be large without the strokes
     going coarse: the browser fits the drawing to the size. */
  --mono: "Source Code Pro", ui-monospace, SFMono-Regular, Menlo, monospace;
  --disp: "Source Sans 3", "Helvetica Neue", Arial, sans-serif;
  --body: "Source Serif 4", Georgia, "Times New Roman", serif;

  --gap: clamp(1.25rem, 3vw, 2.5rem);
  --max: 1080px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  /* The serif carries an optical-size axis; letting the browser drive it means
     hero type gets the high-contrast display drawing and body text gets the
     sturdier reading drawing, from one file. */
  font-optical-sizing: auto;
  font-size: 17px;
  line-height: 1.58;
  -webkit-font-smoothing: antialiased;
}

/* Every family here ships 600 as its bold; the browser default of 700 would
   have no file to use and would smear the glyphs instead. Pinning it keeps the
   ledger's figures and the fine print on real drawn weights. */
b, strong { font-weight: 600; }

a { color: var(--signal); text-decoration: none; border-bottom: 1px solid var(--signal-dim); }
a:hover { border-bottom-color: var(--signal); }

:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
}

.wrap {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gap) 5rem;
}

/* ---------- masthead ---------- */

.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.6rem 0 2.6rem;
  flex-wrap: wrap;
}

.wordmark {
  font-family: var(--mono);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  border: 0;
}

.wordmark span { color: var(--signal); }

.status-pill {
  /* Inline elements clip rounded borders against the line box — the pill's
     bottom edge was cut off once it became a link. */
  display: inline-block;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-mid);
  border: 1px solid var(--rule);
  border-radius: 100px;
  padding: 0.28rem 0.75rem;
}

.status-pill.bad { color: var(--flag); border-color: var(--flag); }

/* ---------- type ---------- */

.kicker {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mid);
  margin: 0 0 0.9rem;
}

.thesis {
  font-family: var(--body);
  font-size: clamp(1.6rem, 4.2vw, 2.6rem);
  line-height: 1.2;
  font-weight: 400;
  letter-spacing: -0.006em;
  margin: 0 0 2rem;
  max-width: 22ch;
}

.thesis em { font-style: italic; color: var(--signal); }

.section-title {
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mid);
  margin: 0 0 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rule);
}

.prose { max-width: 62ch; }
.prose p { margin: 0 0 1rem; }

.small { font-size: 0.9rem; color: var(--ink-mid); }
.mono { font-family: var(--mono); }

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

.launch { margin-bottom: 2.2rem; }

.field-row {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  align-items: stretch;
  max-width: 640px;
}

.domain-input {
  flex: 1 1 260px;
  font-family: var(--mono);
  font-size: 1.05rem;
  padding: 0.95rem 1.05rem;
  color: var(--ink);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 3px;
}

.domain-input::placeholder { color: var(--ink-soft); }
.domain-input:focus { border-color: var(--signal); outline: none; box-shadow: 0 0 0 3px var(--signal-dim); }

.code-input {
  flex: 0 1 150px;
  font-family: var(--mono);
  font-size: 0.95rem;
  padding: 0.95rem 1rem;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 3px;
  color: var(--ink);
}

/* White on #D9480F is 4.30:1 — under the 4.5 small text needs. The buttons use
   the darker ember; it reads as the same colour and clears at 5.65:1. The
   brand --signal is unchanged everywhere it is a rule, a fill or large type. */
.go {
  font-family: var(--mono);
  font-size: 0.82rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 600;
  padding: 0.95rem 1.5rem;
  background: var(--signal-dark);
  color: #fff;
  border: 1px solid var(--signal);
  border-radius: 3px;
  cursor: pointer;
  transition: transform 0.12s ease, background 0.12s ease;
}

.go:hover { background: #1730B4; }
.go:active { transform: translateY(1px); }
.go[disabled] { background: var(--ink-soft); border-color: var(--ink-soft); cursor: not-allowed; }

/* ---------- spec block ---------- */

.spec {
  font-family: var(--mono);
  font-size: 0.78rem;
  line-height: 1.9;
  color: var(--ink-mid);
  margin: 1.4rem 0 0;
}

.spec b { color: var(--ink); font-weight: 600; }

.alert {
  font-family: var(--mono);
  font-size: 0.8rem;
  color: var(--flag);
  border-left: 2px solid var(--flag);
  padding: 0.5rem 0 0.5rem 0.85rem;
  margin: 0 0 1.5rem;
}

/* ---------- the sample grid: one dot per API call ---------- */

.grid-block { margin: 2.6rem 0; }

.grid {
  /* Columns are set inline per run, chosen to divide the call count exactly —
     the block is always a clean rectangle, never two long rows and an orphan
     pair. Wrapping at the viewport made the layout an accident of window
     width. */
  display: grid;
  gap: 7px;
  justify-content: start;
}

.dot {
  width: 17px;
  height: 17px;
  border-radius: 50%;
  border: 1.5px solid var(--rule);
  background: transparent;
  transition: background 0.35s ease, border-color 0.35s ease;
}

.dot.hit          { background: var(--signal); border-color: var(--signal); }
.dot.miss         { background: transparent; border-color: var(--ink-soft); }
.dot.pending_read { background: var(--signal-dim); border-color: var(--signal-dim); }
.dot.failed       { background: repeating-linear-gradient(45deg, var(--flag) 0 2px, transparent 2px 4px); border-color: var(--flag); }
.dot.waiting      { border-style: dashed; border-color: var(--paper-3); }
.dot.inflight     { animation: breathe 1.4s ease-in-out infinite; border-color: var(--signal); }

@keyframes breathe {
  0%, 100% { opacity: 0.25; }
  50%      { opacity: 0.85; }
}

.grid-block .dot { animation: settle 0.5s ease both; }

@keyframes settle {
  from { opacity: 0; transform: scale(0.55); }
  to   { opacity: 1; transform: scale(1); }
}

.legend {
  display: flex;
  gap: 1.2rem;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-mid);
  margin-top: 1rem;
}

.legend i { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 0.4rem; vertical-align: -1px; }
.legend .k-hit    { background: var(--signal); }
.legend .k-miss   { border: 1.5px solid var(--ink-soft); }
.legend .k-fail   { background: var(--flag); }
.legend .k-wait   { border: 1.5px dashed var(--paper-3); }

/* ---------- headline readout ---------- */

.readout {
  display: flex;
  align-items: flex-end;
  gap: clamp(1rem, 4vw, 2.5rem);
  flex-wrap: wrap;
  margin: 0 0 1.2rem;
}

.readout-num {
  font-family: var(--disp);
  font-weight: 700;
  font-size: clamp(3.4rem, 12vw, 6.5rem);
  line-height: 0.86;
  letter-spacing: -0.045em;
  color: var(--signal);
  font-variant-numeric: tabular-nums;
}

.readout-side { padding-bottom: 0.5rem; }

.readout-sub {
  font-size: 1.05rem;
  max-width: 26ch;
  margin: 0 0 0.35rem;
}

.readout-ci {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: var(--ink-mid);
  text-transform: uppercase;
}

/* ---------- findings ---------- */

.findings { list-style: none; margin: 0; padding: 0; max-width: 60ch; }

.findings li {
  border-left: 2px solid var(--signal);
  padding: 0.15rem 0 0.15rem 1rem;
  margin: 0 0 1rem;
  font-size: 1.02rem;
}

.findings li:first-child { font-size: 1.16rem; }

/* ---------- bars ---------- */

.bars { margin: 0; }

/* ---------- leaderboard ----------
   Hierarchy first. Two facts anchor a row — which brand, and in how many
   answers — so those are the only things set in strong ink. The rank is
   navigation and the bar is a scanning aid; both stay quiet.

   The bar spans the gap between the name and its number rather than sitting in
   the middle of the row as an object in its own right. At 12px of solid fill it
   read as a slab separating the two things a reader is trying to pair. At 4px
   it reads as a leader line joining them, which is the job it was always doing.

   Name and value are both two-line cells, so the row has a deliberate rhythm
   instead of one tall element and three short ones. */

.bar-row {
  display: grid;
  grid-template-columns: 2.1rem minmax(0, 13rem) minmax(2rem, 1fr) 3.6rem;
  gap: 0 1rem;
  align-items: baseline;
  padding: 0.62rem 0.5rem 0.62rem 0;
  border-bottom: 1px solid var(--rule);
}

.bar-row:last-child { border-bottom: none; }
.bar-row:hover { background: var(--paper-2); }

.bar-rank {
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--ink-soft);
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.bar-row.top .bar-rank { color: var(--ink-mid); }

.tie {
  color: var(--ink-soft);
  font-size: 0.7rem;
  margin-left: 0.1rem;
}

.bar-name {
  font-family: var(--disp);
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bar-name a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--rule); }
.bar-name a:hover { border-bottom-color: var(--signal); color: var(--signal); }
.bar-domain {
  display: block;
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--ink-mid);
  letter-spacing: 0.01em;
  margin-top: 0.12rem;
}

.bar-track {
  background: var(--paper-3);
  height: 4px;
  border-radius: 2px;
  overflow: hidden;
  align-self: center;
}

/* Filled from the row's own rate, so the column reads as a gradient and the
   cliff edge — where a market stops being one the assistants know — is
   visible without reading a number. Brands never named get no colour at all:
   plasma at zero is a heavy violet, and forty of those would look like an
   alarm rather than an absence. */
.bar-fill { display: block; height: 100%; background: var(--rival); border-radius: 2px; }
.bar-fill.unnamed { background: var(--paper-3); }

.bar-val {
  font-family: var(--mono);
  font-size: 0.92rem;
  color: var(--ink);
  text-align: right;
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}

.bar-pct {
  display: block;
  font-size: 0.78rem;
  color: var(--ink-mid);
  margin-top: 0.12rem;
}

a.status-pill { border-bottom: 1px solid var(--rule); }
a.status-pill:hover { color: var(--signal); border-color: var(--signal); }

.more {
  margin-top: 0.9rem;
  border-top: 1px solid var(--rule);
  padding-top: 0.7rem;
}

.more > summary {
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--ink-mid);
  cursor: pointer;
  list-style: none;
}

.more > summary::-webkit-details-marker { display: none; }
.more > summary::before { content: "+ "; color: var(--ink-soft); }
.more[open] > summary::before { content: "\2212 "; }
.more > summary:hover { color: var(--signal); }
.more .bar-row { opacity: 0.72; }

/* ---------- tables ---------- */

.table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }

.table th {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-mid);
  text-align: left;
  font-weight: 500;
  padding: 0 0.7rem 0.5rem 0;
  border-bottom: 1px solid var(--rule);
}

.table td {
  padding: 0.7rem 0.7rem 0.7rem 0;
  border-bottom: 1px solid var(--paper-3);
  vertical-align: middle;
}

.table tbody tr { transition: background 0.12s ease; }
.table tbody tr:hover { background: var(--paper-2); }

.table .num { font-family: var(--mono); font-size: 0.8rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.table .q { max-width: 34ch; }

.tag {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-mid);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 0.1rem 0.4rem;
  white-space: nowrap;
}

.mini { display: flex; gap: 4px; }
.mini .dot { width: 11px; height: 11px; border-width: 1.2px; }

.own { color: var(--signal); font-weight: 600; }

/* ---------- sections & footer ---------- */

.section { margin: 3.9rem 0 0; }

.cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1.6rem 2.2rem;
}

.note-card {
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 1.1rem 1.2rem;
}

.note-card h3 {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mid);
  margin: 0 0 0.5rem;
  font-weight: 500;
}

.note-card p { margin: 0; font-size: 0.94rem; }

.method {
  margin-top: 3.9rem;
  padding-top: 1.7rem; line-height: 1.62;
  border-top: 2px solid var(--ink);
}

.kv {
  font-family: var(--mono);
  font-size: 0.82rem;
  line-height: 1.95;
  color: var(--ink-mid);
  margin: 0;
}

.kv b { color: var(--ink); font-weight: 500; }

.caveat {
  border-left: 2px solid var(--flag);
  padding-left: 0.85rem;
  color: var(--flag);
  font-family: var(--mono);
  font-size: 0.76rem;
  line-height: 1.7;
  margin: 1rem 0 0;
}

/* ---------- progress page ---------- */

/* Accent text below about 14px uses --signal-dark. The accent is one hue on
   both grounds — #3466B2 on paper at 5.1:1, #6B96D7 on the ink card — because a
   colour dark enough to read on paper caps at 3.7:1 on ink, which is fine for a
   fill and not for a caption. */
.stage {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--signal-dark);
  margin-bottom: 0.6rem;
}

.eta {
  font-family: var(--disp);
  font-weight: 700;
  font-size: clamp(2rem, 7vw, 3.4rem);
  letter-spacing: -0.03em;
  line-height: 1;
  margin: 0 0 0.5rem;
  font-variant-numeric: tabular-nums;
}

.q-list { list-style: none; padding: 0; margin: 0; }

.q-list li {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--ink-mid);
  padding: 0.35rem 0;
  border-bottom: 1px solid var(--paper-3);
}

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

@media (max-width: 560px) {
  body { font-size: 16px; }
  .table .q { max-width: 20ch; }
}

/* ---------- cached-report banner ---------- */

.cached {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-left: 2px solid var(--signal);
  border-radius: 3px;
  padding: 0.7rem 0.9rem;
  margin: 0 0 1.8rem;
  font-family: var(--mono);
  font-size: 0.74rem;
  color: var(--ink-mid);
}

.cached form { margin: 0; display: flex; gap: 0.4rem; }

.go-small {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-weight: 600;
  padding: 0.45rem 0.85rem;
  background: transparent;
  color: var(--signal-dark);
  border: 1px solid var(--signal);
  border-radius: 3px;
  cursor: pointer;
}

.go-small:hover { background: var(--signal); color: #fff; }

/* ---------- prompts excluded from the headline ---------- */

.table tr.excluded td { opacity: 0.55; }

.tag.warn {
  color: var(--flag);
  border-color: var(--flag);
  margin-left: 0.4rem;
}

/* ---------- failed measurement ---------- */

.failure {
  border: 1px solid var(--flag);
  border-left: 4px solid var(--flag);
  border-radius: 3px;
  padding: 1.1rem 1.3rem;
  margin: 0 0 1.8rem;
  background: var(--paper-2);
}

.failure-title {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--flag);
  margin: 0 0 0.6rem;
}

.failure p { margin: 0 0 0.6rem; font-size: 0.96rem; }
.failure p:last-child { margin-bottom: 0; }

/* A number we do not stand behind should not look like a result. */
.readout.void .readout-num { color: var(--ink-soft); text-decoration: line-through; }
.readout.void .readout-sub, .readout.void .readout-ci { color: var(--ink-soft); }

/* ---------- leaderboard ranks ---------- */

.bar-rank {
  font-family: var(--mono);
  font-size: 0.74rem;
  color: var(--ink-soft);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.bar-row.you .bar-rank { color: var(--signal); font-weight: 600; }

.tie { color: var(--ink-soft); }

@media (max-width: 560px) {
  .bar-row { grid-template-columns: 1.8rem minmax(0, 1fr) 3.2rem; gap: 0 0.7rem; }
  .bar-track { display: none; }
}

/* ---------- archive ---------- */

.topnav {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-right: auto;
  padding-left: 1.4rem;
}

.topnav a { color: var(--ink-mid); border: 0; margin-left: 1.1rem; }
.topnav a:first-child { margin-left: 0; }
.topnav a[aria-current] { color: var(--ink); border-bottom: 2px solid var(--signal); padding-bottom: 2px; }
.topnav a:hover { color: var(--signal); }

.table td a { border-bottom: 1px solid var(--signal-dim); }
.bar-name a { color: inherit; border-bottom: 1px solid var(--paper-3); }
.bar-name a:hover { color: var(--signal); border-bottom-color: var(--signal); }
/* ---------- the subject of a brand page ---------- */

.bar-row.you {
  background: var(--tint);
  padding-right: 0.5rem;
}

.bar-row.you .bar-name { font-weight: 600; }
.bar-row.you .bar-track { background: var(--tint-2); }
.bar-row.you:hover { background: var(--tint); }

/* ---------- hero (homepage) ---------- */

.hero {
  max-width: 560px;
  margin: 2.5rem auto 0;
  text-align: center;
}

.hero-thesis {
  font-family: var(--body);
  font-weight: 400;
  font-size: clamp(1.75rem, 4.6vw, 2.5rem);
  line-height: 1.18;
  letter-spacing: -0.004em;
  color: var(--ink);
  margin: 0 0 0.6rem;
}

.hero-sub { font-size: 0.98rem; color: var(--ink-mid); margin: 0 0 1.9rem; }
.hero-launch .field-row { justify-content: center; }

.hero-fine {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--ink-soft);
  margin-top: 0.7rem;
}

.hero-proof {
  font-size: 0.86rem;
  color: var(--ink-mid);
  border-top: 1px solid var(--rule);
  margin-top: 3rem;
  padding-top: 1.2rem;
  line-height: 1.6;
}

.hero-mark { color: var(--signal); }
.hero-dim { color: var(--ink-soft); }
.hero-ask { margin-top: 3.4rem; }

/* Questions a visitor is actually holding, not notes on the method. They read
   as writing rather than as cards, so the page ends in the site's voice
   instead of in a panel of boxes. */
.ask-card h3 {
  font-family: var(--body);
  font-size: 1rem;
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 0.4rem;
}

.ask-card p {
  margin: 0;
  font-size: 0.94rem;
  color: var(--ink-mid);
  line-height: 1.55;
}

/* ---------- site footer ---------- */

.site-footer {
  border-top: 1px solid var(--rule);
  margin-top: 4rem;
  padding: 1.4rem 0 2rem;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.2rem;
}

.site-footer a { color: var(--ink-soft); border: 0; }
.site-footer a:hover { color: var(--signal); }

.legal { max-width: 640px; }
.legal h3 {
  font-family: var(--disp);
  font-size: 0.95rem;
  margin: 1.8rem 0 0.4rem;
  color: var(--ink);
}
.legal p { margin: 0 0 0.8rem; }

/* Visible to screen readers, not to the page. Its absence is why the market
   names inside the rotation tabs rendered as a wall of text across the
   header. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- the spread (homepage proof) ---------- */

.panels { max-width: 560px; margin: 2.8rem auto 0; position: relative; }

/* Floated to the top right of the block so it lands on the market title's
   line: the control sits beside the thing it controls, and no header row is
   left holding the space the kicker used to fill. */
.panels-nav {
  display: flex;
  gap: 5px;
  position: absolute;
  top: 0.5rem;
  right: 0;
}

/* Segmented progress, like a story player: each segment is a market, the
   filling one is playing, and any of them can be clicked to take over. */
.panels-tab {
  background: none;
  border: 0;
  padding: 6px 0;
  cursor: pointer;
  line-height: 0;
}

.panels-bar {
  display: block;
  width: 22px;
  height: 3px;
  border-radius: 2px;
  background: var(--paper-3);
  overflow: hidden;
}

.panels-bar-fill {
  display: block;
  width: 0;
  height: 3px;
  background: var(--signal);
  border-radius: 2px;
}

@keyframes panelFill { from { width: 0; } to { width: 100%; } }

/* The segment fills over one dwell, and the fill finishing is what advances
   the panel — no timer to drift out of step with what the bar shows. Pausing
   the animation therefore pauses the rotation, exactly and for free. */
.panels-tab.on .panels-bar-fill {
  animation: panelFill var(--panel-ms, 6000ms) linear forwards;
}

.panels:hover .panels-tab.on .panels-bar-fill,
.panels:focus-within .panels-tab.on .panels-bar-fill { animation-play-state: paused; }

/* Once the visitor picks a market, it is theirs: no animation, no advancing. */
.panels.taken .panels-tab.on .panels-bar-fill { animation: none; width: 100%; }

@media (prefers-reduced-motion: reduce) {
  .panels-tab.on .panels-bar-fill { animation: none; width: 100%; }
}
.panels-tab.done .panels-bar { background: var(--rival); }
.panels-tab:hover .panels-bar { background: var(--ink-soft); }
.panels-tab:focus-visible { outline: 2px solid var(--signal); outline-offset: 3px; }

.panel-title {
  font-family: var(--body);
  font-weight: 400;
  font-size: 1.15rem;
  padding-right: 9rem;          /* room for the tabs */
  margin: 0 0 0.55rem;
  color: var(--ink);
}

.panel-title a { color: var(--ink); border-bottom-color: var(--paper-3); }
.panel-title a:hover { color: var(--signal); border-bottom-color: var(--signal); }

.spread {
  /* One grid for the whole ledger, not one per row. When each row was its own
     grid, the bar column was sized by that row's own content, so a full 36/36
     bar could render shorter than a 30/36 bar in a roomier row. Shared columns
     plus a fixed bar width make that impossible. */
  display: grid;
  grid-template-columns: minmax(6rem, 1fr) 120px max-content;
  align-items: center;
  column-gap: 0.9rem;
  background: #fff;
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 0.15rem 1rem;
  font-family: var(--mono);
  font-size: 0.74rem;
  color: var(--ink);
}

.spread-row { display: contents; }

.spread-row > * {
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--paper-2);
  min-width: 0;
}

.spread-row:last-child > * { border-bottom: 0; }

/* The whole row is the link, but it is laid out by the shared grid, so the
   hover has to be painted on the cells rather than the anchor. */
a.spread-row { color: inherit; border: 0; text-decoration: none; }
a.spread-row:hover > * { background: var(--paper-2); }
a.spread-row:hover .spread-domain { color: var(--signal); }
a.spread-row:focus-visible > * { background: var(--paper-2); }

.spread-domain { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spread-track { position: relative; }

.spread-track::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 6px;
  margin-top: -3px;
  background: var(--paper-2);
  border-radius: 3px;
}

/* The visitor's row is the one unfilled measurement on the page. */
.spread-empty::before {
  background: none;
  border: 1.5px dashed var(--signal-dim);
}

/* Colour is set per row from the rate, so the ramp is computed rather than
   picked. It carries no information the number does not already give — it is
   there to make the order readable at a glance, which is why the section has
   no legend: a scale that only restates the printed figure does not need
   explaining. */
.spread-fill {
  display: block;
  position: relative;
  height: 6px;
  border-radius: 3px;
}
.spread-count { white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums; }

.spread-row.you .spread-domain,
.spread-row.you .spread-count,
.spread-row.you .spread-count b { color: var(--signal); }

.spread-row.you .spread-track::before { background: transparent; }
/* The visitor's missing bar is where the invitation goes: it keeps the count
   column narrow (it is sized by its widest cell, so a sentence in there pushed
   every row's number away from its bar) and puts the arrow in the column the
   eye is already scanning. */
.spread-hint {
  color: var(--signal-dark);
  font-size: 0.72rem;
  white-space: nowrap;
}
.spread-blank { border-bottom: 1.5px dashed var(--signal); }

.spread-foot {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--ink-soft);
  margin: 0.8rem 0 0;
  text-align: center;
}

.spread-foot a { color: var(--ink-soft); }
.spread-foot a:hover { color: var(--signal); }

@media (max-width: 560px) {
  .spread { grid-template-columns: minmax(0, 1fr) max-content; }
  .spread-track { display: none; }
  /* Tabs drop under the title rather than crowding it on a narrow screen. */
  .panels-nav { position: static; margin: 0 0 0.5rem; }
  .panel-title { padding-right: 0; }
}

/* ---------- homepage market panels ---------- */

.panel { margin: 0; }

/* "of 34" beside a rank: context, not the number itself. */
.bar-of { color: var(--ink-soft); }

/* ---------- market map (mentions against prominence) ---------- */

.mapfig { margin: 1.1rem 0 0.8rem; position: relative; }
.map { width: 100%; height: auto; display: block; overflow: visible; }

/* Median lines, not axes: they cut the field into quadrants without implying
   a fitted relationship the data has not earned. */

/* The whole dot is the target, including the middle of a hollow one: a ring
   drawn with fill:none has no interior to hover, so pointing at the centre of
   a caveated brand did nothing. Paper fill keeps it reading as hollow while
   giving it a surface. */
.map-pt circle {
  fill: var(--ink-mid);
  stroke: var(--paper);
  stroke-width: 1.5;
  transition: fill 0.12s ease, stroke 0.12s ease;
}

.map-pt.caveat circle { fill: var(--paper); stroke: var(--rival); stroke-width: 1.6; }

/* Hover lives on the group, not the link. Brands below the evidence floor for
   their own page have no anchor to hover, and they used to sit there inert. */
.map-pt:hover circle,
.map-pt:focus-within circle { fill: var(--signal); stroke: var(--paper); }
.map-pt.caveat:hover circle,
.map-pt.caveat:focus-within circle { fill: var(--signal); stroke: var(--signal); }

.map-pt a { border: 0; }

.map-label {
  font-family: var(--mono);
  font-size: 10px;
  fill: var(--ink);
  pointer-events: none;
}

/* The subject of a brand page: bigger, ember, and never a link to itself. */
.map-pt.subject circle { fill: var(--signal); stroke: var(--paper); stroke-width: 2; }
.map-pt.subject.caveat circle { fill: var(--paper); stroke: var(--signal); stroke-width: 2.2; }
.map-label.own { fill: var(--signal); font-weight: 600; }

@media (max-width: 620px) {
  /* Labels and axis text are sized in viewBox units, so they shrink with the
     canvas on a phone. Scaling them back up keeps the names readable at the
     cost of a few labels the placer will have dropped anyway. */
  .map-label { font-size: 13px; }
}

.finding {
  border-left: 2px solid var(--signal);
  padding-left: 0.9rem;
  margin: 1.2rem 0 0.6rem;
}

.finding-stat {
  display: block;
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--ink-soft);
  margin-top: 0.35rem;
  line-height: 1.5;
}

/* Only points that link anywhere should look clickable: brands below the
   evidence floor for their own page have nothing to open. */
.map-pt { cursor: default; }
.map-pt:has(a) { cursor: pointer; }

/* ---------- map tooltip ---------- */

.map-tip {
  position: absolute;
  z-index: 5;
  transform: translate(-50%, calc(-100% - 14px));
  min-width: 9rem;
  max-width: 15rem;
  padding: 0.5rem 0.7rem;
  background: var(--ink);
  color: var(--paper);
  border-radius: 7px;
  box-shadow: 0 6px 18px rgba(25, 23, 19, 0.18);
  pointer-events: none;
}

.map-tip.below { transform: translate(-50%, 14px); }

.map-tip::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -5px;
  width: 10px;
  height: 10px;
  margin-left: -5px;
  background: var(--ink);
  transform: rotate(45deg);
  border-radius: 1px;
}

.map-tip.below::after { bottom: auto; top: -5px; }

.map-tip p { margin: 0; }

.map-tip-name {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.82rem;
  line-height: 1.25;
}

.map-tip-count {
  font-family: var(--mono);
  font-size: 0.9rem;
  margin-top: 0.15rem !important;
  font-variant-numeric: tabular-nums;
}

.map-tip-meta {
  font-family: var(--mono);
  font-size: 0.66rem;
  opacity: 0.72;
  margin-top: 0.25rem !important;
  line-height: 1.4;
}

.map-tip-caveat {
  font-family: var(--mono);
  font-size: 0.64rem;
  color: var(--signal-dim);
  margin-top: 0.3rem !important;
  padding-top: 0.3rem !important;
  border-top: 1px solid rgba(250, 247, 240, 0.18);
  line-height: 1.4;
}

@media (max-width: 560px) {
  .map-label { font-size: 11px; }
}

/* ---------- operator review ---------- */

.admin-act { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }

.admin-act select {
  font-family: var(--mono);
  font-size: 0.72rem;
  padding: 0.25rem 0.3rem;
  border: 1px solid var(--rule);
  border-radius: 5px;
  background: var(--paper);
  color: var(--ink);
  max-width: 11rem;
}

.ops-head {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-mid);
  margin: 1.4rem 0 0.4rem;
}

.ops-tick { width: 1.6rem; }
.ops-tick input { accent-color: var(--signal); }

/* ---------- report: the verdict treatment ---------- */
/* The finding is a sentence, not a dial. findings[0] already states the
   result in the report's own words for every case — success, middling,
   failure — so the hero says it once instead of a numeral, a dot grid and a
   findings entry all repeating one number. */

/* The hero moved to .brandtitle (see "report: the title page" below). The
   void treatment moved with it: a broken measurement must still read as struck
   through, and scoping it to the old class would have silently dropped that. */
.brandtitle.void { color: var(--ink-soft); text-decoration: line-through; }

/* The two numbers people actually quote — rank and the gap to the neighbour —
   which the old hero never stated. */

.findings.sub li { font-size: 0.95rem; }
.findings.sub li:first-child { font-size: 0.95rem; }

/* Report leaderboard carries more weight than the homepage panels: the bar is
   the page's main picture, so it gets the heavier line. Scoped so the shared
   bar classes keep their metrics everywhere else. */
.bars.heavy .bar-track { height: 9px; border-radius: 1px; }
.bars.heavy .bar-fill { border-radius: 1px; }
.bars.heavy .bar-row { padding: 0.7rem 0.5rem 0.7rem 0; }
.bars.heavy .bar-name { font-size: 0.95rem; }

/* Everything below the finding folds away. Native details, no script. */
details.fold { border-top: 1px solid var(--rule); }
details.fold:last-of-type { border-bottom: 1px solid var(--rule); }
details.fold > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: 1.05rem 0;
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.95rem;
}
details.fold > summary::-webkit-details-marker { display: none; }
details.fold > summary .hint {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.74rem;
  color: var(--ink-soft);
  text-align: right;
}
details.fold > summary::after {
  content: "+";
  font-family: var(--mono);
  color: var(--ink-soft);
  margin-left: 0.4rem;
}
details.fold[open] > summary::after { content: "–"; }
details.fold .fold-inner { padding: 0.2rem 0 1.8rem; }

/* Questions as a reading list, not a spreadsheet. The question is the content
   — serif, full width — with its intent as a quiet mono note beneath and the
   count as a chip, so the eye reads question then result, never a grid. */
.qlist { list-style: none; margin: 0; padding: 0; }
.qlist li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.2rem;
  padding: 0.72rem 0;
  border-top: 1px solid var(--rule);
}
.qlist li:last-child { border-bottom: 1px solid var(--rule); }
.qtext { font-style: italic; font-size: 0.98rem; line-height: 1.45; }
.qmeta {
  display: block;
  font-style: normal;
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--ink-soft);
  margin-top: 0.15rem;
}
.qchip {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 0.84rem;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 0.08rem 0.5rem;
}

/* ---------- run page: the identity card ---------- */
/* The card starts as the domain the person typed and assembles downward as the
   run settles each fact, then stays as the header the questions play beneath.
   Nothing shown here is raw page text — only fields the run has crystallised. */

.runsteps {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin: 0.4rem 0 1.1rem;
  padding: 0;
  list-style: none;
}
.runsteps .step {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.55rem;
  border-radius: 999px;
  background: var(--paper-2);
  border: 1px solid transparent;
  font-family: var(--disp);
  font-size: 0.735rem;
  font-weight: 500;
  color: var(--ink-soft);
  transition: background 0.35s, color 0.35s;
}
.runsteps .step.done { color: var(--ink-mid); background: var(--paper-3); }
.runsteps .step.done .sl::before { content: "✓ "; color: var(--signal); font-weight: 600; }
.runsteps .step.now { color: #fff; background: var(--ink); border-color: var(--ink); font-weight: 600; }

.idcard {
  /* Flat, faintly violet-tinted ink — plasma's own dark end — rather than a
     glowing dark UI card. Near-square, to match the site's rules and bars. */
  background: var(--card);
  color: var(--card-text);
  border-radius: 3px;
  padding: 1.15rem 1.15rem 0;
  position: relative;
  overflow: hidden;
}

/* THE SPECTRUM: the run's progress, drawn as the plasma ramp along the bottom
   edge — violet at the start, ember by the end. It sits directly above the
   elapsed/ETA/spend line so colour and time read together, and it leaves the
   top edge clean for the identity, which is the first thing to read. The step
   chips above already carry stage, so a second rail up there would be a
   redundant progress signal. The gradient itself is written by JS from
   Archive.PLASMA, so it can never drift from the boards. */
.spectrum-track {
  height: 4px;
  background: rgba(240, 240, 240, 0.1);
  margin: 1.15rem -1.15rem 0;
}
.spectrum-track i {
  display: block;
  height: 100%;
  width: 0;
  transition: width 0.6s linear;
}
.idcard .id { position: relative; }

.idrow {
  /* Every row is laid out only by these rules — no inherited centring, no
     max-width. A stray .hero from the homepage once won this cascade and
     pushed the brand row out of the label column. */
  text-align: left;
  max-width: none;
  margin-left: 0;
  margin-right: 0;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 0.5s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.45s ease, margin 0.5s;
}
.idrow.in { max-height: 5rem; opacity: 1; }
.idrow + .idrow.in { margin-top: 0.62rem; }
.idrow .k {
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--card-soft);
  width: 5.4rem;
  flex-shrink: 0;
}
.idrow .v {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 1.02rem;
  line-height: 1.35;
  min-width: 0;
}
.idrow.brandline .v { font-size: 1.16rem; color: var(--ember); }
.idrow.brandline .v em { font-style: normal; }
.idrow.domain .v { font-family: var(--mono); font-weight: 400; font-size: 0.95rem; }
.idrow .tagl { font-family: var(--mono); font-weight: 400; font-size: 0.72rem; color: var(--card-soft); }

.idcard .cursor {
  display: inline-block;
  width: 2px;
  height: 0.85em;
  background: var(--ember);
  vertical-align: -1px;
  margin-left: 3px;
  animation: idblink 1s steps(1) infinite;
}
@keyframes idblink { 50% { opacity: 0; } }

.idnote {
  font-size: 0.84rem;
  line-height: 1.52;
  color: var(--card-mid);
  margin: 0.9rem 0 0;
  position: relative;
  max-height: 6rem;
  opacity: 1;
  overflow: hidden;
  transition: max-height 0.5s, opacity 0.45s, margin 0.5s;
}
.idnote.out { max-height: 0; opacity: 0; margin-top: 0; }

.qzone {
  position: relative;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 0.6s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.5s;
}
.qzone.in {
  max-height: none;
  opacity: 1;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(246, 241, 231, 0.14);
}

/* The dwell bar: each question's minimum readable time. Answers can arrive in
   bursts, so this is what stops the display outrunning the reader. */

/* The board forms inside the card. Bars take plasma from the live hit rate —
   the same meaning colour carries on every finished page — and the whole thing
   is marked provisional, because it is. */
.boardhead {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin: 1rem 0 0.3rem;
  padding-top: 0.85rem;
  border-top: 1px solid rgba(240, 240, 240, 0.16);
}
.boardhead .sec {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--card-mid);
  margin: 0;
}
.boardhead .prov { font-family: var(--mono); font-size: 0.63rem; color: var(--ember); }
/* A question, then its bar underneath — not a four-column row.

   Beside the text the bar was the first thing a narrow column dropped: below
   430px the grid collapsed and `.utrack { display: none }` hid it outright, so
   a phone showed no motion at all during the one minute the page exists for.
   On its own line it survives any width down to 320px.

   Questions wrap to two lines and then clamp. A single nowrap line cut most
   real ones mid-phrase — "What are good alternatives for managing team…" —
   and the question is the content here, not furniture. Two lines shows nearly
   all of them whole while still bounding the card however wordy a market is. */
.qrow {
  padding: 0.55rem 0;
  border-bottom: 1px solid rgba(240, 240, 240, 0.09);
  opacity: 0.42;
  transition: opacity 0.4s;
}
.qrow.done, .qrow.here { opacity: 1; }
.qrow .utop {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.8rem;
}
.qrow .un {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--card-soft);
  margin-right: 0.45rem;
}
.qrow.here .un { color: var(--ember); }
.qrow .ut {
  font-size: 0.84rem;
  line-height: 1.35;
  color: var(--card-mid);
  flex: 1;
  min-width: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.qrow.here .ut { color: var(--card-text); font-family: var(--disp); font-weight: 600; }
.qrow .uc {
  font-family: var(--mono);
  font-size: 0.68rem;
  color: var(--card-mid);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
  padding-top: 0.08rem;   /* stays level with the first line of a wrapped question */
}
.qrow .utrack {
  display: block;
  height: 6px;
  background: rgba(240, 240, 240, 0.13);
  border-radius: 1px;
  overflow: hidden;
  margin-top: 0.4rem;
}
.qrow .utrack i {
  display: block;
  height: 100%;
  width: 0;
  /* colour comes from the plasma ramp in JS; width is eased per frame */
}

.runfoot {
  display: flex;
  justify-content: space-between;
  gap: 0.8rem;
  flex-wrap: wrap;
  margin-top: 1rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--ink-soft);
}
.runfoot .stay { flex-basis: 100%; }

@media (min-width: 560px) {
  
  .idrow.brandline .v { font-size: 1.28rem; }
  .idcard { padding: 1.4rem 1.5rem 0; }
  .spectrum-track { margin: 1.3rem -1.5rem 0; }
  .runfoot .stay { flex-basis: auto; }
}
@media (prefers-reduced-motion: reduce) {
  .idrow, .idnote, .qzone, .qzone .q, 
  .idcard .cursor { animation: none; }
}

/* The final pass — reading, resolving, counting.
   The questions are all asked by now and the board has stopped moving, which
   is exactly when a still card reads as a hung one. Reading has a real count
   behind it, so it gets a real bar; the stages after it are short and have
   nothing countable, so they get a travelling shimmer rather than an invented
   percentage. */
.finalpass {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 0.5s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.45s, margin 0.5s;
}
.finalpass.in {
  max-height: 5rem;
  opacity: 1;
  margin-top: 0.9rem;
  padding-top: 0.85rem;
  border-top: 1px solid rgba(240, 240, 240, 0.16);
}
.finalpass .fprow {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin-bottom: 0.45rem;
}
.finalpass .fplabel {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.78rem;
  color: var(--card-text);
}
.finalpass .fpcount {
  font-family: var(--mono);
  font-size: 0.68rem;
  color: var(--card-soft);
  font-variant-numeric: tabular-nums;
}
.finalpass .fptrack {
  height: 5px;
  background: rgba(240, 240, 240, 0.13);
  border-radius: 1px;
  overflow: hidden;
}
.finalpass .fptrack i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--ember);
  /* width eased per frame in JS, as everywhere else on this card */
}
.finalpass.pulsing .fptrack {
  background: rgba(240, 240, 240, 0.13);
}
.finalpass.pulsing .fptrack i {
  background: linear-gradient(90deg,
    rgba(241, 113, 47, 0.15) 0%,
    rgba(241, 113, 47, 0.15) 30%,
    var(--ember) 50%,
    rgba(241, 113, 47, 0.15) 70%,
    rgba(241, 113, 47, 0.15) 100%);
  background-size: 260% 100%;
  animation: fpsweep 1.5s linear infinite;
}
@keyframes fpsweep {
  from { background-position: 130% 0; }
  to   { background-position: -130% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .finalpass { transition: none; }
  .finalpass.pulsing .fptrack i { animation: none; background: var(--ember); opacity: 0.5; }
}

/* ---------- report: the title page ----------
   The market is the volume this report belongs to, the brand is the title, and
   one sentence is the finding. Three elements, ranged left so the eye has a
   single margin to follow — centred type makes every line start somewhere
   different, which is real work in a narrow column.

   Two earlier problems are fixed here by structure rather than by styling.
   The market used to sit inside a mono kicker at 0.78rem: the smallest type on
   a page whose whole subject it was. And the run's identity used to sit on its
   own line directly above the board caption, so two wordy mono lines stacked
   into one block of small print that nobody read. The identity now folds into
   the volume line, and the board caption is gone entirely — a column of ranks
   beside a column of counts says "leaderboard" without being told. */

.brandtitle {
  font-family: var(--body);
  font-weight: 400;
  font-size: clamp(2.1rem, 8vw, 2.5rem);
  line-height: 1;
  letter-spacing: -0.035em;
  margin: 0 0 0.75rem;
  overflow-wrap: anywhere;   /* long brand names must not overflow */
}

.finding {
  font-size: clamp(1rem, 3.6vw, 1.08rem);
  line-height: 1.42;
  margin: 0 0 2.2rem;
  max-width: 26ch;
  color: var(--ink);
  border-left: 2px solid var(--signal);
  padding-left: 0.85rem;
}
.finding .q {
  display: block;
  margin-top: 0.22rem;
  font-size: 0.93em;
  color: var(--ink-mid);
}

/* The denominator sits under the board as a footnote rather than over it as a
   caption. It carries the question count too: with short question sets in the
   archive, "18 answers to 3 neutral questions" is the honest shape of the
   evidence, and it reads as thinner than 36 without anyone explaining why. */
.boardfoot {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--ink-mid);
  letter-spacing: 0.03em;
  margin: 1rem 0 0;
}

@media (min-width: 700px) {
  /* Desktop is the same column with more scale, not a different layout: one
     column reads as a document at any width, two would make it a dashboard. */
  .brandtitle { font-size: 2.9rem; }
  .finding { font-size: 1.14rem; max-width: 28ch; }
}

/* ---------- market page: the keyword title ----------
   This page has to rank in search, so the phrase cannot be dropped for
   elegance. It is split instead: the h1 still contains "Best {label},
   according to AI assistants" for a crawler, while a reader sees a title with
   a quiet qualifier under it. */
.brandtitle .qual {
  display: block;
  font-size: 0.42em;
  letter-spacing: -0.01em;
  color: var(--ink-mid);
  margin-top: 0.5rem;
  line-height: 1.3;
}
@media (min-width: 700px) { .brandtitle .qual { font-size: 0.38em; } }

/* ---------- brand page: every market it appears in ----------
   A brand joins a market's registry whenever an answer names it, so this list
   grows from other people's runs without the brand ever being measured. That
   makes it the most honest browse path on the site, and it was buried in the
   method fold at the bottom of the page. */
.alsoin {
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  padding: 0.9rem 0 1rem;
  margin: 0 0 2.2rem;
}
.alsoin-lab {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-mid);
  margin: 0 0 0.6rem;
}
.alsoin-list { list-style: none; margin: 0; padding: 0; }
.alsoin-list li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: 0.32rem 0;
}
.alsoin-list a {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: -0.012em;
  color: var(--ink);
  text-decoration: none;
}
.alsoin-list a:hover { color: var(--signal); }
.alsoin-list .ct {
  font-family: var(--mono);
  font-size: 0.74rem;
  color: var(--ink-mid);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.alsoin-all {
  display: inline-block;
  margin-top: 0.7rem;
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.83rem;
  color: var(--signal-dark);
  text-decoration: none;
}

/* The break row, used only when the subject sits far below the cut. It states
   how many brands are skipped rather than eliding them with an ellipsis — an
   earlier version did that and readers stopped to work out what it meant. */
.bar-gap {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--ink-mid);
  letter-spacing: 0.03em;
  margin: 0.55rem 0;
  padding-left: 2.2rem;
  position: relative;
}
.bar-gap::before {
  content: "";
  position: absolute;
  left: 0.55rem;
  top: 50%;
  width: 1rem;
  border-top: 1px dashed var(--rule);
}

/* The card header: what the run is doing, and how long is left.
   The time remaining used to sit outside the card in 0.72rem mono, below the
   ink, at the same weight as the sentence beside it — the quietest element on
   a page whose entire job is the wait. */
.cardtop {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin: -0.15rem 0 0.95rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid rgba(240, 240, 240, 0.16);
}
.cardtop .doing {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.82rem;
  color: var(--card-text);
  display: flex;
  align-items: center;
  gap: 0.45rem;
  min-width: 0;
}
.cardtop .doing i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ember);
  flex-shrink: 0;
  animation: doingpulse 1.6s ease-in-out infinite;
}
@keyframes doingpulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
/* A ring and time elapsed, in place of a countdown.

   The ring is drawn with strokes and no fill; without these rules an SVG circle
   renders as a solid black disc, which is exactly what shipped when this block
   silently failed to apply. The percentage sits inside the ring, so the ring
   needs to be a positioned box. */
.cardtop .clockslot {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  flex-shrink: 0;
}
.cardtop .ring {
  position: relative;
  width: 46px;
  height: 46px;
  flex-shrink: 0;
  line-height: 0;
}
.cardtop .ring svg {
  display: block;
  width: 46px;
  height: 46px;
  transform: rotate(-90deg);   /* start the arc at twelve o'clock */
}
.cardtop .ring circle { fill: none; }
.cardtop .ring-bg { stroke: rgba(240, 240, 240, 0.16); stroke-width: 3.5; }
.cardtop .ring-fg {
  stroke: var(--ember);
  stroke-width: 3.5;
  stroke-linecap: round;
  /* no CSS transition: the frame loop eases this itself, and a transition on
     top of an eased value fights it and lags behind */
}
.cardtop .ring b {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  /* 0.82rem sets "100%" at about 31px inside 37px of clear space — the largest
     that fits the ring without crowding the stroke. */
  font-size: 0.82rem;
  letter-spacing: -0.02em;
  font-weight: 600;
  line-height: 1;
  color: var(--card-text);
}

.cardtop .clock {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--card-text);
  white-space: nowrap;
}
.cardtop .clock small {
  font-family: var(--disp);
  font-weight: 400;
  font-size: 0.68rem;
  color: var(--card-soft);
  margin-left: 0.35rem;
  letter-spacing: 0;
}
@media (prefers-reduced-motion: reduce) {
  .cardtop .doing i { animation: none; opacity: 1; }
  /* the elapsed counter is what guarantees motion here */
}

/* The board's expand controls.
   Each is the table's next row: same grid, same hairline, so opening one reads
   as the list continuing rather than as a widget below it. The rank column
   carries the count in ember where a number would be. Previously these were
   plain grey summaries that looked like throwaway text rather than something
   to click. */
.expandrow {
  display: grid;
  /* the rank column and gap must match .bar-row exactly, or the "+3" sits a
     few pixels off the numbers directly above it */
  grid-template-columns: 2.1rem minmax(0, 1fr) auto;
  gap: 0 1rem;
  align-items: center;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--rule);
  cursor: pointer;
  list-style: none;
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.88rem;
  color: var(--ink-mid);
}
.expandrow::-webkit-details-marker { display: none; }
.expandrow:hover { color: var(--signal); }
.expandrow .plus {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--signal-dark);
  text-align: right;
}
.expandrow .hint {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.72rem;
  color: var(--ink-soft);
  white-space: nowrap;
}
details[open] > .expandrow .plus { color: var(--ink-soft); }
@media (max-width: 460px) {
  .expandrow { grid-template-columns: 1.8rem minmax(0, 1fr); gap: 0 0.7rem; }
  .expandrow .hint { display: none; }   /* the label already says it */
}

/* The board's notes, in each page's methodology section. They used to print
   under the table itself, where a technical paragraph is least likely to be
   read and most likely to look like clutter. */
.method-note {
  font-size: 1.04rem;
  color: var(--ink-mid);
  line-height: 1.65;
  margin: 0 0 0.85rem; max-width: 62ch;
}
.method-note b { color: var(--ink); font-weight: 600; }

/* ---------- the prominence chart ----------
   Replaced: two paragraphs of grey prose, four crossing lines, rotated axis
   titles, and ticks at roughly 3.3:1 against the paper. The rotated y-title
   even carried an arrow, which rotate(-90) spun round to point left. */

.chartsec { margin-top: 2.6rem; }

.chart-finding {
  font-size: clamp(1.15rem, 3.4vw, 1.5rem);
  line-height: 1.35;
  margin: 0 0 1.3rem;
  max-width: 30ch;
  letter-spacing: -0.012em;
}

/* The legend is HTML, not SVG: anything inside the viewBox shrinks with the
   chart, and at phone width an axis title becomes unreadable. */
.charthead {
  border-bottom: 1px solid var(--rule-2);
  padding-bottom: 0.9rem;
  margin-bottom: 1.4rem;
}
.charthead .chart-finding { margin-bottom: 0.9rem; }

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem 2rem;
  margin: 0;
  font-family: var(--disp);
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--ink);
}
.chart-legend span { display: flex; align-items: center; gap: 0.45rem; }
.chart-legend i {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 1.05rem;
  line-height: 1;
  color: var(--signal);
  font-style: normal;
}

/* The zone captions are prose about the picture, so they live in HTML beneath
   it. Inside the SVG they collided with whatever followed the figure, and any
   fix there is arithmetic against a viewBox rather than layout. */
.zonecap {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.5rem;
  margin: 0.9rem 0 0;
  padding-top: 0.8rem;
  border-top: 1px solid var(--rule);
}
@media (min-width: 620px) { .zonecap { grid-template-columns: 1fr 1fr; gap: 2rem; } }
.zonecap div {
  font-family: var(--disp);
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--ink-mid);
}
.zonecap div span {
  display: block;
  font-weight: 400;
  font-size: 0.8rem;
  color: var(--ink-soft);
}
@media (min-width: 620px) { .zonecap .r { text-align: right; } }

/* Ticks in the display face at 600: mono earns its place in a table where
   figures align in columns, not around a chart at 12px. Counts, not
   percentages — the same unit as the leaderboard the reader just left. */
.map-tick {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 13px;
  fill: var(--ink);
}
/* The rank ticks are gone — the axis line runs grey-to-ember instead, and these
   two words say which end is which. Same face and weight the ticks used, so the
   chart's typography does not change. */
.map-end {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 11.5px;
  fill: var(--ink-soft);
}

/* The chart's own note: a bordered control sized to its label, so it reads as
   part of the figure. Rendered as a full-width fold it was indistinguishable
   from the section heading beneath it. */
.chartfold { margin-top: 1rem; }
.chartfold > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  width: auto;
  background: var(--paper);
  cursor: pointer;
  list-style: none;
  font-family: var(--disp);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--ink-mid);
  border: 1px solid var(--rule-2);
  border-radius: 2px;
  padding: 0.34rem 0.7rem;
}
.chartfold > summary::marker { content: ""; }
.chartfold > summary::-webkit-details-marker { display: none; }
.chartfold > summary::after { content: "+"; color: var(--signal); font-family: var(--mono); }
.chartfold[open] > summary::after { content: "\2212"; }
.chartfold > summary:hover { border-color: var(--signal); color: var(--signal); }
.chartfold-body { margin-top: 0.9rem; max-width: 70ch; }

/* The section that follows a chart needs a real break, or it reads as the next
   item in a list of folds rather than a new part of the page. */
.chartsec + .section, .chartsec + .fold {
  margin-top: 3rem;
  padding-top: 1.3rem;
  border-top: 2px solid var(--ink);
}

/* The breadcrumb: the chain a page hangs from, replacing a "volume" label.
   Market pages carried "The archive", which was identical on all 34 of them
   and named something a reader has no model of. On a brand page the market
   segment is also the route to the full leaderboard, so it carries the brand
   count — which is what the old link at the foot of the board was advertising,
   sitting awkwardly next to two expanders with nearly the same intent. */
.crumb {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mid);
  margin: 0 0 0.85rem;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  line-height: 1.5;
}
.crumb a { color: var(--ink); text-decoration: none; box-shadow: inset 0 -1px 0 var(--signal); }
.crumb a:hover { color: var(--signal); }
.crumb .sep { color: var(--rule-2); }
.crumb .n { color: var(--ink-soft); letter-spacing: 0.06em; }

/* Brands named in none of the answers: a footnote, not an expander. */
.zeronote {
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--ink-mid);
  line-height: 1.8;
  margin: 0.9rem 0 0;
}
.zeronote b { color: var(--ink); font-weight: 400; }

/* The "not ranked" gutter: brands checked against the Tranco list and not
   found. Their websites are known to be outside the top million, which is a
   measurement — so they belong on the chart, at the small end. A subdomain or
   an unchecked domain is a different thing and stays off it entirely: an
   unknown rank cannot be placed, and putting Microsoft Teams at the small end
   would invert the relationship the chart exists to show. */
.map-gutter { stroke: var(--rule-2); stroke-width: 1; stroke-dasharray: 2 4; }
.map-gutter-lab {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 11.5px;
  fill: var(--ink-soft);
}
.map-pt.below circle { fill: var(--ink-soft); }

/* ---------- brand page: two questions, side by side ----------
   The page stated the count in a sentence, again in the leaderboard's
   highlighted row, and a third time in the chart, while how a brand is
   *described* sat at the very bottom. Both are findings; the sentence that
   duplicated the first one is gone. The denominators differ — mentions from
   the market's neutral answers, framing only from questions naming this brand
   — so each cell states its own. */
.pair {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.1rem;
  margin: 0 0 2rem;
  border-top: 2px solid var(--ink);
  border-bottom: 1px solid var(--rule-2);
  padding: 1.1rem 0 1.2rem;
}
@media (min-width: 600px) { .pair { grid-template-columns: 1fr 1fr; gap: 2.4rem; } }
.pair .q {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-mid);
  margin: 0 0 0.45rem;
}
.pair .a {
  font-family: var(--body);
  font-size: 1.72rem;
  line-height: 1.12;
  letter-spacing: -0.025em;
  margin: 0 0 0.3rem;
}
.pair .a b { font-weight: 600; }
.pair .a .of { color: var(--ink-soft); }
.pair .sub { font-size: 1.04rem; color: var(--ink-mid); margin: 0.4rem 0 0; max-width: 62ch; line-height: 1.65; }
@media (min-width: 600px) {
  .pair .right { border-left: 1px solid var(--rule); padding-left: 2.4rem; }
}
@media (max-width: 599px) {
  .pair .right { border-top: 1px solid var(--rule); padding-top: 1.1rem; }
}

/* One cell per direct answer. Six or twelve answers is too few for a
   percentage — "83% recommended" is false precision on a sample this size — so
   the reader counts them instead. */
.pair .cells { display: flex; gap: 4px; align-items: center; margin-top: 0.45rem; flex-wrap: wrap; }
.pair .cells u { width: 18px; height: 9px; border-radius: 2px; text-decoration: none; }
.pair .cells u.rec { background: var(--signal); }
.pair .cells u.neu { background: var(--ink-soft); }
.pair .cells u.neg { background: var(--flag); }
/* An answer that named the brand in the question and never mentioned it in
   the reply. Drawn as a dashed outline it read as an empty slot, so six answers
   looked like five and the sentence disagreed with the blocks. Filled now:
   lighter than "mentioned", solid enough to count. */
.pair .cells u.abs {
  background: var(--paper-3);
  box-shadow: inset 0 0 0 1px var(--rule-2);
}

.pair .thin {
  font-family: var(--mono);
  font-size: 0.68rem;
  color: var(--ink-mid);
  margin-top: 0.6rem;
  border-left: 2px solid var(--rule-2);
  padding-left: 0.6rem;
  line-height: 1.6;
}

/* The empty cell keeps the question and the rhythm of a filled one, so an
   absence reads as a fact about the brand rather than a broken layout. */
.pair .ask .q { color: var(--signal); }
.pair .ask .a { font-size: 1.34rem; line-height: 1.28; max-width: 22ch; }
.askbtn {
  display: inline-block;
  margin-top: 0.85rem;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--signal-dark);
  border: 0;
  padding: 0.55rem 0.9rem;
  border-radius: 2px;
  cursor: pointer;
}
.askbtn:hover { background: var(--signal-deep); }

/* The report's variant of the pair. Quieter than the brand page's: no heavy
   top rule, because this hero is a title page and a second bar under the name
   would fight it. */
.pair.quiet {
  border-top: 1px solid var(--rule-2);
  border-bottom: 1px solid var(--rule-2);
  padding: 1rem 0 1.1rem;
  margin-bottom: 1.4rem;
}
.pair.quiet .a { font-size: 1.6rem; }

/* findings[0] and [1] after the pair: the sentence that interprets the numbers
   above, rather than restating them. */
.lede {
  font-size: clamp(1.02rem, 3vw, 1.14rem);
  line-height: 1.45;
  color: var(--ink);
  margin: 0 0 2rem;
  max-width: 46ch;
}
.lede .q { display: block; margin-top: 0.3rem; font-size: 0.92em; color: var(--ink-mid); }

/* ---------- what to do next ----------
   One ask. A "measure a competitor" field sat beside it and was removed: every
   rival is already a link on the board and in the chart, so it offered a second
   decision rather than a new route, and it competed with the only ask on the
   page that cannot be reached another way. Browsing the market stays in the
   quiet run line below. */
.next {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.4rem;
  margin: 3rem 0 0;
  padding-top: 1.4rem;
  border-top: 2px solid var(--ink);
}
@media (min-width: 620px) { .next { grid-template-columns: 1fr 1fr; gap: 2.4rem; } }
/* with one cell there is no column to balance: let the ask keep a readable
   measure rather than stretching across the page */
.next.one { grid-template-columns: 1fr; }
.next.one .next-cell { max-width: 46ch; }
.next-q {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 1rem;
  margin: 0 0 0.35rem;
}
.next-sub { font-size: 1.04rem; color: var(--ink-mid); margin: 0 0 0.95rem; max-width: 62ch; line-height: 1.65; }
.next-form { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.next-form input {
  flex: 1 1 11rem;
  min-width: 0;
  font-family: var(--mono);
  font-size: 0.86rem;
  padding: 0.5rem 0.65rem;
  border: 1px solid var(--rule-2);
  border-radius: 2px;
  background: var(--paper);
  color: var(--ink);
}
.next-form input:focus { outline: 2px solid var(--signal); outline-offset: -1px; }
.next-form button {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--signal-dark);
  border: 0;
  padding: 0.5rem 0.9rem;
  border-radius: 2px;
  cursor: pointer;
}
.next-form button:hover { background: var(--signal-deep); }
.next-ok { font-family: var(--disp); font-weight: 600; font-size: 0.9rem; color: var(--signal); margin: 0; }
.next-bad { font-family: var(--mono); font-size: 0.72rem; color: var(--flag); margin: 0.5rem 0 0; }
@media (min-width: 620px) { .next .right { border-left: 1px solid var(--rule); padding-left: 2.4rem; } }
@media (max-width: 619px) { .next .right { border-top: 1px solid var(--rule); padding-top: 1.4rem; } }

/* The signup pointer at the foot of a page. It used to reuse .alsoin-line,
   which is written to sit *under* the hero — margin below, none above — so at
   the foot it landed tight against whatever section had just ended. It needs
   the opposite: a rule and real space above, nothing below. */
.signup-line {
  border-top: 1px solid var(--rule-2);
  margin: 3rem 0 0;
  padding-top: 1.1rem;
  font-size: 1rem;
  color: var(--ink-mid);
}
.signup-line a {
  color: var(--signal);
  text-decoration: none;
  box-shadow: inset 0 -1px 0 var(--signal);
}
.signup-line a:hover { color: var(--signal-dark); }

/* The pointer left where the "also named in" list used to sit. Eleven rows of
   other markets arrived before a single result for the market the reader
   clicked; one line keeps the signal without the interruption. */
.alsoin-line {
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--ink-mid);
  margin: 0 0 2rem;
  letter-spacing: 0.02em;
}
.alsoin-line a { color: var(--ink); text-decoration: none; box-shadow: inset 0 -1px 0 var(--signal); }
.alsoin-line a:hover { color: var(--signal); }
.alsoin { scroll-margin-top: 1.5rem; }   /* the anchor should not land under the edge */

/* The ask, mid-page. It was a hairline and a 0.95rem heading between two
   analytical sections, which left it quieter than the section titles around it
   — a footnote where the page's only request should be.

   It is now the one tinted panel on the site. That is a deliberate borrowing:
   nothing else here is boxed, so the box marks this as a thing to act on rather
   than another section to read. */
.next.mid {
  background: var(--paper-2);
  border: 1px solid var(--rule-2);
  border-left: 3px solid var(--signal);
  border-top: 0;
  margin: 2.8rem 0 0;
  padding: 1.3rem 1.4rem;
  scroll-margin-top: 1.5rem;   /* the pointer's anchor should not land under the edge */
}
.next.mid .next-cell { max-width: 52ch; }
.next.mid .next-q {
  font-family: var(--body);
  font-weight: 400;
  font-size: 1.34rem;
  line-height: 1.25;
  letter-spacing: -0.018em;
  margin: 0 0 0.5rem;
}
.next.mid .next-sub { font-size: 1rem; margin-bottom: 1rem; }
.next.mid .next-form input { padding: 0.6rem 0.75rem; font-size: 0.9rem; }
.next.mid .next-form button { padding: 0.6rem 1.1rem; }

/* The rail, once it is full. The estimate covers asking, so the bar reaches
   the end while the run is still reading answers and counting mentions — the
   longest stretch with nothing else moving. A travelling highlight says the
   page is alive without claiming progress it cannot measure. */
.spectrum.finishing { position: relative; overflow: hidden; }
.spectrum.finishing::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.5), transparent);
  animation: railsweep 1.4s linear infinite;
}
@keyframes railsweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}
@media (prefers-reduced-motion: reduce) { .spectrum.finishing::after { animation: none; } }

/* ---------- surfaces: white marks what was measured ----------
   Headlines, findings, footnotes and the signup stay on the paper, because they
   are written rather than measured. A leaderboard, a chart, a pair of findings
   drawn from counts, a list of markets — those go on white. A reader learns the
   rule once and it holds on every page.

   `.surface` is the wrapper; the elements inside keep their own styles, so this
   is additive rather than a rewrite of the board or the chart. */
.surface {
  background: var(--surface);
  border: 1px solid var(--surface-e);
  border-radius: 4px;
  padding: 1.2rem 1.3rem 0.85rem;
  /* Bottom margin only. The shorthand also sets the left and right, and this
     rule sits at the end of the file — so on any element that centres itself
     with `margin: … auto`, it silently replaced the auto and pushed the block
     to the left. The homepage's market card is exactly that element. */
  margin-bottom: 0.4rem;
}
/* Boards end on a row border, so they need no bottom padding of their own;
   blocks of prose-like content do. */
.surface.tight { padding-bottom: 1.2rem; }

/* The board's last row draws a rule that would sit a hair above the panel edge
   and read as a mistake. */
.surface .bar-row:last-of-type,
.surface .mkrow:last-child { border-bottom: 0; }

/* The subject's tint used to bleed to the page edge on grey. Inside a panel it
   needs to reach the panel's padding instead, or it reads as a floating block. */
.surface .bar-row.you {
  box-shadow: 0.55rem 0 0 var(--tint), -0.55rem 0 0 var(--tint);
  position: relative;
  z-index: 0;
}

/* The chart figure carries the surface itself rather than sitting inside one,
   so it keeps its own vertical margin but takes the panel's padding. */
.mapfig.surface { margin: 0 0 0.4rem; padding: 1rem 1rem 0.55rem; }

@media (max-width: 560px) {
  .surface { padding: 1rem 0.9rem 0.7rem; border-radius: 3px; }
  .surface.tight { padding-bottom: 1rem; }
  .surface .bar-row.you {
    box-shadow: 0.45rem 0 0 var(--tint), -0.45rem 0 0 var(--tint);
  }
}

/* The rotating market panels carry the surface on their container, not on each
   section — putting it on the sections themselves would flash a white block in
   and out on every rotation. */
.panels.surface { padding: 1.1rem 1.2rem 1rem; }
/* Absolute positioning resolves against the padding box, so `right: 0` still
   meant the card's inner edge after the surface added padding — the last
   segment ran into the border. These inset it to match. */
.panels.surface .panels-nav { margin-top: 0; top: 1.1rem; right: 1.2rem; }

/* Index tables end on their last row's border. */
.surface .table { margin: 0; }
.surface .table tr:last-child td { border-bottom: 0; }

/* ---------- brand overview: the hub a company lands on ----------
   It was a flat table of every market, which weighted "36 of 36, first of 38"
   exactly like "1 of 36, 38th of 35" and left the reader to do the sorting.
   Three summary cards state what the brand does well, then the same markets as
   a table where the bar and the share carry one colour. */
.ovlede { font-size: 1.14rem; line-height: 1.45; max-width: 47ch; margin: 0.85rem 0 0; }
.ovlede b { font-weight: 600; }

.ovsum {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 0.6rem;
  margin-top: 1.5rem;
}
.ovcard {
  background: var(--surface);
  border: 1px solid var(--surface-e);
  border-radius: 6px;
  padding: 1rem 1.1rem;
  border-top: 4px solid var(--rule-2);
}
.ovcard .k {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 0.45rem;
}
.ovcard .v {
  font-family: var(--disp);
  font-weight: 700;
  font-size: 1.05rem;
  line-height: 1.25;
  letter-spacing: -0.012em;
  margin: 0;
}
.ovcard .v a { color: var(--ink); text-decoration: none; box-shadow: inset 0 -1px 0 var(--rule-2); }
.ovcard .v a:hover { color: var(--signal-dark); box-shadow: inset 0 -1px 0 var(--signal); }
.ovcard .m { font-family: var(--mono); font-size: 0.7rem; color: var(--ink-mid); margin: 0.34rem 0 0; }

.sec-s { font-family: var(--mono); font-size: 0.7rem; color: var(--ink-soft); margin: 0 0 0.85rem; }

/* the footprint table */
.ovtbl {
  background: var(--surface);
  border: 1px solid var(--surface-e);
  border-radius: 6px;
  padding: 0.35rem 1.2rem;
}
.ovth, .ovtr {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(5rem, 13rem) 4.2rem 5.6rem;
  gap: 0 1rem;
  align-items: center;
}
.ovth {
  align-items: baseline;
  padding: 0.75rem 0 0.5rem;
  border-bottom: 1px solid var(--rule-2);
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.ovtr { padding: 0.62rem 0; border-bottom: 1px solid var(--rule); transition: background 0.1s; }
.ovtr:last-of-type { border-bottom: 0; }
.ovtr:hover { background: rgba(20, 20, 20, 0.018); }
.ovtr .nm {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.94rem;
  letter-spacing: -0.008em;
  min-width: 0;
}
.ovtr .nm a { color: var(--ink); text-decoration: none; }
.ovtr:hover .nm a { color: var(--signal-dark); }
.ovtr .tk { height: 8px; border-radius: 4px; background: rgba(20, 20, 20, 0.06); overflow: hidden; }
.ovtr .tk i { display: block; height: 100%; border-radius: 4px; }
.ovtr .pc {
  font-family: var(--body);
  font-weight: 600;
  font-size: 1.12rem;
  text-align: right;
  letter-spacing: -0.022em;
}
/* Larger than the 0.72rem it started at, but still mono and still --ink-mid:
   the share carries the colour, so the placing should read as its companion
   rather than compete with it. */
.ovtr .rk {
  font-family: var(--mono);
  font-size: 0.82rem;
  color: var(--ink-mid);
  text-align: right;
  white-space: nowrap;
}

/* ---------- rivals: six doors ----------
   Each card opens that brand's own overview, so the section is a way onward
   rather than a scoreboard — a company checks itself, then checks the names
   around it. Colour is the overlap, from the same ramp as the footprint table
   above: two adjacent sections using plasma for different quantities would
   make both unreadable. */
.ovriv { margin-top: 2.4rem; }
.ovriv h3 {
  font-family: var(--disp);
  font-weight: 700;
  font-size: 1.06rem;
  letter-spacing: -0.012em;
  margin: 0 0 0.12rem;
}
.ovriv .s { font-family: var(--mono); font-size: 0.7rem; color: var(--ink-soft); margin: 0 0 0.9rem; }

.ovdoors {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
  gap: 0.65rem;
}
.ovdoor {
  display: flex;
  align-items: stretch;
  border: 1.5px solid var(--rule-2);
  border-radius: 8px;
  background: var(--surface);
  overflow: hidden;
  position: relative;
  text-decoration: none;
  color: inherit;
  transition: transform 0.13s ease, box-shadow 0.13s ease;
}
.ovdoor:hover { transform: translateY(-3px); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.09); }

/* Both columns start at the same top padding, so the brand name and the count
   share a top edge by construction. The centred version drifted: each half was
   a centred flex column, and the two held stacks of different heights — the
   arrow in the right-hand flow pushed the name upward. Top alignment also
   survives a brand name that wraps to two lines, which centring does not. */
.ovdoor .num {
  flex: 0 0 6rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  color: #fff;
  line-height: 1;
  padding: 1.05rem 0.5rem;
}
.ovdoor .num b {
  font-family: var(--body);
  font-weight: 600;
  font-size: 2.2rem;
  letter-spacing: -0.04em;
  display: block;
}
.ovdoor .num span {
  font-family: var(--mono);
  font-size: 0.55rem;
  letter-spacing: 0.08em;
  opacity: 0.9;
  margin-top: 0.42rem;
  display: block;
}
.ovdoor .body {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: 1.05rem 1.05rem 1.05rem 1.05rem;
  min-width: 0;
  flex: 1;
}
.ovdoor .n {
  font-family: var(--disp);
  font-weight: 700;
  font-size: 1.04rem;
  letter-spacing: -0.014em;
  line-height: 1.2;
  color: var(--ink);
}
.ovdoor .d {
  font-family: var(--mono);
  font-size: 0.67rem;
  color: var(--ink-soft);
  margin-top: 0.16rem;
  /* clipped rather than wrapped: workspace.google.com made its card taller
     than its neighbours and broke the grid's rhythm */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* out of the flow, so it cannot shift the text it sits beside */
.ovdoor .arrow {
  position: absolute;
  right: 0.85rem;
  bottom: 0.7rem;
  font-family: var(--mono);
  font-size: 0.8rem;
  transition: transform 0.13s;
}
.ovdoor:hover .arrow { transform: translateX(3px); }
@media (prefers-reduced-motion: reduce) {
  .ovdoor, .ovdoor .arrow { transition: none; }
  .ovdoor:hover { transform: none; }
}

@media (max-width: 620px) {
  .ovth, .ovtr { grid-template-columns: minmax(0, 1fr) 3.8rem 5rem; }
  .ovth span:nth-child(2), .ovtr .tk { display: none; }
  .ovdoors { grid-template-columns: 1fr; }
  .ovdoor .num { flex-basis: 5rem; }
}

/* ---------- the homepage field ----------
   Seven columns of real brands drifting past the hero, each name flaring to its
   own plasma colour on its own cycle and drawing a bar whose width is its
   count. The names and the numbers are measurements, not decoration: the field
   is the proof the page is making.

   All CSS on server-rendered nodes — no script — and the whole thing stills
   under prefers-reduced-motion, which matters more than usual for a full-screen
   moving background. */
.namefield {
  position: relative;
  /* full bleed out of .wrap's max-width and padding */
  margin: 0 calc(50% - 50vw) 2.5rem;
  width: 100vw;
  min-height: 560px;
  height: clamp(560px, 76vh, 880px);
  overflow: hidden;
  background: var(--card);
  display: flex;
  align-items: center;
  justify-content: center;
}
.nf-cols { position: absolute; inset: 0; display: flex; }
.nf-col {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  position: relative;
  border-right: 1px solid rgba(242, 240, 244, 0.05);
}
.nf-col:last-child { border-right: 0; }
.nf-run {
  position: absolute;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
  padding: 1rem 0.55rem;
  will-change: transform;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.nf-run.up { animation-name: nf-up; }
.nf-run.dn { animation-name: nf-dn; top: -100%; }
/* the sequence is rendered twice, so -50% lands exactly on a repeat */
@keyframes nf-up { from { transform: translateY(0); } to { transform: translateY(-50%); } }
@keyframes nf-dn { from { transform: translateY(0); } to { transform: translateY(50%); } }

.nf-cell {
  position: relative;
  font-family: var(--mono);
  font-size: 0.78rem;
  line-height: 1.32;
  text-align: center;
  padding-bottom: 0.62rem;
  /* 0.14 shipped first and measured 1.49:1 against the card — under even the
     3:1 large text wants, and the names were unreadable at the edges of the
     field. 0.6 puts them at about 6:1. */
  color: rgba(242, 240, 244, 0.6);
  will-change: color;
  animation-name: nf-flare;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
.nf-cell b {
  display: block;
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: -0.012em;
}
.nf-cell i { font-style: normal; font-size: 0.7rem; opacity: 0.8; }
/* the track the bar fills against: a length alone reads as arbitrary, a length
   inside a track reads as a proportion */
.nf-cell::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 84%;
  height: 2px;
  border-radius: 2px;
  /* lifted with the names: a bright word over an invisible track looked
     unfinished */
  background: rgba(242, 240, 244, 0.18);
  transform: translateX(-50%);
}
.nf-cell::after {
  content: "";
  position: absolute;
  left: calc(50% - 42%);
  bottom: 0;
  width: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--lit);
  opacity: 0;
  animation-name: nf-bar;
  animation-timing-function: cubic-bezier(0.16, 0.8, 0.3, 1);
  animation-duration: inherit;
  animation-delay: inherit;
  animation-iteration-count: infinite;
}
/* Raising the resting state narrows the gap the flare has to cross, so it opens
   on a flash of pure white before falling into the brand's colour — the change
   reads as ignition rather than a fade. */
@keyframes nf-flare {
  0%, 100% { color: rgba(242, 240, 244, 0.6); text-shadow: none; }
  5%  { color: #fff; text-shadow: 0 0 22px var(--glow), 0 0 7px var(--glow); }
  15% { color: var(--lit); text-shadow: 0 0 18px var(--glow); }
  30% { color: var(--lit); text-shadow: 0 0 11px var(--glow); }
  44% { color: rgba(242, 240, 244, 0.6); text-shadow: none; }
}
@keyframes nf-bar {
  0%   { width: 0; opacity: 0; }
  4%   { width: 0; opacity: 0.9; }
  17%  { width: var(--w); opacity: 0.9; }
  30%  { width: var(--w); opacity: 0.9; }
  40%  { width: var(--w); opacity: 0; }
  100% { width: 0; opacity: 0; }
}

.nf-edge { position: absolute; left: 0; right: 0; height: 17%; pointer-events: none; z-index: 3; }
.nf-edge.t { top: 0; background: linear-gradient(var(--card), rgba(26, 26, 26, 0)); }
.nf-edge.b { bottom: 0; background: linear-gradient(rgba(26, 26, 26, 0), var(--card)); }
.nf-grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  opacity: 0.5;
  background-image: repeating-linear-gradient(0deg,
    rgba(242, 240, 244, 0.028) 0 1px, transparent 1px 3px);
}
/* holds the middle perfectly still, so nothing ever drifts under the headline */
.nf-veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
  background: radial-gradient(ellipse 58% 46% at 50% 50%,
    var(--card) 24%, rgba(26, 26, 26, 0.94) 44%, rgba(26, 26, 26, 0.45) 72%,
    rgba(26, 26, 26, 0) 100%);
}
/* the hero, on ink now */
.namefield .hero { position: relative; z-index: 4; padding: 0 1.4rem; margin: 0; text-align: center; }
.namefield .hero-thesis { color: var(--card-text); }
.namefield .hero-thesis em { color: var(--ember); }
.namefield .hero-sub { color: var(--card-mid); }
.namefield .domain-input {
  border-color: var(--card-text);
  background: rgba(242, 240, 244, 0.05);
  color: var(--card-text);
}
.namefield .domain-input::placeholder { color: var(--card-soft); }
/* The operator code field appears beside it at /?op=1 and inherits --paper-2,
   so it rendered as a light box on the ink hero. It is only ever seen with an
   ACCESS_CODE set, which is why it survived the rest of the sweep. */
.namefield .code-input {
  border-color: var(--card-text);
  background: rgba(242, 240, 244, 0.05);
  color: var(--card-text);
}
.namefield .code-input::placeholder { color: var(--card-soft); }
.namefield .go { background: var(--ember); border-color: var(--ember); color: var(--on-ember); }
.namefield .go:hover { background: #fff; border-color: #fff; color: var(--card); }

@media (max-width: 720px) {
  /* three columns is enough texture on a phone, and a third of the nodes */
  .nf-col:nth-child(n + 4) { display: none; }
  .namefield { height: clamp(500px, 70vh, 640px); }
}
@media (prefers-reduced-motion: reduce) {
  .nf-run, .nf-cell, .nf-cell::after { animation: none !important; }
  /* a still field still has to be readable, and every bar still has to be true */
  .nf-cell { color: rgba(242, 240, 244, 0.6); }
  .nf-cell::after { width: var(--w); opacity: 0.8; }
}

/* ---------- the homepage below the field ----------
   The rotating market panels are gone: the field above already shows real
   brands with real counts, so the carousel repeated that claim in a smaller
   box. What it carried that the field does not — the scale of the archive — is
   stated here as three figures.

   The carousel's own rules are left in place rather than surgically removed:
   nothing emits `.panels` or `.spread-row` any more, so they style nothing, and
   picking them out of the stylesheet by hand is how a balanced file becomes an
   unbalanced one. */
.hcounts {
  display: flex;
  flex-wrap: wrap;
  /* it already sits inside .wrap — a second max-width and auto margins inset it
     twice and pulled it narrower than the field above */
  border-bottom: 1px solid var(--rule-2);
}
.hcounts .c {
  flex: 1 1 200px;
  padding: 1.5rem 0 1.5rem 1.6rem;
  border-left: 1px solid var(--rule);
}
.hcounts .c:first-child { border-left: 0; padding-left: 0; }
.hcounts .n {
  font-family: var(--body);
  font-size: 2.2rem;
  line-height: 1;
  letter-spacing: -0.04em;
  margin: 0;
}
.hcounts .l {
  font-family: var(--mono);
  font-size: 0.67rem;
  color: var(--ink-soft);
  margin: 0.45rem 0 0;
}

/* The nav reads as links rather than as a label: a rule under each at rest, the
   accent under the pointer. It also sits above the field on its own ground —
   names drifting behind the wordmark were what made it hard to read. */
.topnav a {
  font-size: 0.76rem;
  letter-spacing: 0.15em;
  padding-bottom: 0.28rem;
  box-shadow: inset 0 -1px 0 var(--rule-2);
  transition: color 0.14s, box-shadow 0.14s;
}
.topnav a:hover,
.topnav a[aria-current="page"] { color: var(--ink); box-shadow: inset 0 -2px 0 var(--signal); }

/* ---------- the homepage runs on ink ----------
   The field is the page rather than a banner on it, so the counts, the
   questions and the footer take the same ground and there is no seam under the
   fold. This class is only ever on the homepage; every other page stays paper. */
body.ink { background: var(--card); color: var(--card-text); }

/* The mockup's bar is not the shared masthead: it spans the viewport, sits
   tight above the field, and pushes the nav right. The shared one is inset by
   .wrap's padding, carries 2.6rem of air beneath it, and pushes the nav left
   with margin-right:auto — so on the homepage the rule floated a long way under
   the wordmark and the field started too far down. These four overrides are
   scoped to the ink page; every other page keeps the masthead as it was. */
body.ink .masthead,
body.index .masthead {
  /* The bar stays inside .wrap, so the wordmark lines up with the counts and
     the questions below it — and with the masthead on every other page, which
     matters more than it sounds: full-bleeding it moved the logo sideways as
     soon as you clicked through to a result.

     Only the rule spans the viewport, drawn as a pseudo-element. Widening the
     header itself would have meant 100vw maths on a layout box, and 100vw
     includes the scrollbar where a percentage does not, so the contents would
     have sat a few pixels off the column they are supposed to match. */
  position: relative;
  margin: 0;
  width: auto;
  padding: 1rem 0;
  align-items: center;
  border-bottom: 0;
}
body.ink .masthead::after,
body.index .masthead::after {
  content: "";
  position: absolute;
  left: calc(50% - 50vw);
  right: calc(50% - 50vw);
  bottom: 0;
  height: 1px;
  background: var(--rule-2);
}
body.ink .masthead::after { background: rgba(240, 240, 240, 0.16); }
body.ink .topnav,
body.index .topnav { margin-right: 0; margin-left: auto; padding-left: 0; }

/* the counts rule matches it, or the page has one edge-to-edge line and one
   that stops short */
body.ink .hcounts { position: relative; border-bottom: 0; }
body.ink .hcounts::after {
  content: "";
  position: absolute;
  left: calc(50% - 50vw);
  right: calc(50% - 50vw);
  bottom: 0;
  height: 1px;
  background: rgba(240, 240, 240, 0.14);
}
body.ink .wordmark { color: var(--card-text); }
body.ink .wordmark span { color: var(--ember); }
body.ink .topnav a { color: var(--card-mid); box-shadow: inset 0 -1px 0 rgba(240, 240, 240, 0.28); }
body.ink .topnav a:hover,
body.ink .topnav a[aria-current="page"] {
  color: var(--card-text);
  box-shadow: inset 0 -2px 0 var(--ember);
}
body.ink .namefield { margin-bottom: 0; }
body.ink .hcounts { border-bottom-color: rgba(240, 240, 240, 0.14); }
body.ink .hcounts .c { border-left-color: rgba(240, 240, 240, 0.1); }
body.ink .hcounts .n { color: var(--card-text); }
body.ink .hcounts .l { color: var(--card-soft); }
body.ink .ask-card h3 {
  font-family: var(--disp);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: -0.014em;
  color: var(--card-text);
  padding-top: 0.9rem;
  border-top: 2px solid var(--ember);
}
/* the field runs to the counts; the questions need their own air */
body.ink .hero-ask { margin-top: 2.8rem; }
body.ink .site-footer,
body.index .site-footer { margin-top: 2.6rem; padding-top: 1.6rem; }
body.ink .site-footer { border-top-color: rgba(240, 240, 240, 0.14); color: var(--card-soft); }
body.ink .site-footer a:hover { color: var(--card-text); }
body.ink .alert { border-color: var(--ember); color: var(--card-text); }

@media (max-width: 620px) {
  .hcounts .c {
    flex-basis: 100%;
    padding: 1rem 0;
    border-left: 0;
    border-top: 1px solid var(--rule);
  }
  .hcounts .c:first-child { border-top: 0; }
}

/* ---------- the markets index ----------
   It was a four-column table — market, brands, questions, leader — all in one
   weight, so no cell was the row's subject and "who leads this market", the
   thing a visitor arrives for, sat last and looked like a footnote.

   The market now leads in the reading face; the leader is set as an attribute
   of it. The bar is a 2.6rem chip rather than a column, because a track and a
   fill were spending a third of the row on a single number. */
.mkhead { padding: 2.4rem 0 1.4rem; }
.mkhead .thesis { max-width: 18ch; }
.mkhead .prose { max-width: 52ch; margin-top: 0.85rem; }
.mkcount {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--ink-soft);
  margin: 1.2rem 0 0;
}

.mklist { margin-top: 1.4rem; }
.mkrow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 12rem 5.5rem 4.6rem;
  gap: 0 1.4rem;
  /* not baseline: .pc is a flex container, so its baseline comes from the bar
     and not from the figure beside it, which sat the number below the market */
  align-items: center;
  padding: 0.62rem 0;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: inherit;
  transition: background 0.1s;
}
.mkrow:hover { background: rgba(20, 20, 20, 0.03); }
.mkrow.head {
  padding: 0 0 0.55rem;
  border-bottom: 1px solid var(--rule-2);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.mkrow.head:hover { background: none; }
.mkrow .r { text-align: right; }
/* the market is the row's subject, so it is set like one */
.mkrow .mk { font-family: var(--body); font-size: 1.16rem; letter-spacing: -0.026em; }
/* and the leader is an attribute of the market, not a peer of it */
.mkrow .who {
  font-family: var(--disp);
  font-weight: 600;
  font-size: 0.86rem;
  color: var(--ink-mid);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mkrow .who em {
  font-style: normal;
  font-family: var(--mono);
  /* 0.76em of 0.86rem is 10.5px; the site's floor for words is 11 */
  font-size: 0.72rem;
  color: var(--ink-soft);
  margin-left: 0.35rem;
}
/* The bar sat at flex-end behind a number whose width changes with its digits,
   so "100%" pushed the bar left of "58%" and the column had no edge. Fixing the
   figure's width puts the bar at the same x on every row. */
.mkrow .pc { display: flex; align-items: center; justify-content: flex-end; gap: 0.45rem; }
/* the markets figure is "100%" at most, one character shorter than "36/36" */
.mkrow:not(.brandrow) .pc b { width: 2.15rem; }
.mkrow .pc b {
  width: 2.6rem;
  flex: none;
  text-align: right;
  /* Not the bar's colour: the plasma ramp is built for fills, and as small text
     on paper it runs from 4.8:1 at the violet end to 2.0:1 at the amber one —
     the highest, most interesting numbers were the least readable. The bar
     carries the colour; the figure carries the value. */
  color: var(--ink);
}
.mkrow .pc i {
  width: 2.6rem;
  height: 5px;
  border-radius: 3px;
  background: var(--paper-3);
  overflow: hidden;
  flex: none;
}
.mkrow .pc i span { display: block; height: 100%; border-radius: 3px; }
.mkrow .pc b { font-family: var(--mono); font-weight: 400; font-size: 0.82rem; }
/* Data is never dimmer than the label naming it. This count — how many markets
   a brand is in, how many brands a market holds — is one of the two things that
   makes a row worth reading, and it sat at --ink-soft, the same tone as the
   column headings and the footer. --ink-mid puts it with the other measured
   cell in the row. */
.mkrow .br { font-family: var(--mono); font-size: 0.74rem; color: var(--ink-mid); text-align: right; }

/* on ink */
body.ink .mkcount { color: var(--card-soft); }
body.ink .mkhead .prose { color: var(--card-mid); }
body.ink .mkrow { border-bottom-color: rgba(240, 240, 240, 0.08); }
body.ink .mkrow:hover { background: rgba(240, 240, 240, 0.04); }
body.ink .mkrow.head { border-bottom-color: rgba(240, 240, 240, 0.22); color: var(--card-soft); }
body.ink .mkrow .mk { color: var(--card-text); }
body.ink .mkrow .who { color: var(--card-mid); }
body.ink .mkrow .who em, body.ink .mkrow .br { color: var(--card-soft); }
body.ink .mkrow .pc i { background: rgba(240, 240, 240, 0.14); }
body.ink .kicker { color: var(--ember); }
body.ink .thesis { color: var(--card-text); }
body.ink .thesis em { color: var(--ember); }
/* The card's own background is --paper-2. Recolouring only the text left
   near-white type on a near-white card — invisible on the ink page. The card
   needs its ground and its border moved too, not just its ink. */
body.ink .note-card {
  background: rgba(240, 240, 240, 0.04);
  border-color: rgba(240, 240, 240, 0.14);
}
body.ink .note-card h3 { color: var(--card-soft); }
body.ink .note-card p { color: var(--card-mid); }
body.ink .section-title { color: var(--card-soft); }

@media (max-width: 760px) {
  /* the two right-hand figures are the first to go: the market and its leader
     are what the row is for */
  .mkrow { grid-template-columns: minmax(0, 1fr) 5.5rem; }
  .mkrow .who { grid-column: 1; font-size: 0.8rem; margin-top: 0.12rem; }
  .mkrow .br, .mkrow.head span:nth-child(2), .mkrow.head span:nth-child(4) { display: none; }
  .mkrow { align-items: center; }
}

/* ---------- the brands index ----------
   Two problems, and the second was the one that would have broken. Every row
   listed every market that brand appears in, inline — unreadable at fifteen
   markets. And the page rendered every brand in the archive: 1.5MB of HTML at
   five thousand brands, 3MB at ten, which is parse time a phone cannot hide.

   A row now carries the brand, where it does best, and how many markets it is
   in; the server sends one page of rows. Rows reuse .mkrow from the markets
   index, so the two indexes are one thing a reader learns once. */
.btools {
  position: sticky;
  top: 0;
  z-index: 6;
  padding: 0.85rem 0;
  margin-top: 1.2rem;
}
/* the bar's ground and rule span the viewport while its contents stay in the
   column — the same treatment the masthead uses */
.btools::before {
  content: "";
  position: absolute;
  left: calc(50% - 50vw);
  right: calc(50% - 50vw);
  top: 0;
  bottom: 0;
  background: var(--paper);
  z-index: -1;
  border-bottom: 1px solid var(--rule-2);
}
.bline { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; margin: 0; }
.sbox { position: relative; flex: 1 1 20rem; max-width: 28rem; display: block; }
.sbox svg {
  position: absolute;
  left: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--ink-soft);
  pointer-events: none;
}
/* The controls carried the same padding but different font sizes, so their
   boxes ended up different heights and their text sat at different levels.
   A shared height with no vertical padding lets each one centre its own text
   natively — which is the only way a <select> centres reliably. */
.sbox input, .pick { height: 2.7rem; }
.sbox input {
  width: 100%;
  font-family: var(--mono);
  font-size: 0.92rem;
  padding: 0 0.9rem 0 2.5rem;
  border: 1px solid var(--rule-2);
  border-radius: 3px;
  background: var(--surface);
  color: var(--ink);
}
.sbox input:focus { outline: 2px solid var(--signal); outline-offset: -1px; }
.pick {
  font-family: var(--mono);
  font-size: 0.82rem;
  padding: 0 0.8rem;
  border: 1px solid var(--rule-2);
  border-radius: 3px;
  background: var(--surface);
  color: var(--ink);
}
/* the submit exists for keyboards and for JavaScript being off; the select
   posts on change, so most people never press it */
.pick.go { cursor: pointer; }
.btools .n { margin-left: auto; font-family: var(--mono); font-size: 0.72rem; color: var(--ink-soft); }

.jump { display: flex; align-items: flex-start; gap: 0.6rem; margin: 0.8rem 0 0; }
.jump .lab {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-soft);
  flex: none;
  padding-top: 0.4rem;
}
/* wraps rather than scrolls: a horizontal strip hides letters past the right
   edge with nothing to say they are there, and on a phone that is most of the
   alphabet */
.rail { display: flex; flex-wrap: wrap; gap: 0.22rem; flex: 1 1 auto; }
.rail a {
  font-family: var(--mono);
  font-size: 0.8rem;
  padding: 0.3rem 0.5rem;
  border-radius: 3px;
  color: var(--ink-mid);
  min-width: 1.9rem;
  text-align: center;
  text-decoration: none;
}
.rail a.all { min-width: auto; padding: 0.3rem 0.75rem; letter-spacing: 0.06em; }
.rail a.on { background: var(--signal); color: #fff; font-weight: 600; }
.rail a:hover { background: var(--paper-2); color: var(--ink); }
.rail a.none { opacity: 0.28; pointer-events: none; }

.bpagehead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin: 1.7rem 0 0.35rem;
}
.bpagehead h2 {
  font-family: var(--body);
  font-weight: 400;
  font-size: 2.1rem;
  letter-spacing: -0.04em;
  margin: 0;
  line-height: 1;
}
.bpagehead .of { font-family: var(--mono); font-size: 0.72rem; color: var(--ink-soft); }

.bpager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 1.5rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 0.76rem;
  color: var(--ink-soft);
}
.bpager .steps { display: flex; gap: 1.1rem; align-items: baseline; }
.bpager a { color: var(--signal); }
.bnone { font-family: var(--mono); font-size: 0.82rem; color: var(--ink-soft); padding: 1.6rem 0; }
.bnone a { color: var(--signal); }

/* on ink */
body.ink .btools::before { background: var(--card); border-bottom-color: rgba(240, 240, 240, 0.16); }
body.ink .sbox input, body.ink .pick {
  border-color: rgba(240, 240, 240, 0.26);
  background: rgba(240, 240, 240, 0.05);
  color: var(--card-text);
}
body.ink .sbox input::placeholder { color: var(--card-soft); }
body.ink .sbox input:focus, body.ink .pick:focus { outline-color: var(--ember); }
body.ink .sbox svg { color: var(--card-soft); }
body.ink .btools .n, body.ink .jump .lab { color: var(--card-soft); }
body.ink .rail a { color: var(--card-mid); }
body.ink .rail a.on { background: var(--ember); color: var(--on-ember); }
body.ink .rail a:hover { background: rgba(240, 240, 240, 0.08); color: var(--card-text); }
body.ink .bpagehead .of, body.ink .bpager, body.ink .bnone { color: var(--card-soft); }
body.ink .bpager { border-top-color: rgba(240, 240, 240, 0.14); }
body.ink .bpager a, body.ink .bnone a { color: var(--ember); }
/* The brand column took all the slack — .mkrow gives the first column 1fr, which
   on a 1080px page leaves a void of forty-odd characters between a short brand
   name and its market, and the eye loses the row crossing it. Capping the brand
   and letting the market take the remainder keeps the four values in a band the
   eye can span. Scoped to .brandrow: the markets index has long market names in
   that column and genuinely wants the full width. */
.mkrow.brandrow, .mklist .mkrow.head.brands {
  grid-template-columns: minmax(0, 20rem) minmax(0, 1fr) 5.5rem 4.6rem;
}

/* The brands index puts the domain inside .mk; the markets index has no domain,
   so this rule never existed and the <em> fell back to inline italic serif —
   "Slackslack.com" on one line. It is a second line in mono, like every other
   domain on the site. */
.mkrow .mk em {
  display: block;
  font-style: normal;
  font-family: var(--mono);
  font-size: 0.71rem;
  letter-spacing: 0;
  /* the domain identifies the row, so it follows the same rule as the count */
  color: var(--ink-mid);
  margin-top: 0.12rem;
}
body.ink .mkrow .mk em { color: var(--card-soft); }

@media (max-width: 760px) {
  .bline .pick { flex: 1 1 8rem; }
  .btools .n { width: 100%; margin-left: 0; order: 3; }
  .jump { flex-direction: column; gap: 0.4rem; }
  .jump .lab { padding-top: 0; }
  .rail { width: 100%; }
  /* every letter on screen over two rows, each a full tap target */
  .rail a { flex: 1 1 auto; min-width: 2.1rem; padding: 0.42rem 0.3rem; }
  .bpagehead h2 { font-size: 1.7rem; }
}

/* The brands header row is labels, not controls — see the template. Its columns
   are the four the page promises: brand, best market, times named, markets. */
.mkrow.head.brands span {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.mklist .mkrow.head.brands { padding: 0.9rem 0 0.55rem; border-bottom: 1px solid var(--rule); }
.mkrow.brandrow, .mklist .mkrow.head.brands {
  grid-template-columns: minmax(0, 18rem) minmax(0, 1fr) 6rem 4.6rem;
}

/* ---------- the brands header ----------
   Most people arrive typing their own brand, so the field is the largest thing
   on the page and the ordering is a footnote on the table's own rule. The
   alphabet is gone — twenty-seven targets over two rows doing a job the search
   box does better — and A–Z survives as one of the three orders. */
.bhead { padding: 2.4rem 0 0; max-width: 46rem; }
.bhead .thesis { max-width: 18ch; }
.bhead .prose { max-width: 50ch; margin-top: 0.85rem; }
.find { position: relative; margin: 1.6rem 0 0; max-width: 34rem; }
.find svg {
  position: absolute;
  left: 1rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--ink-soft);
  pointer-events: none;
}
.find input {
  width: 100%;
  height: 3.2rem;
  font-family: var(--mono);
  font-size: 1rem;
  padding: 0 1rem 0 2.9rem;
  border: 2px solid var(--ink);
  border-radius: 4px;
  background: var(--surface);
  color: var(--ink);
}
.find input:focus { outline: 2px solid var(--signal); outline-offset: 2px; }
.find input::placeholder { color: var(--ink-soft); }
/* 0.72rem mono in the palest grey on the page, carrying its only call to
   action. Reading face, larger, and an ink underline rather than a colour. */
.findhint { font-family: var(--body); font-size: 0.95rem; color: var(--ink-mid); margin: 0.8rem 0 0; }
.findhint a { color: var(--ink); font-weight: 600; box-shadow: inset 0 -1px 0 var(--ink); }
.findhint a:hover { box-shadow: inset 0 -2px 0 var(--ink); }

/* One rule, one typeface. The heading that said "All brands" is gone — the h1
   above already says it, and it was a third alignment on this line. The current
   order is ink and underlined: the same signal the top nav uses for the page
   you are on, and no colour, because these are controls rather than links out. */
.bstate {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.2rem;
  flex-wrap: wrap;
  margin: 2.6rem 0 0;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--rule-2);
  font-family: var(--mono);
  font-size: 0.78rem;
}
.bstate .state { color: var(--ink); }
.bstate .state span { color: var(--ink-soft); }
.bstate .orders { display: flex; align-items: baseline; gap: 1.1rem; margin-left: auto; }
.bstate .orders .lab { color: var(--ink-soft); }
.bstate .orders a { color: var(--ink-mid); padding-bottom: 0.2rem; }
.bstate .orders a:hover { color: var(--ink); }
.bstate .orders a.on { color: var(--ink); font-weight: 600; box-shadow: inset 0 -2px 0 var(--ink); }

/* the figure carries no bar now, so it needs no room for one */
.mkrow.brandrow .pc { justify-content: flex-end; }
.mkrow.brandrow .pc b { width: auto; }

@media (max-width: 760px) {
  .bstate { gap: 0.5rem 1rem; }
  .bstate .orders { margin-left: 0; width: 100%; }
  .find input { font-size: 0.95rem; }
}

/* ---------- reading on ink ----------
   Contrast was never the problem here: the labels measured 6.2:1 and the answers
   8.4:1. Two other things made this text hard to read.

   The labels were the smallest type on the page, under the floor the rest of the
   site keeps. And the answers were a serif at ~16px on a dark ground, where thin
   strokes bloom into the background and read lighter than the same size on
   paper — which is why a face that is comfortable on the market pages is not
   comfortable here.

   So: the reading face stays on paper, and body text on ink moves to the sans
   the questions already use. Sizes and line spacing go up with it. */
body.ink .hcounts .c { padding-top: 1.7rem; padding-bottom: 1.7rem; }
body.ink .hcounts .l { font-size: 0.8rem; color: var(--card-label); }
body.ink .ask-card h3 { font-size: 1.08rem; padding-top: 1rem; }
body.ink .ask-card p {
  font-family: var(--disp);
  font-size: 1.03rem;
  line-height: 1.68;
  color: var(--card-read);
}
body.ink .cols { gap: 1.9rem 2.6rem; }
/* the subhead had the same problem as the answers, one element earlier */
body.ink .hero-sub {
  font-family: var(--disp);
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--card-read);
}
/* .site-footer a is --ink-soft, a paper token: on the ink homepage that is
   3.27:1, which fails. The same rule is correct on every other page. */
body.ink .site-footer a { color: var(--card-mid); }
body.ink .site-footer a:hover { color: var(--card-text); }

/* ---------- the operator's traffic page ----------
   Read-only, and never seen by a visitor, so it is built from the same parts as
   the rest of the site rather than given a look of its own. */
.opsdays { display: flex; gap: 0.5rem; margin: 0.4rem 0 0; font-family: var(--mono); font-size: 0.78rem; }
.opsdays a {
  color: var(--ink-mid);
  border: 1px solid var(--rule-2);
  border-radius: 3px;
  padding: 0.25rem 0.7rem;
}
.opsdays a.on { background: var(--ink); border-color: var(--ink); color: var(--paper); font-weight: 600; }
.opsfigs { display: flex; flex-wrap: wrap; gap: 0; margin: 1.6rem 0 0; border-top: 1px solid var(--rule-2); }
.opsfigs > div { flex: 1 1 150px; padding: 1.2rem 0 1.2rem 1.4rem; border-left: 1px solid var(--rule); }
.opsfigs > div:first-child { border-left: 0; padding-left: 0; }
.opsfigs .n { font-family: var(--body); font-size: 2rem; line-height: 1; letter-spacing: -0.04em; margin: 0; }
.opsfigs .l { font-family: var(--mono); font-size: 0.72rem; color: var(--ink-soft); margin: 0.45rem 0 0; }

.opstbl { background: var(--surface); border: 1px solid var(--surface-e); border-radius: 5px; padding: 0.2rem 1.1rem; }
.opsrow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 6rem minmax(0, 14rem);
  gap: 0 1rem;
  align-items: baseline;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--rule);
}
.opsrow:last-child { border-bottom: 0; }
.opsrow .d { font-family: var(--mono); font-size: 0.85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.opsrow .n { font-family: var(--mono); font-size: 0.85rem; text-align: right; }
.opsrow .t { font-family: var(--mono); font-size: 0.74rem; color: var(--ink-mid); text-align: right; }

/* a bar per day: enough to see a spike, not a chart library */
.opsdaily { display: flex; align-items: flex-end; gap: 3px; height: 90px; margin: 0.8rem 0 0; }
.opsdaily .bar { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: flex-end;
  align-items: center; height: 100%; min-width: 6px; }
.opsdaily .bar i { display: block; width: 100%; background: var(--signal); border-radius: 2px 2px 0 0; min-height: 2px; }
.opsdaily .bar em { font-family: var(--mono); font-style: normal; font-size: 0.6rem; color: var(--ink-soft); margin-top: 0.2rem; }
