/* =========================================================================
   PowerLeaks — public news site. Brand design system (self-hosted fonts).
   Power Blue #1E3A8A · Power Red #D71920 · Ink #111111 · Off-White #F8FAFC.
   Display = Archivo Black (ALL CAPS) · Body = Inter · Metadata = JetBrains Mono.
   Flat, high-contrast, hard-edged — newsroom, not lifestyle. No gradients/pastels.
   ========================================================================= */

/* Self-hosted OFL brand fonts (relative URLs → resolve against /news/ on the public site AND against
   API_BASE/news/ inside the dashboard ArticlePreviewFrame iframe). */
@font-face { font-family: "Archivo Black"; src: url("fonts/Archivo-Black.c1a36cce93e75bb56a9502e384249d8dd6a20189053d1628b12274bcb8437ae1.woff2") format("woff2");
  font-weight: 900; font-display: swap; }
@font-face { font-family: "Inter"; src: url("fonts/Inter-Regular.338239f6b590b8ced3bf857654d32da3fd3663294cd3003651ed57aa3abd7aa1.woff2") format("woff2");
  font-weight: 400; font-display: swap; }
@font-face { font-family: "Inter"; src: url("fonts/Inter-Medium.7e80d9f65861ee6836a0081d4e75d88fb8789e5651d05edbc49640442a9610ee.woff2") format("woff2");
  font-weight: 500; font-display: swap; }
@font-face { font-family: "Inter"; src: url("fonts/Inter-Bold.98c66e49c299c5675426bf5562b1876c2b6b9bd8dc90a8922a49703ed4848813.woff2") format("woff2");
  font-weight: 700; font-display: swap; }
@font-face { font-family: "JetBrains Mono"; src: url("fonts/JetBrainsMono-Regular.f1a7a03672cdd494ce0d5543fac6e4360fe22403c6de297fdc2e55a815f7baff.woff2") format("woff2");
  font-weight: 400; font-display: swap; }

:root {
  /* Brand palette (--pl-* is the canonical token set). */
  --pl-power-blue: #1E3A8A;
  --pl-power-red: #D71920;
  --pl-ink-black: #111111;
  --pl-off-white: #F8FAFC;
  --pl-white: #FFFFFF;
  --pl-steel-gray: #C0C2C4;
  --pl-press-blue: #0F1D45;
  --pl-press-red: #8F0F14;
  --pl-ink-muted: rgba(17, 17, 17, 0.62);   /* muted metadata/dek text — steel-gray fails contrast on off-white */

  /* Legacy aliases so the 60+ existing var() references keep working. */
  --blue: var(--pl-power-blue);
  --red: var(--pl-power-red);
  --red-dark: var(--pl-press-red);
  --ink: var(--pl-ink-black);
  --gray-700: var(--pl-ink-black);   /* body copy → true ink */
  --gray-500: var(--pl-ink-muted);   /* metadata / dek */
  --gray-200: var(--pl-steel-gray);  /* hairline borders */
  --off-white: var(--pl-off-white);
  --white: var(--pl-white);

  --maxw: 1120px;
  --radius: 0;          /* hard-edged "news-sharp" — no rounded cards */
  --radius-sm: 0;
  --shadow: none;
  --shadow-hover: none;
  --font-display: "Archivo Black", "Arial Black", Impact, sans-serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
  --font: var(--font-body);   /* legacy alias */
}

* { box-sizing: border-box; }

/* The [hidden] attribute must win over any explicit display: (grid/flex) on these components,
   otherwise show()/hide() in app.js can't actually hide the hero, grid, pager, etc. */
[hidden] { display: none !important; }

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

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--off-white);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: inherit; text-decoration: none; }

img, video { max-width: 100%; display: block; }

.skip-link {
  position: absolute; left: -999px; top: 0;
  background: var(--ink); color: var(--white);
  padding: 10px 16px; z-index: 100;
}
.skip-link:focus { left: 0; }

:focus-visible { outline: 2px solid var(--pl-power-blue); outline-offset: 2px; }

/* Shared display-headline treatment: Archivo Black, ALL CAPS, tight tracking. Titles are injected via
   textContent from the DB (sentence case) — CSS does the casing so the stored title stays editable. */
.hero__headline, .card__headline, .article__headline {
  font-family: var(--font-display); font-weight: 400;
  text-transform: uppercase; letter-spacing: -0.01em;
}

/* Uppercase mono metadata (bylines, meta lines, captions, section/source labels). */
.meta, .article__byline, .figure figcaption, .sources__title {
  font-family: var(--font-mono); text-transform: uppercase; letter-spacing: .03em;
}

/* Editorial eyebrow / kicker — the small uppercase mono line above a headline. */
.kicker, .article__kicker, .hero__kicker, .card__kicker {
  font-family: var(--font-mono); font-size: 12px; font-weight: 400;
  text-transform: uppercase; letter-spacing: .14em; color: var(--pl-power-red);
  margin: 0 0 8px;
}
.card__kicker { font-size: 11px; margin: 0 0 4px; }

/* Signature accent underline on a headline run. */
.accent-underline {
  text-decoration: underline; text-decoration-color: var(--pl-power-red);
  text-decoration-thickness: .12em; text-underline-offset: .08em;
}

/* LiveIndicator — a pulsing red dot (replaces the old bolt emoji). */
.live-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--pl-power-red); flex: none; animation: pl-pulse 1.6s ease-in-out infinite;
}
@keyframes pl-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }

/* Verified badge — the brand trust mark (blue), distinct from the red fact-check verdict badge. */
.verified-badge {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--pl-power-blue); color: var(--pl-white);
  font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
  padding: 3px 7px;
}
/* Fact-check credibility badge — colored BY the verdict so a fact-checked TRUE story never wears an
   alarm-red stamp. Green = confirmed true, amber = mixed/unverified (a leak with no coverage yet),
   red = false/disputed. Default (unknown) is a neutral slate. */
