/* ================================================================
   ROSCOE — Nieman Lab article redesign 
   ================================================================ */

:root {
  /* Column gutters that shrink with the columns.
     These were fixed at 36 and 32px, which is right at full width and wrong
     as soon as the columns narrow: a hero story column goes from ~211px of
     text to ~130px while the gutter beside it stays 36px, so the gap ends
     up a quarter of the column. Scaling on vw keeps the proportion roughly
     constant — full width they are still 36 and 32, at 900px about 23 and
     20, and they bottom out rather than collapsing entirely. */
  /* The page's side gutter. Everything that goes edge to edge on a small
     screen offsets by exactly this, so the two can never drift apart. */
  --rsc-edge: 28px;

  /* The single vertical gap between stacked things on a small screen. One
     number so the page reads as a stream rather than a stack of modules
     each carrying its own margins. */
  --rsc-stack: 26px;

  /* (--rsc-stack-art, the tighter 18px gap used above a picture, is gone.
     The idea was sound on a wide page and wrong in a single column, where
     it made the space under a picture story smaller than the space under
     the text story beside it. See ONE BOUNDARY in the 1200px block.) */

  /* The single boundary used everywhere the page is one column — see the
     ONE BOUNDARY note in the 1200px block. Half of it sits above the
     divider and half below, so --rsc-gap-half is the number that actually
     appears in the rules and --rsc-gap is the gap a reader sees. */
  --rsc-gap: 36px;
  --rsc-gap-half: 18px;

  --rsc-gut-lg: clamp(16px, 2.6vw, 36px);
  --rsc-gut-md: clamp(14px, 2.3vw, 32px);
  --rsc-well:     1300px;
  --rsc-body-max: 700px;
  /* READER TEXT SIZE.
     Multiplies the ARTICLE's type only — body copy, headline, deck and
     byline — not the interface around it. A reader who wants bigger prose
     does not want a bigger hamburger icon, and scaling the chrome is what
     makes these controls break layouts.

     Every use site writes var(--rsc-tscale, 1), so if this declaration is
     ever lost the whole site simply renders at its normal size. The value
     is set on <html> by the inline script in header-roscoe.php and
     persisted per reader in localStorage. */
  --rsc-tscale: 1;

  --rsc-sans:     'Schibsted Grotesk', system-ui, sans-serif;
  --rsc-serif:    'Literata', Georgia, serif;
  --rsc-headline: 'Literata', Georgia, serif;
  --rsc-text:     #1a1a1a;
  --rsc-muted:    #777;
  --rsc-border:   #e0e0e0;
}

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

body {
  font-family: var(--rsc-serif);
  font-size: 1.25rem;
  line-height: 1.6;
  color: var(--rsc-text);
  background: #fff;
  margin: 0;
  padding: 0;
}

/* ================================================================
   SITE HEADER
   ================================================================ */

.roscoe-site-header {
  position: sticky;
  top: 0;
  z-index: 200;
  background: var(--rsc-header-bg, #fff);
  color: var(--rsc-header-color, #1a1a1a);
  border-bottom: 1px solid rgba(0,0,0,.07);
  box-shadow: rgba(0,0,0,0) 1px 3px 6px;
  transition: background .3s, color .3s, box-shadow .25s;
}

.roscoe-site-header.rsc-scrolled {
  box-shadow: rgba(0,0,0,.15) 1px 3px 6px;
}

.roscoe-site-header-inner {
  max-width: var(--rsc-well);
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 28px;
  position: relative;
  z-index: 2;
}

.roscoe-logo img {
  height: 22px;
  display: block;
  transition: filter .3s;
  /* The spaced wordmark files declare width="100%" height="100%", so unlike
     the old 615x102 files they carry no intrinsic pixel size — the browser
     cannot reserve the box until the SVG itself has parsed, and the header
     shifts on first paint. Stating the ratio restores that. All three files
     (colour, black, white) are 629x101; if any of them is ever re-exported
     at a different crop, this number has to move with it. */
  aspect-ratio: 629 / 101;
}

.roscoe-logo img.rsc-invert { filter: invert(1); }

.roscoe-icon-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: inherit;
  padding: 4px;
  display: flex;
  align-items: center;
  line-height: 0;
}

/* --- Nav / Search overlays --- */

body.rsc-overlay-open { overflow: hidden; }

#rsc-sitemenu,
#rsc-searchmenu,
#rsc-submenu {
  position: fixed;
  inset: 0;
  z-index: 300;
  /* Crimson is the site menu's. Search and Subscribe override it below.
     .985 not .96, and blurred: at three per cent the page behind stayed
     legible under large type, which put the story in competition with the
     thing the reader had just opened. Blur rather than opacity so the
     overlay still reads as a layer over the page instead of a new one. */
  background: rgba(140, 20, 32, 0.985);
  /* The blur lives on .active, NOT here. A full-viewport element with a
     backdrop-filter is promoted to its own compositing layer even at
     opacity:0, and on a cold start — a fresh renderer with no warm GPU
     raster, i.e. exactly an incognito window — that layer can be painted
     for a few frames before the compositor applies the opacity above it.
     Three of these are stacked as the first three children of <body>, so
     what surfaces is crimson over teal over navy: a near-black sheet
     across the page that then fades as the layers settle. Hiding them
     properly (visibility, below) and not asking for a backdrop-filter
     until one is actually open removes the layer, and the flash with it. */
  display: flex;
  align-items: center;
  justify-content: center;
  /* Last resort for a screen too short for the menu: scroll rather than
     clip. The content is centred by its own auto margins (below), not by
     align-items, because align-items:center pushes an overflowing child
     past the TOP edge too, where no scroll can reach it. */
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  /* opacity:0 alone leaves these three painting — invisible, but present,
     and therefore able to flash during any frame where the opacity has
     not yet been composited. visibility:hidden takes them out of the
     paint entirely. It is stepped, not interpolated, so it is delayed by
     the length of the fade on the way out and applied instantly on the
     way in; otherwise the close animation would be cut off at frame one. */
  visibility: hidden;
  pointer-events: none;
  transform: scale(1.03);
  transition: opacity .22s ease, transform .22s ease, visibility 0s linear .22s;
}

#rsc-sitemenu.active,
#rsc-searchmenu.active,
#rsc-submenu.active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: scale(1);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
  transition: opacity .22s ease, transform .22s ease, visibility 0s;
}

.rsc-overlay-close {
  position: absolute;
  top: 20px;
  right: 24px;
  background: none;
  border: none;
  color: rgba(255,255,255,.8);
  cursor: pointer;
  line-height: 0;
  padding: 8px;
  transition: color .15s;
}

