/* BrainHarbor design tokens + base styles ("Clear & Kind" theme, WI-108;
   foundation WI-101). Visual spec: docs/design/entry-hub-handoff/ — recreate
   to match. Audience constraint, not polish: readers may have cognitive
   impairment from the tumor, seizures, or treatment (PLAN.md §3). Hard
   requirements: ≥18px base text, WCAG AA contrast (AAA body), visible focus,
   generous spacing, big tap targets. Change values here, not in page CSS. */

:root {
  /* Color — contrast on --color-paper noted. Palette is deliberately calm:
     no reds/alarms outside true warnings. */
  --color-paper: #ffffff;
  --color-surface: #eef3f7;      /* hub, tags, header band */
  --color-ink: #16202b;          /* body text — 15.6:1 (AAA) */
  --color-ink-muted: #455263;    /* secondary text — 7.6:1 (AAA) */
  --color-accent: #0d6a86;       /* links, buttons — 4.9:1 (AA, underlined) */
  --color-accent-strong: #094f65;/* hover/active — 6.9:1 */
  --color-focus: #0d6a86;        /* focus ring (needs ≥3:1) */
  --color-border: #5b6a78;       /* meaningful borders (inputs) — 4.5:1 */
  --color-border-subtle: #dbe3ea;/* decorative hairlines only */
  --color-band: #0d3b4a;         /* helpline band + dark panels */
  --color-band-ink: #ffffff;     /* text on band — 11:1 */
  /* Two attention palettes, deliberately distinct. NOTICE is a status fact
     ("this trial has closed"); CAUTION is the AI warning from the homepage
     handoff. They say different things, so they do not look identical — and
     the handoff specifies the amber, with its contrast already measured. */
  --color-notice: #fdf3ef;       /* "this has closed / take care" panel fill */
  --color-notice-border: #f0d3c6;
  --color-notice-edge: #b4552b;  /* its left rule — 4.8:1 on the fill */
  --color-caution: #fff6e0;      /* AI notice fill (homepage handoff) */
  --color-caution-border: #e6d3a3;
  --color-caution-edge: #8a6a12; /* its left rule — 5.9:1 on the fill */

  /* Type — 18px base, ~1.2 modular scale */
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-head: var(--font-body);
  --text-sm: 0.889rem;   /* 16px — smallest allowed anywhere */
  --text-base: 1rem;     /* 18px */
  --text-lg: 1.2rem;     /* ~22px */
  --text-xl: 1.44rem;    /* ~26px */
  --text-2xl: 1.728rem;  /* ~31px */
  --text-3xl: 2.074rem;  /* ~37px */
  --leading: 1.6;
  --leading-tight: 1.25;

  /* Spacing */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;

  /* Layout */
  --measure: 65ch;           /* max line length for prose */
  --measure-read: 46rem;     /* single-column reading pages (item pages) */
  --container: 72rem;        /* page shell width */
  --tap-target: 2.75rem;     /* ~50px at 18px root — clears the 44px floor */
  --focus-ring: 3px;

  /* Shape — rounded + soft shadow is the theme's signature */
  --radius: 14px;
  --radius-lg: 18px;         /* doors in the hero band (homepage handoff) */
  --card-bg: #ffffff;
  --card-border: 1px solid #e6ecf1;
  --card-radius: 16px;
  --card-shadow: 0 3px 14px rgba(20, 45, 65, .07);

  /* Journey path — the evidence indicator (journey handoff, 2026-08-19).
     Replaces both the stage badge's dot-meter and the 0-10 readiness dial:
     four named stages a reader can repeat to their doctor, instead of a
     number nobody can interpret at any single value. */
  --journey-on: #0d6a86;     /* stages reached */
  --journey-off: #cfd9e0;    /* not reached — 1.6:1 on white, DECORATIVE ONLY,
                                never put text on it */
  --journey-now: #0d3b4a;    /* the current stage — 11:1 as a label colour */

  /* Laid over a card photo the colours have to invert: the backdrop is a
     different image on every card, so nothing can be assumed about what is
     behind the path. The plate below is near-opaque for exactly that reason —
     it re-establishes a known background, and these values are measured
     against IT, not against the photo. */
  --journey-plate: rgba(11, 45, 58, 0.93);   /* white on this: ~10.4:1 */
  --journey-on-over: #ffffff;
  --journey-off-over: rgba(255, 255, 255, 0.34);  /* decorative only */

  /* Stage badge: pill + evidence dot-meter. Retired from reader-facing pages
     by the journey handoff, but still used by the ADMIN review queue and the
     dev style guide, where a compact operational badge beats a four-stage
     path in a dense triage list. */
  --badge-fill: #0d6a86;
  --badge-empty: #bcd3db;
}

/* ---------- Base ---------- */

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

/* 112.5% = 18px at the browser default, but still scales if the user raises
   their default font size — never a fixed px, this audience needs the knob. */
html {
  font-size: 112.5%;
}

/* Large-text mode (WI-102): 137.5% = 22px base. Everything downstream is
   rem-based, so the whole scale rides along. Set server-side from the
   bh_textsize cookie — works with JavaScript disabled. */
html.text-large {
  font-size: 137.5%;
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading);
  color: var(--color-ink);
  background: var(--color-paper);
}

h1, h2, h3, h4 {
  font-family: var(--font-head);
  line-height: var(--leading-tight);
  margin-block: var(--space-6) var(--space-4);
  max-width: var(--measure);
}

h1 { font-size: var(--text-3xl); }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-xl); }
h4 { font-size: var(--text-lg); }

p, ul, ol {
  margin-block: 0 var(--space-4);
  max-width: var(--measure);
}

small { font-size: var(--text-sm); }

.text-muted { color: var(--color-ink-muted); }

img {
  max-width: 100%;
  height: auto;
}

/* Links stay underlined — color is never the only cue (WCAG 1.4.1). */
a {
  color: var(--color-accent);
  text-underline-offset: 0.15em;
}

a:hover {
  color: var(--color-accent-strong);
}

/* Hidden on screen, still announced. The homepage h1 uses this: the lockup is
   the heading visually, but alt text never appears in a screen reader's
   heading list, and heading navigation is how much of this audience moves
   around a page. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- Focus: always visible, never removed ---------- */

:focus-visible {
  outline: var(--focus-ring) solid var(--color-focus);
  outline-offset: 2px;
}

/* ---------- Controls: big, obvious tap targets ---------- */

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

.button,
button,
input[type="submit"] {
  min-block-size: var(--tap-target);
  padding: var(--space-2) var(--space-6);
  border: 2px solid var(--color-accent);
  border-radius: var(--radius);
  background: var(--color-accent);
  color: var(--color-band-ink);
  font-weight: 700;
  cursor: pointer;
}

