/* ─────────────────────────────────────────────────────────────────────────
   DELIVERABLE READERS — the shared components (deliverable-view.js)
   ─────────────────────────────────────────────────────────────────────────
   One set of readers — findings, questions, actions, visibility — mounted by
   both the crawl hub and the aggregated report. Same markup, same behaviour,
   same information, so an improvement to either lands in both.

   THE RULES THIS SHEET KEEPS (they're what make it scannable):

   1. HIERARCHY IS TYPE, NOT BOXES. A reader is: a header (what this is, how
      many, one sentence of plain English) → a list of rows → a footer. Rows are
      separated by hairlines, never by cards. Nesting a card inside a card is
      what made the old page read as scattered fragments.

   2. ONE IDEA PER ROW, CLOSED. Bold title, one clipped line of why, then quiet
      tags. Everything else waits behind the expander. A reader should be able
      to run their eye down the titles alone and know what's in the list.

   3. COLOUR IS MEANING, NOT DECORATION. The palette is deliberately tiny:
        accent (lime)   yours / done / the thing you asked for
        sev-high        critical + high severity, and only that
        sev-med         medium
        neutral greys   everything else, including all structure
      Nothing is coloured to be interesting. If a row is orange it is because
      it is urgent. Layer badges are the one exception and they are dimmed.

   4. LABELS ARE FIXED. The micro-label above a block ("Why this matters",
      "The moves") comes from deliverable-model.js, so the same field is called
      the same thing everywhere. Never re-word one locally.

   5. THE HOST SUPPLIES THE PALETTE. Every colour is a var with a fallback; the
      hub maps them to its dark tokens and the report to its document tokens,
      including the light flip under @media print. This sheet sets no absolute
      colours of its own.
   ───────────────────────────────────────────────────────────────────────── */

