/* ============================================================================
   rashomon · type system ("bancada")

   The site is an instrument that measures words, and it is dressed like one. Every limit a
   reader sees -- where a section starts, what is a title and what is a caption, which number is
   the answer -- is drawn by type, by a hairline, or by the dot grid the figures sit on. Colour
   is a second hierarchy, and it means something; it never ranks a heading. Five dials do that
   work, and nothing else is allowed to:

     1. FAMILY  IBM Plex Sans Condensed names a thing, in capitals. IBM Plex Sans explains a
                thing. IBM Plex Mono measures a thing: every number, every label, every word on a
                figure, and the sentence a reader edits.
     2. SIZE    One ramp, --t-*. A component never invents a size. Rank is carried at least as
                much by weight, case and family as by size.
     3. COLOUR  --ink is "read this", --accent (amber) is the live thing and the label marker,
                --hostile and --favor are evaluation, --cmp-a/--cmp-b are who, --muted is
                "this supports it". A heading that needed colour to be found is a heading in the
                wrong place.
     4. SPACE   Base 4px. The gap above a heading IS its rank. More air, higher rank.
     5. SURFACE --bg (with its dot grid) < --panel < --soft. A figure is --panel with a 1px
                --line outline: the one border the site draws, and it draws it on every figure
                alike. Data hues stay on marks; they never tint a surface.

   The hierarchy, top to bottom:

     h1        --t-mega  display 700 caps  ink    what this page is        (once per page)
     h2        --t-xl    display 700 caps  ink    what this section is
     h3        --t-lg    display 600 caps  ink    what this block is
     h4        --t-md    display 600 caps  ink    one thing inside a block
     .lede     --t-base  mono 400          muted  the sentence under an h1
     .sentence --t-base  mono 400          ink    the sentence you can change
     p, li     --t-base  sans 400          ink    prose
     .figure-sub --t-sm  mono 400          muted  prose that supports a title
     .figure-key dt --t-2xs mono 500       accent names an encoding
     .figure-key dd --t-sm  mono 400       muted  what that encoding means
     .note,.meta --t-xs  sans 400          muted  captions, counts, footnotes
     .eyebrow  --t-2xs   mono 500          muted  names the rank right below it, after a "//"
     dt / dd             see "definition pairs"
   ========================================================================= */

:root {
  --bg: #0b0e0d;
  --panel: #111615;
  --soft: #1a2220;
  --line: #243029;
  --ink: #d6ded8;
  --muted: #7b8a82;
  --accent: #f0b429;
  --accent-ink: #111411;
  --hostile: #ff7a8a;
  --favor: #74dc86;
  --green: #b9cdc0;
  --danger: #ff8a8a;
  /* Quiet grey in the middle of every ramp: SCALE_MID in format.ts. Not --muted (chrome). */
  --scale-mid: #8b909c;
  /* The ruler figure's own hue pair, one per side (issue #91): kept in step with format.js's
     balanceColor, whose ends resolve to these exact colours. */
  --cmp-a: #7fa8ff;
  --cmp-b: #ff9d6b;
  /* The tema mask (issue #217): six discrete slots for term communities, a Louvain build's own
     grouping, never comparable across builds. Fixed order, distinct from each other and from
     --hostile/--favor/--cmp-a/--cmp-b, each >=4.5:1 against --bg. A 7th+ community paints --muted
     via themeMask's null return, so a 7th slot is never needed. */
  --theme-1: #3987e5;
  --theme-2: #dd543c;
  --theme-3: #199e70;
  --theme-4: #b35bd1;
  --theme-5: #d55181;
  --theme-6: #9085e9;

  --sans: 'IBM Plex Sans', system-ui, sans-serif;
  --display: 'IBM Plex Sans Condensed', 'IBM Plex Sans', system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* The ramp. Nine steps, ratio around 1.25, the top three fluid so a 375px phone and a 1440px
     desktop read the same ranks rather than the same pixels. The condensed display face is
     narrow, so the top steps run smaller than a wide face would need. --t-micro is the floor and
     exists for SVG labels only; nothing on this site is smaller. */
  --t-mega: clamp(34px, 5vw, 58px);
  --t-xl: clamp(24px, 2.8vw, 34px);
  --t-lg: clamp(18px, 2vw, 23px);
  --t-md: 17px;
  --t-base: 15px;
  --t-sm: 14px;
  --t-xs: 13px;
  --t-2xs: 12px;
  --t-micro: 11px;

  /* Line height falls as size rises: display type sets tight, prose sets open. --lh-chip is the
     sentence's own, where a <select> chip needs room to sit on the line without touching it. */
  --lh-tight: 1.02;
  --lh-snug: 1.15;
  --lh-mid: 1.35;
  --lh-body: 1.6;
  --lh-chip: 2;

  /* The condensed face is already tight; capitals need a little air, and mono labels need none. */
  --tr-mega: -.02em;
  --tr-xl: -.01em;
  --tr-lg: 0;
  --tr-label: .04em;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: clamp(56px, 7vw, 96px);

  /* A line of prose stops being readable past ~70 characters. Big type stops sooner. */
  --measure: 66ch;
  --measure-narrow: 48ch;
  --measure-lede: 42ch;

  --gutter: clamp(16px, 4vw, 56px);
}

* { box-sizing: border-box; }
html { overflow-x: hidden; scroll-behavior: smooth; }
/* The dot grid is the bench the figures sit on. It lives on the page, never on a panel, so a
   figure's own ground stays flat behind its marks. */