/* Links styled as buttons (e.g. tel: links on /get-help-now) need the
   flex treatment for the min-height to actually apply. */
a.button {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  margin-inline-end: var(--space-3);
  margin-block-end: var(--space-2);
}

a.button:hover {
  text-decoration: underline;
}

.button:hover,
button:hover,
input[type="submit"]:hover {
  background: var(--color-accent-strong);
  border-color: var(--color-accent-strong);
}

/* Outlined and large variants (homepage handoff): the "See all research
   updates" button under the feed is the page's main way onward, so it gets
   size rather than colour to carry the emphasis. */
.button--outline {
  background: var(--color-paper);
  color: var(--color-accent);
}

.button--outline:hover {
  background: var(--color-surface);
  color: var(--color-accent-strong);
  border-color: var(--color-accent-strong);
}

.button--lg {
  min-block-size: 3.25rem;
  padding: var(--space-3) var(--space-7);
  font-size: var(--text-lg);
}

input[type="text"],
input[type="search"],
input[type="email"],
select,
textarea {
  min-block-size: var(--tap-target);
  padding: var(--space-2) var(--space-3);
  border: 2px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-paper);
}

/* ---------- Page shell ---------- */

.container {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--space-4);
}

/* Single-column reading pages (research items): a calm, narrow flow. */
.container--read {
  max-width: var(--measure-read);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
}

.skip-link:focus-visible {
  position: fixed;
  left: var(--space-2);
  top: var(--space-2);
  z-index: 100;
  padding: var(--space-3) var(--space-4);
  background: var(--color-accent);
  color: var(--color-band-ink);
  border-radius: var(--radius);
}

/* ---------- Persistent helpline band (WI-103 renders it) ---------- */

.helpline-band {
  background: var(--color-band);
  color: var(--color-band-ink);
}

.helpline-band .container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-5);
  padding-block: var(--space-2);
}

.helpline-band a {
  color: var(--color-band-ink);
  text-decoration: underline;
  display: inline-flex;
  align-items: center;
  min-block-size: var(--tap-target);
}

.helpline-band a.tel {
  font-weight: 800;
}

/* On a phone the band stacked into three full-height rows and ate 155px —
   more than a sixth of the viewport, on every page, before anything else.
   Tighten it to two: the prompt sits inline with the number (it is a short
   question, not a heading), and "More help options" keeps its own row because
   it is a separate destination and must stay a full-width tap target.
   Nothing is removed: the number and the route to more help both survive,
   which is the part that is not negotiable on this band. */
@media (max-width: 40rem) {
  .helpline-band .container {
    gap: 0 var(--space-3);
    padding-block: var(--space-1);
  }

  .helpline-band span {
    font-size: var(--text-sm);
  }

  /* The links KEEP a full 44px box. An earlier pass here shaved them to 2.25rem
     (40.5px) to save four pixels and broke the tap-target floor on the two
     most important links on the site. The saving comes from the padding and
     from the label's row instead, never from the target. */
  .helpline-band a {
    min-block-size: var(--tap-target);
  }
}

/* ---------- Header ---------- */

.site-header {
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border-subtle);
  /* The anchor for the mobile menu panel, which drops out of flow below it. */
  position: relative;
}

.site-header .container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-6);
  padding-block: var(--space-3);
}

.site-name {
  font-size: var(--text-lg);
  font-weight: 800;
  color: var(--color-ink);
  text-decoration: none;
  display: inline-flex;   /* kills the inline-image baseline gap */
  align-items: center;
}

/* The lockup. Height in rem, not px, so it rides the large-text scale like
   everything else (WI-102) — 2.5rem is 45px normally, 55px in large-text mode,
   both above the brand README's 180px-wide minimum for the no-tagline lockup.
   width:auto keeps the artwork's ratio whatever the height resolves to. */
.site-name img {
  height: 2.5rem;
  width: auto;
  display: block;
}

/* Icon-only masthead on a phone (see _Layout). The lockup's ~200px width was
   what pushed the menu button onto a row of its own.

   Selectors are `.site-name img.x` (0-2-1) on purpose. `.site-name img` above
   sets `display: block` at 0-1-1, which OUTRANKS a bare `.site-name__lockup`
   (0-1-0) — so the first version of this rule left BOTH images rendering, the
   masthead 242px wide, and the menu button still wrapped. Nothing about the
   markup or the media query was wrong; the toggle simply never won. */
.site-name img.site-name__mark { display: none; }

@media (max-width: 40rem) {
  .site-name img.site-name__lockup { display: none; }
  .site-name img.site-name__mark { display: block; }
}

/* No underline on hover here: the target is a picture, and a rule under a
   logo reads as a rendering fault rather than a link cue. The link is still
   keyboard-focusable and gets the global :focus-visible outline. */
.site-name:hover {
  color: var(--color-ink);
  text-decoration: none;
}

.site-nav {
  margin-inline-start: auto;
}

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
  max-width: none;
}

/* Nav links: padding makes each one a full-size tap target. */
.site-nav a {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--tap-target);
  padding: var(--space-2) var(--space-3);
  color: var(--color-ink);
  text-decoration: none;
  border-radius: var(--radius);
}

.site-nav a:hover {
  color: var(--color-accent-strong);
  text-decoration: underline;
}

/* "Get Help Now" — the one filled pill. Lives OUTSIDE the collapsible menu
   (see _Layout): the crisis route stays one tap at every width. */
.nav-cta {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--tap-target);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius);
  background: var(--color-accent);
  color: var(--color-band-ink);
  font-weight: 700;
  text-decoration: none;
}

.nav-cta:hover {
  background: var(--color-accent-strong);
  color: var(--color-band-ink);
}

/* ---------- Collapsible nav (the hamburger) ----------
   MOBILE FIRST: the menu is closed by default and the toggle is visible. The
   desktop rule below re-opens it permanently. No JavaScript anywhere in here —
   <details> gives us the disclosure, the keyboard handling and the state. */

/* Two rows on a phone, not three:
     row 1  [logo] .......... [Aa] [Menu]
     row 2  [ Get Help Now, full width ]
   The crisis CTA gets the full width deliberately. It is the one control on
   this page a reader might be reaching for in a panic, and a full-width bar is
   both unmissable and impossible to mis-tap — better than the word-sized pill
   it was, not a consolation for moving it down a row. */
.nav-collapse {
  order: 3;
}

.text-toggle { order: 2; }

.nav-cta {
  order: 4;
  flex-basis: 100%;
  justify-content: center;
}

