:root {
  /* Portal width. Wide enough for a lead story plus a rail, narrow enough that
     headlines do not run to unreadable line lengths on a large monitor. */
  --wide: 78rem;
  --bg: #faf9f6;
  --surface: #ffffff;
  --text: #1a1a1a;
  --muted: #6b6b6b;
  --border: #e3e0da;
  --accent: #0f62fe;
  --warn-bg: #fff4e0;
  --warn-text: #7a4d00;
  --dev-bg: #e5f0ff;
  --dev-text: #0043ce;
  --lean-left: #c0392b;
  --lean-center-left: #e08283;
  --lean-center: #95a5a6;
  --lean-center-right: #7fb3d5;
  --lean-right: #2e6da4;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #141414;
    --surface: #1e1e1e;
    --text: #eaeaea;
    --muted: #9a9a9a;
    --border: #2e2e2e;
    --accent: #78a9ff;
    --warn-bg: #3a2c10;
    --warn-text: #f0c674;
    --dev-bg: #16283f;
    --dev-text: #9ec4ff;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 17px/1.6 Georgia, "Times New Roman", serif;
  /* Compiled copy contains bare URLs and hyphenated agency strings that have
     no break opportunity; without this a single token scrolls a phone
     sideways. Applied globally because every surface renders that text. */
  overflow-wrap: break-word;
}

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

.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;
}

/* --- masthead ------------------------------------------------------------- */
/* Editions are the site's primary axis, so they get a full-width bar under the
   nameplate rather than a corner of the header. */

/* Deliberately not sticky. With three nav rows it stands ~9rem tall, which
   would sit on a fifth of a laptop viewport permanently, and it overlaid
   anything scrolled beneath it: clicks landed on the header instead of the
   control under it. The nav is content at the top of the page, not chrome
   that follows you down it. */
.masthead {
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

/* Row one: date, nameplate, edition switch. Deliberately short; the nameplate
   is an anchor, not a billboard, and the height it saves goes to the nav. */
.masthead-bar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1rem;
  max-width: var(--wide);
  margin: 0 auto;
  padding: 0.5rem 1.25rem;
}

.brand {
  font-weight: 700;
  font-size: 1.3rem;
  color: var(--text);
  letter-spacing: -0.035em;
  text-align: center;
  white-space: nowrap;
}
.brand:hover { text-decoration: none; color: var(--accent); }

.masthead-date {
  font-family: system-ui, sans-serif;
  font-size: 0.7rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}

/* Balances the date on the left so the nameplate stays optically centred. */
.masthead-spacer { display: block; }

/* --- the real navigation -------------------------------------------------- */
/* Regions, then countries, then topics, generated from what the edition
   actually carries. Centred, high-contrast and tightly led: it should read as
   the site's spine without taking the vertical space to say so. */

.topnav {
  border-top: 1px solid var(--border);
  padding: 0.35rem 1.25rem 0.5rem;
  /* Narrower than the content grid on purpose. Run across the full 78rem and
     the rows become a thin band of text spanning the whole screen, which reads
     as a run-on line rather than a navigation block. */
  max-width: 52rem;
  margin: 0 auto;
  font-family: system-ui, sans-serif;
}

.topnav-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.9rem;
  padding: 0.15rem 0;
}

.topnav-label {
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.11em;
  color: var(--muted);
  opacity: 0.75;
  /* Fixed width so the three rows align into a column despite different
     label lengths. */
  flex: none;
  min-width: 4.75rem;
  text-align: right;
}

/* Justified like a paragraph: inline items, so the inter-word spaces stretch
   and every line sits flush to both edges. A flexbox cannot do this, since its
   gaps are fixed.
   text-align-last matters as much as text-align here: these rows usually fit
   on one line, and a single line counts as the last line, so with anything
   else they would never justify at all. Narrow screens override it below,
   where rows do wrap and a two-item final line would be flung apart. */