body { margin: 0; background: var(--bg) radial-gradient(var(--line) .7px, transparent .8px) 0 0 / 16px 16px; color: var(--ink); font: 400 var(--t-base)/var(--lh-body) var(--sans); overflow-x: hidden; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
button, input, select { font: inherit; color: inherit; }
button, a, select { -webkit-tap-highlight-color: transparent; }
button { cursor: pointer; }
button:disabled { cursor: default; opacity: .45; }
/* Focus, without a ring. A keyboard reader has to be told where they are -- that is not
   decoration and it does not get dropped -- but a 2px box drawn around a control is a border, and
   this site draws none. So focus speaks the two languages the rest of the page speaks: a control
   floods with a tint (an inset shadow, which has no edge of its own), and a link takes an
   underline, which is type. Marks in SVG answer with their own ground and opt out here. */
:focus-visible { outline: none; }
button:focus-visible, select:focus-visible, input:focus-visible, summary:focus-visible { box-shadow: inset 0 0 0 999px color-mix(in srgb, var(--accent) 14%, transparent); color: var(--ink); }
a:focus-visible { color: var(--accent); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 5px; }
[hidden] { display: none !important; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* ---------- the elements, one fixed style each ---------- */
/* Headings are the display family without exception, and they carry no colour of their own: a
   heading that needed --accent to be found is a heading in the wrong place. */
h1, h2, h3, h4 { margin: 0; font-family: var(--display); color: var(--ink); text-wrap: balance; text-transform: uppercase; }
h1 { font-size: var(--t-mega); font-weight: 700; line-height: var(--lh-tight); letter-spacing: var(--tr-mega); }
h2 { font-size: var(--t-xl); font-weight: 700; line-height: var(--lh-snug); letter-spacing: var(--tr-xl); }
h3 { font-size: var(--t-lg); font-weight: 600; line-height: var(--lh-snug); letter-spacing: var(--tr-lg); }
h4 { font-size: var(--t-md); font-weight: 600; line-height: var(--lh-mid); }

p, li { margin: 0; font-size: var(--t-base); line-height: var(--lh-body); }
p { max-width: var(--measure); }
ol, ul { margin: 0; padding-left: 20px; }
li + li { margin-top: var(--space-2); }

/* <b> and <strong> mean two different jobs and get two different weights: <strong> raises a word
   inside a sentence, <b> is the site's way of writing a value the sentence is about. */
strong { font-weight: 600; }
b { font-weight: 600; color: var(--ink); }
em { font-style: italic; }
a { color: var(--accent); }
small { font-size: var(--t-xs); color: var(--muted); }
code { font-family: var(--mono); font-size: .92em; color: var(--ink); }

/* An eyebrow is the smallest type on the site, set in mono like every other label. It never
   stands alone: it names whatever sits directly under it, and it is what replaces a rule line.
   The "//" is the label marker of the whole site, in the accent, so an eyebrow is found by its
   mark and never by its colour. */
.eyebrow, .stat dt { font-family: var(--mono); font-size: var(--t-2xs); font-weight: 500; line-height: 1.3; letter-spacing: var(--tr-label); color: var(--muted); }
.eyebrow::before { content: '// '; color: var(--accent); }

/* Supporting prose. Three ranks below body, each one step smaller and all of them muted, so the
   eye can skip every one of them and still get the page. */
.lede { max-width: var(--measure-lede); font-family: var(--mono); font-size: var(--t-base); line-height: var(--lh-body); color: var(--muted); text-wrap: pretty; }
.figure-sub, .chapter-intro { font-family: var(--mono); font-size: var(--t-sm); line-height: var(--lh-body); color: var(--muted); max-width: var(--measure); text-wrap: pretty; }
.note, .meta, .empty-hint { font-size: var(--t-xs); line-height: var(--lh-body); color: var(--muted); }

/* ---------- definition pairs ---------- */
/* dt names, dd answers. The default is a real definition list: the term in display type, its
   explanation in sans underneath. */
dl { margin: 0; }
dt { font-family: var(--display); font-size: var(--t-md); font-weight: 600; line-height: var(--lh-snug); letter-spacing: var(--tr-lg); text-transform: uppercase; color: var(--ink); }
dd { margin: 0; font-size: var(--t-sm); line-height: var(--lh-body); color: var(--muted); }

/* .stat is the one named exception, and it inverts the pair: a measurement is a number with a
   caption, not a term with a definition. So the dd becomes the headline and the dt drops to
   eyebrow rank underneath it -- same two elements, one variant with a name to learn. */
.stat > div { display: flex; flex-direction: column-reverse; gap: var(--space-1); }
.stat dd { font-family: var(--mono); font-size: var(--t-lg); font-weight: 500; line-height: var(--lh-snug); letter-spacing: 0; color: var(--ink); font-variant-numeric: tabular-nums; }
.stat dt { color: var(--accent); }

/* ---------- header ---------- */
.top { display: flex; align-items: center; gap: var(--space-5); padding: 18px var(--gutter); }
/* Margin, not gap: gap would also push the accent dot away from the word. */
/* The mark shares its rank with an h3: the site's name is a peer of a block title, under the
   page's own h1, which is the point of having an h1 at all. */
.brand { display: inline-flex; align-items: center; font-family: var(--mono); font-size: var(--t-base); font-weight: 600; line-height: 1; color: var(--accent); text-decoration: none; flex: 0 0 auto; }
.brand img { width: 28px; height: 28px; margin-right: var(--space-3); flex: 0 0 auto; }
.brand span { color: var(--ink); }
.person-pick:empty { display: none; }
.top nav { margin-left: auto; display: flex; flex-wrap: wrap; gap: var(--space-5); font-family: var(--mono); font-size: var(--t-sm); }
.top nav a { color: var(--muted); text-decoration: none; }
.top nav a:hover { color: var(--ink); }

.skip { position: absolute; left: var(--gutter); top: 8px; z-index: 8; padding: var(--space-2) var(--space-3); background: var(--accent); color: var(--accent-ink); font-size: var(--t-sm); font-weight: 600; text-decoration: none; border-radius: 2px; transform: translateY(-120%); }
.skip:focus { transform: none; }

main { max-width: 1440px; margin: auto; padding: var(--space-2) var(--gutter) var(--space-8); }

/* ---------- masthead: the one h1 ---------- */
/* The top of the ramp, and the only place --t-mega is allowed. Its job is to make every h2 below
   read as "a part of this", which is what stops three figure cards from looking like three sites. */
.masthead { padding: var(--space-6) 0 var(--space-7); }
.masthead h1 { margin-top: var(--space-3); max-width: 16ch; }
.masthead .lede { margin-top: var(--space-4); }

/* ---------- the sentence that controls each figure's own recorte ---------- */
/* Figure 1's stats badge, next to its title -- same spot and voice as #testimonyLabel next to
   #testimonyTitle: no colour of its own, so .figure-title h2 b's accent wins on both. */
#atlasStats { font-size: var(--t-sm); font-weight: 500; white-space: nowrap; margin-left: var(--space-2); letter-spacing: 0; }
/* Each figure's sentence lives inside its own .figure-head, which is a two-column grid
   (title | subtitle); both figure heads wrap their sentence in the same .sentence div, so one
   rule spans it across both columns to read as its own row underneath them. */
.figure-head > .sentence { grid-column: 1 / -1; margin-top: var(--space-5); }
.sentence { margin-bottom: 0; }
/* The sentence sits at lede rank but in sans 500 and full --ink: it is the one paragraph on the
   page a reader can edit, and it has to read as a control surface, not as a caption. Each
   control is a chip on the line -- a filled box with a chevron reads as "this changes", where a
   bare underline read as a link. A <select> ignores line-height for its own box, so the chip
   gets an explicit height; the sentence's line-height is what keeps daylight between lines. */
.sentence-line { font-family: var(--mono); font-size: var(--t-base); line-height: var(--lh-chip); font-weight: 400; max-width: 1120px; }
.pick { display: inline-block; position: relative; max-width: 100%; vertical-align: baseline; margin: 0; }
.keep { white-space: nowrap; }
/* The chevron is drawn in CSS so it follows --accent; a data-URI SVG cannot read a token. */
.pick::after { content: ''; position: absolute; right: .55em; top: 50%; width: .32em; height: .32em; border-right: 2px solid var(--accent); border-bottom: 2px solid var(--accent); transform: translateY(-70%) rotate(45deg); pointer-events: none; }
.pick select { appearance: none; -webkit-appearance: none; max-width: 100%; background: var(--soft); border: 1px solid var(--line); border-radius: 2px; padding: 0 1.25em 0 .5em; height: 1.6em; color: var(--accent); font-family: inherit; font-size: inherit; line-height: 1.5em; font-weight: 500; cursor: pointer; text-overflow: ellipsis; field-sizing: content; vertical-align: baseline; transition: background-color .12s, border-color .12s; }
.pick select:hover { background-color: var(--line); border-color: var(--muted); color: var(--ink); }
/* A searchable select (src/ui/combobox.ts): the <select> stays as the value store and hides,
   the input takes its exact face, the listbox drops below it inside the same .pick. Every part
   is a <span>: the .pick sits inside a <p>, and a <div> there makes the parser close the <p>. */
.combo-input { appearance: none; -webkit-appearance: none; max-width: 100%; min-width: 7ch; background: var(--soft); border: 1px solid var(--line); border-radius: 2px; padding: 0 1.25em 0 .5em; height: 1.6em; color: var(--accent); font-family: inherit; font-size: inherit; line-height: 1.5em; font-weight: 500; cursor: text; text-overflow: ellipsis; field-sizing: content; vertical-align: baseline; transition: background-color .12s, border-color .12s; }
.combo-input:hover, .combo-input:focus { background-color: var(--line); border-color: var(--muted); color: var(--ink); }
.combo-input::placeholder { color: var(--muted); font-weight: 400; }
.combo-list { position: absolute; top: calc(100% + 4px); left: 0; z-index: 30; min-width: 100%; width: max-content; max-width: min(28rem, 90vw); max-height: 40vh; overflow-y: auto; background: var(--panel); border: 1px solid var(--line); border-radius: 2px; padding: var(--space-1) 0; font-size: var(--t-sm); font-weight: 400; line-height: 1.4; text-align: left; }
.combo-group, .combo-option, .combo-empty { display: block; }
.combo-group { padding: var(--space-2) var(--space-3) var(--space-1); }
.combo-option { padding: 3px var(--space-3); cursor: pointer; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.combo-option:hover, .combo-option.is-active { background: color-mix(in srgb, var(--accent) 14%, var(--soft)); color: var(--accent); }
.combo-option[aria-selected="true"] { font-weight: 600; }
.combo-empty { padding: var(--space-2) var(--space-3); color: var(--muted); font-size: var(--t-xs); }
select option { background: var(--panel); color: var(--ink); font-size: var(--t-base); }
.status-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); margin-top: var(--space-3); min-height: 22px; }
.status { font-family: var(--mono); font-size: var(--t-sm); color: var(--muted); }
.status.error { color: var(--danger); }

/* ---------- figures: one card per graph ---------- */
.figure { margin-top: var(--space-7); padding: var(--space-5) var(--space-5) 18px; border: 1px solid var(--line); border-radius: 2px; background: var(--panel); }
.figure-head { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: var(--space-4) var(--space-7); align-items: end; padding-bottom: var(--space-5); margin-bottom: var(--space-5); }
.figure-head > .figure-key { grid-column: 1 / -1; margin-top: var(--space-2); }

/* The encoding, always on the figure: a named variant of dt/dd, compact so it sits under the
   title without becoming a second essay. Swatches in the dt are the colour hierarchy teaching
   itself -- the same ramps the marks use. */
.figure-key { display: flex; flex-wrap: wrap; gap: var(--space-4) var(--space-6); }
.figure-key > div { min-width: 12ch; max-width: 28ch; }
.figure-key dt { display: flex; align-items: center; font-family: var(--mono); font-size: var(--t-2xs); font-weight: 500; line-height: 1.3; letter-spacing: var(--tr-label); text-transform: none; color: var(--accent); }
.figure-key dd { margin-top: var(--space-1); font-family: var(--mono); font-size: var(--t-sm); line-height: var(--lh-body); color: var(--muted); max-width: none; }
/* The tema key documents the second colour encoding only while the tema mask is on and the
   figure is not in strip mode -- toggled from script (atlas.ts's render() and toggleMask()),
   not CSS, since is-themed can linger on a hidden viewport's leftover svg regardless of mode
   (paintSelection paints both panes). A sibling dl, not a row inside #keyDefault, so #keyDefault
   stays exactly the four rows test/leitura-ui-acceptance.test.ts pins (Tamanho/Cor/Posição/
   Clique, unchanged). */
.key-bridge { display: inline-block; width: 22px; height: 2px; margin-right: var(--space-2); vertical-align: middle; background: var(--accent); }
.key-pair { display: inline-block; width: 44px; height: 8px; border-radius: 2px; margin-right: var(--space-2); vertical-align: middle; background: linear-gradient(90deg, var(--cmp-a), var(--scale-mid), var(--cmp-b)); }
.figure-title { display: flex; flex-direction: column; gap: var(--space-2); }
/* The accent is spent here on purpose: the only word in a figure title that is a live number. */
.figure-title h2 b { color: var(--accent); font-variant-numeric: tabular-nums; font-weight: inherit; }

.figure-body { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--space-6); align-items: start; }

/* ---------- workspace: the atlas figure ---------- */
/* A reload dims what is on screen instead of blanking it, so the column keeps its height and
   nothing below the map moves until the new map lands. First paint uses a ghost of the map,
   not this dim: dimming an empty figure is how the old loading copy looked dead. */