.site-name { order: 1; margin-inline-end: auto; }

.nav-collapse__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--tap-target);
  min-inline-size: var(--tap-target);
  padding: var(--space-2) var(--space-4);
  border: 2px solid var(--color-accent);
  border-radius: var(--radius);
  color: var(--color-accent-strong);
  font-weight: 700;
  cursor: pointer;
  list-style: none;     /* kill the default disclosure triangle */
}

/* Safari needs the -webkit pseudo-element too, or the triangle survives. */
.nav-collapse__toggle::-webkit-details-marker { display: none; }

.nav-collapse__toggle:hover {
  background: var(--color-surface);
  border-color: var(--color-accent-strong);
}

/* The three bars, drawn with borders so they cost no image and inherit the
   text colour — including in forced-colours / high-contrast mode, where a
   background-drawn icon would disappear. */
.nav-collapse__bars {
  inline-size: 1.15rem;
  block-size: 0.85rem;
  border-block-start: 3px solid currentColor;
  border-block-end: 3px solid currentColor;
  position: relative;
}

.nav-collapse__bars::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-start: calc(50% - 1.5px);
  block-size: 3px;
  background: currentColor;
}

/* MOBILE: the nav is hidden until the toggle is open. It is a SIBLING of the
   <details> (see _Layout), so plain CSS decides — no wrestling with the
   element's built-in content hiding. */
.site-nav { display: none; }

/* Open: a full-width panel dropping below the header, out of flow so the Menu
   button does not jump to another row when it opens. Anchored to
   .site-header, which is position:relative for this. */
.nav-collapse[open] ~ .site-nav {
  display: block;
  position: absolute;
  inset-inline: 0;
  inset-block-start: 100%;
  z-index: 20;
  background: var(--color-surface);
  border-block-end: 1px solid var(--color-border-subtle);
  /* It overlays the hero band, so it needs to read as a layer above the page
     rather than as part of it. */
  box-shadow: 0 12px 28px rgba(20, 45, 65, 0.22);
  /* Inline padding matches .container so the menu items line up with the
     masthead above them rather than sitting a few pixels adrift. */
  padding: var(--space-2) var(--space-4) var(--space-3);
}

.nav-collapse[open] ~ .site-nav ul {
  flex-direction: column;
  align-items: stretch;
  gap: 0;
}

/* Full-width rows with a rule between them: a list of destinations reads
   faster than a wrapped cloud of links, and each row is a wide tap target
   rather than a word-sized one.

   `display: flex` (not the inline-flex these links use elsewhere) is what
   makes the row full width. As inline-flex the box — and so the tap target and
   the divider rule under it — stopped at the end of the word, which put a
   short rule under "Trials" and a long one under "Tumor types" and left most
   of each row untappable. */
.nav-collapse[open] ~ .site-nav a {
  display: flex;
  border-block-end: 1px solid var(--color-border-subtle);
  border-radius: 0;
  padding-inline: var(--space-1);
}

.nav-collapse[open] ~ .site-nav li:last-child a {
  border-block-end: 0;
}

/* Large-text toggle — an outlined pill so it reads as a control, not a link. */
.text-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--tap-target);
  padding: var(--space-2) var(--space-4);
  border: 2px solid var(--color-accent);
  border-radius: var(--radius);
  color: var(--color-accent-strong);
  text-decoration: none;
  font-weight: 700;
}

/* ---------- Desktop: undo the collapse ----------
   Above 48rem the disclosure disappears entirely and the nav is an ordinary
   horizontal list. The `[open]` attribute is irrelevant here: the content is
   shown whatever its state, so a reader who toggled it shut on a phone and
   then rotated to landscape does not find their nav missing. */
@media (min-width: 48rem) {
  /* The disclosure disappears entirely — it is a phone control, and at this
     width the nav is an ordinary horizontal list that never needed one. */
  .nav-collapse { display: none; }

  /* Back to one row, in source order, with the CTA back to a pill. */
  .site-name,
  .text-toggle,
  .nav-cta { order: 0; }

  .site-name { margin-inline-end: 0; }

  .nav-cta { flex-basis: auto; }

  /* Always shown, whatever state the <details> was left in. A reader who
     opened the menu on a phone and then rotated to landscape must not find
     their navigation missing. */
  .site-nav,
  .nav-collapse[open] ~ .site-nav {
    display: block;
    position: static;
    margin-inline-start: auto;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
  }

  .site-nav ul,
  .nav-collapse[open] ~ .site-nav ul {
    flex-direction: row;
    align-items: center;
    gap: var(--space-1);
  }

  .site-nav a,
  .nav-collapse[open] ~ .site-nav a {
    display: inline-flex;
    border-block-end: 0;
    border-radius: var(--radius);
    padding-inline: var(--space-3);
  }
}

/* The words beside "Aa" cost a whole row on a narrow header. The button keeps
   its accessible name either way (aria-label on the anchor), so a screen
   reader still hears "Use larger text" rather than "Aa". */
@media (max-width: 30rem) {
  .text-toggle__label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .text-toggle {
    padding-inline: var(--space-3);
  }
}

.text-toggle:hover {
  text-decoration: underline;
  color: var(--color-accent-strong);
}

main {
  padding-block: var(--space-6) var(--space-8);
}

/* --space-6/8 (2rem/4rem) is composure on a wide page and dead scrolling on a
   phone: it put roughly 150px of nothing between the header and every h1, on
   every page, before a reader saw a single word. Halved at the top, trimmed at
   the bottom — the footer supplies its own breathing room.

   Heading margins come down with it. Vertical rhythm tuned for a 65ch column
   reads as drift in a 390px one, and the FIRST heading needs no top margin at
   all: the container's padding already spaced it, so the two were stacking. */
@media (max-width: 40rem) {
  main {
    padding-block: var(--space-4) var(--space-6);
  }

  h1, h2, h3, h4 {
    margin-block: var(--space-5) var(--space-3);
  }

  main > :first-child,
  main > .container--read > :first-child,
  main > article > :first-child,
  main > article > .container--read > :first-child {
    margin-block-start: 0;
  }
}

/* ---------- Hero band — the "Harbor Banner" (homepage handoff) ----------

   The one branded moment on the page, and the reason the homepage stopped
   burying its own content: what used to be a hero paragraph, three doors and
   a full-width AI panel is now one band and two doors, so the first real
   update sits near the top of the screen instead of a screen and a half down.
   Branding appears here, in the header, and beside the section heading — all
   space that was otherwise empty, never in front of content. */

.hero-band {
  position: relative;
  background: var(--color-band);
  color: var(--color-band-ink);
  overflow: hidden;
  padding-block-start: var(--space-6);
}