.topnav-row ul {
  /* min-width:0 is load-bearing. A flex item defaults to min-width:auto, so
     without it this refuses to shrink below its longest entry ("Central
     America & Caribbean") and pushes the row off the side of the screen. */
  flex: 1 1 0;
  min-width: 0;
  display: block;
  text-align: justify;
  text-align-last: justify;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* inline-BLOCK, not inline. Justification stretches every space on the line,
   including the ones inside a label, so "United States" and "United Kingdom"
   were pulled as far apart as two separate entries and read as four links
   rather than two. An inline-block is atomic: the parent can only justify
   around it. */
.topnav-row li {
  display: inline-block;
  /* A floor under the gap, since justification only ever adds to it. */
  padding: 0 0.28rem;
}

/* Full-contrast text at a small size: presence from weight and colour rather
   than from scale, which is what keeps the bar short. */
.topnav a {
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--text);
  white-space: nowrap;
  border-bottom: 1.5px solid transparent;
  padding-bottom: 1px;
}
.topnav a:hover { color: var(--accent); border-bottom-color: var(--accent); text-decoration: none; }
.topnav .is-active { color: var(--accent); font-weight: 700; border-bottom-color: var(--accent); }

/* Reads as an affordance rather than another facet, so it does not compete
   with the real entries beside it. */
.topnav-more { color: var(--muted) !important; font-style: italic; }
.topnav-more:hover { color: var(--accent) !important; }

@media (max-width: 48rem) {
  .masthead-bar { grid-template-columns: 1fr; }
  .masthead-spacer { display: none; }
  /* The date goes, the language switch stays: one is decoration on a phone,
     the other is the only global control on the site. */
  .masthead-date { display: none; }
  .masthead-left { align-items: center; }
  .topnav-row { justify-content: flex-start; }
  .topnav-label { min-width: 100%; text-align: left; }
}

/* Deliberately a narrower breakpoint than the label stacking above. At tablet
   widths the rows still fit on one line and should justify; only down here do
   they wrap far enough that the final line holds one or two entries, where
   justifying would fling them to opposite edges of the screen. */
@media (max-width: 40rem) {
  .topnav-row ul { text-align-last: center; }
}

/* --- view switcher -------------------------------------------------------- */

.viewnav {
  font-family: system-ui, sans-serif;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--border);
}
.viewnav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 1.4rem;
  list-style: none;
  margin: 0;
  padding: 0 0 0.55rem;
}
.viewnav a {
  font-size: 0.9rem;
  color: var(--muted);
  font-weight: 500;
}
.viewnav a:hover { color: var(--text); text-decoration: none; }
.viewnav .is-active { color: var(--text); font-weight: 700; }

/* --- layout --------------------------------------------------------------- */
/* Two containers, deliberately. Indexes span the grid; article bodies keep a
   ~70-character measure, because long-form text at portal width is unreadable. */

main { margin: 0 auto; padding: 1.5rem 1.25rem 3rem; }
main.wide { max-width: var(--wide); }
main.narrow { max-width: 46rem; }

.portal {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 19rem;
  gap: 2.5rem;
  align-items: start;
}

@media (max-width: 60rem) {
  .portal { grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
  .masthead-top { grid-template-columns: 1fr; text-align: center; }
  .masthead-date, .masthead-aside { display: none; }
}

.edition-stamp {
  font-family: system-ui, sans-serif;
  font-size: 0.78rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  margin: 0 0 1.25rem;
}

.edition-title { font-size: 1.5rem; margin: 0.5rem 0 1.5rem; }
.edition-date { color: var(--muted); font-weight: 400; font-size: 1.1rem; }

/* --- the lead story ------------------------------------------------------- */

.lead {
  border-bottom: 1px solid var(--border);
  padding-bottom: 1.5rem;
  margin-bottom: 1.75rem;
}
.lead h2 {
  font-size: clamp(1.7rem, 3.4vw, 2.4rem);
  line-height: 1.15;
  letter-spacing: -0.02em;
  margin: 0 0 0.6rem;
}
.lead h2 a { color: var(--text); }
.lead-excerpt { font-size: 1.1rem; color: var(--muted); margin: 0 0 0.9rem; }

/* --- cards ---------------------------------------------------------------- */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 1rem;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 1rem 1.25rem;
  /* Inside a grid the gap spaces them; the margin is only for the stacked
     (search results, facet) case. */
  margin-bottom: 0;
  display: flex;
  flex-direction: column;
}
.grid .card { height: 100%; }
.cards:not(.grid) .card { margin-bottom: 1rem; }

.card:hover { border-color: var(--accent); }
.card h2 { margin: 0 0 0.5rem; font-size: 1.1rem; line-height: 1.3; }
.card h2 a { color: var(--text); }
.excerpt { margin: 0 0 0.75rem; color: var(--muted); font-size: 0.95rem; }
/* Push the chips to the bottom so cards of unequal text still line up. */
.card .tags { margin-top: auto; padding-top: 0.6rem; }