.workspace .viewport, .workspace .columns, .workspace .inspector, .workspace .strip,
.testimony .strip, .testimony .testimony-lists, .testimony .outlets,
.compare .ruler, .compare .detail, .rising .ruler, .rising .note,
.lenses .ruler, .lenses .detail, .attention .attention-chart, .attention .note, .agenda .agenda-grid, .persistence .persistence-chart { transition: opacity .16s ease-out; }
.figure.is-loading .viewport, .figure.is-loading .columns, .figure.is-loading .inspector,
.figure.is-loading .strip, .figure.is-loading .testimony-lists, .figure.is-loading .outlets,
.figure.is-loading .ruler, .figure.is-loading .detail, .figure.is-loading .week-chart, .rising.is-loading .note,
.figure.is-loading .attention-chart, .figure.is-loading .agenda-grid, .figure.is-loading .persistence-chart,
.strip.is-loading, .testimony-lists.is-loading, #outletList.is-loading { opacity: .45; pointer-events: none; }
.canvas { min-width: 0; }
.map-tools { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); padding-bottom: var(--space-4); }
.search { flex: 1 1 220px; }
.search input { width: 100%; background: var(--bg); border: 1px solid var(--line); border-radius: 2px; min-height: 40px; padding: var(--space-2) var(--space-3); font-family: var(--mono); font-size: var(--t-sm); }
.search input::placeholder { color: var(--muted); }
.segment { display: inline-flex; max-width: 100%; overflow-x: auto; scrollbar-width: thin; border: 1px solid var(--line); border-radius: 2px; padding: 2px; background: var(--bg); }
.segment button { flex: 0 0 auto; border: 0; background: transparent; color: var(--muted); border-radius: 2px; padding: 6px var(--space-4); font-family: var(--mono); font-size: var(--t-xs); }
.segment button[aria-pressed="true"], .segment button.active { background: var(--accent); color: var(--accent-ink); font-weight: 600; }
.zoom { display: flex; align-items: center; gap: 6px; }
.zoom button { width: 34px; height: 34px; padding: 0; font-size: var(--t-md); }
.zoom #zoomReset { width: 56px; font-size: var(--t-2xs); font-variant-numeric: tabular-nums; }
.quiet-button { background: var(--soft); border: 0; padding: 7px var(--space-3); border-radius: 2px; color: var(--muted); font-family: var(--mono); font-size: var(--t-xs); white-space: nowrap; }
.quiet-button:hover { color: var(--ink); background: var(--line); }
.quiet-button.toggle[aria-pressed="true"] { color: var(--accent-ink); background: var(--accent); font-weight: 600; }
.mobile-hint { display: none; margin: var(--space-2) 0; color: var(--muted); font-size: var(--t-xs); }
.search-note { color: var(--accent); font-family: var(--mono); font-size: var(--t-xs); padding-top: var(--space-2); min-height: 24px; }

.viewport { overflow: auto; min-height: 360px; scrollbar-color: var(--line) var(--bg); }
.map-stage { width: fit-content; margin: auto; }
.map-svg { display: block; width: var(--map-width, auto); height: auto; }
/* Inside the map the ramp is data, not design: --size comes from the score, which is the whole
   point of the graph. The family and weight are still fixed here, like everywhere else. */
.map-svg .atlas-text { font-family: var(--mono); font-weight: 500; fill: var(--wc); font-size: var(--size); }
/* --wc is the word's own colour, resolved once per state on the group so the hit box can borrow
   it. --wc-soft is that colour pulled toward --muted: the box is the word's hue, desaturated and
   nearly transparent, so it says "this one" without competing with what the colour means. */
.atlas-word { cursor: pointer; --wc: var(--ink); --wc-soft: color-mix(in srgb, var(--wc) 55%, var(--muted)); }
.atlas-glow { rx: 9px; }
.atlas-hit { rx: 6px; }
.ruler-glow, .week-glow { rx: 8px; }
.ruler-hit, .week-hit { rx: 5px; }
.atlas-glow, .atlas-hit { fill: transparent; }
/* Under the cursor a ground; picked or matched, the same ground at twice the strength. Its edge
   is two shapes, not one: a core barely blurred (2px) and a wider penumbra behind it (7px). One
   uniformly blurred rectangle has no form -- it is fog, and fog has no boundary to read. Stacked,
   the alpha falls off in two steps, which is what gives the ground a body and an edge without
   ever drawing a line, and this site draws no lines. The blur lives on the shapes themselves,
   never on the state: put it on :hover and it switches off the instant the cursor leaves, so a
   hard rectangle reappears for the length of the fade.
   The mark's own colour never changes either: painting a picked word --accent threw away the one
   thing the colour is there to say. */
.atlas-glow, .ruler-glow { filter: blur(7px); transition: fill .16s ease-out; }
.atlas-hit, .ruler-hit { filter: blur(2px); transition: fill .16s ease-out; }
.center-hit, .dot-halo { filter: blur(4px); transition: fill .16s ease-out; }
.atlas-word:hover .atlas-glow, .atlas-word:focus-visible .atlas-glow { fill: color-mix(in srgb, var(--wc-soft) 9%, transparent); }
.atlas-word:hover .atlas-hit, .atlas-word:focus-visible .atlas-hit { fill: color-mix(in srgb, var(--wc-soft) 13%, transparent); }
.atlas-word.is-selected .atlas-glow, .atlas-word.is-match .atlas-glow { fill: color-mix(in srgb, var(--wc-soft) 16%, transparent); }
.atlas-word.is-selected .atlas-hit, .atlas-word.is-match .atlas-hit { fill: color-mix(in srgb, var(--wc-soft) 26%, transparent); }
.atlas-word.is-dim { opacity: .22; }
.atlas-word.is-neighbor { --wc: var(--green); }
/* The mask: word colour = its texts' testimony against the person's mean. Neighbours keep the
   mask and gain the underline, so the relation stays visible without the green competing. So do
   hover, pick and search match: every one of them is drawn by the box, never by repainting the
   word, or the mask would go blank exactly on the word the reader is looking at. */
.map-svg.is-masked .atlas-word, .map-svg.is-masked .atlas-word.is-neighbor { --wc: var(--mask, var(--muted)); }
.map-svg.is-masked .atlas-word.is-neighbor .underline { opacity: .7; stroke-dasharray: 3 3; }
.mask-scale { display: inline-block; width: 44px; height: 8px; border-radius: 2px; margin-right: var(--space-2); vertical-align: middle; background: linear-gradient(90deg, var(--hostile), color-mix(in srgb, var(--scale-mid) 50%, transparent), var(--favor)); }
/* The tema mask: same shape as the mask above, one discrete --theme token per word instead of a
   continuous --mask gradient. Mutually exclusive with is-masked -- paintSelection never sets both. */
.map-svg.is-themed .atlas-word, .map-svg.is-themed .atlas-word.is-neighbor { --wc: var(--theme, var(--muted)); }
.map-svg.is-themed .atlas-word.is-neighbor .underline { opacity: .7; stroke-dasharray: 3 3; }
.theme-scale { display: inline-block; width: 44px; height: 8px; border-radius: 2px; margin-right: var(--space-2); vertical-align: middle; background: linear-gradient(90deg, var(--theme-1) 0 16.67%, var(--theme-2) 16.67% 33.33%, var(--theme-3) 33.33% 50%, var(--theme-4) 50% 66.67%, var(--theme-5) 66.67% 83.33%, var(--theme-6) 83.33% 100%); } /* six hard stops, not a continuous ramp: communities carry no order for the gradient to imply */
/* Figure 8's own key swatch: muted to full ink, the exact ramp an agenda cell's own share reads
   through -- no new hue, matching the site's "colour means something" rule. */
.ink-scale { display: inline-block; width: 44px; height: 8px; border-radius: 2px; margin-right: var(--space-2); vertical-align: middle; background: linear-gradient(90deg, var(--muted), var(--ink)); }
.underline { stroke: var(--wc, var(--accent)); stroke-width: 1.5; opacity: 0; }
.atlas-word.is-selected .underline { opacity: 1; }
.atlas-word[data-kind="org"]:not(.is-selected) .underline { opacity: .55; stroke-dasharray: 2 2; }
.atlas-word[data-kind="org"].is-selected .underline { stroke-dasharray: 2 2; }
.map-svg.is-masked .atlas-word[data-kind="org"].is-neighbor .underline { stroke-dasharray: 2 2; }
.person-name { font-family: var(--display); font-weight: 700; fill: var(--accent); font-size: var(--size); letter-spacing: var(--tr-lg); }
/* The centre is the person's own entry to the documents, so it answers to the cursor the way a
   word does -- the same soft box, in the colour the name is already written in. */
.center-label { cursor: pointer; }
.center-hit { fill: transparent; }
.center-label:hover .center-hit, .center-label:focus-visible .center-hit { fill: color-mix(in srgb, var(--accent) 10%, transparent); }
.micro { fill: var(--muted); font-family: var(--mono); font-size: var(--t-micro); font-weight: 500; letter-spacing: var(--tr-label); }
.center-note { fill: var(--muted); font-family: var(--mono); font-size: var(--t-xs); }
.edge { fill: none; stroke: var(--accent); stroke-linecap: round; opacity: .46; pointer-events: none; }
.boundary { fill: none; stroke: var(--line); stroke-width: 1; stroke-dasharray: 2 4; }
.halo-in { stop-color: var(--accent); stop-opacity: .045; }
.halo-out { stop-color: var(--accent); stop-opacity: 0; }

.legend { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-5); padding: var(--space-4) 0; color: var(--muted); font-family: var(--mono); font-size: var(--t-xs); }
.type-scale { display: inline-flex; align-items: baseline; gap: 5px; margin-right: var(--space-2); color: var(--ink); }
.type-scale span:first-child { font-size: var(--t-2xs); }
.type-scale span:last-child { font-size: var(--t-lg); }
.legend i { display: inline-block; width: 22px; height: 1px; background: var(--accent); vertical-align: middle; margin-right: var(--space-2); }