.hero-band__watermark {
  position: absolute;
  top: -70px;
  inset-inline-end: -70px;
  width: 400px;
  height: 400px;
  opacity: 0.07;
  pointer-events: none;
}

.hero-band__inner {
  position: relative;
  padding-block-end: var(--space-7);
}

/* The lockup IS the h1: visually-hidden text carries the heading and the image
   is decorative. Alt text is not a heading — it never appears in a screen
   reader's heading list, and heading navigation is a primary strategy for this
   audience. */
.hero-band h1 {
  margin: 0 0 var(--space-6);
  max-width: none;
}

.hero-band h1 img {
  display: block;
  width: 640px;
  max-width: 100%;
  height: auto;
}

/* On a phone the header lockup and this one land within a few hundred pixels
   of each other, so the brand reads twice at full size before a single word of
   content. The header keeps its masthead (it is the link home on every page)
   and this one gives some height back: still the branded moment, no longer a
   second full-width logo stacked under the first.

   The padding goes too. --space-6/7 was tuned for a wide band where the
   whitespace reads as composure; in a 390px column it is just scrolling. */
@media (max-width: 40rem) {
  .hero-band {
    padding-block-start: var(--space-4);
  }

  .hero-band__inner {
    padding-block-end: var(--space-5);
  }

  .hero-band h1 {
    margin-block-end: var(--space-4);
  }

  .hero-band h1 img {
    width: 78%;
  }

  /* The watermark is sized for a desktop band; at this width it dominates the
     doors instead of sitting behind them. */
  .hero-band__watermark {
    width: 260px;
    height: 260px;
    top: -40px;
    inset-inline-end: -50px;
  }
}

/* One plain line of AI disclosure inside the band. The handoff puts the AI
   notice at the foot of the page so it stops standing between the reader and
   the content, which is right — but a reader should not be able to get through
   eight summaries before learning who wrote them. So the admission leads here
   in one sentence, and the full notice still closes the page. */
.hero-band__disclosure {
  max-width: 46ch;
  margin: 0;
  color: var(--color-band-ink);
}

.hero-band__disclosure a {
  color: var(--color-band-ink);
  text-decoration: underline;
}

/* Wave edge where the band meets the page — lifted from the logo's waterline. */
.wave-edge {
  display: block;
  width: 100%;
  height: 52px;
}

/* ---------- Two doors ----------

   Two, not three: three equal choices is three decisions before anyone has
   read anything, and "browse all research" is what the feed underneath already
   does. The crisis door stays — it is the one that must never be hard to find. */

.doors {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--space-4);
  margin-block-end: var(--space-5);
}

.door {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  text-decoration: none;
  min-block-size: var(--tap-target);
}

.door__icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  font-size: 1.7rem;
}

.door__title {
  display: block;
  font-size: var(--text-xl);
  line-height: var(--leading-tight);
}

.door--primary {
  background: var(--color-accent);
  color: var(--color-band-ink);
}

.door--primary .door__icon {
  background: rgba(255, 255, 255, .2);
  font-size: 1.9rem;
  font-weight: 800;
}

.door--secondary {
  background: var(--color-paper);
  color: var(--color-band);
}

.door--secondary .door__icon {
  background: var(--color-surface);
}

/* ---------- Feed grid + cards ---------- */

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

/* The lighthouse mark beside the heading — a "new section starts here"
   wayfinding cue. Deliberately not repeated on cards: it would be identical on
   every one, so it cannot distinguish them, and it would compete with the
   evidence badge, which is the element that genuinely differs. */
.section-head__title {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.section-head__title img {
  display: block;
  width: 46px;
  height: 46px;
  flex: none;
}

.section-head h2 {
  margin: 0;
}

/* The logo's wave, reused as a section rule. */
.wave-rule {
  display: block;
  width: 100%;
  height: 11px;
  margin-block-end: var(--space-3);
}

/* The centred "See all" row. max-width:none is required: the global `p, ul, ol`
   rule caps at --measure (65ch), which would centre the button inside a ~630px
   box rather than the content width and read as accidentally left-shifted. */
.see-all-row {
  text-align: center;
  max-width: none;
  margin-block: var(--space-6);
}

.feed-grid {
  display: grid;
  /* auto-fit rather than a fixed 2 columns: the cards decide when to wrap, so
     one breakpoint stops being a thing that can be forgotten. Two-up on
     desktop, one column on a phone, and it degrades gracefully in between.
     340px, not 320: the journey path's four labels need the width, and below
     this they wrap into an unreadable stack (journey handoff, 2026-08-19). */
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: var(--space-4);
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: none;
}


.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  height: 100%;
  background: var(--card-bg);
  border: var(--card-border);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
  padding: var(--space-4) var(--space-5);
  overflow: hidden; /* clip the banner to the card's rounded top */
}

/* Card hero: a content-matched photo backdrop. Bleeds to the card edges, sits
   above the journey path, breaks up the wall of text. Purely decorative.
   It carried the 0-10 readiness dial until the journey handoff (2026-08-19)
   retired that number; Dan kept the photos, so the hero is now backdrop only. */
.card-hero {
  position: relative;
  margin: calc(-1 * var(--space-4)) calc(-1 * var(--space-5)) 0;
  /* min-height, not height: the indicator plate lives inside this box now, and
     on a narrow card the four journey labels wrap to two lines. A fixed height
     would clip "Tested in people" — the label that matters most — rather than
     letting the band grow.

     11rem, up from the dial era's 8: the plate is ~7rem tall once a label
     wraps, so at 8rem the photo was a sliver and there was no point keeping
     it. This leaves the picture a real band above the plate. */
  min-height: 11rem;
  overflow: hidden;
  display: flex;
  /* The plate sits at the BOTTOM of the photo: it reads as a caption on the
     image rather than a bar floating over the middle of it, and it puts the
     path directly above the headline it qualifies. */
  align-items: flex-end;
  background-size: cover;
  background-position: center;
  background-color: var(--color-surface);
}

/* Fade the photo back so it stays a calm backdrop rather than a focal point.
   Lighter wash than the dial era (0.72/0.82): the dark indicator plate now
   supplies all the contrast the text needs, so the photo no longer has to be
   bleached to make something on top of it readable. It still gets washed
   enough to stay a backdrop — the plate has to be the loudest thing here. */
.card-hero__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.68));
}

.card h3 {
  margin: 0;
  font-size: var(--text-xl);
  max-width: 34ch;
}

.card h3 a {
  color: var(--color-accent);
  text-decoration: underline;
}

