/* Her Silent Data — tokens and base styles.
   Palette and rules follow SPEC.md §7 and §8.2. */

:root {
  /* §7.1 palette */
  --navy-ink:    #0B2545;  /* body text, headings — 14:1 on white */
  --navy-deep:   #13355C;  /* header bar */
  --teal-accent: #17726B;  /* links, focus ring, primary action — 5.6:1 */
  --teal-soft:   #E6F2F1;  /* panel and row backgrounds */
  --surface:     #FFFFFF;  /* page background */
  --border:      #D3DCE4;  /* card edges, rules */
  --muted:       #53657A;  /* captions, secondary labels — 5.9:1 */

  /* status colours — never the only signal (§8.2) */
  --status-collected: #17726B;
  --status-partial:   #8A5A00;
  --status-missing:   #A33A3F;

  /* §7.2 space */
  --space-section: 24px;
  --space-card:    16px;

  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* 1rem, not 16px. The px value pinned body text to 16 while every heading
   was in rem, so the wide-screen step on :root scaled the headings and
   left the prose behind — 684px of column holding 89 characters of 16px
   text, which is the long line this step exists to avoid. */
body {
  margin: 0;
  background: var(--surface);
  color: var(--navy-ink);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.5;
}

h1, h2, h3 { line-height: 1.25; margin: 0 0 8px; }
h1 { font-size: 1.75rem; }
h2 { font-size: 1.25rem; }

p { margin: 0 0 12px; }

/* ONE width: every screen runs the full wrap, 848px inside an 880px
   container. The record and area screens were capped at 38rem for a while
   and the rest of the site was not, which put a visible step between a
   page and the page it linked to.

   The cost is line length. 848px holds about 110 characters at 16px,
   against the 45–85 that reads comfortably, so the type scales up with
   the viewport to pull that back: 18px from 820px wide, 20px from 1180px,
   which brings 848px down to about 88 characters. The step is on :root,
   not on body, so the measure, the headings and the prose keep their
   proportions.

   What the cap did fix stays fixed. Inside a record every block shares one
   right edge — before this work there were five, from 528px to 848px — and
   the sections have real headings. That was the readability problem; the
   width was the part that made the site inconsistent. */
@media (min-width: 820px) {
  :root { font-size: 112.5%; }   /* 18px */
}

@media (min-width: 1180px) {
  :root { font-size: 125%; }     /* 20px */
}

.wrap {
  max-width: 880px;
  margin: 0 auto;
  padding: 0 var(--space-card);
}

/* §8.2 focus ring — visible, 2px, never removed */
:focus-visible {
  outline: 2px solid var(--teal-accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* The one exception: the screen container. The router focuses it after a
   navigation so the next Tab starts inside the new screen — it is not a
   control the user aimed at, and a ring around the whole page would read
   as noise. Every control inside it keeps the ring above. */
.screen:focus, .screen:focus-visible { outline: none; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--surface);
  color: var(--teal-accent);
  padding: 8px 12px;
  z-index: 10;
}
.skip-link:focus { left: 8px; top: 8px; }

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

/* §8.1 — a field the seed does not establish. Italic as well as muted,
   so the distinction does not rest on colour alone. */
.unknown {
  color: var(--muted);
  font-style: italic;
}

/* §8.1 provenance — sits on the record, not in a footer. */
.provenance {
  margin: 0;
  color: var(--muted);
  font-size: 0.875rem;
}
.provenance-slot {
  margin-top: var(--space-card);
  margin-bottom: var(--space-section);
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.provenance .is-demo { color: var(--muted); }


/* ---------- header, banner, footer ---------- */

.site-header {
  background: var(--navy-deep);
  color: var(--surface);
  padding: var(--space-card) 0;
}
.site-name {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: 0.01em;
}
.site-tagline {
  margin: 2px 0 0;
  font-size: 0.9375rem;
  color: #C9D8E6;           /* 8.3:1 on --navy-deep */
}

.demo-banner {
  margin: 0;
  padding: 10px var(--space-card);
  background: var(--teal-soft);
  border-bottom: 1px solid var(--border);
  color: var(--navy-ink);
  text-align: center;
  font-size: 0.9375rem;
}

/* Same band as the masthead. It used to be a hairline rule and grey text
   on white, which left the page trailing off rather than ending; the navy
   closes it. #C9D8E6 is the tagline's colour — 8.3:1 on --navy-deep. */
.site-footer {
  margin-top: 48px;
  padding-top: var(--space-section);
  padding-bottom: var(--space-section);
  background: var(--navy-deep);
  color: #C9D8E6;
  font-size: 0.9375rem;
}
.site-footer p { margin: 0; }
.footer-line + .footer-line { margin-top: 6px; }

/* Teal on navy is under the contrast floor, so the footer's links take the
   footer's own colour — 8.3:1 — and the underline carries the affordance
   that colour would otherwise have to (SPEC 8.2). */
.site-footer a { color: #C9D8E6; }

/* A 16px glyph is not a touch target, so the anchor carries the padding
   and a negative margin keeps the icon optically aligned with the text
   above it (SPEC 7.5 asks 44px). */
.footer-repo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: -10px 0 -10px -11px;
  text-decoration: none;
}
.footer-icon {
  width: 22px;
  height: 22px;
  fill: currentColor;
}
.footer-repo:hover .footer-icon { fill: var(--surface); }

/* ---------- screens ---------- */

.screen { padding: var(--space-section) 0; }

.eyebrow {
  margin: 0 0 4px;
  color: var(--muted);
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.lede { color: var(--navy-ink); }

.label { color: var(--muted); }

.count { color: var(--muted); margin-bottom: var(--space-card); }

.affected { margin-bottom: var(--space-section); }

.back {
  display: inline-block;
  margin-bottom: var(--space-card);
  padding: 6px 0;
  background: none;
  border: 0;
  color: var(--teal-accent);
  font: inherit;
  cursor: pointer;
}
.back:hover { text-decoration: underline; }

/* ---------- screen 1: problem cards ---------- */

.card-list, .need-list-items {
  list-style: none;
  margin: 0;
  padding: 0;
}

.card-list > li { margin-bottom: var(--space-card); }

.problem-card {
  display: block;
  width: 100%;
  padding: var(--space-card);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 150ms ease, background-color 150ms ease;
}
.problem-card:hover {
  border-color: var(--teal-accent);
  background: var(--teal-soft);
}

/* Buttons may only contain phrasing content, so the lines inside a card
   are spans. They are laid out as blocks here. */
.problem-card > span {
  display: block;
}

.problem-card .card-title {
  margin: 4px 0 8px;
  font-size: 1.125rem;
  font-weight: 700;
}

.problem-card .count { margin-bottom: 0; }

/* ---------- screen 2: the data need, in full ---------- */

/* Each need is a block, not a summary that opens a screen of its own. The
   status keeps its coloured left edge, which is what made a need scannable
   when these were buttons and still does when several stack. */
/* A card only where there are several. With one data need the record has
   no list to frame, and the frame was a second box for the eye to enter:
   see .need-flat below. */
.need-block {
  padding: var(--space-card) var(--space-section);
  border: 1px solid var(--border);
  border-left: 4px solid var(--status-missing);
  border-radius: 4px;
  margin-bottom: var(--space-section);
  background: var(--surface);
}

.need-block:last-child { margin-bottom: 0; }
.need-block[data-status="partial"] { border-left-color: var(--status-partial); }
.need-block[data-status="collected"] {
  border-left-color: var(--status-collected);
}

/* The second half of the record, at page level: no card, no section
   heading, no count line. The rule and the space above it are what mark the
   turn from the problem to the data it needs — the job the frame was doing,
   done by one line instead of a box inside a list inside a heading. */
.need-flat {
  margin-top: var(--space-section);
  padding-top: var(--space-section);
  border-top: 1px solid var(--border);
}

.need-several { margin-top: var(--space-section); }

/* The need's own heading. Where the record carries one need this is an h2
   and the title of the screen's second half; inside a card it is an h3 and
   sits under the card's own badge. */
.need-description {
  margin: 8px 0 var(--space-card);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.35;
}

.need-flat > .need-description {
  font-size: 1.375rem;
  font-weight: 700;
  margin: 10px 0 var(--space-card);
}

/* Why the data is needed. Prose, in ink, because it is an argument and not
   a caption — it used to be the only field of a <dl>, under an uppercase
   letterspaced <dt>. */
.need-why {
  margin-bottom: 0;
}

.need-note { color: var(--muted); margin-bottom: 0; }
.need-note { margin-top: 6px; }

/* status badge — colour + shape + word (§8.2) */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--navy-ink);
}
.badge::before {
  content: "";
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
}
.badge[data-status="collected"]::before {
  background: var(--status-collected);
  border: 2px solid var(--status-collected);
}
.badge[data-status="partial"]::before {
  background: linear-gradient(to right,
              var(--status-partial) 0 50%, transparent 50% 100%);
  border: 2px solid var(--status-partial);
}
.badge[data-status="missing"]::before {
  background: transparent;
  border: 2px solid var(--status-missing);
}

/* ---------- list fields on the request card ---------- */

.field-list {
  margin: 0;
  padding-left: 1.25rem;
}

.field-list li {
  margin-bottom: 4px;
}

/* Why a label exists, not what it contains. Muted and smaller, so it
   reads as guidance rather than as another data point. */
.field-hint {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 0.875rem;
  font-style: italic;
}

/* Where existing data lives. Same shape as gap evidence, because they
   are the two halves of one idea; teal rule rather than grey, because
   this one is a thing you can go and use. The box, the ink body and the
   muted label all come from the shared rule further down this file, and
   the teal rule is set there too — same specificity, so it has to be
   stated after the rule it overrides, not before it. */

.dataset .gap-cite {
  display: block;
  margin-top: 4px;
  font-size: 0.875rem;
}

.dataset .unknown {
  font-style: italic;
}

/* ---------- origin badge (§5a) ---------- */

/* Says who identified the gap. Like the status badge, it never rests on
   colour alone: each state has its own shape as well as its own word,
   so the distinction survives greyscale (§8.2, §12.11). */

.origin-slot {
  margin: 0 0 var(--space-card);
}

.origin {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--navy-ink);
}
.origin::before {
  content: "";
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
  border-radius: 50%;
}

/* Filled circle — somebody else published the request. */
.origin[data-origin="sourced"]::before {
  background: var(--teal-accent);
  border: 2px solid var(--teal-accent);
}

/* Hollow circle — the platform's own hypothesis. */
.origin[data-origin="proposed"]::before {
  background: transparent;
  border: 2px dashed var(--status-partial);
}

/* Dashed square — a placeholder, not a claim at all. */
.origin[data-origin="demo"]::before,
.origin[data-origin="unknown"]::before {
  background: transparent;
  border: 2px dashed var(--muted);
  border-radius: 0;
}
.origin[data-origin="demo"],
.origin[data-origin="unknown"] {
  color: var(--muted);
  font-style: italic;
}

/* Only rendered on a card that is a placeholder or a gap this platform
   proposed — the exception, not every card. */
.problem-card .origin {
  margin-top: 10px;
}

/* ---------- gap evidence (§5a) ---------- */

/* A missing need cites the authority that named the hole, because it
   cannot cite data that does not exist. */

/* This is substantive prose, not a caption, so it keeps the §7.2 body
   floor of 16px — and it is the claim itself, so it is set in ink.
   It used to be --muted under a --navy-ink label, which made the loudest
   thing in the block the word "label" and the quietest the quotation a
   sceptic came to read. The label is now the caption and the evidence is
   the text, which is also the one convention the whole app uses: every
   label on a record is muted, every value is ink. */
/* Three kinds of thing sit under a data need, and all of them shared one
   grey left rule — so four in a row read as a single undifferentiated
   column with bold words scattered through it. Each now gets the container
   its content deserves: a quotation, a check, and a note. */
.gap-evidence,
.verification,
.guidance,
.dataset {
  display: block;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--navy-ink);
}