.strip { margin: 0; padding: 6px 0 10px; }
.strip-mean-row { position: relative; height: 22px; margin-top: var(--space-3); }
.strip-mean { position: absolute; left: clamp(0px, var(--pos, 50%), 100%); transform: translateX(clamp(-100%, -50%, 0%)); font-family: var(--mono); font-size: var(--t-2xs); color: var(--accent); white-space: nowrap; }
.strip-svg { display: block; width: 100%; height: auto; overflow: visible; }
.strip-axis { stroke: var(--line); stroke-width: 2; }
.strip-tick { stroke: var(--muted); stroke-width: 1; opacity: .6; }
.strip-overall { stroke: var(--accent); stroke-width: 1; stroke-dasharray: 3 3; opacity: .8; }
/* Same rule as the atlas's words: what answers to the cursor is a soft shape in the mark's own
   colour, desaturated toward --muted and nearly transparent. A dot has no box to draw, so it
   gets a halo behind it -- an ink ring would have said "hovered" while hiding what the colour
   of the dot is there to say. */
.strip-dot { cursor: pointer; outline: none; --wc: var(--tone, var(--muted)); --wc-soft: color-mix(in srgb, var(--wc) 55%, var(--muted)); }
.strip-dot .dot-face { fill: var(--wc); stroke: var(--bg); stroke-width: 1.5; fill-opacity: .9; transition: fill-opacity .12s; }
.strip-dot .dot-halo { fill: transparent; }
.strip-dot:hover .dot-halo, .strip-dot:focus-visible .dot-halo { fill: color-mix(in srgb, var(--wc-soft) 26%, transparent); }
.strip-dot:hover .dot-face, .strip-dot:focus-visible .dot-face { fill-opacity: 1; }
.strip-dot.is-active .dot-face, .strip-dot.is-selected .dot-face, .strip-dot.is-match .dot-face { fill-opacity: 1; }
.strip-dot.is-active .dot-halo, .strip-dot.is-selected .dot-halo, .strip-dot.is-match .dot-halo { fill: color-mix(in srgb, var(--wc) 45%, transparent); }
/* Figure 1's own strip: a word that does not match the search dims, the same treatment
   .column-card.is-dim already gets. */
.strip-dot.is-dim { opacity: .35; }
.strip-axis-labels { display: flex; justify-content: space-between; padding: var(--space-2) 0 0; font-family: var(--mono); font-size: var(--t-xs); color: var(--muted); }
.strip .note { margin-top: var(--space-3); }

/* Figure 1's own strip mode: same .strip skeleton, sitting beside #viewport/#columns
   inside .canvas rather than as its own figure, so it needs its own outer spacing. */
#atlasStrip { margin: var(--space-2) 0 var(--space-3); }
#stripHiddenNote { margin: 0 0 var(--space-3); }

.overflow { padding: 0 0 var(--space-5); }
.overflow p { font-size: var(--t-sm); color: var(--muted); margin-bottom: var(--space-2); }
.overflow button { margin: var(--space-1) 6px 0 0; }
.overflow .is-dim { opacity: .35; }
.overflow .is-match, .overflow .is-selected { color: var(--accent); }

.columns { padding: var(--space-2) 0 var(--space-5); display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
/* Each card gets a ground of its own: the metadata line and the word under it are one thing,
   and with no card behind them a reader on a three-column grid ties the line to the wrong word.
   A very light wash rather than a border, so eighteen of these do not read as a table. */
.column-card { border: 0; padding: var(--space-3) var(--space-4); border-radius: 2px; background: color-mix(in srgb, var(--soft) 65%, transparent); color: inherit; text-align: left; transition: background-color .12s; --wc: var(--ink); --wc-soft: color-mix(in srgb, var(--wc) 55%, var(--muted)); }
/* Same rule as the map: the ground behind the card carries hover and pick, in the card's own
   colour, and the word on it never gets repainted. */
.column-card:hover { background: color-mix(in srgb, var(--wc-soft) 12%, var(--soft)); }
.column-card.is-selected { background: color-mix(in srgb, var(--wc-soft) 24%, var(--soft)); }
/* The word carries the card, so it sits at h3 rank in sans -- the list is the map's other face
   and the map writes its words in sans too. */
.column-card strong { display: block; font-family: var(--mono); font-size: var(--t-lg); font-weight: 500; letter-spacing: 0; line-height: var(--lh-snug); overflow-wrap: anywhere; margin-top: var(--space-1); }
.column-card span { display: block; color: var(--muted); font-family: var(--mono); font-size: var(--t-xs); }
.column-card.is-dim { opacity: .35; }
/* The list is the map without its centre, so the person gets the head of it: full width, above
   the words, saying the same two things the centre of the map says. */
.column-person { grid-column: 1 / -1; padding: var(--space-3) var(--space-4); border-radius: 2px; background: color-mix(in srgb, var(--accent) 7%, var(--soft)); cursor: pointer; }
.column-person span { display: block; font-family: var(--mono); font-size: var(--t-2xs); font-weight: 500; letter-spacing: var(--tr-label); color: var(--muted); }
.column-person strong { display: block; margin-top: var(--space-1); font-family: var(--display); font-size: var(--t-lg); font-weight: 700; color: var(--accent); letter-spacing: var(--tr-lg); overflow-wrap: anywhere; }
.column-person:hover { background: color-mix(in srgb, var(--accent) 13%, var(--soft)); }
.column-card strong { color: var(--wc); }
.columns.is-masked .column-card { --wc: var(--mask, var(--muted)); }
.columns.is-themed .column-card { --wc: var(--theme, var(--muted)); }

/* ---------- the lists under the strip ---------- */
.outlets { min-width: 0; padding-top: var(--space-1); }
.outlets > .eyebrow { display: flex; align-items: center; gap: var(--space-2); padding: 0 0 6px; }
.outlets .eyebrow b { color: var(--accent); letter-spacing: 0; font-size: var(--t-sm); font-weight: 500; overflow-wrap: anywhere; }
/* The one outlet list: as many columns as the figure is wide, so 80 outlets are a scrollable
   block of a few hundred pixels rather than a screen and a half of single-file rows. */
.outlet-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 0 var(--space-6); max-height: 210px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
#outletList { max-height: 420px; overflow-y: auto; scrollbar-width: thin; padding-bottom: var(--space-4); font-family: var(--mono); font-size: var(--t-sm); color: var(--muted); }
.outlet { transition: background-color .16s ease-out, color .16s ease-out; width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 10px; align-items: center; border: 0; background: none; text-align: left; padding: var(--space-1) 0; font-size: var(--t-xs); color: inherit; }
.outlet:hover { color: var(--accent); }
.outlet.is-static { color: var(--muted); cursor: default; }
.outlet.is-static:hover { color: var(--muted); }
/* The focused outlet sits on a wash of its own avaliação colour, the same one its chip on the
   right already carries. It used to draw a 3px bar down its left edge; the wash says the same
   thing without a line, which is the rule everywhere else on this page. */
.outlet.is-active { color: var(--ink); background: color-mix(in srgb, var(--tone, var(--muted)) 18%, transparent); }
.outlet .d { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.outlet .n { color: var(--muted); font-variant-numeric: tabular-nums; }
.outlet .t { min-width: 40px; text-align: center; border-radius: 2px; padding: 2px 5px; font-size: var(--t-2xs); font-variant-numeric: tabular-nums; color: var(--accent-ink); background: var(--tone); }
.outlet .t:empty { visibility: hidden; }
.outlets .note { margin: var(--space-3) 0 0; }
/* The focused outlet's own neighbours list rides the .stat pattern's dt/dd shape but is a list,
   not one measurement, so it spans every column of the grid and each pair drops out of .stat
   dd's big number size onto its own line instead of running together. */
.outlet-grid dl.metric.stat { grid-column: 1 / -1; margin: var(--space-2) 0 0; padding-bottom: var(--space-3); }
.outlet-grid dl.metric.stat dd { font-size: var(--t-sm); }
.outlet-neighbor { display: block; color: var(--muted); font-variant-numeric: tabular-nums; }
.outlet-neighbor .n { color: var(--ink); }
.outlet-neighbor + .outlet-neighbor { margin-top: 2px; }
.testimony-lists { min-width: 0; font-family: var(--mono); font-size: var(--t-sm); color: var(--muted); }

/* Figure 2's answer: one stat pair, the number at h2 rank because it is what the whole figure is
   for, and its name in eyebrow type underneath. The reading in words follows as a caption. */
.testimony .verdict { padding: var(--space-1) 0 var(--space-1); }
.testimony .verdict dd { font-size: var(--t-xl); line-height: 1; color: var(--tone, var(--ink)); }
.testimony .verdict-class { margin-top: var(--space-1); font-size: var(--t-xs); color: var(--muted); }
.testimony .focus { margin: 6px 0 var(--space-1); font-size: var(--t-xs); color: var(--muted); }
.testimony .focus b { overflow-wrap: anywhere; }
.testimony .focus strong { color: var(--tone, var(--ink)); font-variant-numeric: tabular-nums; font-weight: 600; }

/* The per-source means as one wrapping row of stat chips: four full-width rows cost 164px to say
   four numbers, and the strip above already carries the shape of the distribution. Inside a chip
   the pair goes back upright -- name first, number after -- because the row is read sideways. */
.source-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: 2px 0 var(--space-1); }
.source-chip { display: inline-flex; align-items: center; gap: var(--space-2); background: var(--soft); border: 1px solid var(--line); border-radius: 2px; padding: 4px 6px 4px var(--space-3); }
.source-chip dt { font-family: var(--mono); font-size: var(--t-xs); font-weight: 500; line-height: 1.4; letter-spacing: 0; text-transform: none; color: var(--ink); }
.source-chip dd { display: inline-flex; align-items: center; gap: var(--space-2); font-family: var(--mono); font-size: var(--t-xs); font-weight: 400; letter-spacing: 0; color: var(--muted); }
.source-chip .n { font-variant-numeric: tabular-nums; }
.source-chip .t { min-width: 40px; text-align: center; border-radius: 2px; padding: 2px 6px; font-size: var(--t-2xs); font-variant-numeric: tabular-nums; color: var(--accent-ink); background: var(--tone); }
.source-chip .t:empty { display: none; }

/* ---------- the atlas inspector ---------- */
.inspector { padding: var(--space-3) 0 0 var(--space-6); min-width: 0; align-self: stretch; }
/* The selected word is the subject of this column, so it is an h3 -- one rank under the figure's
   own h2, which is exactly what it is. */
.inspector h3 { margin: 10px 0 18px; overflow-wrap: anywhere; }
.metric { display: flex; flex-wrap: wrap; gap: var(--space-4) var(--space-6); padding-bottom: 18px; margin-bottom: 18px; }
.inspector p { font-size: var(--t-sm); color: var(--muted); margin-bottom: var(--space-4); }
.inspector .eyebrow { margin-top: var(--space-5); }
.metric + p, .inspector .eyebrow:first-child { margin-top: 0; }
.score-highlight { color: var(--accent); font-weight: 600; }
.empty-note { margin-top: var(--space-3); }
/* Issue #147 AC20: the inspector's own 7-bar sparkline, one word's last 7 rolling days. No hue
   of its own -- --ink / --soft only, the same pair a ghost already uses. */
.sparkline { display: flex; align-items: flex-end; gap: 4px; height: 34px; margin: var(--space-2) 0 4px; }
.spark-bar { width: 8px; height: var(--h); background: var(--ink); border-radius: 1px 1px 0 0; }
.spark-ghost { width: 8px; height: 18px; }
.related { margin: var(--space-2) 0 var(--space-5); }
.related button { width: 100%; border: 0; background: none; display: flex; align-items: center; gap: var(--space-3); text-align: left; padding: 10px 0; font-family: var(--mono); font-size: var(--t-base); }
.related button:hover span { color: var(--accent); }
.related span { flex: 1; overflow-wrap: anywhere; }
.related b { font-weight: 500; color: var(--accent); font-variant-numeric: tabular-nums; font-size: var(--t-sm); }
.docs-summary { margin: 0 0 6px; color: var(--muted); font-family: var(--mono); font-size: var(--t-xs); }
/* ---------- the documents modal ---------- */
/* Documents are fetched only when this opens (issue: the main page must never GET /docs on its
   own), and they scroll inside the dialog so a long text never grows the page. A dialog is its
   own document to a reader, so its title is an h2 and not a continuation of the page's ranks. */
/* A flat panel with the same hairline every figure carries: the card is one more instrument on
   the bench, not a sheet lifted off it. The split between the head and the texts is space. */
.docs-dialog { width: min(720px, calc(100vw - 32px)); max-height: min(85vh, 900px); margin: auto; padding: 0; border: 1px solid var(--line); border-radius: 2px; background: var(--panel); color: var(--ink); display: none; flex-direction: column; }
.docs-dialog[open] { display: flex; animation: card-in .18s ease-out; }
.docs-dialog::backdrop { background: rgba(0, 0, 0, .62); }
@keyframes card-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .docs-dialog[open] { animation: none; }
  .atlas-glow, .atlas-hit, .ruler-glow, .ruler-hit, .center-hit, .dot-halo, .outlet, .column-card,
  .attention-glow, .attention-hit { transition: none; }
  .ghost-field { animation: none; }
}
.docs-dialog-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); padding: 18px 22px var(--space-4); }
/* One control, on a ground that is already lighter than the page: a chip here read as a second
   card sitting on the first. Type carries it, like every other quiet control on this site. */