.card__hook {
  margin: 0;
  color: var(--color-ink);
  max-width: 60ch;
}

/* Meta pinned to the bottom so cards in a row align. */
.card__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  margin-block-start: auto;
}

.tag {
  display: inline-block;
  font-size: var(--text-sm);
  padding: var(--space-1) var(--space-3);
  background: var(--color-surface);
  border-radius: 999px;
  color: var(--color-ink-muted);
}

/* ---------- Pager (WI-438) ----------
   Back / page numbers / Next. Every control is at least --tap-target square,
   because this is a control a reader uses repeatedly and often on a phone, and
   the audience includes people whose treatment has affected their fine motor
   control. Numbers wrap rather than scroll sideways on a narrow screen. */

.pager {
  margin-block-start: var(--space-6);
}

.pager__status {
  margin: 0 0 var(--space-3);
  color: var(--color-ink-muted);
  max-width: none;
}

.pager__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: none;
}

.pager__page,
.pager__step,
.pager__gap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: var(--tap-target);
  min-block-size: var(--tap-target);
  padding-inline: var(--space-3);
  border-radius: var(--radius);
  font-size: var(--text-base);
}

.pager__page,
.pager__step {
  border: 2px solid var(--color-border-subtle);
  color: var(--color-accent);
  text-decoration: underline;
  gap: var(--space-2);
}

.pager__page:hover,
.pager__step:hover {
  border-color: var(--color-accent);
  color: var(--color-accent-strong);
}

/* The current page is not a link — there is nowhere to go — so it must be told
   apart by more than colour: it is filled, and its border is solid ink. */
.pager__page--current {
  background: var(--color-band);
  border: 2px solid var(--color-band);
  color: var(--color-band-ink);
  font-weight: 700;
  text-decoration: none;
}

/* Disabled Back/Next keep their space so the control does not resize under a
   reader's finger as they page. */
.pager__step--off {
  border: 2px dashed var(--color-border-subtle);
  color: var(--color-ink-muted);
  text-decoration: none;
}

.pager__gap {
  min-inline-size: 0;
  padding-inline: var(--space-1);
  color: var(--color-ink-muted);
}

/* ---------- Journey path: the evidence indicator ----------
   (journey handoff, 2026-08-19 — replaces the badge dot-meter AND the 0-10
   readiness dial.) Four named stages, a filled dot for each stage reached and
   a larger ringed dot on the current one. Markup, built server-side from the
   stage enum so no author ever types a number:
     <ol class="journey" role="img"
         aria-label="Review of existing research. Stage 3 of 4.">
       <li class="journey__step is-done">
         <span class="journey__dot"></span>
         <span class="journey__label">Lab cells</span>
       </li> … always all four
     </ol>
   All four steps always render: the unreached ones ARE the message, because
   they show how much road is left. */

.journey {
  display: flex;
  align-items: flex-start;
  list-style: none;
  margin: 0 0 var(--space-2);
  padding: 0;
  max-width: none;
}

.journey__step {
  flex: 1;
  text-align: center;
  position: relative;
  min-width: 0;
}

/* Connector runs from the previous dot's centre to this one's. Dots are 22px,
   so their centre is at 11px; the 4px line sits at top:9px. The current dot is
   32px with margin-top:-5px, which puts ITS centre at 11px too. Change either
   size and you must keep those centres equal or the line visibly steps. */
.journey__step::before {
  content: "";
  position: absolute;
  top: 9px;
  left: -50%;
  right: 50%;
  height: 4px;
  background: var(--journey-off);
}

.journey__step:first-child::before { display: none; }

.journey__step.is-done::before,
.journey__step.is-current::before { background: var(--journey-on); }

.journey__dot {
  position: relative;
  display: block;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--journey-off);
  margin: 0 auto var(--space-2);
}

.journey__step.is-done .journey__dot { background: var(--journey-on); }

/* The current stage is bigger, darker and double-ringed so it is found by
   SHAPE and SIZE, not colour alone (WCAG 1.4.1). Keep both if you restyle. */
.journey__step.is-current .journey__dot {
  width: 32px;
  height: 32px;
  margin: -5px auto var(--space-2);
  background: var(--journey-now);
  border: 4px solid var(--color-paper);
  box-shadow: 0 0 0 3px var(--journey-now);
}

.journey__label {
  display: block;
  font-size: var(--text-sm);  /* 16px — the floor, not a suggestion */
  line-height: 1.2;
  color: var(--color-ink-muted);
}

.journey__step.is-current .journey__label {
  font-weight: 700;
  color: var(--journey-now);
}

/* The item page's larger path, under "How far along is this research?" */
.journey--lg {
  max-width: 34rem;
  margin-block-end: var(--space-5);
}

.journey--lg .journey__label { font-size: var(--text-base); }

/* ---- Laid over the card photo (Dan, 2026-08-19) ----
   The path takes the dial's old position AND its prominence: it is the first
   thing on the card and the only element that differs meaningfully between
   cards. Sitting under the photo made it a footnote to a decorative image. */

.card-hero__indicator {
  position: relative;          /* above the scrim */
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background: var(--journey-plate);
  /* The plate is why this is legible on ANY photo in the pool. Without it the
     contrast of every label would depend on which image the matcher picked,
     which is not something that can be tested per card. */
  box-shadow: 0 6px 18px rgba(10, 25, 38, 0.38);
}

.journey--over { margin: 0; }

.journey--over .journey__dot { background: var(--journey-off-over); }
.journey--over .journey__step::before { background: var(--journey-off-over); }

.journey--over .journey__step.is-done .journey__dot,
.journey--over .journey__step.is-done::before,
.journey--over .journey__step.is-current::before {
  background: var(--journey-on-over);
}

/* White disc, dark gap, white ring — a bullseye that reads as "you are here"
   at a glance. The ring/gap colours swap from the on-white version because the
   surround is now dark; the SIZE difference is what carries the meaning either
   way, so this still is not colour alone. */
.journey--over .journey__step.is-current .journey__dot {
  background: var(--journey-on-over);
  border-color: var(--journey-plate);
  box-shadow: 0 0 0 3px var(--journey-on-over);
}

.journey--over .journey__label { color: rgba(255, 255, 255, 0.86); }

.journey--over .journey__step.is-current .journey__label {
  color: #ffffff;
  font-weight: 800;
}

/* The vertical flip below 30rem must NOT apply here: the path sits in a band
   across a card photo, and stacking it turns the band into a full-height
   column that swallows the picture entirely. It stays horizontal and the
   labels wrap instead; the hero uses min-height so the band grows rather than
   clipping them.

   Selectors are doubled (.journey.journey--over) deliberately. The base
   vertical rule lives in a LATER media block, so a single-class override here
   ties on specificity and loses on order — which is exactly what happened the
   first time, and it only showed up in a phone-width screenshot. Doubling the
   class makes this independent of where the blocks sit in the file. */