.rsc-overlay-close:hover { color: #fff; }

/* Overlay content: centered vertically + horizontally */
.rsc-overlay-content {
  width: 100%;
  max-width: 800px;
  margin: auto;
  padding: 40px 60px;
  font-family: var(--rsc-sans);
  color: #fff;
}

/* Nav overlay — two column groups + social row */
.rsc-nav-groups {
  display: flex;
  gap: 80px;
  margin-bottom: 52px;
  flex-wrap: wrap;
}

.rsc-nav-group {
  display: flex;
  flex-direction: column;
}

/* The beats column in the overlay gets a label, because "AI & Journalism"
   next to "Nieman Foundation" needs to say what kind of thing it is. The
   other two columns are self-evident and stay bare. */
.rsc-nav-group-label {
  font-family: var(--rsc-sans);
  font-size: .8rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: rgba(255,255,255,.55);
  margin-bottom: 16px;
}

.rsc-nav-group-label {
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: rgba(255,255,255,.45);
  margin-bottom: 20px;
}

.rsc-nav-group a {
  color: #fff;
  text-decoration: none;
  font-family: var(--rsc-headline);
  font-size: clamp(1.5rem, 2.5vw, 2rem);
  font-weight: 400;
  line-height: 1;
  margin-bottom: 18px;
  transition: opacity .15s;
}

.rsc-nav-group a:last-child { margin-bottom: 0; }
.rsc-nav-group a:hover { opacity: .6; }

/* Beats in the overlay take an underline instead of the fade, in the light
   variant: the overlay ground is rgba(140,20,32,.96) and the base colours
   measure 1.3-2.0:1 against it, which is no colour at all. Opacity stays at
   1 so the name holds its white while the rule carries the colour. */
.rsc-nav-group-beats a:hover {
  opacity: 1;
  text-decoration: underline;
  text-decoration-color: var(--rsc-beat-c-lite, currentColor);
  text-decoration-thickness: 3px;
  text-underline-offset: 7px;
}

/* ----------------------------------------------------------------
   READER TEXT SIZE  (hamburger overlay)
   ----------------------------------------------------------------
   Three A's at increasing size — the convention readers already know
   from news apps, and legible without a label if the label is missed.
   The control itself does NOT scale with --rsc-tscale: a sizing widget
   that resizes itself as you use it is disorienting. */
.rsc-textsize {
  display: flex;
  align-items: flex-end;   /* the label sits on the tiles' shelf too */
  gap: 16px;
  margin: 0 0 26px;
}

.rsc-textsize-label {
  font-family: var(--rsc-sans);
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  opacity: .7;
  line-height: 1;
  white-space: nowrap;
  /* The label's own BASELINE sits on the shelf the tiles stand on.
     flex-end aligns BOXES, and a text box hangs below its baseline by
     the font's descent — measured at 0.17em for Schibsted Grotesk at
     this line-height — so without this the label floats that far above
     the line the tiles stand on. */
  transform: translateY(0.17em);
}

/* Bottom-aligned, so the three tiles sit on a shelf and grow upward.
   Centring them instead made each larger tile extend both above AND
   below the one before it, which reads as three unrelated sizes rather
   than one scale going up. */
.rsc-textsize-btns { display: flex; gap: 10px; align-items: flex-end; }

.rsc-textsize-btn {
  font-family: var(--rsc-serif);
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: inherit;
  border: 1px solid currentColor;
  border-radius: 2px;
  cursor: pointer;
  padding: 0;
  opacity: .55;
  transition: opacity .15s, background .15s;
  /* The tiles graduate too, not just the letters. Three same-sized
     boxes with three nearly-same-sized A's read as one control
     repeated, which is what made the first version unreadable as a
     size picker. */
}

/* Optical centring, derived from Literata's own metrics rather than
   eyeballed.

   Flex centring centres the glyph's LINE BOX, and a line box is mostly
   empty space that is not distributed evenly around the letter. In
   Literata at line-height:1 the baseline falls 0.935em below the top of
   the box, and a cap "A" has no descender — its ink runs from 0.205em
   to 0.935em, so the ink's centre is 0.57em while the box's centre is
   0.50em. The letter therefore sits 0.07em low, every time, in every
   one of the three sizes.

   Correcting in em rather than px is the point: one number fixes all
   three buttons and keeps working if the sizes change. */
.rsc-textsize-btn span {
  display: block;
  line-height: 1;
  transform: translateY(-0.07em);
}

/* 34 / 39 / 44. The first pass stepped by 10px a tile and the big one
   ended up the size of a button rather than a swatch. The letters still
   step by a clear ratio (1 : 1.33 : 1.78) — that is the part doing the
   explaining — while the boxes step gently enough to stay a row of
   swatches. Inner clearance round the letter stays near-constant at
   ~12px, which is why they read as one set. */
.rsc-textsize-btn        { width: 34px; height: 34px; font-size: .9rem;  }
.rsc-textsize-mid        { width: 39px; height: 39px; font-size: 1.2rem; }
.rsc-textsize-big        { width: 44px; height: 44px; font-size: 1.6rem; }

.rsc-textsize-btn:hover { opacity: .85; }

.rsc-textsize-btn[aria-pressed="true"] {
  opacity: 1;
  border-width: 2px;
  background: rgba(255, 255, 255, .16);
}

.rsc-nav-social {
  display: flex;
  gap: 28px;
  align-items: center;
}

.rsc-nav-social a {
  color: rgba(255,255,255,.65);
  font-size: 1.35rem;
  text-decoration: none;
  line-height: 0;
  transition: color .15s;
}

.rsc-nav-social a:hover { color: #fff; }

/* Deep teal (#0d4a52), from the Roscoe hero palette. Three overlays now
   want three grounds: crimson is the house colour and stays on the site
   menu; Subscribe took navy to match the button that opens it; search —
   the one a reader opens to DO something rather than to go somewhere —
   takes the teal. Far enough round the wheel from both that it can't be
   mistaken for either, and 9.9:1 under white text. */
#rsc-searchmenu { background: rgba(13, 74, 82, 0.985); }

/* Search overlay */
.rsc-search-form { width: 100%; }

.rsc-search-field-wrap {
  display: flex;
  align-items: center;
  border-bottom: 2px solid rgba(255,255,255,.5);
  padding-bottom: 4px;
}

.rsc-search-input {
  flex: 1;
  background: none;
  border: none;
  color: #fff;
  font-size: clamp(1.6rem, 3vw, 2.4rem);
  font-family: var(--rsc-sans);
  font-weight: 300;
  padding: 10px 0;
  outline: none;
  caret-color: rgba(255,255,255,.7);
}

.rsc-search-input::placeholder { color: rgba(255,255,255,.35); }

.rsc-search-submit {
  background: none;
  border: none;
  color: rgba(255,255,255,.6);
  cursor: pointer;
  padding: 8px;
  line-height: 0;
  transition: color .15s;
  flex-shrink: 0;
}

.rsc-search-submit:hover { color: #fff; }

/* ================================================================
   TEX ZONE (wraps hero; receives background color for layouts 1/4/6)
   ================================================================ */

#rsc-tex-zone {
  position: relative;
  overflow: hidden;
  transition: background .3s;
}

.rsc-tex-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.roscoe-hero {
  position: relative;
  overflow: visible;
  transition: background-color .3s;
}

/* ================================================================
   HEADLINE / DECK / EYEBROW — shared across layouts
   ================================================================ */

/* Opening gap when the headline leads the hero. An image leading instead
   sits closer (see .rsc-stack-img-wrap:first-child) — a picture is a solid
   block and needs less air above it than type does. */
.roscoe-hed-wrap {
  max-width: var(--rsc-well);
  margin: 0 auto;
  padding: 48px 28px 0;
}

.roscoe-hed-wrap-inner {
  max-width: var(--rsc-body-max);
  margin: 0 auto;
}

/* The headline can be given its own width (the Headline width field, Layout 1
   only) without the deck following it. Unset, this resolves to --rsc-body-max
   and nothing changes; set, only the headline widens, so the hero keeps
   funnelling headline → deck → body.

   Deliberately placed here and not later: the .rsc-side-text /
   .rsc-split-text rules further down neutralise this wrapper for those
   layouts and are the same specificity, so they need to stay downstream to
   keep winning. */
.roscoe-hed-wrap-hed .roscoe-hed-wrap-inner {
  max-width: var(--rsc-hed-max, var(--rsc-body-max));
}

h2.roscoe-headline {
  font-family: var(--rsc-headline);
  /* Per-post, from the Headline style control; 500 when unset. */
  font-weight: var(--rsc-hed-wght, 500);
  line-height: 1.1;
  letter-spacing: -0.05em;
  margin: 0 0 18px;
  text-wrap: balance;
  color: var(--rsc-text);

  /* Optical size follows the rendered size by default — which is what the
     axis is for. It used to be pinned at 51, which is simply what auto gives
     at M (51.2px); the pin froze that cut onto S and XL too, and onto phones,
     where an XL headline is 35px but was still drawn with the 51 cut.
     A post that wants a specific cut sets --rsc-hed-fvs ('opsz' N) from the
     Headline style control. Only opsz is listed there, so font-weight above
     still drives the weight axis. */
  font-optical-sizing: auto;
  font-variation-settings: var(--rsc-hed-fvs, normal);
}

/* Size is NOT set above — the .hl-* classes below own it, so the S/M/L/XL
   field keeps working (the legacy mapping sets L on 1400px art and XL on
   center-body posts). 51px, the size this was judged at, is what .hl-m
   already resolves to at desktop: clamp max 3.2rem = 51.2px. */

/* Headline sizes */

h2.roscoe-headline.hl-s  { font-size: calc(clamp(1.6rem, 3vw,   2.4rem) * var(--rsc-tscale, 1)); line-height: 1.1; }
h2.roscoe-headline.hl-m  { font-size: calc(clamp(2rem,   4vw,   3.2rem) * var(--rsc-tscale, 1)); line-height: 1.15; }
h2.roscoe-headline.hl-l  { font-size: calc(clamp(2.2rem, 4.5vw, 3.6rem) * var(--rsc-tscale, 1)); line-height: 1.06; }
h2.roscoe-headline.hl-xl { font-size: calc(clamp(3rem,   7vw,   4.4rem) * var(--rsc-tscale, 1)); line-height: 1.0; }

/* Color-aware text (used when headline sits on a colored bg) */
h2.roscoe-headline.on-light { color: #1a1a1a; }
h2.roscoe-headline.on-dark  { color: #fff; }

.roscoe-post-deck {
  font-family: var(--rsc-sans);
  font-size: calc(22px * var(--rsc-tscale, 1));
  line-height: 1.4;  /* unitless so the 600px override still scales */
  letter-spacing: -0.005em;
  text-wrap: pretty;
  margin: 0 0 28px;
  color: var(--rsc-text);
}

.roscoe-post-deck.on-light { color: var(--rsc-text); }
.roscoe-post-deck.on-dark  { color: rgba(255,255,255,.75); }

/* Whatever ends the hero drops its bottom margin, so the gap down to the
   byline is set in one place (.roscoe-body-section) rather than being the
   sum of whatever the hero happened to finish with. That sum is what left
   ~92px under the deck: its own 28px on top of the body's opening pad.

   The trailing `:last-child` on each target is load-bearing. Without it this
   matched ANY headline or deck inside the hero's last child — including the
   overlay layout's headline, which has a deck after it inside the same box.
   At (1,2,1) it then beat .rsc-overlay-text's (0,2,1) on the ID alone and
   flattened the gap between headline and deck to zero. Now it only fires on
   the element that genuinely ends the hero, which is all it ever meant. */
#rsc-hero-inner > *:last-child .roscoe-post-deck:last-child,
#rsc-hero-inner > *:last-child h2.roscoe-headline:last-child,
#rsc-l1-after   > *:last-child .roscoe-post-deck:last-child,
#rsc-l1-after   > *:last-child h2.roscoe-headline:last-child { margin-bottom: 0; }

/* Eyebrow wrapper is a block; inner span is inline-block so border-bottom spans text only */
.roscoe-eyebrow-wrap {
  display: block;
  margin-bottom: 14px;
}

.roscoe-eyebrow-wrap.on-dark  { color: #fff; }
.roscoe-eyebrow-wrap.on-light { color: #1a1a1a; }

.roscoe-eyebrow {
  font-family: var(--rsc-sans);
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  display: inline-block;
  border-bottom: 2px solid currentColor;
  padding-bottom: 3px;
  opacity: .75;
}

/* Series kicker chip */
.roscoe-series-kicker {
  margin-bottom: 16px;
  font-family: var(--rsc-sans);
}

.roscoe-series-kicker a {
  display: inline-block;
  background: #444;
  color: #fff !important;
  padding: 3px 10px;
  border-radius: 3px;
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  text-decoration: none;
}

/* Alignment utilities */
.rsc-left   { text-align: left; }
.rsc-center { text-align: center; }

/* Deck directly after headline — no extra gap */
.roscoe-hed-wrap + .roscoe-hed-wrap { padding-top: 0; }

/* ================================================================
   LAYOUT 1 / 2: STACK
   ================================================================ */

.rsc-stack-img-wrap { margin: 0 auto; }
.rsc-stack-img-wrap img { width: 100%; height: auto; display: block; }
.rsc-stack-img-fullbleed .rsc-img-caption { padding-left: 10%; padding-right: 10%; }

/* Image leading the hero. Closer to the header than a leading headline —
   60px left the art visibly adrift under the nav. */
#rsc-hero-inner > .rsc-stack-img-wrap:first-child,
#rsc-l1-after   > .rsc-stack-img-wrap:first-child { margin-top: 32px; }

/* Headline or deck following an image anywhere in the hero. */
.rsc-stack-img-wrap + .roscoe-hed-wrap { padding-top: 28px; }

/* After-zone for Layout 1 straddling effect — set by inline JS */
#rsc-l1-after {
  position: relative;
  z-index: 2;
}

/* Image caption / credit */
.rsc-img-caption {
  font-family: var(--rsc-sans);
  font-size: .95rem;
  line-height: 1.4;
  color: #666;
  padding: 7px 0 0;
}

.rsc-img-credit { color: #999; }

/* Links in a caption or credit. These sit in the hero, outside .roscoe-body,
   so they match none of the article link rules and would otherwise render as
   default browser blue. Same crimson underline as the body, at 1px instead of
   2px — a credit line is 0.95rem grey and a 2px rule under it reads as a
   correction, not a link. */
.rsc-img-caption a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  text-decoration-color: rgba(165, 28, 48, .45);
  transition: text-decoration-color .15s, color .15s;
}
.rsc-img-caption a:hover {
  color: var(--rsc-text);
  text-decoration-color: rgba(165, 28, 48, .9);
}
.rsc-img-caption.on-dark a:hover {
  color: #fff;
  text-decoration-color: rgba(255, 255, 255, .8);
}

.photocredit {
  font-family: var(--rsc-sans);
  font-size: 0.8rem;
  text-transform: uppercase;
}

.rsc-img-caption.on-dark { color: rgba(255,255,255,.75); }
.rsc-img-caption.on-dark .rsc-img-credit { color: rgba(255,255,255,.5); }

/* ================================================================
   LAYOUT 3: OVERLAY
   ================================================================ */

.rsc-overlay-hero {
  position: relative;
  min-height: 60vh;
  overflow: hidden;
}

.rsc-overlay-hero > img {
  width: 100%;
  height: auto;
  min-height: 60vh;
  object-fit: cover;
  display: block;
}

.rsc-overlay-gradient {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.rsc-overlay-text {
  position: absolute;
  z-index: 2;
  padding: 48px;
}

.rsc-overlay-text h2.roscoe-headline { color: #fff; }
.rsc-overlay-text .roscoe-post-deck  { color: rgba(255,255,255,.85); }

/* Tightened from 26px to 16px, 4 Oct 2026, on the page rather than in a mock.
   The 26px came from reasoning that white type over a photograph, separated
   by a gradient rather than a crisp edge, would read smaller than the 18px
   the other layouts use — so it was pushed UP to compensate. Looked at in
   situ on a real headline it goes the other way: with no rule or colour
   change between them, the headline and deck want to read as one block, and
   the extra air broke them apart. */
.rsc-overlay-text h2.roscoe-headline { margin-bottom: 16px; }

/* The overlay's caption sits BELOW the hero rather than over it — the image
   is full-bleed and already carries the headline and deck, so a credit on
   top of it would be a fourth thing competing in the same space.
   Indented to match .rsc-stack-img-fullbleed's caption (line ~496) and the
   overlay text's own default 10% inset, so a credit lines up with the words
   above it instead of running to the window edge. */
.rsc-overlay-hero + .rsc-img-caption {
  padding-left: 10%;
  padding-right: 10%;
}

/* ================================================================
   LAYOUT 4: SIDE-BY-SIDE (colored bg)
   ================================================================ */

.rsc-side-hero {
  display: flex;
  padding: 80px 0;
  max-width: var(--rsc-well);
  margin: 0 auto;
}

.rsc-side-hero.rsc-reversed { flex-direction: row-reverse; }

.rsc-side-text {
  flex: 1;
  min-width: 0;
  padding: 0 clamp(24px, 4vw, 56px);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* roscoe_hed_block() and roscoe_deck_block() both emit .roscoe-hed-wrap,
   which is built for the full-width stack layout: a 1300px max-width, auto
   side margins and 48px of top padding. Dropped inside a narrow flex column
   that already has its own padding, all three compound — which is what put
   the text low in its half and made the side spacing look uneven. Neutralise
   it here and let the column own the spacing. */
.rsc-side-text .roscoe-hed-wrap,
.rsc-split-text .roscoe-hed-wrap {
  max-width: none;
  margin: 0;
  padding: 0;
}

.rsc-side-text .roscoe-hed-wrap-inner,
.rsc-split-text .roscoe-hed-wrap-inner { max-width: none; margin: 0; }

/* Headline-to-deck gap set on the deck itself. The headline and deck sit in
   separate .roscoe-hed-wrap divs, so a bottom margin on the headline
   collapses through the wrapper and lands somewhere unpredictable — it
   measured 4px. Owning it from one side keeps it exact. */
.rsc-side-text h2.roscoe-headline,
.rsc-split-text h2.roscoe-headline { margin-bottom: 0; }

.rsc-side-text .roscoe-post-deck,
.rsc-split-text .roscoe-post-deck { margin: 16px 0 0; }

.rsc-side-img         { flex: 1; }
.rsc-side-img img     { width: 100%; height: auto; object-fit: cover; display: block; }

/* ================================================================
   LAYOUT 5: SPLIT (half color + half image, no outer color bg)
   ================================================================ */

/* A true half-and-half, filling the window — the shape a NYT feature opener
   uses. Both halves get their height from the hero, so a landscape or a
   portrait source both work: object-fit crops to whatever the column is.

   HEIGHT. 100svh, not 100vh. On a phone 100vh measures to behind the
   browser's own chrome, so a "full height" hero overflows by the height of
   the address bar and the page starts life already scrolled. svh is the
   small-viewport unit and measures what you can actually see. The vh line
   above it is the fallback for anything too old to know svh.

   The clamp is the practical limit: below ~540px of window the headline and
   deck stop fitting, and above ~920px the words end up marooned in the
   middle of a very tall colour field with the picture towering beside them. */
/* WHY THE HEADER COMES OFF THE HEIGHT.
   The hero is supposed to end exactly at the fold, and it does not start at
   the top of the window — the sticky header sits above it in flow and takes
   ~50px. A plain 100svh therefore puts the bottom edge 50px BELOW the fold,
   so you can never see the whole opener without scrolling. The old 920px
   ceiling hid that on short windows and caused the opposite fault on tall
   ones: a 1000px window got a 920px hero and showed a sliver of the body
   underneath. Subtracting the measured header height lands it on the fold at
   every window size, and the 540px floor keeps it sane in landscape on a
   phone. --rsc-hdr-h is written by the script at the foot of
   header-roscoe.php; the fallback is the header at its normal padding, used
   for the first paint and if the script never runs. */
.rsc-split-hero {
  display: flex;
  align-items: stretch;
  min-height: max(540px, calc(100vh - var(--rsc-hdr-h, 50px)));
  min-height: max(540px, calc(100svh - var(--rsc-hdr-h, 50px)));
}
.rsc-split-hero.rsc-reversed { flex-direction: row-reverse; }

/* WHY NOT flex: 1.
   flex: 1 means flex: 1 1 0%, and a flex base size of 0 does not make an
   item able to BE zero wide — its padding and border still occupy the
   border box. So the text half's floor was its own horizontal padding, up
   to 56px a side. Both halves then grew by an equal share of what was left,
   which left the text half permanently wider by exactly 112px, at every
   viewport. Measured on a 1990px window on 4 Oct 2026: image 910px, text
   1015px. A 105px difference, against 112px of padding.
   flex-basis: 50% puts the padding INSIDE the half, so halves are halves. */
.rsc-split-text,
.rsc-split-img {
  flex: 0 0 50%;
  max-width: 50%;
  min-width: 0;
}

.rsc-split-text {
  padding: clamp(32px, 5vw, 64px) clamp(24px, 4vw, 56px);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* OPTICAL vs MATHEMATICAL CENTRING.
   justify-content centres boxes, not ink. .roscoe-eyebrow-wrap sets no
   line-height, so it inherits body's 1.6 at the inherited 20px font size —
   a 32px strut around an inline-block that is only 22px tall. The extra
   10px of half-leading sits ABOVE the eyebrow's first visible pixel, while
   the deck closing the block has a tight 1.4. The result measures dead
   centre (91.5px of box either side) and reads as 11px top-heavy, which is
   the "significantly more space above the headline" you see. Killing the
   strut lets the line box hug the inline-block. line-height inherits as a
   NUMBER here, so the 0 would reach the eyebrow itself and collapse its own
   line box — hence restating 1.6 on the child. */
.rsc-split-text .roscoe-eyebrow-wrap { line-height: 0; }
.rsc-split-text .roscoe-eyebrow      { line-height: 1.6; }

/* Nothing but the picture, floor to ceiling. The caption used to live in
   here and took the bottom ~80px of the column with it, so the image ended
   short of where the colour field ended and the two halves stopped meeting
   at the same line. It is a sibling of the hero now, below. */
.rsc-split-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Caption, under the hero and held to the image's half of the window — the
   way a NYT split opener does it. margin-left pushes it across when the
   picture is on the right (the default); .rsc-reversed drops that when the
   sides are swapped, so the caption always tracks the image.
   The side padding matches .rsc-split-text's, so a credit under a
   right-hand picture lines up with the headline above it. */
.rsc-split-cap {
  width: 50%;
  margin-left: 50%;
  padding: 10px clamp(24px, 4vw, 56px) 0;
}
.rsc-split-cap.rsc-reversed { margin-left: 0; }

/* ================================================================
   BODY ZONE
   ================================================================ */

/* overflow-x: clip, not hidden, and not visible.
   [bigimagebreakout] bleeds to 100vw, and vw counts the scrollbar — so on a
   platform with a classic (space-taking) scrollbar the picture ends up a few
   pixels wider than the page and raises a horizontal scrollbar across the
   whole site. Clipping the few pixels is the right trade.

   It has to be clip rather than hidden because hidden makes the element a
   scroll container, which would both capture descendant position: sticky and
   force overflow-y to auto; clip does neither, so it pairs with a visible
   y-axis and leaves sticky behaviour alone. */
.roscoe-body-zone { position: relative; overflow-x: clip; overflow-y: visible; }

#rsc-body-canvas,
#rsc-accent-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
}

/* Text mask: shown only when body texture is active (toggled by JS) */
.rsc-text-mask {
  display: none;
  position: absolute;
  z-index: 1;
  pointer-events: none;
  top: 0;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 820px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(255,255,255,.92) 8%,
    #fff 15%,
    #fff 85%,
    rgba(255,255,255,.92) 92%,
    transparent 100%
  );
}

.roscoe-body-section {
  padding: 64px 24px 80px;
  position: relative;
  z-index: 2;
}

/* [fullpagebreakout] bands (rsc_fullpagebreakout() in roscoe-functions.php).
   The 64/80 above is sized for one continuous article; band after band it
   stacked into 204px gaps where Simple has about 60. So a section that runs
   into a band drops its bottom padding, and a band has no top padding of its
   own — as in Simple, the space comes from the content's own margins.
   flow-root keeps those margins inside the band, so its colour starts at its
   top edge instead of below the first heading's margin. Measured against
   Simple at 1440px: byline to first paragraph 60 (Simple 61), band to band
   60 (57), band edge to first line 30 (31). The last band keeps its bottom
   padding for the article footer. */
.rsc-fpb-section { padding-top: 0; display: flow-root; }
.roscoe-body-section:has(+ .fullpagebreakout) { padding-bottom: 0; }

.roscoe-article-body {
  max-width: var(--rsc-body-max);
  margin: 0 auto;
}

.roscoe-article-body p { margin-bottom: 1.5em; }

/* Article body type. Nothing set font-size on .roscoe-body before this —
   body copy was inheriting whatever the page default was. */
.roscoe-body {
  font-size: calc(20px * var(--rsc-tscale, 1));
  line-height: 1.5;   /* = 30/20, unitless so nested type keeps proportional leading */
  letter-spacing: -0.009em;
}

/* block kills the stray baseline gap under a standalone image — but a row of
   images sharing one wrapper (the old logo rows in archive posts) has to stay
   on one line, so only an image with no image siblings gets it. */
.roscoe-body img { max-width: 100%; height: auto; display: block; }
.roscoe-body img:not(:only-of-type) { display: inline-block; vertical-align: middle; }

/* ================================================================
   LEGACY EMBEDS — the 600px well problem
   ================================================================
   The body well was 600px for most of the site's life and is 700px
   in Roscoe, so every embed with a hardcoded width="600" now sits
   in a short column with a ragged right edge. 306 published posts
   have a 600px YouTube embed; 335 have a YouTube iframe at all.

   Video scales for free, so it gets widened. Deliberately scoped to
   video hosts rather than all iframes:

     - Twitter (1,818 posts) and Instagram (897) render through their
       own scripts, which cap themselves at 550px and 658px and
       manage their own sizing. Forcing width:100% fights the widget.
     - Soundcloud (136) is a fixed-height audio player. An
       aspect-ratio would wreck it.

   The height comes from an aspect-ratio set per element in
   footer-roscoe.php, copied from each embed's OWN width/height
   attributes rather than assumed to be 16:9 — 90 posts carry a
   600x450 (4:3) embed, and hardcoding 16:9 would pillarbox them.
   The height:auto here is what lets that ratio drive the box. */
.roscoe-body iframe[src*="youtube"],
.roscoe-body iframe[src*="youtu.be"],
.roscoe-body iframe[src*="vimeo"],
.roscoe-body iframe[src*="dailymotion"] {
  width: 100% !important;
  height: auto !important;
  max-width: 100%;
  display: block;
  margin-inline: auto;
}

/* ---------------- Captioned body image ----------------
   Legacy markup, still all over the archive and still what the editors
   write today:

     <div class="nakedboxedimagecaption">
       <img class="nakedboxedimage" …><p></p>
       <p>Caption. Photo courtesy of …</p>
     </div>

   Roscoe had no rules for it at all, so the image sat loose in the column
   and the caption rendered as another body paragraph — same size, same
   colour as the story around it.

   The empty <p> is wpautop's: it closes a paragraph at the <img> and
   opens the next before the caption text. It really is childless (the
   newline sits outside it), so :empty matches — checked on the live page
   rather than assumed.

   Caption styling follows .rsc-img-caption, Roscoe's own treatment for
   hero captions, rather than Simple's: same face, size and grey, so a
   caption reads the same wherever it turns up. The rules above and below
   are Simple's device and worth keeping, drawn with Roscoe's border
   token instead of `lightgrey`. */
.roscoe-body .nakedboxedimagecaption {
  margin: 34px 0;
  padding: 28px 0;
  border-top: 1px solid var(--rsc-border);
  border-bottom: 1px solid var(--rsc-border);
}

.roscoe-body .nakedboxedimagecaption .nakedboxedimage,
.roscoe-body .nakedboxedimagecaption img {
  display: block;
  width: 100%;
  height: auto;
  margin: 0;
}

.roscoe-body .nakedboxedimagecaption p:empty { display: none; }

.roscoe-body .nakedboxedimagecaption p {
  font-family: var(--rsc-sans);
  font-size: .95rem;
  line-height: 1.4;
  color: #666;
  margin: 14px 0 0;
}
.roscoe-body .nakedboxedimagecaption p:last-child { margin-bottom: 0; }

/* The breakout variants carry a width attribute that would otherwise win
   on a narrow column. */
.roscoe-body .nakedboxedimagewide,
.roscoe-body .nakedboxedimage990 { width: 100%; max-width: 100%; height: auto; }

/* ================================================================
   LEGACY BODY CLASSES — floats, footnotes, datelines, TWIR
   ================================================================
   Simple styles these and Roscoe did not. Audited 2026-10-02 by
   diffing both stylesheets against the classes actually present in
   800 sampled posts. Figures are extrapolated to the 12,005-post
   archive.

   The floated images were not merely unstyled — they were BROKEN.
   `.roscoe-body img { display: block }` above turns them into
   full-width blocks, so every paragraph written to wrap around a
   half-column image had it wedged in at double size instead.
   ~2,970 instances across five classes. */

/* --- floated images ------------------------------------------------
   Two shapes share these names: a bare <img class="rightimage"> and a
   <div class="rightimage"> wrapping an image plus a caption <p>. They
   need different rules, hence the element-qualified selectors. */
.roscoe-body .nakedrightimage,
.roscoe-body .nakedleftimage,
.roscoe-body .rightimage,
.roscoe-body .leftimage { max-width: 50%; height: auto; }

.roscoe-body img.nakedrightimage,
.roscoe-body img.rightimage,
.roscoe-body div.rightimage { float: right; margin: 6px 0 18px 26px; }

.roscoe-body img.nakedleftimage,
.roscoe-body img.leftimage,
.roscoe-body div.leftimage { float: left; margin: 6px 26px 18px 0; }

/* The naked* variants are deliberately borderless; the plain ones
   carry Simple's 6px mat and hairline rule, drawn with Roscoe's
   border token rather than `gray`. */
.roscoe-body img.rightimage,
.roscoe-body img.leftimage {
  padding: 6px;
  border: 1px solid var(--rsc-border);
  background: #fff;
}

.roscoe-body div.rightimage img,
.roscoe-body div.leftimage img {
  float: none;
  display: block;
  width: 100%;
  height: auto;
  margin: 0;
  padding: 6px;
  border: 1px solid var(--rsc-border);
  background: #fff;
}

/* Simple set these captions in myriad-pro italic, in green (#68ad00).
   Matched to Roscoe's own caption treatment instead — see
   .nakedboxedimagecaption p above — so every caption in the body
   reads the same way. */
.roscoe-body div.rightimage p,
.roscoe-body div.leftimage p {
  font-family: var(--rsc-sans);
  font-size: .95rem;
  line-height: 1.4;
  color: #666;
  margin: 10px 0 0;
  padding: 0;
}

/* Stop a float at the end of a post escaping into the furniture
   below it. Simple relied on its own wrappers for this. */
.roscoe-body::after { content: ""; display: table; clear: both; }

/* A 50% float in a 700px well is ~350px; on a phone it is unreadable
   and strands the text in a 2-word column. Simple predates this
   being a concern. */
@media (max-width: 600px) {
  .roscoe-body .nakedrightimage,
  .roscoe-body .nakedleftimage,
  .roscoe-body .rightimage,
  .roscoe-body .leftimage,
  .roscoe-body div.rightimage,
  .roscoe-body div.leftimage {
    float: none;
    max-width: 100%;
    width: 100%;
    margin: 22px 0;
  }
}

/* --- boxed image, centred ------------------------------------------
   Simple gave this width:111.111% with margin-left:-38px, which made a
   600px image bleed to ~667px out of the old 600px well. That arithmetic
   is wrong at 700px (it would compute 778px and overflow), so the bleed
   is dropped and the image simply fills the column. */
.roscoe-body .boxedimage {
  display: block;
  width: 100%;
  height: auto;
  margin: 34px auto;
  padding: 6px;
  border: 1px solid var(--rsc-border);
  background: #fff;
}

/* --- This Week in Review headers  (~480 posts) ----------------------
   Simple used freight-sans-pro (gone) in #8a1823. Mapped to Roscoe's
   sans and the house crimson so it matches the rest of the design. */
.roscoe-body .simple-twir-header,
.roscoe-body .simple-twir-header a {
  font-family: var(--rsc-sans);
  font-weight: 700;
  color: #A51C30;
}

/* --- footnotes  (~240 posts) ---------------------------------------
   Without these the apparatus collapses into ordinary paragraphs and
   inline links: the superscript markers sit on the baseline and the
   back-links read as body links. */
.roscoe-body .footnotes-header {
  font-family: var(--rsc-sans);
  font-weight: 700;
  margin: 28px 0 10px;
  padding-top: 18px;
  border-top: 1px solid var(--rsc-border);
}
.roscoe-body ol.footnotes {
  font-family: var(--rsc-sans);
  font-size: 1rem;
  line-height: 1.5;
  color: #666;
  margin: 34px 0 0;
  padding: 30px 0 0 30px;
  border-top: 1px solid var(--rsc-text);
}
.roscoe-body ol.footnotes li { margin: 0 0 10px; }
.roscoe-body .footnote-link,
.roscoe-body .footnote-identifier-link {
  font-family: var(--rsc-sans);
  font-size: .75em;
  vertical-align: baseline;
  position: relative;
  top: -.4em;
  text-decoration: none;
}
.roscoe-body .footnote-back-link {
  top: 0;
  border-bottom: 0;
  text-decoration: none;
}

/* --- dateline  (~165 posts) ----------------------------------------- */
.roscoe-body .dateline {
  font-family: var(--rsc-sans);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #444;
}

/* --- .pq1 pullquote variant  (~30 posts) ----------------------------
   A modifier on the left/right/full pullquotes, scoped in Simple to
   `.simple-body` and therefore inert in Roscoe. Simple set it in
   jubilat — never loaded here — so the distinguishing features are
   kept (heavy weight, the 15px rule above) in Roscoe's headline face. */
.roscoe-body .leftpullquote.pq1,
.roscoe-body .rightpullquote.pq1,
.roscoe-body .fullpullquote.pq1 {
  font-family: var(--rsc-headline);
  font-weight: 900;
  background: none;
  border: none;
  border-top: 15px solid var(--rsc-text);
  color: var(--rsc-text);
  padding: 16px 0 0;
}
.roscoe-body .leftpullquote.pq1,
.roscoe-body .rightpullquote.pq1 { font-size: 1.5rem; line-height: 1.16; }
.roscoe-body .fullpullquote.pq1 {
  font-size: 1.75rem;
  line-height: 1.2;
  margin: 30px 0;
}

/* Article body links */
.roscoe-body a {
  color: #1a1a1a;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  text-decoration-color: rgba(165, 28, 48, .4);
  transition: text-decoration-color .15s, color .15s;
}
.roscoe-body a:hover {
  color: #7d1525;
  text-decoration-color: rgba(165, 28, 48, .9);
}

/* Labby drew link underlines with a background-image gradient, and archive
   posts still carry rules like `#fivebody a { background-image: linear-
   gradient(...) }`. Roscoe draws a real underline, so the leftover gradient
   turns up as a solid block behind the words. Those rules use an ID, which
   outranks any selector here — hence !important. */
.roscoe-body a, .bigimagebreakout-caption a { background-image: none !important; }

/* ================================================================
   IN-ARTICLE SHORTCODES
   ================================================================ */

/* --- [relatedstory] --- */

.embed-relatedstory {
  float: right;
  width: 300px;
  max-width: 50%;
  clear: right;
  margin: 4px 0 20px 24px;
  background: #eceae8;
  font-family: var(--rsc-sans);
}

a.embed-relatedstory-imagelink {
  display: block;
  line-height: 0;
  text-decoration: none;
}

.embed-relatedstory-image {
  width: 100%;
  height: auto;
  display: block;
}

.embed-relatedstory-header {
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  padding: 20px 25px 0;
  color: var(--rsc-muted);
}

a.embed-relatedstory-link {
  text-decoration: none !important;
  border-bottom: 0 !important;
  color: var(--rsc-text) !important;
}

.embed-relatedstory-header a.embed-relatedstory-link { color: var(--rsc-muted) !important; }
a.embed-relatedstory-link:hover { color: #555 !important; }

.embed-relatedstory-headline {
  font-family: var(--rsc-headline);
  font-size: 1.3rem;
  font-weight: 400;
  line-height: 1.3;
  padding: 8px 25px 0;
}

.embed-relatedstory-date {
  font-family: var(--rsc-sans);
  font-size: .75rem;
  color: var(--rsc-muted);
  padding: 6px 25px 20px;
}

.embed-relatedstory-author { display: none !important; }

/* inline variant: [relatedstory inline="true"] */
p.inline-relatedstory {
  font-family: var(--rsc-sans);
  font-size: .9rem;
  font-style: italic;
  color: var(--rsc-muted);
  margin: 1.2em 0;
}

p.inline-relatedstory a { color: var(--rsc-muted); }
p.inline-relatedstory a:hover { color: var(--rsc-text); }

/* --- [ednote] --- */

.ednote {
  font-family: var(--rsc-sans);
  font-size: 1rem;
  line-height: 1.65;
  background: #f7f6f5;
  padding: 32px;
  margin: 32px 0;
  color: #444;
}

/* Zero on the last one so the box keeps its own padding, but an ednote of
   several paragraphs still reads as several paragraphs. Labby used 15px. */
.ednote p { margin: 0 0 15px; }
.ednote p:last-child { margin-bottom: 0; }
.ednote a { color: #444; }
.ednote a:hover { color: var(--rsc-text); }

/* --- [rp] / [rippedpaper] --- */

blockquote.rippedpaper {
  background: #f7f6f5;
  padding: 32px 28px;
  margin: 36px 0;
  font-family: var(--rsc-serif);
  font-size: 1.1rem;
  line-height: 1.7;
  color: var(--rsc-text);
  border: none;
  box-shadow: 0 1px 3px rgba(0,0,0,.06), 0 4px 20px rgba(0,0,0,.09);
}

blockquote.rippedpaper p:last-child { margin-bottom: 0; }

/* Plain <blockquote> — some 3,200 archive posts, and Roscoe had no style for
   it at all: the browser default, indented text with no box. Simple set every
   one as a warm off-white box in the sans. This is that box in Roscoe's own
   terms: the #f7f6f5 paper the ednote and [rp] use, but flat — no shadow, no
   torn edge, so [rp] stays the special one — and inset 20px from the column,
   which also keeps it apart from the full-width ednote. Sizes are Simple's:
   35px inside, 20px outside, 18px type on a 1.5 line, 14px between
   paragraphs; first and last paragraphs drop their outer margins so the
   padding is the whole of the space.
   :not([class]) because every classed blockquote in the archive is an embed
   or a pull quote that must not be boxed — twitter-tweet (~1,300 posts),
   instagram-media, bluesky-embed, tiktok-embed, left/rightpullquote.
   wp-block-quote is the one exception: the block editor's plain quote.
   A blockquote that paints its own inline background keeps it. */
.roscoe-body blockquote:not([class]),
.roscoe-body blockquote.wp-block-quote {
  background: #f7f6f5;
  padding: 35px;
  margin: 20px;
  font-family: var(--rsc-sans);
  font-size: 18px;
  line-height: 1.5;
  color: #333;
}
.roscoe-body blockquote:not([class]) p,
.roscoe-body blockquote.wp-block-quote p { margin: 0 0 14px; }
.roscoe-body blockquote:not([class]) > :first-child,
.roscoe-body blockquote.wp-block-quote > :first-child { margin-top: 0; }
.roscoe-body blockquote:not([class]) > :last-child,
.roscoe-body blockquote.wp-block-quote > :last-child { margin-bottom: 0; }
@media (max-width: 600px) {
  .roscoe-body blockquote:not([class]),
  .roscoe-body blockquote.wp-block-quote { margin: 20px 0; padding: 24px; }
}
[data-theme="dark"] .roscoe-body blockquote:not([class]),
[data-theme="dark"] .roscoe-body blockquote.wp-block-quote {
  background: var(--rsc-d-surface);
  color: var(--rsc-d-text);
}

/* Optional source attribution: [rp source="Name"] */
.rippedsource {
  font-family: var(--rsc-sans);
  font-size: .8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--rsc-muted);
  margin-bottom: 12px;
}

.rippedsource span::before { content: "— "; }

/* --- [rightpullquote] / [leftpullquote] / [fullpullquote] --- */

.rightpullquote span::before,
.leftpullquote span::before,
.fullpullquote span::before {
  content: attr(data-pullquote);
}

.rightpullquote,
.leftpullquote {
  font-family: var(--rsc-headline);
  font-size: 1.5rem;
  line-height: 1.3;
  font-weight: 700;
  color: var(--rsc-text);
  background: none;
  border: none;
  border-top: 3px solid var(--rsc-text);
  box-shadow: none;
  padding: 16px 0 8px;
  width: 240px;
  max-width: 44%;
  margin-top: 6px;
  margin-bottom: 20px;
  text-indent: 0;
}

.rightpullquote {
  float: right;
  margin-left: 28px;
  margin-right: 0;
}

.leftpullquote {
  float: left;
  text-align: right;
  margin-right: 28px;
  margin-left: 0;
}

.rightpullquoteattrib,
.leftpullquoteattrib {
  font-family: var(--rsc-sans);
  font-size: .8rem;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--rsc-muted);
  margin-top: 10px;
  font-style: normal;
}

.fullpullquote {
  clear: both;
  float: none;
  width: 100%;
  font-family: var(--rsc-headline);
  font-size: 1.9rem;
  line-height: 1.25;
  font-weight: 700;
  color: var(--rsc-text);
  text-align: center;
  background: none;
  border: none;
  border-top: 2px solid var(--rsc-text);
  border-bottom: 2px solid var(--rsc-text);
  box-shadow: none;
  padding: 24px 0;
  margin: 36px 0;
}

blockquote.fullpullquote > div { display: none; }

.fullpullquoteattrib {
  font-family: var(--rsc-sans);
  font-size: .8rem;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--rsc-muted);
  margin-top: 12px;
  text-align: right;
}

@media (max-width: 680px) {
  .rightpullquote,
  .leftpullquote {
    float: none;
    width: 100%;
    max-width: 100%;
    margin: 28px 0;
    text-align: left;
  }
}

/* --- [bigimagebreakout] --- */

/* FULL BLEED FROM INSIDE THE COLUMN.
   These two used to be emitted as siblings of .roscoe-body-section, because
   the shortcode closed its way out of the article wrappers and opened new
   ones behind itself. They are written inside .roscoe-body now and escape
   with margins instead; rsc_bigimagebreakout() in roscoe-functions.php has
   the full reasoning.

   calc(50% - 50vw) is half the column minus half the window. Pulling that
   much off each side puts the edges exactly on the window's, whatever the
   column is and however deeply it is nested — the point being that nothing
   here has to know the depth. Width has to go back to auto: the old 100%
   would resolve against the 700px column and leave the picture that wide
   with the margins hanging off it. */
.bigimagebreakout {
  clear: both;
  margin: 0 calc(50% - 50vw);
  width: auto;
  max-width: none;
  line-height: 0;
}

/* wpautop runs before do_shortcode, so the picture arrives already wrapped
   in a paragraph and brings its bottom margin with it. */
.bigimagebreakout p { margin: 0; }

.bigimagebreakout img {
  width: 100%;
  height: auto;
  display: block;
}

/* Bleeds with the picture, so the 5% inset below still measures against the
   full window and the caption sits where it always did. */
.bigimagebreakout-caption {
  font-family: var(--rsc-sans);
  font-size: .95rem;
  letter-spacing: 0;
  color: var(--rsc-muted);
  margin: 0 calc(50% - 50vw);
  width: auto;
  max-width: none;
  padding: 20px 5%;
  line-height: 1.4;
}

/* Article body links */
.bigimagebreakout-caption a {
  color: #1a1a1a;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  text-decoration-color: rgba(165, 28, 48, .4);
  transition: text-decoration-color .15s, color .15s;
}




/* --- h3.subhead / h4.subsubhead --- */

h3.subhead {
  font-family: var(--rsc-sans);
  font-size: 1.8rem;
  font-weight: normal;
  line-height: 1.3;
  color: #333;
  margin: 0;
  padding: 45px 0 0;
}

h4.subsubhead {
  font-family: var(--rsc-sans);
  font-size: 1.4rem;
  font-weight: normal;
  color: #333;
  margin: 0;
  padding: 25px 0 0;
}

/* --- [dropcap] --- */

.dropcap {
  font-family: var(--rsc-serif);
  font-size: 600%;
  font-weight: normal;
  float: left;
  line-height: 0.8em;
  padding: 0 15px 10px 0;
  color: #333;
  position: relative;
}

/* --- [storybreak] --- */

.storybreak-simple {
  margin: 40px 0;
  text-align: center;
  font-family: var(--rsc-serif);
  font-size: 1.2rem;
  line-height: 18px;
  color: rgba(0,0,0,.2);
  height: auto;
  width: 100%;
  clear: both;
}

.storybreak-simple span::before {
  content: '\00A7\00A0\00A0\00A0\00A0\00A7\00A0\00A0\00A0\00A0\00A7';
}

.storybreak-simple.storybreak-asterism span::before { content: '\2042'; }
.storybreak-simple.storybreak-texas span::before    { content: 'q q q'; }

.storybreak-simple.storybreak-tv span::before {
  content: '\1F4FA\00A0\00A0\00A0\00A0\1F4FA\00A0\00A0\00A0\00A0\1F4FA';
}
.storybreak-simple.storybreak-camera span::before {
  content: '\1F4F7\00A0\00A0\00A0\00A0\1F4F7\00A0\00A0\00A0\00A0\1F4F7';
}
.storybreak-simple.storybreak-tv,
.storybreak-simple.storybreak-camera { color: rgba(0,0,0,.7); }

.storybreak-simple.storybreak-medium span::before {
  content: '...';
  letter-spacing: .6em;
  color: black;
}
.storybreak-simple.storybreak-medium { margin: 80px 0 40px; }

/* --- [conl] / [conr] / [conm] / [conml] / [conmr] (Q&A) --- */

.conl  { margin: 30px 60px 30px 0;   color: #4a4a4a; font-family: var(--rsc-serif); font-size: inherit; line-height: inherit; letter-spacing: 0.01rem; }
.conr  { margin: 30px 0 30px 60px;   color: #4a4a4a; font-family: var(--rsc-serif); font-size: inherit; line-height: inherit; letter-spacing: 0.01rem; }
.conm  { margin: 30px 30px 30px 30px; color: #4a4a4a; font-family: var(--rsc-serif); font-size: inherit; line-height: inherit; letter-spacing: 0.01rem; }
.conml { margin: 30px 45px 30px 15px; color: #4a4a4a; font-family: var(--rsc-serif); font-size: inherit; line-height: inherit; letter-spacing: 0.01rem; }
.conmr { margin: 30px 15px 30px 45px; color: #4a4a4a; font-family: var(--rsc-serif); font-size: inherit; line-height: inherit; letter-spacing: 0.01rem; }

.conl strong, .conr strong, .conm strong, .conml strong, .conmr strong {
  font-family: var(--rsc-sans);
  text-transform: uppercase;
  font-size: 0.9rem;
}

.conl  strong { color: indianred; }
.conr  strong { color: steelblue; }
.conm  strong { color: darkolivegreen; }
.conml strong { color: #751770; }
.conmr strong { color: #B88202; }

/* ================================================================
   BYLINE
   ================================================================ */

.roscoe-byline-row {
  font-family: var(--rsc-sans);
}

.roscoe-bylineauthor {
  font-size: calc(1.125rem * var(--rsc-tscale, 1));
  color: var(--rsc-text);
  font-weight: 700;
}

.roscoe-bylineauthor a { color: var(--rsc-text); text-transform: uppercase; text-decoration: none; }
.roscoe-bylineauthor-by { font-style: italic; font-weight: 400; }

.roscoe-byline-twitter { margin-left: 12px; font-size: .85rem; font-weight: 400; }
.roscoe-byline-twitter a { color: var(--rsc-muted); text-decoration: none; }

.roscoe-bylinedate {
  display: block;
  font-size: 1.125rem;
  color: var(--rsc-muted);
  margin-top: 5px;
  font-weight: 400;
}

/* Edit link, at the end of the byline date. It is only in the markup at
   all for someone who can edit the post (roscoe-single-standardpost.php
   tests get_edit_post_link, which is null otherwise), so a reader never
   receives it — this only governs when an editor sees it.

   opacity rather than display, so revealing it doesn't shift the date
   beside it. Hovering anywhere on the byline row brings it up, because an
   invisible target can't be hovered on its own. Keyboard focus shows it
   too, and on touch — where there is no hover at all — it simply stays
   visible, otherwise it would be unreachable on a phone or tablet. */
.roscoe-bylineedit {
  opacity: 0;
  margin-left: 9px;
  font-size: .8em;
  color: var(--rsc-muted);
  text-decoration: none;
  transition: opacity .15s, color .15s;
}
.roscoe-byline-row:hover .roscoe-bylineedit,
.roscoe-bylineedit:focus-visible { opacity: 1; }
.roscoe-bylineedit:hover { color: #A51C30; }

/* No hover, no button. It was briefly left visible on touch so an editor
   could still reach it, but that put it into every phone screenshot of the
   site. Editing from a phone is rare; screenshotting isn't. wp-admin is
   still a URL away. */
@media (hover: none) {
  .roscoe-bylineedit { display: none; }
}

/* ================================================================
   TRANSLATIONS
   ================================================================ */

.roscoe-byline-translations {
  margin-top: 10px;
  font-size: .9rem;
  font-family: var(--rsc-sans);
}

.roscoe-byline-translations a { color: var(--rsc-muted); }

/* ================================================================
   WIRE LINK POST
   ================================================================ */

/* Link posts suppress the Roscoe hero headline, and that headline's wrapper
   was what held the hero image away from the sticky bar — without it the
   image sits flush at the top. Put the space back on the image itself. */
body.rsc-link-post .rsc-stack-img-wrap { margin-top: 44px; }

/* And with the headline gone, the body section's 64px top padding leaves
   too big a gap under that image. Tightened only when an image actually
   precedes it (#rsc-l1-after only exists when the hero rendered one), so
   the far more common artless link post keeps its full opening space. */
body.rsc-link-post #rsc-l1-after + .roscoe-body-zone .roscoe-body-section,
body.rsc-link-post #rsc-l1-after + .rsc-has-sidebar .roscoe-body-section {
  padding-top: 30px;
}

/* When the hero rendered something, the body section opens tighter — the
   hero already put space above this point. Set in roscoe-single-meat.php,
   which is the only place that knows whether the hero produced anything. */
.roscoe-body-section.rsc-after-hero { padding-top: 44px; }

/* Link posts run this headline block below the image instead of the Roscoe
   hero headline, which roscoe-single-meat.php suppresses for the category.
   Sans-serif against the serif body, with the meta line boxed in by rules
   above and below so it reads as a masthead for the post. */

.roscoe-linkpost-head { margin-bottom: 34px; }

h1.roscoe-linkheadline {
  font-family: var(--rsc-sans);
  font-weight: 700;
  font-size: clamp(1.7rem, 3.4vw, 2.3rem);
  line-height: 1.18;
  letter-spacing: -.02em;
  text-wrap: balance;
  margin: 0 0 20px;
}

h1.roscoe-linkheadline a { color: var(--rsc-text); text-decoration: none; }
h1.roscoe-linkheadline a:hover { color: #A51C30; }

.roscoe-linkmeta {
  font-family: var(--rsc-sans);
  font-size: 1rem;
  line-height: 1.5;
  color: #555;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 26px;
  border-top: 2px solid var(--rsc-text);
  border-bottom: 1px solid var(--rsc-border);
  padding: 11px 0;
}

.roscoe-linkmeta-item { display: inline-flex; align-items: baseline; gap: 7px; }

.roscoe-linkmeta-label {
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--rsc-muted);
}

.roscoe-linkmeta a { color: var(--rsc-text); text-decoration: none; }
.roscoe-linkmeta a:hover { color: #A51C30; text-decoration: underline; }

/* The outbound link is the point of the post, so it gets the accent. */
.roscoe-linkmeta-out { color: #A51C30 !important; font-weight: 600; }

@media (max-width: 600px) {
  .roscoe-linkmeta { gap: 4px 18px; font-size: .92rem; }
}

/* ================================================================
   POST BOTTOM
   ================================================================ */

.roscoe-post-bottom {
  font-family: var(--rsc-sans);
  border-top: 1px solid var(--rsc-border);
  margin-top: 48px;
  padding: 20px 0;
}

.roscoe-datestamprow {
  font-size: .85rem;
  color: var(--rsc-muted);
  margin-bottom: 16px;
}

.roscoe-datestamprow a { color: var(--rsc-muted); text-decoration: none; }
.roscoe-datestamprow strong { text-transform: uppercase; color: #444; letter-spacing: .04em; }

.roscoe-sharing-row { font-size: .85rem; font-weight: 700; }

.roscoe-sharing-row a {
  color: #444;
  text-decoration: none;
  margin-right: 20px;
  text-transform: uppercase;
  letter-spacing: .04em;
}

.roscoe-sharing-row a:hover { color: #999; }
.roscoe-sharing-row i { margin-right: 5px; }

.roscoe-serieswrapper {
  font-family: var(--rsc-sans);
  font-size: .85rem;
  color: var(--rsc-muted);
  margin: 16px 0;
  font-weight: 700;
  text-transform: uppercase;
}

.roscoe-serieswrapper a { color: #444; text-decoration: none; }

/* Post-bottom meta row: hub link + tags toggle on one line */
.roscoe-post-meta-row {
  display: flex;
  align-items: baseline;
  gap: 24px;
  flex-wrap: wrap;
}

.roscoe-post-date { font-family: var(--rsc-sans); font-size: .85rem; color: var(--rsc-muted); }

.roscoe-hub-link { font-size: .85rem; }
.roscoe-hub-link strong { color: #444; }
.roscoe-hub-link a { text-decoration: none; font-weight: 700; }

.roscoe-tags-toggle {
  font-family: var(--rsc-sans);
  font-size: .85rem;
  font-weight: 700;
  color: var(--rsc-muted);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}

.roscoe-tags-toggle:hover { color: var(--rsc-text); }

/* Tags panel — hidden by default, shown via .rsc-open */
.roscoe-tags {
  display: none;
  flex-wrap: wrap;
  gap: 6px 12px;
  margin-top: 10px;
}

.roscoe-tags.rsc-open {
  display: flex;
}

.roscoe-tag {
  font-family: var(--rsc-sans);
  font-size: .8rem;
  color: var(--rsc-muted);
}

.roscoe-tag a { color: var(--rsc-muted); text-decoration: none; }
.roscoe-tag a:hover { color: var(--rsc-text); }

/* ================================================================
   NEWSLETTER SIGNUP BOX
   ================================================================ */

.roscoe-newsletter-box {
  margin: 48px 0 0;
  padding: 36px 40px 44px;
  background: #EDCDA5;
  color: #1a1a1a;
}

/* The bleed pushes the box 50px past each side of the 700px column, so it
   needs 800px of window before it fits; this used to switch on at 700 and
   ran 16px off the screen at tablet widths. 820 leaves room for a
   scrollbar, which the width a media query sees includes. */
@media (min-width: 820px) {
  .roscoe-newsletter-box {
    width: calc(100% + 100px);
    margin-left: -50px;
    margin-right: -50px;
  }
}

/* No bleed when there is a sidebar.
   The bleed above assumes the column is centred in the window, so 50px of
   slack exists on both sides. With a sidebar the column is pushed left and
   the rail takes that slack, so the box runs under the rail on the right
   and off the well on the left. It compresses to the column perfectly well,
   which is the whole fix — there is nothing to expand into.

   Deliberately outside the media query: this has to hold at every width, and
   two classes beat the one inside it regardless of source order. Same shape
   as the .rsc-home exception further down, for the same reason — the
   homepage column is not centred in the window either. */
.rsc-has-sidebar .roscoe-newsletter-box {
  width: auto;
  margin-left: 0;
  margin-right: 0;
}

.roscoe-newsletter-hed {
  font-family: var(--rsc-headline);
  font-size: 1.75rem;
  font-weight: 400;
  line-height: 1.2;
  margin: 0 0 8px;
  color: #1a1a1a;
}

.roscoe-newsletter-desc {
  font-family: var(--rsc-sans);
  font-size: 1.05rem;
  color: rgba(0,0,0,.65);
  margin: 0 0 20px;
}

.roscoe-newsletter-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.roscoe-nl-email-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.roscoe-nl-name-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  overflow: hidden;
  max-height: 0;
  margin-bottom: -8px;
  transition: max-height .28s ease, margin-bottom .28s ease;
}

.roscoe-nl-name-row.is-visible {
  max-height: 60px;
  margin-bottom: 0;
}

.roscoe-nl-input {
  flex: 1;
  min-width: 0;
  font-family: var(--rsc-sans);
  font-size: 1rem;
  padding: 10px 14px;
  border: 1px solid rgba(0,0,0,.25);
  border-radius: 3px;
  background: #fff;
  color: #1a1a1a;
}

.roscoe-nl-input::placeholder { color: rgba(0,0,0,.4); }

.roscoe-newsletter-form button[type="submit"] {
  font-family: var(--rsc-sans);
  font-size: .85rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  padding: 10px 20px;
  background: #A51C30;
  color: #fff;
  border: none;
  border-radius: 3px;
  cursor: pointer;
  white-space: nowrap;
}

.roscoe-newsletter-form button[type="submit"]:hover { background: #8b1525; }

/* The author bio is a boxed callout with rules above and below. When the
   post-bottom meta follows it directly, its own top rule lands a second
   line right beneath the box's — one divider is enough. */
.roscoe-author-bio + .roscoe-post-bottom { border-top: 0; }

/* ================================================================
   AUTHOR BIO BOX
   ================================================================ */

.roscoe-author-bio {
  border-top: 1px solid var(--rsc-border);
  margin: 40px 0 0;
  padding: 28px 0 0;
  font-family: var(--rsc-sans);
  font-size: .95rem;
  line-height: 1.6;
  color: #444;
}

.roscoe-author-bio p { margin: 0 0 12px; }
.roscoe-author-bio p:last-child { margin-bottom: 0; }
.roscoe-author-bio a { color: var(--rsc-text); }
.roscoe-author-bio a:hover { color: #555; }

/* ================================================================
   SOCK — five most recent stories, just above the footer

   Light and ruled, not a dark slab. The dark band was the only one in
   Roscoe, which made it read as the top of the footer rather than the end
   of the article — furniture instead of journalism. On the page's own
   ground with a heavy top rule, it reads as the last editorial module,
   and the footer's tone shift becomes the only one on the page.

   Rules do the separating: 3px across the top (the same device as the
   hero and the homepage's All stories button), hairlines between the
   columns. It is labelled now, too — nothing previously said these were
   the newest stories.
   ================================================================ */

.roscoe-sock {
  /* A tint rather than a rule. The 3px line read as a hard stop across the
     whole page; the block only needs to sit apart from the article, and a
     shade does that without cutting the page in two. Same warm light the
     WWR rail uses, so the two read as the same kind of furniture. */
  background: #F2F0EB;
  padding: 0 0 64px;
  margin-top: 40px;
}

.roscoe-sock-head {
  max-width: var(--rsc-well);
  margin: 0 auto;
  padding: 40px 28px 14px;
  text-align: center;
  border-bottom: 1px solid var(--rsc-border);
  margin-bottom: 4px;
}

h2.roscoe-sock-kicker {
  font-family: var(--rsc-sans);
  font-size: 1.2rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--rsc-text);
  margin: 0;
}

.roscoe-sock-inner {
  max-width: var(--rsc-well);
  margin: 0 auto;
  padding: 26px 28px 0;
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  gap: 40px;
  /* stretch, not start: the column rules below need full-height boxes to
     run against, the same way .rsc-hero-col works on the homepage. */
  align-items: stretch;
}

.sock-col {
  display: flex;
  flex-direction: column;
  gap: 36px;
}

/* Hairlines between the three columns. */
.roscoe-sock-inner > .sock-col + .sock-col {
  border-left: 1px solid var(--rsc-border);
  padding-left: 40px;
}

/* Center column: gap handled by element margins, not column gap */
.sock-center { gap: 0; }

/* Side cards */
.sock-card { display: flex; flex-direction: column; gap: 12px; }

.sock-card-img-link { display: block; }

.sock-card-img {
  aspect-ratio: 16/9;
  overflow: hidden;
  background: #eee;
}

.sock-card-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: opacity .2s;
}

.sock-card-img-link:hover .sock-card-img img { opacity: .85; }

.sock-card-text { font-family: var(--rsc-sans); }

h3.sock-hed {
  font-family: var(--rsc-headline);
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.25;
  margin: 0 0 6px;
}

h3.sock-hed a { color: var(--rsc-text); text-decoration: none; }
h3.sock-hed a:hover { color: #A51C30; }

.sock-deck {
  font-family: var(--rsc-sans);
  font-size: .85rem;
  line-height: 1.45;
  color: var(--rsc-muted);
  margin: 0 0 6px;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.sock-byline {
  font-family: var(--rsc-sans);
  font-size: .75rem;
  color: var(--rsc-muted);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
}

/* Center featured story */
.sock-featured-img-link { display: block; }

.sock-featured-img {
  aspect-ratio: 3/2;
  overflow: hidden;
  background: #eee;
  margin-bottom: 18px;
}

.sock-featured-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: opacity .2s;
}

.sock-featured-img-link:hover .sock-featured-img img { opacity: .85; }

h2.sock-featured-hed {
  font-family: var(--rsc-headline);
  font-size: clamp(1.4rem, 2.2vw, 1.9rem);
  font-weight: 400;
  line-height: 1.15;
  margin: 0 0 10px;
}

h2.sock-featured-hed a { color: var(--rsc-text); text-decoration: none; }
h2.sock-featured-hed a:hover { color: #A51C30; }

.sock-featured-deck {
  font-family: var(--rsc-sans);
  font-size: .9rem;
  line-height: 1.5;
  color: var(--rsc-muted);
  margin: 0 0 10px;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ================================================================
   FOOTER
   ================================================================ */

.roscoe-footer { background: #f7f6f5; border-top: 1px solid var(--rsc-border); }

.footer-wrapper {
  max-width: var(--rsc-well);
  margin: 0 auto;
  padding: 40px 28px 32px;
}

/* --- First row: logo + nav dots (left) | social links (right) --- */

.footer-first-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 20px;
  padding-bottom: 28px;
}

.first-row-left {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
}

.footer-branding {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

.footer-logo a { display: block; }
.footer-logo img { height: 90px; display: block; }

.footer-highlight ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}

.footer-highlight li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--rsc-serif);
  font-style: normal;
  font-size: 2rem;
  margin-right: 20px;
  margin-bottom: 0;
}

.footer-highlight li.footer-highlight-active { font-style: italic; }

.footer-highlight li a { color: #333; text-decoration: none; }
.footer-highlight li a:hover { color: #000; }

/* Social links — stacked vertically, right-aligned, all-caps */
.footer-social ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0;
}

.footer-social li { margin: 0; }

.footer-social a {
  font-family: var(--rsc-sans);
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: #555;
  text-decoration: none;
}

.footer-social a:hover { color: #000; }

/* --- Mission statement (large) --- */

.footer-description {
  font-family: var(--rsc-serif);
  font-size: clamp(1.15rem, 2.2vw, 1.65rem);
  line-height: 1.45;
  color: #1a1a1a;
  margin: 32px 0 24px;
  max-width: 820px;
}

.footer-description p { margin: 0; }

.footer-description em {
  font-family: var(--rsc-serif);
  font-style: italic;
}

.footer-description a {
  color: #1a1a1a;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 2px;
}

/* --- Contact block --- */

.footer-contact {
  font-family: var(--rsc-sans);
  font-size: .85rem;
  color: #555;
  line-height: 1.65;
}

/* --- Bottom bar --- */

.footer-bottom { background: #A51C30; }

.footer-bottom-inner {
  max-width: var(--rsc-well);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 28px;
  font-family: var(--rsc-sans);
  font-size: .75rem;
}

.footer-copyright p { margin: 0; color: rgba(255,255,255,.8); }

.footer-links ul { list-style: none; padding: 0; margin: 0; display: flex; gap: 20px; }
.footer-links a { color: rgba(255,255,255,.8); text-decoration: none; }
.footer-links a:hover { color: #fff; }

/* ================================================================
   SIDEBAR
   ================================================================ */

.rsc-has-sidebar {
  display: grid;
  /* Sidebar track = 250px content + 50px left padding (for divider spacing).
     Gap = 50px (left side of divider). Max-width centers body and sidebar
     so outer margins are equal on both sides. */
  grid-template-columns: 1fr 300px;
  gap: 0 50px;
  align-items: start;
  max-width: calc(var(--rsc-body-max) + 300px + 50px + 56px);
  margin: 0 auto;
  padding: 0 28px;
  box-sizing: border-box;
}

.rsc-has-sidebar-main {
  min-width: 0;
}

/* Remove body-section's side padding inside the sidebar layout — the grid
   already provides outer spacing, and the padding would shrink the body well. */
.rsc-has-sidebar .roscoe-body-section {
  padding-left: 0;
  padding-right: 0;
}

/* Remove hed-wrap's side padding inside the sidebar layout for the same reason. */
.rsc-has-sidebar .roscoe-hed-wrap {
  padding-left: 0;
  padding-right: 0;
}

.roscoe-sidebar {
  margin-top: 60px; /* matches .roscoe-hed-wrap padding-top; margin (not padding) so border-left starts here too */
  padding-left: 50px;
  border-left: 1px solid var(--rsc-border);
}

.rsc-sidebar-post {
  padding: 20px 0;
  border-bottom: 1px solid var(--rsc-border);
}

.rsc-sidebar-post:not(:first-child) {
  border-top: 1px solid var(--rsc-border);
}

.rsc-sidebar-img-link {
  display: block;
  margin-bottom: 10px;
}

.rsc-sidebar-img-link img,
img.rsc-sidebar-img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4/3;
  object-fit: cover;
}

.rsc-sidebar-hed {
  display: block;
  font-family: var(--rsc-headline);
  font-size: 1.2rem;
  line-height: 1.3;
  color: var(--rsc-text);
  text-decoration: none;
  margin-bottom: 6px;
}

.rsc-sidebar-hed:hover { text-decoration: underline; }

.rsc-sidebar-byline {
  font-family: var(--rsc-sans);
  font-size: .78rem;
  color: var(--rsc-muted);
}

@media (max-width: 900px) {
  .rsc-has-sidebar {
    grid-template-columns: 1fr;
    max-width: var(--rsc-well);
    padding: 0;
  }

  /* Restore side padding that the desktop sidebar overrides zeroed out */
  .rsc-has-sidebar .roscoe-hed-wrap {
    padding-left: 16px;
    padding-right: 16px;
  }
  .rsc-has-sidebar .roscoe-body-section {
    padding-left: 16px;
    padding-right: 16px;
  }

  /* Articles restore their own gutters above, on the two wrappers they use.
     Every other template built on this grid — pages, archives, search, 404,
     the WWR pages, and the hub/tag/author loops — has different children, so
     it inherited the zeroed padding and ran edge to edge. Padding the main
     column covers all of them at once. Scoped away from articles so
     full-bleed images inside a story body keep reaching the edge. */
  .rsc-page-sidebar .rsc-has-sidebar-main,
  .rsc-archive .rsc-has-sidebar-main {
    padding-left: 16px;
    padding-right: 16px;
  }

  /* Hide sidebar entirely — the sock below already shows recent stories */
  .roscoe-sidebar { display: none; }
}

/* ================================================================
   RESPONSIVE
   ================================================================ */

@media (max-width: 960px) {
  /* --- Layouts 3 and 4 stack here ---
     Once they are a single column they are Layout 1 in all but name, so
     they take Layout 1's rhythm: text first with real side padding, image
     under it, caption under that. The desktop rules centre the text
     vertically and pad it for a half-width column, neither of which makes
     sense stacked. */
  .rsc-side-hero,
  .rsc-side-hero.rsc-reversed { flex-direction: column; padding: 0 0 8px; }

  .rsc-split-hero,
  .rsc-split-hero.rsc-reversed { flex-direction: column; min-height: 0; }

  /* Undo the desktop halves. Once the hero is a COLUMN, flex-basis measures
     height, not width — so 50% would make each band half the hero's height
     instead of half its width, and max-width:50% would squeeze both into
     the left half of the phone. Both have to go. */
  .rsc-split-text,
  .rsc-split-img {
    flex: 0 0 auto;
    max-width: none;
  }

  .rsc-side-text,
  .rsc-split-text {
    justify-content: flex-start;
    /* Matches the existing 600px rule further down so the two bands agree. */
    padding: 32px 24px 28px;
    min-height: 0;
  }

  /* Layout 4 used to write min-height:60vh inline on its image, which these
     rules had to unseat with !important. The inline style is gone (4 Oct
     2026) and the sizing now lives in the stylesheet, so plain declarations
     are enough. Stacked, the image goes back to its natural aspect ratio
     instead of filling a column: flex-grow off, height auto. */
  .rsc-side-img img { min-height: 0; height: auto; }
  .rsc-split-img img { min-height: 0; height: auto; }

  /* Stacked there are no halves to hold the caption to, so it runs the full
     width under its picture like any other. 24px matches the text column's
     side padding above, so its left edge lines up with the headline rather
     than sitting 8px inside it. */
  .rsc-side-img .rsc-img-caption { padding: 12px 24px 0; }
  .rsc-split-cap,
  .rsc-split-cap.rsc-reversed {
    width: auto;
    margin-left: 0;
    padding: 12px 24px 0;
  }

  /* --- Layout 2 (overlay) reverts to Layout 1 ---
     Text over a photo works at desktop and is unreadable on a phone: the
     headline covers the picture and the gradient eats what's left. Let the
     text escape the image instead.

     The overlay branch writes its colours inline (white on the photo), so
     the fallback has to out-rank those with !important — the one place in
     this file that is warranted. */
  .rsc-overlay-hero { position: static; }
  .rsc-overlay-hero > img { min-height: 0 !important; height: auto !important; }
  .rsc-overlay-gradient { display: none; }

  .rsc-overlay-text {
    position: static !important;
    inset: auto !important;
    padding: 28px 16px 0 !important;
    text-align: left !important;
  }

  .rsc-overlay-text h2.roscoe-headline { color: var(--rsc-text) !important; text-align: left !important; }
  .rsc-overlay-text .roscoe-post-deck { color: #555 !important; text-align: left !important; }
  .rsc-overlay-text .roscoe-eyebrow-wrap { color: var(--rsc-text) !important; text-align: left !important; }


  .roscoe-hed-wrap { padding: 32px 16px 0; }
  .roscoe-site-header-inner { padding: 12px 16px; }
  .rsc-overlay-text { padding: 24px; }

  /* Sock: center story spans full width on top, sides stack below in 2 cols */
  .roscoe-sock-inner {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto auto;
  }

  /* The centre now sits above the sides rather than between them, so a rule
     to the left of it would divide nothing. Only the left/right pair keeps
     one, and it moves onto .sock-right — the two are no longer adjacent in
     source order once the centre is pulled to the first row. */
  .roscoe-sock-inner > .sock-col + .sock-col { border-left: 0; padding-left: 0; }
  /* .sock-col.sock-right, not .sock-right: the reset above is three classes
     deep (.roscoe-sock-inner > .sock-col + .sock-col) and outranks a
     two-class selector no matter how late it appears. */
  .roscoe-sock-inner > .sock-col.sock-right {
    border-left: 1px solid var(--rsc-border);
    padding-left: 40px;
  }

  .sock-center {
    grid-column: 1 / -1;
    order: -1;
  }

  /* Nav overlay: groups stack vertically */
  .rsc-nav-groups { gap: 40px; }
  .rsc-overlay-content { padding: 40px 32px; }
}

@media (max-width: 600px) {
  .rsc-side-text,
  .rsc-split-text { padding: 32px 24px; }

  .roscoe-body-section { padding: 40px 16px 60px; }

  .footer-first-row { flex-direction: column; }
  .footer-bottom-inner { flex-direction: column; gap: 8px; text-align: center; }

  h2.roscoe-headline.hl-xl { font-size: calc(clamp(2.2rem, 8vw, 3.5rem) * var(--rsc-tscale, 1)); }

  /* Sock: single column */
  .roscoe-sock-inner {
    grid-template-columns: 1fr;
  }

  .sock-center { grid-column: 1; }

  .roscoe-sock { padding: 0 0 48px; }
  .roscoe-sock-head { padding: 28px 16px 12px; }
  .roscoe-sock-inner { padding: 22px 16px 0; gap: 28px; }

  /* Stacked: no vertical rules left to draw. Same three-class weight as the
     960px rule above, which would otherwise keep the right-hand rule alive
     all the way down to phone width. */
  .roscoe-sock-inner > .sock-col + .sock-col,
  .roscoe-sock-inner > .sock-col.sock-right { border-left: 0; padding-left: 0; }

  /* Overlay: one screen, no scrolling. On a phone it is height that runs
     out, not width, so the links and the space between them scale with the
     viewport HEIGHT (svh = the height with the browser's toolbars showing).
     At 1.5rem they fit a tall phone; an iPhone SE gets about 1.2rem. The
     Foundation link stands in for Fellowships, Reports and Storyboard. */
  .rsc-overlay-content { padding: 28px 20px; }
  .rsc-nav-groups { flex-direction: column; gap: clamp(16px, 3svh, 32px); margin-bottom: clamp(20px, 4svh, 52px); }
  .rsc-nav-group a { font-size: clamp(1.15rem, 3.4svh, 1.5rem); margin-bottom: clamp(8px, 1.6svh, 14px); }
  .rsc-nav-group a.rsc-nav-more { display: none; }
  .rsc-nav-group a:has(+ a.rsc-nav-more) { margin-bottom: 0; }
  .rsc-nav-group-label { margin-bottom: 12px; }

  /* Hide related-story embeds — screen too narrow to be useful */
  .embed-relatedstory,
  p.inline-relatedstory { display: none; }

  /* Caption/credit: restore the side padding the full-bleed image doesn't have */
  .rsc-img-caption { padding-left: 16px; padding-right: 16px; }

  /* Footer: hide social icons row */
  .footer-social { display: none; }

  /* Deck: scale down to roughly body text size at mobile */
  .roscoe-post-deck { font-size: calc(1.1rem * var(--rsc-tscale, 1)); }

  /* Sticky header: reclaim the pixel space at mobile */
  .roscoe-site-header { position: relative; }
}

/* ================================================================
   HOMEPAGE
   ================================================================ */

/* The topic panels bleed with 100vw, which is wider than the content area
   by the scrollbar. Clipping absorbs that without a scrollbar. */
/* The big masthead — logo that shrinks on scroll, Nieman family bar, beats
   bar. Homepage only; every other page takes the small bar. Kept separate
   from .rsc-home-page because the two answer different questions: this one
   is "which masthead", that one is "does this page have full-bleed bands".
   They happen to coincide again, but the rules below are about the header
   and would follow it if it ever moved. */
body.rsc-big-header {
  /* The header loses ~80px of in-flow height when it shrinks on scroll.
     Scroll anchoring would compensate by moving the scroll position by that
     same amount — which is enough to swing the trigger back and forth and
     make the logo jitter. The sentinel in header-roscoe.php already breaks
     that loop; this removes the mechanism entirely. Safe here because every
     image on the page reserves its box with aspect-ratio, so there is no
     late reflow for anchoring to correct. */
  overflow-anchor: none;

  /* Two weights of rule, after Monocle: black hairlines that carry the
     structure, and a mid grey for dividers inside a module. The old
     #e0e0e0 was doing both jobs and reading as neither. */
  --rsc-rule-strong: #000;
  --rsc-rule-mid:    #b9b6b0;
}

/* Homepage only, and genuinely: the topic panels bleed with 100vw, wider
   than the content area by the width of the scrollbar. Clipping absorbs
   that without producing one. No other page has a full-bleed band. */
body.rsc-home-page { overflow-x: clip; }

.rsc-home {
  max-width: var(--rsc-well);
  margin: 0 auto;
  padding: 0 28px 76px;
}

/* ---------------- Nieman family bar (homepage only) ---------------- */

/* Tinted band above the masthead. Nieman's own top bar is #EBE9E8; this
   runs a shade lighter. The tint does the separating, so this row carries no
   rule of its own — and no crimson stripe above it. */
.rsc-familybar {
  background: #f7f6f5;
}

/* Zero-height marker between the family bar and the header. The header
   script watches it to decide when to shrink; see header-roscoe.php. */
#rsc-hdr-sentinel {
  height: 1px;
  margin-bottom: -1px;
  pointer-events: none;
}

.rsc-familybar-inner {
  max-width: var(--rsc-well);
  margin: 0 auto;
  padding: 9px 28px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  font-family: var(--rsc-sans);
  font-size: .78rem;
}

.rsc-familybar-links { display: flex; gap: 22px; flex-wrap: wrap; }

.rsc-familybar-links a {
  color: #555;
  text-decoration: none;
  white-space: nowrap;
}

.rsc-familybar-links a:first-child { color: var(--rsc-text); font-weight: 600; }
.rsc-familybar-links a:hover { color: #A51C30; }

/* Today's date, where Subscribe used to sit. Quieter than the link it
   replaces — it is a fact, not something to press — so it takes the same
   grey as the sibling links instead of the near-black, bold, uppercase
   treatment the old button wore. Tabular figures so the bar does not
   twitch as the date changes. */
/* NO tabular-nums here, and nowhere else a date is written out in words.
   Schibsted Grotesk's tnum feature puts the COMMA on the tabular advance
   too: measured at 20px it goes from 5.3px to 12.7px, so "September 29,
   2026" opens a visible hole before the comma. Literata and the system
   sans don't do it, which is why it only showed up in Roscoe's sans.
   lining-nums measures identical to normal in both faces — they're already
   lining — so the declaration just comes off. Tabular figures are still
   right where numerals STACK and have no punctuation: .rsc-otd-year, the
   admin tables. */
.rsc-familybar-date {
  color: #555;
  font-size: .78rem;
  white-space: nowrap;
}

/* ---------------- Subscribe, in the masthead ----------------
   Both headers are hamburger / logo / (subscribe + search). Three flex
   children under space-between centred the logo only because the two
   flanking buttons happened to be the same width; a fourth item breaks
   that. So the masthead is a 1fr auto 1fr grid, which centres the logo on
   the HEADER rather than on the space left over, and keeps it centred
   however wide the button turns out to be.

   No longer scoped to the small header: the homepage carries the same
   button now, in the same place, and the Nieman family bar above gave its
   Subscribe up to the date. */
.roscoe-site-header-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
}

/* A grid item stretches to its track by default, which made the hamburger's
   clickable box span the whole left-hand third — clicking empty space beside
   the logo opened the menu. */
.roscoe-site-header-inner > .roscoe-icon-btn { justify-self: start; }

.roscoe-header-right {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
}

/* Filled rather than outlined, so it reads as the one thing on the bar you
   are meant to press.

   The colour is True blue (#154a8a) out of the Roscoe hero palette — not a
   new colour, one the design already owns. Blue rather than the house
   crimson on purpose: crimson is the masthead and the brand, and a crimson
   button beside a crimson wordmark reads as more branding rather than as an
   action. 8.8:1 against white, so the label clears AAA.

   A fixed fill can't use currentColor, and this bar inverts on a dark hero
   and tints on a coloured one — but the blue holds against all of them, and
   a button that changes colour per article would stop being a fixed landmark
   the way a nav item should be. */
.rsc-header-subscribe {
  font-family: var(--rsc-sans);
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  text-decoration: none;
  color: #fff;
  background: #154a8a;
  border: 0;
  border-radius: 3px;
  padding: 7px 13px;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background .15s;
}
.rsc-header-subscribe:hover,
.rsc-header-subscribe:focus-visible { background: #0f3868; }

/* Off on phones. At 390px the logo is 133px and the grid's two side tracks
   have to match it, which left the button flush against the wordmark; and
   the hamburger menu already carries a subscribe link. Nothing is lost by
   giving the small screen back to the logo. 600px because that is where the
   masthead's own width ramp bottoms out. */
@media (max-width: 600px) {
  .rsc-header-subscribe { display: none; }
}

/* ---------------- Subscribe overlay ----------------
   Same full-screen furniture as the site menu and search, but NOT crimson.
   A whole screen of the house red is a lot of red, and this is the one
   overlay a reader lands in by choosing to rather than to navigate.

   Ink navy (#12243a) from the Roscoe hero palette — the same family the
   Subscribe button's True blue comes from, so pressing a blue button opens
   a blue room. Deep rather than saturated: a full screen of #154a8a is
   loud, while the navy reads as a surface and lets the white do the work.
   AND IT BLURS. At .97 the three per cent of page coming through was
   nothing on small text but perfectly legible under a 50px headline —
   enough that the story behind competed with the form in front. Rather
   than going opaque and losing the sense of a layer over the page, the
   backdrop is blurred: nothing behind resolves into words, but the
   surface still has depth and movement. .985 is then plenty of tint.

   Tested against the alternatives — .96 with a heavier 14px blur reads as
   frosted glass, with shapes still sensed behind it, and solid is simply
   flat. Where backdrop-filter is unsupported the .985 alone still lands
   far closer than the .97 it replaces, so the fallback is the fix too. */
#rsc-submenu { background: rgba(18, 36, 58, 0.985); }

.rsc-sub-content { max-width: 680px; }

.rsc-sub-head { margin-bottom: 30px; }

/* Big enough to take two lines and mean it. The longer wording pushed
   this onto a second line anyway, so it may as well be the point — at
   4rem the break after "Lab" falls where a reader would put it.

   opsz pinned to 7 for the same reason as the homepage module headings:
   Literata's small-text cut, drawn sturdy and open, blown up large. Left
   to itself the axis would follow the size and draw the delicate display
   cut instead. */
.rsc-sub-title {
  font-family: var(--rsc-headline);
  font-weight: 600;
  font-variation-settings: "opsz" 7;
  font-size: clamp(2.1rem, 5.2vw, 4rem);
  line-height: 1.08;
  letter-spacing: -.028em;
  margin: 0 0 30px;
  color: #fff;
}

.rsc-sub-standfirst {
  margin: 0;
  font-size: 1rem;
  line-height: 1.5;
  color: rgba(255,255,255,.72);
  max-width: 34em;
}

/* The head now carries the whole pitch, so it gets the room the two
   newsletter cards used to take. */
.rsc-sub-head { margin-bottom: 34px; }

.rsc-sub-fields { margin-bottom: 22px; }

.rsc-sub-label {
  display: block;
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: rgba(255,255,255,.62);
  margin: 0 0 5px;
}
.rsc-sub-label span { font-weight: 400; text-transform: none; letter-spacing: 0; }
.rsc-sub-label + .rsc-sub-input { margin-bottom: 18px; }

/* Underline rather than a box, to match the search field in the overlay
   next door. */
.rsc-sub-input {
  display: block;
  width: 100%;
  background: none;
  border: 0;
  border-bottom: 2px solid rgba(255,255,255,.45);
  border-radius: 0;
  color: #fff;
  font-family: var(--rsc-sans);
  font-size: 1.35rem;
  font-weight: 300;
  padding: 8px 0;
  outline: none;
  caret-color: rgba(255,255,255,.7);
  transition: border-color .15s;
  -webkit-appearance: none;
  appearance: none;
}
.rsc-sub-input:focus { border-bottom-color: #fff; }
/* :user-invalid, not :invalid — an empty required field is invalid from
   the moment it renders, and :not(:placeholder-shown) does not save you
   because a field with no placeholder attribute never matches it, so the
   error colour was showing before anyone had typed a character.
   :user-invalid waits until the reader has actually had a go. Browsers
   without it simply never colour the underline, which is the safe miss. */
.rsc-sub-input:user-invalid { border-bottom-color: #FFB4A2; }

/* Right-aligned: it ends the form, and the eye finishes a line of fields
   on the right rather than returning to the left margin for one more
   thing. */
.rsc-sub-actions { display: flex; justify-content: flex-end; }

.rsc-sub-submit {
  position: relative;
  font-family: var(--rsc-sans);
  font-size: .8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  background: #fff;
  color: #12243a;
  border: 0;
  border-radius: 4px;
  padding: 14px 30px;
  min-width: 170px;
  cursor: pointer;
  transition: opacity .15s;
}
.rsc-sub-submit:hover { opacity: .85; }
.rsc-sub-submit:disabled { cursor: default; }

/* While it waits, the label goes and the ring takes its place. min-width
   above keeps the button from collapsing around the smaller content and
   jumping the layout. */
.rsc-sub-spinner { display: none; }
.rsc-sub-submit.is-busy .rsc-sub-submit-label { visibility: hidden; }
.rsc-sub-submit.is-busy .rsc-sub-spinner {
  display: block;
  position: absolute;
  top: 50%;
  left: 50%;
  width: 17px;
  height: 17px;
  margin: -9px 0 0 -9px;
  border: 2px solid rgba(18,36,58,.25);
  border-top-color: #12243a;
  border-radius: 50%;
  animation: rsc-sub-spin .6s linear infinite;
}
@keyframes rsc-sub-spin { to { transform: rotate(360deg); } }

/* Reduced motion gets a pulse instead of a rotation — still says "working",
   without the spin. */
@media (prefers-reduced-motion: reduce) {
  .rsc-sub-submit.is-busy .rsc-sub-spinner {
    animation: rsc-sub-pulse 1s ease-in-out infinite;
    border-top-color: rgba(18,36,58,.25);
    background: #12243a;
  }
  @keyframes rsc-sub-pulse { 50% { opacity: .25; } }
}

/* Spoken only. The spinner is decorative, so the status line is what a
   screen reader gets — but it must stay in the accessibility tree, which
   display:none would not. */
.rsc-sub-status {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.rsc-sub-small {
  margin: 16px 0 0;
  font-size: .75rem;
  line-height: 1.5;
  color: rgba(255,255,255,.55);
}
.rsc-sub-small a { color: rgba(255,255,255,.8); }

/* Off-screen rather than display:none — a bot reading the DOM should find
   a field that looks fillable. aria-hidden on the wrapper keeps it away
   from screen readers. */
.rsc-sub-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.rsc-sub-done-hed {
  font-family: var(--rsc-headline);
  font-weight: 600;
  font-size: clamp(1.5rem, 3.4vw, 2.2rem);
  line-height: 1.12;
  letter-spacing: -.02em;
  margin: 0 0 12px;
  color: #fff;
}
.rsc-sub-done-body {
  margin: 0 0 22px;
  font-size: 1rem;
  line-height: 1.55;
  color: rgba(255,255,255,.78);
  max-width: 34em;
}
.rsc-sub-done-body strong { color: #fff; }
#rsc-sub-done:focus { outline: none; }

.rsc-sub-again {
  font-family: var(--rsc-sans);
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  background: none;
  color: #fff;
  border: 1px solid rgba(255,255,255,.5);
  border-radius: 4px;
  padding: 11px 20px;
  cursor: pointer;
}
.rsc-sub-again:hover { border-color: #fff; }

@media (max-width: 620px) {
  .rsc-sub-input   { font-size: 1.15rem; }
  /* Full width beats right-aligned on a phone: the thumb is nowhere near
     the right edge, and there is no line of fields to finish. */
  .rsc-sub-actions { display: block; }
  .rsc-sub-submit  { width: 100%; }
}

/* ---------------- Hub nav (homepage only) ----------------
   Small on purpose: it earns its place as a divider under the logo more
   than as navigation. */

/* Two labels per beat, one shown at a time — see roscoe-beats.php. The
   short set takes over just above the width where six full names wrap to a
   second line. display:none rather than visually-hidden so a screen reader
   hears each beat once, not twice.

   Scoped to the hub bar, and only the hub bar. The short names exist to
   solve one problem — six beats on a single horizontal line running out of
   room — and the hamburger overlay does not have that problem: it stacks
   them, one per line, with the width of the screen to play with. Left
   unscoped, shrinking the window silently truncated the overlay's names
   too, so "Reporting & Production" became "Reporting" in the one place
   there was no reason for it to. */
.rsc-beat-short { display: none; }

/* Measured, not guessed. At .8rem/.05em the six full names plus their five
   30px gaps and the bar's 56px of padding come to 1081px; the short set
   comes to 775px. Switching at 1100px leaves 19px of headroom — about what
   1040px left the old .7rem type, which needed 1017px. Re-measure if a beat
   is renamed; "Reporting & Production" is the long pole. */
@media (max-width: 1100px) {
  .rsc-hubnav .rsc-beat-long  { display: none; }
  .rsc-hubnav .rsc-beat-short { display: inline; }
}

.rsc-hubnav-inner {
  max-width: var(--rsc-well);
  margin: 0 auto;
  padding: 10px 28px;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px 30px;
  font-family: var(--rsc-sans);
  /* Up from .7rem: the beats are the only place on the site where the
     taxonomy is put in front of a reader, and at .7 they read as fine
     print. Tracking comes down from .09em to compensate — uppercase still
     wants positive tracking, but .09 was buying air the larger size no
     longer needs, and at .8rem/.09em the six full names need 1133px of
     viewport, more than the layout has to give. em rather than rem on
     purpose: tracking should scale with the type, so the .62rem phone size
     stays proportionally spaced instead of wearing desktop tracking. */
  font-size: .8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
}

.rsc-hubnav-inner a { color: #666; text-decoration: none; white-space: nowrap; }
/* The beat's own colour, as an underline, and the text stays where it is.
   It used to go crimson, which said "link" rather than "this beat" — and
   with six beats now carrying six colours, crimson was the one colour on
   the page that meant something else. --rsc-beat-c is set per link in
   roscoe_beats_links(); currentColor is the fallback if a link ever lands
   here without one. */
.rsc-hubnav-inner a:hover {
  color: var(--rsc-text);
  text-decoration: underline;
  text-decoration-color: var(--rsc-beat-c, currentColor);
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
}

/* ---------------- Header logo ----------------
   One logo, always inside the sticky bar — same structure as article
   pages. It starts at masthead size and shrinks to article size on the
   first scroll. 40px tall is ~241px wide at the mark's 6.03:1. */

/* The masthead collapses in step with the scroll rather than snapping at a
   threshold: header-roscoe.php sets --rsc-shrink from 0 to 1 as the logo row
   scrolls away, and every size below interpolates across it. Scroll 10% of
   the way through the bar and the logo is 10% of the way down.

   Deliberately no transitions on these: the value already tracks scroll
   position, and easing it would only make it lag behind the finger. */

/* The masthead interpolates on two axes at once.

   SCROLL: --rsc-shrink runs 0 to 1 as the logo row leaves the top of the
   screen; every dimension below collapses toward its scrolled size.

   WIDTH: the full sizes used to be fixed until 600px and then snap to the
   phone set, so a 900px tablet wore the full 60px desktop logo and then
   dropped to 30px in one step. --rsc-mast now ramps 0 to 1 between 600 and
   1300px, so the masthead shrinks with the window instead of falling off a
   cliff. The two multiply: a narrow window and a scrolled page both make
   it smaller, and the scrolled size is the same 22px everywhere. */
/* Each dimension ramps between its 600px value and its 1300px value.

   Written as clamp(min, min + (100vw - 600px) * slope, max) rather than a
   shared 0-to-1 ratio, because CSS cannot divide a length by a length to
   produce a unitless number — clamp(0, (100vw - 600px)/700, 1) mixes types
   and the whole declaration is dropped. The multipliers are (max - min)/700.

   The scroll interpolation then runs on top, written from the SCROLLED end
   outwards: 22px + (full - 22px) * (1 - shrink). The obvious form —
   full - (full - 22px) * shrink — computes correctly at every value except
   exactly 1, where Chrome collapses it to 0px; substituting a clamp() twice
   into one multiplication appears to be what trips it. Measured both:
   60 / 41 / 0 the obvious way, 60 / 41 / 22 this way. Same arithmetic,
   different order, and this order survives. */

/* 30px at 600, 60px at 1300 and above. */
body.rsc-big-header .roscoe-logo img {
  --rsc-logo-full: clamp(30px, calc(30px + (100vw - 600px) * 0.0428571), 60px);
  height: calc(22px + (var(--rsc-logo-full) - 22px) * (1 - var(--rsc-shrink, 0)));
  transition: filter .3s;
}

body.rsc-big-header .roscoe-site-header-inner {
  --rsc-mast-pad: clamp(14px, calc(14px + (100vw - 600px) * 0.0342857), 38px);
  padding: calc(12px + (var(--rsc-mast-pad) - 12px) * (1 - var(--rsc-shrink, 0)))
           clamp(16px, calc(16px + (100vw - 600px) * 0.0171429), 28px);
}

/* Hamburger and search ride the same curve. Their SVGs carry width/height
   attributes of 22, which CSS dimensions override. */
body.rsc-big-header .roscoe-icon-btn svg {
  --rsc-icon-full: clamp(26px, calc(26px + (100vw - 600px) * 0.00857143), 32px);
  width:  calc(22px + (var(--rsc-icon-full) - 22px) * (1 - var(--rsc-shrink, 0)));
  height: calc(22px + (var(--rsc-icon-full) - 22px) * (1 - var(--rsc-shrink, 0)));
}

/* ---------------- Masthead rules ----------------
   The three stacked rows (family bar, logo, hub nav) are each closed by a
   black hairline that stops at the content well rather than running to the
   viewport edge. A border on the wrapper would sit on its padded box and
   reach the edges below 1300px, so each rule is an inset pseudo-element
   that lines up with the text above and below it.

   Once the header pins itself over scrolling content it drops its rule and
   goes back to the full-width hairline + shadow, which is what reads
   correctly for a floating bar. */

.rsc-hubnav-inner,
body.rsc-big-header .roscoe-site-header-inner { position: relative; }

.rsc-hubnav-inner::after,
body.rsc-big-header .roscoe-site-header:not(.rsc-scrolled) .roscoe-site-header-inner::after {
  content: "";
  position: absolute;
  left: 28px;
  right: 28px;
  bottom: 0;
  border-bottom: 1px solid var(--rsc-rule-strong);
}

body.rsc-big-header .roscoe-site-header:not(.rsc-scrolled) { border-bottom-color: transparent; }


/* ---------------- Shared story typography ----------------
   Literata Variable runs 200–900, so weight carries a lot of the variety
   here rather than every card changing shape. */

h3.rsc-hed {
  font-family: var(--rsc-headline);
  font-weight: 400;
  font-size: 1.28rem;
  line-height: 1.22;
  letter-spacing: -.015em;
  margin: 0 0 7px;
  text-wrap: balance;
}

h3.rsc-hed a { color: var(--rsc-text); text-decoration: none; }
h3.rsc-hed a:hover { color: #666; }

.rsc-w-light h3.rsc-hed { font-weight: 300; }
.rsc-w-book  h3.rsc-hed { font-weight: 400; }
.rsc-w-med   h3.rsc-hed { font-weight: 550; }
.rsc-w-bold  h3.rsc-hed { font-weight: 700; letter-spacing: -.022em; }

/* Emitted by art-only and text-only cards, shown only in the stacked
   layout. See the note in index-roscoe.php. */
.rsc-deck-stack { display: none; }

.rsc-deck {
  font-family: var(--rsc-sans);
  font-size: .93rem;
  line-height: 1.45;
  color: #666;
}

.rsc-byline {
  font-family: var(--rsc-sans);
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--rsc-muted);
  margin-top: 10px;
}

.rsc-img { display: block; overflow: hidden; background: #eee; }
.rsc-img img { width: 100%; height: 100%; object-fit: cover; display: block; transition: opacity .2s; }
.rsc-img:hover img { opacity: .88; }

/* --- Variants --- */

.rsc-s-art .rsc-img { aspect-ratio: 3/2; margin-bottom: 13px; }

.rsc-s-horiz { display: grid; grid-template-columns: 44% 1fr; gap: 26px; align-items: start; }
.rsc-s-horiz .rsc-img { aspect-ratio: 3/2; }
.rsc-s-horiz h3.rsc-hed { font-size: 1.7rem; letter-spacing: -.025em; }
.rsc-s-horiz .rsc-deck { font-size: 1.02rem; }

/* Text-first stories. A heavier rule above stands in for the missing
   picture so they read as a deliberate treatment, not a failed image. */
.rsc-s-text { border-top: 3px solid var(--rsc-text); padding-top: 12px; }
.rsc-s-text h3.rsc-hed { font-size: 1.34rem; }

/* Link posts point outward rather than being our own reporting. A lighter
   rule and a lighter weight separate them; no italics, no arrow glyph. */
.rsc-s-pointer { border-top: 1px solid var(--rsc-text); padding-top: 12px; }
.rsc-s-pointer h3.rsc-hed { font-size: 1.18rem; }

/* ---------------- Hero ---------------- */

/* 2fr 1fr 1fr: the lead takes half the well and the remaining stories run
   in two columns beside it, rather than one narrow rail.

   align-items: stretch (the default) rather than start, so each column runs
   the full height of the row and its left rule reaches the bottom of
   whichever column is tallest — otherwise the rules stop short and leave a
   gap. Content still sits at the top of each column. */
.rsc-hero {
  display: grid;
  /* Lead + one story column. The rail now runs alongside the hero rather
     than starting beneath it, so the hero has ~874px to work in instead of
     the full 1244px well — a third track here came out around 200px, too
     narrow to set a headline in. */
  grid-template-columns: 2fr 1fr;
  gap: 0 var(--rsc-gut-lg);
  align-items: stretch;
  padding: 36px 0 40px;
  border-bottom: 3px solid var(--rsc-text);
  margin-bottom: 40px;
}

.rsc-hero-col { border-left: 1px solid var(--rsc-rule-mid); padding-left: var(--rsc-gut-lg); }

/* The variants' own decorative top rules would double up in these columns,
   so they come off first... */
.rsc-hero-col .rsc-s-text,
.rsc-hero-col .rsc-s-pointer { border-top: 0; padding-top: 0; }

/* ...and every item after the first gets one hairline separator instead.
   Matching on .rsc-s (every card carries it) outweighs the rule above, so
   the separators survive — without this the stories blur together. */
.rsc-hero-col > .rsc-s + .rsc-s {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--rsc-rule-mid);
}

.rsc-hero-col > *:first-child { padding-top: 0; }

/* Art in these columns runs the full width of the column — never a
   thumbnail squeezed to the left of a headline. */
.rsc-hero-col .rsc-img { aspect-ratio: 16/9; margin-bottom: 11px; }
.rsc-hero-col h3.rsc-hed { font-size: 1.08rem; }

/* ---------------- Hero arrangements ----------------
   Chosen on the Homepage screen in wp-admin. The markup is identical in all
   three; only the class on .rsc-hero changes. Base rules above are the
   lead-left case, so that variant needs nothing of its own. */

/* Mirror: story column first, lead second. `order` rather than reordering
   the markup, so the lead stays first in the source for screen readers and
   for the phone layout, where it belongs at the top either way. */
.rsc-hero-lead-right { grid-template-columns: 1fr 2fr; }
.rsc-hero-lead-right .rsc-hero-lead { order: 2; }
.rsc-hero-lead-right .rsc-hero-col {
  order: 1;
  border-left: 0;
  padding-left: 0;
  border-right: 1px solid var(--rsc-rule-mid);
  padding-right: var(--rsc-gut-lg);
}

/* Full-width lead, three headlines in a row beneath it. The column becomes
   a row: one track above, three below. */
.rsc-hero-lead-full { grid-template-columns: 1fr; }

.rsc-hero-lead-full .rsc-hero-col {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0 var(--rsc-gut-md);
  border-left: 0;
  padding-left: 0;
  margin-top: 30px;
  padding-top: 28px;
  border-top: 1px solid var(--rsc-rule-strong);
}

/* Separators turn from horizontal to vertical. Four classes deep so it
   outranks the three-class stacking rule above rather than fighting it. */
.rsc-hero-lead-full .rsc-hero-col > .rsc-s + .rsc-s {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
  border-left: 1px solid var(--rsc-rule-mid);
  padding-left: var(--rsc-gut-md);
}

/* The lead's picture is the whole point of this arrangement, so it runs
   wider and shallower than the 16:9 it uses beside a column. */
/* No picture in the row of three. Only the first of the three ever has one,
   which tips the row off balance, and in a ~250px column it is too small to
   show anything while still pushing the headline down past its neighbours.
   The lead's picture is the one that matters in this arrangement. The card
   keeps its art everywhere the column is full width — see the 600px block. */
.rsc-hero-lead-full .rsc-hero-col .rsc-img { display: none; }

.rsc-hero-lead-full .rsc-lead-img { margin-bottom: 24px; }
.rsc-hero-lead-full .rsc-hero-col h3.rsc-hed { font-size: 1.12rem; }

/* THE LEAD IS NEVER CROPPED.
   This used to be a fixed box — 16/9 here, 2/1 in the full-width hero and
   again at the 1200px breakpoint — with overflow: hidden and a cover fit,
   so whatever the art's real shape, it got trimmed to the layout's. That is
   fine for a thumbnail grid and wrong for the lead, where the picture is
   the story: a 1536x864 cartoon is 16/9, the 2/1 box is wider, and cover
   took the difference off the top and bottom — which on a cartoon means the
   caption. No ratio and no clipping, so the art prints whole at whatever
   shape it was published in.

   Nothing is lost on layout stability. get_the_post_thumbnail() writes real
   width and height attributes, and with width: 100% / height: auto the
   browser derives the ratio from those and reserves the box before the file
   arrives, exactly as aspect-ratio did. The #eee stays as the placeholder
   that fills that reserved box. */
.rsc-lead-img { display: block; background: #eee; margin-bottom: 20px; }

/* Headline-first lead: the picture closes the story instead of opening it,
   so its margin flips. The byline above it already carries the gap the
   headline block needs, so this is a straight swap rather than a new
   rhythm. */
.rsc-lead-imglast .rsc-lead-img { margin-bottom: 0; margin-top: 22px; }
.rsc-lead-imglast .rsc-byline { margin-bottom: 0; }
.rsc-lead-img img { width: 100%; height: auto; display: block; transition: opacity .2s; }
.rsc-lead-img:hover img { opacity: .88; }

h2.rsc-lead-hed {
  font-family: var(--rsc-headline);
  font-weight: 500;
  /* ~32px at 1280 and capped at 34.4px, down from ~45px — the lead column
     is half the well now, not three-quarters of it. */
  font-size: clamp(1.6rem, 2.5vw, 2.15rem);
  line-height: 1.2;
  letter-spacing: -.03em;
  margin: 0 0 13px;
  text-wrap: balance;
}

h2.rsc-lead-hed a { color: var(--rsc-text); text-decoration: none; }
h2.rsc-lead-hed a:hover { color: #555; }

.rsc-lead-deck {
  font-family: var(--rsc-sans);
  font-size: 1.18rem;
  line-height: 1.42;
  color: #555;
  text-wrap: pretty;
  max-width: 40em;
}

/* ---------------- Feed ----------------
   Two columns: the story river (which now contains the topic panels) and
   one continuous WWR rail. Flex stretch keeps the rail's tint running the
   full height even when its content ends first. */

.rsc-feed { display: flex; gap: 0 40px; align-items: stretch; }
.rsc-feed-main { flex: 1 1 auto; min-width: 0; }

/* Positioned + z-indexed so it paints over the topic panels' full-width
   background bands, which are themselves absolutely positioned. */
.rsc-rail {
  flex: 0 0 330px;
  width: 330px;
  /* Drops the column to the line where the hero's images begin, matching
     .rsc-hero's 36px top padding. Without it the tint starts at the top of
     the feed and runs up to the hub nav as a band of bare colour above the
     masthead. Margin rather than padding so the tint moves with it; flex
     stretch still carries the bottom to the foot of the river. */
  margin-top: 36px;
  background: #F2F0EB;
  position: relative;
  z-index: 2;
}
/* No top padding: .rsc-rail's margin already puts the column at the right
   height, and .rsc-rail-head brings its own 22px above the words. Padding
   here as well would stack on that and push the masthead down twice.

   The rail runs out well before the story column does, so it sticks rather
   than leaving a tall empty margin down the right of the page.

   `top`, not `bottom`. Bottom-sticky reads like the obvious answer — scroll
   until the end is visible, then hold — but Chrome does not shift a
   bottom-stuck box that already sits above its threshold, so it does
   nothing at all here. Measured: top-sticky holds at every scroll position,
   bottom-sticky never engages once.

   The value below is only the short-rail case (clear of the collapsed
   masthead). When the rail is TALLER than the window, a positive top would
   pin it immediately and put its lower half out of reach — so the script in
   index-roscoe.php recalculates it as a negative number, letting the rail
   scroll up until its last item is on screen and holding it there. Without
   that script this still behaves, just less cleverly.

   The tint lives on .rsc-rail, which is still stretched to the full height
   of the feed, so no colour moves — only the words inside it. */
.rsc-rail-in {
  padding: 0 22px 24px;
  position: sticky;
  top: 64px;
}

/* Where the jump links land. scroll-margin-top is honoured by
   scrollIntoView() (the reduced-motion path) and read by the animated one,
   so the two cannot disagree — and the number lives here rather than in
   the script. 56px clears the collapsed masthead; without it the rail's
   first item lands behind the pinned header and reads as though it had
   been scrolled past. */
/* 48px. Measured three ways: the masthead is 63px tall unscrolled at phone
   width and taller still on a tablet now that it scales, but by the time a
   jump lands it has always collapsed — and collapsed it is 47px at every
   width, because the scrolled sizes are fixed. 48 clears that and nothing
   more. The earlier 68 was sized against the *expanded* header, which is a
   state the reader is never in when they arrive here, and the extra 20px is
   what left the foot of the All stories button showing above the rail. */
#rsc-wwr { scroll-margin-top: 48px; }
#rsc-home-top { scroll-margin-top: 0; }

/* ---------------- WWR teaser + running head ----------------
   Both of these exist only below 900px, where the rail has left the side of
   the page. They are declared display:none here and switched on in the
   900px block, so the desktop layout carries no trace of them. */
.rsc-wwr-teaser,
.rsc-rail-totop { display: none; }

.rsc-wwr-teaser {
  grid-template-columns: 1fr;
  gap: 14px;
  background: #F2F0EB;
  padding: 22px 24px 20px;
  margin: 0 0 44px;
  text-decoration: none;
  color: var(--rsc-text);
  border-top: 3px solid var(--rsc-text);
}

.rsc-wwr-teaser-kicker {
  font-family: var(--rsc-sans);
  font-size: 1rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .05em;
}

.rsc-wwr-teaser-items {
  display: grid;
  gap: 12px;
}

/* A bulleted list, so three headlines read as a list of three things
   rather than a paragraph that happens to have line breaks. */
.rsc-wwr-teaser-item {
  display: grid;
  grid-template-columns: 12px 1fr;
  gap: 0 10px;
  align-items: baseline;
}

.rsc-wwr-teaser-bullet { color: #A51C30; font-size: 1rem; line-height: 1.3; }

/* Whole headlines. This used to clamp to two lines, which truncated any
   WWR headline longer than that mid-sentence — and a half-headline is
   worse than no headline, because the reader cannot tell whether the
   missing part was the interesting bit. Three items at full length is
   still a short block. */
.rsc-wwr-teaser-hed {
  font-family: var(--rsc-sans);
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.3;
}

/* A button, not a text link.
   The complaint was that the whole block reads as a static module on a
   phone — fair, because the only interactive signal was a small coloured
   line at the bottom, and a phone has no hover to reveal more. A filled
   pill is the one shape nobody mistakes for decoration. */
.rsc-wwr-teaser-go {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: #A51C30;
  color: #fff;
  font-family: var(--rsc-sans);
  font-size: .95rem;
  font-weight: 700;
  padding: 10px 18px;
  border-radius: 999px;
  transition: background .15s;
}

.rsc-wwr-teaser-arrow { font-size: 1.05em; line-height: 1; }

.rsc-wwr-teaser:hover .rsc-wwr-teaser-go { background: #7d1524; }

/* Touch has no hover, so the press itself has to answer "did that do
   anything". The whole card dips, not just the pill, because the whole
   card is the link — tapping a headline should feel the same as tapping
   the button. */
.rsc-wwr-teaser:active {
  background: #EAE7E0;
  transform: scale(.995);
}
.rsc-wwr-teaser { transition: background .12s, transform .12s; }

@media (prefers-reduced-motion: reduce) {
  .rsc-wwr-teaser { transition: background .12s; }
  .rsc-wwr-teaser:active { transform: none; }
}

.rsc-rail-totop {
  text-align: right;
  font-family: var(--rsc-sans);
  font-size: .95rem;
  font-weight: 700;
  color: #A51C30;
  text-decoration: none;
  margin-top: 26px;
  padding-top: 18px;
  border-top: 1px solid var(--rsc-border);
  width: 100%;
}
.rsc-rail-totop:hover { text-decoration: underline; }

.rsc-block { margin-bottom: 44px; }

/* ---------------- Editor's Choice ----------------
   Hand-picked stories, sitting inside the river between the AI and Local
   News modules. Tinted so it reads as chosen rather than as one more thing
   the page did automatically, and contained rather than full-bleed — the
   topic panels already own the full-bleed device, and a second one running
   under the WWR rail would muddle both.

   Shape follows the topic panels: one card with the picture, the rest as
   headlines beside it. */
.rsc-ec {
  /* Cool, where the WWR rail is warm. The old #EFEDE8 sat a couple of
     percent off the rail's #F2F0EB — near enough to read as the same
     surface rather than a different kind of thing. Shifting hue rather
     than only lightness is what separates them. */
  background: #E7EDEF;
  margin: 30px 0 44px;
}

.rsc-ec-inner { padding: 22px 28px 28px; }

/* The row below Editor's Choice normally opens with a rule, which read as a
   bottom border on the module while its top edge had none. The tint is
   doing the separating on both sides now, so the rule comes off whenever
   the module is what precedes it. */
.rsc-ec + .rsc-row-rule { border-top: 0; padding-top: 0; }

/* Headed like the AI and Local News panels rather than like the rail: this
   is a module in the story column, the same class of thing they are, and it
   was wearing the rail's small sans label. Rule under it mirrors theirs. */
.rsc-ec-head {
  border-bottom: 2px solid rgba(26,26,26,.85);
  padding-bottom: 14px;
  margin-bottom: 26px;
}

h2.rsc-ec-title {
  font-family: var(--rsc-headline);
  font-weight: 600;
  /* Matches h2.rsc-panel-title exactly — see the notes there. Editor's
     Choice is the same class of module as the AI and Local News panels and
     its head measures within ~25px of theirs, so it takes the same size
     ramp and the same pinned optical size. */
  font-variation-settings: "opsz" 7;
  font-size: clamp(1.6rem, 3.4vw, 3rem);
  line-height: 1.1;
  letter-spacing: -.028em;
  color: var(--rsc-text);
  margin: 0;
}

.rsc-ec-body {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 0 var(--rsc-gut-md);
  align-items: stretch;   /* see .rsc-panel-body */
}

/* Only one pick: the card takes the whole width rather than leaving an
   empty track beside it. */
.rsc-ec-body > .rsc-ec-card:only-child { grid-column: 1 / -1; }

.rsc-ec-body > * + * {
  border-left: 1px solid rgba(26,26,26,.16);
  padding-left: var(--rsc-gut-md);
}

.rsc-ec-card .rsc-img { aspect-ratio: 16/9; margin-bottom: 12px; }
.rsc-ec-card h3.rsc-hed { font-size: 1.4rem; }

.rsc-ec-list > * { padding: 11px 0; border-bottom: 1px solid rgba(26,26,26,.14); }
.rsc-ec-list > *:first-child { padding-top: 0; }
.rsc-ec-list > *:last-child { border-bottom: 0; padding-bottom: 0; }
.rsc-ec-list .rsc-s-text,
.rsc-ec-list .rsc-s-pointer { border-top: 0; }
.rsc-ec-list h3.rsc-hed { font-size: 1.125rem; margin-bottom: 0; }

/* ---------------- On this day ----------------
   The archive module. Deliberately text-only: art from 2010 is small,
   inconsistently cropped and often missing, and a row of broken-looking
   cards would undersell the thing. The year is the hook, so it gets the
   display size and the headline follows it. */
.rsc-otd {
  border-top: 3px solid var(--rsc-text);
  padding-top: 18px;
  margin-bottom: 44px;
}

.rsc-otd-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 4px;
}

h2.rsc-otd-title {
  font-family: var(--rsc-sans);
  font-size: 1rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--rsc-text);
  margin: 0;
}

.rsc-otd-date {
  font-family: var(--rsc-sans);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--rsc-muted);
}

.rsc-otd-item {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  gap: 0 20px;
  align-items: baseline;
  padding: 14px 0;
  border-bottom: 1px solid var(--rsc-rule-mid);
  text-decoration: none;
  color: var(--rsc-text);
}

.rsc-otd-item:last-child { border-bottom: 0; padding-bottom: 0; }

.rsc-otd-year {
  font-family: var(--rsc-sans);
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--rsc-muted);
  font-variant-numeric: tabular-nums;
}

.rsc-otd-hed {
  font-family: var(--rsc-headline);
  font-size: 1.3rem;
  line-height: 1.2;
  font-weight: 400;
  text-wrap: balance;
}

.rsc-otd-item:hover .rsc-otd-hed { color: #A51C30; }
.rsc-otd-item:hover .rsc-otd-year { color: var(--rsc-text); }

@media (max-width: 600px) {
  /* The year sits above the headline rather than beside it; a 4.5rem
     column plus a headline is too little room for either on a phone. */
  .rsc-otd-item { grid-template-columns: 1fr; gap: 4px; }
  .rsc-otd-year { font-size: 1.05rem; }
}

/* ---------------- All stories ----------------
   The exit to the reverse-chron archive, at the foot of the story column.
   Sized like a destination rather than a caption: full width of the column,
   sans, and the same 3px rule the hero uses so it reads as the bottom edge
   of the river rather than one more story. */
.rsc-allstories {
  display: block;
  text-align: center;
  font-family: var(--rsc-sans);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--rsc-text);
  text-decoration: none;
  padding: 26px 20px;
  border: 3px solid var(--rsc-text);
  background: transparent;
  transition: background .15s, color .15s;
}
.rsc-allstories:hover,
.rsc-allstories:focus-visible {
  background: var(--rsc-text);
  color: #fff;
}
.rsc-allstories span { display: inline-block; margin-left: 4px; }

/* Rows + the rules that keep the river from reading as one flat flow */
.rsc-row { display: grid; gap: 32px; }
.rsc-row + .rsc-row { margin-top: 30px; }
.rsc-row-1up { grid-template-columns: 1fr; }
.rsc-row-2up { grid-template-columns: repeat(2, 1fr); gap: 0 var(--rsc-gut-md); }
.rsc-row-3up { grid-template-columns: repeat(3, 1fr); gap: 0 var(--rsc-gut-md); }
.rsc-row-rule { border-top: 1px solid var(--rsc-rule-strong); padding-top: 30px; }

/* Vertical hairlines between columns, Monocle-style */
.rsc-row-2up > * + *,
.rsc-row-3up > * + * { border-left: 1px solid var(--rsc-rule-mid); padding-left: var(--rsc-gut-md); }

/* A row that draws its own rule across the top doesn't need each item's
   rule as well — that stacked two lines a few pixels apart. */
.rsc-row-rule > .rsc-s-text,
.rsc-row-rule > .rsc-s-pointer { border-top: 0; padding-top: 0; }

/* Headline-only row: the three stories under the top pair, carrying no art
   and no decks by design. One rule above the row, hairlines between the
   columns, and no per-item rules so nothing doubles. */
.rsc-row-heds {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0 var(--rsc-gut-md);
  border-top: 1px solid var(--rsc-rule-strong);
  padding-top: 26px;
}

.rsc-row-heds > * + * { border-left: 1px solid var(--rsc-rule-mid); padding-left: var(--rsc-gut-md); }

.rsc-row-heds .rsc-s-text,
.rsc-row-heds .rsc-s-pointer { border-top: 0; padding-top: 0; }

.rsc-row-heds h3.rsc-hed { font-size: 1.24rem; margin-bottom: 0; }

/* Catch-all row: a full card on the left, and on the right a column of
   several stories stacked — the link posts skipped by the art/deck slots
   above. Stacking them keeps that column tall enough to sit beside the
   card instead of leaving a block of white space under a lone headline. */
/* stretch, not start: the divider lives on the stack column's left edge, so
   with align-items:start it stopped wherever the stack's content ended and
   left the rule hanging short of the taller card beside it. */
.rsc-row-catch {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 0 var(--rsc-gut-md);
  align-items: stretch;
}

.rsc-row-catch > * + * { border-left: 1px solid var(--rsc-rule-mid); padding-left: var(--rsc-gut-md); }

.rsc-stackcol > .rsc-s + .rsc-s {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--rsc-rule-mid);
}

/* The stack supplies its own separators, so the variants drop theirs. */
.rsc-stackcol .rsc-s-text,
.rsc-stackcol .rsc-s-pointer { border-top: 0; padding-top: 0; }
.rsc-stackcol h3.rsc-hed { font-size: 1.16rem; }

/* ---------------- WWR rail ---------------- */

.rsc-rail-head {
  font-family: var(--rsc-sans);
  font-size: 1rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .05em;
  padding: 22px 0 12px;
  border-bottom: 3px solid var(--rsc-text);
}

.rsc-rail-head a { color: var(--rsc-text); text-decoration: none; }

.rsc-wwr { padding: 20px 0; border-bottom: 1px solid #DEDBD4; }

.rsc-wwr-img { display: block; margin-bottom: 11px; background: #e6e4df; overflow: hidden; }
.rsc-wwr-img img { width: 100%; height: auto; display: block; }

/* Sans — deliberately unlike the serif story headlines */
h3.rsc-wwr-hed {
  font-family: var(--rsc-sans);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.35;
  margin: 0 0 7px;
}

h3.rsc-wwr-hed a { color: var(--rsc-text); text-decoration: none; }
h3.rsc-wwr-hed a:hover { color: #A51C30; }

/* Unclamped: the column is meant to be read straight through like a
   newsletter, so every entry runs its full length. It can do that now
   because the rail is its own continuous column and no longer has to
   match the height of a story block beside it. */
.rsc-wwr-body {
  font-family: var(--rsc-sans);
  font-size: .87rem;
  line-height: 1.5;
  color: #57544e;
}

.rsc-wwr-body p { margin: 0 0 .6em; }
.rsc-wwr-body p:last-child { margin-bottom: 0; }

.rsc-wwr-flag {
  font-family: var(--rsc-sans);
  font-size: .67rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: #A51C30;
  margin-bottom: 6px;
}

/* Nieman Reports / Storyboard / Foundation. It inherits the colour of
   whatever source line it sits in — crimson in .rsc-wwr-flag, the body
   colour inside a quote's attribution — so it reads as part of that line
   rather than as a badge stuck on the front of it. Nudged down a touch
   because a star at cap height sits optically high against uppercase. */
.rsc-wwr-sister {
  font-size: .95em;
  line-height: 1;
  margin-right: 2px;
  letter-spacing: 0;
}

.rsc-wwr-quote {
  font-family: var(--rsc-headline);
  font-weight: 400;
  font-size: 1.28rem;
  line-height: 1.28;
  letter-spacing: -.02em;
  margin: 0 0 9px;
  text-wrap: balance;
}

.rsc-wwr-quote a { color: var(--rsc-text); text-decoration: none; }

.rsc-wwr-attrib {
  font-family: var(--rsc-sans);
  font-size: .8rem;
  line-height: 1.45;
  color: #6a675f;
}


.rsc-wwr-shot { display: block; margin: 11px 0; }
.rsc-wwr-shot img { width: 100%; height: auto; display: block; border: 1px solid #DEDBD4; }

/* Right-aligned: these are onward links, and sitting them against the right
   edge separates them from the headlines above, which all start at the left. */
.rsc-rail-more {
  text-align: right;
  display: block;
  padding-top: 18px;
  font-family: var(--rsc-sans);
  font-size: .8rem;
  font-weight: 700;
  color: #A51C30;
  text-decoration: none;
}

.rsc-rail-more:hover { color: var(--rsc-text); }

/* ---------------- Topic panels ----------------
   The panel lives inside the story column, so its CONTENT is narrowed by
   the WWR rail. Its colored background, though, is painted by an absolutely
   positioned ::before spanning the full viewport width — so the band still
   runs edge to edge, and the rail simply sits on top of it.

   The rail has to out-paint that pseudo-element: an absolutely positioned
   background otherwise paints above a plain block's background regardless
   of DOM order, which is why .rsc-rail is given a z-index below. */

.rsc-panel {
  --rsc-bleed: calc(max(0px, (100vw - var(--rsc-well)) / 2) + 28px);
  position: relative;
  padding: 52px 0 58px;
  margin-bottom: 44px;
}

.rsc-panel::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(-1 * var(--rsc-bleed));
  width: 100vw;
  z-index: 0;
}

.rsc-panel-inner { position: relative; z-index: 1; padding-right: 32px; }

/* Both drawn from the single-template hero palette (roscoe-acf-fields.php)
   so the homepage and article pages share one set of colors. Deep Teal and
   Forest both fall well under roscoe_is_light_color()'s threshold, so they
   carry white text. */
.rsc-panel-teal::before { background: #264653; }  /* Deep Teal  — 10.1:1 on white */
.rsc-panel-rust::before { background: #8B2500; }  /* Rust       —  8.9:1 on white */

/* --- Everything inside a panel inverts for the dark ground --- */

.rsc-panel h3.rsc-hed a,
.rsc-panel h2.rsc-panel-title a { color: #fff; }
.rsc-panel h3.rsc-hed a:hover,
.rsc-panel h2.rsc-panel-title a:hover { color: rgba(255,255,255,.7); }
.rsc-panel .rsc-deck { color: rgba(255,255,255,.72); }
.rsc-panel .rsc-byline { color: rgba(255,255,255,.55); }

.rsc-panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  border-bottom: 2px solid rgba(255,255,255,.85);
  padding-bottom: 14px;
  margin-bottom: 26px;
}

h2.rsc-panel-title {
  font-family: var(--rsc-headline);
  font-weight: 600;

  /* Literata's optical-size axis runs 7 (the cut drawn for footnote-sized
     text: sturdy, open, low contrast) to 72 (the display cut: fine
     hairlines, tight fit). Left to itself the axis follows the rendered
     size, so a 48px heading would be drawn with the delicate cut. Pinning
     it to 7 does the opposite — the chunky small-text letterforms blown up
     large, which is what makes these two module headings read as
     deliberate rather than just big.

     Only opsz is listed, so font-weight above still drives the wght axis.
     This also overrides font-optical-sizing, which is the point. */
  font-variation-settings: "opsz" 7;

  /* Was clamp(1.6rem, 2.3vw, 2rem), which topped out at 32px around
     1390px. The phone end is unchanged — 3.4vw is still under 1.6rem below
     ~750px — and the ceiling is now 48px, reached at about 1410px. Both
     module heads measure ~830px at a 1440px viewport, so the longest of
     the three ("AI and the news") still sets on one line. */
  font-size: clamp(1.6rem, 3.4vw, 3rem);
  line-height: 1.1;
  letter-spacing: -.028em;
  margin: 0;
}

h2.rsc-panel-title a { color: var(--rsc-text); text-decoration: none; }

.rsc-panel-more {
  font-family: var(--rsc-sans);
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: rgba(255,255,255,.7);
  text-decoration: none;
  white-space: nowrap;
}

.rsc-panel-more:hover { color: #fff; }

/* Two columns: one card and the headline list. */
/* stretch, not start: the divider below is drawn on the second column, so
   with `start` it stopped at whichever column happened to be shorter.
   Stretch makes both boxes the height of the taller one; the content still
   sits at the top of each. */
.rsc-panel-body {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 0 var(--rsc-gut-lg);
  align-items: stretch;
}

.rsc-panel-body > * + * { border-left: 1px solid rgba(255,255,255,.28); padding-left: var(--rsc-gut-lg); }

.rsc-panel-card-big h3.rsc-hed { font-size: 1.5rem; }

/* The text-first variants carry their own dark rules; invert those too. */
.rsc-panel .rsc-s-text { border-top-color: rgba(255,255,255,.85); }
.rsc-panel .rsc-s-pointer { border-top-color: rgba(255,255,255,.4); }

/* Headline list — where artless stories and link posts go */
.rsc-panel-list > * { padding: 11px 0; border-bottom: 1px solid rgba(255,255,255,.24); }
.rsc-panel-list > *:first-child { padding-top: 0; }
.rsc-panel-list > *:last-child { border-bottom: 0; padding-bottom: 0; }
.rsc-panel-list .rsc-s-text,
.rsc-panel-list .rsc-s-pointer { border-top: 0; }
.rsc-panel-list h3.rsc-hed { font-size: 1.125rem; margin-bottom: 0; }

/* ---------------- Newsletter ----------------
   The shared box's negative side margins are sized for the 700px article
   well; here it's already full width. */

.rsc-home .roscoe-newsletter-box { width: auto; margin-left: 0; margin-right: 0; }

/* ---------------- Responsive ---------------- */

/* Below this width the desktop grid runs out of room — but the rail is the
   wrong thing to sacrifice. What We're Reading reads well in a narrow
   measure and badly in a wide one, and it is the freshest thing on the
   page. So the rail keeps its column, narrowed, and the STORY rows give up
   theirs: single-column river, panels and Editor's Choice card-over-list.
   The rail only leaves the side at 900px, below. */
@media (max-width: 1200px) {
  /* Card over list once the two columns get tight. */
  .rsc-panel-body { grid-template-columns: 1fr; }
  .rsc-panel-body > * + * { border-left: 0; padding-left: 0; margin-top: 28px; }

  .rsc-ec-body { grid-template-columns: 1fr; }
  .rsc-ec-body > * + * {
    border-left: 0;
    padding-left: 0;
    margin-top: 22px;
    padding-top: 22px;
    border-top: 1px solid rgba(26,26,26,.16);
  }

  /* 280 rather than 330, and a tighter gutter, to buy the story column back
     about 70px without dropping the rail. */
  .rsc-feed { gap: 0 32px; }
  .rsc-rail { flex-basis: 280px; width: 280px; }

  /* One story per row from here down. Matched on .rsc-s, not *, because
     .rsc-row-heds .rsc-s-text zeroes these borders further up and is two
     classes deep — a universal selector loses to it and the stacked
     headlines run together with nothing between them. */
  .rsc-row-2up, .rsc-row-3up, .rsc-row-heds { grid-template-columns: 1fr; gap: 28px; }
  .rsc-row-2up  > .rsc-s + .rsc-s,
  .rsc-row-3up  > .rsc-s + .rsc-s,
  .rsc-row-heds > .rsc-s + .rsc-s {
    border-left: 0; padding-left: 0;
    border-top: 1px solid var(--rsc-rule-mid); padding-top: 28px;
  }

  .rsc-row-catch { grid-template-columns: 1fr; }
  .rsc-row-catch > * + * {
    border-left: 0; padding-left: 0;
    margin-top: 28px; padding-top: 28px;
    border-top: 1px solid var(--rsc-rule-mid);
  }

  /* ================= ONE BOUNDARY =================
     Below 1200 every story row is a single column, so the page is one
     stream and every gap in it should be the same number.

     Four earlier attempts failed because whitespace was arriving from five
     independent places — a block's margin-bottom, a row's margin-top, a
     grid's row-gap, a card's padding-top, and each module's own rules —
     so adjusting any one of them only moved the inconsistency somewhere
     else. Measuring the boundaries rather than the properties finally
     showed the damage: five different gaps on one phone screen (26, 36,
     52, 53 and 79px), which is why one story always looked wrong no matter
     which one got fixed.

     The boundary now belongs to none of those. It is defined once: every
     structural sibling in the stream carries half the gap above itself as
     margin and half as padding, and every container's own vertical spacing
     is zeroed so nothing can stack on top of it. Where a divider is drawn
     it sits on that padding edge — which puts it exactly in the middle of
     the gap, with equal air above and below, for free.

     Two consequences worth keeping in mind. Nothing depends on what came
     before, so a hidden module can no longer collapse the gap after it
     (the reason the old sibling selectors kept missing cases). And a
     container owns the boundary above ITSELF, so its first card must not
     add one too — which is why every card rule below uses `+`.

     One warning for anyone editing this. The rules these replaced were
     `.rsc-home .rsc-row:has(> .rsc-s:first-child .rsc-img)`, which looks
     like two classes and is actually five: :has() contributes the full
     specificity of its most specific argument. That is why they silently
     outranked every general rule written afterwards. Do not reintroduce a
     :has() row selector here without counting it. */
  /* padding-bottom, NOT 0. The hero closes with a 3px section rule, and
     zeroing this put the tallest of the three headline columns flush
     against it — 0px above the rule and 36 below. Everywhere else on this
     page a divider gets half the gap on each side; the hero's own rule was
     the one that got missed, because it belongs to a container rather than
     to a row and so fell outside the boundary rules entirely.
     A full gap either side, not a half: this is a 3px black section break
     between the hero and the river, not a hairline between two stories,
     and it is roughly what the desktop padding (40px) already gives it. */
  .rsc-home .rsc-hero { margin-bottom: 0; padding-bottom: var(--rsc-gap); }
  .rsc-home .rsc-feed-main .rsc-block { margin-top: 0; margin-bottom: 0; }

  .rsc-home .rsc-feed-main .rsc-row,
  .rsc-home .rsc-feed-main .rsc-stackcol {
    margin-top: var(--rsc-gap-half);
    padding-top: var(--rsc-gap-half);
    margin-bottom: 0;
    padding-bottom: 0;
    row-gap: 0;
  }

  .rsc-home .rsc-feed-main .rsc-row > .rsc-s + .rsc-s,
  .rsc-home .rsc-feed-main .rsc-stackcol > .rsc-s + .rsc-s {
    margin-top: var(--rsc-gap-half);
    padding-top: var(--rsc-gap-half);
  }

  /* The modules are objects, not stories: a tint with its own padding, so
     there is no divider for the gap to sit either side of. Like the teaser,
     they take the whole boundary above themselves as margin and none below,
     and the row that follows supplies its own half-and-half. Left on their
     old margins they were the only thing on the page still out of rhythm —
     52px above a panel, 120 below it, 30 above Editor's Choice and 62
     below — which is what put the wrong space above "Google's" and "The
     Athletic" and under everything that ran into a module. */
  .rsc-home .rsc-feed-main .rsc-panel,
  .rsc-home .rsc-feed-main .rsc-ec,
  .rsc-home .rsc-feed-main .rsc-otd,
  .rsc-home .rsc-feed-main .rsc-allstories {
    margin-top: var(--rsc-gap);
    margin-bottom: 0;
  }

  /* ("No rule against a picture" is the last block in this file. It has to
     come after every breakpoint block to win — see the note down there.) */

  /* ===== One hero shape below 1200 =====
     All three arrangements collapse to the same thing here: the lead on its
     own row, the three stories across underneath it. Beside a 732px column
     the side variants were giving the story column about 230px — too narrow
     to set a headline in, and the reason they looked warped. Three tracks
     under a full-width lead is the one shape that still works at this
     width, so lead-left and lead-right both borrow it rather than each
     degrading in its own way. It also means one hero to reason about below
     1200 instead of three. */
  .rsc-home .rsc-hero,
  .rsc-home .rsc-hero-lead-right { grid-template-columns: 1fr; }
  .rsc-home .rsc-hero-lead-right .rsc-hero-lead { order: 0; }
  .rsc-home .rsc-hero-lead-right .rsc-hero-col { order: 0; }

  .rsc-home .rsc-hero-col {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0 var(--rsc-gut-md);
    border-left: 0;
    border-right: 0;
    padding-left: 0;
    padding-right: 0;
    border-top: 1px solid var(--rsc-rule-strong);
    margin-top: var(--rsc-gap-half);
    padding-top: var(--rsc-gap-half);
  }

  /* Separators turn from horizontal to vertical, as in the full-width
     arrangement at desktop. */
  .rsc-home .rsc-hero-col > .rsc-s + .rsc-s {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
    border-left: 1px solid var(--rsc-rule-mid);
    padding-left: var(--rsc-gut-md);
  }

  /* (.rsc-home .rsc-lead-img used to re-crop to 2/1 here. The lead prints
     whole at every width now — see .rsc-lead-img.) */

  /* Same as the desktop full-width arrangement: three abreast, no art. */
  .rsc-home .rsc-hero-col .rsc-img { display: none; }

  /* A card has no padding or border at the bottom, so its last child's
     margin-bottom collapses straight out of it and lands on the container
     instead — the headline in the final stack-column card carries 7px, and
     that 7px made the module below it sit 43px away while every other
     boundary sat at 36. Zeroing the LAST child only, so the space between a
     headline and the deck under it is untouched. */
  .rsc-home .rsc-feed-main .rsc-s > *:last-child { margin-bottom: 0; }
}

@media (max-width: 900px) {
  /* Where the rail finally leaves the side. Below 900 there is no honest way
     to run two columns, so it becomes a full-width block — but it keeps a
     running head in its own left column so the items stay at a readable
     measure instead of sprawling the width of the page. */
  .rsc-feed { display: block; }
  .rsc-rail { width: auto; flex-basis: auto; margin-top: 40px; }

  /* A running head in its own column, so the items keep a column measure
     instead of setting to the full width of the page. At 899px an
     unconstrained item ran to ~840px a line; this holds it near 600. The
     grid row is as tall as the items, so the head can stick and travel
     alongside them the way it does in the desktop rail. */
  /* 28px of top padding: as a sidebar the rail sits below the masthead and
     .rsc-rail-head's own 22px is enough, but as a block its tint starts at
     the top of the element and the head was pinned against it. */
  .rsc-rail-in {
    position: static;
    display: grid;
    grid-template-columns: 210px minmax(0, 620px);
    gap: 0 36px;
    padding: 28px 24px 28px;
  }

  /* 6px of padding, not 0. The head and the first item's source line start
     from the same box edge, but the head is 16px type and the flag is 10.7px
     — the bigger face puts its cap higher, so equal boxes read as a head
     floating above the column it belongs to. */
  .rsc-rail-head {
    position: sticky;
    /* Matches #rsc-wwr's scroll-margin-top. If the head sticks higher than
       the jump lands, it gets pinned the moment you arrive and sits out of
       line with the item beside it — which reads as the page having
       scrolled too far. */
    top: 48px;
    align-self: start;
    /* Measured, not guessed: the head is 16px type and the first item's
       source line is 10.7px, so equal box tops leave the head's cap 14px
       higher than the flag's. This lands the two caps on the same line. */
    padding-top: 14px;
  }

  .rsc-rail-items { min-width: 0; }

  /* The jump link under the top story, and the way back up from the foot of
     the rail. Both exist only while the rail is out of the reader's way. */
  .rsc-wwr-teaser { display: grid; }
  .rsc-rail-totop { display: inline-block; }

  /* Lead across the top, the story column full width beneath it. Was
     1fr 1fr for the old two-column hero, which now leaves an empty track. */
  .rsc-hero { grid-template-columns: 1fr; }

  .rsc-hero-lead {
    grid-column: 1 / -1;
    padding-bottom: 26px;
    margin-bottom: 26px;
    border-bottom: 3px solid var(--rsc-text);
  }

  .rsc-hero-lead + .rsc-hero-col { border-left: 0; padding-left: 0; }

  /* All three arrangements become the same single column here, with the
     lead on top. The mirror's `order` is undone so the source order wins
     again, and the full-width variant's row goes back to a stack. */
  .rsc-hero-lead-right { grid-template-columns: 1fr; }
  .rsc-hero-lead-right .rsc-hero-lead { order: 0; }
  .rsc-hero-lead-right .rsc-hero-col {
    order: 0;
    border-right: 0;
    padding-right: 0;
  }

  .rsc-hero-lead-full .rsc-hero-col {
    grid-template-columns: repeat(3, 1fr);
    margin-top: 26px;
    padding-top: 24px;
  }
  /* (Re-cropped to 16/9 here before; the lead is uncropped now.) */

  /* Stacked, the lead already closes with its own rule, and the row of
     three opens with another — two lines and a gap directly under the top
     story. The row's is the one to drop; the lead's belongs to the hero. */
  .rsc-hero-lead-full .rsc-hero-col {
    border-top: 0;
    padding-top: 0;
    margin-top: 0;
  }

  .rsc-panel-inner { padding-right: 0; }
  /* (.rsc-row-catch stacks at 1200px, above) */
  .rsc-familybar-links { gap: 16px; }
}

@media (max-width: 700px) {
  /* The family bar's left links wrap badly at phone width; the hamburger
     menu already carries all of them. */
  .rsc-familybar-links a:not(:first-child) { display: none; }
}

@media (max-width: 600px) {
  /* Keep the bottom padding — it's the gap between the newsletter box and
     the footer, and a bare `padding: 0 16px` would drop it. */
  .rsc-home { padding: 0 16px 52px; }

  /* Too narrow for a running head beside the items; it goes back on top. */
  .rsc-rail-in { grid-template-columns: 1fr; gap: 0; padding: 26px 16px 24px; }
  .rsc-rail-head { position: static; }

  /* (edge-to-edge now runs from 900px down — see the block near the end) */

  /* One column at phone width; the story columns stack under the lead. */
  .rsc-hero { padding: 24px 0 28px; margin-bottom: 28px; grid-template-columns: 1fr; }
  .rsc-hero-col { border-left: 0; padding-left: 0; }

  /* Three across is too little room for a headline on a phone. Every
     arrangement, not just the full-width one — below 1200 they are all the
     same shape now, so they all have three columns to stack. */
  .rsc-home .rsc-hero-col { grid-template-columns: 1fr; }

  /* Full width again, so the picture comes back — and at the 13px the rest
     of the stacked stream uses between a picture and its headline, not the
     11px it needed when it was one of three narrow columns. */
  .rsc-home .rsc-hero-col .rsc-img { display: block; margin-bottom: 13px; }
  .rsc-home .rsc-hero-col > .rsc-s + .rsc-s {
    border-left: 0;
    padding-left: 0;
    margin-top: var(--rsc-gap-half);
    padding-top: var(--rsc-gap-half);
    border-top: 1px solid var(--rsc-rule-mid);
  }

  .rsc-ec-inner { padding: 20px 16px 24px; }
  .rsc-hero-col + .rsc-hero-col {
    margin-top: 22px;
    padding-top: 22px;
    border-top: 1px solid var(--rsc-rule-mid);
  }

  /* (row stacking now happens at 780px, above) */

  .rsc-s-horiz { grid-template-columns: 1fr; gap: 13px; }
  .rsc-s-horiz h3.rsc-hed { font-size: 1.35rem; }

  /* .rsc-home drops to 16px of side padding here, so the band's offset has
     to follow or it lands 12px off the viewport edge. */
  .rsc-panel { --rsc-bleed: 16px; padding: 36px 0 40px; }
  .rsc-panel-body { grid-template-columns: 1fr; }
  .rsc-panel-body > * + * { border-left: 0; padding-left: 0; margin-top: 24px; }
  .rsc-panel-head { flex-direction: column; align-items: flex-start; gap: 8px; }

  h2.rsc-lead-hed { font-size: clamp(1.8rem, 7vw, 2.3rem); }
  .rsc-lead-deck { font-size: 1.05rem; }

  .rsc-hubnav-inner { gap: 5px 16px; font-size: .62rem; padding: 10px 16px; }
  .rsc-familybar-inner { padding: 8px 16px; }

  /* (the masthead's width ramp bottoms out at 600px on its own — these
     overrides are no longer needed) */

  /* Rules follow the narrower side padding here. */
  .rsc-hubnav-inner::after,
  body.rsc-big-header .roscoe-site-header:not(.rsc-scrolled) .roscoe-site-header-inner::after {
    left: 16px;
    right: 16px;
  }
}



/* ================================================================
   ROSCOE — ARCHIVE / LOOP
   ================================================================
   Every "list of stories" route — author, tag, category, date, hubs,
   collection, countries, languages — renders through
   roscoe-archive.php + loop-roscoe.php and is styled here. Change a
   rule in this block and all eight routes move together.

   Structurally this mirrors Simple's archive pages: a main column of
   stories with a right rail. What differs is the well width and the
   type, both of which come from Roscoe's tokens rather than the
   hardcoded pixel values and Typekit stacks Simple used.
   ================================================================ */

:root {
  /* The archive well. Matches --rsc-body-max so that every page built on
     the sidebar grid — pages, archives, search, the WWR pages — comes out
     the same 1106px overall. It was 760px, which made archives 60px wider
     than pages for no reason anyone could see except by measuring them.
     This is the one number to change if the columns feel wrong. */
  --rsc-archive-main: 700px;
}

.rsc-archive {
  padding-bottom: 80px;
}

/* Reuse the article page's sidebar grid. Pages ride along here: an About
   page and an author archive are the same object — a well of copy with a
   rail beside it — and they were drifting apart because each template
   styled its own top edge. Scoped away from .rsc-single so the article
   layout, whose rail clears a hero instead, is untouched. */
.rsc-archive .rsc-has-sidebar,
.rsc-page-sidebar .rsc-has-sidebar {
  max-width: calc(var(--rsc-archive-main) + 300px + 50px + 56px);
  padding-top: 40px;
}


/* ---------- page heading ---------- */

.roscoe-loop-page-headlinewrapper {
  margin: 0 0 40px 0;
  padding-bottom: 20px;
  border-bottom: 2px solid var(--rsc-text);
}

/* Set in the sans, not Literata: these label a list rather than being read
   as prose, and the switch tells you at a glance that you are on an index
   rather than a story. Covers author, category, tag, collection, date and
   search — every one of them renders through this class. Tracking goes a
   little tighter than the serif wanted; Schibsted Grotesk sets loose at
   display sizes. */
.roscoe-loop-page-headline {
  font-family: var(--rsc-sans);
  font-size: clamp(2rem, 4vw, 2.75rem);
  line-height: 1.1;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--rsc-text);
  margin: 0;
  text-wrap: balance;
}

.roscoe-loop-page-headline strong { font-weight: 700; }

.roscoe-category-info {
  font-family: var(--rsc-sans);
  font-size: 1.05rem;
  line-height: 1.5;
  color: var(--rsc-muted);
  margin-top: 14px;
  max-width: 60ch;
}

/* Press Publish topper (category 8984) */
.roscoe-category-topper {
  border: 1px solid var(--rsc-border);
  padding: 24px;
  margin-bottom: 40px;
  text-align: center;
}
.roscoe-category-topper img { max-width: 100%; height: auto; margin: 0 auto 16px; display: block; }
.roscoe-category-topper p {
  font-family: var(--rsc-sans);
  font-size: 1.15rem;
  line-height: 1.45;
  color: var(--rsc-text);
  margin: 0;
}


/* ---------- author bio ---------- */

/* Scoped to the archive: the single-post bio box above also matches
   .roscoe-author-bio and contributes a top border and top padding that this
   rule never reset, so the author page was drawing a rule on both sides of
   the bio — and, on an author with no bio at all, two rules with nothing
   between them. The heading's own rule already separates this from the
   page title, so only the bottom edge is drawn here. */
.rsc-archive .roscoe-author-bio {
  font-family: var(--rsc-sans);
  font-size: 1.05rem;
  line-height: 1.55;
  color: var(--rsc-muted);
  margin: 0 0 40px 0;
  border-top: 0;
  padding-top: 0;
  padding-bottom: 30px;
  border-bottom: 1px solid var(--rsc-border);
}

.roscoe-author-mug {
  float: right;
  margin: 4px 0 12px 24px;
  border-radius: 50%;
}

.roscoe-author-social { margin-top: 16px; }
.roscoe-author-social a {
  color: var(--rsc-muted);
  text-decoration: none;
  font-size: 0.95rem;
}
.roscoe-author-social a:hover { color: var(--rsc-text); }


/* ---------- the story list ---------- */

.roscoe-loop-article,
.roscoe-loop-wirepost,
.roscoe-loop-wirelink {
  padding-bottom: 32px;
  margin-bottom: 32px;
  border-bottom: 1px solid var(--rsc-border);
}

.roscoe-loop-article:last-child,
.roscoe-loop-wirepost:last-child,
.roscoe-loop-wirelink:last-child { border-bottom: 0; }

.roscoe-loop-headline {
  font-family: var(--rsc-headline);
  font-size: 1.75rem;
  line-height: 1.2;
  font-weight: 700;
  margin: 6px 0 10px 0;
  text-wrap: balance;
}
.roscoe-loop-headline a { color: var(--rsc-text); text-decoration: none; }
.roscoe-loop-headline a:hover { text-decoration: underline; }

.roscoe-loop-deck {
  font-family: var(--rsc-sans);
  font-size: 1.05rem;
  line-height: 1.45;
  color: var(--rsc-muted);
}

.roscoe-loop-author,
.roscoe-loop-date {
  font-family: var(--rsc-sans);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--rsc-muted);
}
.roscoe-loop-author a { color: inherit; text-decoration: none; }
.roscoe-loop-author a:hover { text-decoration: underline; }
.coauthor-and { font-weight: 400; text-transform: none; font-style: italic; letter-spacing: 0; }

/* Small thumbnail variant: art floats right of the text. */
.roscoe-loop-thumbnail {
  float: right;
  margin: 4px 0 8px 24px;
  max-width: 200px;
  height: auto;
}

/* Big-art variant: full-width image, then a meta rail beside the text.
   loop-roscoe-meat.php sets the column widths inline; these are the
   things it doesn't. */
.roscoe-loop-bigart {
  display: block;
  width: 100%;
  height: auto;
}
.roscoe-loop-bigart:hover {
  opacity: 0.8;
  transition: opacity 0.2s;
}
.roscoe-loop-article-bigarttextwrapper { margin-top: 4px; }

/* Link posts (category 6672): headline only, no art, no deck. */
/* display:block is what makes the line-height below actually bite.
   The headline is a <span>, and an inline element cannot pull its lines
   closer than the strut of the block it sits in — that block inherits
   body's line-height: 1.6, i.e. 32px at this size. Any value under 1.6 was
   being floored and silently ignored. As a block it sets its own strut. */
.roscoe-loop-wirelink-headline {
  display: block;
  font-family: var(--rsc-sans);
  font-size: 1.25rem;
  line-height: 1.3;
  font-weight: 600;
}
.roscoe-loop-wirelink-headline-link { color: var(--rsc-text); text-decoration: none; }
.roscoe-loop-wirelink-headline-link:hover { text-decoration: underline; }
.roscoe-loop-wirelink-headline-box { margin: 6px 0; }

/* Link posts share the regular post's two-column shape: meta at the left,
   headline to the right of a hairline. A regular post gets these same
   measurements from inline styles in loop-roscoe-meat.php; they are written
   as rules here so the two columns line up exactly without touching the
   markup that already works. Percentages assume the global border-box at
   the top of this file — 20 + 80 with the padding inside. */
.roscoe-loop-wirelink-meta {
  float: left;
  width: 20%;
  padding-right: 25px;
  padding-top: 10px;
  margin-top: 10px;
}

.roscoe-loop-wirelink-meta .roscoe-loop-author,
.roscoe-loop-wirelink-meta .roscoe-loop-date {
  display: block;
  line-height: 16px;
}

.roscoe-loop-wirelink-text {
  float: right;
  width: 80%;
  padding-left: 25px;
  border-left: 1px solid #ddd;
  /* Pairs with the headline's line-height: the two together decide where
     the first line's cap lands against the meta column's. */
  margin-top: 11px;
  padding-bottom: 10px;
}

/* Art sits above both columns, full width, exactly as on a regular post. */
.roscoe-loop-wirelink .roscoe-loop-bigart { margin-bottom: 4px; }

@media (max-width: 700px) {
  /* Same stacking the rest of the loop uses: the rule between the columns
     stops making sense once they are on top of each other. */
  .roscoe-loop-wirelink-meta,
  .roscoe-loop-wirelink-text {
    float: none;
    width: 100%;
    padding-left: 0;
    padding-right: 0;
    border-left: 0;
  }
  .roscoe-loop-wirelink-meta .roscoe-loop-author,
  .roscoe-loop-wirelink-meta .roscoe-loop-date { display: inline; }
}

/* Wire posts (category 6588): currently commented out in the loop, kept
   styled so re-enabling them doesn't require a CSS pass. */
.roscoe-loop-wirepost-headline {
  font-family: var(--rsc-headline);
  font-size: 1.4rem;
  line-height: 1.25;
  margin: 5px 0;
}
.roscoe-loop-wirepost-headline a { color: var(--rsc-text); text-decoration: none; }
.roscoe-loop-wirepost-deck,
.roscoe-loop-wirepost-body {
  font-family: var(--rsc-sans);
  font-size: 1rem;
  line-height: 1.45;
  color: var(--rsc-muted);
  margin: 8px 0 0 0;
}


/* ---------- sidebar rail ---------- */

.rsc-sidebar-kicker {
  font-family: var(--rsc-sans);
  /* 0.8rem, not the 1rem the other small heads were brought up to. This one
     has 0.1em of letter-spacing on a six-word line in a narrow rail, and at
     1rem "The latest from Nieman Lab" wraps to two lines. */
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--rsc-text);
  margin: 0 0 4px 0;
}

.rsc-sidebar-text { min-width: 0; }

.rsc-sidebar-byline {
  font-family: var(--rsc-sans);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--rsc-muted);
}

/* These rails start level with the heading, not 60px down like the article
   rail (which clears the hed-wrap). */
.rsc-archive .roscoe-sidebar,
.rsc-page-sidebar .roscoe-sidebar { margin-top: 0; }


/* ---------- pagination ---------- */

.roscoe-loop-prevnext {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  margin: 40px 0 0 0;
  padding-top: 24px;
  border-top: 1px solid var(--rsc-border);
  font-family: var(--rsc-sans);
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
}
.roscoe-loop-prevnext .nav-next { text-align: right; margin-left: auto; }
.roscoe-loop-prevnext a { color: var(--rsc-muted); text-decoration: none; }
.roscoe-loop-prevnext a:hover { color: var(--rsc-text); }


/* ---------- responsive ---------- */

@media (max-width: 1000px) {
  /* Rail drops below the stories rather than squeezing them. Pages behave
     the same way; below 900px the shared rule hides the rail outright. */
  .rsc-archive .rsc-has-sidebar,
  .rsc-page-sidebar .rsc-has-sidebar { grid-template-columns: 1fr; }
  .rsc-archive .roscoe-sidebar,
  .rsc-page-sidebar .roscoe-sidebar {
    margin-top: 40px;
    padding-left: 0;
    padding-top: 30px;
    border-left: 0;
    border-top: 2px solid var(--rsc-text);
  }
}

@media (max-width: 600px) {
  .roscoe-loop-headline { font-size: 1.4rem; }
  .roscoe-loop-thumbnail { max-width: 110px; margin-left: 16px; }
  .roscoe-loop-deck { padding-right: 0 !important; font-size: 1rem; }
  /* Big-art variant stacks its meta rail above the text. */
  .roscoe-loop-article-meta,
  .roscoe-loop-article-text {
    float: none !important;
    width: 100% !important;
    padding: 0 !important;
    border-left: 0 !important;
  }
  .roscoe-loop-article-text { margin-top: 8px !important; }
}


/* ================================================================
   PAGES, SEARCH, ARCHIVES, 404
   Shared furniture for the non-article routes: page-roscoe.php,
   page-archives-roscoe.php, search-roscoe.php and 404-roscoe.php.
   ================================================================ */

.rsc-page {
  max-width: var(--rsc-well);
  margin: 0 auto;
  padding: 0 28px 80px;
}

.rsc-page-head {
  border-bottom: 2px solid var(--rsc-text);
  /* 40px matches the top padding on the sidebar grid, so a page title and
     an archive heading begin at the same height. */
  padding: 40px 0 18px;
  margin-bottom: 40px;
}

h1.rsc-page-title {
  font-family: var(--rsc-headline);
  font-weight: 400;
  font-size: clamp(2rem, 4vw, 3rem);
  line-height: 1.1;
  letter-spacing: -0.04em;
  margin: 0;
}

/* Pages run at the article measure so prose, links and shortcodes all
   inherit the body treatment rather than needing their own rules. */
.rsc-page .roscoe-body-section { padding-top: 0; }

.rsc-page-links {
  font-family: var(--rsc-sans);
  font-size: .9rem;
  margin-top: 32px;
}

/* ---------------- Search field ----------------
   Shared by the search page, the archives page and the 404.

   Styled after the search overlay in header-roscoe.php — a large field on
   a rule rather than a boxed input with a filled button. The crimson
   submit is gone; the accent is reserved for links and flags, and a black
   rule is what the rest of Roscoe uses to carry structure. */

/* A tinted, bounded field rather than a rule across the column — on a page
   already built out of horizontal rules, an underlined input just read as
   one more divider. Kept narrow so it looks like a control, not a banner. */
.rsc-searchpage-form,
.rsc-wwr-search,
.rsc-404-form {
  display: flex;
  align-items: stretch;
  gap: 0;
  background: #F2F0EB;
  border: 1px solid #d9d5cd;
  margin-bottom: 34px;
}

/* On a 404 the field IS the page's one offer, and a full-bleed input above
   almost no content reads as a banner — so it stays a control. */
.rsc-404-form { max-width: 460px; }

/* On the results page it is the opposite: the field sits above a list of
   results it filters, and a 460px box floating over an 800px column looked
   like it belonged to something else. Full width ties it to the results. */
.rsc-searchpage-form,
.rsc-wwr-search { max-width: none; }

/* Type and padding scale with it. 16px text in a 460px control reads fine;
   the same 16px stranded in an 800px box reads as a mistake. 18px is still
   below the 20px body copy, which is right for a UI control. */
.rsc-searchpage-form input[type="search"],
.rsc-wwr-search input[type="search"] { font-size: 1.125rem; padding: 15px 18px; }
.rsc-searchpage-form button,
.rsc-wwr-search button { padding: 0 26px; }

.rsc-searchpage-form:focus-within,
.rsc-wwr-search:focus-within,
.rsc-404-form:focus-within { border-color: var(--rsc-text); background: #fff; }

.rsc-searchpage-form input[type="search"],
.rsc-wwr-search input[type="search"],
.rsc-404-form input[type="search"] {
  flex: 1;
  min-width: 0;
  font-family: var(--rsc-sans);
  font-size: 1rem;
  line-height: 1.3;
  padding: 12px 14px;
  border: 0;
  background: none;
  color: var(--rsc-text);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}

.rsc-searchpage-form input::placeholder,
.rsc-wwr-search input::placeholder,
.rsc-404-form input::placeholder { color: #b3b0aa; }

.rsc-searchpage-form input:focus,
.rsc-wwr-search input:focus,
.rsc-404-form input:focus { outline: none; }

/* Keyboard users still need a visible focus state; put it on the rule. */
.rsc-searchpage-form button,
.rsc-wwr-search button,
.rsc-404-form button {
  flex: 0 0 auto;
  font-family: var(--rsc-sans);
  font-size: .72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .1em;
  padding: 0 18px;
  border: 0;
  border-left: 1px solid #d9d5cd;
  background: none;
  color: var(--rsc-text);
  cursor: pointer;
}

.rsc-searchpage-form button:hover,
.rsc-wwr-search button:hover,
.rsc-404-form button:hover { background: var(--rsc-text); color: #fff; }

.rsc-searchpage-count {
  font-family: var(--rsc-sans);
  font-size: .8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--rsc-muted);
  padding-bottom: 14px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--rsc-border);
}

/* ----------------------------------------------------------------
   STREAM SWITCHER — Articles / What We're Reading
   ----------------------------------------------------------------
   One component for four pages: both search results pages and both tag
   archives. It states how many are in the stream you are looking at and
   offers the other, so none of them needs a separate count line.

   Tabs, not a sentence: the relationship is "two halves of the same
   subject", and a row of two reads that way immediately where a line of
   prose does not. */
.rsc-streamtabs {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin: 0 0 24px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--rsc-border);
}

/* Deliberately quiet. This is orientation, not the headline — the <h1>
   above already says what you are looking at, so the switcher only has to
   confirm it and offer the other half. The first version was a pair of
   big filled lozenges that competed with the heading for the eye. */
.rsc-streamtab {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-family: var(--rsc-sans);
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  text-decoration: none;
  padding: 5px 13px;
  border-radius: 999px;
  border: 1px solid var(--rsc-border);
  color: var(--rsc-muted);
  transition: border-color .15s, color .15s, background .15s;
}

/* The count leads and is not uppercase — it is a number, and small caps
   makes digits harder to read at a glance. */
.rsc-streamtab-n {
  font-size: .85rem;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
}

/* The tab you are on is a tint, not a solid black fill. With both tabs
   now carrying an arrow, the arrow direction already says which is which;
   the fill only has to separate them, so it can be faint. */
.rsc-streamtab.is-current {
  background: #F2F0EB;
  border-color: #e3dfd7;
  color: var(--rsc-text);
}

a.rsc-streamtab:hover {
  color: #A51C30;
  border-color: #A51C30;
}

/* The arrows are the one part that should NOT shrink with the label —
   at .7rem a glyph becomes a speck. */
.rsc-streamtab-go { font-size: 1.15em; line-height: 1; }

/* On the empty-results page it is the only thing on offer, so it loses
   the rule under it. */
.rsc-searchpage-empty .rsc-streamtabs {
  border-bottom: 0;
  padding-bottom: 0;
  margin-top: 14px;
}

/* ----------------------------------------------------------------
   WWR SEARCH BOX  (/reading/ and a single WWR)
   ---------------------------------------------------------------- */
/* The WWR box is now the same control as the one on a search results page
   — same tint, same border, same uppercase submit — rather than a second,
   narrower, black-buttoned design doing the same job three clicks away.
   Everything it needs comes from the shared .rsc-searchpage-form rules
   above; only its spacing is its own.

   It was previously capped at 460px, which left it stranded mid-column
   under a full-width rule and read as something that had failed to load. */
.rsc-wwr-search { margin: 26px 0 34px; }

/* A single WWR is a short page, so the form below it needs air above. */
.rsc-wwr-single + .rsc-wwr-search { margin-top: 36px; }

.rsc-searchpage-empty {
  font-family: var(--rsc-sans);
  font-size: 1.05rem;
  line-height: 1.6;
  color: #555;
  padding: 8px 0 60px;
}

.rsc-searchpage-empty a { color: #A51C30; }

/* ---------------- Archives page ---------------- */

.rsc-archives-section { margin-bottom: 52px; }

h2.rsc-archives-heading {
  font-family: var(--rsc-sans);
  font-size: .82rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .1em;
  padding-bottom: 12px;
  margin: 0 0 22px;
  border-bottom: 1px solid var(--rsc-rule-strong, #000);
}

.rsc-archives-tags {
  font-family: var(--rsc-sans);
  font-size: .95rem;
  line-height: 2.1;
}

.rsc-archives-tags a {
  color: var(--rsc-text);
  text-decoration: none;
  border-bottom: 1px solid var(--rsc-border);
  padding-bottom: 1px;
  margin-right: 14px;
  white-space: nowrap;
}

.rsc-archives-tags a:hover { color: #A51C30; border-bottom-color: #A51C30; }

/* One row per year: the year on the left, twelve month boxes beside it. */
.rsc-archives-year {
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: 0 20px;
  align-items: center;
  padding: 12px 0;
  border-bottom: 1px solid var(--rsc-border);
}

.rsc-archives-year:last-child { border-bottom: 0; }

.rsc-archives-yearlabel {
  font-family: var(--rsc-headline);
  font-size: 1.4rem;
  letter-spacing: -0.03em;
}

.rsc-archives-yearlabel a { color: var(--rsc-text); text-decoration: none; }
.rsc-archives-yearlabel a:hover { color: #A51C30; }

.rsc-archives-months {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 6px;
}

.rsc-archives-month {
  display: block;
  text-align: center;
  font-family: var(--rsc-sans);
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  padding: 7px 2px;
  border: 1px solid var(--rsc-border);
  color: var(--rsc-text);
  text-decoration: none;
}

a.rsc-archives-month:hover { background: var(--rsc-text); border-color: var(--rsc-text); color: #fff; }

/* Months with nothing published stay in place so the grid keeps its
   shape, but read as unavailable. */
.rsc-archives-month.is-empty { color: #c9c6c0; border-color: #efedea; }

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

.rsc-404 {
  max-width: 760px;
  margin: 0 auto;
  padding: 60px 28px 100px;
  text-align: center;
}

h1.rsc-404-headline {
  font-family: var(--rsc-headline);
  font-weight: 400;
  font-size: clamp(2rem, 5vw, 3.2rem);
  line-height: 1.1;
  letter-spacing: -0.04em;
  margin: 0 0 36px;
  text-wrap: balance;
}

.rsc-404-figure { margin: 0 0 36px; }
.rsc-404-figure img { width: 100%; height: auto; display: block; }

.rsc-404-figure figcaption {
  font-family: var(--rsc-sans);
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--rsc-muted);
  text-align: right;
  margin-top: 8px;
}

.rsc-404-figure figcaption a { color: inherit; }

.rsc-404-text {
  font-family: var(--rsc-sans);
  font-size: 1.15rem;
  line-height: 1.5;
  color: #555;
  margin: 0 0 28px;
  text-wrap: pretty;
}

.rsc-404 .rsc-404-form { max-width: 480px; margin: 0 auto 32px; text-align: left; }

.rsc-404-links {
  font-family: var(--rsc-sans);
  font-size: .85rem;
  color: var(--rsc-muted);
}

.rsc-404-links a { color: var(--rsc-text); text-decoration: none; }
.rsc-404-links a:hover { color: #A51C30; }
.rsc-404-links span { margin: 0 8px; color: var(--rsc-border); }

@media (max-width: 700px) {
  .rsc-page { padding: 0 16px 60px; }
  .rsc-page-head { padding-top: 32px; margin-bottom: 28px; }

  /* The 12-across month grid is unreadable on a phone; go to six. */
  .rsc-archives-year { grid-template-columns: 1fr; gap: 10px; align-items: start; }
  .rsc-archives-months { grid-template-columns: repeat(6, 1fr); }

  .rsc-404 { padding: 36px 16px 70px; }
}


/* ================================================================
   WHAT WE'RE READING — standalone pages
   /reading/ (archive-argolinks-roscoe.php) and a single item
   (single-argolinks-roscoe.php). Items themselves are rendered by
   rsc_wwr_render() and reuse the .rsc-wwr-* rules from the homepage
   rail; what follows is only the page furniture around them.
   ================================================================ */

.rsc-wwr-masthead {
  border-bottom: 2px solid var(--rsc-text);
  padding-bottom: 20px;
  margin-bottom: 8px;
}

/* /reading/ and a single WWR item are index pages too, so they follow the
   loop headers into the sans. */
h1.rsc-wwr-masthead-title,
a.rsc-wwr-masthead-title {
  display: block;
  font-family: var(--rsc-sans);
  font-weight: 400;
  font-size: clamp(1.9rem, 3.6vw, 2.7rem);
  line-height: 1.1;
  letter-spacing: -0.04em;
  color: var(--rsc-text);
  text-decoration: none;
  margin: 0 0 12px;
}

a.rsc-wwr-masthead-title:hover { color: #A51C30; }

.rsc-wwr-masthead-blurb {
  font-family: var(--rsc-sans);
  font-size: 1rem;
  line-height: 1.5;
  color: #666;
  margin: 0;
  max-width: 46em;
}

/* --- Day groups on the archive --- */

h2.rsc-wwr-dayhead {
  font-family: var(--rsc-sans);
  font-size: .74rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .1em;
  margin: 44px 0 0;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--rsc-rule-strong, #000);
}

h2.rsc-wwr-dayhead a { color: var(--rsc-text); text-decoration: none; }
h2.rsc-wwr-dayhead a:hover { color: #A51C30; }

.rsc-wwr-daygroup > .rsc-wwr:last-child { border-bottom: 0; }

/* --- A single WWR standing on its own ---
   The rail sizes are tuned for a 330px column; at full width the same
   item needs to carry the page, so the type steps up. */

.rsc-wwr-single { padding: 26px 0 8px; }

.rsc-wwr-full { padding: 0; border-bottom: 0; }
.rsc-wwr-full .rsc-wwr-flag { font-size: .76rem; margin-bottom: 10px; }

.rsc-wwr-full h3.rsc-wwr-hed {
  font-family: var(--rsc-headline);
  font-weight: 400;
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  line-height: 1.14;
  letter-spacing: -0.03em;
  margin-bottom: 14px;
}

.rsc-wwr-full .rsc-wwr-body {
  font-size: 1.08rem;
  line-height: 1.6;
  color: #333;
  max-width: 42em;
}

.rsc-wwr-full .rsc-wwr-quote { font-size: clamp(1.5rem, 2.8vw, 2rem); }
.rsc-wwr-full .rsc-wwr-attrib { font-size: .95rem; }
.rsc-wwr-full .rsc-wwr-figure { font-size: clamp(3rem, 6vw, 4.4rem); }
.rsc-wwr-full .rsc-wwr-img { margin-bottom: 18px; }

.rsc-wwr-fullmeta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 14px;
  font-family: var(--rsc-sans);
  font-size: .74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--rsc-muted);
  margin-top: 20px;
  padding-top: 14px;
  border-top: 1px solid var(--rsc-border);
}

.rsc-wwr-fullmeta a { color: inherit; text-decoration: none; }
.rsc-wwr-fullmeta a:hover { color: var(--rsc-text); }
.rsc-wwr-initials { font-style: italic; text-transform: none; letter-spacing: 0; }

/* Sits inline with the date in .rsc-wwr-fullmeta. */
.rsc-wwr-tags {
  font-family: var(--rsc-sans);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  font-size: .82rem;
  color: var(--rsc-muted);
}

.rsc-wwr-tags a { color: var(--rsc-muted); }
.rsc-wwr-tags a:hover { color: #A51C30; }

/* --- The rest of that day, under a single item --- */

.rsc-wwr-sameday { margin-top: 44px; }

h2.rsc-wwr-sameday-head {
  font-family: var(--rsc-sans);
  font-size: .74rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .1em;
  margin: 0;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--rsc-rule-strong, #000);
}

.rsc-wwr-sameday > .rsc-wwr:last-of-type { border-bottom: 0; }

.rsc-wwr-more {
  margin-top: 36px;
  padding-top: 20px;
  border-top: 1px solid var(--rsc-border);
  font-family: var(--rsc-sans);
  font-size: .85rem;
  font-weight: 700;
}

.rsc-wwr-more a { color: #A51C30; text-decoration: none; }
.rsc-wwr-more a:hover { color: var(--rsc-text); }


/* ================================================================
   PAGE LAYOUTS + WWR PAGE REFINEMENTS
   ================================================================ */

/* --- Pages: title sits at the measure of the copy under it --- */

.rsc-page-narrow .rsc-page-well { max-width: var(--rsc-body-max); margin: 0 auto; }
.rsc-page-narrow .rsc-page-head { border-bottom-width: 2px; }

/* With a rail, the page is already a column; the .rsc-page wrapper would
   add its own well on top of .rsc-has-sidebar's. */
.rsc-page-sidebar { max-width: none; padding-left: 0; padding-right: 0; }
/* With a rail, the grid supplies the top padding (see the shared rule in
   the archive section) and both columns start on the same line, so the
   head must not add a second helping. Pages without a rail keep the 40px
   above, which puts their title at the same height. */
.rsc-page-sidebar .rsc-page-head { padding-top: 0; }
.rsc-page .roscoe-body { padding-bottom: 40px; }

/* The archives search field is a filter for the page, not its headline. */
.rsc-archivespage .rsc-searchpage-form { max-width: 380px; }

/* --- WWR pages: rail-sized type is too small at full width --- */

.rsc-wwrpage .rsc-wwr { position: relative; padding: 26px 0; }

.rsc-wwrpage .rsc-wwr-flag { font-size: .74rem; margin-bottom: 8px; }

.rsc-wwrpage h3.rsc-wwr-hed {
  font-family: var(--rsc-headline);
  font-weight: 400;
  font-size: clamp(1.35rem, 2.2vw, 1.75rem);
  line-height: 1.18;
  letter-spacing: -0.03em;
  margin-bottom: 12px;
}

.rsc-wwrpage .rsc-wwr-body {
  font-size: 1.05rem;
  line-height: 1.6;
  color: #333;
  max-width: 44em;
}

.rsc-wwrpage .rsc-wwr-quote { font-size: clamp(1.4rem, 2.4vw, 1.9rem); max-width: 24em; }
.rsc-wwrpage .rsc-wwr-attrib { font-size: .92rem; max-width: 44em; }
.rsc-wwrpage .rsc-wwr-img { max-width: 620px; }
.rsc-wwrpage .rsc-wwr-shot { max-width: 520px; }

/* The item the page is actually about leads at a larger size than the
   same-day list beneath it. These have to out-rank the .rsc-wwrpage rules
   above, which come later in the file at equal specificity. */
.rsc-wwrpage .rsc-wwr-full h3.rsc-wwr-hed {
  font-size: clamp(1.8rem, 3.4vw, 2.5rem);
  line-height: 1.12;
  margin-bottom: 16px;
}

.rsc-wwrpage .rsc-wwr-full .rsc-wwr-body { font-size: 1.18rem; line-height: 1.55; }
.rsc-wwrpage .rsc-wwr-full .rsc-wwr-flag { font-size: .8rem; }
.rsc-wwrpage .rsc-wwr-full .rsc-wwr-quote { font-size: clamp(1.7rem, 3.2vw, 2.3rem); }
.rsc-wwrpage .rsc-wwr-full .rsc-wwr-figure { font-size: clamp(3rem, 5.5vw, 4rem); }
.rsc-wwrpage .rsc-wwr-full .rsc-wwr-figure.is-long  { font-size: clamp(2.2rem, 4vw, 3rem); }
.rsc-wwrpage .rsc-wwr-full .rsc-wwr-figure.is-xlong { font-size: clamp(1.8rem, 3vw, 2.4rem); }

/* --- Number items ---
   The numeral was set as a display headline with the explanation dropped
   underneath at rail size and full column measure: a 43px figure sitting
   on a line of 14px text running 900px wide. Pair them instead — the
   figure beside its sentence, both at a readable size. */

/* Stacked. A two-column pairing reads well for "29" and breaks for
   "Nearly 100 million", and both are valid values — so the figure sits
   above its explanation and is sized by its own length (set in
   rsc_wwr_render()) rather than assuming a short numeral. */
.rsc-wwr-number-wrap { display: block; }

.rsc-wwr-figure {
  font-family: var(--rsc-headline);
  font-weight: 500;
  font-size: clamp(2.4rem, 4.4vw, 3.2rem);
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--rsc-text);
  margin: 0 0 10px;
  text-wrap: balance;
}

/* Longer values step down so they stay on one or two lines. */
.rsc-wwr-figure.is-long  { font-size: clamp(1.9rem, 3.2vw, 2.5rem); }
.rsc-wwr-figure.is-xlong { font-size: clamp(1.6rem, 2.6vw, 2rem); letter-spacing: -0.03em; }

/* The second selector is for the older markup, where the numeral's link sat
   directly inside .rsc-wwr-number rather than in its own .rsc-wwr-figure.
   Without it that link falls all the way back to the browser default and
   renders blue and underlined. Excluding .rsc-wwr-permalink matters: in the
   current markup that anchor IS a direct child of .rsc-wwr-number, and it
   carries its own colour for the hover icon. */
.rsc-wwr-figure a,
.rsc-wwr-number > a:not(.rsc-wwr-permalink) { color: inherit; text-decoration: none; }
.rsc-wwr-figure a:hover,
.rsc-wwr-number > a:not(.rsc-wwr-permalink):hover { color: var(--rsc-text); }

.rsc-wwrpage .rsc-wwr-number-wrap .rsc-wwr-body,
.rsc-wwr-full .rsc-wwr-number-wrap .rsc-wwr-body { max-width: 44em; margin: 0; }

/* In the homepage rail there is no room for two columns. */
.rsc-rail .rsc-wwr-figure { font-size: 2.2rem; }
.rsc-rail .rsc-wwr-figure.is-long  { font-size: 1.7rem; }
.rsc-rail .rsc-wwr-figure.is-xlong { font-size: 1.4rem; }

/* --- Hover permalink --- */

.rsc-wwr { position: relative; }

.rsc-wwr-permalink {
  position: absolute;
  top: 18px;
  right: 0;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--rsc-muted);
  opacity: 0;
  transition: opacity .15s, color .15s;
}

.rsc-wwr-permalink svg { width: 15px; height: 15px; }

.rsc-wwr:hover .rsc-wwr-permalink,
.rsc-wwr-permalink:focus-visible { opacity: 1; }
.rsc-wwr-permalink:hover { color: #A51C30; }

/* Touch devices have no hover, so keep it visible but quiet. */
@media (hover: none) {
  .rsc-wwr-permalink { opacity: .45; }
}

/* Keep the icon clear of the text it sits beside. */
.rsc-wwrpage .rsc-wwr-flag,
.rsc-wwrpage h3.rsc-wwr-hed { padding-right: 34px; }

.rsc-wwr-numsrc { color: var(--rsc-muted); white-space: nowrap; }

/* Links inside a WWR's text were falling through to the browser default
   blue. Match the article body treatment so a link reads the same
   wherever it appears. */
.rsc-wwr-body a,
.rsc-wwr-attrib a {
  color: #1a1a1a;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  text-decoration-color: rgba(165, 28, 48, .4);
  transition: text-decoration-color .15s, color .15s;
}

.rsc-wwr-body a:hover,
.rsc-wwr-attrib a:hover { color: #7d1525; text-decoration-color: rgba(165, 28, 48, .9); }

/* ---- Flagger's initials ----------------------------------------
   Who found the item, trailing the last word. #ddd is about 1.3:1
   against white — far below any contrast floor, and deliberately so:
   this is a note between colleagues, not content. Simple used exactly
   this colour, and bringing it back at anything more legible would
   turn a private signature into a byline.
   nowrap keeps "—SC" from breaking across lines on its own. */
.rsc-wwr-by {
  color: #ddd;
  font-style: normal;
  white-space: nowrap;
}
.rsc-wwr-by em { font-style: italic; }


/* ================================================================
   MOBILE PASS — masthead, dividers, footer
   ================================================================ */

@media (max-width: 900px) {
  /* Below desktop the masthead is hamburger, logo, subscribe and search,
     and nothing else. The hub nav wrapped to a second line and the Nieman
     family bar duplicated links the hamburger menu already carries —
     neither earns the space. (Subscribe drops out too, but later, at
     600px — see .rsc-header-subscribe.)
     A rule under the header stands in for the one the hub nav was
     drawing, so the top of the page still closes. */
  .rsc-familybar,
  .rsc-hubnav { display: none; }

  body.rsc-big-header .roscoe-site-header { border-bottom: 1px solid var(--rsc-rule-strong, #000); }

  /* With the family bar gone there is no sentinel above the header, so the
     collapse trigger falls back to the first pixel of scroll — see
     header-roscoe.php. Nothing to do here beyond not relying on it. */
}

/* --- Divider weights ---
   Normalised at 900, not 600: that is where the hero stacks, and from that
   point down the heavier rule under it no longer marks a change of block —
   it just reads as an arbitrary thick line inside one column. */
@media (max-width: 900px) {
  /* Two separate rules sit under the top story once stacked: the hero
     wrapper's, and .rsc-hero-lead's own 3px rule which only exists in the
     stacked layout. Both have to come down, or the heavier one survives —
     which is what was still reading as a thick line. */
  .rsc-hero { border-bottom-width: 1px; }
  .rsc-hero-lead { border-bottom-width: 1px; }
  .rsc-s-text { border-top-width: 1px; }
  .rsc-row-heds { border-top-width: 1px; }
}

@media (max-width: 600px) {
  /* Once the columns stack, the vertical hairlines that carried these rows'
     dividers are gone, leaving headlines running together. Restored as
     horizontal rules.

     Matching on .rsc-s is deliberate: the rules that strip each variant's
     own top border inside these rows are more specific than a `> * + *`
     selector and were winning.

     No margin-top here — the grid's own 28px row-gap already sits above the
     rule. Adding a margin on top of it put 56px above and 28px below, which
     is what read as stray space under a headline. */
  .rsc-row-heds > .rsc-s + .rsc-s,
  .rsc-row-rule > .rsc-s + .rsc-s,
  .rsc-row-2up  > .rsc-s + .rsc-s,
  .rsc-row-3up  > .rsc-s + .rsc-s {
    border-top: 1px solid var(--rsc-rule-mid);
    padding-top: 28px;
  }

  /* (divider + spacing cleanup now runs from 900px down — see below) */

  /* --- Footer ---
     Sized for a wide three-part row; stacked on a phone it ran very tall
     with a 90px logo and a 26px pull-quote of a description. */
  .footer-wrapper { padding: 28px 16px 24px; }
  .footer-first-row { gap: 16px; padding-bottom: 20px; }
  .footer-logo img { height: 54px; }

  .footer-description {
    font-size: 1.05rem;
    line-height: 1.4;
    margin: 20px 0 16px;
  }

  .footer-highlight ul { gap: 6px 14px; }
  .footer-highlight li { font-size: .95rem; }
  .footer-contact { font-size: .85rem; }
  .footer-bottom-inner { padding: 14px 16px; font-size: .78rem; }
  .footer-links ul { gap: 14px; flex-wrap: wrap; justify-content: center; }
}


/* ================================================================
   SMALL SCREENS — edge to edge, one rule weight, one rhythm
   ================================================================
   These were written at 600px, which is narrower than any current iPhone
   in landscape and narrower than a browser window someone has dragged in
   to "about phone size". From 900 down the page is a single column and all
   of this applies to it.

   Offsets key off --rsc-edge rather than a literal, because .rsc-home's
   gutter is 28px here and 16px below 600 — a hardcoded -16px was right in
   one band and wrong in the other. */
@media (max-width: 900px) {

  /* --- Edge to edge ---
     Pictures and tinted blocks run the full width of the screen; only text
     keeps the gutter. The negative margin puts them back on the viewport
     edge and `width` covers the two margins it just gave away. Each tinted
     block then takes the gutter back as its own padding, so the colour
     reaches the edge and the words do not. */
  .rsc-home .rsc-img,
  .rsc-home .rsc-lead-img,
  .rsc-wwr-teaser,
  .rsc-ec,
  .rsc-rail,
  .rsc-home .roscoe-newsletter-box {
    margin-left: calc(var(--rsc-edge) * -1);
    margin-right: calc(var(--rsc-edge) * -1);
    width: calc(100% + var(--rsc-edge) * 2);
  }

  .rsc-wwr-teaser { padding: 20px var(--rsc-edge) 18px; }
  .rsc-ec-inner   { padding: 20px var(--rsc-edge) 24px; }
  .rsc-rail-in    { padding: 26px var(--rsc-edge) 24px; }
  .rsc-home .roscoe-newsletter-box { padding: 30px var(--rsc-edge) 34px; }
  .rsc-panel { --rsc-bleed: var(--rsc-edge); }

  /* --- One rule weight ---
     A single column doesn't need three weights of line to tell blocks
     apart, and the tinted ones don't need a rule at all — a colour change
     is already the strongest separator on the page. */
  .rsc-wwr-teaser { border-top: 0; }
  .rsc-otd { border-top-width: 1px; }
  .rsc-ec-head,
  .rsc-panel-head,
  .rsc-rail-head { border-bottom-width: 1px; }
  .rsc-allstories { border-width: 1px; }
  .rsc-home .roscoe-nl-input { border-width: 1px; }

  /* --- One rhythm ---
     The lists ran on an 11px half-gap while the story rows used 28px,
     which is what made Editor's Choice look tighter than its neighbours. */
  .rsc-ec-list > *,
  .rsc-panel-list > * { padding: 14px 0; }
  .rsc-ec-list > *:first-child,
  .rsc-panel-list > *:first-child { padding-top: 0; }
  .rsc-ec-list > *:last-child,
  .rsc-panel-list > *:last-child { padding-bottom: 0; }

  .rsc-ec-body > * + * { margin-top: var(--rsc-stack); padding-top: var(--rsc-stack); }
  /* (.rsc-row-catch's stack column is spaced by the ONE BOUNDARY rules;
     it used to be given margin and padding here as well, and with the
     grid's own row-gap on top that came to 79px under the story above it —
     the widest gap on the page.) */

  /* --- One colour ---
     The lines that read as "thicker" are not thicker. They are 1px black
     (--rsc-rule-strong / --rsc-text) next to 1px #b9b6b0, and at this size
     that contrast reads as weight. Stacked, nothing on the page is
     important enough to earn a black rule while its neighbour gets a grey
     one, so they all become the grey. */
  .rsc-home .rsc-s-text,
  .rsc-home .rsc-s-pointer,
  .rsc-home .rsc-row-rule,
  .rsc-home .rsc-row-heds,
  .rsc-home .rsc-hero,
  .rsc-home .rsc-hero-lead,
  .rsc-home .rsc-hero-col,
  .rsc-home .rsc-otd,
  .rsc-home .rsc-block { border-color: var(--rsc-rule-mid); }

  /* ("No rule against a picture" moved up to the 1200px block, and no
     longer touches padding-top. See the note there.) */

  /* The hero closes against the first story of the river, which nearly
     always leads with art — and the lead itself closes against the tinted
     teaser. Neither needs a line. */
  .rsc-hero,
  .rsc-hero-lead { border-bottom: 0; }

  /* The masthead's rule sits directly on top of the lead picture. Once
     scrolled the header carries a shadow of its own, so nothing is lost. */
  body.rsc-home-page .roscoe-site-header:not(.rsc-scrolled) { border-bottom-color: transparent; }

  /* --- The hero column joins the stream ---
     The teaser appears at this width, so the hero column needs the
     boundary below it. Only the CONTAINER takes it: the three cards are
     still side by side until 600px, and padding on the cards themselves
     would push the second and third 18px out of line with the first.
     Their own boundary is already set in the 600px block, where they
     finally stack. */
  .rsc-home .rsc-feed-main .rsc-hero-col {
    margin-top: var(--rsc-gap-half);
    padding-top: var(--rsc-gap-half);
    margin-bottom: 0;
    row-gap: 0;
    /* No rule here. The teaser appears at this width and sits directly
       above the column, so the hairline landed under a tinted box — and
       under the picture of the first card below it. */
    border-top: 0;
  }

  /* The teaser is an object rather than a story — it has its own padding
     inside a tint, so it takes the whole gap as margin instead of being
     split across a divider that isn't there. The card below it supplies
     its own half, so the teaser's bottom margin comes off. */
  .rsc-home .rsc-wwr-teaser { margin-top: var(--rsc-gap); margin-bottom: 0; }

  /* The modules keep their own outer spacing: they are display:none below
     900, and this is what they use at 900-1200. */
  .rsc-ec { margin: var(--rsc-stack) 0; }
  .rsc-otd { margin-bottom: var(--rsc-stack); padding-top: var(--rsc-stack); }
  .rsc-panel { margin-bottom: var(--rsc-stack); }
  /* (.rsc-hero's bottom padding is set in the 1200px block and applies from
     there down. A `padding-bottom: 0` used to sit here too, saying the
     opposite at lower specificity — dead, but the kind of dead line someone
     later reads as the intent.) */

  /* Inside the rail the two hairlines were a shade apart from each other
     (#dedbd4 against #e0e0e0). Its masthead rule stays as it is — that is a
     section head on tint, not a story divider. */
  .rsc-rail-totop { border-top-color: var(--rsc-border); }
  .rsc-home .rsc-wwr { border-bottom-color: var(--rsc-border); }

  /* The wide picture-left story becomes an ordinary art card: picture on
     top at full width, headline under it. Everything else at this size
     already runs its art full width, and keeping this one at 44%/1fr left
     a cramped image with a headline jammed beside it — and put it outside
     the art spacing rules that every other card follows. Same shape as its
     neighbours now, so the same rules reach it. */
  .rsc-s-horiz { grid-template-columns: 1fr; gap: 13px; }
  .rsc-s-horiz h3.rsc-hed { font-size: 1.35rem; }


  /* --- One headline size, one deck size ---
     The stream is assembled from shapes that mean something different side
     by side — a wide picture story, a headline row, a hero column — and
     each brought its own type size along. Stacked they are just stories in
     a row, and 22/20px headlines with 16/15px decks one after another reads
     as a mistake rather than a hierarchy. The lead keeps its size; it is
     the one story on the page that is genuinely more important. */
  .rsc-feed-main .rsc-s h3.rsc-hed { font-size: 1.3rem; line-height: 1.25; }
  .rsc-feed-main .rsc-s .rsc-deck  { font-size: 1rem;   line-height: 1.5; }

  /* --- The out-of-sequence modules come off ---
     AI, Local News, Editor's Choice and On This Day all reach outside the
     reverse-chron flow for older stories. Beside a story column they read
     as departments; stacked into that column they are three long blocks of
     older material interrupting the newest thing we have, and they roughly
     double the scroll. See the note in index-roscoe.php: the stories in
     them are claimed from the pool, so they do not reappear further down —
     they are simply not on the phone. */
  .rsc-panel,
  .rsc-ec,
  .rsc-otd { display: none; }

  /* --- The top of the page ---
     The lead picture should meet the masthead the way it does on the
     current site: no rule between them and no gap. The header's hairline
     is drawn by an ::after on its inner wrapper, so hiding the border alone
     was never going to remove it. */
  body.rsc-home-page .roscoe-site-header .roscoe-site-header-inner::after { display: none; }
  .rsc-hero { padding-top: 0; }

  /* The lead hands off to the teaser, which now carries the gap itself. */
  .rsc-hero-lead { padding-bottom: 0; margin-bottom: 0; }

  /* The 18px art exception and the .rsc-ec/.rsc-otd/.rsc-panel sibling
     compensators that used to sit here are both gone. The exception made
     the gap under a picture story smaller than the gap under the text
     story beside it — the "Google's" bug, chased for four rounds. The
     compensators existed only because a gap defined by `+` disappears when
     the sibling is display:none; a boundary a row carries itself cannot
     have that problem. See ONE BOUNDARY in the 1200px block. */
}

@media (max-width: 600px) {
  /* .rsc-home drops to a 16px gutter here; the bleed follows it. */
  :root { --rsc-edge: 16px; }

  /* --- Decks come back ---
     600, not 900. The story rows stack at 1200, but the hero's row of three
     in the full-width-lead arrangement holds its columns until 600 — and a
     deck on the middle one of three makes it run far taller than the two
     beside it, which is the exact raggedness these variants drop decks to
     avoid. Once nothing is side by side, there is nothing to be uneven
     against. */
  .rsc-deck-stack { display: block; margin-top: 7px; }
  .rsc-row-heds h3.rsc-hed:has(+ .rsc-deck-stack),
  .rsc-hero-col h3.rsc-hed:has(+ .rsc-deck-stack) { margin-bottom: 0; }
}

/* ================================================================
   BEAT ARCHIVE
   A standing section, not a tag page. The job is a scannable index of
   hundreds of stories, so it runs as a three-column ledger — date,
   headline and deck, byline — at a wider measure than the other
   archives, with no sidebar competing beside it.
   ================================================================ */

.rsc-beat-page {
  --rsc-beat-rail: 106px;
  max-width: 1140px;
  margin: 0 auto;
  padding: 0 var(--rsc-edge) 72px;
}

/* ---- masthead ---- */

/* The rule under the masthead takes the beat's colour. This is the quiet
   version of "colour the page": a 3px band the full width of the well is
   unmistakable, but it is a flag under the name rather than the name itself,
   so the title keeps the weight it earns from being big and black.
   To colour the TITLE instead, set `color: var(--rsc-beat-c)` on
   h1.rsc-beat-title and put --rsc-text back here. */
.rsc-beat-masthead {
  border-bottom: 3px solid var(--rsc-beat-c, var(--rsc-text));
  margin-bottom: 8px;
  /* A little more above than there was with the eyebrow: the title now
     starts the page cold, and at this size it needs room off the header
     rather than the eyebrow's 27px of lead-in. */
  padding: 56px 0 28px;
}

/* No cap on the wrapper. It used to be 760px, which the title inherited and
   which wrapped "Reporting & Production" onto two lines at the new size. The
   measure belongs on the prose that needs it — the description — not on the
   box everything happens to sit in. */
.rsc-beat-masthead-in { max-width: none; }

h1.rsc-beat-title {
  font-family: var(--rsc-headline);
  font-weight: 600;
  /* Big. With the eyebrow gone this is the only thing at the top of the
     page, and a beat name is short enough to carry the size — the longest
     is "Reporting & Production" at 22 characters, which still sets on one
     line at the cap on any desktop width. */
  font-size: clamp(2.6rem, 7vw, 4.9rem);
  line-height: 1.02;
  letter-spacing: -.04em;
  margin: 0;
  color: var(--rsc-text);
}

.rsc-beat-desc {
  font-family: var(--rsc-sans);
  font-size: 1.08rem;
  line-height: 1.5;
  color: #444;
  margin-top: 16px;
  max-width: 62ch;
}
.rsc-beat-desc p { margin: 0 0 10px; }
.rsc-beat-desc p:last-child { margin-bottom: 0; }

.rsc-beat-count {
  font-family: var(--rsc-sans);
  font-size: .82rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #6d6a63;
  margin-top: 18px;
}
.rsc-beat-count strong { color: var(--rsc-beat-c, var(--rsc-text)); font-weight: 700; }
.rsc-beat-page-no { color: #9a9a96; }

.rsc-beat-switch {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin-top: 22px;
}
/* Each chip wears its own beat's colour. Every one of the six clears 4.5:1
   on white, so this is legible as text and not just decoration — the row
   doubles as the colour key for the whole system. The border stays neutral
   until hover so six coloured outlines don't compete with the six labels. */
.rsc-beat-switch a {
  font-family: var(--rsc-sans);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--rsc-beat-c, #555);
  text-decoration: none;
  border: 1px solid var(--rsc-border);
  border-radius: 2px;
  padding: 5px 10px;
  white-space: nowrap;
  transition: border-color .15s, background-color .15s;
}
.rsc-beat-switch a:hover {
  border-color: var(--rsc-beat-c, var(--rsc-rule-mid));
  /* color-mix keeps the tint derived from the one colour rather than adding
     six more hex values to maintain; the plain background is the fallback
     anywhere it is unsupported. */
  background: #fafafa;
  background: color-mix(in srgb, var(--rsc-beat-c, #000) 7%, transparent);
}

/* ---- the ledger ---- */

.rsc-beat-list { list-style: none; margin: 0; padding: 0; }

.rsc-beat-item {
  display: grid;
  /* A FIXED rail, and it has to be. Every <li> is its own grid, so
     max-content sizes per row — measured at 88.4, 90.3, 92.9, 96.3px down
     one page — and every headline would start at a different x. The straight
     left edge down the headlines is what makes this read as a ledger rather
     than a list.
     106px is measured, not guessed: the widest AP date the archive can
     produce is "Sept. 30, 2026" at 96.3px in this face at this size, which
     leaves ~10px of headroom. */
  grid-template-columns: var(--rsc-beat-rail) minmax(0, 1fr) 168px;
  gap: 0 var(--rsc-gut-md);
  align-items: start;
  padding: 17px 0;
  border-bottom: 1px solid var(--rsc-border);
}

/* The date and byline rails are supporting information: same size, same
   weight, quiet enough that the eye runs down the headlines and only
   stops at a rail when it wants to. */
.rsc-beat-when,
.rsc-beat-who {
  font-family: var(--rsc-sans);
  font-size: .78rem;
  line-height: 1.45;
  color: #8a8a86;
  padding-top: 4px;
}
/* No tabular-nums: these read "Sept. 25, 2026" and Schibsted's tnum widens
   the comma — see .rsc-familybar-date. */
.rsc-beat-when { white-space: nowrap; }
.rsc-beat-who a { color: inherit; text-decoration: none; }
.rsc-beat-who a:hover { color: var(--rsc-text); }

h2.rsc-beat-hed {
  font-family: var(--rsc-headline);
  font-weight: 500;
  font-size: 1.22rem;
  line-height: 1.25;
  letter-spacing: -.02em;
  margin: 0;
  text-wrap: pretty;
}
h2.rsc-beat-hed a { color: var(--rsc-text); text-decoration: none; }
h2.rsc-beat-hed a:hover { color: #7d1525; }

.rsc-beat-deck {
  font-family: var(--rsc-sans);
  font-size: .93rem;
  line-height: 1.45;
  color: #666;
  margin: 5px 0 0;
  max-width: 68ch;
}

/* ---- the picture rows ---- */

/* Sized to punctuate rather than take over: it sits in the same column as
   the headlines so the ledger's left edge never breaks, and it is capped
   short enough that a dozen text rows still share the screen with it. */
.rsc-beat-item-art { padding: 24px 0 22px; }

.rsc-beat-art {
  display: block;
  margin-bottom: 13px;
  max-width: 440px;
}
.rsc-beat-art img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: #eee;
}
.rsc-beat-item-art h2.rsc-beat-hed { font-size: 1.34rem; line-height: 1.2; }

/* ---- pagination ---- */

.rsc-beat-prevnext {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  margin-top: 34px;
  font-family: var(--rsc-sans);
  font-size: .9rem;
  font-weight: 600;
}
.rsc-beat-prevnext a { color: var(--rsc-text); text-decoration: none; }
.rsc-beat-prevnext a:hover { color: #7d1525; }

.rsc-beat-empty {
  font-family: var(--rsc-sans);
  color: #666;
  padding: 40px 0;
}

@media (max-width: 900px) {
  /* The byline rail is the first thing to go: it is the least useful of
     the three at a glance, and dropping it buys the headline real width
     before anything has to stack. */
  .rsc-beat-item { grid-template-columns: var(--rsc-beat-rail) minmax(0, 1fr); }
  .rsc-beat-who {
    grid-column: 2;
    padding-top: 6px;
    font-size: .76rem;
  }
  .rsc-beat-art { max-width: none; }
}

@media (max-width: 600px) {
  /* The rails cannot survive here — a 92px date column leaves the headline
     about 30 characters — so date and byline pair up on one meta line above
     the story instead, date left, byline right. Stacking all four as
     separate lines worked but ran 192px a row, which is not an index; this
     is about 150px and still reads as one entry per line-and-a-bit. */
  .rsc-beat-item {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas: "when who" "body body";
    gap: 0;
    padding: 15px 0;
  }
  .rsc-beat-when { grid-area: when; padding-top: 0; font-size: .72rem; }
  .rsc-beat-who  { grid-area: who;  padding-top: 0; font-size: .72rem; text-align: right; }
  .rsc-beat-body { grid-area: body; margin-top: 6px; }
  h2.rsc-beat-hed { font-size: 1.15rem; }
  .rsc-beat-item-art h2.rsc-beat-hed { font-size: 1.3rem; }
  .rsc-beat-masthead { padding-top: 28px; }
}

/* ================================================================
   DARK MODE — first pass
   ----------------------------------------------------------------
   HOW IT IS WIRED. An inline script at the top of <head> resolves the
   stored preference (auto | light | dark) to a concrete data-theme of
   light or dark before first paint. That means everything below keys off
   [data-theme="dark"] alone and never needs repeating inside a
   prefers-color-scheme block — one source of truth per colour. The cost
   is that with JS off the page stays light; that is a deliberate trade
   for a preview feature, and worth revisiting before this ships.

   HOW FAR THIS GOES. 43% of the colour declarations in this file already
   run through a token, and those come across for free. The other 57% are
   hardcoded — 20 literal #fff backgrounds and a spread of greys (#333,
   #444, #555, #666, #4a4a4a) that all mean "muted text" and should have
   been one token from the start. This block covers the structural
   surfaces and the common greys; it does not pretend to cover everything.
   Anything still bright in dark mode is one of those hardcoded values,
   and the fix is to convert it to a token rather than to add an override
   here.

   THE LIGHT DESIGN IS UNTOUCHED. Every rule below is additive and scoped
   to [data-theme="dark"], so nothing above this comment changed.
   ================================================================ */

:root {
  /* The dark values live here, once, so a colour is edited in one place.
     They are inert until the mapping block below points a token at one. */
  --rsc-d-page:    #161513;   /* warm near-black; this palette is warm in light too */
  --rsc-d-surface: #1F1E1A;   /* raised: rail, panels, Editor's Choice, footer */
  --rsc-d-text:    #E9E6DF;   /* 14.6:1 on the page */
  --rsc-d-muted:   #A6A199;   /*  7.1:1 */
  --rsc-d-faint:   #8A857C;   /*  5.0:1 */
  --rsc-d-border:  #33312C;
  --rsc-d-rule:    #4A473F;
  --rsc-d-strong:  #6E6A61;
  --rsc-d-accent:  #E4586B;   /* crimson lifted to 5.1:1; #A51C30 is 1.9:1 here */
}

[data-theme="dark"] {
  color-scheme: dark;

  --rsc-text:        var(--rsc-d-text);
  --rsc-muted:       var(--rsc-d-muted);
  --rsc-border:      var(--rsc-d-border);
  --rsc-rule-mid:    var(--rsc-d-rule);
  --rsc-rule-strong: var(--rsc-d-strong);
}

/* ---- surfaces ---- */

[data-theme="dark"] body,
[data-theme="dark"] .rsc-home,
[data-theme="dark"] .rsc-beat-page,
[data-theme="dark"] .rsc-archive,
[data-theme="dark"] .roscoe-body-zone,
[data-theme="dark"] #rsc-tex-zone {
  background: var(--rsc-d-page);
  color: var(--rsc-d-text);
}

/* The header sets background AND color from --rsc-header-bg / --rsc-header-color,
   and both are INLINE on the element — the same trap as the beat colours, so
   reassigning either from here does nothing. The properties that consume them
   have to be overridden instead.

   Flipping the background but not the color is exactly what left the hamburger
   and search icons black on black: they are color:inherit with currentColor
   SVGs, so they kept taking the inline #1a1a1a.

   :not(.rsc-header-tinted) leaves a coloured-hero header matching its hero.
   These three declarations are also duplicated inline in header-roscoe.php so
   the first frame is dark; this is the copy that takes over once roscoe.css
   lands. */
[data-theme="dark"] .roscoe-site-header:not(.rsc-header-tinted) {
  background: var(--rsc-d-page);
  color: var(--rsc-d-text);
  border-bottom-color: rgba(255,255,255,.10);
}
[data-theme="dark"] .roscoe-site-header:not(.rsc-header-tinted) .roscoe-icon-btn { color: var(--rsc-d-text); }
[data-theme="dark"] .roscoe-site-header.rsc-scrolled { box-shadow: rgba(0,0,0,.5) 1px 3px 8px; }

[data-theme="dark"] .rsc-familybar,
[data-theme="dark"] .rsc-hubnav { background: var(--rsc-d-page); }

[data-theme="dark"] .roscoe-footer,
[data-theme="dark"] .rsc-rail,
[data-theme="dark"] .rsc-ec { background: var(--rsc-d-surface); }

/* (An earlier version set --rsc-header-bg here. Dead: the variable is inline
   on the element, so a stylesheet rule can never win against it.) */

/* ---- type ---- */

[data-theme="dark"] h2.roscoe-headline,
[data-theme="dark"] h2.rsc-lead-hed a,
[data-theme="dark"] h3.rsc-hed a,
[data-theme="dark"] h2.rsc-beat-hed a,
[data-theme="dark"] .roscoe-loop-headline a,
[data-theme="dark"] h1.rsc-beat-title,
[data-theme="dark"] .rsc-sidebar-hed { color: var(--rsc-d-text); }

[data-theme="dark"] .roscoe-post-deck,
[data-theme="dark"] .rsc-deck,
[data-theme="dark"] .rsc-beat-deck,
[data-theme="dark"] .rsc-lead-deck,
[data-theme="dark"] .roscoe-loop-deck,
[data-theme="dark"] .rsc-beat-desc { color: var(--rsc-d-muted); }

[data-theme="dark"] .rsc-byline,
[data-theme="dark"] .rsc-beat-when,
[data-theme="dark"] .rsc-beat-who,
[data-theme="dark"] .rsc-img-caption,
[data-theme="dark"] .roscoe-body .nakedboxedimagecaption p,
[data-theme="dark"] .rsc-sidebar-byline,
[data-theme="dark"] .roscoe-loop-date,
[data-theme="dark"] .roscoe-loop-author { color: var(--rsc-d-faint); }

[data-theme="dark"] .roscoe-body { color: var(--rsc-d-text); }
[data-theme="dark"] .roscoe-body a { color: var(--rsc-d-text); }
[data-theme="dark"] .bigimagebreakout-caption { color: var(--rsc-d-text); }
[data-theme="dark"] .roscoe-body a:hover { color: var(--rsc-d-accent); }
[data-theme="dark"] .bigimagebreakout-caption a:hover { color: var(--rsc-d-accent); }

/* ---- accents ---- */

/* Crimson at #A51C30 measures 1.9:1 on this page — unreadable. Everywhere it
   carries meaning it lifts to the accent; the WWR source flags come along. */
[data-theme="dark"] .rsc-wwr-source,
[data-theme="dark"] .rail-flag,
[data-theme="dark"] .rsc-rail-more,
[data-theme="dark"] .roscoe-linkmeta a:hover { color: var(--rsc-d-accent); }

/* Beat colours: the base set runs 2.7-3.9:1 here, too weak for text. The
   light variants built for the crimson overlay measure 6.0-6.4:1 on this
   page, so dark mode reuses them rather than adding a third palette.

   These override the PROPERTIES THAT CONSUME the variable, not the variable
   itself. --rsc-beat-c is set as an inline style on the page wrapper and on
   each chip, and an inline custom property beats any stylesheet rule on the
   same element — so reassigning it here silently did nothing. Overriding the
   uses works because they sit on different elements and properties. */
[data-theme="dark"] .rsc-beat-masthead {
  border-bottom-color: var(--rsc-beat-c-lite, var(--rsc-d-strong));
}
[data-theme="dark"] .rsc-beat-count strong {
  color: var(--rsc-beat-c-lite, var(--rsc-d-text));
}
[data-theme="dark"] .rsc-beat-switch a {
  color: var(--rsc-beat-c-lite, var(--rsc-d-muted));
}
[data-theme="dark"] .rsc-beat-switch a:hover {
  border-color: var(--rsc-beat-c-lite, var(--rsc-d-rule));
  background: color-mix(in srgb, var(--rsc-beat-c-lite, #fff) 12%, transparent);
}
[data-theme="dark"] .rsc-hubnav-inner a:hover {
  text-decoration-color: var(--rsc-beat-c-lite, currentColor);
}

/* ---- images ---- */

/* Full-strength white photos against a near-black page are the single most
   fatiguing thing in a dark reading view. A slight knock-down, lifted on
   hover so nothing is permanently dulled. */
[data-theme="dark"] .rsc-img img,
[data-theme="dark"] .rsc-lead-img img,
[data-theme="dark"] .rsc-beat-art img,
[data-theme="dark"] .roscoe-loop-bigart { filter: brightness(.88); transition: filter .2s; }
[data-theme="dark"] a:hover .rsc-img img,
[data-theme="dark"] a:hover img { filter: none; }

/* ---- logo ---- */

/* Two files, swapped by CSS. See the note in header-roscoe.php for why this
   is not filter: invert(). */
/* Qualified with img on purpose: .roscoe-logo img sets display:block at
   (0,1,1), so a bare .rsc-logo-darkmode at (0,1,0) loses and BOTH marks
   render in light mode. */
.roscoe-logo img.rsc-logo-darkmode { display: none; }
[data-theme="dark"] .roscoe-logo img.rsc-logo-lightmode { display: none; }
[data-theme="dark"] .roscoe-logo img.rsc-logo-darkmode  { display: block; }
/* The homepage sizes the mark off .roscoe-logo img, so the second file has to
   inherit the same rules rather than sit outside them. */
[data-theme="dark"] body.rsc-big-header .roscoe-logo img.rsc-logo-darkmode {
  height: calc(22px + (var(--rsc-logo-full) - 22px) * (1 - var(--rsc-shrink, 0)));
}

/* ---- surfaces that were hardcoded light ---- */

/* These are the bright patches. Every one was a literal in the light half of
   this file; they are listed here by the value they used to carry so the two
   halves can be diffed. */

/* #f7f6f5 — the ripped-paper blockquote, the ed note, the footer. This is
   what showed up as big white blocks in the middle of a dark article. */
[data-theme="dark"] .ednote,
[data-theme="dark"] blockquote.rippedpaper,
[data-theme="dark"] .roscoe-footer { background: var(--rsc-d-surface); }

/* #f2f0eb — the warm light surfaces. */
[data-theme="dark"] .roscoe-sock,
[data-theme="dark"] .rsc-rail,
[data-theme="dark"] .rsc-wwr-teaser { background: var(--rsc-d-surface); }

/* The teaser CTA is a filled pill now, not coloured text, so it wants the
   lifted crimson as its BACKGROUND and keeps white type. It used to sit in
   the crimson-as-text list below, which on this ground would have painted
   crimson on crimson. */
[data-theme="dark"] .rsc-wwr-teaser-go { background: var(--rsc-d-accent); color: #10100f; }
[data-theme="dark"] .rsc-wwr-teaser:hover .rsc-wwr-teaser-go { background: #ffb3bf; }
[data-theme="dark"] .rsc-wwr-teaser:active { background: #26241f; }

/* #e7edef / #eceae8 / #edcda5 — Editor's Choice, related-story embeds, and
   the newsletter box, which was the last big light rectangle on the page. */
[data-theme="dark"] .rsc-ec { background: var(--rsc-d-surface); }
[data-theme="dark"] .embed-relatedstory { background: var(--rsc-d-surface); }
[data-theme="dark"] .roscoe-newsletter-box { background: #2A2724; }
[data-theme="dark"] .roscoe-newsletter-desc { color: var(--rsc-d-muted); }
[data-theme="dark"] .roscoe-nl-input {
  background: var(--rsc-d-page);
  color: var(--rsc-d-text);
  border-color: var(--rsc-d-rule);
}
[data-theme="dark"] .roscoe-nl-input::placeholder { color: var(--rsc-d-faint); }

/* #eee / #e6e4df — image placeholders. A light grey box behind a loading
   photo is a flash of white on every scroll. */
[data-theme="dark"] .rsc-img,
[data-theme="dark"] .rsc-lead-img,
[data-theme="dark"] .sock-card-img,
[data-theme="dark"] .sock-featured-img,
[data-theme="dark"] .rsc-wwr-img,
[data-theme="dark"] .rsc-beat-art img { background: #26241F; }

/* The fade-out mask over long text runs was a white gradient. */
[data-theme="dark"] .rsc-text-mask {
  background: linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, var(--rsc-d-page) 92%, transparent) 8%,
    var(--rsc-d-page) 15%,
    var(--rsc-d-page) 85%,
    color-mix(in srgb, var(--rsc-d-page) 92%, transparent) 92%,
    transparent 100%);
}

/* ---- the grey ramp ---- */

/* #333 #444 #4a4a4a #555 — all of these meant "body copy, slightly quieter".
   On a dark ground they have to go the other way or they vanish. */
[data-theme="dark"] h3.subhead,
[data-theme="dark"] h4.subsubhead,
[data-theme="dark"] .dropcap,
[data-theme="dark"] .ednote,
[data-theme="dark"] .ednote a,
[data-theme="dark"] .conl,
[data-theme="dark"] .conr,
[data-theme="dark"] .conm,
[data-theme="dark"] .roscoe-linkmeta,
[data-theme="dark"] .rsc-wwr-body { color: var(--rsc-d-text); }

/* #666 #999 #8a8a86 #9a9a96 #6d6a63 #6a675f #57544e #b3b0aa #c9c6c0 —
   the "supporting information" greys. */
[data-theme="dark"] .rsc-hubnav-inner a,
[data-theme="dark"] .rsc-img-credit,
[data-theme="dark"] .rsc-wwr-attrib,
[data-theme="dark"] .rsc-beat-count,
[data-theme="dark"] .rsc-beat-page-no,
[data-theme="dark"] .rsc-404-form input::placeholder,
[data-theme="dark"] .rsc-archives-month.is-empty,
[data-theme="dark"] .roscoe-sharing-row a { color: var(--rsc-d-faint); }

/* The initials are the one thing here that must NOT use a readable grey.
   #ddd is near-invisible on white; the same value on the dark surface is
   bright and shouty, the opposite of the intent.
   Matched arithmetically rather than by eye: #ddd is 221 against 255, so
   it sits 13% of the way down from the background. On #16161a (22), 13%
   of the way up is ~52, which is alpha .13 — not the .17 I first guessed,
   which rendered noticeably louder than the light version. */
[data-theme="dark"] .rsc-wwr-by { color: rgba(255, 255, 255, .13); }

[data-theme="dark"] .rsc-archives-month.is-empty { border-color: var(--rsc-d-border); }

/* The page section heads on About and similar were mid-grey on white and
   became almost unreadable. */
[data-theme="dark"] .rsc-page-well h2,
[data-theme="dark"] .rsc-page-well h3,
[data-theme="dark"] .roscoe-body h2,
[data-theme="dark"] .roscoe-body h3,
[data-theme="dark"] .roscoe-body h4 { color: var(--rsc-d-text); }

/* ---- crimson ---- */

/* #a51c30 as TEXT is 1.9:1 here. As a background it is fine, so only the
   text and border uses are lifted. */
[data-theme="dark"] h1.roscoe-linkheadline a:hover,
[data-theme="dark"] .roscoe-linkmeta-out,
[data-theme="dark"] .rsc-beat-hed a:hover,
[data-theme="dark"] h3.rsc-hed a:hover,
[data-theme="dark"] h2.rsc-lead-hed a:hover,
[data-theme="dark"] .footer-highlight li a:hover,
[data-theme="dark"] .footer-social a:hover,
[data-theme="dark"] .rsc-beat-prevnext a:hover { color: var(--rsc-d-accent); }

[data-theme="dark"] .roscoe-body a { text-decoration-color: rgba(228,88,107,.45); }
[data-theme="dark"] .roscoe-body a:hover { text-decoration-color: rgba(228,88,107,.9); }
[data-theme="dark"] .bigimagebreakout-caption a { text-decoration-color: rgba(228,88,107,.45); }
[data-theme="dark"] .bigimagebreakout-caption a:hover { text-decoration-color: rgba(228,88,107,.9); }
[data-theme="dark"] .rsc-img-caption a { text-decoration-color: rgba(228,88,107,.5); }

/* ---- footer ---- */

[data-theme="dark"] .footer-copyright p,
[data-theme="dark"] .footer-links a,
[data-theme="dark"] .footer-social a,
[data-theme="dark"] .footer-highlight li a { color: var(--rsc-d-muted); }
[data-theme="dark"] .footer-links a:hover,
[data-theme="dark"] .footer-highlight li a:hover { color: var(--rsc-d-text); }

/* ---- borders ---- */

[data-theme="dark"] .rsc-beat-item,
[data-theme="dark"] .rsc-sidebar-post,
[data-theme="dark"] .roscoe-sidebar,
[data-theme="dark"] .rsc-block,
[data-theme="dark"] .rsc-row-heds,
[data-theme="dark"] .rsc-stackcol,
[data-theme="dark"] .rsc-s-text,
[data-theme="dark"] .rsc-hero { border-color: var(--rsc-d-border); }

[data-theme="dark"] .rsc-beat-masthead,
[data-theme="dark"] .rsc-row-rule,
[data-theme="dark"] .rsc-panel-head { border-color: var(--rsc-d-strong); }

/* ---- misc ---- */

[data-theme="dark"] .storybreak-simple { color: rgba(255,255,255,.28); }
[data-theme="dark"] .storybreak-simple.storybreak-camera { color: rgba(255,255,255,.7); }
[data-theme="dark"] .conml strong { color: #C48ABF; }   /* #751770 lifted */
[data-theme="dark"] .conmr strong { color: #E0B23F; }   /* #b88202 lifted */
[data-theme="dark"] .roscoe-series-kicker a { background: var(--rsc-d-rule); }

/* ---- second pass: the long tail ---- */

/* Everything below came out of an audit of the light half of this file for
   hardcoded colours with no dark answer. The ones NOT listed here were
   checked and left alone on purpose: white text on the crimson overlay, on
   the teal/rust panels, on the crimson buttons and on the footer bar is
   already correct in both themes, and .on-light / .on-dark are chosen per
   hero by the editor rather than by the theme. */

/* Crimson used as TEXT. 1.9:1 on this ground, so every one of these lifts. */
[data-theme="dark"] .rsc-familybar-links a:hover,
[data-theme="dark"] .roscoe-bylineedit:hover,
[data-theme="dark"] .rsc-wwr-teaser-bullet,
[data-theme="dark"] .rsc-rail-totop,
[data-theme="dark"] .rsc-otd-item:hover .rsc-otd-hed,
[data-theme="dark"] h3.rsc-wwr-hed a:hover,
[data-theme="dark"] .rsc-wwr-flag,
[data-theme="dark"] h3.sock-hed a:hover,
[data-theme="dark"] h2.sock-featured-hed a:hover,
[data-theme="dark"] .rsc-searchpage-empty a,
[data-theme="dark"] .rsc-archives-tags a:hover,
[data-theme="dark"] .rsc-archives-yearlabel a:hover,
[data-theme="dark"] .rsc-404-links a:hover,
[data-theme="dark"] a.rsc-wwr-masthead-title:hover,
[data-theme="dark"] h2.rsc-wwr-dayhead a:hover,
[data-theme="dark"] .rsc-wwr-tags a:hover,
[data-theme="dark"] .rsc-wwr-more a,
[data-theme="dark"] .rsc-wwr-permalink:hover,
[data-theme="dark"] .rsc-wwr-body a:hover,
[data-theme="dark"] .rsc-wwr-attrib a:hover { color: var(--rsc-d-accent); }

/* New in the cross-surface work: the articles <-> WWR link, and the WWR
   search box on /reading/ and a single WWR. */
[data-theme="dark"] .rsc-streamtab { color: var(--rsc-d-muted, #9b968c); border-color: rgba(255,255,255,.18); }
[data-theme="dark"] .rsc-streamtab.is-current {
  background: var(--rsc-d-surface);
  border-color: var(--rsc-d-rule);
  color: var(--rsc-d-text);
}
[data-theme="dark"] a.rsc-streamtab:hover { color: var(--rsc-d-accent); border-color: var(--rsc-d-accent); }
[data-theme="dark"] .rsc-archives-tags a:hover { border-bottom-color: var(--rsc-d-accent); }

/* Near-black text that has to become near-white. */
[data-theme="dark"] .roscoe-newsletter-hed,
[data-theme="dark"] .footer-description,
[data-theme="dark"] .footer-description a,
[data-theme="dark"] .rsc-wwr-body a,
[data-theme="dark"] .rsc-wwr-attrib a,
[data-theme="dark"] .rsc-wwr-full .rsc-wwr-body,
[data-theme="dark"] .rsc-wwrpage .rsc-wwr-body,
[data-theme="dark"] .roscoe-author-bio,
[data-theme="dark"] .conml,
[data-theme="dark"] .conmr { color: var(--rsc-d-text); }

/* Supporting greys. */
[data-theme="dark"] .roscoe-datestamprow strong,
[data-theme="dark"] .roscoe-serieswrapper a,
[data-theme="dark"] .roscoe-hub-link strong,
[data-theme="dark"] .footer-contact,
[data-theme="dark"] .rsc-familybar-links a,
[data-theme="dark"] .rsc-familybar-date,
[data-theme="dark"] .rsc-searchpage-empty,
[data-theme="dark"] .rsc-404-text,
[data-theme="dark"] .rsc-wwr-masthead-blurb,
[data-theme="dark"] .rsc-beat-empty,
[data-theme="dark"] .rsc-searchpage-form input::placeholder,
[data-theme="dark"] .rsc-wwr-search input::placeholder { color: var(--rsc-d-muted); }

[data-theme="dark"] .roscoe-author-bio a:hover,
[data-theme="dark"] .roscoe-sharing-row a:hover { color: var(--rsc-d-accent); }

/* The search and 404 fields were a light tint that went white on focus. */
[data-theme="dark"] .rsc-searchpage-form,
[data-theme="dark"] .rsc-wwr-search,
[data-theme="dark"] .rsc-404-form {
  background: var(--rsc-d-surface);
  border-color: var(--rsc-d-rule);
}
[data-theme="dark"] .rsc-searchpage-form:focus-within,
[data-theme="dark"] .rsc-wwr-search:focus-within,
[data-theme="dark"] .rsc-404-form:focus-within {
  background: var(--rsc-d-page);
  border-color: var(--rsc-d-strong);
}
[data-theme="dark"] .rsc-searchpage-form input,
[data-theme="dark"] .rsc-wwr-search input,
[data-theme="dark"] .rsc-404-form input { color: var(--rsc-d-text); }

/* Story breaks are near-black glyphs. */
[data-theme="dark"] .storybreak-simple.storybreak-tv { color: rgba(255,255,255,.7); }

/* Caption link hover, and the beat headline hover written with its h2 in the
   light half. (.on-light / .on-dark are deliberately absent from this whole
   block: those track the hero colour an editor picked, not the theme, so a
   light hero keeps dark text in dark mode and should.) */
[data-theme="dark"] .rsc-img-caption a:hover { color: var(--rsc-d-text); }
[data-theme="dark"] h2.rsc-beat-hed a:hover { color: var(--rsc-d-accent); }

/* Two declarations in the light half carry !important, so these have to. */
[data-theme="dark"] a.embed-relatedstory-link:hover { color: var(--rsc-d-accent) !important; }
[data-theme="dark"] .rsc-overlay-text .roscoe-post-deck { color: var(--rsc-d-muted) !important; }

/* ---- the theme switch itself ---- */

.rsc-nav-theme { margin-top: 6px; }

.rsc-theme-switch {
  display: inline-flex;
  /* Its parent .rsc-nav-group is a flex column, which stretches every child
     to full width — inline-flex or not — leaving the empty rest of the box
     hanging off the last button, "Dark". */
  align-self: flex-start;
  border: 1px solid rgba(255,255,255,.35);
  border-radius: 3px;
  overflow: hidden;
}
.rsc-theme-switch button {
  font-family: var(--rsc-sans);
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .02em;
  color: rgba(255,255,255,.8);
  background: transparent;
  border: 0;
  border-right: 1px solid rgba(255,255,255,.2);
  padding: 7px 14px;
  cursor: pointer;
  transition: background-color .15s, color .15s;
}
.rsc-theme-switch button:last-child { border-right: 0; }
.rsc-theme-switch button:hover { background: rgba(255,255,255,.12); color: #fff; }
.rsc-theme-switch button.is-on { background: #fff; color: #A51C30; }

/* =====================================================================
   NO RULE AGAINST A PICTURE
   ---------------------------------------------------------------------
   A photograph is already the strongest separator there is; a hairline
   drawn immediately above one is only furniture. Because art sits at the
   TOP of a card, this is the card's own border-top — a divider below an
   art card falls under its text, which is fine and stays.

   Two things about where this lives.

   It is LAST in the file on purpose. At (0,3,0) it kept losing ties to
   equally specific rules that simply came later — `.rsc-row-2up > .rsc-s +
   .rsc-s` in the 600px block was the one drawing the lines under "Go west"
   and "The Athletic". It is now (0,4,0) as well, so it wins on specificity
   rather than only on position, but keeping it at the end means a new
   breakpoint rule cannot quietly take the tie back.

   And it suppresses the BORDER only. An earlier version also zeroed
   padding-top, which was harmless while padding existed purely to give a
   rule air, and wrong the moment padding became half the gap — it silently
   halved every boundary above a picture to 18px. Do not add padding here.
   ===================================================================== */
@media (max-width: 1200px) {
  .rsc-home .rsc-feed-main .rsc-s:has(.rsc-img),
  .rsc-home .rsc-feed-main .rsc-row:has(> .rsc-s:first-child .rsc-img) { border-top: 0; }
}

/* =====================================================================
   STAGE 2 — THE SPLIT OPENER'S NAV BAR (hero layout 4)
   =====================================================================
   On layout 4 the nav bar belongs inside the hero's text half, scrolling
   away with it, and the ordinary full-width bar only drops in once the
   hero is gone — the NYT split-opener behaviour.

   WHY absolute AND THEN fixed. The bar has to be out of flow from the
   first paint, or the hero cannot own the whole window. absolute makes it
   scroll away with the hero; fixed pins it afterwards. Going from one to
   the other is free: neither occupies flow space, so the document height
   never changes and nothing jumps at the handoff. Hiding the bar and
   showing a second copy, or taking a sticky bar out of flow partway down,
   both move the page by the bar's height at the switch.

   An article page has no familybar, so the header is the first in-flow
   element and body is not positioned — top/left 0 is the hero's own top
   left corner.

   Confined to wide screens on purpose. Below 960px the halves stack, the
   hero drops to min-height 0, and the bar goes back to being an ordinary
   sticky bar; scoping the whole block to the complement of that
   breakpoint means none of this has to be undone there.
   ===================================================================== */
@media (min-width: 961px) {

  body.rsc-split-opener .roscoe-site-header {
    position: absolute;
    top: 0;
    left: 0;
    width: 50%;
  }
  /* Picture on the left puts the text half, and so the bar, on the right. */
  body.rsc-split-opener.rsc-split-reversed .roscoe-site-header {
    left: auto;
    right: 0;
  }

  /* No bar of its own: the hero's colour field is the background.
     The :not() is also carrying specificity — the dark-mode rule
     [data-theme="dark"] .roscoe-site-header:not(.rsc-header-tinted) is
     (0,3,1), so matching it here and sitting later in the file is what
     keeps the bar transparent on a dark-theme article. */
  body.rsc-split-opener:not(.rsc-hdr-pinned) .roscoe-site-header {
    background: transparent;
    border-bottom-color: transparent;
    box-shadow: none;
  }

  /* The controls sit in the CORNER of the half, not on the headline's
     margin. Matching .rsc-split-text's side padding here was the obvious
     thing to try and it is wrong: it put the hamburger exactly on the
     headline's left edge, which reads as the bar belonging to the text
     block rather than to the window, and it paired a 56px side inset with
     a 12px top one. 28px is the site header's own padding, so the corner
     keeps the proportion the full-width bar has and is clearly inside the
     headline's 38-56px margin at every width above the breakpoint.

     max-width off because --rsc-well is wider than half a normal window
     but not half a very wide one, where it would suddenly start
     re-centring the row inside the half. */
  body.rsc-split-opener:not(.rsc-hdr-pinned) .roscoe-site-header-inner {
    max-width: none;
    margin: 0;
    padding-left: 28px;
    padding-right: 28px;
  }

  /* THE SUBSCRIBE BUTTON IS AN EXCEPTION HERE — see the note on
     .rsc-header-subscribe, which argues for a fixed blue fill so the button
     stays a landmark that does not change per article. That argument rests
     on the button sitting on a predictable background, which is true of
     every bar on the site except this one: unpinned, this bar is
     transparent over whatever colour the hero's text half happens to be.
     A fixed blue outline disappears on a dark half, and a reversed white
     fill becomes the loudest thing on the bar there. currentColor is the
     only treatment that stays quiet on both, and it is already the contrast
     colour the hamburger and search icon use, so the three controls read as
     one set instead of one of them shouting. Halving the bar's width
     doubled the share of it the filled button took.

     Scoped to the unpinned state only: the moment the full-width bar drops
     back in, the blue fill and the landmark argument return with it. */
  body.rsc-split-opener:not(.rsc-hdr-pinned) .rsc-header-subscribe {
    background: transparent;
    color: inherit;
    border: 1px solid currentColor;
    font-size: .66rem;
    padding: 5px 11px;
    opacity: .85;
    transition: opacity .15s;
  }
  body.rsc-split-opener:not(.rsc-hdr-pinned) .rsc-header-subscribe:hover,
  body.rsc-split-opener:not(.rsc-hdr-pinned) .rsc-header-subscribe:focus-visible {
    background: transparent;
    opacity: 1;
  }

  /* Nothing above the hero in flow any more, so it takes the whole window
     rather than the window minus the bar. */
  body.rsc-split-opener .rsc-split-hero {
    min-height: max(540px, 100vh);
    min-height: max(540px, 100svh);
  }

  /* The bar now floats over the top of the text half, so the half needs
     enough padding to clear it. Both sides get the same value: the
     headline block is centred by justify-content, and a padding-top that
     did not match padding-bottom would push it off centre again. */
  body.rsc-split-opener .rsc-split-text {
    padding-top:    max(clamp(32px, 5vw, 64px), calc(var(--rsc-hdr-h, 50px) + 12px));
    padding-bottom: max(clamp(32px, 5vw, 64px), calc(var(--rsc-hdr-h, 50px) + 12px));
  }

  /* Hero gone: the ordinary bar, full width and pinned. It is added one
     frame before .rsc-hdr-shown so the transform has a value to animate
     from — see the observer in header-roscoe.php. */
  body.rsc-split-opener.rsc-hdr-pinned .roscoe-site-header {
    position: fixed;
    left: 0;
    right: 0;
    width: 100%;
    transform: translateY(-100%);
  }
  body.rsc-split-opener.rsc-hdr-pinned.rsc-hdr-shown .roscoe-site-header {
    transform: none;
    transition: transform .28s ease;
  }

  @media (prefers-reduced-motion: reduce) {
    body.rsc-split-opener.rsc-hdr-pinned.rsc-hdr-shown .roscoe-site-header {
      transition: none;
    }
  }
}


/* ================================================================
   IN-POST LAYOUT PATTERNS
   ================================================================
   A vocabulary for the inside of a story: width tiers, figure
   arrangements, margin notes, quote variants and editorial furniture.

   Two rules govern the whole section.

   1. ADDITIVE. Nothing here restyles an existing class. 2,542 posts
      use .nakedboxedimage and 2,522 use .rightimage; 561 use the old
      pull quotes. Those keep rendering exactly as they do today. The
      one deliberate exception is [rp] (298 posts), which was asked
      for by name.

   2. DEPTH-INDEPENDENT. Every width tier works out its own width and
      takes the difference out of its own margins, so a pattern does
      not care how deeply it is nested inside .roscoe-body. The old
      [bigimagebreakout] closed four <div>s to escape the column and
      broke whenever the template's depth changed; nothing here can
      fail that way.
   ================================================================ */

/* ----------------------------------------------------------------
   1 · WIDTH TIERS
   ----------------------------------------------------------------
   The well is 700px (--rsc-body-max). A tier sets --rsc-w and the
   shared rule centres it on the column's own centre line.

   margin-left: calc(50% - W/2) rather than a transform: a transform
   would make the element a containing block for fixed descendants
   and interfere with position: sticky inside it. The arithmetic is
   the same and the side effects are none.

   The width is clamped against the viewport first, so the margin and
   the box always agree about how wide the thing actually is — which
   is what stops a breakout from hanging off the right edge on a
   laptop. .roscoe-body-zone clips the x-axis as a final backstop. */
.roscoe-body .rsc-out {
  --rsc-ow: min(var(--rsc-w, 700px), calc(100vw - 48px));
  width: var(--rsc-ow);
  max-width: none;
  margin-left: calc(50% - var(--rsc-ow) / 2);
  margin-right: 0;
  margin-bottom: 34px;
  box-sizing: border-box;
}

.roscoe-body .rsc-mid  { --rsc-w: 880px; }
.roscoe-body .rsc-wide { --rsc-w: 1100px; }

/* Full bleed. 100vw counts the scrollbar, which is exactly why
   .roscoe-body-zone uses overflow-x: clip — see the BODY ZONE note. */
.roscoe-body .rsc-full {
  --rsc-ow: 100vw;
  width: 100vw;
  margin-left: calc(50% - 50vw);
}

/* Asymmetry as emphasis: one margin gains precisely what the other
   gives up, so the block stays the same size and only moves. */
/* The push is clamped to the room that actually exists, rather than
   taken on faith. A flat 90px is fine at 1440 and walks the picture off
   the screen at 700: measured at a 570px viewport, "wide right" ran to
   636px and "wide left" started at -66px, both cropped by the body
   zone's overflow clip.

   --rsc-push-fit is whatever is left after the block and a 24px gutter,
   never less than zero — so the offset shrinks smoothly as the window
   narrows and reaches zero exactly when the margin runs out. No
   breakpoint to maintain, and it cannot overflow whatever distance= an
   editor types. */
.roscoe-body .rsc-push-r,
.roscoe-body .rsc-push-l {
  --rsc-push-fit: max(0px, min(var(--rsc-push, 90px), (100vw - var(--rsc-ow)) / 2 - 24px));
}
.roscoe-body .rsc-push-r { margin-left: calc(50% - var(--rsc-ow) / 2 + var(--rsc-push-fit)); }
.roscoe-body .rsc-push-l { margin-left: calc(50% - var(--rsc-ow) / 2 - var(--rsc-push-fit)); }

/* A post with the sidebar option has no margins to escape INTO — the
   right-hand rail is already there. Everything collapses back to the
   column rather than sliding under the sidebar. */
.rsc-has-sidebar .roscoe-body .rsc-out,
.rsc-has-sidebar .roscoe-body .rsc-full {
  --rsc-ow: 100%;
  width: 100%;
  margin-left: 0;
  margin-right: 0;
}

/* ----------------------------------------------------------------
   2 · FIGURES
   ---------------------------------------------------------------- */
/* The UA stylesheet gives every <figure> `margin: 1em 40px`. A tiered
   figure never noticed, because .rsc-out writes its own margin-left and
   margin-right. An untiered one kept all 80px of it and came out 620px
   wide inside a 700px well — which is why [img] with no width rendered
   NARROWER than the same picture with no wrapper at all.

   :not(.rsc-out) matters: a blanket margin-inline on .rsc-fig would sit
   AFTER the tier rules in this file and quietly undo every one of them. */
.roscoe-body .rsc-fig { margin-top: 34px; }
.roscoe-body .rsc-fig:not(.rsc-out) { margin: 34px 0; }
.roscoe-body .rsc-fig img { width: 100%; height: auto; display: block; }

/* Deliberately identical to .rsc-img-caption, the featured-image
   caption: same family, size, leading and colour. A caption under a
   picture in the body and a caption under the picture at the top of the
   story are the same kind of text, and a reader scrolling past both
   should not be able to tell they were built by different code. */
.roscoe-body .rsc-fig figcaption,
.roscoe-body .rsc-cap {
  font-family: var(--rsc-sans);
  font-size: .95rem;
  line-height: 1.4;
  color: #666;
  margin-top: 10px;
}

.roscoe-body .rsc-credit {
  display: block;
  font-size: .8rem;
  color: #999;          /* = .rsc-img-credit on the featured image */
  margin-top: 4px;
}

/* A full-bleed picture pulls its caption back to a readable measure —
   a caption is text and wants a text column, not the whole window. */
.roscoe-body .rsc-full > figcaption {
  max-width: 880px;
  margin-left: auto;
  margin-right: auto;
  padding: 0 24px;
}

/* Caption in the margin. A tall picture and a long caption stacked
   become one very tall object; side by side they stay one unit. */
@media (min-width: 1150px) {
  .roscoe-body .rsc-fig-aside {
    display: grid;
    grid-template-columns: 1fr 200px;
    gap: 0 26px;
    align-items: end;
  }
  .roscoe-body .rsc-fig-aside > figcaption {
    margin-top: 0;
    padding-bottom: 4px;
  }
}

/* Comparison pairs and triples. Captions belong to each pane, which
   is the whole point when the two pictures are the argument. */
.roscoe-body .rsc-duo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 26px;
  margin-top: 34px;
}
.roscoe-body .rsc-trio { grid-template-columns: repeat(3, 1fr); }
.roscoe-body .rsc-duo figure,
.roscoe-body .rsc-duo .rsc-pane { margin: 0; }
.roscoe-body .rsc-duo img { width: 100%; height: auto; display: block; }

.roscoe-body .rsc-fig-label,
.roscoe-body .rsc-pane-label {
  font-family: var(--rsc-sans);
  font-size: .68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--rsc-text);
  padding-bottom: 7px;
  margin-bottom: 9px;
  border-bottom: 2px solid var(--rsc-text);
}

@media (max-width: 760px) {
  .roscoe-body .rsc-duo { grid-template-columns: 1fr; gap: 22px; }
}

/* ----------------------------------------------------------------
   3 · MARGIN NOTES
   ----------------------------------------------------------------
   A float with a negative margin, which is the whole trick. It works
   only because .roscoe-body is still normal flow — floats are ignored
   on grid items, so turning the body into a grid would cost this
   entire section (and .leftimage / .rightimage with it).

   The note is rendered TWICE from one source: once as a margin aside,
   once as a numbered footnote at the foot of the article. CSS shows
   exactly one. Because the other is display: none rather than
   visually hidden, it is out of the accessibility tree too — a screen
   reader meets each note once, in either mode.

   Geometry, at the 1150px breakpoint: the well's right edge sits at
   925px from the viewport's left. A 180px note pushed out 200px
   occupies 945–1125, so it clears the text by 20px and the viewport
   by 25px. Those two numbers are why the width and the offset are
   what they are. */
.roscoe-body .rsc-note-mark {
  font-family: var(--rsc-sans);
  font-size: .62em;
  font-weight: 700;
  line-height: 0;
  vertical-align: super;
  color: #A51C30;
  padding-left: 1px;
}

.roscoe-body .rsc-note-aside { display: none; }
.roscoe-body .rsc-notes-list { display: block; }

@media (min-width: 1150px) {
  .roscoe-body .rsc-note-aside {
    display: block;
    float: right;
    clear: right;
    width: 180px;
    margin: 6px -200px 20px 20px;
    font-family: var(--rsc-sans);
    font-size: .8rem;
    line-height: 1.5;
    color: var(--rsc-muted, #6b665c);
  }
  /* No rule above the note. A border plus its padding pushed the first
     line down by ten pixels, so the note's text no longer sat level
     with the marker that points at it — and the marker IS the alignment
     reference. Nothing to draw: the margin already separates the note
     from the column. */
  .roscoe-body .rsc-note-aside .rsc-note-n {
    font-weight: 800;
    color: #A51C30;
    margin-right: 5px;
  }
  /* The footnote list is redundant once the notes are in the margin. */
  .roscoe-body .rsc-notes-list { display: none; }
}

.roscoe-body .rsc-notes-list {
  margin: 44px 0 0;
  padding-top: 18px;
  border-top: 1px solid var(--rsc-border);
  font-family: var(--rsc-sans);
  font-size: .9rem;
  line-height: 1.55;
  color: var(--rsc-muted, #6b665c);
}
.roscoe-body .rsc-notes-list h2 {
  font-family: var(--rsc-sans);
  font-size: .72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--rsc-text);
  margin: 0 0 12px;
}
.roscoe-body .rsc-notes-list ol { margin: 0; padding-left: 1.3em; }
.roscoe-body .rsc-notes-list li { margin-bottom: 9px; }

/* A picture in the margin — same float, same geometry. */
.roscoe-body .rsc-marginfig { display: none; }
@media (min-width: 1150px) {
  .roscoe-body .rsc-marginfig {
    display: block;
    float: right;
    clear: right;
    width: 180px;
    margin: 6px -200px 20px 20px;
  }
  .roscoe-body .rsc-marginfig img { width: 100%; height: auto; display: block; }
  .roscoe-body .rsc-marginfig figcaption { font-size: .78rem; margin-top: 7px; }
}
/* Below the breakpoint it is still a picture, so it stays in the column
   rather than disappearing the way a note does. */
@media (max-width: 1149px) {
  .roscoe-body .rsc-marginfig {
    display: block;
    float: none;
    width: auto;
    margin: 24px 0;
  }
  .roscoe-body .rsc-marginfig img { width: 100%; height: auto; display: block; }
}

/* ----------------------------------------------------------------
   5 · EDITORIAL FURNITURE
   ---------------------------------------------------------------- */

/* A boxed aside that overlaps the margin: distinct object, still
   inside the story. The right weight for methodology notes and
   definitions. Because it floats, it wants a reasonably long passage
   beside it — dropped next to two lines it dangles into what follows. */
.roscoe-body .rsc-sidebar-box {
  margin: 10px 0 24px;
  padding: 22px 24px;
  background: #F2F0EB;
  border-top: 3px solid var(--rsc-text);
  font-family: var(--rsc-sans);
  font-size: .92rem;
  line-height: 1.5;
}
.roscoe-body .rsc-sidebar-box p { margin-bottom: .9em; }
.roscoe-body .rsc-sidebar-box p:last-child { margin-bottom: 0; }
.roscoe-body .rsc-sidebar-box-title {
  font-size: .7rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .1em;
  margin: 0 0 12px;
}
@media (min-width: 1150px) {
  .roscoe-body .rsc-sidebar-box {
    float: right;
    clear: right;
    width: 280px;
    margin: 8px -140px 24px 32px;
  }
  .roscoe-body .rsc-sidebar-box.rsc-box-left {
    float: left;
    clear: left;
    margin: 8px 32px 24px -140px;
  }
}



/* ----------------------------------------------------------------
   6 · CAROUSEL
   ----------------------------------------------------------------
   Scroll-snap, not a slider library. The track is a real scroll
   container, so it works with a trackpad, a touch swipe, the keyboard
   and a screen reader before a single line of JS runs; the buttons
   just call scrollBy() on it. With JS off it degrades to a swipeable
   strip, which is still the right behaviour. */
.roscoe-body .rsc-carousel { margin-block: 34px; position: relative; }

.roscoe-body .rsc-carousel-track {
  display: flex;
  gap: 18px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: thin;
  padding-bottom: 10px;
}
/* snap-align: start, not center. With centre alignment the snap points
   are "wherever a slide's middle lines up with the track's middle",
   which is NOT the same series as the slides' own offsets — so a
   button that advances by one slide width lands between two snap
   points and the browser yanks it somewhere else. Aligning to the
   start makes snap position == slide offset, which is the series the
   buttons actually navigate. */
.roscoe-body .rsc-carousel-track > figure {
  flex: 0 0 min(78%, 620px);
  scroll-snap-align: start;
  margin: 0;
}
.roscoe-body .rsc-carousel-track img { width: 100%; height: auto; display: block; }
.roscoe-body .rsc-carousel-track figcaption {
  font-family: var(--rsc-sans);
  font-size: .82rem;
  line-height: 1.45;
  color: var(--rsc-muted, #6b665c);
  margin-top: 9px;
}

.roscoe-body .rsc-carousel-nav {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 12px;
}
.roscoe-body .rsc-carousel-btn {
  width: 38px;
  height: 38px;
  border-radius: 999px;
  border: 1px solid var(--rsc-border);
  background: transparent;
  color: var(--rsc-text);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.roscoe-body .rsc-carousel-btn:hover { border-color: #A51C30; color: #A51C30; }
.roscoe-body .rsc-carousel-btn[disabled] { opacity: .3; cursor: default; }
.roscoe-body .rsc-carousel-count {
  font-family: var(--rsc-sans);
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--rsc-muted, #6b665c);
  margin-left: 4px;
}

/* ----------------------------------------------------------------
   DARK MODE
   ---------------------------------------------------------------- */
[data-theme="dark"] .roscoe-body .rsc-sidebar-box { background: var(--rsc-d-surface); }

[data-theme="dark"] .roscoe-body .rsc-sidebar-box { border-top-color: var(--rsc-d-text); }

[data-theme="dark"] .roscoe-body .rsc-note-mark,
[data-theme="dark"] .roscoe-body .rsc-note-aside .rsc-note-n { color: var(--rsc-d-accent); }
[data-theme="dark"] .roscoe-body .rsc-note-aside,
[data-theme="dark"] .roscoe-body .rsc-fig-label,
[data-theme="dark"] .roscoe-body .rsc-pane-label { border-color: var(--rsc-d-text); }
[data-theme="dark"] .roscoe-body .rsc-notes-list { border-top-color: var(--rsc-d-rule); }
[data-theme="dark"] .roscoe-body .rsc-carousel-btn { border-color: var(--rsc-d-rule); color: var(--rsc-d-text); }
[data-theme="dark"] .roscoe-body .rsc-carousel-btn:hover { border-color: var(--rsc-d-accent); color: var(--rsc-d-accent); }


/* ----------------------------------------------------------------
   .inpost — the class every newly inserted picture carries
   ----------------------------------------------------------------
   One class, and it never changes. It says "this is a picture in the
   body of a story" and nothing else; every variation — wider, full
   bleed, margin caption, side by side — comes from wrapping the tag in
   [img wide] and friends. That is the point of the split: the class is
   identity, the shortcode is treatment, and a staffer only ever touches
   the second one.

   max-width rather than width: a 300px logo should stay 300px, not be
   stretched to fill the well. Large images fill it anyway. */
.roscoe-body img.inpost {
  display: block;
  max-width: 100%;
  height: auto;
  margin-block: 34px;
}

/* Inside a wrapper the figure owns the spacing and the width, so the
   image gives both up. */
.roscoe-body .rsc-fig img.inpost,
.roscoe-body .rsc-pane img.inpost,
.roscoe-body .rsc-marginfig img.inpost,
.roscoe-body .rsc-carousel-track img.inpost {
  margin: 0;
  width: 100%;
}

/* nakedboxedimagewide was a 600px well's way of reaching 700px. The
   well IS 700px in Roscoe, so it has been identical to nakedboxedimage
   since launch and needs nothing further — noted here so the next
   person does not go looking for the difference. (466 posts use it.) */


/* ----------------------------------------------------------------
   IN-POST PATTERNS ON A PHONE
   ----------------------------------------------------------------
   Below 600px every picture in the body goes edge to edge, which is
   what Simple did with .nakedboxedimage and what a single narrow
   column wants: at this size a "wider" tier is not wider than
   anything, it is just a differently-inset version of the same
   picture, and three different insets on one screen read as a mistake.

   Measured at 570px before this block, left/right edges were:

     text, bare <img>, untiered [img]   16 / 554   (the body gutter)
     mid, wide, duo, trio, carousel     24 / 546   (8px adrift)
     full                                0 / 570
     wide right                        114 / 636   (66px off-screen)
     wide left                         -66 / 456   (66px off-screen)

   The 8px had one cause: the tiers clamp to 100vw - 48px, a 24px
   gutter, while .roscoe-body-section drops to 16px at this width. Two
   numbers for one gutter is the bug; the fix is to stop having an
   inset here at all.

   Art goes to the viewport edge. TEXT — captions, labels, carousel
   controls — comes back to the body gutter, so every line of type on
   the page still starts at the same place. */
@media (max-width: 600px) {

  /* :not(.rsc-out) is repeated here deliberately. The untiered rule
     further up is three classes deep and therefore MORE specific than a
     plain .roscoe-body .rsc-fig, so it went on forcing margin-left: 0
     while this block set width: 100vw — a viewport-wide box starting at
     the text margin, hanging 16px off the right edge and silently
     cropped by the body zone's overflow clip. Source order does not
     settle a specificity argument. */
  .roscoe-body .rsc-fig,
  .roscoe-body .rsc-fig:not(.rsc-out),
  .roscoe-body .rsc-duo,
  .roscoe-body .rsc-carousel,
  .roscoe-body .rsc-marginfig,
  .roscoe-body img.inpost {
    --rsc-ow: 100vw;
    width: 100vw;
    max-width: none;
    margin-left: calc(50% - 50vw);
    margin-right: 0;
  }

  /* A push needs a margin to push into, and there isn't one. */
  .roscoe-body .rsc-push-r,
  .roscoe-body .rsc-push-l { --rsc-push-fit: 0px; }

  /* …and the text inside them lines up with the prose again. */
  .roscoe-body .rsc-cap,
  .roscoe-body .rsc-fig figcaption,
  .roscoe-body .rsc-fig-label,
  .roscoe-body .rsc-pane-label,
  .roscoe-body .rsc-carousel-nav {
    padding-left: 16px;
    padding-right: 16px;
  }

  /* The full-bleed caption already pulls itself back to a readable
     measure; on a phone the measure IS the viewport, so it only needs
     the gutter. */
  .roscoe-body .rsc-full > figcaption {
    max-width: none;
    margin-left: 0;
    margin-right: 0;
    padding-left: 16px;
    padding-right: 16px;
  }

  /* Stacked panes sit flush under one another rather than keeping a
     gutter the full-bleed container no longer has. */
  .roscoe-body .rsc-duo { gap: 26px; }
}


/* ----------------------------------------------------------------
   FEATURED-IMAGE CAPTION: a gutter only when the picture needs one
   ----------------------------------------------------------------
   .rsc-stack-img-wrap takes its width INLINE, per post, from the
   roscoe_img_width field — 1000, 1200, 1400 and so on. So the window
   width at which the picture stops being centred and starts touching
   the viewport edge is different for every post, and a media query
   cannot know it: a breakpoint tuned to the 1000px default would
   wrongly inset every post set narrower, across an archive where 607
   posts carry that field.

   roscoe-single-meat.php now also publishes the width as
   --rsc-heroimg-w, which lets the CSS do the comparison itself.

   The clamp is a switch, not a scale. When 100vw is at least as wide
   as the picture the inner term is negative, so clamp takes the
   minimum: no padding, and the caption stays flush with the art. Once
   the window is narrower the term goes positive and is multiplied far
   past the maximum, so clamp takes the gutter. The multiplier only
   has to be large enough to clear the gutter from one pixel of
   difference. */
.rsc-stack-img-wrap:not(.rsc-stack-img-fullbleed) > .rsc-img-caption {
  padding-inline: clamp(
    0px,
    (var(--rsc-heroimg-w, 1000px) - 100vw) * 999,
    var(--rsc-cap-gutter, 24px)
  );
}
@media (max-width: 600px) {
  .rsc-stack-img-wrap { --rsc-cap-gutter: 16px; }
}


/* ----------------------------------------------------------------
   [sidenote plain] — an aside, not a reference
   ----------------------------------------------------------------
   No number and no marker: the note is beside the sentence, and that
   adjacency is the link. The * † ‡ § sequence exists for notes at the
   foot of a page, where adjacency is gone and ordering is the only
   route back; in the margin it would be answering a question the
   margin has already answered.

   Which is also why it behaves differently when the margin runs out.
   A numbered note collapses into the list at the end of the article —
   a reference survives that trip, because the number carries the
   reader back. An aside does not: at the end it is beside nothing,
   and there is no number to return on. So it stays where it was
   written and becomes an indented block in the flow. */
.roscoe-body .rsc-note-plain .rsc-note-aside { display: block; }

@media (max-width: 1149px) {
  .roscoe-body .rsc-note-plain .rsc-note-aside {
    float: none;
    clear: none;
    width: auto;
    margin: 20px 0;
    padding: 2px 0 2px 18px;
    border-top: 0;
    border-left: 3px solid var(--rsc-border);
    font-family: var(--rsc-sans);
    font-size: .92rem;
    line-height: 1.5;
    color: var(--rsc-muted, #6b665c);
  }
}

[data-theme="dark"] .roscoe-body .rsc-note-plain .rsc-note-aside {
  border-color: var(--rsc-d-rule);
}
@media (min-width: 1150px) {
  [data-theme="dark"] .roscoe-body .rsc-note-plain .rsc-note-aside {
    border-color: var(--rsc-d-text);
  }
}


/* ----------------------------------------------------------------
   BLOCKS CLEAR THE MARGIN FURNITURE
   ----------------------------------------------------------------
   A float pushes LINE BOXES aside, not block boxes. So a margin note
   floated into the right margin is perfectly happy to be painted over
   by the next picture, because that picture is a block and simply
   starts at the top of the float and covers it. Wider tiers make it
   worse, since they reach further into the margin where the note is.

   clear is the mechanism for exactly this: the block waits until the
   margin is empty. Both sides, because a note or box can be floated
   left as well.

   Only above 1150px, which is the only place any of this furniture
   floats — below that the notes are in the flow and clearing would be
   inventing vertical gaps for no reason.

   The trade is a taller page when a long note runs up against a
   picture. That is the right way round: a gap is a layout you can see
   and judge, an overlap is one that hides your own words. */
@media (min-width: 1150px) {
  .roscoe-body .rsc-fig,
  .roscoe-body .rsc-duo,
  .roscoe-body .rsc-carousel,
  .roscoe-body img.inpost {
    clear: both;
  }
}