#docsClose { background: none; padding: 6px 0 6px var(--space-3); }
#docsClose:hover { background: none; color: var(--ink); }
/* Reached by keyboard it still has to say so; it says it the way every other control does. */
#docsClose:focus-visible { box-shadow: inset 0 0 0 999px color-mix(in srgb, var(--accent) 14%, transparent); color: var(--ink); border-radius: 2px; }
/* Wide screens get the card, not the sheet: it floats over the figure, leaves the map readable
   behind it, stays open while the reader picks the next word, and is dragged by its own head.
   `left`/`top` arrive from the drag; until then the card sits where this rule puts it. */
/* Three shadows rather than one: a tight contact shadow so the card sits on the page, a mid one
   for its body, and a wide soft one for the room it takes up. One 44px blur did all three jobs
   badly and read like a sticker. */
.docs-dialog.is-floating { position: fixed; right: var(--docs-right, 24px); top: var(--docs-y, 96px); left: var(--docs-x, auto); margin: 0; width: min(380px, calc(100vw - 32px)); max-height: min(62vh, 560px); box-shadow: 0 1px 2px rgba(0, 0, 0, .5), 0 10px 22px -8px rgba(0, 0, 0, .55), 0 36px 64px -20px rgba(0, 0, 0, .7); }
.docs-dialog.is-floating .docs-dialog-head { padding: var(--space-4) 18px var(--space-3) 22px; cursor: grab; touch-action: none; }
.docs-dialog.is-floating .docs-dialog-head h2 { font-size: var(--t-md); }
.docs-dialog.is-dragging { user-select: none; }
.docs-dialog.is-dragging .docs-dialog-head { cursor: grabbing; }
.docs-dialog-head h2 { font-size: var(--t-lg); margin-top: var(--space-1); overflow-wrap: anywhere; }
/* The texts fade at both scroll edges rather than being sliced by the card's rim -- a cut edge
   reads as a line, and this site draws none. */
#docs { overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; padding: 6px 22px var(--space-5); min-height: 120px; mask-image: linear-gradient(transparent, #000 14px, #000 calc(100% - 20px), transparent); }
/* The ruler asks the same word of both people, so its card answers in two columns -- one per
   person, each under its own name. Below the card's own width they stack. */
.docs-columns { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--space-5); }
/* The column's own header, not the domain line each document carries. */
.docs-side-name { margin-bottom: var(--space-2); color: var(--ink); }
.doc .eyebrow, .docs-side-name { font-family: var(--mono); }
.docs-dialog.is-floating.is-wide { width: min(660px, calc(100vw - 32px)); }
@media (max-width: 560px) { .docs-columns { grid-template-columns: 1fr; } }
.doc { padding: var(--space-3) 0; }
.doc p { margin: 6px 0; color: var(--ink); font-size: var(--t-sm); }
.doc a { font-family: var(--mono); font-size: var(--t-xs); }
.empty { padding: 80px var(--space-5); text-align: center; color: var(--muted); font-size: var(--t-base); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

/* Ghost of a figure's own geometry while the recorte is in flight. --soft wash of --ink, never
   a data hue and never invented words. The pulse is the wait; reduced motion stays still. */
@keyframes ghost-pulse {
  50% { opacity: .62; }
}
.ghost-field { animation: ghost-pulse 1.6s ease-in-out infinite; pointer-events: none; }
.ghost {
  display: block;
  background: color-mix(in srgb, var(--ink) 28%, var(--soft));
  fill: color-mix(in srgb, var(--ink) 36%, var(--soft));
  border-radius: 2px;
}
.ghost-kicker { width: 9em; height: .7em; }
.ghost-title { width: 10em; height: 1.35em; margin: 10px 0 18px; }
.ghost-stat { width: 3.2em; height: 1.15em; }
.ghost-stat.is-xl { width: 2.4em; height: 1.6em; }
.ghost-line { width: 36ch; max-width: 100%; height: .7em; margin: 0 0 var(--space-3); }
.ghost-line.is-short { width: 22ch; }
.ghost-chip { width: 8.5em; height: 1.5em; border-radius: 2px; }
.ghost-name { width: 7em; height: .85em; }
.ghost-doc-kicker { width: 6em; height: .65em; margin-bottom: 6px; }
.ghost-doc-line { width: 100%; height: .7em; margin: 6px 0; }
.ghost-doc-line.is-short { width: 62%; }
.ghost-outlet-d { width: 16em; max-width: 100%; height: .8em; }
.ghost-outlet-d.is-mid { width: 11em; }
.ghost-outlet-d.is-short { width: 8em; }
.ghost-outlet-n { width: 2.2em; height: .8em; }
.inspector .ghost-title { display: block; }
.source-chip .ghost-chip { display: inline-block; }
.outlet .ghost { display: inline-block; }
.ruler-end-row .ghost-name:last-child { margin-left: auto; }

/* ---------- the in-page guide ---------- */
/* Same card language as the documents dialog, but this one is always a modal: it is a reading
   surface, not a companion to a pick. The figure's own .figure-key already taught the encoding;
   what lives here is the depth (PMI ladder, kikori's cut, the honesty notes). */
.help-dialog { width: min(680px, calc(100vw - 32px)); max-height: min(88vh, 900px); margin: auto; padding: 0; border: 1px solid var(--line); border-radius: 2px; background: var(--panel); color: var(--ink); display: none; flex-direction: column; }
.help-dialog[open] { display: flex; animation: card-in .18s ease-out; }
.help-dialog::backdrop { background: rgba(11, 14, 13, .74); }
@media (prefers-reduced-motion: reduce) { .help-dialog[open] { animation: none; } }
.help-dialog-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); padding: 18px 22px var(--space-4); }
#helpClose { background: none; padding: 6px 0 6px var(--space-3); }
#helpClose:hover { background: none; color: var(--ink); }
#helpClose:focus-visible { box-shadow: inset 0 0 0 999px color-mix(in srgb, var(--accent) 14%, transparent); color: var(--ink); border-radius: 2px; }
.help-dialog-head h2 { font-size: var(--t-lg); margin-top: var(--space-1); }
.help-body { overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; padding: var(--space-3) 22px var(--space-8); min-height: 120px; mask-image: linear-gradient(transparent, #000 12px, #000 calc(100% - 36px), transparent); }
.help-body > * { scroll-margin-top: var(--space-4); }
/* Wrappers exist so scroll-into-view has a target. Space lives on the wrapper: an h3 is always
   first-child of its div, so a :first-child zero on h3 collapses every heading. */
.help-body > :first-child { margin-top: 0; }
.help-body > div { margin-top: var(--space-7); }
.help-body h3 { margin-top: 0; }
.help-body p, .help-body ol, .help-body dl { margin-top: var(--space-3); }
.help-body h3 + p, .help-body h3 + ol, .help-body h3 + dl, .help-body h3 + .figure-key { margin-top: var(--space-3); }
.help-body .figure-key { margin-top: var(--space-3); }
.help-body .pmi-scale { margin-top: var(--space-4); }
.help-body .pmi-scale + p { margin-top: var(--space-4); }
.help-foot { margin-top: var(--space-7); padding-bottom: var(--space-3); font-family: var(--mono); font-size: var(--t-xs); color: var(--muted); max-width: none; }

/* ---------- candidates ---------- */
.candidate .samples { padding-left: var(--space-3); }
.candidate .doc .eyebrow { margin-bottom: var(--space-1); }

/* ---------- the page that explains how to read ---------- */
/* Prose is the only place on the site where headings stack freely, so this is where the "space
   is the rank" rule has to be spelled out: an h2 opens more air than an h3, an h3 more than a
   paragraph, and nothing draws a line. :where() keeps the specificity at zero so any component
   inside a chapter can still set its own margins. */
.reading { padding-top: var(--space-2); }
.chapter { margin-top: var(--space-2); }
.chapter :where(h2) { margin-top: var(--space-7); }
.chapter :where(h3) { margin-top: var(--space-6); }
.chapter :where(h4) { margin-top: var(--space-5); }
.chapter :where(h2, h3, h4):first-child { margin-top: 0; }
.chapter :where(p, ol, ul, dl) { margin-top: var(--space-3); }
.chapter :where(h2, h3, h4) + :where(p, ol, ul, dl) { margin-top: var(--space-2); }
.chapter-nav { display: flex; flex-wrap: wrap; gap: var(--space-2) 22px; margin: var(--space-5) 0 var(--space-7); font-family: var(--mono); font-size: var(--t-sm); }
.chapter-nav a { color: var(--muted); text-decoration: none; padding-bottom: 2px; }
.chapter-nav a:hover { color: var(--accent); }
.chapter-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-7) var(--space-7); align-items: start; }
.chapter-grid > div { scroll-margin-top: var(--space-5); }
.chapter h2[id], .chapter h3[id] { scroll-margin-top: var(--space-5); }
/* Inside the grid a column is narrow, so prose drops one step to --t-sm and stays muted: the
   headings above it are what a reader scans, and the body is what they land on. */