@media (max-width: 30rem) {
  .journey.journey--over {
    flex-direction: row;
    align-items: flex-start;
  }

  .journey.journey--over .journey__step {
    display: block;
    text-align: center;
    width: auto;
    flex: 1;
  }

  .journey.journey--over .journey__step::before {
    top: 9px;
    bottom: auto;
    left: -50%;
    right: 50%;
    width: auto;
    height: 4px;
  }

  .journey.journey--over .journey__dot { margin: 0 auto var(--space-2); }

  .journey.journey--over .journey__step.is-current .journey__dot {
    margin: -5px auto var(--space-2);
  }
}

/* Below 30rem the path turns vertical. Same markup, same classes. */
@media (max-width: 30rem) {
  .journey {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
  }

  .journey__step {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    text-align: start;
    width: 100%;
    flex: none;
  }

  .journey__step::before {
    top: auto;
    bottom: 100%;
    left: 9px;
    right: auto;
    width: 4px;
    height: var(--space-2);
  }

  .journey__dot { margin: 0; flex: none; }
  .journey__step.is-current .journey__dot { margin: 0 0 0 -5px; }
}

/* ---------- Stage strip: items that are NOT on the evidence ladder ----------
   Trials, news and preprints are not findings. They get no path, because a
   path would imply they sit somewhere on the evidence scale — and they don't.
   A tinted strip with a glyph, the stage name, and one plain line instead. */

.stage-note {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--color-surface);
  border-inline-start: 5px solid var(--color-accent);
  border-radius: 8px;
  padding: var(--space-2) var(--space-3);
}

.stage-note__glyph {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: 2px solid var(--color-accent);
  border-radius: 6px;
  font-weight: 800;
  color: var(--color-band);
}

.stage-note--info .stage-note__glyph {
  border-radius: 50%;
  font-family: Georgia, serif;
  font-style: italic;
}

.stage-note--unverified { border-inline-start-style: dashed; }

.stage-note__text strong {
  display: block;
  font-size: var(--text-base);
  color: var(--color-band);
}

.stage-note__text span {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

/* Over a card photo, same reasoning as .journey--over: a card whose indicator
   is a stage-note sits in the same grid, on the same kind of photo, and must
   be as readable and as prominent as its neighbours. */
.stage-note--over {
  background: none;          /* the plate behind it already provides the fill */
  border-radius: 0;
  padding: 0;
  border-inline-start-color: var(--journey-on-over);
}

.stage-note--over .stage-note__glyph {
  border-color: var(--journey-on-over);
  color: #ffffff;
}

.stage-note--over .stage-note__text strong { color: #ffffff; }
.stage-note--over .stage-note__text span { color: rgba(255, 255, 255, 0.86); }

/* ---------- Stage badge: pill + evidence dot-meter ----------
   ADMIN + style guide only since the journey handoff (2026-08-19). Reader
   pages use .journey / .stage-note above. Kept because the review queue lists
   many items densely and a compact pill triages better than four labelled
   stages. Trust is still read from filled marks + words, never colour alone.
     <span class="badge badge--result" role="img"
           aria-label="Tested in people. Evidence strength 4 of 4.">
       <span class="badge__meter" aria-hidden="true">…</span>
       <span class="badge__label">Tested in people</span>
     </span>
   Kinds: --result (meter) | --progress (→) | --info (i) | --unverified (dashed). */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  max-width: 100%;
  padding: 6px 14px;
  border: 2px solid var(--color-band);
  border-radius: 999px;
  background: #e9f3f6;
  color: var(--color-band);
  font-weight: 700;
  font-size: var(--text-base);
  line-height: 1.15;
}

.badge__label { white-space: normal; }

.badge__meter {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
}

.step {
  display: block;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1.5px solid var(--badge-empty);
}

.step--on {
  background: var(--badge-fill);
  border-color: var(--badge-fill);
}

.badge--unverified .step {
  border-style: dashed;
  background: transparent;
  border-color: var(--badge-empty);
}

.badge__glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 24px;
  height: 24px;
  border: 2px solid var(--badge-fill);
  border-radius: 50%;
  font-weight: 800;
}

.badge--progress .badge__glyph { border-radius: 6px; }

.badge--info .badge__glyph {
  font-family: Georgia, serif;
  font-style: italic;
}

/* ---------- Item page: short version + means block ---------- */

.original-title {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

/* Glossary term buttons (tooltip behavior arrives in WI-105). */
.term {
  background: none;
  border: none;
  padding: 0;
  min-block-size: 0;
  font: inherit;
  color: var(--color-accent);
  text-decoration: underline dotted;
  text-underline-offset: 0.15em;
  cursor: help;
}

.term:hover {
  background: none;
  color: var(--color-accent-strong);
}

/* The tooltip panel (WI-105) — a native popover: dismissible via Esc/light
   dismiss, focusable trigger, no JS. Deliberately uses the UA default
   position (centered mini-dialog): easier to find than a tiny anchored
   tooltip for readers with vision or attention problems. */
.term-definition {
  max-width: 28rem;
  padding: var(--space-4) var(--space-5);
  border: 2px solid var(--color-band);
  border-radius: var(--radius);
  background: var(--color-paper);
  color: var(--color-ink);
  box-shadow: var(--card-shadow);
}

/* Browsers without popover support show the definition inline after the
   term — degraded but readable, wrapped in parentheses for flow. */
@supports not selector(:popover-open) {
  .term-definition {
    display: inline;
    font-size: var(--text-sm);
    border: none;
    box-shadow: none;
    padding: 0;
  }

  .term-definition::before { content: " ("; }
  .term-definition::after { content: ")"; }
}

/* The anti-hype block — a calm, honest aside. */
.means-block {
  background: #eef6f8;
  border: 1px solid #d3e6ec;
  border-inline-start: 6px solid var(--color-accent);
  border-radius: var(--card-radius);
  padding: var(--space-5) var(--space-6);
  margin-block: var(--space-6);
}

.means-block__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-block-end: var(--space-3);
}

.means-block__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--color-accent);
  color: var(--color-band-ink);
  font-family: Georgia, serif;
  font-style: italic;
  font-weight: 700;
}

.means-block h2 {
  margin: 0;
  font-size: var(--text-xl);
}

/* A trial's live status (WI-402). Read from the trial registry at page load,
   not from the summary — trials close, and a stale "enrolling" is a wasted
   phone call for someone who is already exhausted. The closed variant is
   deliberately louder than the open one. */