.verdict-badge {
  /* align-self keeps it a compact pill inside .card__body (a column flexbox stretches children by
     default); in the article header's inline-flex row it's a no-op. */
  display: inline-block; align-self: flex-start;
  background: #64748b; color: var(--pl-white);
  font-family: var(--font-mono); font-size: 11px; font-weight: 400;
  text-transform: uppercase; letter-spacing: .04em; padding: 4px 9px;
}
.verdict-badge--true { background: #15803d; }              /* confirmed true */
.verdict-badge--false { background: var(--pl-power-red); } /* false / disputed */
.verdict-badge--caution { background: #b45309; }           /* mixed / unverified / questionable */

/* ============================== NAV ============================== */
.nav {
  position: sticky; top: 0; z-index: 40;
  background: var(--white);
  border-bottom: 1px solid var(--gray-200);
}
.nav__inner {
  max-width: var(--maxw); margin: 0 auto;
  display: flex; align-items: center; gap: 18px;
  padding: 14px 20px;
}
.logo { display: inline-flex; align-items: center; }
.logo__img { height: 30px; width: auto; }
.logo__fallback { display: none; align-items: center; gap: 9px; }
.logo__bolt {
  width: 22px; height: 26px; flex: none;
  background: linear-gradient(135deg, var(--red) 0 50%, var(--blue) 50% 100%);
  clip-path: polygon(55% 0, 0 58%, 42% 58%, 30% 100%, 100% 40%, 55% 40%);
}
.logo__word { font-family: var(--font-display); font-size: 20px; letter-spacing: -0.01em; color: var(--ink); text-transform: uppercase; }
.logo__word--leaks { font-weight: 400; }

.nav__links { display: none; gap: 26px; margin-left: 18px; }
.nav__link { font-family: var(--font-mono); font-weight: 400; font-size: 13px; text-transform: uppercase; letter-spacing: .05em; color: var(--gray-500); padding: 6px 0; position: relative; }
.nav__link:hover { color: var(--ink); }
.nav__link--active { color: var(--ink); }
.nav__link--active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 2px; background: var(--red);
}

.nav__actions { display: flex; align-items: center; gap: 10px; }
.iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  border: 1px solid var(--gray-200); background: var(--white); color: var(--ink);
  cursor: pointer; transition: background .15s, border-color .15s;
}
.iconbtn:hover { background: var(--off-white); border-color: var(--pl-steel-gray); }

/* Opening choreography, composited. The box CHANGES THE SPACE IT OCCUPIES — pushing the nav aside is the
   interaction — and nothing that reflows siblings can be animated off the main thread. So the layout change
   happens ONCE, instantly, and the motion the reader actually sees rides on `transform` + `opacity`, which
   the compositor owns: ~24 relayouts per open (0.4s at 60fps) become 1.
     open  -> max-width / flex-basis snap to full (one layout), then the box slides 14px right into its
              flush-right resting place and fades up. The offset is NEGATIVE on purpose: a transform does
              not reflow, but it does create VISUAL overflow, and `.nav__inner` does not clip while nothing
              guards `overflow-x` on body — so nudging a right-anchored box outward could raise a horizontal
              scrollbar on a viewport narrower than --maxw. Moving inward never can.
     close -> it slides and fades out FIRST; the collapse is delayed (`0s linear .4s`) to land after it.
   The trade-off, taken deliberately: the nav links snap aside once instead of gliding with the box.
   `padding` is constant. `* { box-sizing: border-box }` (:55) puts it inside the width, so at `max-width: 0`
   it is already clipped to nothing — animating it was a second layout property doing no visual work. */
.nav__search {
  display: flex; align-items: center; gap: 10px; overflow: hidden;
  flex: 0 1 0; max-width: 0; min-width: 0; opacity: 0; visibility: hidden;
  margin-left: auto;
  background: var(--off-white); border: 1px solid var(--gray-200);
  padding: 9px 16px;
  transform: translateX(-14px);
  /* visibility AND both layout properties flip only after the fade, so the box keeps its full size and
     stays interactive the whole way out — nothing is clipped mid-animation. */
  transition: transform .4s cubic-bezier(.22,.61,.36,1), opacity .28s ease,
              max-width 0s linear .4s, flex-basis 0s linear .4s, visibility 0s linear .4s;
}
.nav--searching .nav__search,
.nav__search:focus-within {
  flex: 0 1 360px; max-width: 360px; opacity: 1; visibility: visible;
  transform: none;
  /* opening: take the space immediately (0s, no delay), then play the slide + fade into it. */
  transition: transform .4s cubic-bezier(.22,.61,.36,1), opacity .28s ease .06s,
              max-width 0s, flex-basis 0s, visibility 0s;
}
/* The house invariant: every animation ships an off-switch — the search box still opens, it just arrives
   instead of sweeping.

   SPECIFICITY IS LOAD-BEARING HERE, and a bare `.nav__search` guard silently did only half the job. The
   OPEN state (`.nav--searching .nav__search`, `.nav__search:focus-within` — 0-2-0) declares its own
   `transition`, so a 0-1-0 guard loses to it on specificity no matter where it sits in the file: the
   collapse was suppressed while the 0.4s open sweep still played for a reader who had asked for no motion.
   Every selector that SETS a transition needs a counterpart here. A media query adds NO specificity, so
   each guard must also sit AFTER the rules it overrides — the magnifier's own guard therefore lives down
   beside #search-toggle rather than here. */
@media (prefers-reduced-motion: reduce) {
  .nav__search,
  .nav--searching .nav__search,
  .nav__search:focus-within { transition: none; }
}
.nav__search-icon { color: var(--gray-500); flex: none; }
.nav__search-input {
  /* 16px is NOT a style choice here, it is the iOS Safari threshold. WebKit zooms the whole page in when a
     form control with a computed font-size under 16px takes focus, so it can render the text at 16px — and
     it does NOT zoom back out on blur. At 15px an iPhone reader who taps search was left on a permanently
     magnified site, with the nav and article overflowing, and no obvious way back short of pinching.
     This is the only form control on the public site, so one declaration closes it.
     Deliberately NOT fixed with `maximum-scale=1` / `user-scalable=no` in the viewport meta: that stops the
     zoom by disabling pinch-zoom for everyone, which fails WCAG 1.4.4 and hurts the readers who need it. */
  flex: 1; min-width: 0; border: 0; outline: none; font: inherit; font-size: 16px;
  background: transparent; color: var(--ink);
}
.nav__search-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.nav__search-input { -webkit-appearance: none; appearance: none; }
.nav__search-input::placeholder { color: var(--gray-500); }
.nav__search-clear {
  border: 0; background: transparent; color: var(--gray-500);
  width: 24px; height: 24px; border-radius: 50%; font-size: 20px; line-height: 1; cursor: pointer; flex: none;
}
.nav__search-clear:hover { background: var(--gray-200); color: var(--ink); }
/* Keep the toggle in the layout while searching — display:none would fire a mouseleave the instant the box
   opens under the cursor, flickering the hover-to-open. Fade it out smoothly in sync with the box opening
   (the base .iconbtn only transitions background/border, so without this the magnifier SNAPS away). */