.chapter-grid :where(p, li) { font-size: var(--t-sm); line-height: var(--lh-body); color: var(--muted); max-width: var(--measure-narrow); }
.chapter-grid :where(p) + :where(p) { margin-top: 10px; }
.chapter-grid b { color: var(--ink); font-weight: 600; }
/* The PMI ladder is the site's one true definition list: a value, then what it means. It uses
   the default dt/dd style, which is the whole reason that default exists. */
.pmi-scale { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-2); margin: var(--space-3) 0 var(--space-4); max-width: 440px; }
.pmi-scale > div { background: var(--panel); border: 1px solid var(--line); border-radius: 2px; padding: 10px var(--space-3); }
.pmi-scale dt { font-family: var(--mono); font-size: var(--t-lg); font-weight: 500; color: var(--accent); margin-bottom: var(--space-1); font-variant-numeric: tabular-nums; }
.pmi-scale dd { font-family: var(--mono); font-size: var(--t-2xs); line-height: 1.35; }
.chapter-foot { margin-top: var(--space-6); padding-top: var(--space-4); color: var(--muted); font-family: var(--mono); font-size: var(--t-xs); display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--space-2) var(--space-5); max-width: none; }

/* ---------- the about page (/sobre) ---------- */
/* Same reading rules as como-ler, one column wide: this page tells a story in order, and the
   kikori block is its centre, so it alone gets a figure card. */
.about .about-block { margin-top: var(--space-8); scroll-margin-top: var(--space-5); max-width: 980px; }
.about .chapter-nav + .about-block { margin-top: 0; }
.about-block .eyebrow + h2 { margin-top: var(--space-2); }
.about-kikori-head { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 340px); gap: var(--space-5) var(--space-7); align-items: center; }
.about-mascot { margin: 0; }
.about-mascot img { display: block; width: 100%; height: auto; image-rendering: pixelated; }
@media (max-width: 760px) { .about-kikori-head { grid-template-columns: 1fr; } .about-mascot { max-width: 260px; } }
.about-lead { font-size: var(--t-md); color: var(--ink); }
.about-block em { font-style: normal; font-weight: 600; }
.about-block b { font-weight: 600; }
.about-stats { display: flex; flex-wrap: wrap; gap: var(--space-5) var(--space-7); margin-top: var(--space-5); }
.about-sources { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--space-4) var(--space-5); margin-top: var(--space-5); }
.about-sources li { display: flex; flex-direction: column; gap: 2px; }
.about-sources b { font-family: var(--mono); font-size: var(--t-sm); font-weight: 500; color: var(--ink); }
.about-sources span { font-size: var(--t-xs); color: var(--muted); }
.about-steps { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-6) var(--space-5); margin-top: var(--space-4); }
.about-steps li { margin: 0; display: flex; flex-direction: column; gap: var(--space-3); padding: 0 var(--space-5) 0 0; }
.about-steps p { font-size: var(--t-xs); color: var(--muted); margin: 0; }
.about-pair { font-family: var(--mono); font-size: var(--t-xs); line-height: var(--lh-body); color: var(--ink); }
.about-pair i { font-style: normal; color: var(--muted); }
.about-steps .about-big { font-family: var(--mono); font-size: var(--t-xl); font-weight: 500; color: var(--ink); line-height: 1; }
.about-probs { display: grid; gap: var(--space-2); margin: 0; }
.about-probs > div { display: grid; grid-template-columns: 56px minmax(0, 1fr); align-items: center; gap: var(--space-2); }
.about-probs dt { font-family: var(--mono); font-size: var(--t-2xs); font-weight: 500; text-transform: none; letter-spacing: var(--tr-label); color: var(--muted); }
.about-probs dd { display: flex; align-items: center; gap: var(--space-2); font-family: var(--mono); font-size: var(--t-2xs); color: var(--ink); font-variant-numeric: tabular-nums; }
.about-probs .bar { flex: 1; height: 6px; background: var(--soft); border-radius: 1px; overflow: hidden; }
.about-probs .fill { display: block; height: 100%; background: var(--scale-mid); }
.about-probs .neg .fill { background: var(--hostile); }
.about-probs .pos .fill { background: var(--favor); }
.about-probs .p15 { width: 15%; } .about-probs .p18 { width: 18%; } .about-probs .p67 { width: 67%; }
.about-steps .about-formula { font-family: var(--mono); font-size: var(--t-sm); color: var(--ink); }
.about-formula b, .about .favor { color: var(--favor); font-weight: 600; }
.about-swap { margin: var(--space-6) 0 0; overflow-x: auto; }
.about-swap-head h3 { margin-top: var(--space-2); }
.about-swap-head .figure-sub { margin-top: var(--space-2); }
.about-ruler { display: block; width: 100%; min-width: 600px; height: auto; margin-top: var(--space-5); overflow: visible; }
.about-ruler .axis { stroke: var(--line); stroke-width: 2; }
.about-ruler .tick { stroke: var(--muted); stroke-width: 1; opacity: .6; }
.about-ruler .zone { font-family: var(--mono); font-size: var(--t-micro); font-weight: 600; letter-spacing: var(--tr-label); }
.about-ruler .zone.neg { fill: var(--hostile); }
.about-ruler .zone.neu { fill: var(--muted); }
.about-ruler .zone.pos { fill: var(--favor); }
.about-ruler .sent { fill: var(--ink); font-family: var(--mono); font-size: var(--t-xs); }
.about-ruler .who { fill: var(--muted); font-family: var(--mono); font-size: var(--t-micro); }
.about-ruler .who.hot { fill: var(--ink); font-weight: 600; }
.about-ruler .dot { fill-opacity: .75; stroke: var(--panel); stroke-width: 1.5; }
.about-ruler .dot.neg { fill: var(--hostile); }
.about-ruler .dot.neu { fill: var(--scale-mid); }
.about-ruler .dot.pos { fill: var(--favor); }
.about-swap-note { margin-top: var(--space-5); font-size: var(--t-sm); color: var(--muted); }
.about-swap-note b { color: var(--ink); }
.about-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5) var(--space-7); margin-top: var(--space-6); }
.about-cols ul, .about-caveats { padding-left: 1.1em; }
.about-cols li, .about-caveats li { font-size: var(--t-sm); color: var(--muted); margin-top: var(--space-2); }
.about-cols li b, .about-caveats li b { color: var(--ink); }
.about-links { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); font-family: var(--mono); font-size: var(--t-sm); margin-top: var(--space-5); }
.about-links a { color: var(--accent); text-underline-offset: 4px; }
@media (max-width: 900px) { .about-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .about-steps, .about-cols { grid-template-columns: 1fr; } }

/* ---------- the ruler (figure 3, compare two people, issue #91; figure 4, one person's own
   before/now, issue #151) — one set of rules, since both figures draw a term on a -1..1 axis
   with the same --cmp-a/--cmp-b pair, only the words at either end and axis prose differ. ---------- */