.trial-status {
  background: var(--color-surface);
  border: 1px solid var(--color-border-subtle);
  border-inline-start: 6px solid var(--color-accent);
  border-radius: var(--card-radius);
  padding: var(--space-4) var(--space-5);
  margin-block: var(--space-5);
}

.trial-status p {
  margin: 0;
}

.trial-status p + p {
  margin-block-start: var(--space-2);
}

.trial-status--closed {
  background: var(--color-notice);
  border-color: var(--color-notice-border);
  border-inline-start-color: var(--color-notice-edge);
}

.trial-status__checked {
  font-size: var(--text-base);
  color: var(--color-ink-muted);
}

/* ---------- Trial finder (WI-403) ---------- */

.trial-near {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-block: var(--space-4) var(--space-5);
}

/* Same treatment as the feed filters: full-width stacked blocks so the ZIP
   field and its buttons never end up sharing a cramped row. This is the form a
   reader fills in one-handed, on a phone, to find a trial near them. */
@media (max-width: 40rem) {
  .trial-near {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-3);
  }

  .trial-near input[type="text"],
  .trial-near button,
  .trial-near .button,
  .trial-near .button-secondary {
    inline-size: 100%;
    min-block-size: var(--tap-target);
  }
}

.button-secondary {
  background: var(--color-paper);
  color: var(--color-accent);
  border: 2px solid var(--color-accent);
}

.button-secondary:hover {
  background: var(--color-surface);
  color: var(--color-accent-strong);
}

.trial-note {
  color: var(--color-ink-muted);
}

.trial-list {
  list-style: none;
  padding: 0;
  margin-block: var(--space-4);
  max-width: none;
}

.trial-list__item {
  border-bottom: 1px solid var(--color-border-subtle);
  padding-block: var(--space-4);
}

.trial-list__item h3,
.trial-list__item h4 {
  margin-block: 0 var(--space-2);
  font-size: var(--text-lg);
}

.trial-list__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  color: var(--color-ink-muted);
  font-size: var(--text-base);
  margin-block-end: var(--space-2);
}

.trial-facts dt {
  font-weight: 700;
  margin-block-start: var(--space-3);
}

.trial-facts dd {
  margin-inline-start: 0;
}

.trial-sites,
.trial-sites ul {
  list-style: none;
  padding-inline-start: 0;
}

.trial-sites ul {
  margin-block: var(--space-1) var(--space-3);
  padding-inline-start: var(--space-4);
  color: var(--color-ink-muted);
}

/* The old trials-only .pager (display:flex, two links side by side) lived here
   and, being later in the file, silently overrode the shared pager above — it
   turned the whole control into a flex ROW, squeezing "Page 8 of 16" into a
   column three lines tall. Removed with WI-438; the shared rule is the only
   one now. Kept as a note because a duplicate class name in a 1,500-line
   stylesheet is not something the next person will think to look for. */

.breadcrumb {
  margin-block-end: var(--space-4);
}

.checkbox {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* The whole label is the target, not just the box, so the row is comfortably
     tappable even where the box itself is small. */
  min-block-size: var(--tap-target);
}

/* A default checkbox renders about 13px square — a third of the 44px floor, and
   the hardest thing on the page to hit for someone whose treatment has affected
   their fine motor control. Scaling the control keeps the native widget (and
   its focus ring, its checked state, and its behaviour with assistive tech)
   rather than replacing it with a styled div that only looks like one. */
.checkbox input[type="checkbox"] {
  inline-size: 1.375rem;
  block-size: 1.375rem;
  flex: none;
  accent-color: var(--color-accent);
}

/* Filter bars (/research, /trials, /search). Without a layout rule these are
   plain inline flow, so the submit button lands wherever the previous control
   happens to end — on /research it wrapped alone onto its own line while the
   long "show early-stage research" sentence sat up in the control row.
   One row of controls ending in the button, and any long checkbox on its own
   row beneath: the toggle changes WHICH items appear, so it reads better as a
   statement under the controls than as another control among them. */
.feed-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin-block-end: var(--space-5);
}

/* A full-width basis is what puts it on its own row; it comes after the button
   in the markup too, so what a keyboard tabs through matches what the eye
   reads. */
.feed-filters .checkbox {
  flex-basis: 100%;
}

/* On a phone the wrapped row separated labels from their controls: "Kind" and
   its select landed on one line while "Sort by" was pushed to the end of it and
   its select dropped to the next — so the page read "Kind [Everything] Sort by"
   then "[Newest first]". A label beside the wrong control is worse than no
   label, and this is a form a reader uses to find the thing that is about them.

   Below 40rem each label+control becomes its own full-width block. Grid rather
   than more flex-wrapping, so pairing is structural and cannot come apart at
   some width nobody tested. */
@media (max-width: 40rem) {
  .feed-filters {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-3);
    align-items: stretch;
  }

  .feed-filters label:not(.checkbox) {
    margin-block-end: calc(-1 * var(--space-2));
    font-weight: 700;
  }

  .feed-filters select,
  .feed-filters input[type="text"],
  .feed-filters input[type="search"],
  .feed-filters button {
    inline-size: 100%;
    min-block-size: var(--tap-target);
  }
}

/* The registry's own words, visibly not ours. */
.registry-text {
  margin-inline: 0;
  padding-inline-start: var(--space-4);
  border-inline-start: 4px solid var(--color-border-subtle);
}

.registry-text footer {
  color: var(--color-ink-muted);
  font-size: var(--text-base);
}

.provenance {
  font-size: var(--text-base);
  color: var(--color-ink-muted);
  border-top: 1px solid var(--color-border-subtle);
  padding-block-start: var(--space-4);
  margin-block-start: var(--space-6);
}

/* AI-transparency line — a deliberate trust cue, not fine print. */
.ai-note {
  border-inline-start: 3px solid var(--color-accent);
  padding-inline-start: var(--space-3);
}

/* Item-page header: badge above the plain-language headline (WI-306). */
.item-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-block-end: var(--space-5);
}

.item-header h1 { margin: 0; }

/* The one-sentence hook, given a little more presence than body text. */
.hook {
  font-size: var(--text-lg);
  line-height: var(--leading);
}

/* Report-a-problem — quiet by default, one tap to open. */
.report-problem {
  margin-block-start: var(--space-4);
}

.report-problem summary {
  cursor: pointer;
  color: var(--color-accent);
  text-decoration: underline;
  min-block-size: var(--tap-target);
  display: inline-flex;
  align-items: center;
}

.report-problem textarea { width: 100%; }