#search-toggle { transition: background .15s, border-color .15s, opacity .28s ease, visibility 0s; }
.nav--searching #search-toggle { visibility: hidden; opacity: 0; pointer-events: none; transition: opacity .24s ease, visibility 0s linear .24s; }
/* The magnifier's half of the house off-switch. It sits HERE, not up with the .nav__search guard: a media
   query carries no specificity of its own, so an id-selector rule declared further down the file would beat
   an identical guard placed above it. Same rule, wrong line, silently no effect. */
@media (prefers-reduced-motion: reduce) {
  #search-toggle,
  .nav--searching #search-toggle { transition: none; }
}

/* ============================== LAYOUT ============================== */
/* min-height: the story grid is rendered by app.js after /blog/posts answers. Holding a full viewport keeps the
   footer below the fold until then, so its drop past the grown feed is not a visible layout shift (the tall
   carousel-cover cards took Lighthouse CLS from 0.08 to 0.125 without it). */
.home { max-width: var(--maxw); margin: 0 auto; padding: 22px 20px 60px; min-height: 100vh; }

.state { text-align: center; padding: 60px 16px; color: var(--gray-500); }
.state h2 { color: var(--ink); font-size: 22px; margin: 0 0 8px; }

/* Designed empty/error states — the client-side #article-404 / #home-error / #home-empty /
   #home-noresults blocks AND the standalone /404 page share this treatment. Flat, hard-edged,
   brand-forward newsroom look (radius 0, no gradients).

   These rules come from milestone2 and CLOSE A REAL GAP: `state--error` / `state--empty` are applied in
   index.html and article.html on both branches, but this branch styled NEITHER — so every error and empty
   state on the public site fell through to the bare `.state` default and rendered as small grey centred
   text. */
.state--error,
.state--empty {
  max-width: 620px;
  margin: 0 auto;
  padding: 84px 20px 96px;
}
.state--error h2,
.state--empty h2 {
  font-family: var(--font-display); font-weight: 400;
  text-transform: uppercase; letter-spacing: -0.01em; line-height: 1.1;
  font-size: clamp(24px, 4vw, 32px);
}
.state--error p,
.state--empty p {
  font-size: 16px; max-width: 46ch; margin: 0 auto; color: var(--gray-500);
}
/* The big status numeral — Archivo-Black, brand red, with a blunt blue accent bar (echoes the
   brand AccentUnderline motif). NOT the muted-gray default text.
   This carries its own accent, so the separate `.state__rule` bar below is redundant WHEN used with it;
   the rule is kept defined because 404.html still emits the element and other surfaces may use it alone. */
.state__code {
  display: inline-block;
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(72px, 15vw, 120px); line-height: 0.82; letter-spacing: -0.02em;
  color: var(--red);
  margin: 0 0 22px; padding-bottom: 12px;
  border-bottom: 6px solid var(--blue);
}
/* A standalone brand rule for surfaces that want the bar WITHOUT the numeral. Immediately after a
   `.state__code` it would double the accent, so it collapses there. */
.state__rule { width: 72px; height: 6px; background: var(--red); margin: 0 auto 20px; }
.state__code + .state__rule { display: none; }
.btn {
  margin-top: 14px; border: 0; cursor: pointer;
  background: var(--red); color: var(--white); font-family: var(--font-mono); font-weight: 400;
  text-transform: uppercase; letter-spacing: .05em;
  padding: 11px 20px; font-size: 14px;
}
.btn:hover { background: var(--red-dark); }

/* ============================== HERO ============================== */
.hero {
  display: grid; grid-template-columns: 1fr; gap: 22px;
  background: var(--white); border: 1px solid var(--gray-200);
  padding: 22px; margin-bottom: 34px;
}
.hero__body { display: flex; flex-direction: column; }
.hero__media {
  position: relative; overflow: hidden;
  background: var(--pl-steel-gray); aspect-ratio: 16 / 10;
}
.hero__media img, .hero__media video, .hero__media iframe { width: 100%; height: 100%; object-fit: cover; border: 0; }
.tag {
  display: inline-block; font-family: var(--font-mono); font-size: 11px; font-weight: 400; letter-spacing: .06em;
  text-transform: uppercase; color: var(--white); background: var(--red);
  padding: 5px 10px; align-self: flex-start;
}
.tag--blue { background: var(--blue); }
.tag--ink { background: var(--ink); }
.tag--outline { background: var(--white); color: var(--ink); border: 1.5px solid var(--ink); }
.hero__tag { margin-bottom: 16px; }
.hero__headline {
  font-size: clamp(26px, 5vw, 40px); line-height: 1.05;
  margin: 0 0 14px; color: var(--ink);
}
.hero__headline a:hover { text-decoration: underline; text-decoration-color: var(--pl-power-red); text-decoration-thickness: .1em; text-underline-offset: .08em; }
.hero__dek { font-size: 17px; color: var(--gray-500); margin: 0 0 18px; max-width: 46ch; }
.meta { font-size: 12px; color: var(--gray-500); margin: 0; }
.meta__dot { margin: 0 7px; }
.hero__meta { margin-bottom: 20px; }
.hero__cta { display: flex; align-items: center; gap: 14px; margin-top: auto; }
.cta-btn {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--red); color: var(--white); font-family: var(--font-mono); font-weight: 400; font-size: 14px;
  text-transform: uppercase; letter-spacing: .05em;
  padding: 12px 22px; transition: background .15s, transform .15s;
}
.cta-btn:hover { background: var(--red-dark); transform: translateY(-1px); }
.cta-btn__arrow { transition: transform .15s ease; }
.cta-btn:hover .cta-btn__arrow { transform: translateX(3px); }
/* .cta-arrow retained for any legacy markup; the arrow now lives inside .cta-btn. */
.cta-arrow {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%; border: 1.5px solid var(--gray-200); color: var(--blue);
}

/* ============================== SECTION HEADING ============================== */
.section-heading { display: flex; align-items: center; gap: 14px; margin: 6px 0 18px; }
.section-heading__title {
  font-family: var(--font-mono); font-size: 13px; font-weight: 400; text-transform: uppercase; letter-spacing: .08em;
  margin: 0; color: var(--ink); display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
}
.section-heading__bolt { color: var(--red); }
.section-heading__line { flex: 1; height: 1px; background: var(--gray-200); }

/* ============================== GRID + CARDS ============================== */
.grid { display: grid; grid-template-columns: 1fr; gap: 22px; }

