/* ============================================================
   Neutral News — CSS Design System
   v0.1 · 2026-05-07
   Mostly black & white, paper-feel, bold editorial typography.
   Drop this single file into site/static/ and import in templates.
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,200..800;1,6..72,200..800&family=Schibsted+Grotesk:wght@400..900&family=JetBrains+Mono:wght@400;500;600&display=swap');

/* ---------- Tokens ---------- */
:root {
  /* Paper & ink */
  --nn-paper:        #f6f4ee;
  --nn-paper-dim:    #ede9df;
  --nn-paper-deep:   #e3dfd1;
  --nn-ink:          #111110;
  --nn-ink-soft:     #2a2a27;
  --nn-ink-mute:     #6b6960;
  --nn-ink-faint:    #a09c91;
  --nn-rule:         #1a1a18;
  --nn-rule-soft:    #d6d2c5;

  /* Single signal accent — verification / primary source */
  --nn-signal:       oklch(0.52 0.18 30);
  --nn-signal-ink:   oklch(0.32 0.12 30);
  --nn-signal-soft:  oklch(0.95 0.04 30);

  /* Type families */
  --nn-font-display: 'Schibsted Grotesk', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --nn-font-text:    'Newsreader', 'Source Serif Pro', Georgia, 'Times New Roman', serif;
  --nn-font-mono:    'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Fluid type scale (1.2 mobile → 1.25 desktop) */
  --nn-step--2: clamp(0.69rem, 0.67rem + 0.13vw, 0.78rem);
  --nn-step--1: clamp(0.83rem, 0.79rem + 0.20vw, 0.94rem);
  --nn-step-0:  clamp(1.00rem, 0.94rem + 0.30vw, 1.13rem);
  --nn-step-1:  clamp(1.20rem, 1.11rem + 0.45vw, 1.41rem);
  --nn-step-2:  clamp(1.44rem, 1.31rem + 0.66vw, 1.76rem);
  --nn-step-3:  clamp(1.73rem, 1.54rem + 0.93vw, 2.20rem);
  --nn-step-4:  clamp(2.07rem, 1.81rem + 1.31vw, 2.75rem);
  --nn-step-5:  clamp(2.49rem, 2.13rem + 1.81vw, 3.43rem);
  --nn-step-6:  clamp(2.99rem, 2.49rem + 2.50vw, 4.29rem);
  --nn-step-7:  clamp(3.58rem, 2.91rem + 3.36vw, 5.36rem);
  --nn-step-8:  clamp(4.30rem, 3.40rem + 4.50vw, 6.70rem);

  /* Spacing */
  --nn-3xs: 0.25rem;
  --nn-2xs: 0.5rem;
  --nn-xs:  0.75rem;
  --nn-s:   1rem;
  --nn-m:   1.5rem;
  --nn-l:   2rem;
  --nn-xl:  3rem;
  --nn-2xl: 4.5rem;
  --nn-3xl: 6rem;

  /* Layout */
  --nn-measure:    65ch;
  --nn-container:  78rem;
  --nn-narrow:     42rem;
  --nn-gutter:     clamp(1rem, 4vw, 2.5rem);
  --nn-rule-w:     1px;
  --nn-rule-w-bold: 3px;
}

/* Dark mode opt-in (paper inverts to deep ink) */
[data-theme="dark"] {
  --nn-paper:        #0c0c0a;
  --nn-paper-dim:    #161614;
  --nn-paper-deep:   #1f1f1c;
  --nn-ink:          #f1eee5;
  --nn-ink-soft:     #d8d4c8;
  --nn-ink-mute:     #9a978c;
  --nn-ink-faint:    #4a4843;
  --nn-rule:         #f1eee5;
  --nn-rule-soft:    #2a2926;
  --nn-signal:       oklch(0.72 0.18 30);
  --nn-signal-ink:   oklch(0.85 0.15 30);
  --nn-signal-soft:  oklch(0.28 0.08 30);
}

/* High-contrast / pure mode (true B&W press) */
[data-theme="pure"] {
  --nn-paper:        #ffffff;
  --nn-paper-dim:    #f4f4f4;
  --nn-paper-deep:   #ebebeb;
  --nn-ink:          #000000;
  --nn-ink-soft:     #000000;
  --nn-ink-mute:     #555555;
  --nn-ink-faint:    #999999;
  --nn-rule:         #000000;
  --nn-rule-soft:    #d8d8d8;
  --nn-signal:       #000000;
  --nn-signal-ink:   #000000;
  --nn-signal-soft:  #ebebeb;
}

/* ---------- Reset (light) ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--nn-paper);
  color: var(--nn-ink);
  font-family: var(--nn-font-text);
  font-size: var(--nn-step-0);
  line-height: 1.55;
  font-feature-settings: "ss01", "kern", "liga";
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; padding: 0; }
hr { border: 0; border-top: var(--nn-rule-w) solid var(--nn-rule); margin: var(--nn-l) 0; }
::selection { background: var(--nn-ink); color: var(--nn-paper); }

/* ---------- Layout primitives ---------- */
.nn-container {
  width: 100%;
  max-width: var(--nn-container);
  margin-inline: auto;
  padding-inline: var(--nn-gutter);
}
.nn-main { padding-block: var(--nn-l) var(--nn-2xl); }
.nn-narrow { max-width: var(--nn-narrow); margin-inline: auto; }
.nn-measure { max-width: var(--nn-measure); }

.nn-stack > * + * { margin-top: var(--nn-stack-gap, var(--nn-m)); }
.nn-stack-s > * + * { margin-top: var(--nn-2xs); }
.nn-stack-m > * + * { margin-top: var(--nn-m); }
.nn-stack-l > * + * { margin-top: var(--nn-l); }

.nn-row { display: flex; flex-wrap: wrap; gap: var(--nn-row-gap, var(--nn-s)); align-items: center; }
.nn-row-between { justify-content: space-between; }
.nn-row-baseline { align-items: baseline; }

/* ---------- Type ---------- */
.nn-display {
  font-family: var(--nn-font-display);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 0.95;
  text-wrap: balance;
}
.nn-headline {
  font-family: var(--nn-font-display);
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.05;
  text-wrap: balance;
  color: var(--nn-ink);
}
.nn-dek {
  font-family: var(--nn-font-text);
  font-weight: 300;
  font-style: italic;
  font-size: var(--nn-step-1);
  line-height: 1.35;
  color: var(--nn-ink-soft);
  text-wrap: pretty;
}
.nn-body {
  font-family: var(--nn-font-text);
  font-size: var(--nn-step-0);
  line-height: 1.65;
  color: var(--nn-ink);
  text-wrap: pretty;
  hanging-punctuation: first last;
}
.nn-body p { margin: 0; }
.nn-body p + p { margin-top: 1em; text-indent: 1.4em; }
.nn-body p.nn-lede {
  text-indent: 0;
  font-size: var(--nn-step-1);
  line-height: 1.5;
}
.nn-body p.nn-lede::first-letter {
  font-family: var(--nn-font-display);
  font-weight: 800;
  font-size: 4.4em;
  float: left;
  line-height: 0.85;
  padding: 0.05em 0.1em 0 0;
  margin-right: 0.04em;
  color: var(--nn-ink);
}

.nn-meta {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--nn-ink-mute);
}

/* Issue #114 mitigation B: rollover banner shown on the front page
   when the displayed edition is from a previous calendar day (typical
   between 00:00 and the next 07:00 build). Informational, not
   alarming — uses paper-dim background + signal-coloured leading
   marker so the eye lands on it but the page stays calm. */