.dv {
  --dv-panel:   var(--dvx-panel, var(--paper, var(--bg-card, #141416)));
  --dv-panel-2: var(--dvx-panel-2, var(--paper-2, var(--bg-card-hover, #1b1b1f)));
  --dv-rule:    var(--dvx-rule, var(--rule, var(--border, #27272a)));
  --dv-rule-2:  var(--dvx-rule-2, var(--rule-2, var(--border-light, #3f3f46)));
  --dv-text:    var(--dvx-text, var(--ink, var(--text, #fafafa)));
  --dv-text-2:  var(--dvx-text-2, var(--ink-2, var(--text-secondary, #e4e4e7)));
  --dv-muted:   var(--dvx-muted, var(--ink-3, var(--text-muted, #a1a1aa)));
  --dv-faint:   var(--dvx-faint, var(--grey, var(--text-faint, #71717a)));
  --dv-accent:  var(--dvx-accent, var(--accent, #c8ff00));
  --dv-accent-dim: var(--dvx-accent-dim, var(--accent-dim, rgba(200,255,0,.13)));
  --dv-high:    var(--dvx-high, var(--high, #fb923c));
  --dv-med:     var(--dvx-med, var(--med, #fbbf24));
  /* Cited-but-not-named is neither a win nor an absence, so it gets neither the
     accent nor the red. Same role as --r-info in the reader. */
  --dv-info:    var(--dvx-info, var(--info, #7dd3fc));
  --dv-low:     var(--dvx-low, var(--low, var(--text-faint, #71717a)));
  --dv-mono:    var(--mono, "JetBrains Mono", ui-monospace, monospace);
  font-size: 15px;
  color: var(--dv-text-2);
  /* No max-width here on purpose. Capping the READER inside a wider host just
     moves the gutter: on the crawl hub it left the reader inset in an 1118px
     section, so the dead space to the right of a paragraph went UP (34% of the
     section) rather than down. The column has to be set by the page — see
     `.dash--hub` and the report's `.doc` — so that the reader fills it and the
     leftover falls outside the card, where it reads as page margin. */
}

/* ── header ───────────────────────────────────────────────────────────────
   Every reader opens the same way: what it is, how many, and one sentence of
   plain English telling a non-expert how to read the list. The sentence is not
   decoration — it is the difference between "6 findings" and knowing that
   findings are ordered by severity and each one has an owner. */
.dv__hd { margin-bottom: .9rem; }
.dv__k { font-size: .98rem; font-weight: 600; letter-spacing: -.015em; color: var(--dv-text); }
.dv__k .n { font-family: var(--dv-mono); font-size: .72rem; font-weight: 400; color: var(--dv-faint); margin-left: .45rem; }
.dv__note { margin: .25rem 0 0; font-size: .84rem; line-height: 1.5; color: var(--dv-muted); max-width: 68ch; }
.dv__tools { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-top: .75rem; }

/* Filter chips. "On" is a filled neutral, never the accent — the accent means
   your data, and a UI control borrowing it dilutes that. */
.dv-chip-f { font-family: var(--dv-mono); font-size: .63rem; letter-spacing: .05em; text-transform: uppercase;
  display: inline-flex; align-items: center; gap: .38rem; padding: .34rem .6rem; border-radius: 7px;
  cursor: pointer; border: 1px solid var(--dv-rule-2); background: transparent; color: var(--dv-muted); }
.dv-chip-f:hover { color: var(--dv-text); }
.dv-chip-f.on { background: var(--dv-panel-2); color: var(--dv-text); border-color: var(--dv-muted); }
.dv-chip-f .dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }

.dv__find { display: flex; align-items: center; gap: .45rem; padding: 0 .65rem; flex: 1 1 190px; min-width: 0;
  background: var(--dv-panel-2); border: 1px solid var(--dv-rule); border-radius: 8px; }
.dv__find input { flex: 1; min-width: 0; background: none; border: 0; outline: none; color: var(--dv-text);
  font: inherit; font-size: .84rem; padding: .44rem 0; }
.dv__find input::placeholder { color: var(--dv-faint); }
.dv__find span { color: var(--dv-faint); font-size: .9rem; }

.dv__b { font-family: var(--dv-mono); font-size: .63rem; letter-spacing: .05em; text-transform: uppercase;
  padding: .36rem .62rem; border-radius: 7px; cursor: pointer; white-space: nowrap;
  border: 1px solid var(--dv-rule-2); background: transparent; color: var(--dv-muted); }
.dv__b:hover { color: var(--dv-accent); border-color: var(--dv-accent); }
.dv__b--go { margin-left: auto; }
/* The copy control is a primary action on the plan — as a ghost mono chip it
   read as a label, and people couldn't find it at all. */
.dv__b--solid { background: var(--dv-accent-dim); border-color: rgba(var(--accent-rgb, 200,255,0), .4); color: var(--dv-accent); }
.dv__b--solid:hover { background: var(--btn-fill, #3f5c0b); color: var(--btn-ink, #f4ffe0); border-color: var(--btn-fill, #3f5c0b); }

/* ── the list ─────────────────────────────────────────────────────────── */
.dv__list { display: flex; flex-direction: column; }

.dv-ex { border-bottom: 1px solid var(--dv-rule); scroll-margin-top: 84px;
  transition: box-shadow .16s ease, padding-left .16s ease; }
.dv-ex:last-child { border-bottom: 0; }
/* An open row is marked in the margin. It does NOT become a filled card —
   that is the rule that keeps a long list reading as one document. */
.dv-ex.is-open { box-shadow: inset 2px 0 0 var(--dv-rule-2); padding-left: .85rem; }
.dv-ex.is-hit { box-shadow: inset 2px 0 0 var(--dv-accent); padding-left: .85rem; }
.dv-ex[hidden] { display: none; }

.dv-ex__hd { display: grid; grid-template-columns: auto 1fr auto auto; gap: .7rem; align-items: baseline;
  width: 100%; padding: .72rem 0; background: none; border: 0; cursor: pointer; text-align: left;
  font: inherit; color: inherit; }
.dv-ex__lead { align-self: center; }
.dv-ex__t { font-size: .89rem; font-weight: 600; color: var(--dv-text); min-width: 0; line-height: 1.4; }
/* The summary line spans to the END of the row, not just the title column. Held
   at column 2 it was competing with the tag group for width, so it wrapped at
   ~75% while the tags sat in dead space to its right — the row looked squeezed
   even though nothing was constraining the text but the grid. */
.dv-ex__why { grid-column: 2 / -1; font-size: .84rem; color: var(--dv-muted); line-height: 1.55;
  margin-top: .22rem; max-width: 78ch; }
.dv-ex__tags { display: flex; gap: .35rem; flex-wrap: nowrap; justify-content: flex-end;
  align-self: center; flex: none; }
.dv-ex__chev { color: var(--dv-faint); font-size: .68rem; align-self: center; transition: transform .18s ease; }
.dv-ex.is-open .dv-ex__chev { transform: rotate(180deg); color: var(--dv-accent); }
.dv-ex__body { display: none; padding: .1rem 0 1.1rem; }
.dv-ex.is-open .dv-ex__body { display: block; }

/* Severity dot — the only colour in a closed findings row, so scanning the
   list top to bottom reads as a severity ramp. */
.dv-dot { width: 8px; height: 8px; border-radius: 50%; display: block; background: var(--dv-low); }
.dv-dot.sev-critical, .dv-dot.sev-high { background: var(--dv-high); }
.dv-dot.sev-medium { background: var(--dv-med); }
.dv-num { font-family: var(--dv-mono); font-size: .72rem; color: var(--dv-faint); min-width: 1.5rem; }

.dv-tag { font-family: var(--dv-mono); font-size: .57rem; letter-spacing: .08em; text-transform: uppercase;
  border: 1px solid var(--dv-rule-2); border-radius: 5px; padding: .12rem .38rem;
  color: var(--dv-muted); white-space: nowrap; }
.dv-tag.sev-critical, .dv-tag.sev-high { color: var(--dv-high); border-color: rgba(var(--high-rgb, 251,146,60), .4); background: rgba(var(--high-rgb, 251,146,60), .1); }
.dv-tag.sev-medium { color: var(--dv-med); border-color: rgba(var(--med-rgb, 251,191,36), .35); background: rgba(var(--med-rgb, 251,191,36), .09); }
.dv-tag--layer { color: var(--dv-accent); border-color: var(--dv-accent-dim); background: var(--dv-accent-dim); }

/* ── blocks (the composed body) ───────────────────────────────────────── */
.dv-blk { margin-top: .8rem; }
.dv-blk:first-child { margin-top: .3rem; }
.dv-blk__k { font-family: var(--dv-mono); font-size: .57rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--dv-faint); margin-bottom: .25rem; }
.dv-blk p { margin: 0; font-size: .86rem; line-height: 1.62; color: var(--dv-text-2); max-width: 78ch; }
.dv-blk ul, .dv-blk ol { margin: .15rem 0 0; padding-left: 1.15rem; }
.dv-blk li { font-size: .85rem; line-height: 1.58; color: var(--dv-text-2); padding: .1rem 0; max-width: 78ch; }
.dv-blk--none p { color: var(--dv-faint); font-style: italic; }
/* The overflow control on a capped list. It reads as a control, not a caption —
   a static "+ 2 more" looks like a miscount when you can't act on it. */
.dv-morelist { margin-top: .3rem; font-family: var(--dv-mono); font-size: .62rem; letter-spacing: .05em;
  text-transform: uppercase; padding: .26rem .5rem; border-radius: 6px; cursor: pointer;
  border: 1px dashed var(--dv-rule-2); background: none; color: var(--dv-muted); }
.dv-morelist:hover { border-style: solid; border-color: var(--dv-accent); color: var(--dv-accent); }
@media print { .dv-morelist { display: none; } .dv-over[hidden] { display: list-item !important; } }

.dv-chips { display: flex; flex-wrap: wrap; gap: .32rem; }
.dv-chip { font-size: .74rem; color: var(--dv-muted); background: none; border: 1px solid var(--dv-rule);
  border-radius: 20px; padding: .18rem .6rem; text-decoration: none; white-space: nowrap; }
a.dv-chip:hover { border-color: var(--dv-accent); color: var(--dv-accent); }
.dv-url { font-family: var(--dv-mono); font-size: .68rem; color: var(--dv-muted); background: none;
  border: 1px solid var(--dv-rule); border-radius: 5px; padding: .16rem .42rem; word-break: break-all; }

.dv-ex__acts { display: flex; gap: .45rem; flex-wrap: wrap; align-items: center; margin-top: .95rem; }
.dv-go { font-size: .76rem; color: var(--dv-text-2); text-decoration: none; border: 1px solid var(--dv-rule-2);
  border-radius: 7px; padding: .3rem .62rem; background: none; cursor: pointer; white-space: nowrap; }
.dv-go:hover { border-color: var(--dv-accent); color: var(--dv-accent); }
.dv-go.copied { border-color: var(--dv-accent); color: var(--dv-accent); }

/* ── footer ───────────────────────────────────────────────────────────── */
.dv__foot { display: flex; align-items: center; gap: .55rem; flex-wrap: wrap; margin-top: .8rem; }
.dv__count { font-family: var(--dv-mono); font-size: .66rem; color: var(--dv-faint); margin-right: auto; }
.dv__more { font-size: .78rem; font-weight: 600; padding: .42rem .8rem; border-radius: 8px; cursor: pointer;
  border: 1px dashed var(--dv-rule-2); background: none; color: var(--dv-text-2); }
.dv__more:hover { border-style: solid; border-color: var(--dv-accent); color: var(--dv-accent); }
.dv__empty { color: var(--dv-faint); font-size: .85rem; padding: .7rem 0; font-style: italic; }

/* ── actions: progress + checkbox ─────────────────────────────────────── */
.dv-prog { display: flex; align-items: center; gap: .7rem; margin: 0 0 .8rem; }
.dv-prog__b { flex: 1; height: 6px; background: var(--dv-panel-2); border-radius: 3px; overflow: hidden; }
.dv-prog__f { display: block; height: 100%; background: var(--dv-accent); border-radius: 3px; transition: width .25s ease; }
.dv-prog__l { font-family: var(--dv-mono); font-size: .7rem; color: var(--dv-muted); white-space: nowrap; }
.dv-chk { width: 19px; height: 19px; border-radius: 6px; border: 1.5px solid var(--dv-rule-2); background: transparent;
  cursor: pointer; display: grid; place-items: center; padding: 0; flex: none; }
.dv-chk.on { background: var(--dv-accent); border-color: var(--dv-accent); }
.dv-chk svg { width: 11px; height: 11px; opacity: 0; }
.dv-chk.on svg { opacity: 1; }
.dv-ex.is-done .dv-ex__t { text-decoration: line-through; color: var(--dv-faint); }
.dv-ex.is-done .dv-ex__why { opacity: .6; }

/* The layer legend. "L1" means nothing to a customer on its own; three words
   next to it turn the plan's ranking into something they can act on. */
.dv-legend { display: flex; flex-wrap: wrap; gap: .3rem .9rem; margin: .1rem 0 .9rem;
  font-size: .78rem; color: var(--dv-muted); }
.dv-legend b { color: var(--dv-text-2); font-weight: 600; }

/* ── questions ────────────────────────────────────────────────────────── */
.dv-q { display: grid; grid-template-columns: 1.7rem 1fr auto; gap: .5rem .7rem; align-items: baseline;
  padding: .32rem 0; border-bottom: 1px solid var(--dv-rule); }
.dv-q:last-child { border-bottom: 0; }
.dv-q__n { font-family: var(--dv-mono); font-size: .66rem; color: var(--dv-faint); }
.dv-q__t { font-size: .85rem; color: var(--dv-text-2); line-height: 1.5; }
.dv-q__a { font-size: .68rem; padding: .12rem .48rem; }

/* ── visibility ───────────────────────────────────────────────────────── */
.dv-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
  border-top: 1px solid var(--dv-rule); border-bottom: 1px solid var(--dv-rule); margin: .2rem 0 1rem; }
.dv-kpi { border-left: 1px solid var(--dv-rule); padding: .85rem 1.05rem; }
.dv-kpi:first-child { border-left: 0; padding-left: 0; }
.dv-kpi__k { font-family: var(--dv-mono); font-size: .57rem; letter-spacing: .1em; text-transform: uppercase; color: var(--dv-faint); }
.dv-kpi__v { font-size: 1.55rem; font-weight: 600; letter-spacing: -.03em; margin-top: .1rem;
  font-variant-numeric: tabular-nums; color: var(--dv-text); }
.dv-kpi--hero .dv-kpi__v { color: var(--dv-accent); }
.dv-kpi__s { font-size: .72rem; color: var(--dv-faint); }

.dv-lede { font-size: .9rem; color: var(--dv-text-2); border-left: 2px solid var(--dv-rule-2);
  padding-left: .9rem; margin: 0 0 1rem; max-width: 76ch; line-height: 1.65; }
.dv-lede b { color: var(--dv-text); font-weight: 600; }

/* ── PROSE ────────────────────────────────────────────────────────────────
   The narrative sections arrive as one long string. Rendered as a single
   paragraph at full column width they became a wall nobody reads — the
   executive summary was twenty unbroken lines. Three rules fix it: a measure
   near 62 characters (not the full column), real space between paragraphs, and
   a line-height that lets the eye find the next line. */
/* Measure. The readable band is roughly 45–75 characters; the column these sit
   in is ~900px, which is ~90ch — too long to read. But at 62ch the text stopped
   at 69% of the column while the tables above and below ran edge to edge, and
   that mismatch reads as a wrapping bug rather than as considered typography.
   74ch is the top of the readable band and closes most of the gap. */
.dv-prose { max-width: 74ch; }
.dv-prose p { font-size: .93rem; line-height: 1.72; color: var(--dv-text-2); margin: 0 0 .95rem; }
.dv-prose p:last-child { margin-bottom: 0; }
.dv-prose--nar { margin-bottom: 1.1rem; }
.dv-prose--nar .dv-lede { margin-bottom: .8rem; }

/* A pull quote for the one sentence a section turns on. Bigger than body copy
   and set apart, because it is the finding — not an introduction to it. */
/* The pull quote carries a full sentence, not a three-word headline — at 34ch
   that was six lines of four words in a 900px column. Wider measure, and a size
   that earns the space it takes. */
.dv-pull { font-size: 1.2rem; line-height: 1.42; font-weight: 600; letter-spacing: -.02em;
  color: var(--dv-text); max-width: 50ch; margin: .25rem 0 1rem; padding-left: 1rem;
  border-left: 3px solid var(--dv-accent); }

/* The TL;DR points. Each one is a finding, so they get room rather than being
   packed into a tight list. */
.dv-points { margin: .2rem 0 1.2rem; padding-left: 1.1rem; max-width: 76ch; }
.dv-points li { font-size: .92rem; line-height: 1.65; color: var(--dv-text-2); padding: .28rem 0; }
.dv-points li::marker { color: var(--dv-accent); }

.dv-note { font-size: .84rem; line-height: 1.6; color: var(--dv-muted); max-width: 78ch; margin: 0 0 .75rem; }

.dv-bars { display: grid; gap: .5rem; margin-top: .4rem; }
.dv-bars { margin-bottom: 1.2rem; }
.dv-bar { display: grid; grid-template-columns: minmax(140px, 262px) 1fr 92px; align-items: center;
  gap: .8rem; font-size: .84rem; padding: .1rem 0; }
.dv-bar__n { color: var(--dv-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dv-bar__t { height: 9px; background: var(--dv-panel-2); border-radius: 5px; overflow: hidden; }
.dv-bar__f { display: block; height: 100%; border-radius: 5px; background: var(--dv-rule-2); }
.dv-bar__v { font-family: var(--dv-mono); font-size: .78rem; text-align: right; color: var(--dv-text-2);
  display: flex; align-items: baseline; justify-content: flex-end; gap: .4rem; }
/* The raw counts sit beside the percentage, quieter — "12%" means little without
   "3/25" next to it, but the percentage is what you scan. */
.dv-bar__of { font-size: .66rem; color: var(--dv-faint); }
/* The figures behind a section narrative — "Label: value" pairs cut out of the
   pipeline's `data` sentence and set as two columns, so a reader scans them
   instead of reading them. Two-up where there is room; one column on a phone
   and, deliberately, on paper, where the label column would otherwise run to a
   measure nothing fills. */
.dv-figs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0; margin: .5rem 0 1.2rem; border-top: 1px solid var(--dv-rule); }
.dv-fig { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .9rem;
  align-items: baseline; padding: .42rem 1rem .42rem 0;
  border-bottom: 1px solid var(--dv-rule); font-size: .82rem; }
.dv-fig--wide { grid-column: 1 / -1; display: block; color: var(--dv-text-2); }
.dv-fig__k { color: var(--dv-muted); min-width: 0; }
/* No `white-space: nowrap` here. It kept short values like "4-0-3 (7 shared
   queries)" on one line, which is right, but an unbreakable long one had nowhere
   to go and ran straight through its own label and out past the right margin.
   Short values do not wrap anyway — there is room. */
.dv-fig__v { font-family: var(--dv-mono); font-size: .78rem; color: var(--dv-text);
  text-align: right; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
.dv-fig--wide b { color: var(--dv-text); font-weight: 600; }
@media (max-width: 760px) { .dv-figs { grid-template-columns: 1fr; } }

.dv-flag { text-decoration: none; color: var(--dv-med); cursor: help; margin-left: .1rem; }
.dv-note--foot { font-size: .74rem; margin: .1rem 0 0; }
.dv-bar.me .dv-bar__n, .dv-bar.me .dv-bar__v { color: var(--dv-accent); font-weight: 600; }
.dv-bar.me .dv-bar__f { background: var(--dv-accent); }
/* Tone comes from the analysis (vis_tone / win_tone), never from a threshold
   invented in the browser. Bad is the severity orange used everywhere else. */
.dv-bar.is-bad .dv-bar__f { background: var(--dv-high); }
.dv-bar.is-warn .dv-bar__f { background: var(--dv-med); }
.dv-bar.is-good .dv-bar__f { background: var(--dv-accent); }
.dv-bar.is-bad .dv-bar__v { color: var(--dv-high); }
.dv-bar .dv-tag { font-size: .5rem; padding: .05rem .28rem; margin-left: .3rem; vertical-align: middle; }

.dv-tbl-wrap { overflow-x: auto; }
.dv table { width: 100%; border-collapse: collapse; font-size: .85rem; margin: .3rem 0 0; }
.dv th { text-align: left; font-family: var(--dv-mono); font-size: .57rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--dv-faint); font-weight: 500; padding: .35rem .5rem .35rem 0; border-bottom: 1px solid var(--dv-rule); }
.dv td { padding: .44rem .5rem .44rem 0; border-bottom: 1px solid var(--dv-rule); vertical-align: top; color: var(--dv-text-2); }
/* A right-aligned column only loses its right padding when it's the LAST one.
   Zeroing it unconditionally jammed a right-aligned "Citations" column into the
   "Cited from" column beside it — the header read "CITATIONSCITED FROM". */
.dv td.r, .dv th.r { text-align: right; padding-right: 1.1rem; }
.dv td.r:last-child, .dv th.r:last-child { padding-right: 0; }
.dv tr.me td { color: var(--dv-accent); font-weight: 600; }

.dv-sub { font-size: .92rem; font-weight: 600; color: var(--dv-text); margin: 1.5rem 0 .5rem;
  padding-bottom: .3rem; border-bottom: 1px solid var(--dv-rule); display: flex; align-items: baseline; gap: .5rem; }
.dv-sub:first-child { margin-top: .2rem; }
.dv-sub .c { font-family: var(--dv-mono); font-size: .62rem; color: var(--dv-faint); font-weight: 400; }


/* ── visibility, drawn ───────────────────────────────────────────────────
   The scorecard grammar shared with /account/reader/: score and reading on the
   left, engine rings and count tiles on the right; every cut as a stacked bar
   of top pick / visible / absent; head-to-head as chips. Colours are the dv
   tokens plus four engine hues that hold on the dark screen and the white page. */
.dv { --dv-e-chatgpt: #2a9d6f; --dv-e-claude: #d4753a; --dv-e-gemini: #4d7fd6; --dv-e-perplexity: #23a8a3; --dv-info: var(--dvx-info, var(--rl-blue, #7aa6f5)); }
.dv-score { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: .6rem 2rem; align-items: start; margin: .2rem 0 1.4rem; break-inside: avoid; }
.dv-score__big { font-size: 3.8rem; line-height: 1; font-weight: 700; letter-spacing: -.04em; color: var(--dv-accent); margin: .25rem 0 .55rem; font-variant-numeric: tabular-nums; }
.dv-score__big small { font-size: 1.5rem; color: var(--dv-faint); font-weight: 600; margin-left: .1rem; }
.dv-lede--score { border-left: 0; padding-left: 0; margin-bottom: 0; }
.dv-ci { font-family: var(--dv-mono); font-size: .72rem; color: var(--dv-faint); }
.dv-sub--quiet { margin-top: .2rem; font-size: .8rem; font-weight: 500; color: var(--dv-muted); border-bottom: 0; padding-bottom: 0; }
.dv-rings { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.dv-ring { border: 1px solid var(--dv-rule); border-radius: 12px; padding: 8px 4px 9px; text-align: center; min-width: 0; break-inside: avoid; }
.dv-ring__svg { width: 56px; height: 56px; display: block; margin: 0 auto 5px; }
.dv-eng { display: inline-block; font-family: var(--dv-mono); font-size: .6rem; letter-spacing: .06em; text-transform: uppercase; padding: .16rem .4rem; border-radius: 5px; border: 1px solid; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.dv-eng--chatgpt { color: var(--dv-e-chatgpt); border-color: color-mix(in srgb, var(--dv-e-chatgpt) 45%, transparent); background: color-mix(in srgb, var(--dv-e-chatgpt) 12%, transparent); }
.dv-eng--claude { color: var(--dv-e-claude); border-color: color-mix(in srgb, var(--dv-e-claude) 45%, transparent); background: color-mix(in srgb, var(--dv-e-claude) 12%, transparent); }
.dv-eng--gemini { color: var(--dv-e-gemini); border-color: color-mix(in srgb, var(--dv-e-gemini) 45%, transparent); background: color-mix(in srgb, var(--dv-e-gemini) 12%, transparent); }
.dv-eng--perplexity { color: var(--dv-e-perplexity); border-color: color-mix(in srgb, var(--dv-e-perplexity) 45%, transparent); background: color-mix(in srgb, var(--dv-e-perplexity) 12%, transparent); }
.dv-ring__s { display: block; font-family: var(--dv-mono); font-size: .62rem; color: var(--dv-faint); margin-top: 4px; }
.dv-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 8px; }
.dv-tiles--2 { margin: .6rem 0 .8rem; }
.dv-tile { border: 1px solid var(--dv-rule); border-radius: 12px; padding: 10px 12px; min-width: 0; break-inside: avoid; }
.dv-tile__v { font-family: var(--dv-mono); font-size: 1.35rem; font-weight: 600; color: var(--dv-text); letter-spacing: -.02em; font-variant-numeric: tabular-nums; line-height: 1.15; }
.dv-tile__v small { font-size: .8rem; color: var(--dv-faint); font-weight: 400; }
.dv-tile__v.is-bad { color: var(--dv-high); }
.dv-tile__v.is-info { color: var(--dv-info); }
/* Said beside a number we cannot fully stand behind — a crawl scored before
   named and cited were separated. Mirrors .rdr .integrity in reader.css. */
.dv-integrity { font-size: .78rem; line-height: 1.5; color: var(--dv-muted); margin: .6rem 0 0;
  border-left: 2px solid var(--dv-med); padding-left: .6rem; }
.dv-tile__s { font-size: .74rem; color: var(--dv-muted); line-height: 1.35; margin-top: 2px; }
.dv-stack__key { display: flex; flex-wrap: wrap; gap: .4rem 1rem; font-family: var(--dv-mono); font-size: .66rem; color: var(--dv-muted); margin: .2rem 0 .5rem; }
.dv-stack__key i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: .3rem; vertical-align: -1px; }
.dv-stack__key .w { background: var(--dv-accent); } .dv-stack__key .v { background: var(--dv-info); } .dv-stack__key .a { border: 1px solid var(--dv-faint); }
.dv-stacks { display: grid; gap: .45rem; margin-bottom: 1.2rem; }
.dv-stack { display: grid; grid-template-columns: minmax(150px, 262px) 1fr 52px; align-items: center; gap: .8rem; font-size: .84rem; break-inside: avoid; }
.dv-stack__n { color: var(--dv-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dv-stack__n small { font-family: var(--dv-mono); font-size: .64rem; color: var(--dv-faint); margin-left: .45rem; }
.dv-stack__t { display: flex; height: 10px; background: var(--dv-panel-2); border-radius: 5px; overflow: hidden; gap: 2px; }
.dv-stack__t i { display: block; height: 100%; }
.dv-stack__t .w { background: var(--dv-accent); } .dv-stack__t .v { background: var(--dv-info); }
.dv-stack__v { font-family: var(--dv-mono); font-size: .82rem; text-align: right; color: var(--dv-text); font-variant-numeric: tabular-nums; }
.dv-stack.is-bad .dv-stack__v { color: var(--dv-high); } .dv-stack.is-warn .dv-stack__v { color: var(--dv-med); }
.dv-h2h { display: flex; flex-wrap: wrap; gap: 6px; margin: .2rem 0 1.2rem; }
.dv-h2h span { font-family: var(--dv-mono); font-size: .7rem; border: 1px solid var(--dv-rule-2); border-radius: 999px; padding: .28rem .6rem; color: var(--dv-text-2); break-inside: avoid; }
.dv-h2h span b { color: var(--dv-accent); font-weight: 600; } .dv-h2h span.l b { color: var(--dv-high); }
.dv-chips { display: flex; flex-wrap: wrap; gap: 5px; margin: .2rem 0 1.2rem; }
.dv-chip--flat, .dv-chips .dv-chip { pointer-events: none; }
@media (max-width: 760px) {
  .dv-score { grid-template-columns: 1fr; }
  .dv-stack { grid-template-columns: minmax(0, 1fr) 48px; }
  .dv-stack__n { grid-column: 1 / -1; }
  .dv-stack__t { grid-row: 2; } .dv-stack__v { grid-row: 2; }
}
@media print {
  .dv-score { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .dv-score__big { font-size: 3rem; }
  .dv-rings, .dv-tiles, .dv-stack__t, .dv-stack__t i, .dv-eng, .dv-h2h span, .dv-tile { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .dv-stacks, .dv-bars, .dv-h2h, .dv-chips { break-inside: avoid; }
}

/* ── responsive ───────────────────────────────────────────────────────── */
@media (max-width: 680px) {
  .dv-ex__hd { grid-template-columns: auto 1fr auto; gap: .5rem .55rem; }
  .dv-ex__chev { grid-column: 3; grid-row: 1; }
  .dv-ex__tags { grid-column: 1 / -1; justify-content: flex-start; }
  .dv-ex__why { grid-column: 1 / -1; }
  .dv-kpis { grid-template-columns: repeat(2, 1fr); }
  .dv-kpi:nth-child(3) { border-left: 0; padding-left: 0; }
  .dv-kpi:nth-child(n+3) { border-top: 1px solid var(--dv-rule); }
  .dv-bar { grid-template-columns: 1fr auto; gap: .3rem .6rem; padding: .3rem 0; }
  .dv-bar__n { grid-column: 1; white-space: normal; }
  .dv-bar__v { grid-column: 2; }
  .dv-bar__t { grid-column: 1 / -1; }
  .dv-pull { font-size: 1.02rem; max-width: none; }
  .dv-prose, .dv-points, .dv-note { max-width: none; }
  .dv-q { grid-template-columns: 1.5rem 1fr; }
  .dv-q__a { grid-column: 2; justify-self: start; }
  /* Filters scroll sideways rather than stacking four rows deep. */
  .dv__tools { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding-bottom: .2rem; }
  .dv__tools::-webkit-scrollbar { display: none; }
  .dv-chip-f, .dv__b { flex: none; min-height: 36px; }
  .dv__find { flex: 1 0 160px; }
  .dv__foot { flex-direction: column; align-items: stretch; }
  .dv__count { order: 3; margin-right: 0; text-align: center; }
  .dv__more, .dv__foot .dv-go { text-align: center; justify-content: center; }
}

/* ─────────────────────────────────────────────────────────────────────────
   CONTENTS RAIL (mountToc)
   Moved here verbatim from booklet.css so every viewer shares one rail rather
   than the foundation review having a good one and the rest having none.
   ───────────────────────────────────────────────────────────────────────── */
/* Slide-out side Table of Contents — stacked links, always reachable via the
   handle, open by default on wide screens. */
.chapter-toc { position: fixed; top: var(--rl-topnav-h, 64px); left: 0; bottom: 0; z-index: 40; pointer-events: none; }
.chapter-toc__handle {
  pointer-events: auto; position: absolute; top: 1.5rem; left: 0;
  display: inline-flex; align-items: center; gap: 0.4rem;
  background: var(--btn-fill, #3f5c0b); color: var(--btn-ink, #f4ffe0); border: none; cursor: pointer;
  font: inherit; font-size: 0.8rem; font-weight: 700; padding: 0.55rem 0.75rem;
  border-radius: 0 10px 10px 0; box-shadow: 2px 2px 12px rgba(0,0,0,0.4);
  transition: left .25s ease;
}
.chapter-toc__handle-icon { font-size: 0.95rem; }
.chapter-toc__list {
  pointer-events: auto; position: absolute; top: 1rem; left: 0;
  width: 240px; max-height: calc(100vh - var(--rl-topnav-h, 64px) - 2rem); overflow-y: auto;
  display: flex; flex-direction: column; gap: 0.3rem; padding: 0.8rem;
  background: var(--paper, var(--bg-card, #141416)); border: 1px solid var(--border, var(--rule, #27272a)); border-left: none;
  border-radius: 0 14px 14px 0; box-shadow: 6px 0 30px rgba(0,0,0,0.5);
  transform: translateX(-100%); transition: transform .25s ease; scrollbar-width: thin;
}
.chapter-toc.is-open .chapter-toc__list { transform: translateX(0); }
.chapter-toc.is-open .chapter-toc__handle { left: 240px; }

/* Desktop: the open rail is DOCKED, not an overlay — so the report has to clear
   it instead of sitting behind it (on a ~1180px Retina laptop the centred column
   used to slide under the 240px rail and clip on the left). Reserve the rail's
   width and re-centre in the space that's left; on wide screens the column ends
   up centred again, on tighter ones it left-aligns just past the rail. Below
   1101px the rail is an overlay drawer (scrim + closed by default), so none of
   this must apply there. */
@media (min-width: 1101px) {
  /* Every viewer's main column is #doc, so one rule makes room for the docked
     rail on all of them. Page-specific furniture (the notes FAB, the approval
     bar) clears it in that page's own sheet. */
  body.has-toc #doc { margin-left: max(288px, calc(50% - 440px)); margin-right: auto; }
  /* Open, the handle is a compact collapse tab at the rail edge — the "Contents"
     label is only needed when it's closed. */
  body.has-toc .chapter-toc__handle-text { display: none; }
}
.toc-item {
  display: flex; align-items: center; gap: 0.55rem; width: 100%; text-align: left;
  padding: 0.5rem 0.7rem; border-radius: 9px; cursor: pointer;
  background: transparent; border: 1px solid transparent;
  color: var(--text-secondary, var(--ink-3, #a1a1aa)); font: inherit; font-size: 0.88rem; line-height: 1.3; transition: all .12s ease;
}
.toc-item:hover { background: rgba(var(--ink-rgb, 255,255,255), 0.05); color: var(--text, var(--ink, #fafafa)); }
.toc-item.is-active { background: var(--accent-glow, var(--accent-dim, rgba(200,255,0,0.08))); border-color: rgba(var(--accent-rgb, 200,255,0), .4); color: var(--text, var(--ink, #fafafa)); font-weight: 600; }
.toc-item__n { flex: 0 0 auto; width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; border-radius: 6px; background: var(--border, var(--rule, #27272a)); color: var(--text-secondary, var(--ink-3, #a1a1aa)); font-family: var(--mono, monospace); font-size: 0.72rem; }
.toc-item.is-active .toc-item__n { background: var(--accent-fill, var(--accent, #c8ff00)); color: var(--accent-ink, #09090b); }
.toc-item__t { flex: 1; }
/* Scrim sits behind the drawer on phones so it reads as a real overlay (and taps
   to close). Hidden / inert on desktop where the TOC is a docked rail. */
.chapter-toc__scrim { display: none; }

/* Wherever the TOC is a DRAWER rather than a docked rail — which is everywhere
   below 1101px, the breakpoint that docks it in deliverable.css.
   This block was written for phones and scoped to 680px, leaving 681–1100px
   (both iPad orientations) running drawer behaviour in docked-rail clothing: no
   scrim, and the full-width "Contents" tab floating on top of the reading column
   where it covered the first words of the chapter line — "Chapter 1 of 11"
   rendered as "…of 11". Same mistake as the approval bar: the fix was right, its
   breakpoint described a device instead of the mode it belonged to. */
@media (max-width: 1100px) {
  /* The TOC is an overlay drawer, not a docked rail: lift the whole thing above
     the bottom approval bar (z 50) so it never renders behind it, dim the page
     behind the open panel, and shrink the edge handle to an icon. */
  .chapter-toc.is-open { z-index: 60; }
  .chapter-toc.is-open .chapter-toc__scrim {
    display: block; pointer-events: auto; cursor: pointer; border: 0; padding: 0;
    position: fixed; left: 0; right: 0; bottom: 0; top: var(--rl-topnav-h, 64px);
    background: rgba(9, 9, 11, 0.62);
  }
  .chapter-toc__list { width: min(82vw, 280px); }
  /* Keep the handle pinned to the left edge under the open drawer (the scrim +
     a chapter tap close it), so it can't poke out past the panel. */
  .chapter-toc.is-open .chapter-toc__handle { left: 0; }
  /* Below 1101px the rail collapses and the handle docks at the left edge — where it
     landed on top of the chapter kicker. The handle spans x 0-31 and the content column
     starts at 24, so it clipped the first character of "CHAPTER n OF n" at every width
     from 390 up to 1100. Dropping it into the gap between the kicker and the chapter
     title clears both without moving the content or breaking the kicker's alignment
     with the heading under it. */
  .chapter-toc__handle { top: 3.5rem; padding: 0.5rem 0.55rem; }
  .chapter-toc__handle-text { display: none; }
}

/* A page can take the rail out entirely (the visibility report's presentation
   mode is a slide deck — a docked contents rail has no place in it). */
.chapter-toc.is-gone { display: none !important; }

/* Group headings and sub-items — a five-section report needs a second level in
   the rail; a chapter list doesn't use them and is unaffected. */
.toc-group { font-family: var(--mono, monospace); font-size: .58rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-faint, var(--grey, #71717a)); padding: .7rem .7rem .2rem; }
.toc-group:first-child { padding-top: .1rem; }
.toc-item--sub { padding-left: 1.5rem; font-size: .82rem; color: var(--text-muted, var(--ink-3, #a1a1aa)); }
.toc-item.is-off { opacity: .45; }
.toc-item__c { flex: 0 0 auto; font-family: var(--mono, monospace); font-size: .68rem; color: var(--text-faint, var(--grey, #71717a)); }
@media print { .chapter-toc { display: none !important; } body.has-toc #doc { margin-left: auto !important; } }

/* ── print ────────────────────────────────────────────────────────────── */
/* Paper has no disclosure triangles: everything opens, and every control goes. */
@media print {
  .dv__tools, .dv-ex__chev, .dv-ex__acts, .dv__more, .dv-chk, .dv-prog { display: none !important; }
  /* Copy that describes a control print has just removed. */
  .dv-screen-only { display: none !important; }
  .dv-ex__body { display: block !important; }
  .dv-ex, .dv-ex.is-open, .dv-ex.is-hit { box-shadow: none !important; padding-left: 0 !important;
    break-inside: avoid; page-break-inside: avoid; }
  .dv-ex[hidden] { display: revert !important; }
  .dv-ex__hd { padding: .25rem 0; }

  /* Sized to content, not to the column. `.dv table { width:100% }` is right on
     a 900px screen column and wrong on a 7.1in page — it put the label at one
     edge and its number at the other with five inches of nothing between. This
     has to live here rather than in the report's own print block: `.dv table`
     out-specifies a bare `table` selector, so an override there never applied. */
  .dv table { width: auto; min-width: 3.4in; max-width: 100%; }
  .dv-tbl-wrap { overflow: visible; }

  /* THE CLOSED-ROW TEASER MUST GO. `.dv-ex__why` is the clipped first 200
     characters of the same text the body opens with — on screen you see one or
     the other, never both, because the teaser is only rendered while the row is
     shut. Print opens every body without clearing the teaser, so each action
     printed its summary, ending in a literal "…", directly above the identical
     paragraph in full. Twice over, forty-one times, in the document a customer
     forwards to their board. */
  .dv-ex__why { display: none !important; }

  /* SEVERITY NEEDS A CHANNEL THAT ISN'T COLOUR. The dot is the only marker on a
     closed findings row and it carried hue alone, so a greyscale print reduced
     critical, medium and low to the same grey circle. Shape survives any
     printer: filled, ringed, hollow. */
  .dv-dot { box-sizing: border-box; background: transparent;
    border: 1.5px solid var(--dv-low); }
  .dv-dot.sev-critical, .dv-dot.sev-high { background: var(--dv-high); border-color: var(--dv-high); }
  .dv-dot.sev-medium { background: transparent; border: 2.5px solid var(--dv-med); }

  /* A block's LABEL must never be the last thing on a page — "The moves" at the
     foot with its list overleaf is the one break that actually misleads. The
     list itself is free to break; asking to keep a box taller than the page
     whole just strands the page instead. */
  .dv-blk__k { break-after: avoid; page-break-after: avoid; }

  /* The closing count ("41 of 41") is worth printing — it tells the reader
     nothing was truncated — but it had landed alone on a page of its own. */
  .dv__foot { break-before: avoid; page-break-before: avoid; }

  /* The reader's own intro used to split mid-sentence — "…each one is a concrete
     fix, with an owner and an effort" stopped dead at a page foot and resumed
     overleaf, with six inches of white under it. Keep the block whole. */
  .dv__hd, .dv__note { break-inside: avoid; page-break-inside: avoid; }

  /* ── the questions section ────────────────────────────────────────────
     Eleven pages of identical rows, with the buyer's name printed exactly once
     at the top of the first of them. A reader four pages into the run had no
     way of telling whose questions these were, and no rhythm in the page to
     hold on to. This is the section people give up in.

     EVERY BUYER STARTS A PAGE, AND FITS ON IT. CSS gives you exactly one way to
     repeat a heading across a page break — `thead` on a real table — and these
     are divs, shared with the screen. So the attribution is guaranteed the
     other way: each group begins a page, and the list is set tight enough that
     the largest set here (33 questions) lands inside one. The section goes from
     eleven undifferentiated pages to one per buyer, each headed by the buyer.
     A set too long to fit still spills, and degrades to the old behaviour.

     Not multi-column: two columns halve the measure and would fit these
     comfortably, but Chromium's fragmenter miscomposes a multicol inside a
     paged block — it duplicated and dropped rows (two "16"s, no "10"). A
     correct list at a smaller size beats a dense one that lies. */
  /* `.dv__list` is a flex column, and Chromium's paged-media fragmenter ignores
     break-before on a flex ITEM. As a block container the same stack of rows
     lays out identically and the breaks are honoured. */
  .dv--questions .dv__list { display: block; }
  .dv--questions .dv-ex { break-before: page; page-break-before: always;
    break-inside: auto; page-break-inside: auto; margin: 0; }
  /* The buyer's name is now a group opener rather than a row title. */
  .dv--questions .dv-ex__hd { padding: 0 0 .45rem; margin-bottom: .55rem;
    border-bottom: 1.5px solid var(--dv-rule-2); break-after: avoid; page-break-after: avoid; }
  .dv--questions .dv-ex__t { font-size: 1.05rem; }
  /* Tuned so the largest buyer set here (33) lands on one page. It is a fit, not
     a guarantee: a longer set spills, which is the old behaviour and still
     readable — the page break above is what keeps every set headed. */
  .dv--questions .dv-q { padding: .1rem 0; break-inside: avoid; page-break-inside: avoid; }
  .dv--questions .dv-q__t { font-size: .745rem; line-height: 1.32; }
  .dv--questions .dv-q__n { font-size: .58rem; }
  .dv--questions .dv-q__a { font-size: .58rem; padding: .05rem .36rem; }
}

/* ── action plates ───────────────────────────────────────────────────────── */
.dv-plate { margin: .2rem 0 .6rem; padding: .7rem .9rem; border: 1px solid var(--dv-rule); border-radius: 10px; background: var(--dv-panel-2); }
.dv-plate__facts { display: flex; flex-wrap: wrap; gap: .35rem 1.1rem; font-size: .82rem; color: var(--dv-text-2); }
.dv-plate__f b { color: var(--dv-text); font-weight: 600; }
.dv-plate__u { font-family: var(--dv-mono); font-size: .72rem; color: var(--dv-muted); }
.dv-plate__k { font-family: var(--dv-mono); font-size: .58rem; letter-spacing: .12em; text-transform: uppercase; color: var(--dv-faint); margin: .7rem 0 .35rem; }
.dv-plate .dv-chips { margin: 0; }
.dv-plate__ac { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.dv-plate__acr { display: flex; flex-direction: column; align-items: center; gap: .3rem; padding: .4rem .3rem; border: 1px solid var(--dv-rule); border-radius: 8px; }
.dv-plate__acv { font-family: var(--dv-mono); font-size: .62rem; color: var(--dv-muted); }
.dv-plate__acv.is-hi { color: var(--dv-accent); }
@media (max-width: 600px) { .dv-plate__ac { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* On paper every action is a plate: framed, kept together, its title set as a
   heading with the rank in the margin, the strip above the brief. The bookmark
   per action already exists; this gives the page it lands on a shape. */
@media print {
  .dv--actions .dv-ex { border: 1px solid var(--dv-rule); border-radius: 10px; padding: .55rem .8rem .6rem !important; margin: 0 0 .7rem; break-inside: avoid; page-break-inside: avoid; box-shadow: none !important; }
  .dv--actions .dv-ex__hd { border-bottom: 1px solid var(--dv-rule); padding-bottom: .4rem; margin-bottom: .3rem; }
  .dv--actions .dv-ex__t { font-size: 1rem; }
  .dv--actions .dv-plate { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .dv-plate__acr, .dv-plate__ac { break-inside: avoid; }
}