.ruler { margin: 18px 0 0; padding: 6px 0 10px; }
.ruler-end-row { display: flex; justify-content: space-between; font-family: var(--mono); font-size: var(--t-xs); padding-bottom: var(--space-1); }
.ruler-end { font-weight: 600; overflow-wrap: anywhere; }
.ruler-end.cmp-a { color: var(--cmp-a); }
.ruler-end.cmp-b { color: var(--cmp-b); }
.ruler-svg { display: block; width: 100%; height: auto; overflow: visible; }
.ruler-axis { stroke: var(--line); stroke-width: 2; }
.ruler-tick { stroke: var(--muted); stroke-width: 1; opacity: .6; }
/* The atlas's --wc/--wc-soft pair again: the word's colour is which side it leans to, and the
   ground under the cursor is that same colour, desaturated and nearly transparent. Recolouring
   the word on hover or on a pick would have hidden the one thing this figure draws. */
.ruler-word { cursor: pointer; outline: none; --wc: var(--cmp, var(--muted)); --wc-soft: color-mix(in srgb, var(--wc) 55%, var(--muted)); }
.ruler-glow, .ruler-hit { fill: transparent; }
.ruler-text { font-family: var(--mono); font-weight: 500; font-size: var(--size); fill: var(--wc); }
.ruler-word:hover .ruler-glow, .ruler-word:focus-visible .ruler-glow { fill: color-mix(in srgb, var(--wc-soft) 9%, transparent); }
.ruler-word:hover .ruler-hit, .ruler-word:focus-visible .ruler-hit { fill: color-mix(in srgb, var(--wc-soft) 13%, transparent); }
.ruler-word.is-selected .ruler-glow { fill: color-mix(in srgb, var(--wc-soft) 16%, transparent); }
.ruler-word.is-selected .ruler-hit { fill: color-mix(in srgb, var(--wc-soft) 26%, transparent); }
.ruler-bridge .ruler-bridge-mark { stroke: var(--accent); stroke-width: 2; }
.detail-bridge { margin: var(--space-1) 0 0; font-family: var(--mono); font-size: var(--t-xs); color: var(--accent); }
.ruler-overflow { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--space-4); }
.ruler-overflow p { flex: 1 0 100%; margin: 0; max-width: none; }
.ruler-overflow .quiet-button { color: var(--cmp, var(--muted)); }
.ruler-overflow .quiet-button:hover { color: var(--ink); }
.ruler-overflow .quiet-button.is-selected { color: var(--cmp, var(--ink)); background: color-mix(in srgb, var(--cmp, var(--muted)) 22%, var(--soft)); font-weight: 600; }
.ruler-axis-labels { display: flex; justify-content: space-between; padding: var(--space-2) 0 0; font-family: var(--mono); font-size: var(--t-xs); color: var(--muted); }
.ruler .note { margin-top: var(--space-3); }
/* The detail line: the word at h4 rank because it is the subject of the line, then one stat pair
   per person. Both sides keep the same shape whether the number is real or missing. */
.detail { margin: 18px 0 0; min-height: 26px; }
.detail .term { display: block; font-family: var(--mono); font-size: var(--t-md); font-weight: 500; line-height: var(--lh-mid); color: var(--ink); }
.detail-sides { display: flex; flex-wrap: wrap; gap: var(--space-1) 22px; margin-top: var(--space-1); }
.detail-sides > div { min-width: 0; }
.detail-sides dt { font-family: var(--mono); font-size: var(--t-xs); font-weight: 500; line-height: 1.4; letter-spacing: 0; text-transform: none; color: var(--ink); overflow-wrap: anywhere; }
.detail-sides dd { font-family: var(--mono); font-size: var(--t-xs); color: var(--muted); }
.detail-sides dd b { font-weight: 600; font-variant-numeric: tabular-nums; }
.detail-sides dd.empty-hint { color: var(--muted); font-style: italic; }
#compareHiddenNote { margin: 10px 0 0; }
#compareA, #compareB { font-family: var(--mono); }

/* ---------- the week (figure 5, calendar days, issue #147): seven columns, oldest at the
   left; each column is a day head (the .stat pattern above: --accent label, ink number) and an
   SVG swarm of that day's words, sized by that day's count, positioned only to avoid collision.
   Same glow/hit/text triad as the atlas and the ruler; no --hostile/--favor/--cmp-a/--cmp-b
   here, --ink only. ---------- */
.week-chart { margin: 18px 0 0; padding: 6px 0 10px; }
.week-columns { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: var(--space-4); align-items: start; }
.week-day { min-width: 0; }
/* Only the gap separates the day head from its swarm: no second hairline inside a figure. */
.week-day .stat { margin-bottom: var(--space-3); }
/* Drawn at the measured column width, so max-width never scales it in steady state; it only
   keeps the svg inside the column in the instant before a resize repaints. */
.week-svg { display: block; max-width: 100%; height: auto; overflow: visible; }
.week-word { cursor: pointer; outline: none; --wc: var(--ink); --wc-soft: color-mix(in srgb, var(--wc) 55%, var(--muted)); }
.week-glow, .week-hit { fill: transparent; }
.week-text { font-family: var(--mono); font-weight: 500; font-size: var(--size); fill: var(--wc); }
.week-word:hover .week-glow, .week-word:focus-visible .week-glow { fill: color-mix(in srgb, var(--wc-soft) 9%, transparent); }
.week-word:hover .week-hit, .week-word:focus-visible .week-hit { fill: color-mix(in srgb, var(--wc-soft) 13%, transparent); }
.week-word.is-selected .week-glow { fill: color-mix(in srgb, var(--wc-soft) 16%, transparent); }
.week-word.is-selected .week-hit { fill: color-mix(in srgb, var(--wc-soft) 26%, transparent); }
.week-overflow { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--space-2); min-width: 0; }
/* The label takes its own row; narrower than about 120px it wraps, it never clips. */
.week-overflow .eyebrow { flex-basis: 100%; margin: 0; }
/* The ruler's overflow keeps .quiet-button's nowrap; a week column is 145px at 1280px and a
   phrase button must wrap inside it, never draw across the next day (#148 review, 1). A word
   longer than the column breaks with a hyphen where the page's pt-BR lets the browser find
   one, and anywhere as the last resort: this list is where such words go, so it cannot refuse. */
.week-overflow .quiet-button { white-space: normal; text-align: left; max-width: 100%; hyphens: auto; overflow-wrap: anywhere; }
.week-overflow .quiet-button b { margin-left: 6px; font-weight: 500; color: var(--accent); font-variant-numeric: tabular-nums; }
.week-overflow .quiet-button.is-selected { color: var(--ink); background: color-mix(in srgb, var(--muted) 22%, var(--soft)); font-weight: 600; }
#weekNote { margin-top: var(--space-3); }

/* ---------- the attention figure (figure 7, wikipedia pageviews against press mentions,
   issue #216): two bar-chart rows on one shared day axis, each scaled off its own maximum --
   pageviews and documents live in different orders of magnitude and are never read as one
   number against the other. [data-row] tells the rows apart, in the row head text; both draw
   in --ink, since --accent is reserved for the live control elsewhere on the page. The svg
   draws at its own measured width (figures/attention.ts), never scaled by CSS, so a bar's
   physical size is never distorted. ---------- */
.attention-chart { margin: 18px 0 0; padding: 6px 0 10px; }
.attention-row { margin-bottom: var(--space-4); }
.attention-row:last-child { margin-bottom: 0; }
.attention-row-head { display: flex; justify-content: space-between; font-family: var(--mono); font-size: var(--t-xs); color: var(--muted); padding-bottom: var(--space-1); }
.attention-svg { display: block; overflow: visible; }
.attention-axis { stroke: var(--line); stroke-width: 2; }
.attention-tick { stroke: var(--muted); stroke-width: 1; opacity: .6; }
.attention-mark { cursor: pointer; outline: none; --wc: var(--ink); --wc-soft: color-mix(in srgb, var(--wc) 55%, var(--muted)); }
.attention-glow, .attention-hit { fill: transparent; rx: 4px; }
.attention-glow { filter: blur(7px); transition: fill .16s ease-out; }
.attention-hit { transition: fill .16s ease-out; }
.attention-bar { fill: var(--wc); transition: height .16s ease-out, y .16s ease-out; }
.attention-mark:hover .attention-glow, .attention-mark:focus-visible .attention-glow { fill: color-mix(in srgb, var(--wc-soft) 9%, transparent); }
.attention-mark:hover .attention-hit, .attention-mark:focus-visible .attention-hit { fill: color-mix(in srgb, var(--wc-soft) 13%, transparent); }
.attention-mark.is-selected .attention-hit { fill: color-mix(in srgb, var(--wc-soft) 26%, transparent); }
#attentionNote { margin-bottom: var(--space-3); }
/* ---------- agenda (figure 8, domain × person coverage share, issue #208): a plain table --
   the mark is a percentage, not a position to lay out, so it earns no swarm/ruler of its own.
   Ink only: no new hue, share alone drives how dark a cell's own number reads. */