.nn-rollover-banner {
  margin: 0 0 var(--nn-m) 0;
  padding: var(--nn-s) var(--nn-m);
  background: var(--nn-paper-dim);
  border-left: var(--nn-rule-w-bold) solid var(--nn-signal);
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--1);
  letter-spacing: 0.04em;
  color: var(--nn-ink-soft);
}

/* Issue #114 mitigation D: small footer-style line under the live
   page subtitle showing when the realtime fetcher last ran. Calmer
   than the rollover banner — this is "everything's running" signal,
   not "something's stale". */
.nn-live-last-check {
  margin-top: var(--nn-xs);
}

/* ---- Weather widget (#144) — `nw-` page prefix ------------------
   Collapsed-by-default <details> bar matching the section-eyebrow
   style (mono caps + signal-bullet + paper-dim bg). One-glance brief
   on the bar; click "Veure tota la predicció" to expand the full
   5-section detail. Native <details> — no JS. */
.nw-weather {
  /* Full-width like the realtime ticker — the weather bar is a
     glance-and-go strip, not a reading column. Operator feedback
     2026-05-14: should mirror .nn-ticker's full-bleed shape. */
  margin: 0 0 var(--nn-l) 0;
}
/* The <summary> is the always-visible bar. Use the eyebrow look:
   mono caps, signal bullet, paper-dim background with thin rules. */
.nw-weather__bar {
  display: flex;
  align-items: baseline;
  gap: var(--nn-s);
  padding: var(--nn-2xs) var(--nn-m);
  background: var(--nn-paper-dim);
  border-top: var(--nn-rule-w-bold) solid var(--nn-rule);
  border-bottom: var(--nn-rule-w) solid var(--nn-rule);
  cursor: pointer;
  list-style: none;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.04em;
  color: var(--nn-ink-soft);
}
/* Hide the default disclosure triangle on webkit; the toggle label
   below carries the affordance. */
.nw-weather__bar::-webkit-details-marker { display: none; }
.nw-weather__eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--nn-ink-mute);
  white-space: nowrap;
  flex-shrink: 0;
}
.nw-weather__eyebrow::before {
  content: "";
  display: inline-block;
  width: 0.6em; height: 0.6em;
  background: var(--nn-signal);
  margin-right: 0.7em;
  transform: translateY(-0.05em);
}
.nw-weather__brief {
  flex: 1;
  min-width: 0;
  color: var(--nn-ink);
  font-family: var(--nn-font-text);
  font-size: var(--nn-step--1);
  letter-spacing: 0;
  text-transform: none;
  /* Wrap to multiple lines rather than ellipsis-truncate — the
     full brief is the load-bearing content of the collapsed bar,
     not the eyebrow or the toggle. Bar height adapts; eyebrow +
     toggle stay aligned to the first-line baseline. Operator
     feedback 2026-05-14. */
  text-wrap: pretty;
  line-height: 1.4;
}
.nw-weather__toggle {
  flex-shrink: 0;
  color: var(--nn-signal);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.nw-weather__toggle::after { content: "  →"; }
.nw-weather[open] .nw-weather__toggle::after { content: "  ↓"; }
/* Brief wraps natively now — no expanded-state override needed. */

/* Expanded panel: the original multi-section detail. */
.nw-weather__panel {
  padding: var(--nn-s) var(--nn-m) var(--nn-m);
  background: var(--nn-paper-dim);
  border-bottom: var(--nn-rule-w) solid var(--nn-rule);
}
.nw-weather__list {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: var(--nn-m);
  row-gap: var(--nn-2xs);
  margin: 0;
}
.nw-weather__row { display: contents; }
.nw-weather__label {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--nn-ink-mute);
  align-self: baseline;
}
.nw-weather__text {
  margin: 0;
  font-family: var(--nn-font-text);
  font-size: var(--nn-step-0);
  line-height: 1.45;
  color: var(--nn-ink);
  text-wrap: pretty;
}
.nw-weather__source {
  margin: var(--nn-s) 0 0 0;
  padding-top: var(--nn-2xs);
  border-top: var(--nn-rule-w) solid var(--nn-rule-soft);
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.04em;
  color: var(--nn-ink-faint);
}
.nw-weather__source a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--nn-rule);
}
.nw-weather__source a:hover {
  color: var(--nn-signal);
  border-bottom-color: var(--nn-signal);
}

@media (max-width: 760px) {
  /* On narrow screens, let the brief drop to its own row below the
     eyebrow + toggle. Eyebrow stays a left-edge anchor; toggle slides
     to the right of the eyebrow on the same row. */
  .nw-weather__bar {
    flex-wrap: wrap;
  }
  .nw-weather__brief { flex-basis: 100%; }
  .nw-weather__list {
    grid-template-columns: 1fr;
    row-gap: var(--nn-s);
  }
  .nw-weather__label { margin-bottom: var(--nn-3xs); }
}
.nn-eyebrow {
  font-family: var(--nn-font-display);
  font-weight: 700;
  font-size: var(--nn-step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nn-ink);
}
.nn-byline {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-ink-mute);
  letter-spacing: 0.02em;
}

/* Display sizes */
.nn-d-1 { font-size: var(--nn-step-8); } /* masthead-grade */
.nn-d-2 { font-size: var(--nn-step-7); }
.nn-d-3 { font-size: var(--nn-step-6); }
.nn-d-4 { font-size: var(--nn-step-5); }
.nn-d-5 { font-size: var(--nn-step-4); }
.nn-d-6 { font-size: var(--nn-step-3); }
.nn-d-7 { font-size: var(--nn-step-2); }
.nn-d-8 { font-size: var(--nn-step-1); }

/* ---------- Rules ---------- */
.nn-rule        { border: 0; border-top: var(--nn-rule-w) solid var(--nn-rule); margin: 0; }
.nn-rule-bold   { border: 0; border-top: var(--nn-rule-w-bold) solid var(--nn-rule); margin: 0; }
.nn-rule-soft   { border: 0; border-top: var(--nn-rule-w) solid var(--nn-rule-soft); margin: 0; }
.nn-rule-double { border: 0; border-top: 1px solid var(--nn-rule); border-bottom: 1px solid var(--nn-rule); height: 4px; margin: 0; }