/* --- the rail ------------------------------------------------------------- */

.rail {
  border-top: 2px solid var(--text);
  padding-top: 0.6rem;
  margin-bottom: 2rem;
  font-family: system-ui, sans-serif;
}
.rail-heading {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 0 0 0.75rem;
}
.rail-list { list-style: none; padding: 0; margin: 0; counter-reset: rail; }
.rail-list li {
  counter-increment: rail;
  display: grid;
  grid-template-columns: 1.4rem 1fr;
  gap: 0.5rem;
  padding: 0.5rem 0;
  border-top: 1px solid var(--border);
  font-size: 0.9rem;
  line-height: 1.35;
}
.rail-list li:first-child { border-top: 0; }
.rail-list li::before {
  content: counter(rail);
  color: var(--muted);
  font-weight: 700;
  font-size: 0.85rem;
}
/* Both pinned to the text column. The counter is a ::before, so it is itself a
   grid item: without this the meta line auto-places into the 1.4rem counter
   column on row two and wraps after the first word. */
.rail-list a { grid-column: 2; color: var(--text); }
.rail-meta {
  grid-column: 2;
  display: block;
  color: var(--muted);
  font-size: 0.75rem;
  margin-top: 0.15rem;
}
.rail-more { font-size: 0.8rem; margin: 0.75rem 0 0; }

.rail-tags { list-style: none; padding: 0; margin: 0; }
.rail-tags li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.3rem 0;
}
.rail-tags .rail-meta { margin: 0; }

.meta { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.6rem; }

.badge {
  font: 600 0.72rem/1 system-ui, sans-serif;
  padding: 0.3rem 0.55rem;
  border-radius: 999px;
  background: var(--border);
  color: var(--muted);
}

.badge-dev { background: var(--dev-bg); color: var(--dev-text); }
.badge-warn { background: var(--warn-bg); color: var(--warn-text); }

/* --- provenance bar ------------------------------------------------------- */
/* Country groups, separated by a gap; lean shown only inside a group, where it
   is comparable. Hatching marks state-linked sources, using pattern rather
   than colour because colour is already spent on lean and pattern survives
   colour-blindness. */

.provenance { margin-top: 0.4rem; }

.provbar {
  display: flex;
  gap: 3px;
  height: 7px;
  margin-bottom: 0.3rem;
}

.provbar-group {
  display: flex;
  min-width: 4px;
  border-radius: 3px;
  overflow: hidden;
}
.provbar-group > span { display: block; flex: 1 1 0; min-width: 2px; }

/* Diagonal overlay on top of whatever lean colour the segment already has. */
.provbar-group > span.is-state {
  background-image: repeating-linear-gradient(
    45deg,
    rgba(255, 255, 255, 0.55) 0 2px,
    rgba(255, 255, 255, 0) 2px 4px
  );
}

.provnote {
  font-family: system-ui, sans-serif;
  font-size: 0.72rem;
  color: var(--muted);
  margin: 0;
}
.prov-flag { color: var(--warn-text); font-weight: 600; }
.prov-warn { margin-top: 0.4rem; font-size: 0.78rem; }

/* The note, and on a story page the share control, on one line. The disclosure
   takes the remaining width rather than its own: without that the panel it
   opens inline, for a reader with no JavaScript, would be squeezed to the
   width of the summary text instead of getting the full measure. */
/* flex-start, not baseline: the summary is an inline-block, and an
   inline-block hands flexbox the baseline of its LAST line, so on a card whose
   note wraps to two lines the button dropped to the second one. The button's
   negative top margin cancels its own padding, which lands its label exactly
   on the note's first line. */
.provfoot {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}
.provfoot > .provdetail { flex: 1 1 auto; min-width: 0; }

/* Quiet by default and the same size as the note it sits beside: sharing is
   something a reader goes looking for, not something to interrupt them with. */
.sharebtn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  flex: none;
  font-family: system-ui, sans-serif;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  background: none;
  border: 0;
  cursor: pointer;
  /* Padded out to a thumb-sized target, then pulled back by the same amount so
     the label still lines up with the right edge of the bar above it. */
  padding: 0.35rem 0.4rem;
  margin: -0.35rem -0.4rem -0.35rem 0;
}
.sharebtn[hidden] { display: none; }
.sharebtn:hover { color: var(--accent); }
.sharebtn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: 4px;
}
.sharebtn.is-done { color: var(--accent); }
.sharebtn-icon { width: 0.85rem; height: 0.85rem; flex: none; }