.card {
  background: var(--white); border: 1px solid var(--gray-200);
  overflow: hidden;
  display: flex; flex-direction: column; transition: transform .18s, border-color .18s;
  position: relative;
}
.card:hover { transform: translateY(-2px); border-color: var(--pl-ink-black); }
.card__media { position: relative; aspect-ratio: 16 / 10; background: var(--pl-steel-gray); }
.card__media img, .card__media video, .card__media iframe { width: 100%; height: 100%; object-fit: cover; border: 0; }
/* Scrim so an overlaid chip stays legible over a photo. */
.card__media::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 64px; pointer-events: none;
  background: linear-gradient(to top, rgba(17, 17, 17, 0.55), transparent);
}
.card__tag { position: absolute; left: 10px; bottom: 10px; z-index: 1; }
.card__body { padding: 14px 15px 16px; display: flex; flex-direction: column; gap: 8px; }
.card__headline {
  font-size: 16px; line-height: 1.12; margin: 0; color: var(--ink);
  /* Clamp very long titles so a card's height stays sane (the .card__hit overlay is absolute, unaffected). */
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.card:hover .card__headline { color: var(--red); }
.card__hit { position: absolute; inset: 0; }
.card__dek {
  font-size: 14px; color: var(--gray-500); margin: 0; line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.card__meta { margin-top: 2px; }

/* A DELIBERATE branded plate for image-less stories — a two-desk gradient + faint diagonal weave + the
   wordmark — so a wall of them reads as intentional house style, not a field of broken/empty boxes. */
.card__media--placeholder, .hero__media--placeholder {
  display: grid; place-items: center; position: relative; overflow: hidden;
  background:
    radial-gradient(120% 120% at 100% 0%, rgba(158, 27, 46, .30), transparent 55%),
    linear-gradient(150deg, var(--pl-press-blue), #0b0b0e 72%);
}
.card__media--placeholder::after, .hero__media--placeholder::after {
  content: ""; position: absolute; inset: 0; height: auto;
  background: repeating-linear-gradient(135deg, rgba(255, 255, 255, .035) 0 2px, transparent 2px 10px);
}
/* The wordmark app.js leaves when the placeholder art itself fails. :not(.tag) keeps the card's topic chip on
   its own .card__tag bottom-left placement instead of this centred, relative wordmark rule. */
.card__media--placeholder span:not(.tag), .hero__media--placeholder span:not(.tag) {
  position: relative; z-index: 1;
  font-family: var(--font-display); font-weight: 800; letter-spacing: .18em; text-transform: uppercase;
  color: rgba(255, 255, 255, .30);
}
.card__media--placeholder span:not(.tag) { font-size: 15px; }
.hero__media--placeholder span:not(.tag) { font-size: 30px; }
.branded-hero-placeholder {
  display: block; width: 100%; height: 100%; object-fit: cover; border: 0;
}
.card__media--placeholder .branded-hero-placeholder,
.hero__media--placeholder .branded-hero-placeholder { position: absolute; inset: 0; z-index: 0; }

/* ============================== PAGINATION ============================== */
.pager { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 40px; flex-wrap: wrap; }
.pager__btn {
  min-width: 38px; height: 38px; padding: 0 12px;
  border: 1px solid var(--gray-200); background: var(--white); color: var(--gray-500);
  font: inherit; font-family: var(--font-mono); font-weight: 400; font-size: 14px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; transition: background .15s, border-color .15s;
}
.pager__btn:hover:not(:disabled) { background: var(--off-white); border-color: var(--pl-ink-black); }
.pager__btn--active { background: var(--red); border-color: var(--red); color: var(--white); }
.pager__btn:disabled { opacity: .4; cursor: default; }
.pager__gap { color: var(--gray-500); padding: 0 4px; }

.result-summary {
  min-height: 1.5em; margin: -10px 0 18px;
  color: var(--gray-500); font-family: var(--font-mono); font-size: 12px;
  text-transform: uppercase; letter-spacing: .04em;
}

/* Trust pages keep the newsroom's hard rules and mono evidence labels, but give policy copy a quiet,
   readable measure. The red left rule is the one signature carried over from article pull quotes. */
.trust-page { max-width: 760px; margin: 0 auto; padding: 56px 20px 80px; }
.trust-page__eyebrow { margin: 0 0 8px; color: var(--pl-power-red); font: 12px var(--font-mono); text-transform: uppercase; letter-spacing: .12em; }
.trust-page > h1 { margin: 0 0 20px; font: 400 clamp(34px, 7vw, 58px)/1 var(--font-display); text-transform: uppercase; letter-spacing: -.02em; }
.trust-page__lead { margin: 0 0 42px; padding-left: 20px; border-left: 4px solid var(--pl-power-red); color: var(--ink); font-size: clamp(19px, 3vw, 23px); line-height: 1.5; }
.trust-page section { padding: 24px 0; border-top: 1px solid var(--gray-200); }
.trust-page section h2 { margin: 0 0 8px; font: 400 20px/1.2 var(--font-display); text-transform: uppercase; }
.trust-page section p { margin: 0; color: var(--gray-500); font-size: 17px; line-height: 1.75; }
.trust-page__links { display: flex; flex-wrap: wrap; gap: 10px 20px; margin-top: 26px; padding-top: 20px; border-top: 2px solid var(--ink); font: 12px var(--font-mono); text-transform: uppercase; }
.trust-page__links a { color: var(--blue); text-decoration: underline; text-underline-offset: 3px; }
.trust-page section p a { color: var(--blue); text-decoration: underline; text-underline-offset: 3px; }

/* ============================== FOOTER ============================== */
.site-footer { background: var(--ink); color: var(--pl-steel-gray); margin-top: 50px; }
.site-footer__inner { max-width: var(--maxw); margin: 0 auto; padding: 46px 20px 30px; }
/* minmax(0, …): the subscribe row's intrinsic width must not widen the phone track past the viewport. */
.footer-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 32px; }
.footer-brand { max-width: 42ch; }
.site-footer__mark { font-family: var(--font-display); font-size: 22px; letter-spacing: -0.01em; margin: 0 0 6px; color: var(--white); text-transform: uppercase; }
.site-footer__mark span { font-weight: 400; }
.site-footer__tagline { color: var(--pl-steel-gray); font-family: var(--font-mono); font-weight: 400; font-size: 13px; text-transform: uppercase; letter-spacing: .05em; margin: 0 0 10px; }
.site-footer__note { color: var(--pl-steel-gray); font-size: 14px; line-height: 1.6; margin: 0 0 18px; }

.footer-social { display: flex; gap: 10px; }
.social {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px;
  background: rgba(255, 255, 255, 0.08); color: var(--white); transition: background .15s, transform .15s;
}
.social:hover { background: var(--red); transform: translateY(-2px); }

.footer-col { display: flex; flex-direction: column; gap: 11px; }
.footer-col__title {
  font-family: var(--font-mono); font-size: 12px; font-weight: 400; text-transform: uppercase; letter-spacing: .1em;
  color: var(--white); margin: 0 0 4px;
}
.footer-col a { color: var(--pl-steel-gray); font-size: 14px; }
.footer-col a:hover { color: var(--white); }

.footer-bottom {
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: space-between; align-items: center;
  margin-top: 36px; padding-top: 20px; border-top: 1px solid rgba(255, 255, 255, 0.1);
  font-family: var(--font-mono); font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--pl-steel-gray);
}
.footer-bottom__tag { font-weight: 400; color: var(--pl-steel-gray); }

@media (min-width: 720px) {
  .footer-grid { grid-template-columns: 2fr 1fr 1fr 1fr; gap: 40px; }
}

/* ============================== ARTICLE ============================== */
.article { max-width: 720px; margin: 0 auto; padding: 30px 20px 70px; min-width: 0; }
.article__header { margin-bottom: 22px; }
.article__label { margin-bottom: 12px; display: inline-flex; align-items: center; gap: 10px; }
.article__headline { font-size: clamp(24px, 5vw, 38px); line-height: 1.06; margin: 0 0 14px; }
.article__dek { font-size: 19px; color: var(--gray-500); margin: 0 0 16px; }
.article__byline { font-size: 12px; color: var(--gray-500); margin: 0; padding-bottom: 18px; border-bottom: 2px solid var(--ink); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* A hero is a full-width STAGE, not a fixed crop. The image keeps its intrinsic ratio and is bounded by
   both the article column and the visible viewport, so a landscape, square, 4:5 carousel cover, or portrait
   source photo is always shown in full. Width:auto also avoids needlessly upscaling a small source asset. */
.article__hero {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  width: 100%; max-width: 100%; min-width: 0; margin: 24px auto; overflow: hidden;
  background: transparent;
}
.article__hero img {
  display: block; width: auto; max-width: 100%; height: auto;
  max-height: min(76svh, 760px); margin: 0 auto; object-fit: contain; border: 0;
}
.article__hero video, .article__hero iframe {
  display: block; width: 100%; max-width: 100%; height: auto; margin: 0 auto;
  object-fit: contain; border: 0;
}
/* An iframe (YouTube embed) has no intrinsic aspect, so pin 16:9 or it collapses to a sliver. */
.article__hero iframe { aspect-ratio: 16 / 9; }
.article__hero--video { width: 100%; }
/* A missing workflow hero still gets one bounded, local stage so every Blog keeps its visual rhythm. This
   contains no remote/sentinel image URL; reviewed media replaces it without changing the article structure. */
.article__hero--placeholder {
  min-height: 180px; aspect-ratio: 16 / 9; max-height: min(76svh, 760px);
  border-top: 4px solid var(--pl-power-red); background: var(--pl-ink-black); color: var(--pl-white);
}
.article__hero--placeholder .branded-hero-placeholder {
  width: 100%; max-width: 100%; height: 100%; max-height: min(76svh, 760px); object-fit: contain;
}
.article__hero-placeholder {
  display: grid; width: 100%; height: 100%; grid-template-columns: auto minmax(0, 1fr);
  align-content: center; align-items: center; gap: clamp(14px, 3vw, 24px); padding: clamp(18px, 4vw, 34px);
}
.article__hero-placeholder-mark {
  display: grid; width: 56px; height: 56px; place-items: center;
  background: var(--pl-power-blue); color: var(--pl-white);
  font: 400 22px/1 var(--font-display); letter-spacing: -.03em;
}
.article__hero-placeholder-copy { display: grid; gap: 4px; min-width: 0; }
.article__hero-placeholder-copy strong {
  font: 400 clamp(18px, 4vw, 24px)/1.1 var(--font-display); text-transform: uppercase;
}
.article__hero-placeholder-copy > span {
  color: var(--pl-steel-gray); font: 500 11px/1.5 var(--font-mono); letter-spacing: .08em; text-transform: uppercase;
}
/* A published snapshot may name a real third-party hero that later becomes unavailable. Keep that failure
   distinct from the intentional text-report/placeholder sentinel: replace only the failed declared media
   with a compact, accessible stage instead of silently collapsing the article or showing a broken icon. */
.article__hero--unavailable {
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-content: center; align-items: center;
  gap: clamp(14px, 3vw, 24px); min-height: 180px; max-height: 300px; aspect-ratio: 16 / 9;
  padding: clamp(18px, 4vw, 34px); border-top: 4px solid var(--pl-power-red);
  background: var(--pl-ink-black); color: var(--pl-white);
}
.article__hero--unavailable .branded-hero-placeholder { grid-column: 1 / -1; }
.article__hero-unavailable-mark {
  display: grid; width: 56px; height: 56px; place-items: center; flex: none;
  background: var(--pl-power-blue); color: var(--pl-white);
  font: 400 22px/1 var(--font-display); letter-spacing: -.03em;
}
.article__hero-unavailable-copy { display: grid; gap: 4px; min-width: 0; }
.article__hero-unavailable-copy strong {
  font: 400 clamp(18px, 4vw, 24px)/1.1 var(--font-display); text-transform: uppercase;
}
.article__hero-unavailable-copy > span { color: var(--pl-steel-gray); font-size: 13px; line-height: 1.5; }
/* Section heading for the scraped source images gallery */
.article__media-heading {
  font-family: var(--font-mono); font-size: 13px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink); margin: 0 0 16px; font-weight: 400;
}
.article__body { min-width: 0; font-size: 18px; line-height: 1.75; color: var(--gray-700); overflow-wrap: anywhere; }
.article__body p { margin: 0 0 1.2em; }
.article__body h2, .article__body h3 { color: var(--ink); font-family: var(--font-display); text-transform: uppercase; letter-spacing: -0.01em; line-height: 1.15; margin: 1.6em 0 .5em; }
.article__body a { color: var(--blue); text-decoration: underline; text-underline-offset: 2px; }
.article__body img, .article__body video, .article__body iframe { max-width: 100%; }
.article__body img, .article__body video { height: auto; }
.article__body iframe { width: 100%; aspect-ratio: 16 / 9; border: 0; }
.article__body pre, .article__body table {
  display: block; max-width: 100%; overflow-x: auto; overscroll-behavior-inline: contain;
  -webkit-overflow-scrolling: touch;
}
.article__body pre { padding: 14px; background: var(--pl-white); border: 1px solid var(--gray-200); }
.article__body code { overflow-wrap: anywhere; }
.article__body mark { background: none; color: inherit; border-bottom: 3px solid var(--pl-power-red); padding: 0; }
.article__body u { text-decoration-thickness: 1.5px; text-underline-offset: 3px; }
.article__body s { color: var(--gray-500); }
/* Two red-barred quote treatments that share the brand's red left-bar but NOT the voice:
   - .article__pullquote (the :::pullquote fence) is the SIGNATURE — the one sharpest line the newsroom
     amplifies, set loud in Archivo ALL-CAPS. Spend the boldness here, once.
   - a plain body <blockquote> is a PERSON SPEAKING — kept quiet (Inter, sentence case, a notch above body)
     so a spoken quote doesn't read as shouting and the pull stays singular.
   The :not() keeps the pullquote out of the quiet rule: a pullquote IS a <blockquote class="article__pullquote">,
   and `.article__body blockquote` (0,1,1) would otherwise out-specify `.article__pullquote` (0,1,0). */
.article__pullquote {
  border-left: 4px solid var(--pl-power-red); padding: .2em 0 .2em 22px; margin: 1.8em 0;
  font-family: var(--font-display); font-size: 25px; line-height: 1.24; text-transform: uppercase;
  color: var(--ink);
}
.article__body blockquote:not(.article__pullquote) {
  border-left: 4px solid var(--pl-power-red); padding: .1em 0 .1em 20px; margin: 1.5em 0;
  font-family: var(--font-body); font-weight: 500; font-size: 20px; line-height: 1.5;
  color: var(--ink);
}
.article__media { display: grid; gap: 20px; margin: 28px 0; }
.figure { margin: 0; }
.figure img, .figure video, .figure iframe {
  display: block; width: 100%; height: auto; max-height: 620px; object-fit: contain;
  background: var(--pl-steel-gray);
}
.figure.article__hero img {
  width: auto; max-width: 100%; height: auto; max-height: min(76svh, 760px);
  object-fit: contain; background: transparent;
}
.figure iframe { aspect-ratio: 16 / 9; max-height: none; border: 0; }
.article__inline-media { margin: 30px 0; }
.figure figcaption { font-size: 12px; color: var(--gray-500); margin-top: 6px; }
.people { font-size: 14px; color: var(--gray-500); margin: 26px 0 0; }
.people__label { font-weight: 700; color: var(--ink); }
.tags { display: flex; flex-wrap: wrap; gap: 8px; margin: 18px 0 0; }
.tags .tag {
  background: var(--off-white); color: var(--gray-500); border: 1px solid var(--gray-200);
  font-family: var(--font-mono); text-transform: none; letter-spacing: 0; font-weight: 400;
}
.sources { margin: 34px 0 0; padding-top: 20px; border-top: 1px solid var(--gray-200); }
.sources__title { font-size: 12px; text-transform: uppercase; letter-spacing: .08em; color: var(--gray-500); margin: 0 0 12px; }
.sources__trust { margin: -4px 0 14px; color: var(--gray-500); font: 12px/1.5 var(--font-mono); letter-spacing: .02em; }
.sources__trust[data-corroborated="true"]::before { content: "Corroborated · "; color: var(--blue); font-weight: 700; }
.sources__trust[data-corroborated="false"]::before { content: "Evidence record · "; color: var(--gray-500); font-weight: 700; }
.sources__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.sources__link { color: var(--blue); overflow-wrap: anywhere; }
.sources__link:hover { text-decoration: underline; }
.back-link { display: inline-flex; align-items: center; gap: 6px; color: var(--gray-500); font-family: var(--font-mono); font-weight: 400; text-transform: uppercase; letter-spacing: .04em; font-size: 12px; margin-bottom: 18px; }
.back-link:hover { color: var(--red); }
.article-back { min-height: 44px; justify-content: center; white-space: nowrap; }

/* states reused on the article page */
.article .state { max-width: 720px; }

/* ============================== READING PROGRESS (article) ============================== */
/* Full width, scaled from the left — NOT an animated `width`. This bar is written on every scroll event,
   so animating a layout property relaid out the page on each frame; a transform is composited instead.
   Visually identical: it is a solid rectangle, so scaleX has nothing to distort. */
.reading-progress {
  position: absolute; left: 0; bottom: -3px; height: 3px; width: 100%;
  transform: scaleX(0); transform-origin: 0 50%;
  background: var(--pl-power-red);
  z-index: 60; transition: transform .08s linear; will-change: transform;
}
@media (prefers-reduced-motion: reduce) { .reading-progress { transition: none; } }

/* ============================== SHIMMER SKELETONS ============================== */
.skeleton { position: relative; overflow: hidden; background: #eceef2; }
.skeleton::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.65), transparent);
  animation: shimmer 1.3s infinite;
}
@keyframes shimmer { 100% { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .skeleton::after { animation: none; } }

.skel-hero { margin-bottom: 34px; }
.skel-tag { display: block; width: 84px; height: 22px; margin-bottom: 16px; }
.skel-line { display: block; height: 16px; margin-bottom: 12px; }
.skel-line--xl { height: 30px; }
.skel-btn { display: block; width: 150px; height: 44px; margin-top: 8px; }
.skel-media { width: 100%; aspect-ratio: 16 / 10; }
.skel-card .skel-media { border-radius: 0; }
.skel-card { border: 1px solid var(--gray-200); overflow: hidden; background: var(--white); }
.skel-card__body { padding: 14px 15px 16px; }

/* ============================== RESPONSIVE ============================== */
@media (min-width: 600px) {
  .grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 720px) {
  .nav__links { display: flex; }
  .hero { grid-template-columns: 1fr 1.05fr; align-items: center; padding: 28px; gap: 30px; }
  .hero__body { order: 0; }
  .hero__media { order: 1; aspect-ratio: 4 / 3; }
}
@media (min-width: 1040px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
  .home { padding-top: 30px; }
}

/* ============================== PORTRAIT MEDIA (ALL WIDTHS) ==============================
   Images arrive as bare URLs with NO dimensions, and the generated 16:9 website hero is only best-effort —
   a 4:5 cover or a scraped portrait legitimately reaches the hero + inline body. The fixed 16:10 crop
   (feed/hero) and 620px clip (inline) slice a portrait. app.js::tagMediaRatio flags a <0.9-aspect image
   `.media--portrait` on load, at every width; the rules below let ONLY those render uncropped, wherever
   they appear (1-column phone feed, 2/3-column tablet/desktop grid, or the article body). Two-class
   selectors (e.g. `.hero__media.media--portrait`) already out-specificity the single-class desktop rules
   above, so no reordering is needed. Landscape/video/iframe media is never tagged, so the common 16:9
   hero is unchanged at every width.
   NOTE: this same stylesheet also styles the dashboard's article Preview iframe (390px mobile frame), so
   it inherits these fixes by design. */
/* Hero (single, full-width): show a tagged portrait in full instead of a 16:10 center-crop — no grid to break. */
.hero__media.media--portrait { aspect-ratio: auto; }
.hero__media.media--portrait img { height: auto; object-fit: contain; }
/* Grid cards show a portrait whole at card width. Every image hero is the story's 4:5 carousel cover (hero gate,
   2026-09-27), so rows stay level; the cover's own type and baked footer are never cropped or letterboxed. */
/* The grey well moves onto the image (the box a cover reserves before it loads), so no grey band shows under it. */
.card__media.media--portrait { aspect-ratio: auto; background: none; }
.card__media.media--portrait img { display: block; height: auto; object-fit: contain; background: var(--pl-steel-gray); }
.card__media.media--portrait::after { content: none; }
/* The chip sits on the white card under the cover: 14px above it and 14px (.card__body's top padding) below it,
   left edge on the headline's (.card__body's 15px side padding). */
.card__media.media--portrait .card__tag { position: static; display: block; width: fit-content; margin: 14px 15px 0; }
/* Inline article portraits: lift the 620px clip so a tall photo isn't sliced. */
.figure.media--portrait img { max-height: none; object-fit: contain; height: auto; }

/* ============================== MOBILE REFINEMENTS ============================== */
@media (max-width: 719.98px) {
  /* The article shell uses the natural document scroller. Every child may shrink, and long source URLs,
     embeds, tables, and code scroll inside their own content box rather than widening the whole page. */
  .article { width: 100%; padding: 22px 16px 56px; }
  .article__header { margin-bottom: 18px; }
  .article__headline { font-size: clamp(28px, 9.5vw, 38px); line-height: 1.08; overflow-wrap: anywhere; }
  .article__dek { font-size: 17px; line-height: 1.55; }
  .article__byline { line-height: 1.55; }
  .article__hero { margin: 20px auto 24px; }
  .article__hero img, .figure.article__hero img { max-height: min(70svh, 640px); }
  .article__body { font-size: 17px; line-height: 1.7; }
  .article__body h2 { font-size: clamp(23px, 7vw, 30px); }
  .article__body h3 { font-size: clamp(20px, 6vw, 26px); }
  .article__body blockquote:not(.article__pullquote) {
    margin: 1.35em 0; padding-left: 16px; font-size: 18px;
  }
  .article__inline-media, .article__media { margin: 24px 0; }

  /* Keep the sticky article header usable at phone widths and at 200% zoom. The wordmark is allowed to
     shrink, while the back link remains a 44px target and the short "Stories" label stays legible. */
  .nav__inner { gap: 10px; padding: 9px 14px; }
  .logo { min-width: 0; flex: 0 1 auto; }
  .logo__img { width: min(142px, 42vw); max-height: 30px; height: auto; }
  .nav__actions { min-width: 0; margin-left: auto; }
  .article-back { padding: 0 4px; font-size: 11px; }
  .article-back__wide { display: none; }

  .site-footer { margin-top: 36px; }
  .site-footer__inner { padding: 34px 16px 24px; }
  .footer-grid { gap: 24px; }
  .footer-col { gap: 0; }
  .footer-col a { display: flex; align-items: center; min-height: 44px; }
  .footer-bottom { align-items: flex-start; flex-direction: column; gap: 10px; margin-top: 28px; }
  .social { width: 44px; height: 44px; }

  /* 44px minimum touch targets (were 38px). Icon buttons are square; the pager buttons carry variable-width
     text ("< Prev" / "Next >") so they take a MINIMUM width (a fixed 44px would clip/wrap the label). */
  .iconbtn { width: 44px; height: 44px; min-height: 44px; }
  .pager__btn { min-width: 44px; height: 44px; min-height: 44px; }
  /* Long ALL-CAPS pull-quotes can overflow a ~350px column — clamp the size and allow breaking. */
  .article__pullquote { font-size: clamp(20px, 5.5vw, 25px); overflow-wrap: break-word; }
  /* Lead story: image-first like the cards below, instead of a long text block before any visual.
     Bleed the media edge-to-edge (drop the hero's own padding) and pad only the text body under it. */
  .hero { padding: 0; }
  .hero__media { order: -1; }
  .hero__body { padding: 22px; }
  /* Open search becomes a full-bleed row under the sticky header so it never squeezes the logo.
     .nav__search is a child of the unpositioned .nav__inner, so absolute anchors to the sticky .nav. */
  .nav--searching .nav__search {
    position: absolute; top: 100%; left: 0; right: 0; max-width: none; margin: 0;
    border-left: 0; border-right: 0;
  }
}

/* ============================== READER RESPONSE + CONSENT ============================== */
.article__correction { margin-top: 18px; border-left: 3px solid var(--red, #e71d3d); padding: 10px 14px; background: #fff5f6; color: #42161d; font-size: 14px; line-height: 1.6; }
.reader-response { margin: 64px 0 20px; padding: 28px 0; border-top: 1px solid var(--gray-200); border-bottom: 1px solid var(--gray-200); }
.reader-response__eyebrow { margin: 0 0 8px; font-family: var(--font-mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--red); }
.reader-response__title { margin: 0; font-family: var(--font-display); font-size: clamp(24px, 3vw, 34px); }
.reader-response__copy { margin: 8px 0 18px; color: var(--gray-500); line-height: 1.6; }
.reader-response__actions { display: flex; flex-wrap: wrap; gap: 10px; }
.reader-response__button { min-height: 44px; border: 1px solid var(--gray-200); background: var(--white); padding: 0 18px; font: 600 14px var(--font-body); cursor: pointer; }
.reader-response__button:hover, .reader-response__button--active { border-color: var(--ink); background: var(--ink); color: var(--white); }
@media (max-width: 719.98px) {
  .reader-response { margin-top: 48px; padding: 24px 0; }
  .reader-response__actions { display: grid; grid-template-columns: 1fr 1fr; }
  .reader-response__button { width: 100%; min-width: 0; padding-inline: 12px; }
}
/* Reading analytics is an optional DATA choice, so it uses the brand's blue desk rather than editorial red.
   The body inset is measured from the real banner height in app.js: even at 200% zoom or on a narrow phone,
   the final line of an article/footer remains reachable instead of sitting behind a fixed cookie card. */
body.audience-consent-open { padding-bottom: var(--audience-consent-inset, 0); }
.audience-consent {
  position: fixed; z-index: 90; inset: auto 0 0; pointer-events: none;
  padding: 0 14px max(12px, env(safe-area-inset-bottom));
}
.audience-consent__inner {
  width: min(860px, 100%); margin: 0 auto; pointer-events: auto;
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 20px;
  border: 1px solid var(--pl-steel-gray); border-top: 3px solid var(--pl-power-blue);
  background: var(--pl-white); color: var(--pl-ink-black); padding: 13px 14px 14px 16px;
}
.audience-consent__copy { min-width: 0; }
.audience-consent__eyebrow {
  display: block; margin-bottom: 2px; color: var(--pl-power-blue);
  font: 400 10px/1.3 var(--font-mono); letter-spacing: .14em; text-transform: uppercase;
}
.audience-consent__title { display: block; font: 700 14px/1.35 var(--font-body); }
.audience-consent__description {
  margin: 3px 0 0; max-width: 620px; color: var(--pl-ink-muted); font-size: 12px; line-height: 1.5;
}
.audience-consent__actions { display: flex; align-items: center; gap: 8px; }
.audience-consent__button {
  min-width: 96px; min-height: 44px; border: 1px solid var(--pl-steel-gray);
  background: var(--pl-white); color: var(--pl-ink-black); padding: 0 16px;
  font: 700 13px var(--font-body); cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}
.audience-consent__button--accept {
  border-color: var(--pl-power-blue); background: var(--pl-power-blue); color: var(--pl-white);
}
@media (hover: hover) {
  .audience-consent__button:hover { border-color: var(--pl-ink-black); background: var(--pl-off-white); }
  .audience-consent__button--accept:hover { border-color: var(--pl-press-blue); background: var(--pl-press-blue); color: var(--pl-white); }
}
.audience-consent__button--accept:focus-visible { outline-color: var(--pl-ink-black); }
@media (prefers-reduced-motion: reduce) { .audience-consent__button { transition: none; } }
@media (max-width: 640px) {
  .audience-consent { padding: 0 8px max(8px, env(safe-area-inset-bottom)); }
  .audience-consent__inner { grid-template-columns: 1fr; gap: 11px; padding: 12px 13px 13px; }
  .audience-consent__description { font-size: 11.5px; }
  .audience-consent__actions { display: grid; grid-template-columns: 1fr 1fr; width: 100%; }
  .audience-consent__button { width: 100%; min-width: 0; }
}

/* ============================== DAILY BRIEFING SIGNUP ============================== */
/* One form, two homes: a panel after each article (app.js renderSubscribe) and a compact form in every footer.
   The blue top rule is the desk colour the consent card and the 404 numeral use: this is a reader-data choice,
   not editorial red. The input stays at 16px for the same iOS focus-zoom reason as .nav__search-input. */
.subscribe__label { display: block; margin: 0 0 8px; font: 700 14px/1.4 var(--font-body); }
.subscribe__row { display: flex; gap: 8px; }
.subscribe__input {
  flex: 1; min-width: 0; min-height: 44px; margin: 0; padding: 0 12px;
  border: 1px solid var(--pl-steel-gray); border-radius: 0; background: var(--pl-white); color: var(--ink);
  font: 16px var(--font-body); -webkit-appearance: none; appearance: none;
}
.subscribe__input::placeholder { color: var(--gray-500); }
.subscribe__input:focus-visible { border-color: var(--pl-power-blue); outline-offset: 0; }
.subscribe__button { flex: none; min-height: 44px; margin-top: 0; }
.subscribe__button:disabled { opacity: .6; cursor: progress; }
.subscribe__note { margin: 8px 0 0; color: var(--gray-500); font-size: 13px; line-height: 1.5; }
.subscribe__note a { text-decoration: underline; text-underline-offset: 3px; }
.subscribe__status { margin: 8px 0 0; font-size: 14px; font-weight: 600; line-height: 1.5; }
.subscribe__status:empty { display: none; }
.subscribe__status[data-state="error"] { color: var(--pl-power-red); }

.subscribe--article {
  margin: 28px 0 20px; padding: 24px 22px 22px;
  background: var(--pl-white); border: 1px solid var(--gray-200); border-top: 6px solid var(--pl-power-blue);
}
.subscribe__title { margin: 0; font: 400 clamp(22px, 3vw, 30px)/1.1 var(--font-display); text-transform: uppercase; }
.subscribe__copy { margin: 8px 0 18px; color: var(--gray-500); line-height: 1.6; }

/* On the ink footer: white label and status (red text fails contrast on ink), steel-grey fine print. */
.subscribe--footer { max-width: 440px; margin: 0 0 8px; }
.subscribe--footer .subscribe__label {
  color: var(--white); font: 400 12px/1.4 var(--font-mono); text-transform: uppercase; letter-spacing: .1em;
}
.subscribe--footer .subscribe__input { border-color: var(--white); }
.subscribe--footer .subscribe__note { color: var(--pl-steel-gray); }
.subscribe--footer .subscribe__status,
.subscribe--footer .subscribe__status[data-state="error"] { color: var(--white); }
.subscribe--footer :focus-visible { outline-color: var(--white); }
@media (max-width: 719.98px) {
  .subscribe--article { padding: 20px 16px 18px; }
}

/* The new-visitor prompt (app.js showBriefingPrompt): the article panel inside a native modal <dialog>. The UA
   centres it and makes the page behind it inert; nothing here locks body scroll or pads the page, so opening it
   moves no layout. Opacity is the only motion. */
.briefing { width: min(480px, calc(100% - 32px)); padding: 0; border: 0; background: transparent; color: var(--ink); }
.briefing::backdrop { background: rgba(17, 17, 17, .6); }
.briefing .subscribe--article { margin: 0; }
.briefing .subscribe__title { padding-right: 28px; }
.briefing__close {
  position: absolute; top: 6px; right: 0; z-index: 1; width: 44px; height: 44px;
  display: grid; place-items: center; border: 0; background: transparent; color: var(--ink);
  font: 400 18px/1 var(--font-body); cursor: pointer;
}
.briefing__close:hover { background: var(--pl-off-white); }
.briefing[open], .briefing[open]::backdrop { animation: briefing-in .2s ease-out; }
@keyframes briefing-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .briefing[open], .briefing[open]::backdrop { animation: none; } }