/* ---------- Masthead ---------- */
.nn-masthead {
  padding: var(--nn-l) 0 0;
  position: relative;
  overflow: visible;
}
.nn-masthead__row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--nn-s);
  padding-block: var(--nn-2xs);
}
.nn-masthead__title {
  font-family: var(--nn-font-display);
  font-weight: 900;
  font-size: var(--nn-step-7);
  letter-spacing: -0.04em;
  line-height: 0.85;
  text-align: center;
  margin: 0;
  font-feature-settings: "ss01";
  position: relative;
  display: inline-block;
}
/* ---------- BETA stamp (Claude Design / archive.html) ---------- */
.beta-stamp {
  position: absolute;
  top: 50%;
  left: 0;
  transform: translate(-78%, -52%) rotate(-11deg);
  pointer-events: none;
  z-index: 20;
  --stamp-red: #c2342a;
  color: var(--stamp-red);
  border: 3px double currentColor;
  padding: 0.22em 0.6em 0.14em;
  font-family: var(--nn-font-display);
  font-weight: 900;
  font-size: clamp(1.1rem, 2.2vw, 1.6rem);
  letter-spacing: 0.18em;
  line-height: 0.95;
  text-transform: uppercase;
  opacity: 0.92;
  background: transparent;
  -webkit-mask-image:
    radial-gradient(ellipse at 22% 38%, transparent 0 6%, black 8%),
    radial-gradient(ellipse at 78% 62%, transparent 0 5%, black 7%),
    radial-gradient(ellipse at 50% 80%, transparent 0 4%, black 6%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='400' height='200'><filter id='r'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' seed='3'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 1.6 -0.4'/></filter><rect width='100%25' height='100%25' filter='url(%23r)'/></svg>");
  -webkit-mask-composite: source-over, source-over, source-over, source-in;
          mask-image:
    radial-gradient(ellipse at 22% 38%, transparent 0 6%, black 8%),
    radial-gradient(ellipse at 78% 62%, transparent 0 5%, black 7%),
    radial-gradient(ellipse at 50% 80%, transparent 0 4%, black 6%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='400' height='200'><filter id='r'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' seed='3'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 1.6 -0.4'/></filter><rect width='100%25' height='100%25' filter='url(%23r)'/></svg>");
  mask-composite: intersect;
  filter: contrast(1.1);
  text-shadow: 0.5px 0 0 currentColor;
}
.beta-stamp::before {
  content: "";
  position: absolute;
  top: -10%;
  right: -6%;
  width: 0.6em;
  height: 0.4em;
  background: currentColor;
  opacity: 0.55;
  border-radius: 50%;
  transform: rotate(28deg);
  filter: blur(0.5px);
}
.beta-stamp::after {
  content: "BETA";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: currentColor;
  opacity: 0.18;
  transform: translate(2px, 1.5px);
  pointer-events: none;
}
@media (max-width: 720px) {
  .beta-stamp {
    font-size: 0.95rem;
    letter-spacing: 0.14em;
  }
}
.nn-masthead__title .fets-dot {
  color: var(--nn-signal);
}
.nn-masthead__title sup {
  font-family: var(--nn-font-mono);
  font-size: 0.18em;
  font-weight: 500;
  vertical-align: super;
  margin-left: 0.3em;
  letter-spacing: 0.08em;
  color: var(--nn-signal);
  text-transform: uppercase;
}
.nn-masthead__left, .nn-masthead__right {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--nn-ink-mute);
  display: flex;
  gap: var(--nn-m);
  align-items: center;
}
.nn-masthead__right { justify-content: flex-end; }
.nn-masthead__left  { justify-content: flex-start; flex-wrap: wrap; }
/* The left side of the masthead carries the print-paper triplet:
   issue number · edition kind · date. Each in mono caps; the issue
   number is the bold headline of the three. */
.nn-masthead__issue {
  color: var(--nn-ink);
  font-weight: 700;
}
.nn-masthead__edition-kind {
  color: var(--nn-signal);
  font-weight: 600;
}
.nn-masthead__date {
  color: var(--nn-ink-mute);
}
.nn-masthead__build-time {
  color: var(--nn-ink-faint);
}
.nn-masthead__motto {
  text-align: center;
  font-family: var(--nn-font-text);
  font-style: italic;
  font-weight: 300;
  font-size: var(--nn-step-3);
  color: var(--nn-ink-mute);
  margin-top: var(--nn-m);
  margin-bottom: var(--nn-m);
  line-height: 1.25;
  letter-spacing: -0.005em;
  text-wrap: balance;
  max-width: 60ch;
  margin-left: auto;
  margin-right: auto;
}

/* ---------- Section nav (Today · Archive · Timeline · About) ----------
   The nav itself spans the full viewport width so the thin rule at its
   bottom edge meets the page gutters; an inner container re-applies
   horizontal padding so the LINKS stay centred on the same gutter as
   the masthead and content above. The bold divider lives on a sibling
   <hr> so it can also reach the viewport edges. */
.nn-secnav {
  border-bottom: var(--nn-rule-w) solid var(--nn-rule-soft);
  font-family: var(--nn-font-display);
  font-weight: 700;
  font-size: var(--nn-step-2);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.nn-secnav__inner {
  display: flex;
  justify-content: center;
  /* Fluid gap that holds 5 items on a single line even with longer
     translations (Basque labels are 30-40% wider than CA). Falls back
     to flex-wrap if a viewport is genuinely too narrow. */
  gap: clamp(var(--nn-l), 4vw, var(--nn-2xl));
  padding-block: var(--nn-m) var(--nn-s);
  flex-wrap: wrap;
}
.nn-secnav a {
  position: relative;
  padding: var(--nn-2xs) 0;
  color: var(--nn-ink);
  text-decoration: none;
}
.nn-secnav a[aria-current="page"]::after,
.nn-secnav a:hover::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  background: var(--nn-ink);
}
.nn-secnav__divider {
  border: 0;
  border-top: var(--nn-rule-w-bold) solid var(--nn-rule);
  margin: 0;
}

/* ---------- Language toggle ---------- */
.nn-lang {
  display: inline-flex;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border: 1px solid var(--nn-rule);
}
.nn-lang button, .nn-lang a {
  padding: 0.35em 0.7em;
  color: var(--nn-ink);
  border-right: 1px solid var(--nn-rule);
}
.nn-lang button:last-child, .nn-lang a:last-child { border-right: 0; }
.nn-lang [aria-current="true"], .nn-lang .is-active {
  background: var(--nn-ink);
  color: var(--nn-paper);
}
/* AI-translation disclosure: injected by pipeline/post_translate.py
   only on EXTRA_LANGS trees (not present on /ca/ or /en/). Sits as a
   sibling AFTER the motto, centred under the title in small mono
   signal-red — same font/size/colour as the previous beside-the-
   switcher version, just relocated. */
.nn-masthead__ai-note {
  text-align: center;
  font-family: var(--nn-font-mono);
  font-size: 0.6rem;
  line-height: 1.3;
  letter-spacing: 0.02em;
  color: var(--nn-signal);
  margin: 0 0 var(--nn-m);
}

/* ---------- Section header ---------- */
.nn-section-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: end;
  gap: var(--nn-m);
  padding: var(--nn-xl) 0 var(--nn-s);
  border-bottom: var(--nn-rule-w) solid var(--nn-rule);
}
.nn-section-head__label {
  font-family: var(--nn-font-display);
  font-weight: 900;
  font-size: var(--nn-step-5);
  letter-spacing: -0.02em;
  line-height: 0.9;
  margin: 0;
}
.nn-section-head__count {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--1);
  color: var(--nn-ink-mute);
  letter-spacing: 0.04em;
  align-self: end;
}
.nn-section-head__meta {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--nn-ink-mute);
  text-align: right;
}

/* ---------- Article cards / bulletins ---------- */
.nn-grid {
  display: grid;
  gap: 0;
  grid-template-columns: repeat(12, 1fr);
}
.nn-grid > * { padding: var(--nn-m) var(--nn-m) var(--nn-l); }
.nn-grid > * + * { border-left: var(--nn-rule-w) solid var(--nn-rule-soft); }

.nn-grid--lead-3 > :nth-child(1) { grid-column: span 6; padding-left: 0; }
.nn-grid--lead-3 > :nth-child(2) { grid-column: span 3; }
.nn-grid--lead-3 > :nth-child(3) { grid-column: span 3; padding-right: 0; }

.nn-grid--3up > * { grid-column: span 4; }
.nn-grid--3up > :first-child { padding-left: 0; }
.nn-grid--3up > :last-child  { padding-right: 0; }

.nn-grid--4up > * { grid-column: span 3; }
.nn-grid--4up > :first-child { padding-left: 0; }
.nn-grid--4up > :last-child  { padding-right: 0; }