.lean-left { background: var(--lean-left); }
.lean-center-left { background: var(--lean-center-left); }
.lean-center { background: var(--lean-center); }
.lean-center-right { background: var(--lean-center-right); }
.lean-right { background: var(--lean-right); }

.story h1 { font-size: 1.7rem; line-height: 1.25; margin: 0.75rem 0 0.25rem; }
.story-meta { color: var(--muted); font-family: system-ui, sans-serif; font-size: 0.85rem; }

.dev-banner {
  background: var(--dev-bg);
  color: var(--dev-text);
  font-family: system-ui, sans-serif;
  font-size: 0.85rem;
  padding: 0.6rem 0.9rem;
  border-radius: 6px;
  margin-top: 1rem;
}
.dev-banner a { color: inherit; text-decoration: underline; }

.warn-note {
  background: var(--warn-bg);
  color: var(--warn-text);
  font-family: system-ui, sans-serif;
  font-size: 0.85rem;
  padding: 0.6rem 0.9rem;
  border-radius: 6px;
}

.body { margin-top: 1.25rem; }

.breakdown, .sources { margin-top: 2rem; border-top: 1px solid var(--border); padding-top: 1rem; }
.breakdown h2, .sources h2 { font-size: 1rem; font-family: system-ui, sans-serif; }

.breakdown dl { margin: 0; }
.breakdown dt { margin-top: 0.6rem; }
.breakdown dd { margin: 0.15rem 0 0; }

.lean-label {
  font: 600 0.7rem/1 system-ui, sans-serif;
  color: #fff;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  display: inline-block;
}

.sources ul { list-style: none; padding: 0; }
.sources li { margin-bottom: 0.5rem; }

.score-note, .empty { color: var(--muted); font-family: system-ui, sans-serif; font-size: 0.85rem; }

/* --- about ---------------------------------------------------------------- */

.about h2 { font-size: 1.25rem; margin: 2.25rem 0 0.5rem; }
.about h3 { font-size: 1rem; margin: 1.5rem 0 0.25rem; }
.about-lede { font-size: 1.15rem; color: var(--muted); margin-bottom: 2rem; }

.about-steps { padding-left: 1.2rem; }
.about-steps li { margin-bottom: 0.6rem; }

.about-limits { list-style: none; padding: 0; }
.about-limits li {
  border-left: 3px solid var(--border);
  padding: 0.15rem 0 0.15rem 0.9rem;
  margin-bottom: 0.8rem;
}

.about-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem;
  margin: 1rem 0 0;
  font-family: system-ui, sans-serif;
}
.about-stats dt {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.about-stats dd { margin: 0.15rem 0 0; font-size: 1.6rem; font-weight: 700; }

/* --- when a story published ------------------------------------------------ */

/* Uppercase and letterspaced like the edition stamp at the top of the index,
   because they say the same kind of thing: on this site that treatment means
   a time and nothing else. A step quieter than the provenance note above it,
   so the bar still takes the eye first. */
.card-when {
  font-family: system-ui, sans-serif;
  font-size: 0.7rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  margin: 0.55rem 0 0;
}

/* --- facet chips ---------------------------------------------------------- */

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  list-style: none;
  margin: 0.6rem 0 0;
  padding: 0;
}

.tag {
  display: inline-block;
  font: 500 0.72rem/1 system-ui, sans-serif;
  padding: 0.3rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
}

.tag:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
/* Subject is the chip a reader scans for first, so it carries the only fill. */
.tag-subject { background: var(--border); }
.tag-scope { border-style: dashed; }

/* --- client-side filter (search.html) ------------------------------------ */
/* The form ships hidden and search.js reveals it, so a reader without
   JavaScript never sees controls that cannot work. */

.filters {
  font-family: system-ui, sans-serif;
  font-size: 0.9rem;
  margin-bottom: 1.5rem;
}

#q {
  width: 100%;
  font: inherit;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
}
#q:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: center;
  margin-top: 0.75rem;
}

/* --- time range ----------------------------------------------------------- */

.window-control {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.75rem;
}
.window-label {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-right: 0.2rem;
}

/* Groups stack full-width. Side by side they cramped a wrapping chip cloud
   into three narrow columns. */