/* Borrowed words, in the app's own quoted-panel idiom (.intake-principle),
   because that is exactly what this is: something a published source said,
   set apart from everything the platform says for itself. */
.gap-evidence {
  margin-top: var(--space-card);
  padding: 14px var(--space-card);
  background: var(--teal-soft);
  border-left: 3px solid var(--teal-accent);
  border-radius: 0 4px 4px 0;
}

/* What the platform did, and what that check cannot show. One box, because
   a reader deciding whether to run a study has to weigh the result and its
   limit together — they used to be two containers stacked on a third. */
.check-block {
  margin-top: var(--space-card);
  padding: 14px var(--space-card);
  border: 1px solid var(--border);
  border-radius: 4px;
}

/* Notes hanging off the record. These keep the left rule the others gave
   up, which is what makes the two containers above read as containers. */
.guidance,
.dataset {
  margin-top: 10px;
  padding-left: var(--space-card);
  border-left: 3px solid var(--border);
}

.gap-evidence .label,
.verification .label,
.guidance .label,
.dataset .label {
  font-weight: 600;
  color: var(--muted);
}

/* Teal rather than grey, because existing data is a thing you can go and
   use. After the rule above, which sets the border it replaces. */
.dataset { border-left-color: var(--teal-accent); }


/* When the gap was named. The check below says when the platform last
   looked; without this line "collected since" has no since. */