.nn-grid--2up > * { grid-column: span 6; }
.nn-grid--2up > :first-child { padding-left: 0; }
.nn-grid--2up > :last-child  { padding-right: 0; }

@media (max-width: 760px) {
  .nn-grid > * { grid-column: 1 / -1 !important; padding-inline: 0 !important; border-left: 0 !important; border-top: var(--nn-rule-w) solid var(--nn-rule-soft); }
  .nn-grid > :first-child { border-top: 0; }
}

/* Article card content */
.nn-art { display: flex; flex-direction: column; gap: var(--nn-2xs); }
.nn-art__kicker {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nn-2xs);
  align-items: center;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--nn-ink-mute);
}
.nn-art__head {
  font-family: var(--nn-font-display);
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.05;
  color: var(--nn-ink);
  text-wrap: balance;
}
.nn-art--lead .nn-art__head { font-size: var(--nn-step-5); font-weight: 800; }
.nn-art--medium .nn-art__head { font-size: var(--nn-step-3); }
.nn-art--small .nn-art__head { font-size: var(--nn-step-2); }
.nn-art--bulletin .nn-art__head { font-size: var(--nn-step-1); font-weight: 700; }
.nn-art__dek {
  font-family: var(--nn-font-text);
  font-style: italic;
  font-weight: 300;
  font-size: var(--nn-step-0);
  line-height: 1.4;
  color: var(--nn-ink-soft);
  text-wrap: pretty;
  margin-top: var(--nn-2xs);
}
.nn-art__body {
  font-family: var(--nn-font-text);
  font-size: var(--nn-step-0);
  line-height: 1.55;
  color: var(--nn-ink-soft);
  margin-top: var(--nn-2xs);
  text-wrap: pretty;
}
.nn-art__foot {
  margin-top: var(--nn-s);
  display: flex;
  flex-wrap: wrap;
  gap: var(--nn-2xs) var(--nn-s);
  align-items: center;
}

/* ---------- Entity chips (topic-card provenance: people/orgs/places) ---------- */
.nn-art__entities {
  margin-top: var(--nn-xs);
}
.nn-art__entities-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--nn-3xs) var(--nn-2xs);
}
.nn-art__entities-more {
  display: inline-block;
  margin-top: var(--nn-3xs);
}
.nn-art__entities-more-toggle {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.06em;
  color: var(--nn-ink-mute);
  cursor: pointer;
  user-select: none;
}
.nn-art__entities-more-toggle:hover {
  color: var(--nn-ink);
}
/* Entity chip — small inline link in mono, type-differentiated */
.nn-entity {
  display: inline-block;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.04em;
  padding: 0.2em 0.45em;
  border: 1px solid var(--nn-rule-soft);
  color: var(--nn-ink-mute);
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
}
.nn-entity:hover {
  color: var(--nn-ink);
  border-color: var(--nn-rule);
}
/* Person chips: round pill to distinguish from source chips (square) */
.nn-entity--person {
  border-radius: 999px;
}
/* Organization chips: default square corners */
.nn-entity--organization {
  border-radius: 0;
}
/* Place chips: subtle background tint */
.nn-entity--place {
  background: var(--nn-paper-dim);
}

/* ---------- Source pills (the "neutrality guarantee" UI) ---------- */
.nn-source {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.25em 0.55em;
  border: 1px solid var(--nn-rule);
  color: var(--nn-ink);
  line-height: 1;
  white-space: nowrap;
}
.nn-source::before {
  content: "";
  width: 0.55em;
  height: 0.55em;
  display: inline-block;
  background: currentColor;
}
.nn-source--institutional { color: var(--nn-ink); border-color: var(--nn-ink); }
.nn-source--institutional::before { background: var(--nn-ink); }
.nn-source--sensor       { color: var(--nn-ink); border-color: var(--nn-ink); }
.nn-source--sensor::before { background: var(--nn-paper); border: 2px solid var(--nn-ink); width: 0.6em; height: 0.6em; transform: rotate(45deg); }
.nn-source--wire         { color: var(--nn-ink-mute); border-color: var(--nn-ink-mute); }
.nn-source--wire::before { background: transparent; border: 1px solid currentColor; border-radius: 999px; }
.nn-source--editorial-press { color: var(--nn-ink); border-color: var(--nn-ink); }
.nn-source--editorial-press::before { background: var(--nn-ink); border-radius: 999px; }
.nn-source--verified     { color: var(--nn-signal); border-color: var(--nn-signal); }
.nn-source--verified::before { background: var(--nn-signal); }

/* ---------- Threshold badge ---------- */
.nn-threshold {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-ink-mute);
  letter-spacing: 0.02em;
  border-bottom: 1px dotted var(--nn-ink-faint);
  padding-bottom: 0.1em;
}
.nn-threshold strong {
  color: var(--nn-ink);
  font-weight: 600;
}
.nn-threshold__op { color: var(--nn-signal); font-weight: 600; }

/* ---------- Per-card relevance disclosure trigger ----------
   The summary line that, when clicked, reveals the existing
   `.nn-prov` provenance card with PROVENANCE + EDITORIAL tabs. */
.nn-rationale {
  margin-top: var(--nn-2xs);
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-ink-mute);
  border-top: 1px dotted var(--nn-rule);
  padding-top: var(--nn-2xs);
}
.nn-rationale__summary {
  cursor: pointer;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  user-select: none;
}
.nn-rationale__summary::-webkit-details-marker { display: none; }
.nn-rationale__summary::before {
  content: "▶";
  display: inline-block;
  font-size: 0.7em;
  transition: transform 120ms ease;
}
.nn-rationale[open] > .nn-rationale__summary::before {
  transform: rotate(90deg);
}
.nn-rationale__summary:hover { color: var(--nn-ink); }
.nn-rationale > .nn-prov { margin-top: var(--nn-xs); }

/* ---------- Provenance card tabs (PROVENANCE / EDITORIAL) ----------
   Pure CSS tabs via radio + label inside the existing .nn-prov
   container. Each card gets a unique radio group via item_id so
   multiple expanded cards on a page don't fight each other. */
.nn-prov__tabs {
  display: flex;
  gap: 0;
  margin-bottom: var(--nn-s);
  border-bottom: 1px solid var(--nn-rule);
}
.nn-prov__tab-input { position: absolute; opacity: 0; pointer-events: none; }
.nn-prov__tab-label {
  font-family: var(--nn-font-display);
  font-weight: 700;
  font-size: var(--nn-step--2);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nn-ink-mute);
  padding: 0.4em 0.9em;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  user-select: none;
}
.nn-prov__tab-label:hover { color: var(--nn-ink); }
.nn-prov:has(.nn-prov__tab-input--prov:checked) .nn-prov__tab-label[for$="-prov"],
.nn-prov:has(.nn-prov__tab-input--edit:checked) .nn-prov__tab-label[for$="-edit"] {
  color: var(--nn-ink);
  border-bottom-color: var(--nn-signal);
}
.nn-prov:has(.nn-prov__tab-input--prov:focus-visible) .nn-prov__tab-label[for$="-prov"],
.nn-prov:has(.nn-prov__tab-input--edit:focus-visible) .nn-prov__tab-label[for$="-edit"] {
  outline: 2px solid var(--nn-signal);
  outline-offset: 2px;
}
.nn-prov__panel { display: none; }
.nn-prov:has(.nn-prov__tab-input--prov:checked) .nn-prov__panel--prov,
.nn-prov:has(.nn-prov__tab-input--edit:checked) .nn-prov__panel--edit {
  display: block;
}
/* Editorial panel — same dl shape as provenance but the value cells
   often hold short prose, so they wrap onto their own line. */