.filter-groups {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.filter-group {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  overflow: hidden;
}

.filter-group summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.85rem;
  cursor: pointer;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  user-select: none;
  /* Both properties are needed to drop the native triangle across engines. */
  list-style: none;
}
.filter-group summary::-webkit-details-marker { display: none; }
.filter-group summary:hover { color: var(--text); }
.filter-group[open] summary { color: var(--text); }

/* Chevron, drawn rather than an image so it inherits colour and needs no asset. */
.filter-group summary::before {
  content: "";
  width: 0.4rem;
  height: 0.4rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
  flex: none;
}
.filter-group[open] summary::before { transform: rotate(45deg); }

.filter-tally { color: var(--accent); font-weight: 700; }

.filter-options {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  padding: 0.15rem 0.85rem 0.85rem;
  /* Countries runs to dozens of entries, so cap and scroll rather than push
     the results off the page. */
  max-height: 13.5rem;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
.filter-options::-webkit-scrollbar { width: 8px; }
.filter-options::-webkit-scrollbar-track { background: transparent; }
.filter-options::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 999px;
}
.filter-options::-webkit-scrollbar-thumb:hover { background: var(--muted); }

/* The checkbox stays real (keyboard, form semantics, :checked drives the
   styling) but is taken out of the paint; the span beside it is the chip. */
.filter-chip { position: relative; display: inline-block; cursor: pointer; }
.filter-chip input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}

.chip-body {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font: 500 0.78rem/1 system-ui, sans-serif;
  padding: 0.4rem 0.65rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  color: var(--text);
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.filter-chip:hover .chip-body { border-color: var(--accent); color: var(--accent); }
.filter-chip input:checked + .chip-body {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.filter-chip input:focus-visible + .chip-body {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.chip-count {
  font-size: 0.68rem;
  opacity: 0.6;
  font-variant-numeric: tabular-nums;
}
.filter-chip input:checked + .chip-body .chip-count { opacity: 0.85; }

/* --- active filter pills -------------------------------------------------- */
/* Sits between the controls and the results, so what is narrowing the list is
   visible (and removable) even when its own group is collapsed. */

.active-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 1.25rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border);
}
/* An author `display` beats the UA stylesheet's rule for [hidden], so without
   this the empty bar keeps its border and padding when nothing is filtered. */
.active-filters[hidden] { display: none; }

.active-label {
  font-family: system-ui, sans-serif;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-right: 0.2rem;
}

.active-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font: 500 0.78rem/1 system-ui, sans-serif;
  padding: 0.4rem 0.5rem 0.4rem 0.65rem;
  border: 1px solid var(--accent);
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}
.active-pill:hover { filter: brightness(1.1); }
.active-pill:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }

.pill-x {
  font-size: 0.95rem;
  line-height: 1;
  opacity: 0.75;
  /* Optical centring: the glyph sits high in its box. */
  margin-top: -1px;
}
.active-pill:hover .pill-x { opacity: 1; }

/* A chip that would return nothing given the other active filters. Dimmed and
   disabled rather than removed: a chip vanishing and reappearing as you filter
   is far more disorienting than one that greys out in place. */
.filter-chip.is-empty { cursor: default; }
.filter-chip.is-empty .chip-body {
  opacity: 0.35;
  border-style: dashed;
}
.filter-chip.is-empty:hover .chip-body {
  border-color: var(--border);
  color: var(--text);
}

.filter-controls select {
  font: inherit;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.25rem 0.4rem;
}

.linkish {
  font: inherit;
  background: none;
  border: 0;
  padding: 0;
  color: var(--accent);
  cursor: pointer;
}
.linkish:hover { text-decoration: underline; }

.result-count { margin-left: auto; color: var(--muted); font-size: 0.8rem; }

.facet-note {
  color: var(--muted);
  font-family: system-ui, sans-serif;
  font-size: 0.85rem;
  margin-top: -0.75rem;
  margin-bottom: 1.5rem;
}

.edition-group { margin-bottom: 1.5rem; }
.edition-group h2 { font-size: 1.05rem; font-family: system-ui, sans-serif; }
.edition-group ul { list-style: none; padding: 0; }
.edition-group li { margin-bottom: 0.4rem; }

.site-footer {
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-family: system-ui, sans-serif;
  font-size: 0.8rem;
  padding: 2rem 1.25rem;
  text-align: center;
  background: var(--surface);
  margin-top: 3rem;
}
.footer-note { max-width: 34rem; margin: 0 auto 0.75rem; }
.footer-links a { margin: 0 0.6rem; color: var(--muted); }