.gap-claimed {
  display: block;
  margin-top: 4px;
  font-size: 0.875rem;
  color: var(--muted);
}

.gap-evidence .gap-cite,
.guidance .gap-cite {
  display: block;
  margin-top: 4px;
  font-size: 0.875rem;
}

.gap-evidence .region,
.verification .region {
  display: block;
  margin-top: 4px;
  font-size: 0.875rem;
  font-style: italic;
}

.gap-evidence .unknown,
.verification .unknown,
.guidance .unknown {
  font-style: italic;
}

/* ---------- instrument link ---------- */

.instrument-label {
  display: block;
  margin-top: 6px;
  color: var(--muted);
  font-size: 0.875rem;
}

/* Both forms: a linked instrument and a named one. The model answers this
   field with a name far more often than with a URL, and the two must not
   render at different sizes. */
.instrument {
  font-size: 0.875rem;
}


.request-field { margin-bottom: var(--space-section); }
.request-field:last-child { margin-bottom: 0; }

/* The label was 14px, weight 400, grey, against content at 17px navy — so
   the thing marking the structure was smaller, lighter AND fainter than
   the thing it marked, and the eye slid past it. Navy and bold now: still
   a label, no longer the quietest text in its own block. */
.request-field dt {
  margin-bottom: 4px;
  color: var(--navy-ink);
  font-size: 0.8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
/* 1rem, matching the lede, the why and the disclaimer. It was 1.0625rem,
   which gave the card two body sizes 1px apart and no rule saying which
   went where. */
.request-field dd {
  margin: 0;
  font-size: 1rem;
}

/* ---------- body map, home screen ---------- */

.home-hero { margin-bottom: var(--space-section); }

/* 20ch broke the hero into three short lines 345px wide, under a lede
   604px wide, inside an 848px column — a heading narrower than its own
   paragraph reads as text that got clipped rather than as a measure
   somebody chose. 34ch puts the two within a few pixels of each other, so
   the block has one right edge and the rag looks deliberate. Still capped
   rather than full-width: §7.2 keeps prose around 70 characters, and a
   30px line running the whole column would be worse than either. */
/* Full column. 34ch put the hero and the lede on one right edge, which was
   the right instinct about those two lines and the wrong one about the
   screen: everything below them — the counts strip, the bar, the figure —
   is 848px wide, and two blocks ending at 604 made the top of the page look
   unfinished. The edge they share now is the content edge. */
.hero-line {
  /* 32px, not 30. On one line the sentence measured 733px against an 848px
     column; at 32 it measures 782 and ends within 50px of the lede beneath
     it, so the two read as one block against the same edge. Not larger:
     34px measures 831 and would wrap to a line and a half on any machine
     whose font stack sets it a touch wider. */
  font-size: 2rem;
  margin-bottom: 12px;
}

.hero-lede {
  color: var(--muted);
  max-width: none;
}

/* The counts strip. Numbers are always framed in words (§8.3), so the bar
   is decoration and the key beneath it is the statement. */
.gap-summary {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 18px;
  margin-top: 20px;
}

.summary-count { margin: 0; }
.summary-count strong { font-size: 1.25rem; }

/* Clay and amber are both dark warm colours, and butted straight against
   each other they read as one bar with a smudge in it — the boundary,
   which is the only thing this bar exists to show, was invisible. A 2px
   gap of page background separates them, which is what the map's marker
   bars have always done (statusBar() in app.js uses the same 2). The
   segments carry percentage widths and may shrink by that gap; over a
   300px bar that is well under one percent, and a visible boundary is
   worth more than the third decimal place of a proportion. */
/* The bar fills whatever the count and the key leave. It used to stop at
   300px, so the three items ended 185px short of the content edge inside
   a row that presents itself as full width — a row that quits a fifth of
   the way from the right reads as unfinished rather than composed. */
.summary-bar {
  display: flex;
  gap: 2px;
  height: 9px;
  min-width: 220px;
  flex: 1;
  border-radius: 5px;
}

/* A zero-count status renders no segment at all (renderGapSummary skips
   it), so a gap never appears with nothing on the other side of it. */
.summary-seg { border-radius: 5px; }

.summary-seg[data-status="missing"]   { background: var(--status-missing); }
.summary-seg[data-status="partial"]   { background: var(--status-partial); }
.summary-seg[data-status="collected"] { background: var(--status-collected); }

.summary-key {
  display: flex;
  gap: 14px;
  margin: 0;
  font-size: 0.9375rem;
  color: var(--muted);
}

.summary-key-item[data-status="missing"] strong   { color: var(--status-missing); }
.summary-key-item[data-status="partial"] strong   { color: var(--status-partial); }
.summary-key-item[data-status="collected"] strong { color: var(--status-collected); }

.body-map { margin: 0 0 var(--space-section); }

.map-svg { display: block; width: 100%; height: auto; }

/* The whole point of this screen is to be understood in one look, and at
   848×626 the figure's lower third fell below the fold on a 1440×900
   laptop — where the browser leaves about 780px. Capping the height
   against the viewport keeps the figure, the systemic pin and the hint on
   screen together; the SVG letterboxes horizontally rather than
   distorting, because preserveAspectRatio defaults to meet.

   Desktop only. On a phone the map IS the page and scrolling it is
   expected, so the cap would only make the figure small for no gain. */
/* No height cap. There used to be one, to keep the figure, the systemic pin
   and the hint above the fold on a 1440x900 laptop. It worked, and it cost
   more than it bought: preserveAspectRatio letterboxes rather than
   distorting, so capping the height shrank the whole drawing — the figure,
   its labels and its status bars all — and left gutters either side of an
   848px column. A figure that has to be scrolled to is better than one that
   is too small to read. */

/* Systemic problems are not located in one place, so their pins sit on this
   ring rather than on the body. The caption says so — the two pin types
   explain themselves without a legend. */
.map-ring {
  fill: none;
  stroke: var(--navy-ink);
  stroke-opacity: 0.2;
  stroke-width: 1.2;
  stroke-dasharray: 4 7;
  transition: stroke-opacity 0.15s ease;
}

/* OpenClipart #71126, public domain. stroke-width is in the path's own
   units, so it is divided by the 0.3469 scale on the group. */
.map-figure path {
  fill: var(--teal-soft);
  stroke: var(--navy-ink);
  stroke-opacity: 0.32;
  stroke-width: 4;
  transition: stroke-opacity 0.15s ease;
}

/* Only where it is a control: under 640px the marks are not buttons, and
   every interactive rule below is scoped the same way. */
.map-mark[role="button"] { cursor: pointer; }

.mark-leader {
  fill: none;
  stroke: var(--navy-ink);
  stroke-opacity: 0.35;
  stroke-width: 1;
}

/* Teal, not clay, and the reason is not only that dark red dots on a
   woman's torso read as bullet wounds — though they did, which is reason
   enough for a product about women's health.

   A pin does not mean "missing". It means "this area has data needs, open
   it", and it is a button. Clay is the colour of `missing` everywhere
   else, and four of the six areas are Partly covered with no missing need
   at all — so a clay pin was asserting, in colour, the opposite of the
   sentence printed beside it. §6 says the status vocabularies stay apart;
   this was the one place they had not.

   teal-accent is the palette's interactive colour (§7.1: links, focus
   ring, primary action), which is what these are. It holds 5.0:1 on the
   figure's teal-soft fill, against a 3:1 non-text floor (§8.2), and the
   white stroke keeps the pin off the body at any size. Status is carried
   where it always was: the bar and the sentence beside the label. */
/* Widens the pin's touch target without widening the pin. A transparent
   colour, not "none": "none" would not be hit-tested. */
.mark-hit { fill: rgba(0, 0, 0, 0); }

.mark-halo {
  fill: var(--teal-accent);
  opacity: 0.18;
  transition: opacity 0.15s ease;
}

.mark-pin {
  fill: var(--teal-accent);
  stroke: var(--surface);
  stroke-width: 2.5;
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 0.15s ease;
}

.mark-title {
  font-size: 17px;
  font-weight: 600;
  fill: var(--navy-ink);
}

.mark-count {
  font-size: 13px;
  fill: var(--muted);
}

/* Why one pin sits off the body, said where the words are. The legend has
   carried this under 640px since the ring caption was dropped; at desktop
   width the same pin sat on a faint dashed ellipse beside the ankles with
   nothing to explain it until after the click. */
.mark-systemic {
  font-size: 13px;
  font-weight: 400;
  fill: var(--muted);
}

/* Only shown under 640px, where the labels give way to the legend. */
.mark-num {
  font-size: 10px;
  font-weight: 700;
  fill: var(--surface);
  display: none;
}

.mark-bar rect[data-status="missing"]   { fill: var(--status-missing); }
.mark-bar rect[data-status="partial"]   { fill: var(--status-partial); }
.mark-bar rect[data-status="collected"] { fill: var(--status-collected); }

.map-mark[role="button"]:hover .mark-halo,
.map-mark[role="button"]:focus-visible .mark-halo { opacity: 0.28; }

.map-mark[role="button"]:hover .mark-pin,
.map-mark[role="button"]:focus-visible .mark-pin { transform: scale(1.18); }

.map-mark[role="button"]:hover .mark-count,
.map-mark[role="button"]:focus-visible .mark-count { fill: var(--navy-ink); }

/* Hovering a mark pushes the figure back so the pin comes forward. A
   systemic mark also brings up the ring its pin sits on, which is how the
   two kinds tell themselves apart on contact. */
.body-map:has(.map-mark[role="button"]:hover) .map-figure path,
.body-map:has(.map-mark[role="button"]:focus-visible) .map-figure path {
  stroke-opacity: 0.18;
}

.body-map:has(.map-mark[data-kind="systemic"][role="button"]:hover) .map-ring,
.body-map:has(.map-mark[data-kind="systemic"][role="button"]:focus-visible)
  .map-ring {
  stroke-opacity: 0.55;
}

/* The numbered legend — hidden until the labels are dropped. */
.map-legend { display: none; }

@media (max-width: 640px) {
  .mark-leader,
  .mark-title,
  .mark-count,
  .mark-bar { display: none; }

  .mark-num { display: block; }

  /* The footer's 48px on top of the screen's own 24px left a run of dead
     space under the last legend item on a phone. */
  .site-footer { margin-top: var(--space-section); }

  .map-legend {
    display: block;
    margin: 12px 0 0;
    padding-left: 1.5rem;
  }

  .map-legend li { margin-bottom: 8px; }

  /* The only control on the page at this width, so it carries the 44px
     target Apple and Android both ask for — which is the target the pins
     could not be given without overlapping each other. */
  .legend-item {
    display: flex;
    flex-direction: column;
    justify-content: center;
    width: 100%;
    min-height: 44px;
    text-align: left;
    background: none;
    border: 0;
    padding: 6px 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
  }

  .legend-area {
    display: block;
    font-weight: 600;
    color: var(--teal-accent);
  }

  /* Why this one pin sits off the body. Muted and lighter than the area
     name, because it qualifies the name rather than competing with it. */
  .legend-systemic {
    margin-left: 8px;
    font-weight: 400;
    font-size: 0.8125rem;
    color: var(--muted);
  }
  .legend-systemic::before { content: "· "; }

  .legend-count {
    display: block;
    font-size: 0.8125rem;
    color: var(--muted);
  }

  .hero-line { font-size: 1.5rem; }
}

/* ---------- responsive floor, 360px (§7.5) ---------- */

@media (max-width: 480px) {
  h1 { font-size: 1.5rem; }
}

/* ---------- the record column ---------- */

/* The cap goes on the screen, so every child shares one right edge rather
   than each carrying its own max-width. The inner caps below are cleared
   for the same reason: a 70ch lede inside a 38rem column is a second edge
   a few pixels off the first, which looks like a mistake rather than a
   measure. */
/* No per-element measure anywhere on a record: the column is the width,
   and a 70ch paragraph inside an 848px column was one of the five right
   edges this work removed. */
#screen-detail .lede,
#screen-detail .need-description,
#screen-detail .need-why,
#screen-detail .need-note { max-width: none; }

/* The three sections of a record: the claim, the check, the design. They
   were muted run-in spans at body size, which made the only structural
   markers on the card quieter than the prose they introduced. */
.section-head {
  margin: 0 0 6px;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--navy-ink);
}