.nn-prov__panel--edit dl {
  grid-template-columns: 1fr;
  gap: var(--nn-s);
}
.nn-prov__panel--edit dt {
  font-family: var(--nn-font-display);
  font-weight: 700;
  font-size: var(--nn-step--2);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nn-ink);
}
.nn-prov__path strong { color: var(--nn-ink); font-weight: 600; }
.nn-prov__arrow { color: var(--nn-ink-faint); margin: 0 0.3em; }
.nn-prov__hint { color: var(--nn-ink-mute); font-style: italic; margin-left: 0.3em; }
.nn-prov__why-heading {
  margin: var(--nn-s) 0 0.2em;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.04em;
  color: var(--nn-ink);
}
.nn-prov__reason {
  margin: 0.3em 0 0;
  color: var(--nn-ink-soft);
  font-family: var(--nn-font-text, inherit);
  font-size: var(--nn-step--1);
  line-height: 1.5;
}
.nn-prov__rules { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5em; }
.nn-prov__rule {
  display: grid;
  grid-template-columns: 1.4em auto 1fr;
  gap: 0.2em 0.5em;
  align-items: baseline;
}
.nn-prov__rule .nn-prov__reason { grid-column: 2 / span 2; }
.nn-prov__verdict { font-weight: 600; width: 1.1em; text-align: center; }
.nn-prov__rule--match .nn-prov__verdict { color: var(--nn-signal); }
.nn-prov__rule--miss .nn-prov__verdict { color: var(--nn-ink-faint); }
.nn-prov__rule--miss .nn-prov__rule-name { color: var(--nn-ink-mute); }
.nn-prov__rule--miss .nn-prov__reason { color: var(--nn-ink-faint); }
.nn-prov__rule-name { letter-spacing: 0.03em; text-transform: uppercase; }

/* Bias-detection block (Provenance tab) — small score chip + dl rows
   for target / polarity / verbatim signals from the source. The
   chip's colour follows the score so a 0 reads neutral and a 3
   reads as a clear warning. */
.nn-prov__head--bias {
  margin-top: var(--nn-m);
  padding-top: var(--nn-s);
  border-top: 1px dotted var(--nn-rule);
}
.nn-prov__bias dt { color: var(--nn-ink-mute); }
.nn-prov__bias dd { color: var(--nn-ink); }
.nn-bias-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 0.2em 0.55em;
  border: 1px solid var(--nn-rule);
  text-transform: uppercase;
  white-space: nowrap;
}
.nn-bias-chip--0 { color: var(--nn-ink-mute); border-color: var(--nn-rule); }
.nn-bias-chip--1 { color: var(--nn-ink); border-color: var(--nn-rule); }
.nn-bias-chip--2 {
  color: var(--nn-signal);
  border-color: var(--nn-signal);
}
.nn-bias-chip--3 {
  color: var(--nn-paper);
  background: var(--nn-signal);
  border-color: var(--nn-signal);
}
.nn-prov__bias-signals {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3em;
}
.nn-prov__bias-signals li {
  font-family: var(--nn-font-text, inherit);
  font-size: var(--nn-step--1);
  color: var(--nn-ink-soft);
  line-height: 1.45;
  font-style: italic;
}

/* At-a-glance bias mark in the article footer. Visually a sibling of
   `.nn-threshold` (same mono/mute typography, same dotted underline)
   so the two chips read as a coherent pair under the article body.
   Forced onto its own line (flex-basis: 100%) directly below the
   threshold chip. Score 3 swaps to the accent colour so promotional
   framing is visible at a glance while skimming. */
.nn-threshold--bias {
  flex-basis: 100%;
  cursor: help;
}
.nn-threshold--bias-3 {
  color: var(--nn-signal);
  border-bottom-color: var(--nn-signal);
}
.nn-threshold--bias-3 strong,
.nn-threshold--bias-3 .nn-threshold__op {
  color: var(--nn-signal);
}

/* --- Multi-bias inline disclosure (v2). Replaces the single
   .nn-threshold--bias chip with a short sentence list — one line
   per detected bias. Each line reads "Favourable framing toward
   X (kind, score/3)" so the substance is visible while skimming.
   Sits in the article footer alongside threshold chips. --- */
.nn-biases {
  flex-basis: 100%;
  margin-top: var(--nn-2xs);
  display: grid;
  gap: var(--nn-2xs);
}
.nn-biases__label {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--nn-ink-mute);
}
.nn-biases__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2px;
}
.nn-biases__item {
  font-family: var(--nn-font-text);
  font-size: var(--nn-step--1);
  line-height: 1.4;
  color: var(--nn-ink-soft);
  text-wrap: pretty;
  cursor: help;
}
.nn-biases__phrase {
  color: var(--nn-ink-mute);
}
.nn-biases__target {
  color: var(--nn-ink);
  font-weight: 600;
}
.nn-biases__meta {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-ink-mute);
  font-feature-settings: "tnum";
}
/* Score 3 gets the signal accent so promotional framing pops
   while skimming, matching the v1 chip's "score 3 → signal" rule. */
.nn-biases__item--score-3 .nn-biases__target {
  color: var(--nn-signal);
}
.nn-biases__item--score-3 .nn-biases__meta {
  color: var(--nn-signal);
}

/* ---------- Topic card (#45, synthesis front page) ----------
   The published unit when redaction is dormant: a synthesized topic,
   not a per-source bulletin. The card face reuses the `.nn-art`
   vocabulary (mono kicker, display head, text body) so a topic card
   and a bulletin card read as siblings; no new tokens. */
.nn-topic-card { display: flex; flex-direction: column; gap: var(--nn-2xs); }
.nn-topic-card__kicker {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nn-2xs) var(--nn-s);
  align-items: center;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--nn-ink-mute);
}
.nn-topic-card__sources {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--nn-2xs);
  align-items: center;
}
/* Inline declared-stance bias chip on the card face. Phase 1 carries
   stance spread only — we never claim "detected bias". Sits as a
   sibling of the source chips, styled like the `.nn-threshold` pair. */