/* Bulk approve (WI-426). Admin-only. Bordered rather than loud: it publishes
   real pages, so it should read as a considered action, not a convenience. */
.bulk-approve {
  border: 1px solid var(--color-border);
  border-radius: var(--card-radius);
  padding: var(--space-4) var(--space-5);
  margin-block: var(--space-5);
}

.bulk-approve p { margin-block: 0 var(--space-3); }
.bulk-approve p.text-muted { margin-block: var(--space-3) 0; font-size: var(--text-sm); }

/* Why an item was flagged, in the queue (WI-418). Admin-only, so this is
   plainer than the reader-facing surfaces — the job is to be scannable down a
   column of 20 items, not calm. */
.review-flags p { margin-block: 0; }

.review-flags__list {
  margin-block: var(--space-2);
  padding-inline-start: var(--space-5);
}

.review-flags__list li { margin-block-end: var(--space-1); }

.review-flags__note {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  margin-block-start: var(--space-2) !important;
}

/* Reader-reported live pages, at the top of the admin queue (WI-306). */
.reported-section {
  border: 1px solid var(--color-border);
  border-inline-start: 6px solid #b23c17;
  border-radius: var(--card-radius);
  padding: var(--space-4) var(--space-5);
  margin-block-end: var(--space-6);
}

/* ---------- Dev style guide (WI-109; /dev/styleguide, dev-only) ---------- */

.styleguide-badges {
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: 0;
  max-width: none;
}

.styleguide-badges li {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-block-end: var(--space-3);
}

/* ---------- Disclaimers (WI-107) ---------- */

.disclaimer {
  background: var(--color-surface);
  border-inline-start: 6px solid var(--color-ink-muted);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  margin-block: var(--space-5);
}

.disclaimer p:last-child { margin-block-end: 0; }

/* ---------- Suggestions box (home, 2026-08-15) ----------

   Quieter than the AI notice on purpose: it sits next to it at the foot of the
   page, and two loud panels in a row means neither is read. The surface fill is
   enough to mark it as its own thing. */
.suggest {
  background: var(--color-surface);
  border-radius: var(--card-radius);
  padding: var(--space-5) var(--space-6);
  margin-block-start: var(--space-7);
}

.suggest h2 {
  margin-block: 0 var(--space-2);
  font-size: var(--text-lg);
}

.suggest p { margin-block-end: var(--space-2); }
.suggest p:last-child { margin-block-end: 0; }

/* The "this is not how you get help" line. Muted, but not small: it is the
   part that stops a frightened reader emailing a suggestions box and waiting. */
.suggest__not {
  color: var(--color-ink-muted);
}

.footer-suggest {
  margin-block: var(--space-2) 0;
}

/* ---------- AI notice (homepage handoff; was .ai-caution, WI-422) ----------

   Moved to the foot of the page: it stays honest and findable without standing
   between the reader and the content. The admission itself has not been
   demoted — one plain sentence now leads inside the hero band
   (.hero-band__disclosure), so nobody can read a summary before learning AI
   wrote it. This is the fuller version, and the last thing before the footer. */
.ai-notice {
  background: var(--color-caution);
  border: 1px solid var(--color-caution-border);
  border-inline-start: 6px solid var(--color-caution-edge);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  margin-block: var(--space-7) var(--space-5);
}

.ai-notice h2 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-lg);
}

.ai-notice p {
  margin: 0;
}

/* ---------- Digest signup ---------- */

.digest-signup {
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--card-radius);
  padding: var(--space-5) var(--space-6);
  background: var(--card-bg);
  box-shadow: var(--card-shadow);
}

.digest-signup form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-start: var(--space-3);
}

.digest-signup input[type="email"] {
  flex: 1 1 16rem;
}

/* ---------- Footer ---------- */

.site-footer {
  border-top: 1px solid var(--color-border-subtle);
  padding-block: var(--space-5);
  color: var(--color-ink-muted);
}

.site-footer ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  list-style: none;
  margin: 0 0 var(--space-3);
  padding: 0;
  max-width: none;
}

.site-footer a {
  color: var(--color-ink-muted);
  text-decoration: underline;
  display: inline-flex;
  align-items: center;
  min-block-size: var(--tap-target);
}

/* ---------- Readiness score (WI-305/306) ---------- */
/* How close a finding is to everyday care, 1-10. Meaning is carried by the
   number, the label, and a filled bar — never color alone (WCAG). */

.readiness {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.readiness__bar {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  flex: none;
}

.readiness__step {
  display: block;
  width: 9px;
  height: 14px;
  border-radius: 2px;
  border: 1.5px solid var(--badge-empty);
}

.readiness__step--on {
  background: var(--badge-fill);
  border-color: var(--badge-fill);
}

.readiness__text { line-height: 1.15; }

/* The item-page readiness callout (.readiness-callout) was removed by the
   journey handoff, 2026-08-19: the item page now answers "how far along is
   this research?" once, with the large journey path, instead of asking the
   reader to reconcile a 4-step badge and a 1-10 bar that measured different
   things. The badge + bar above remain for the admin queue only — as does
   .readiness-reason, which the review row still renders. */

.readiness-reason { color: var(--color-ink-muted); }

/* ---------- Review queue v1 (WI-305) ---------- */

.review-card:focus-visible {
  outline: var(--focus-ring) solid var(--color-focus);
  outline-offset: 3px;
}

.review-card__badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  margin-block-end: var(--space-3);
}

/* Summary and source side by side, so the reviewer judges the real output. */
.review-compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5);
}

@media (max-width: 48rem) {
  .review-compare { grid-template-columns: 1fr; }
}

.review-compare__col { min-width: 0; }

.review-compare__heading {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-ink-muted);
  margin-block-end: var(--space-2);
}

.review-compare__source {
  padding-inline-start: var(--space-5);
  border-inline-start: 1px solid var(--color-border-subtle);
}

@media (max-width: 48rem) {
  .review-compare__source {
    padding-inline-start: 0;
    border-inline-start: none;
    padding-block-start: var(--space-4);
    border-block-start: 1px solid var(--color-border-subtle);
  }
}

.review-edit {
  margin-block: var(--space-4);
  padding: var(--space-3);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius);
}

.review-edit__grid {
  display: grid;
  gap: var(--space-2);
  margin-block-start: var(--space-3);
}

.review-edit__grid input,
.review-edit__grid textarea {
  width: 100%;
}

.review-actions {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.review-actions kbd {
  font-size: var(--text-sm);
  padding: 0 0.4em;
  border: 1px solid currentColor;
  border-radius: 4px;
  opacity: 0.8;
}

/* ---------- Motion ---------- */

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