/* The design's heading IS its button, so the heading carries no box of its
   own and the button keeps the look it had. */
.design-head { margin-bottom: 0; }

/* ---------- screen 4: about ---------- */

/* Two items: the masthead, which is the way home, and the About link,
   which is the only route into screen 4. They sit on one row and wrap to
   two at 360px. Centred rather than baseline-aligned, because the
   masthead is two lines tall and there is no shared baseline to align a
   one-line button to. */
.site-header .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
}
/* The masthead is one button holding both lines, so the two are no longer
   flex children of .wrap — the button is. It is content-sized rather than
   growing, so the click target is the words and not the empty half of the
   bar; About is pushed to the right edge by its own auto margin. */
.site-home {
  flex: 0 1 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* The mark. 32px — the wordmark beside it is two lines and about 40px
   tall, and a mark much under that reads as a stray bullet rather than
   as the thing the name sits against. The gap — the one point not
   filled in — is drawn in white rather than teal: teal holds 2.3:1 on
   --navy-deep, under the 3:1 floor (§8.2), and this is the one part of
   the drawing that has to be seen for it to mean anything. */
.site-mark {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
}
.site-mark svg {
  display: block;
  width: 100%;
  height: 100%;
}
.site-mark circle { fill: #C9D8E6; }
.site-mark .site-mark-gap {
  fill: none;
  stroke: var(--surface);
  stroke-width: 1.1;
}

.site-words { min-width: 0; }

.site-home .site-name,
.site-home .site-tagline { display: block; }

.site-home:hover .site-name { text-decoration: underline; }

/* Same backing as .header-link below, and for the same reason. */
.site-home:focus-visible {
  outline: 2px solid var(--teal-accent);
  outline-offset: 3px;
  box-shadow: 0 0 0 2px var(--surface);
  border-radius: 2px;
}

.header-link {
  flex: 0 0 auto;
  margin-left: auto;
  /* 44px tall, which is what Apple and Android ask of a touch target. At
     6px of padding it rendered 36. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 6px 16px;
  background: none;
  border: 1px solid #C9D8E6;   /* 8.3:1 on --navy-deep, same as the tagline */
  border-radius: 4px;
  color: #C9D8E6;
  font: inherit;
  font-size: 0.9375rem;
  cursor: pointer;
  transition: background-color 150ms ease, color 150ms ease;
}
.header-link:hover {
  background: var(--surface);
  color: var(--navy-deep);
}

/* The global ring is teal-accent on white. On --navy-deep teal holds only
   2.3:1, which is under the 3:1 non-text floor (§8.2), so the same teal
   ring is laid on a white backing rather than swapped for another colour. */
.header-link:focus-visible {
  outline: 2px solid var(--teal-accent);
  outline-offset: 2px;
  box-shadow: 0 0 0 2px var(--surface);
}

/* Built or planned. Deliberately not the three data-status colours: those
   mean the status of *data* on every other screen and must keep meaning
   only that. Word, colour and shape all carry it (§8.2, §12.11). */
.build-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  padding: 3px 10px 3px 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.875rem;
  font-weight: 600;
}
.build-chip::before {
  content: "";
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
}

/* Filled square, solid edge — it exists and is running. */
.build-chip[data-build-state="built"] {
  color: var(--navy-deep);
  border-style: solid;
  border-color: var(--navy-deep);
}
.build-chip[data-build-state="built"]::before {
  background: var(--navy-deep);
  border: 2px solid var(--navy-deep);
}

/* Half-filled square, solid edge — some of it is running and the sub-steps
   below say which. Same half-square idiom as a partial data need. */
.build-chip[data-build-state="partly"] {
  color: var(--navy-deep);
  border-style: solid;
  border-color: var(--navy-deep);
}
.build-chip[data-build-state="partly"]::before {
  background: linear-gradient(to right,
              var(--navy-deep) 0 50%, transparent 50% 100%);
  border: 2px solid var(--navy-deep);
}

/* Open square, dashed edge — designed, not built. */
.build-chip[data-build-state="planned"] {
  color: var(--muted);
  border-style: dashed;
  border-color: var(--muted);
}
.build-chip[data-build-state="planned"]::before {
  background: transparent;
  border: 2px dashed var(--muted);
}

/* The diagram. Under 640px it is dropped and the list below is the
   diagram, stacked — a five-node loop at 360px reads as nothing. */
.about-svg {
  display: block;
  width: 100%;
  height: auto;
  margin: 0 0 var(--space-section);
}

.about-node rect {
  fill: var(--surface);
  stroke-width: 2;
}
.about-node rect[data-build-state="built"] {
  fill: var(--teal-soft);
  stroke: var(--navy-deep);
}
.about-node rect[data-build-state="partly"] {
  fill: var(--teal-soft);
  stroke: var(--navy-deep);
  stroke-dasharray: 16 7;
}
.about-node rect[data-build-state="planned"] {
  stroke: var(--muted);
  stroke-dasharray: 4 6;
}

.about-node-num {
  font-size: 15px;
  font-weight: 700;
  fill: var(--muted);
}
.about-node-title {
  font-size: 20px;
  font-weight: 600;
  fill: var(--navy-ink);
}

/* Who runs this step. The word carries it; the FILL repeats it, not the
   ink. Three shades of dark text on seven identical boxes was the first
   attempt and the three were not tellable apart at a glance — muted grey,
   teal and navy are close in value, which is exactly what makes them all
   safe on white and all alike to each other.

   So the box itself says it. White is plain code, teal is AI, and the one
   dark box is the person — which also puts the emphasis where the whole
   pipeline is pointed. Deliberately none of the three data-status colours:
   those mean the status of DATA everywhere else and must keep meaning only
   that. */
.about-node-actor { font-size: 15px; font-weight: 700; }

.intake-node rect {
  stroke: var(--navy-deep);
  stroke-width: 2;
  stroke-dasharray: none;
}
.intake-node[data-actor="code"] rect { fill: var(--surface); }
.intake-node[data-actor="code"] .about-node-actor { fill: var(--muted); }

.intake-node[data-actor="ai"] rect { fill: var(--teal-soft); }
.intake-node[data-actor="ai"] .about-node-actor { fill: var(--teal-accent); }

.intake-node[data-actor="person"] rect { fill: var(--navy-deep); }
.intake-node[data-actor="person"] .about-node-title { fill: var(--surface); }
.intake-node[data-actor="person"] .about-node-actor { fill: #C9D8E6; }

.about-node-status { font-size: 14px; font-weight: 600; }
.about-node-status[data-build-state="built"],
.about-node-status[data-build-state="partly"] { fill: var(--navy-deep); }
.about-node-status[data-build-state="planned"] { fill: var(--muted); }

.about-flow {
  stroke: var(--navy-ink);
  stroke-opacity: 0.55;
  stroke-width: 1.5;
  marker-end: url(#about-arrow);
}
#about-arrow path { fill: var(--navy-ink); fill-opacity: 0.55; }

/* The return arrow is the point of the diagram, so it is the one line in
   the accent colour and the one drawn heavier. */
/* fill:none because the return is a <path> now, not a <line> — an L out of
   stage 6 and along into the platform. Without it the path fills black. */
.about-flow-loop {
  fill: none;
  stroke: var(--teal-accent);
  stroke-width: 2.5;
  marker-end: url(#about-arrow-loop);
}
#about-arrow-loop path { fill: var(--teal-accent); }
#intake-arrow path { fill: var(--navy-ink); fill-opacity: 0.55; }

/* The line that carries the intake chain on to its second row. A flow
   arrow that happens to turn two corners, so it is drawn like one. */
.about-flow-wrap {
  fill: none;
  stroke: var(--navy-ink);
  stroke-opacity: 0.55;
  stroke-width: 1.5;
  marker-end: url(#intake-arrow);
}

.about-loop-label {
  font-size: 15px;
  font-weight: 600;
  fill: var(--teal-accent);
}

/* The stages and the intake steps as text.

   Above 640px they are for assistive technology only. A sighted reader
   has the figure; printing the same six stages underneath it was the
   page saying everything twice, which is what made the About screen
   long. Below 640px the figures are dropped and these lists become the
   diagram, so the content is never actually absent — only ever in one
   form at a time. */
@media (min-width: 641px) {
  #screen-about .diagram-text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}
.system-stages {
  list-style: none;
  margin: 0 0 44px;
  padding: 0;
  counter-reset: stage;
}

.system-stages > li {
  position: relative;
  counter-increment: stage;
  margin-bottom: 30px;
  padding: var(--space-card) var(--space-card) var(--space-card) 56px;
  border: 1px solid var(--border);
  border-radius: 4px;
}

.system-stages > li::before {
  content: counter(stage);
  position: absolute;
  top: var(--space-card);
  left: var(--space-card);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--navy-deep);
  color: var(--surface);
  font-size: 0.875rem;
  font-weight: 700;
}

.system-stages > li::after {
  content: "\2193";
  position: absolute;
  left: 50%;
  bottom: -25px;
  transform: translateX(-50%);
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
}

/* Stage 5 does not point at nothing: it points back at stage 2. */
.system-stages > li:last-child::after {
  content: "\21BA  the loop returns to stage 2";
  left: 0;
  bottom: -28px;
  transform: none;
  color: var(--teal-accent);
  font-size: 0.875rem;
  font-weight: 600;
}

.system-stages h3 {
  margin: 2px 0 8px;
  font-size: 1.0625rem;
}
.system-stages p { max-width: none; }
.system-stages > li > p:last-child { margin-bottom: 0; }

/* The rotating mark on the research-design disclosure. It was shared with
   a stage-1 "How a record enters the system" toggle until that section was
   given a heading of its own and opened. */
.toggle-mark {
  width: 0;
  height: 0;
  flex: 0 0 auto;
  border-left: 6px solid currentColor;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  transition: transform 150ms ease;
  transform-origin: 30% 50%;
}
.design-toggle[aria-expanded="true"] .toggle-mark {
  transform: rotate(90deg);
}

@keyframes intake-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.intake-steps {
  margin: 0 0 var(--space-card);
  padding-left: 1.5rem;
}
.intake-steps > li { margin-bottom: var(--space-card); }
/* h3, not h4: the steps used to sit inside a stage-1 list item and are now
   their own section under an h2. */
.intake-steps h3 {
  margin: 0 0 6px;
  font-size: 1rem;
  line-height: 1.25;
}
.intake-steps p { margin-bottom: 0; }
.intake-steps .build-chip { margin-bottom: 4px; }

/* The diagram's actor label, in the text form of the same figure. Below
   640px this IS the diagram, so it has to carry what the boxes carry. */
.step-actor {
  margin: 0 0 8px;
  font-size: 0.9375rem;
  font-weight: 700;
}
.step-actor[data-actor="code"]   { color: var(--muted); }
.step-actor[data-actor="ai"]     { color: var(--teal-accent); }
.step-actor[data-actor="person"] { color: var(--navy-deep); }

/* The design rule the pipeline exists to protect. */
.intake-principle {
  margin: 0;
  padding: var(--space-card);
  background: var(--teal-soft);
  border-left: 3px solid var(--teal-accent);
  border-radius: 0 4px 4px 0;
}
.intake-principle p { margin: 0; }

.about-facts {
  margin: 0;
  padding-left: 1.25rem;
}
.about-facts > li {
  margin-bottom: 12px;
}

.system-stages code, .about-facts code {
  font-size: 0.9375rem;
  background: var(--teal-soft);
  padding: 1px 4px;
  border-radius: 3px;
}

@media (max-width: 640px) {
  /* The list below already carries every stage, in order, with its status.
     The loop itself is stated by stage 5's connector. */
  .about-svg { display: none; }

  .system-stages > li { padding-left: var(--space-card); padding-top: 52px; }
  .system-stages > li::before { top: var(--space-card); }
}

/* ---------- §7.3 motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- the check, its limit, and the generated design ---------- */

/* The disclaimer is not a footnote. A reader deciding whether to run a
   study has to see the limit of the check at the same moment as its
   result, so it sits directly under it and is not quieter than it. */
/* Inside .check-block now, under a rule rather than in a box of its own. */
.check-note {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--navy-ink);
}

.check-note p { margin: 0; }

.check-invite {
  display: inline-block;
  margin-top: 8px;
  font-weight: 600;
  color: var(--teal-accent);
}

/* The one place a model writes on a screen. Set apart from every record
   block above it, because what it holds is an answer, not data. */
.design {
  margin-top: var(--space-section);
  padding-top: var(--space-card);
  border-top: 1px solid var(--border);
}

/* Inline-flex rather than inline-block, so the disclosure mark sits on the
   button's centreline. */
.design-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: var(--teal-accent);
  border: 0;
  border-radius: 4px;
  color: var(--surface);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.design-toggle:hover { background: var(--navy-deep); }

.design-panel {
  margin-top: var(--space-card);
  animation: intake-in 150ms ease;
}

.design-origin { margin: 0 0 var(--space-card); }

/* A footnote, and set like one: what the source said about collecting the
   data, on the records where it said nothing. It was a labelled block with a
   rule in every card, which gave "there is nothing here" the weight of a
   finding on eight records out of eleven. */
.record-footnote {
  margin-top: var(--space-section);
  padding-top: 12px;
  border-top: 1px solid var(--border);
}

.record-footnote p {
  margin: 0;
  color: var(--muted);
  font-size: 0.875rem;
  font-style: italic;
}

.legacy-origin { margin: var(--space-section) 0 var(--space-card); }

/* What a design does not contain. Not quieter than the fields above it:
   a reader who skims the study design and misses this is exactly the
   reader it is for. */
/* No max-width. 70ch here measured 604px against the 848px the design
   fields beside it run to, so the disclaimer stopped two-thirds of the way
   across and read as a stray block rather than the closing note of the
   panel. Prose elsewhere is measured for reading length; this one is
   measured against the panel it closes. */
.design-limits {
  margin: var(--space-card) 0 0;
  padding: 12px var(--space-card);
  border-left: 3px solid var(--status-partial);
  background: var(--surface);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--navy-ink);
}

/* A design the intake rules refused. The record stands; this says what is
   missing from it and why, rather than showing nothing at all. */
.design-withheld {
  border-top: 1px solid var(--border);
}

/* Weight comes from .section-head now, so a withheld record's heading
   matches the other two on the card instead of sitting one step lighter. */
.design-withheld-head {
  margin: var(--space-card) 0 6px;
  color: var(--navy-ink);
}

.design-withheld-why {
  margin: 0;
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.5;
}

/* ---------- copy the design out ---------- */

/* The platform ends where study design begins, so the last thing on the
   card is the way to carry it there. Secondary to Show research design:
   an outline button, because it is the second action and not the first. */
.design-copy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin-top: var(--space-card);
  padding-top: var(--space-card);
  border-top: 1px solid var(--border);
}

.copy-button {
  padding: 7px 13px;
  background: var(--surface);
  border: 1px solid var(--teal-accent);
  border-radius: 4px;
  color: var(--teal-accent);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
}

.copy-button:hover {
  background: var(--teal-accent);
  color: var(--surface);
}

/* The word carries the result, not the colour (§8.2). */
.copy-status {
  font-size: 0.875rem;
  color: var(--teal-accent);
}

/* Deliberately not the clay of `missing`: those three colours mean the
   status of DATA everywhere else and must keep meaning only that (§6).
   The sentence carries the failure, and it carries an instruction. */
.copy-status.copy-failed {
  color: var(--muted);
  font-style: italic;
}

/* ---------- the rest of a long check ---------- */

/* The verdict is visible and the working is one keystroke away. A text
   button, so it reads as "more of this paragraph" rather than as an
   action of its own. */
.check-toggle {
  display: block;
  margin-top: 6px;
  padding: 2px 0;
  background: none;
  border: 0;
  color: var(--teal-accent);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}

.check-toggle:hover { color: var(--navy-deep); }

/* ---------- screen 1a: one area ---------- */

/* The home screen is the map alone, so an area opens as its own screen
   rather than as a heading in a list below the figure. This is the hint
   that says so, and it is the only prose left on the home screen. */
/* Left-aligned like everything else on the page. Centred, it read as a
   stray caption rather than as the instruction it is. */
.map-hint {
  margin: 12px 0 0;
  font-size: 0.9375rem;
  color: var(--muted);
}

/* Centred under the figure, which is centred. Only where that is true: below
   640px this line introduces a left-aligned numbered list and belongs on the
   same edge as it. */
@media (min-width: 641px) {
  .map-hint { text-align: center; }
}

/* Only true under 640px, where the labels are gone and the pins carry
   numbers instead. The override sits here rather than in the main mobile
   block further up the file: same specificity, so whichever comes last
   wins, and up there this rule would have overruled it at every width. */
.map-hint-narrow { display: none; }
.map-hint-wide { display: inline; }

@media (max-width: 640px) {
  .map-hint-narrow { display: inline; }
  .map-hint-wide { display: none; }
}

#screen-area .count { margin-bottom: var(--space-section); }