.nn-topic-card__bias {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.04em;
  color: var(--nn-ink-mute);
  cursor: help;
}
.nn-topic-card__bias-label {
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.nn-topic-card__bias-value {
  color: var(--nn-ink);
  text-transform: none;
  letter-spacing: 0;
}
.nn-topic-card__head {
  font-family: var(--nn-font-display);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.05;
  color: var(--nn-ink);
  text-wrap: balance;
  font-size: var(--nn-step-3);
  margin: var(--nn-2xs) 0 0;
  max-width: 28ch;
}
.nn-topic-card--lead .nn-topic-card__head { font-size: var(--nn-step-5); }
.nn-topic-card__head--regular {
  font-size: var(--nn-step-1);
  font-weight: 700;
}
.nn-topic-card__narrative {
  font-family: var(--nn-font-text);
  font-size: var(--nn-step-0);
  line-height: 1.55;
  color: var(--nn-ink-soft);
  margin-top: var(--nn-2xs);
  text-wrap: pretty;
  max-width: 65ch;
}
.nn-topic-card--lead .nn-topic-card__narrative {
  font-size: var(--nn-step-1);
  line-height: 1.6;
}

/* ---------- Topic-card five-tab disclosure (#45, spec §6) ----------
   The `.nn-prov` two-tab :has() switch is hardcoded to prov/edit, so
   the five-tab topic disclosure gets its own switch — same radio+label
   mechanism, same tokens, same visual treatment (mono caps tab labels,
   signal underline on the active tab, paper-dim panel). The `.nn-prov`
   container styling at the foot of this file styles `.nn-tprov` too via
   the shared selector below. */
.nn-tprov {
  border: 1px solid var(--nn-rule);
  padding: var(--nn-m);
  background: var(--nn-paper-dim);
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-ink-soft);
}
.nn-tprov__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin-bottom: var(--nn-s);
  border-bottom: 1px solid var(--nn-rule);
}
.nn-tprov__tab-input { position: absolute; opacity: 0; pointer-events: none; }
.nn-tprov__tab-label {
  font-family: var(--nn-font-display);
  font-weight: 700;
  font-size: var(--nn-step--2);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--nn-ink-mute);
  padding: 0.4em 0.8em;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  user-select: none;
}
.nn-tprov__tab-label:hover { color: var(--nn-ink); }
.nn-tprov:has(.nn-tprov__tab-input--facts:checked) .nn-tprov__tab-label[for$="-facts"],
.nn-tprov:has(.nn-tprov__tab-input--bias:checked) .nn-tprov__tab-label[for$="-bias"],
.nn-tprov:has(.nn-tprov__tab-input--reliab:checked) .nn-tprov__tab-label[for$="-reliab"],
.nn-tprov:has(.nn-tprov__tab-input--import:checked) .nn-tprov__tab-label[for$="-import"],
.nn-tprov:has(.nn-tprov__tab-input--route:checked) .nn-tprov__tab-label[for$="-route"] {
  color: var(--nn-ink);
  border-bottom-color: var(--nn-signal);
}
.nn-tprov:has(.nn-tprov__tab-input--facts:focus-visible) .nn-tprov__tab-label[for$="-facts"],
.nn-tprov:has(.nn-tprov__tab-input--bias:focus-visible) .nn-tprov__tab-label[for$="-bias"],
.nn-tprov:has(.nn-tprov__tab-input--reliab:focus-visible) .nn-tprov__tab-label[for$="-reliab"],
.nn-tprov:has(.nn-tprov__tab-input--import:focus-visible) .nn-tprov__tab-label[for$="-import"],
.nn-tprov:has(.nn-tprov__tab-input--route:focus-visible) .nn-tprov__tab-label[for$="-route"] {
  outline: 2px solid var(--nn-signal);
  outline-offset: 2px;
}
.nn-tprov__panel { display: none; }
.nn-tprov:has(.nn-tprov__tab-input--facts:checked) .nn-tprov__panel--facts,
.nn-tprov:has(.nn-tprov__tab-input--bias:checked) .nn-tprov__panel--bias,
.nn-tprov:has(.nn-tprov__tab-input--reliab:checked) .nn-tprov__panel--reliab,
.nn-tprov:has(.nn-tprov__tab-input--import:checked) .nn-tprov__panel--import,
.nn-tprov:has(.nn-tprov__tab-input--route:checked) .nn-tprov__panel--route {
  display: block;
}
.nn-tprov__head {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--nn-ink);
  margin: 0 0 var(--nn-s);
}
.nn-tprov__meta {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--nn-2xs) var(--nn-m);
  margin: 0;
}
.nn-tprov__meta dt { color: var(--nn-ink-mute); }
.nn-tprov__meta dd { margin: 0; color: var(--nn-ink); }
.nn-tprov__sources {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--nn-2xs) var(--nn-m);
  margin: 0;
}
.nn-tprov__sources dt {
  color: var(--nn-ink);
  letter-spacing: 0.06em;
}
.nn-tprov__sources dd { margin: 0; color: var(--nn-ink-soft); }
.nn-tprov__stance { margin-right: var(--nn-m); }
.nn-tprov__detected { color: var(--nn-ink-mute); }
.nn-tprov__reason {
  margin: var(--nn-s) 0 0;
  color: var(--nn-ink-soft);
  font-family: var(--nn-font-text);
  font-size: var(--nn-step--1);
  line-height: 1.5;
  text-wrap: pretty;
}
.nn-tprov__path { margin: 0; color: var(--nn-ink); }
.nn-tprov__path strong { font-weight: 600; }
.nn-tprov__arrow { color: var(--nn-ink-faint); margin: 0 0.3em; }
.nn-tprov__hint { color: var(--nn-ink-mute); font-style: italic; margin-left: 0.3em; }
.nn-tprov__empty {
  margin: 0;
  color: var(--nn-ink-mute);
  font-style: italic;
}
/* Triple-first facts list — lifted from sintesi.html's `.sn-topic__triple`
   so a topic's claims read the same here as they did on /sintesi/. */
.nn-tprov__triples {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--nn-m);
}
.nn-tprov__triple {
  color: var(--nn-ink);
  font-family: var(--nn-font-text);
  font-size: var(--nn-step--1);
  line-height: 1.5;
}
.nn-tprov__pred {
  color: var(--nn-ink-mute);
  font-style: italic;
  margin: 0 var(--nn-2xs);
}
.nn-tprov__triple-sources {
  list-style: none;
  padding: 0;
  margin: var(--nn-2xs) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--nn-2xs);
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
}
.nn-tprov__triple-sources a,
.nn-tprov__triple-sources span {
  display: inline-block;
  padding: var(--nn-3xs) var(--nn-2xs);
  color: var(--nn-ink-soft);
  background: var(--nn-paper);
  border: 1px solid var(--nn-rule-soft);
  text-decoration: none;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  overflow-wrap: anywhere;
}
.nn-tprov__triple-sources a:hover {
  color: var(--nn-signal);
  border-color: var(--nn-signal);
}

/* ---------- Primary source link / footer card on article ---------- */
.nn-prov {
  border: 1px solid var(--nn-rule);
  padding: var(--nn-m);
  background: var(--nn-paper-dim);
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--1);
  line-height: 1.5;
  color: var(--nn-ink-soft);
}
.nn-prov__head {
  font-family: var(--nn-font-display);
  font-weight: 700;
  font-size: var(--nn-step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nn-ink);
  margin: 0 0 var(--nn-s);
  display: flex;
  align-items: center;
  gap: var(--nn-2xs);
}
.nn-prov__head::before {
  content: "";
  width: 0.7em; height: 0.7em;
  background: var(--nn-signal);
  display: inline-block;
}
/* The card responds to its own container width (not the viewport) so
   it can sit in any-sized column. When the column is narrow — e.g. a
   span-3 cell of a 4-up grid — the dl collapses to single-column
   (label above value) so URLs and long target names get the full
   width instead of wrapping one segment per line. */
.nn-prov {
  container-type: inline-size;
  container-name: provcard;
}
.nn-prov dl {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--nn-2xs) var(--nn-s);
  margin: 0;
}
/* Threshold sits comfortably above the typical 4-up cell width (~280-
   320px content area at desktop) so the query fires reliably for any
   non-lead column. Lead columns at 6/12 (~600px+) stay above the
   threshold and keep the airy default treatment. */