.agenda-grid { display: block; margin-top: 18px; }
.agenda-scroll { overflow-x: auto; padding-bottom: 4px; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
.agenda-table { border-collapse: collapse; font-family: var(--mono); font-size: var(--t-xs); white-space: nowrap; }
.agenda-table th, .agenda-table td { padding: 6px var(--space-3); border-bottom: 1px solid var(--line); text-align: left; }
.agenda-table thead th { color: var(--muted); font-weight: 500; vertical-align: bottom; }
.agenda-table tbody th { color: var(--ink); font-weight: 500; }
.agenda-table tbody th .d { margin-right: 6px; }
.agenda-cell { text-align: right; font-variant-numeric: tabular-nums; }
.agenda-cell.is-empty { color: var(--muted); text-align: center; }
.agenda-pick { border: 0; background: none; padding: 2px 4px; font: inherit; cursor: pointer; color: color-mix(in srgb, var(--ink) var(--share, 0%), var(--muted)); }
.agenda-pick:hover, .agenda-pick:focus-visible { text-decoration: underline; }
.agenda-pick.is-active { font-weight: 600; text-decoration: none; background: color-mix(in srgb, var(--muted) 22%, var(--soft)); }
.agenda-grid > .note { margin-top: var(--space-3); }
/* Ink weight, not a lean colour: a small neutral chip beside the domain name it labels. */
.lean-chip { display: inline-block; margin-left: 6px; padding: 1px 5px; border: 1px solid var(--line); border-radius: 2px; font-family: var(--mono); font-size: var(--t-2xs); font-weight: 500; letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--muted); vertical-align: middle; }
.agenda-ghost { display: flex; flex-direction: column; gap: var(--space-3); padding-top: 6px; }
.agenda-ghost-row { display: flex; align-items: center; gap: var(--space-4); }
/* ---------- the comention matrix (figure 9, issue #207): a 27x27 half-matrix, upper triangle
   only (a < b). One ink ramp, --ink only, no --hostile/--favor/--cmp-a/--cmp-b: exposure is not
   evaluation. Both .comention-grid and .comention-list are always in the DOM; only the media
   query below decides which one shows, the same move the week figure's own breakpoint uses. ---- */
.comention-body { margin: 18px 0 0; overflow-x: auto; }
.comention-grid { display: table; border-collapse: collapse; }
.comention-row { display: flex; align-items: stretch; }
.comention-rowhead {
  flex: 0 0 140px;
  width: 140px;
  display: flex;
  align-items: center;
  padding-right: var(--space-2);
  font-family: var(--display);
  font-weight: 600;
  font-size: var(--t-xs);
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.comention-headrow .comention-rowhead { flex-basis: 140px; }
.comention-colhead {
  flex: 1 1 var(--cell, 26px);
  width: var(--cell, 26px);
  max-width: var(--cell, 26px);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: 4px;
  font-family: var(--mono);
  font-weight: 500;
  font-size: var(--t-2xs);
  color: var(--muted);
}
.comention-cell {
  flex: 1 1 var(--cell, 26px);
  width: var(--cell, 26px);
  max-width: var(--cell, 26px);
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 1px;
  border: 1px solid var(--line);
  border-radius: 2px;
  font-family: var(--mono);
  font-weight: 500;
  font-size: var(--t-2xs);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: color-mix(in srgb, var(--ink) calc(var(--w, 0) * 30%), var(--panel));
  cursor: pointer;
  overflow: hidden;
}
.comention-cell.is-empty, .comention-cell.is-blank { cursor: default; background: transparent; border-color: transparent; }
.comention-cell.is-blank { border: none; }
.comention-cell:hover:not(.is-empty):not(.is-blank), .comention-cell:focus-visible { border-color: var(--accent); outline: none; }
.comention-cell.is-selected { border-color: var(--accent); }
.comention-cell.ghost { background: var(--soft); border-color: var(--line); }
.comention-grid.is-ghost { opacity: 0.6; }
.comention-list.is-ghost { opacity: 0.6; }
#comentionAbout { margin-top: var(--space-3); }
/* The narrow-viewport fallback: count first, then the pair, ranked high to low. Hidden above
   700px, where the matrix itself is legible (same breakpoint the week figure uses). */
.comention-list { display: none; margin: 18px 0 0; padding: 0; list-style: none; }
.comention-list li + li { margin-top: var(--space-2); }
.comention-listitem {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: var(--space-2) var(--space-3);
  font-family: var(--sans);
  font-size: var(--t-sm);
  color: var(--ink);
  cursor: pointer;
}
.comention-listitem b { font-family: var(--mono); font-weight: 600; color: var(--ink); margin-right: var(--space-2); font-variant-numeric: tabular-nums; }
.comention-listitem.is-selected { border-color: var(--accent); background: color-mix(in srgb, var(--muted) 22%, var(--soft)); }
.comention-listitem.ghost { background: var(--soft); min-height: 2.3em; }

/* ---------- persistence (figure 10, issue #215): one row per word, one cell per week, --ink only.
   A filled cell's ink is its data-lv (1..5) on one ramp for the whole figure, so any positive count is
   visibly filled; an outline cell is a week the word was outside that week's top 50 (or before
   the series began), never a zero. No --hostile/--favor/--cmp-a/--cmp-b. ---------- */
.persistence-chart { margin: 18px 0 0; }
.persistence-scroll { overflow-x: auto; padding-bottom: 4px; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
.persistence-table { border-collapse: separate; border-spacing: 0; width: 100%; font-family: var(--mono); font-size: var(--t-xs); }
.persistence-table th, .persistence-table td { padding: 0; font-weight: 400; text-align: left; }
.persistence-table thead th { height: 1.6em; vertical-align: bottom; }
.persistence-week { position: relative; min-width: 24px; }
.persistence-week span { position: absolute; bottom: 4px; left: 0; white-space: nowrap; font-size: var(--t-2xs); font-weight: 500; letter-spacing: var(--tr-label); color: var(--muted); }
.persistence-table .persistence-term { padding: 0 var(--space-4) 0 0; max-width: 24ch; min-width: 12ch; color: var(--ink); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.persistence-table .persistence-c { padding: 1px; }
.persistence-cell {
  display: flex; align-items: center; justify-content: center;
  width: 100%; min-width: 24px; height: 26px; padding: 0;
  border: 1px solid var(--line); border-radius: 2px;
  font-family: var(--mono); font-size: var(--t-2xs); font-weight: 500; font-variant-numeric: tabular-nums;
  color: var(--ink); overflow: hidden;
}
.persistence-cell[data-lv="1"] { --lv: 1; }
.persistence-cell[data-lv="2"] { --lv: 2; }
.persistence-cell[data-lv="3"] { --lv: 3; }
.persistence-cell[data-lv="4"] { --lv: 4; }
.persistence-cell[data-lv="5"] { --lv: 5; }
button.persistence-cell, .persistence-cell.is-expired {
  background: color-mix(in srgb, var(--ink) calc(var(--lv, 1) * 17%), var(--panel));
  border-color: transparent;
}
/* From 51% ink up the number would be light on light. */
.persistence-cell[data-lv="3"], .persistence-cell[data-lv="4"], .persistence-cell[data-lv="5"] { color: var(--accent-ink); }
button.persistence-cell { cursor: pointer; }
button.persistence-cell:hover, button.persistence-cell:focus-visible { border-color: var(--accent); outline: none; }
button.persistence-cell.is-selected { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.persistence-cell.is-expired { cursor: default; }
.persistence-cell.is-gap { background: transparent; }
.persistence-cell.is-nodata { background: transparent; border-style: dashed; border-color: color-mix(in srgb, var(--line) 60%, transparent); }
.persistence-cell.ghost { background: var(--soft); border-color: var(--line); }
.persistence-gap-swatch { display: inline-block; width: 14px; height: 10px; margin-right: var(--space-2); border: 1px solid var(--line); border-radius: 2px; }
.persistence-table .persistence-stats { padding-left: var(--space-4); white-space: nowrap; }
.persistence-stats .stat { display: flex; gap: var(--space-5); margin: 0; }
.persistence-stats .stat > div { flex-direction: row-reverse; align-items: baseline; justify-content: flex-end; gap: var(--space-2); }
.persistence-stats .stat dd { font-size: var(--t-sm); }
.persistence-stats .stat dt { font-size: var(--t-2xs); color: var(--muted); }
.persistence-ghost { display: flex; flex-direction: column; gap: 2px; }
.persistence-ghost-row { display: flex; align-items: center; gap: 2px; }
.persistence-ghost-row .ghost-outlet-d { flex: 0 0 12ch; margin-right: var(--space-3); }
.persistence-ghost-row .persistence-cell { flex: 1 1 0; }
#persistenceNote { margin-top: var(--space-3); }

/* ---------- the pet ---------- */
/* The one raster on a site that otherwise draws every limit with type. It is allowed exactly
   where a graph is absent -- an empty recorte, an /api/people outage -- and never beside a
   number a reader is reading. Integer scales only: a pixel sprite at 1.4x is a blurred sprite,
   so these widths are 1x and 2x of the two files and nothing in between. */
.pet { image-rendering: pixelated; flex: 0 0 auto; }
.pet-empty { display: flex; align-items: center; gap: var(--space-5); padding: var(--space-3) 0; }
.pet-empty .pet { width: 106px; height: 78px; }
.pet-empty p { max-width: 38ch; }
/* .empty centres its text, so the perched bird centres with it rather than sitting in a row. */
.empty .pet { display: block; width: 52px; height: 74px; margin: 0 auto var(--space-4); }

/* ---------- smaller screens ---------- */
@media (max-width: 1000px) {
  .figure { padding: 18px var(--space-4) var(--space-4); }
  .figure-head { grid-template-columns: 1fr; }
  .figure-body { grid-template-columns: 1fr; gap: var(--space-5); }
  .inspector { padding: var(--space-4) 0 0; }
  .columns { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .related { display: grid; grid-template-columns: 1fr 1fr; gap: 0 25px; }
  .chapter-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 700px) {
  .mobile-hint { display: block; }
  .top { flex-wrap: wrap; gap: var(--space-3) var(--space-5); }
  .top nav { margin-left: 0; width: 100%; }
  .masthead { padding: var(--space-5) 0 var(--space-6); }
  .masthead h1 { max-width: none; }
  .columns { grid-template-columns: 1fr; }
  .related { grid-template-columns: 1fr; }
  .chapter-grid { grid-template-columns: 1fr; }
  .pmi-scale { grid-template-columns: repeat(2, 1fr); }
  .chapter-foot { flex-direction: column; }
  .week-columns { grid-template-columns: 1fr; }
  .comention-grid { display: none; }
  .comention-list { display: block; }
}

.app-root { display: contents; }