/* --- newsletter ----------------------------------------------------------- */
/* Rendered only when NEWSLETTER_ACTION is set; a plain POST to Mailchimp, which
   is all a site of static files can do without a backend. */

.newsletter {
  max-width: 30rem;
  margin: 0 auto 2rem;
  padding-bottom: 2rem;
  border-bottom: 1px solid var(--border);
}
.newsletter h2 {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text);
  margin: 0 0 0.4rem;
}
.newsletter p { margin: 0 0 0.9rem; }

/* Wraps rather than overflowing. The submit label is a translated string and
   runs half again as long in Spanish as in English, which a fixed single row
   cannot hold at 320px. `min-width: 0` is what actually lets the input shrink:
   an input carries an intrinsic width that `flex: 1` alone will not override. */
.newsletter form { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.newsletter input[type="email"] {
  flex: 1 1 12rem;
  min-width: 0;
  font: inherit;
  font-size: 0.9rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  color: var(--text);
}
.newsletter input[type="email"]:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.newsletter button {
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  padding: 0.55rem 1.1rem;
  border: 0;
  border-radius: 6px;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}
.newsletter button:hover { filter: brightness(1.08); }

/* Mailchimp's honeypot: must exist and stay empty, so it is hidden from sight
   rather than display:none, which some bots detect and skip.
   Clipped rather than Mailchimp's own `left: -5000px`, which extends the
   document's scrollable width and gives every page a horizontal scrollbar. */
.mc-honeypot {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.source-meta {
  display: block;
  font-family: system-ui, sans-serif;
  font-size: 0.72rem;
  color: var(--muted);
  margin-top: 0.1rem;
}

/* --- 404 ------------------------------------------------------------------ */

.notfound-code {
  font: 700 3.5rem/1 system-ui, sans-serif;
  color: var(--border);
  letter-spacing: -0.04em;
  margin: 0 0 0.25rem;
}
.notfound h1 { margin-top: 0; }
.notfound-links { list-style: none; padding: 0; }
.notfound-links li {
  border-top: 1px solid var(--border);
  padding: 0.6rem 0;
}
.notfound-links li:last-child { border-bottom: 1px solid var(--border); }

/* --- language switch ------------------------------------------------------ */
/* Opposite the date, because it is the only global choice on the site: the
   nav below filters one shared pool, this changes what that pool reads as. */

/* Under the date, top left: the reader's first decision, before they read
   anything. Everything else in the masthead filters one shared pool; this is
   the only control that changes what the pool reads as. */
.masthead-left {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.2rem;
}

.langswitch {
  display: flex;
  gap: 0.2rem;
  font-family: system-ui, sans-serif;
  font-size: 0.7rem;
}
.langswitch a {
  color: var(--muted);
  font-weight: 600;
  letter-spacing: 0.06em;
  padding: 0.2rem 0.45rem;
  border-radius: 4px;
}
.langswitch a:hover { color: var(--text); background: var(--border); text-decoration: none; }
.langswitch .is-current { color: var(--bg); background: var(--text); }

/* --- provenance legend ---------------------------------------------------- */
/* The bar encodes country, lean and state linkage at once. A tooltip covers
   that on a mouse; this covers it on a phone, and for anyone who never hovers. */

/* The disclosure: a plain <details> without JavaScript, a modal with it.
   Both states show the same thing, so the enhancement can fail safely. */

.provdetail { margin: 0; font-family: system-ui, sans-serif; }
.provdetail > summary {
  cursor: pointer;
  list-style: none;
  display: inline-block;
  border-bottom: 1px dotted var(--border);
}
.provdetail > summary::-webkit-details-marker { display: none; }
.provdetail > summary:hover { color: var(--accent); border-bottom-color: var(--accent); }
.provdetail > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.provdetail-body {
  font-size: 0.8rem;
  color: var(--muted);
  padding-top: 0.6rem;
}
/* Section labels rather than headings: the disclosure is inside every card,
   and real headings here would clutter the page outline with two entries per
   story. */
.provdetail-label {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text);
  margin: 0.9rem 0 0.4rem;
}
.provdetail-label:first-of-type { margin-top: 0; }
.provdetail-close { display: none; }

.provroster { list-style: none; padding: 0; margin: 0; }
.provroster li {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.2rem 0;
  border-bottom: 1px solid var(--border);
}
.provroster li:last-child { border-bottom: 0; }
.provroster-name { color: var(--text); font-weight: 600; flex: none; }
.provroster-meta { font-size: 0.75rem; }
.provroster .legend-swatch { width: 1.1rem; }

/* Both lists align their swatch to the FIRST line of the row, not to the
   middle of it: a source or a key whose text wraps to two lines used to leave
   its swatch floating in the gutter between them, pointing at neither. Baseline
   rather than a hand-tuned offset, so it holds at any font size. */
.legend-scale { list-style: none; padding: 0; margin: 0.4rem 0; }
.legend-scale li {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.15rem 0;
}
.legend-swatch {
  display: inline-block;
  width: 1.6rem;
  height: 0.6rem;
  border-radius: 3px;
  flex: none;
}
.legend-swatch.is-state {
  background-image: repeating-linear-gradient(
    45deg,
    rgba(255, 255, 255, 0.55) 0 2px,
    rgba(255, 255, 255, 0) 2px 4px
  );
}
.legend-caveat { font-size: 0.75rem; opacity: 0.85; margin: 0.5rem 0 0; }

/* --- modal, only once the script has said it can be one ------------------- */

body.has-modal { overflow: hidden; }

.has-modal .provdetail[open]::before {
  content: "";
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: 40;
}
.has-modal .provdetail[open] > .provdetail-body {
  position: fixed;
  z-index: 41;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(34rem, calc(100vw - 2rem));
  max-height: min(80vh, 44rem);
  overflow-y: auto;
  padding: 1.4rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
}
.has-modal .provdetail[open] > .provdetail-body .provdetail-close {
  display: block;
  position: absolute;
  top: 0.5rem;
  right: 0.7rem;
  font: inherit;
  font-size: 1.4rem;
  line-height: 1;
  background: none;
  border: 0;
  color: var(--muted);
  cursor: pointer;
  padding: 0.2rem 0.4rem;
}
.has-modal .provdetail[open] > .provdetail-body .provdetail-close:hover { color: var(--text); }

/* --- analytics consent ---------------------------------------------------- */
/* Floats over the foot of the viewport until the question is answered once.
   Fixed rather than parked in the footer, because the answer decides whether a
   tracker loads on this page view and only a fraction of readers ever scroll
   to the end of a story.

   Below the provenance modal's z-index (40) on purpose: a dialog the reader
   deliberately opened outranks a bar the site opened for them. */

.consent {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  /* env() keeps it clear of the iOS home indicator, and max() keeps the plain
     gap on every browser that has no such inset to report. */
  bottom: max(0.75rem, env(safe-area-inset-bottom));
  z-index: 30;
  width: min(42rem, calc(100% - 1.5rem));
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
  padding: 0.8rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
  font-family: system-ui, sans-serif;
  font-size: 0.8rem;
  color: var(--text);
}
/* `display: flex` beats the hidden attribute's UA rule, so the bar would ship
   visible and un-dismissable to everyone without this line. */
.consent[hidden] { display: none; }

/* Room for it at the end of the page, so the bar covers nothing a reader
   scrolled all the way down to reach. The height comes from consent.js, which
   is the only thing that can know it: the question is translated and wraps to
   between one line and six. The fallback matters only if that measurement
   fails, and errs generous. */
body.has-consent .site-footer {
  padding-bottom: calc(var(--consent-space, 12rem) + 1.5rem);
}

.consent-text { margin: 0; flex: 1 1 15rem; }
.consent-actions { display: flex; gap: 0.5rem; flex: 1 0 auto; }

/* Same size, same weight, side by side: refusing has to cost the reader
   exactly what accepting costs them. Only the fill differs. */
.consent button {
  font: inherit;
  font-weight: 600;
  flex: 1 1 auto;
  padding: 0.45rem 1.1rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  color: var(--text);
  cursor: pointer;
}
.consent .consent-yes {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.consent button:hover { filter: brightness(1.08); }
.consent .consent-no:hover { background: var(--bg); }

/* Said plainly rather than hidden: the reader should know these words came
   from a machine translating an English original. */
.translated-note {
  font-family: system-ui, sans-serif;
  font-size: 0.75rem;
  color: var(--muted);
  border-left: 2px solid var(--border);
  padding-left: 0.7rem;
  margin: 1rem 0;
}