@container provcard (max-width: 420px) {
  .nn-prov dl {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .nn-prov dt {
    margin-top: var(--nn-xs);
  }
  .nn-prov dt:first-of-type {
    margin-top: 0;
  }
  /* Tab labels are uppercase + wide letter-spacing by default — fine in
     a wide cell but visually overstuffed in a narrow column. Tighten
     letter-spacing and padding (font-size keeps --nn-step--2 since
     there's no smaller step variable defined). */
  .nn-prov__tab-label {
    letter-spacing: 0.04em;
    padding: 0.4em 0.55em;
    font-size: 0.62rem;
  }
  /* Inner card section headers ("FONT PRIMÀRIA", "BIAIX DETECTAT")
     get the same treatment so they don't bump into the card edge. */
  .nn-prov__head {
    letter-spacing: 0.06em;
    font-size: 0.7rem;
  }
}
.nn-prov dt { color: var(--nn-ink-mute); }
.nn-prov dd {
  margin: 0;
  color: var(--nn-ink);
  /* Long URLs and other unbroken strings must wrap inside the
     value cell so they don't blow the card past its container. */
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.nn-prov dd a { border-bottom: 1px solid currentColor; }
.nn-prov dd a:hover { color: var(--nn-signal); }

/* ---------- Source list (end of synthesis article) ---------- */
.nn-sources {
  border-top: var(--nn-rule-w-bold) solid var(--nn-rule);
  border-bottom: var(--nn-rule-w-bold) solid var(--nn-rule);
  padding: var(--nn-l) 0;
  margin-top: var(--nn-xl);
}
.nn-sources__title {
  font-family: var(--nn-font-display);
  font-weight: 800;
  font-size: var(--nn-step-2);
  letter-spacing: -0.01em;
  margin: 0 0 var(--nn-s);
}
.nn-sources__sub {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--nn-ink-mute);
  margin-bottom: var(--nn-m);
}
.nn-sources ol {
  list-style: none;
  margin: 0; padding: 0;
  counter-reset: src;
}
.nn-sources li {
  counter-increment: src;
  display: grid;
  grid-template-columns: 2.5em 1fr auto;
  gap: var(--nn-s);
  padding: var(--nn-s) 0;
  border-top: 1px solid var(--nn-rule-soft);
  font-family: var(--nn-font-text);
  font-size: var(--nn-step--1);
  line-height: 1.45;
  align-items: baseline;
}
.nn-sources li::before {
  content: "[" counter(src, decimal-leading-zero) "]";
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-signal);
  letter-spacing: 0.04em;
}
.nn-sources li a { border-bottom: 1px solid var(--nn-ink-faint); }
.nn-sources li a:hover { color: var(--nn-signal); border-color: var(--nn-signal); }
.nn-sources li .nn-meta { white-space: nowrap; }

/* In-body inline citation marker */
.nn-cite {
  font-family: var(--nn-font-mono);
  font-size: 0.7em;
  vertical-align: super;
  color: var(--nn-signal);
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 0 0.1em;
}
.nn-cite::before { content: "["; }
.nn-cite::after  { content: "]"; }

/* ---------- Banner / status ---------- */
.nn-banner {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: var(--nn-2xs) var(--nn-gutter);
  background: var(--nn-ink);
  color: var(--nn-paper);
  text-align: center;
}
.nn-banner--soft {
  background: var(--nn-paper-dim);
  color: var(--nn-ink-mute);
  border-bottom: 1px solid var(--nn-rule-soft);
}

/* ---------- Buttons ---------- */
.nn-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--nn-font-display);
  font-weight: 700;
  font-size: var(--nn-step--1);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.85em 1.3em;
  background: var(--nn-ink);
  color: var(--nn-paper);
  border: 1px solid var(--nn-ink);
  transition: background 120ms, color 120ms;
}
.nn-btn:hover { background: var(--nn-paper); color: var(--nn-ink); }
.nn-btn--ghost { background: transparent; color: var(--nn-ink); }
.nn-btn--ghost:hover { background: var(--nn-ink); color: var(--nn-paper); }
.nn-btn::after { content: "→"; font-family: var(--nn-font-text); font-weight: 400; }

/* ---------- Footer ---------- */
.nn-footer {
  margin-top: var(--nn-3xl);
  padding: var(--nn-xl) 0 var(--nn-l);
  border-top: var(--nn-rule-w-bold) solid var(--nn-rule);
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-ink-mute);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.nn-footer a:hover { color: var(--nn-ink); }
.nn-footer__cols {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--nn-l);
}
.nn-footer__cols h4 {
  font-family: var(--nn-font-display);
  font-size: var(--nn-step--1);
  margin: 0 0 var(--nn-s);
  color: var(--nn-ink);
}
.nn-footer__cols ul { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--nn-2xs); }
@media (max-width: 760px) {
  .nn-footer__cols { grid-template-columns: 1fr 1fr; }
}

/* ---------- Image placeholder (rare) ---------- */
.nn-img-slot {
  background:
    repeating-linear-gradient(135deg, var(--nn-paper-deep) 0 8px, var(--nn-paper-dim) 8px 16px);
  border: 1px solid var(--nn-rule-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--nn-ink-mute);
  aspect-ratio: 16 / 10;
  text-align: center;
  padding: var(--nn-s);
}

/* ---------- Pull quote ---------- */
.nn-pull {
  border-top: var(--nn-rule-w-bold) solid var(--nn-rule);
  border-bottom: var(--nn-rule-w-bold) solid var(--nn-rule);
  padding: var(--nn-l) 0;
  margin: var(--nn-xl) 0;
  font-family: var(--nn-font-display);
  font-weight: 700;
  font-size: var(--nn-step-4);
  line-height: 1.05;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.nn-pull cite {
  display: block;
  margin-top: var(--nn-s);
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  font-weight: 400;
  font-style: normal;
  color: var(--nn-ink-mute);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* ---------- Held / corrections marker (transparency) ---------- */
.nn-held {
  display: inline-block;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.2em 0.55em;
  background: var(--nn-signal);
  color: var(--nn-paper);
}

/* ---------- Archive list ---------- */
.nn-arch {
  list-style: none;
  margin: 0;
  padding: 0;
}
.nn-arch li {
  display: grid;
  grid-template-columns: 6em 1fr auto;
  gap: var(--nn-m);
  padding: var(--nn-s) 0;
  border-top: 1px solid var(--nn-rule-soft);
  align-items: baseline;
}
.nn-arch li:first-child { border-top: 0; }
.nn-arch__date {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--1);
  color: var(--nn-ink);
  letter-spacing: 0.02em;
}
.nn-arch__title {
  font-family: var(--nn-font-display);
  font-weight: 700;
  font-size: var(--nn-step-1);
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.nn-arch__count {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-ink-mute);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* ---------- Tag swatch (style guide) ---------- */
.nn-swatch {
  border: 1px solid var(--nn-rule-soft);
  padding: var(--nn-s);
  display: flex;
  flex-direction: column;
  gap: var(--nn-2xs);
}
.nn-swatch__chip {
  height: 5rem;
  border: 1px solid var(--nn-rule-soft);
}
.nn-swatch__name {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--nn-ink);
}
.nn-swatch__val {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-ink-mute);
}

/* ---------- Utilities ---------- */
.nn-link        { border-bottom: 1px solid var(--nn-ink-faint); }
.nn-link:hover  { color: var(--nn-signal); border-color: var(--nn-signal); }

/* Source link in the article kicker — shows the upstream hostname
   ("boe.es ↗", "govern.cat ↗") so the reader knows where the link
   leads before clicking. Mono font + small caps to sit alongside
   the source-id pill without competing with the headline. Always
   opens in a new tab so the fets. tab stays put. */
.nn-source-link {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.04em;
  color: var(--nn-ink-mute);
  text-decoration: none;
  border-bottom: 1px dotted currentColor;
  padding-bottom: 0.05em;
  white-space: nowrap;
}
.nn-source-link:hover {
  color: var(--nn-signal);
  border-bottom-color: var(--nn-signal);
}
.nn-text-mute   { color: var(--nn-ink-mute); }
.nn-text-faint  { color: var(--nn-ink-faint); }
.nn-text-signal { color: var(--nn-signal); }
.nn-mono        { font-family: var(--nn-font-mono); }
.nn-display-f   { font-family: var(--nn-font-display); }
.nn-text-f      { font-family: var(--nn-font-text); }
.nn-uppercase   { text-transform: uppercase; letter-spacing: 0.08em; }
.nn-center      { text-align: center; }
.nn-right       { text-align: right; }
.nn-hide        { display: none !important; }

/* ─── Live page: time-synced 4-column grid ──────────────────────────
   Each row is a (time, event_type) tuple spanning four columns:
   [time + START/END badge] [roads] [trains] [natural].
   Empty cells stay empty so the time axis aligns across all lanes —
   reading top-to-bottom across the columns gives the chronological
   order of events across the three editorial lanes.

   Mobile: CSS-only radio-tab switcher hides two of the three lane
   cells; rows where the active lane has no event are hidden via
   data-has-<lane> attributes that the row markup carries.

   The "active tab" red underline on the header only matters on
   mobile (where it indicates which lane is visible). On desktop
   all three lanes are always visible so the underline is
   misleading; suppressed via the @media block below. */

.nn-synced__radio { position: absolute; opacity: 0; pointer-events: none; }

.nn-synced__header {
  display: grid;
  grid-template-columns: 6em repeat(3, 1fr);
  gap: var(--nn-2xs);
  align-items: end;
  border-top: var(--nn-rule-w-bold) solid var(--nn-rule);
  border-bottom: var(--nn-rule-w) solid var(--nn-rule);
  padding: var(--nn-2xs) 0;
  margin-bottom: var(--nn-2xs);
}

.nn-synced__time-head { /* placeholder cell over the time column */ }

.nn-synced__lane-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--nn-3xs);
  padding: var(--nn-2xs) var(--nn-2xs);
  cursor: default;
  text-align: center;
  color: var(--nn-ink-soft);
  border-bottom: var(--nn-rule-w-bold) solid transparent;
  transition: color 120ms ease, border-color 120ms ease;
}
.nn-synced__lane-head:hover { color: var(--nn-ink); }

.nn-synced__icon svg {
  width: 1.6em; height: 1.6em;
  display: block;
}
.nn-synced__lane-label {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.nn-synced__lane-count {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-ink-faint);
}

.nn-synced__grid { display: contents; }

.nn-synced__row {
  display: grid;
  grid-template-columns: 6em repeat(3, 1fr);
  column-gap: var(--nn-2xs);
  /* No row-gap and no border between rows — the trains-column tint
     must be visually continuous top-to-bottom. The time-column on
     the left already differentiates rows; horizontal rules would
     just chop the zebra band. */
}

.nn-synced__time {
  display: flex;
  flex-direction: column;
  gap: var(--nn-3xs);
  padding: var(--nn-2xs) 0;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--1);
  color: var(--nn-ink-mute);
}
.nn-synced__time-text {
  font-weight: 700;
  color: var(--nn-ink);
}
.nn-synced__time-day {
  /* "Ahir" / "Yesterday" pill above the HH:MM for events from the
     previous local day (rolling 24h window crosses midnight). */
  font-size: var(--nn-step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--nn-ink-mute);
}
.nn-synced__row-badge {
  display: inline-block;
  align-self: flex-start;
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 2px;
}
.nn-synced__row-badge--start {
  background: var(--nn-signal);
  color: var(--nn-paper);
}
.nn-synced__row-badge--end {
  background: transparent;
  color: var(--nn-ink-mute);
  border: var(--nn-rule-w) solid var(--nn-rule);
}

.nn-synced__cell {
  min-width: 0;
  /* Vertical padding inside the cell, not on the row — so an empty
     cell still has the full row height (and its tint paints all the
     way through, giving the column visual continuity). */
  padding: var(--nn-2xs);
}
/* Zebra-vertical: tint the middle (trains) column so the eye can
   scan across rows without losing the lane it's reading. Tint the
   matching lane-head too so the column reads as a continuous band. */
.nn-synced__lane-head--trains,
.nn-synced__cell--trains { background: var(--nn-paper-dim); }

.nn-synced__note {
  margin-inline: auto;
  text-align: center;
}

.nn-synced__events {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--nn-3xs);
}
.nn-synced__event {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--nn-font-text);
  font-size: var(--nn-step-0);
  line-height: 1.35;
}
.nn-synced__event-source {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  letter-spacing: 0.04em;
  color: var(--nn-ink-mute);
}
.nn-synced__event-text {
  color: var(--nn-ink);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
a.nn-synced__event-text { border-bottom-color: var(--nn-rule); }
a.nn-synced__event-text:hover {
  border-bottom-color: var(--nn-signal);
  color: var(--nn-signal);
}
.nn-synced__event-duration {
  font-family: var(--nn-font-mono);
  font-size: var(--nn-step--2);
  color: var(--nn-ink-faint);
}

/* Mobile: tab-switcher gates BOTH the header underline and the
   per-row cell visibility. Above the breakpoint, all three columns
   are always visible — the "active tab" indicator is suppressed
   because it would be misleading (no single lane is "the visible
   one"; they all are). */
@media (max-width: 760px) {
  .nn-synced__header { grid-template-columns: 6em 1fr; }
  .nn-synced__row { grid-template-columns: 6em 1fr; }
  .nn-synced__lane-head { display: none; }
  /* Show only the active lane's header + cell on each row. */
  #nn-lane-roads:checked   ~ .nn-synced__header .nn-synced__lane-head--roads,
  #nn-lane-trains:checked  ~ .nn-synced__header .nn-synced__lane-head--trains,
  #nn-lane-natural:checked ~ .nn-synced__header .nn-synced__lane-head--natural {
    display: flex;
  }
  .nn-synced__cell { display: none; }
  #nn-lane-roads:checked   ~ .nn-synced__grid .nn-synced__cell--roads,
  #nn-lane-trains:checked  ~ .nn-synced__grid .nn-synced__cell--trains,
  #nn-lane-natural:checked ~ .nn-synced__grid .nn-synced__cell--natural {
    display: block;
  }
  /* Hide rows where the active lane has no events for this time
     slot — otherwise mobile readers scroll past many empty rows. */
  #nn-lane-roads:checked   ~ .nn-synced__grid .nn-synced__row:not([data-has-roads]),
  #nn-lane-trains:checked  ~ .nn-synced__grid .nn-synced__row:not([data-has-trains]),
  #nn-lane-natural:checked ~ .nn-synced__grid .nn-synced__row:not([data-has-natural]) {
    display: none;
  }
  /* Tab-active indicator: ONLY on mobile, where it indicates
     which lane is visible. On desktop all three are visible
     simultaneously so the underline is suppressed (cleaner). */
  #nn-lane-roads:checked   ~ .nn-synced__header .nn-synced__lane-head--roads,
  #nn-lane-trains:checked  ~ .nn-synced__header .nn-synced__lane-head--trains,
  #nn-lane-natural:checked ~ .nn-synced__header .nn-synced__lane-head--natural {
    color: var(--nn-ink);
    border-bottom-color: var(--nn-signal);
  }
  .nn-synced__lane-head { padding: var(--nn-3xs); cursor: pointer; }
  .nn-synced__lane-label { font-size: var(--nn-step--3); }
}
