/* ============================================================
   Stacked Homes — BoF track: single article.

   This is the ?redesign=1 ARTICLE LAYOUT ported onto BoF chrome. The layout,
   type scale and rhythm are the sibling track's (Adam liked that page); only the
   COLOUR and TYPE TOKENS are BoF's. assets/redesign/article.css is frozen and
   was copied from, never edited.

   TOKENS, NOT HEXES. Every colour here is a var(--…) from assets/ed/tokens.css.
   That is not a style preference: `?colour=sky` loads assets/ed/scheme-sky.css
   LAST and re-declares those same custom properties, so a token-only sheet
   recolours for free and a single hardcoded hex is a hole in the scheme. Where
   the source had a literal, it was mapped:
     #C4B79C (share-circle / tag-pill border) -> var(--border-alt)
     #B0381C (in-body link red)               -> var(--hover)   (the track's one hover colour)
     #CFC2A8 (popular-list numeral)           -> var(--border-alt)
     #6A5F50 (darkened metadata ink)          -> see the a11y note below
     #fff on dark chrome                      -> var(--ivory-2) / var(--sand)

   NO --f-mono. The redesign's metadata face is a token that aliases the body
   font; this track never defined one, so every `font-family:var(--f-mono)` in
   the source became var(--f-body) here. Same rendered result, one less alias.

   SCOPING. Every rule is scoped under `.ed-single` (the body class this
   template passes to site-header.php via $sh_body_class) — the layout uses
   generic names like .article-grid, .byline and .faq that would otherwise leak
   into other BoF pages sharing base.css/chrome.css. Body rules are additionally
   scoped under .article-body, which is injected post markup.
   ============================================================ */

/* ---------- GAM sticky-header leaderboard reservation ----------
   The ad plate is position:fixed at the viewport top and publishes its reserved
   height as --launch-lb-h (declared in the ad's own inline CSS, so it exists
   ONLY when a leaderboard actually rendered — Pro articles and logged-in
   subscribers get no plate and no variable).

   Legacy pushes `.wrapper` down by that var; the redesign pushes `.sh-canvas`.
   This track has neither, and <main> starts below the header, so the space has
   to be reserved on the HEADER itself or the fixed plate paints straight over
   the utility bar and the masthead. The fallback of 0px makes this a no-op on
   every page with no ad, which is why it can live unconditionally in the
   stylesheet rather than being branched in PHP.

   MOVED to chrome.css on 2026-09-10. The homepage and section fronts emit the ad
   calls too now, and this stylesheet only loads on articles — so the rule has to
   live with the rest of the chrome or those pages reserve nothing and the plate
   paints over their header. */

/* ---------- page frame ---------- */

/* Cells stretch to the tallest (the article) so the left + right rails can host
   sticky content that travels the full height of the article. */
/* No top rule. The Intelligence promo band sits directly above this grid and is
   already a hard dark edge, so a 4px rule 1px below it read as a second, thicker
   bar stacked under the banner. The band IS the division. */
.ed-single .article-grid {
  display:grid;
  grid-template-columns:250px minmax(0,1fr) 310px;
  align-items:stretch;
}
/* The left rail is kept (empty) when an article has no internal backlink so the
   article column stays centred; it only collapses out below the desktop breakpoint. */

/* A11y: the metadata ink (--text-faint, #8A8172) fails WCAG AA on the sand
   ground (~2.9:1). Darken it to ~4.7:1 ONLY within the article's light content
   areas — the global token is left alone for the dark footer, where it sits on
   ink and must stay light. Derived from the token with a filter-free
   colour-mix so an alternate scheme's --text-faint darkens with it rather than
   being overridden by a fixed brown. */
.ed-single .article-grid,
.ed-single .more-stacked,
.ed-single .more-cols {
  --text-faint:color-mix(in srgb, var(--text-2) 82%, var(--structure));
}

/* ---------- LEFT: Read next ---------- */
.ed-single .art-rail-l { border-right:1px solid var(--border); padding:20px; min-width:0 }
/* Not sticky: the card is a margin reference that sits beside the first internal
   backlink in the body, so it starts lower down (past the title/hero stack).
   article.js replaces this fallback with the measured offset. */
/* The first card starts level with the article body, not 600px down.

   The old rule pushed it by a flat --readnext-offset (default 600px) that
   nothing ever set, so every article got the same guess regardless of how tall
   its headline, standfirst and hero actually were. On a long-titled review that
   put the card below the first screen entirely — visible only after scrolling
   past the point it was meant to accompany.

   28px is the body's own top offset, so the card now begins where the prose
   does. The rail is NOT sticky: it stays with the passage that cites it rather
   than following the reader. */
/* PLACED BEFORE PAINTED.

   article.js aligns each margin card with the link in the body that produced
   it, which moves it by hundreds of pixels — measured here, a 353px card
   leaving the viewport at 1.3s, scoring 0.064 CLS on a quiet load and 0.26 on
   a busy one. That was the whole of this template's layout shift.

   visibility, not display: the box is in the layout from the start, so the card
   is already holding its space and revealing it shifts nothing. The animation is
   the failsafe — if article.js never loads or throws, the card still appears a
   moment later rather than staying invisible forever, which is the failure mode
   a plain class toggle would have. */
.ed-single .art-rail-l__inner { margin-top:28px; visibility:hidden;
  animation:sh-rail-placed 0s linear 1.2s forwards }
@keyframes sh-rail-placed { to { visibility:visible } }
.ed-single .art-rail-l.is-placed .art-rail-l__inner { visibility:visible; animation:none }
@media (prefers-reduced-motion:reduce) {
  /* No motion here to reduce — but a user agent that disables animations
     outright must not be left with a permanently invisible card. */
  .ed-single .art-rail-l__inner { visibility:visible }
  .ed-single .art-rail-l:not(.is-placed) .art-rail-l__inner { visibility:hidden }
}

/* Subsequent cards are spaced down the rail so they sit alongside later
   passages instead of stacking as a block at the top. */
.ed-single .art-rail-l__inner--next { margin-top:96px }
.ed-single .read-next { display:block; position:relative }
/* Stretched-link card so the byline author can be its own link (rides above). */
.ed-single .read-next__link { display:block; color:inherit }
.ed-single .read-next__link::after { content:''; position:absolute; inset:0; z-index:1 }
.ed-single .read-next__img { width:100%; height:auto; aspect-ratio:4/3; object-fit:cover;
  background:var(--panel); margin-bottom:11px }
.ed-single .read-next__k { font-family:var(--f-body); font-size:9.5px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--text-faint); margin-bottom:6px }
.ed-single .read-next__t { font-family:var(--f-display); font-weight:700; font-size:21px;
  line-height:1.16; color:var(--ink-hard) }
.ed-single .read-next:hover .read-next__t { text-decoration:underline }
.ed-single .read-next__dek { font-size:13px; line-height:1.5; color:var(--body); margin-top:9px }
.ed-single .read-next__meta { font-family:var(--f-body); font-weight:700; font-size:9px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--text-faint); margin-top:12px }
/* Card byline author link — rides above the stretched card link.

   This declaration lost its body when .more-stacked__author was removed and the
   selector was left with a trailing comma, which silently joined it to the
   .clamp-* rule below: the author link became a -webkit-box, and a box cannot
   sit inline, so "By" and the name broke onto separate lines. */
.ed-single .read-next__author { color:inherit; text-decoration:none; position:relative; z-index:2 }
.ed-single .read-next__author:hover { color:var(--ink-hard); text-decoration:underline }

/* Line clamps. The source relied on the redesign's base.css for these; this
   track's base.css clamps only its own card deks, so they are declared here. */
.ed-single .clamp-2,
.ed-single .clamp-3 { display:-webkit-box; -webkit-box-orient:vertical; overflow:hidden }
.ed-single .clamp-2 { -webkit-line-clamp:2 }
.ed-single .clamp-3 { -webkit-line-clamp:3 }

/* --- In-article "Read this next": recirculation pullout the read-next-block
   plugin injects at the article midpoint. Sits between body paragraphs, so it
   reads as a raised module (card ground + section-accent top rule), not body
   copy. The .article-body-scoped rules beat the a/img styles it would inherit. */
.ed-single .rn-inline { margin:34px 0; background:var(--card); border-top:3px solid var(--accent) }
.ed-single .rn-inline__label { font-family:var(--f-body); font-weight:700; font-size:10px;
  letter-spacing:.14em; text-transform:uppercase; color:var(--accent-text); padding:12px 16px 0 }
.ed-single .rn-inline__card { display:flex; gap:18px; align-items:center; padding:9px 16px 16px }
.ed-single .article-body .rn-inline__card,
.ed-single .article-body .rn-inline__card:hover { color:inherit; text-decoration:none }
.ed-single .rn-inline__media { flex:0 0 38%; max-width:220px }
.ed-single .rn-inline__img,
.ed-single .article-body .rn-inline__img { width:100%; height:auto; aspect-ratio:4/3;
  object-fit:cover; display:block; margin:0 }
.ed-single .rn-inline__body { min-width:0 }
.ed-single .rn-inline__k { font-family:var(--f-body); font-size:9.5px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--text-faint); margin-bottom:6px }
.ed-single .rn-inline__t { font-family:var(--f-display); font-weight:700; font-size:22px;
  line-height:1.18; color:var(--ink-hard) }
.ed-single .rn-inline__card:hover .rn-inline__t { text-decoration:underline }
.ed-single .rn-inline__dek { font-size:14px; line-height:1.5; color:var(--body); margin-top:8px }
.ed-single .rn-inline__meta { font-family:var(--f-body); font-weight:700; font-size:9px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--text-faint); margin-top:11px }
@media (max-width:560px) {
  .ed-single .rn-inline__card { flex-direction:column; align-items:stretch; gap:12px }
  .ed-single .rn-inline__media { flex:none; max-width:none }
  .ed-single .rn-inline__img,
  .ed-single .article-body .rn-inline__img { aspect-ratio:16/9 }
  .ed-single .rn-inline__t { font-size:20px }
}

/* ---------- CENTER: article ---------- */
.ed-single .article-main { border-right:1px solid var(--border); padding:24px 44px 40px;
  max-width:760px; min-width:0 }

.ed-single .breadcrumb { display:flex; align-items:center; gap:9px; flex-wrap:wrap;
  font-family:var(--f-body); font-size:11px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--text-faint) }
.ed-single .breadcrumb a { color:var(--text-faint) }
.ed-single .breadcrumb a:hover { color:var(--ink-hard) }
.ed-single .breadcrumb .sep { color:var(--border-alt) }
.ed-single .breadcrumb .here { color:var(--ink-hard) }

/* --- Series context above the headline ---
   Reads "Winners & Losers · Analysis 10 of 17". Sits between the breadcrumb and
   the H1, so it uses the breadcrumb's own scale and the mango accent to mark it
   as membership furniture rather than another crumb. */
.ed-single .article-series { display:inline-flex; align-items:baseline; gap:8px;
  flex-wrap:wrap; margin-top:16px }
/* --mango-active, not --mango: the brand orange is ~3:1 on the sand ground,
   which is under AA for 11px text. The darker token clears it. */
.ed-single .article-series__name { font-family:var(--f-body); font-size:11px; font-weight:700;
  letter-spacing:.08em; text-transform:uppercase; color:var(--mango-active) }
.ed-single .article-series__pos { font-family:var(--f-body); font-size:11px; letter-spacing:.05em;
  color:var(--text-faint) }
.ed-single .article-series:hover .article-series__name { text-decoration:underline; text-underline-offset:3px }

.ed-single .article-title { font-family:var(--f-display); font-weight:700; font-size:36px;
  line-height:1.08; letter-spacing:-.3px; color:var(--ink-hard); margin:22px 0 0;
  overflow-wrap:break-word; text-wrap:pretty }
/* The kicker already supplies the gap above the headline. */
.ed-single .article-series + .article-title { margin-top:10px }
.ed-single .article-title i,
.ed-single .article-title em { font-weight:400; font-style:italic }
.ed-single .article-standfirst { font-size:17px; line-height:1.55; color:var(--body);
  margin:16px 0 0; text-wrap:pretty }
.ed-single .article-standfirst i { font-style:italic }

/* ---------- byline ---------- */
.ed-single .byline { display:flex; align-items:center; gap:14px;
  border-top:1px solid var(--border); border-bottom:1px solid var(--border);
  padding:14px 0; margin:22px 0 }
.ed-single .byline__avatar { width:44px; height:44px; border-radius:50%; flex:none;
  overflow:hidden; display:block; background:var(--panel) }
.byline__avatar img { width:100%; height:100%; object-fit:cover; display:block;
  transform-origin:center }
.ed-single .byline__meta-wrap { flex:1; min-width:0 }
.ed-single .byline__name { font-weight:700; font-size:13.5px; color:var(--ink-hard) }
.ed-single .byline__author:hover { color:var(--accent-text) }
.ed-single .byline__meta { font-family:var(--f-body); font-size:10px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--text-faint); margin-top:3px }

/* ---- Published / Updated ----
   sh_article_timestamps() emits the two stamps as ADJACENT SPANS with no
   separator in the markup — the separator is a stylesheet's job, and the legacy
   sheets (assets/css/article.css, combined.css) supply it with display:block.
   This track loads neither, so a post with a declared update rendered as
   "...9:34 PM SGTUPDATED 5 JANUARY 2026" with the two run together.

   Nobody had hit it because `_sh_substantive_update` is set on zero posts today;
   the first editor to tick the box after cutover would have been the first to
   see it. Same treatment as legacy: its own line, slightly recessive. */
.ed-single .post-date__upd { display:block; opacity:.78; margin-top:2px }
.ed-single .byline__share { display:flex; gap:8px }
.ed-single .byline__share a,
.ed-single .byline__share button { width:32px; height:32px; border-radius:50%;
  border:1px solid var(--border-alt); display:flex; align-items:center; justify-content:center;
  font-family:var(--f-body); font-weight:700; font-size:11px; color:var(--body);
  background:none; cursor:pointer; position:relative; flex:none }
.ed-single .byline__share a svg,
.ed-single .byline__share button svg { width:13px; height:13px }
.ed-single .byline__share a:hover,
.ed-single .byline__share button:hover { border-color:var(--ink); color:var(--ink) }
/* dss copy-button "Copied!" toast (shared by the byline + end-of-article blocks) */
.ed-single .dss-share-ui .copied-msg { position:absolute; bottom:calc(100% + 7px); left:50%;
  transform:translateX(-50%); background:var(--structure); color:var(--ivory-2);
  font:600 10px/1 var(--f-body); letter-spacing:0; text-transform:none; padding:5px 8px;
  border-radius:4px; white-space:nowrap; opacity:0; pointer-events:none; transition:opacity .15s; z-index:2 }
.ed-single .dss-share-ui .copied-msg.visible { opacity:1 }

/* ---------- Google Preferred Source opt-in banner ---------- */
.ed-single .gps-banner { display:flex; align-items:center; gap:16px; text-decoration:none;
  border:1px solid var(--border-alt); background:var(--card); padding:14px 16px; margin:26px 0 }
.ed-single .gps-banner:hover { border-color:var(--ink) }
.ed-single .gps-banner__icon { flex:none; width:42px; height:42px; display:flex;
  align-items:center; justify-content:center; background:var(--ivory-2);
  border:1px solid var(--border); border-radius:50% }
.ed-single .gps-banner__icon svg { width:22px; height:22px; display:block }
.ed-single .gps-banner__body { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px }
.ed-single .gps-banner__title { font-family:var(--f-display); font-weight:700; font-size:17px;
  line-height:1.2; color:var(--ink-hard) }
.ed-single .gps-banner__subtitle { font-size:13px; line-height:1.4; color:var(--body) }
.ed-single .gps-banner__cta { flex:none; font-weight:600; font-size:12.5px; color:var(--ink-hard);
  border:1px solid var(--ink); padding:9px 15px; white-space:nowrap; transition:background .12s,color .12s }
.ed-single .gps-banner:hover .gps-banner__cta { background:var(--ink); color:var(--card) }

/* ---------- hero ---------- */
.ed-single .article-hero { margin:0 0 12px }
.ed-single .article-hero img { width:100%; height:auto; aspect-ratio:16/9; object-fit:cover;
  background:var(--panel); display:block }
.ed-single .article-figcaption { font-family:var(--f-body); font-size:13px; line-height:1.5;
  color:var(--text-faint); border-bottom:1px solid var(--border); padding:9px 0 11px }

/* ============================================================
   ARTICLE BODY
   Post markup this design does not control (Gutenberg blocks, plugin
   shortcodes, a decade of different editors), so every rule is scoped under
   .article-body and the overflow defences at the bottom are deliberately broad.
   ============================================================ */
/* font-family is set EXPLICITLY, not inherited. The two tracks disagree on the
   default: assets/ed/base.css makes the serif the site-wide body face, while
   the redesign's is the sans — and long-form running text is the one place that
   difference is felt over 2,000 words. This layout was ported precisely because
   Adam liked how it reads, so the body copy keeps the source's sans. base.css is
   left alone: the serif default is correct for the rest of this track, so the
   override is scoped here rather than changed globally.

   The same applies to the furniture around the body (byline, captions, rails,
   comments) — everywhere the source used var(--f-mono) it now names var(--f-body)
   directly, so those all resolve to the sans too. Headings stay --f-display. */
.ed-single .article-main,
.ed-single .art-rail-l,
.ed-single .art-rail-r,
.ed-single .more-stacked,
.ed-single .more-cols { font-family:var(--f-body) }

.ed-single .article-body { font-family:var(--f-body); font-size:17px; line-height:1.7;
  color:var(--body-strong); margin-top:22px }
.ed-single .article-body > p { margin:0 0 20px }

/* The consultation CTA's own paragraphs.

   The rule above is a DIRECT-CHILD selector, and the CTA nests its copy two
   levels down (.consult-cta-wrapper > .consult-cta > p). So those paragraphs
   matched nothing and ran together with no spacing at all — three separate
   thoughts reading as one block. Nothing else styles them either: the legacy
   theme leans on combined.css, which this track does not load. */
.ed-single .article-body .consult-cta p { margin:0 0 18px; color:var(--text-2) }
.ed-single .article-body .consult-cta p:last-child { margin-bottom:0 }

/* The two rules around it. The CTA ships two empty <div class="consult-divider">
   elements and the legacy stylesheet paints them as 1px lines; this track never
   loads that file, so BOTH were rendering 0x0 and the block ran straight into the
   body copy with nothing marking where the article stopped and the pitch began.

   Given the rules back, the rest is air and voice: the CTA is the newsroom talking
   about its own service, so it gets space, a quieter text colour than the article,
   and its closing line set as an action in the accent. Deliberately NOT a tinted
   card like .rn-inline -- a coloured panel here reads as an advert, which is the
   one thing this block must not look like. */
.ed-single .article-body .consult-cta-wrapper { margin:44px 0 }
.ed-single .article-body .consult-divider { height:1px; width:100%; background:var(--border) }
.ed-single .article-body .consult-cta { padding:24px 0 }
.ed-single .article-body .consult-cta p:last-child a {
  /* --hover, not --accent: in-body links are already this colour, and --accent
     resolves to the yellow in this scheme, which is close to unreadable on cream. */
  font-family:var(--f-body); font-weight:600; font-size:15px; color:var(--hover);
  text-decoration:none; border-bottom:1px solid transparent;
}
.ed-single .article-body .consult-cta p:last-child a:hover { border-bottom-color:currentColor }
.ed-single .article-body h2 { font-family:var(--f-display); font-weight:700; font-size:27px;
  line-height:1.2; color:var(--ink-hard); margin:32px 0 14px; text-wrap:pretty }
.ed-single .article-body h3 { font-family:var(--f-display); font-weight:700; font-size:22px;
  line-height:1.25; color:var(--ink-hard); margin:26px 0 12px; text-wrap:pretty }
.ed-single .article-body h4 { font:700 13px/1.3 var(--f-body); letter-spacing:.1em;
  text-transform:uppercase; color:var(--text-2); margin:30px 0 10px }
.ed-single .article-body h5,
.ed-single .article-body h6 { font:700 11px/1.3 var(--f-body); letter-spacing:.13em;
  text-transform:uppercase; color:var(--text-faint); margin:26px 0 8px }
/* In-body links are UNDERLINED — the opposite of the chrome, where every link is
   bare. In running prose an unmarked link is invisible; in a nav it is noise. */
.ed-single .article-body a { color:var(--hover); text-decoration:underline; text-underline-offset:2px }
.ed-single .article-body a:hover { text-decoration-thickness:2px }
.ed-single .article-body strong,
.ed-single .article-body b { font-weight:700 }
.ed-single .article-body em,
.ed-single .article-body i { font-style:italic }
.ed-single .article-body mark { background:var(--accent-tint); color:inherit }
.ed-single .article-body sup,
.ed-single .article-body sub { font-size:.7em; line-height:0 }
.ed-single .article-body small { font-size:.82em; color:var(--text-2) }
.ed-single .article-body code,
.ed-single .article-body kbd { font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size:.86em; background:var(--panel); padding:2px 5px }
.ed-single .article-body img { width:100%; height:auto; margin:24px 0; background:var(--panel) }
.ed-single .article-body figure { margin:26px 0 }
/* The figure owns the outer spacing; keep the caption tight to the image (not
   the img's own 24px margin + the caption's padding). */
.ed-single .article-body figure img { margin:0 }
.ed-single .article-body figcaption { font-family:var(--f-body); font-size:13px; line-height:1.5;
  color:var(--text-faint); padding:9px 0 0 }
/* Markers are restored here because base.css strips list-style for the chrome's nav lists. */
.ed-single .article-body ul,
.ed-single .article-body ol { padding-left:22px; margin:0 0 20px }
.ed-single .article-body ul { list-style:disc }
.ed-single .article-body ol { list-style:decimal }
.ed-single .article-body li { margin:0 0 8px }
.ed-single .article-body li::marker { color:var(--text-faint) }
.ed-single .article-body li > ul,
.ed-single .article-body li > ol { margin:8px 0 0 }
.ed-single .article-body blockquote { margin:26px 0; padding:4px 0 4px 22px;
  border-left:4px solid var(--mango); font-family:var(--f-display); font-size:26px;
  line-height:1.35; color:var(--ink-hard) }
.ed-single .article-body blockquote p { margin:0 }
.ed-single .article-body blockquote cite { display:block; font:400 10.5px/1.4 var(--f-body);
  letter-spacing:.08em; text-transform:uppercase; color:var(--text-faint); font-style:normal;
  margin-top:12px }
.ed-single .article-body hr { border:0; border-top:1px solid var(--border); margin:32px 0 }
.ed-single .article-body pre { background:var(--panel); padding:16px 18px; margin:28px 0;
  font:400 13px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace; color:var(--ink-hard) }
.ed-single .article-body pre code { background:none; padding:0 }

/* --- Tables (property/data tables): uppercase head with an ink underline,
   hairline rows, tabular figures, subtle zebra, and horizontal scroll on narrow
   screens so a wide table never pushes the page sideways. --- */
.ed-single .article-body .wp-block-table,
.ed-single .article-body .table-scroll {
  margin:28px 0; max-width:100%; overflow-x:auto; -webkit-overflow-scrolling:touch;
  overscroll-behavior-x:contain }
.ed-single .article-body .wp-block-table table,
.ed-single .article-body .table-scroll table { margin:0 }
.ed-single .article-body table { width:100%; border-collapse:collapse; font-size:15px;
  line-height:1.4; font-variant-numeric:tabular-nums; color:var(--body-strong) }
/* A bare <table> the editor pasted without Gutenberg's figure wrapper has no
   scroll container of its own, so it would push the page instead. article.js
   wraps those in .table-scroll; this is the no-JS fallback — `display:block`
   makes the table itself the scroll box, and the inner <tbody> keeps table
   semantics. Only applied where there is no wrapper: inside .wp-block-table the
   figure already scrolls and a block-level table there would break the table
   layout algorithm. */
.ed-single .article-body > table { display:block; max-width:100%; overflow-x:auto;
  -webkit-overflow-scrolling:touch; margin:28px 0 }
.ed-single .article-body th,
.ed-single .article-body td { padding:11px 20px; text-align:left; white-space:nowrap;
  border-bottom:1px solid var(--border); vertical-align:top }
.ed-single .article-body th:first-child,
.ed-single .article-body td:first-child { padding-left:0 }
.ed-single .article-body th:last-child,
.ed-single .article-body td:last-child { padding-right:0 }
.ed-single .article-body thead th,
.ed-single .article-body tr:first-child th { font-family:var(--f-body); font-weight:700;
  font-size:10.5px; letter-spacing:.06em; text-transform:uppercase; color:var(--text-2);
  background:var(--panel); border-bottom:2px solid var(--ink-hard);
  padding-top:10px; padding-bottom:10px }
.ed-single .article-body td:first-child { font-weight:600; color:var(--ink-hard) }  /* label column */
/* Zebra + hover derived from the ink token so an alternate scheme tints with it. */
.ed-single .article-body tbody tr:nth-child(even) td { background:color-mix(in srgb, var(--structure) 3%, transparent) }
.ed-single .article-body tbody tr:hover td { background:color-mix(in srgb, var(--structure) 6%, transparent) }
.ed-single .article-body tbody tr:last-child td { border-bottom:0 }
.ed-single .article-body th.has-text-align-right,
.ed-single .article-body td.has-text-align-right { text-align:right }
.ed-single .article-body th.has-text-align-center,
.ed-single .article-body td.has-text-align-center { text-align:center }
.ed-single .article-body .wp-block-table figcaption { font-family:var(--f-body); font-size:11px;
  color:var(--text-faint); text-align:left; margin-top:10px; white-space:normal }

/* --- The last line of defence for author-written HTML ---
   Editors paste inline `style="width:840px"` on images, `width="885"` on
   iframes, and full-width floats from a decade of different editors. Anything
   that still measures wider than the column would push the PAGE sideways, which
   is the one failure this layout must never have. These caps are deliberately
   broad and use !important, because an inline style is the thing being
   overridden and nothing short of !important beats it. */
.ed-single .article-body img,
.ed-single .article-body video,
.ed-single .article-body canvas,
.ed-single .article-body svg { max-width:100% !important; height:auto }
.ed-single .article-body iframe { max-width:100% !important }
/* GAM slots are the exception (23 Sep 2026, Adam). The cap above squeezed a
   900x285 billboard's FRAME to the ~670px column while the creative inside kept
   its 900px, so the right third was cut off. Ad frames keep their real size and
   article.js scales the whole slot down to the column instead, as the sticky
   leaderboard already is. */
.ed-single .article-body [id^="div-gpt-ad-"] iframe { max-width:none !important }
/* Blocks that carry an inline pixel width (galleries, columns, embeds). Capped
   rather than forced to 100%, so a deliberately narrow element stays narrow. */
.ed-single .article-body figure,
.ed-single .article-body .wp-block-image,
.ed-single .article-body .wp-block-gallery,
.ed-single .article-body .wp-block-columns,
.ed-single .article-body .wp-block-embed { max-width:100% }
/* A long unbroken string (a URL, a reference number) is the one thing no
   max-width can contain, because it is a single unbreakable box. */
.ed-single .article-body p,
.ed-single .article-body li,
.ed-single .article-body h2,
.ed-single .article-body h3,
.ed-single .article-body td,
.ed-single .article-body th { overflow-wrap:anywhere }

/* Embeds (YouTube, tweets, maps) keep their own aspect and never overflow. */
.ed-single .article-body iframe,
.ed-single .article-body video,
.ed-single .article-body embed,
.ed-single .article-body object { max-width:100%; border:0 }
.ed-single .article-body .wp-block-embed { margin:30px 0 }
.ed-single .article-body .wp-block-embed__wrapper { position:relative }
.ed-single .article-body .wp-embed-aspect-16-9 .wp-block-embed__wrapper { aspect-ratio:16/9 }
.ed-single .article-body .wp-block-embed__wrapper > iframe { width:100%; height:100% }

/* --- Raw embeds the editor pasted as bare markup ---
   The two containers the posts actually use are .youtube-container and
   .google-maps, each holding an <iframe> with hardcoded width/height ATTRIBUTES
   (width="885" height="498", width="600" height="450"). max-width:100% shrinks
   the width but leaves the height attribute untouched, so the frame ends up
   339px wide and still 498px tall — a letterboxed video in a tall grey box.
   Giving the container the aspect and stretching the iframe to fill it is what
   actually preserves the ratio, and it costs no CLS because the box is reserved
   before the frame loads. */
.ed-single .article-body .youtube-container,
.ed-single .article-body .wp-block-embed-youtube .wp-block-embed__wrapper {
  position:relative; width:100%; aspect-ratio:16/9; margin:28px 0; background:var(--panel) }
.ed-single .article-body .youtube-container > iframe,
.ed-single .article-body .wp-block-embed-youtube .wp-block-embed__wrapper > iframe {
  position:absolute; inset:0; width:100%; height:100% }
.ed-single .article-body .google-maps { position:relative; width:100%; aspect-ratio:4/3;
  margin:28px 0; background:var(--panel) }
.ed-single .article-body .google-maps > iframe { position:absolute; inset:0; width:100%; height:100% }

.ed-single .article-body .aligncenter { margin-left:auto; margin-right:auto }
.ed-single .article-body .alignwide,
.ed-single .article-body .alignfull { max-width:100% }

/* ---------- paywall ----------
   The gate markup comes from sh_paywall_render_preview(): a
   .premium-preview.with-fade wrapper plus a 1px #paywall-locked token anchor.
   Both are styled here because the legacy CSS that used to dress them
   (combined.css) is not loaded on this track — without these rules the preview
   would simply end mid-sentence with no visual signal that anything is missing. */
.ed-single .article-body .premium-preview { position:relative }
.ed-single .article-body .premium-preview.with-fade::after {
  content:''; position:absolute; left:0; right:0; bottom:0; height:190px;
  pointer-events:none;   /* an invisible overlay must never eat clicks */
  background:linear-gradient(to bottom, transparent 0%, var(--sand) 92%) }
.ed-single .article-body #paywall-locked { display:block }

/* The subscribe panel below the preview. Reuses the Intelligence dark ground so
   the gate reads as the same product as the homepage's Intelligence band. */
.ed-single .ed-gate { background:var(--intel-dark); color:var(--ivory-2);
  padding:26px 28px 28px; margin-top:12px }
.ed-single .ed-gate__eyebrow { color:var(--ivory) }
.ed-single .ed-gate__title { font:400 clamp(22px, 3.2vw, 27px)/1.1 var(--f-display);
  letter-spacing:-.015em; margin-top:10px }
.ed-single .ed-gate__dek { font:400 14px/1.45 var(--f-display); color:var(--border-alt);
  margin-top:10px; max-width:56ch }
.ed-single .ed-gate__actions { display:flex; align-items:center; flex-wrap:wrap; gap:18px;
  margin-top:18px }
.ed-single .ed-gate__signin { font:400 11px/1 var(--f-body); letter-spacing:.08em;
  color:var(--border-alt); text-decoration:underline; text-underline-offset:3px }
.ed-single .ed-gate__signin:hover { color:var(--ivory) }

/* ---------- FAQ (ACF faq_items): CSS-only <details> accordion ---------- */
.ed-single .faq { border:1px solid var(--border-alt); border-radius:12px; background:var(--card);
  padding:4px 24px 14px; margin:32px 0 }
.ed-single .faq__head { font-family:var(--f-display); font-size:15px; color:var(--ink-hard);
  padding:16px 0 2px }
.ed-single .faq__item { border-top:1px solid var(--border) }
.ed-single .faq__item:first-of-type { border-top:0 }
.ed-single .faq__q { list-style:none; cursor:pointer; display:flex; align-items:center;
  justify-content:space-between; gap:18px; padding:16px 0; font-weight:500; font-size:17px;
  line-height:1.3; color:var(--ink-hard) }
.ed-single .faq__q::-webkit-details-marker { display:none }
.ed-single .faq__q::after { content:"+"; flex:none; font-weight:400; font-size:24px;
  line-height:1; color:var(--text-2); transition:transform .2s ease }
.ed-single .faq__item[open] .faq__q::after { transform:rotate(45deg) }
.ed-single .faq__a { padding:0 2px 18px; font-size:15px; line-height:1.6; color:var(--body-strong) }
.ed-single .faq__a p { margin:0 0 12px }
.ed-single .faq__a p:last-child { margin:0 }
.ed-single .faq__a a { color:var(--hover); text-decoration:underline; text-underline-offset:2px }

/* ---------- previous / next in series ----------
   Two equal cards under the body. An empty span holds the column when there is
   no prev (or no next) so the remaining card keeps its side rather than sliding
   across. */
.ed-single .series-nav { border-top:2px solid var(--ink-hard); margin-top:30px; padding-top:14px }
.ed-single .series-nav__head { display:flex; justify-content:space-between; align-items:baseline;
  gap:14px; margin-bottom:12px }
.ed-single .series-nav__label { font-family:var(--f-body); font-size:11px; font-weight:700;
  letter-spacing:.08em; text-transform:uppercase; color:var(--ink-hard) }
.ed-single .series-nav__all { font-family:var(--f-body); font-size:11px; letter-spacing:.05em;
  color:var(--text-faint); white-space:nowrap }
.ed-single .series-nav__all:hover { color:var(--ink-hard) }
.ed-single .series-nav__pair { display:grid; grid-template-columns:1fr 1fr; gap:14px }
.ed-single .series-nav__item { display:block; border:1px solid var(--border); padding:14px 16px;
  min-width:0 }
.ed-single .series-nav__item--empty { border:0; padding:0 }
.ed-single .series-nav__item:not(.series-nav__item--empty):hover { border-color:var(--ink-hard) }
.ed-single .series-nav__item--next { text-align:right }
.ed-single .series-nav__dir { display:block; font-family:var(--f-body); font-size:10px;
  letter-spacing:.07em; text-transform:uppercase; color:var(--mango-active); margin-bottom:6px }
.ed-single .series-nav__t { display:block; font-family:var(--f-display); font-weight:600;
  font-size:17px; line-height:1.22; color:var(--ink-hard) }

/* ---------- tags ---------- */
.ed-single .article-tags { display:flex; gap:9px; flex-wrap:wrap;
  border-top:1px solid var(--border); padding-top:18px; margin-top:26px }
.ed-single .article-tag { font-weight:500; font-size:12px; color:var(--ink-hard);
  border:1px solid var(--border-alt); border-radius:16px; padding:6px 13px }
.ed-single .article-tag:hover { border-color:var(--ink) }

/* ---------- end-of-article share block ---------- */
.ed-single .article-share { display:flex; align-items:center; gap:20px; flex-wrap:wrap;
  border-top:1px solid var(--border); border-bottom:1px solid var(--border);
  padding:18px 0; margin:30px 0 }
.ed-single .article-share__count { font-size:11px; letter-spacing:.05em; text-transform:uppercase;
  color:var(--text-2); line-height:1.1 }
.ed-single .article-share__count strong { display:block; font-family:var(--f-display);
  font-weight:700; font-size:26px; letter-spacing:0; text-transform:none;
  color:var(--ink-hard); margin-bottom:2px }
.ed-single .article-share__icons { display:flex; gap:9px; margin-left:auto; flex-wrap:wrap }
.ed-single .article-share__icons .dss-icon { width:40px; height:40px; border-radius:50%;
  border:1px solid var(--border-alt); display:flex; align-items:center; justify-content:center;
  color:var(--body); background:none; cursor:pointer; position:relative; flex:none }
.ed-single .article-share__icons .dss-icon svg { width:15px; height:15px }
.ed-single .article-share__icons .dss-icon:hover { border-color:var(--ink); color:var(--ink) }

/* ---- "Gift this article" (staff only, Pro posts) ----
   The plugin styles .gift-button as a bordered pill with a visible label, which
   is legacy's share row. Here the row sized the box to a 32px circle but the
   plugin's 14px padding and overflow:hidden stayed, so the label was clipped to
   its middle four letters and the control rendered as a circle reading "t this".
   It now takes the row's own circle with the gift glyph inside, filled in ink so
   the one control that DOES something is not read as a seventh share link. The
   plugin's purple hover and its recurring sheen are both off this palette.
   The row scope in each selector is load-bearing, not decoration: the row's own
   `.byline__share button` rules are (0,2,1), so a bare `.gift-button` would lose
   the fill and the hover colour back to them. */
.ed-single .byline__share .gift-button,
.ed-single .article-share__icons .gift-button {
  padding:0; gap:0; overflow:visible; margin-left:4px;
  background:var(--ink); border-color:var(--ink); color:var(--ivory-2);
  transition:background-color .16s ease, border-color .16s ease, color .16s ease }
.ed-single .byline__share .gift-button::after,
.ed-single .article-share__icons .gift-button::after { content:none }
.ed-single .byline__share .gift-button:hover,
.ed-single .article-share__icons .gift-button:hover {
  background:var(--mango); border-color:var(--mango); color:var(--on-mango) }

/* ---------- Telegram subscribe CTA ---------- */
.ed-single .telegram-cta { display:flex; align-items:center; gap:16px; text-decoration:none;
  border:1px solid var(--border-alt); background:var(--card); padding:16px 18px; margin:26px 0 }
.ed-single .telegram-cta:hover { border-color:var(--ink) }
.ed-single .telegram-cta__icon { flex:none; display:flex }
.ed-single .telegram-cta__icon svg { width:40px; height:40px; display:block }
.ed-single .telegram-cta__text { flex:1; min-width:0; font-size:14px; line-height:1.45;
  color:var(--body-strong) }
.ed-single .telegram-cta__text strong { color:var(--ink-hard); font-weight:700 }
.ed-single .telegram-cta__btn { flex:none; font-weight:600; font-size:12.5px; color:var(--ivory-2);
  background:var(--structure); padding:11px 16px; white-space:nowrap; transition:background .12s }
.ed-single .telegram-cta:hover .telegram-cta__btn { background:var(--ink-deep) }

/* ---------- author bio ---------- */
.ed-single .author-bio { display:flex; gap:16px; align-items:flex-start; background:var(--card);
  border:1px solid var(--border); padding:18px; margin-top:22px }
.ed-single /* The avatar is now a WRAPPER holding the image, so a scaled portrait is
   clipped by the circle instead of overflowing it — transforming the <img>
   while the <img> itself is the clip would crop the face, not enlarge it.
   See sh_bof_avatar(). */
.author-bio__avatar { width:56px; height:56px; border-radius:50%; flex:none;
  overflow:hidden; display:block; background:var(--panel) }
.author-bio__avatar img { width:100%; height:100%; object-fit:cover; display:block;
  transform-origin:center }
.ed-single .author-bio__name { font-weight:700; font-size:15px; color:var(--ink-hard) }
.ed-single .author-bio__namelink:hover { color:var(--accent-text) }
.ed-single .author-bio__role { font-family:var(--f-body); font-size:10px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--text-faint); margin:3px 0 8px }
.ed-single .author-bio__desc { font-size:13.5px; line-height:1.55; color:var(--body) }
.ed-single .author-bio__desc p { margin:0 0 9px }
.ed-single .author-bio__desc p:last-child { margin-bottom:0 }
.ed-single .author-bio__desc a { color:var(--hover); text-decoration:underline; text-underline-offset:2px }

/* ---------- RIGHT rail ---------- */
.ed-single .art-rail-r { padding:20px; min-width:0 }
.ed-single .art-rail-r__sticky { position:sticky; top:16px }

.ed-single .popular__head { font-family:var(--f-body); font-weight:700; font-size:10px;
  letter-spacing:.14em; text-transform:uppercase; color:var(--ink-hard);
  border-bottom:2px solid var(--ink-hard); padding-bottom:9px; margin-bottom:6px }
.ed-single .popular__item { display:flex; gap:12px; align-items:flex-start; padding:10px 0;
  border-bottom:1px solid var(--border) }
.ed-single .popular__n { font-family:var(--f-display); font-size:22px; line-height:1;
  color:var(--border-alt); width:22px; flex:none }
.ed-single .popular__t { flex:1; font-family:var(--f-display); font-weight:600; font-size:14px;
  line-height:1.25; color:var(--ink-hard) }
.ed-single .popular__item:hover .popular__t { text-decoration:underline }

.ed-single .workwith { background:var(--structure); color:var(--ivory-2); padding:20px;
  margin-top:22px }
.ed-single .workwith__eyebrow { font-family:var(--f-body); font-weight:700; font-size:10px;
  letter-spacing:.14em; text-transform:uppercase; color:var(--mango); margin-bottom:11px }
.ed-single .workwith__title { font-family:var(--f-display); font-size:21px; line-height:1.22;
  color:var(--ivory-2); margin-bottom:15px }
.ed-single .workwith__cta { display:block; background:var(--ivory-2); color:var(--structure);
  font-weight:600; font-size:12.5px; padding:11px; text-align:center }
.ed-single .workwith__cta:hover { background:var(--sand) }

.ed-single .digest { border:1px solid var(--structure); padding:18px; margin-top:16px }
.ed-single .digest__title { font-family:var(--f-display); font-weight:700; font-size:15px;
  line-height:1.25; color:var(--ink-hard); margin-bottom:9px }
.ed-single .digest__dek { font-size:12px; line-height:1.5; color:var(--body); margin-bottom:12px }
.ed-single .digest__form { display:flex; align-items:stretch }
/* Both given the SAME explicit height rather than relying on the flex stretch.
   At mobile widths the shared tap-target rules grow the input to 51px while the
   button sizes to its own 11px/9px content at 31px, and align-items:stretch did
   not close the gap (verified in the browser: the form and button both computed
   `stretch`, and the button still rendered 31px). So the button floated 20px
   short of the field it is butt-joined to. An explicit pair cannot drift. */
@media (max-width:780px) {
  .ed-single .digest input,
  .ed-single .digest button { height:48px; padding-top:0; padding-bottom:0 }
}
.ed-single .digest input { flex:1; min-width:0; border:1px solid var(--structure);
  border-right:none; background:var(--ivory-2); color:var(--ink); font-family:var(--f-body);
  font-size:12px; padding:9px 10px; outline:none }
.ed-single .digest input::placeholder { color:var(--text-faint) }
.ed-single .digest button { background:var(--structure); color:var(--ivory-2);
  border:1px solid var(--structure); font-family:var(--f-body); font-weight:600; font-size:11px;
  padding:9px 12px; cursor:pointer }
.ed-single .digest button:hover { background:var(--ink-deep) }

/* ---------- More from Stacked ----------
   Headerless by design (Adam dropped the heading + its 4px section rule): the
   "More from {Parent}/{Subcategory}" columns below cover recirculation. The card
   grid keeps its own 1px top hairline separating it from above. */
.ed-single .more-stacked__grid { display:grid; grid-template-columns:repeat(4, minmax(0,1fr));
  border-top:1px solid var(--border) }
/* The cards are .ed-card now (base.css owns image, kicker, headline, dek and
   byline). Only the GRID is this file's business: the cell padding and the
   hairlines that divide the four columns. Anything that restyled the card parts
   here has been deleted rather than kept in step with base.css by hand. */
.ed-single .more-stacked__grid > .ed-card { padding:16px 20px;
  border-right:1px solid var(--border); min-width:0; color:inherit }
.ed-single .more-stacked__grid > .ed-card:last-child { border-right:0 }
.ed-single .more-stacked__grid > .ed-card:hover .ed-card__title { text-decoration:underline }
/* base.css puts the label's air above it, which double-counts against the cell
   padding on a card whose image is its first child. */
.ed-single .more-stacked__grid > .ed-card > .ed-img { margin-bottom:0 }

/* ---------- More from {Parent} | {Subcategory} ----------
   Two numbered lists side by side. Column-major grid: col 1 = head + 5 items,
   col 2 = head + 5 items. grid-template-rows sizes each of the 6 rows to the
   taller of its two cells, so the hairlines stay in sync across columns
   regardless of 1- vs 2-line titles. */
.ed-single .more-cols { border-top:4px solid var(--structure); display:grid;
  grid-template-columns:1fr 1fr; grid-auto-flow:column; grid-template-rows:repeat(6, auto) }
.ed-single .more-cols--one { grid-template-columns:1fr; grid-auto-flow:row; grid-template-rows:none }
.ed-single .more-cols > :nth-child(-n+6) { border-right:1px solid var(--border) }  /* col 1 → centre divider */
.ed-single .more-cols--one > * { border-right:0 }
.ed-single .more-cols__head { font-family:var(--f-display); font-weight:700; font-size:24px;
  line-height:1; color:var(--ink-hard); padding:16px 20px 12px; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; min-width:0 }
.ed-single .more-cols__item { display:flex; gap:16px; align-items:flex-start; padding:13px 20px;
  min-width:0; border-top:1px solid var(--border) }
.ed-single .more-cols__head + .more-cols__item { border-top:0 }   /* no rule between a head and its first item */
.ed-single .more-cols__item--pad { padding:0 }                    /* empty spacer keeps col 2 aligned */
.ed-single .more-cols__item:hover .more-cols__t { text-decoration:underline }
.ed-single .more-cols__n { font-family:var(--f-display); font-weight:400; font-size:30px;
  line-height:1.16; color:var(--border-alt); width:30px; flex:none }
.ed-single .more-cols__t { font-family:var(--f-display); font-weight:600; font-size:16px;
  line-height:1.22; color:var(--ink-hard) }

/* ---------- comments ----------
   The editorial-light-comments plugin supplies the .elc markup and a heavier
   default stylesheet; these `.article-comments …` rules out-specify it
   (0-3-0 with the body scope > the plugin's single-class 0-1-0), so the section
   reads like the rest of the article: Whyte body, display headings, token
   colours, tighter rhythm. */
.ed-single .article-comments { margin-top:34px; max-width:680px }
.ed-single .article-comments .elc { margin-top:0; padding-top:0; border:0 }
.ed-single .article-comments #comments.elc.elc-wrap { padding-left:0 !important }  /* drop the plugin's 2.5rem inset */

/* No rule above the heading. The article already closes with the share row and
   the recirculation blocks, each with its own hairline, so a fourth one here
   just added another band to a stack of them. */
.ed-single .article-comments .elc-title { font-family:var(--f-display); font-weight:700;
  font-size:22px; line-height:1.2; letter-spacing:-.2px; color:var(--ink); margin:0 0 4px;
  padding-top:0; border-top:0 }
.ed-single .article-comments .elc-form-title { font-family:var(--f-display); font-weight:700;
  font-size:17px; line-height:1.2; color:var(--ink); margin:0 0 14px }

.ed-single .article-comments .elc-list { list-style:none; margin:18px 0 0; padding:0 }
.ed-single .article-comments .elc-item { padding:16px 0; border-top:1px solid var(--border) }
.ed-single .article-comments .elc-list > .elc-item:first-child { border-top:0 }
.ed-single .article-comments .elc-head { display:flex; align-items:baseline; gap:10px;
  margin-bottom:5px }
.ed-single .article-comments .elc-author { font-family:var(--f-body); font-weight:700;
  font-size:14px; color:var(--ink) }
.ed-single .article-comments .elc-time { font-family:var(--f-body); font-size:11px;
  letter-spacing:.04em; text-transform:uppercase; color:var(--text-faint) }
.ed-single .article-comments .elc-body { font-family:var(--f-body); font-size:15px;
  line-height:1.6; color:var(--body) }
.ed-single .article-comments .elc-body p { margin:.5em 0 }
.ed-single .article-comments .elc-body p:first-child { margin-top:0 }
.ed-single .article-comments .elc-foot { margin-top:8px }
.ed-single .article-comments .elc-foot a { font-family:var(--f-body); font-size:11px;
  letter-spacing:.04em; text-transform:uppercase; color:var(--accent-text) }
.ed-single .article-comments .elc-foot a:hover { color:var(--ink) }
.ed-single .article-comments .elc-list .children { margin-top:14px; padding-left:20px;
  border-left:1px solid var(--border) }
.ed-single .article-comments .elc-moderation { font-family:var(--f-body); font-size:11px;
  letter-spacing:.04em; text-transform:uppercase; color:var(--text-faint) }

.ed-single .article-comments #respond { margin-top:24px; padding-top:22px;
  border-top:1px solid var(--border) }
.ed-single .article-comments .cancel-comment-reply-link { font-family:var(--f-body);
  font-size:11px; letter-spacing:.04em; text-transform:uppercase; color:var(--text-faint);
  margin-left:10px }
.ed-single .article-comments .cancel-comment-reply-link:hover { color:var(--ink) }
.ed-single .article-comments .elc-field { margin:0 0 13px }
.ed-single .article-comments .elc-field label { display:block; font-family:var(--f-body);
  font-weight:700; font-size:11px; letter-spacing:.07em; text-transform:uppercase;
  color:var(--text-faint); margin:0 0 6px }
.ed-single .article-comments .elc-field input,
.ed-single .article-comments .elc-field textarea { width:100%; box-sizing:border-box;
  display:block; font-family:var(--f-body); font-size:14px; line-height:1.5; color:var(--ink);
  background:var(--card); border:1px solid var(--border-alt); border-radius:0; padding:10px 12px }
.ed-single .article-comments .elc-field textarea { min-height:120px; resize:vertical }
.ed-single .article-comments .elc-field input:focus,
.ed-single .article-comments .elc-field textarea:focus { outline:none; border-color:var(--ink) }
.ed-single .article-comments .elc-field input::placeholder,
.ed-single .article-comments .elc-field textarea::placeholder { color:var(--text-faint) }

/* Submit — compact ink button, matching the structural chrome. */
.ed-single .article-comments .elc-form input[type="submit"],
.ed-single .article-comments .form-submit input[type="submit"] { display:inline-block; width:auto;
  cursor:pointer; font-family:var(--f-body); font-weight:700; font-size:12px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--sand); background:var(--ink); border:0; border-radius:0;
  padding:11px 20px; transition:opacity .15s }
.ed-single .article-comments .elc-form input[type="submit"]:hover,
.ed-single .article-comments .form-submit input[type="submit"]:hover { opacity:.88 }

/* Touch devices: enlarge the article's own tap targets to ~44px (byline share
   circles + tag pills). Shared-chrome targets (util bar, nav, drawer, footer)
   are handled in chrome.css. */
@media (pointer:coarse) {
  .ed-single .byline__share a,
  .ed-single .byline__share button { width:42px; height:42px }
  .ed-single .article-tag { padding:9px 15px }
}

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

@media (max-width:1080px) {
  /* Drop the left "Read next" rail; keep the article + right rail. */
  .ed-single .article-grid { grid-template-columns:minmax(0,1fr) 310px }
  .ed-single .art-rail-l { display:none }
  .ed-single .article-main { padding:24px 32px 36px }
}

@media (max-width:860px) {
  .ed-single .article-grid { grid-template-columns:minmax(0,1fr) }
  .ed-single .article-main { border-right:0; padding:22px 0 30px; max-width:none }
  .ed-single .art-rail-r { border-top:1px solid var(--border); padding:24px 0 30px }
  .ed-single .art-rail-r__sticky { position:static }
  .ed-single .more-stacked__grid { grid-template-columns:repeat(2, minmax(0,1fr)) }
  .ed-single .more-stacked__grid > .ed-card:nth-child(2) { border-right:0 }
  .ed-single .more-stacked__grid > .ed-card:nth-child(1),
  .ed-single .more-stacked__grid > .ed-card:nth-child(2) { border-bottom:1px solid var(--border) }
  .ed-single .more-cols { display:block }                       /* stack the two columns */
  .ed-single .more-cols > :nth-child(-n+6) { border-right:0 }
  .ed-single .more-cols__item--pad { display:none }
  .ed-single .more-cols__head { border-top:1px solid var(--border); padding-top:20px }
  .ed-single .more-cols > .more-cols__head:first-child { border-top:0; padding-top:16px }
  /* The rails' 20px inset is redundant once they are full width inside
     .ed-wrap's gutter, and doubling the two reads as a wide, uneven margin. */
  .ed-single .more-stacked__grid > .ed-card { padding-inline:16px }
  .ed-single .more-cols__head,
  .ed-single .more-cols__item { padding-inline:0 }
}

@media (max-width:560px) {
  .ed-single .article-title { font-size:30px }
  .ed-single .article-standfirst { font-size:16px }
  /* Stack the pair; drop the empty placeholder so it leaves no gap, and let the
     "next" card read left-aligned like everything else once it is full width. */
  .ed-single .series-nav__pair { grid-template-columns:1fr }
  .ed-single .series-nav__item--empty { display:none }
  .ed-single .series-nav__item--next { text-align:left }
  .ed-single .byline { flex-wrap:wrap }
  .ed-single .byline__share { width:100%; margin-top:2px; justify-content:flex-start }
  .ed-single .gps-banner,
  .ed-single .telegram-cta { flex-wrap:wrap }
  .ed-single .gps-banner__cta,
  .ed-single .telegram-cta__btn { width:100%; text-align:center; margin-top:2px }
  /* Icons beside the count, not beneath it. Stacking them cost ~50px of height
     at the foot of every article for no gain; the row fits once the circles come
     down to 34px (6 x 34 + 5 x 7 = 239px, inside a 375px screen's 339px of
     column). align-items:center on .article-share does the vertical centring. */
  .ed-single .article-share__icons { margin-left:auto; width:auto; gap:7px; flex-wrap:nowrap }
  .ed-single .article-share__icons .dss-icon { width:34px; height:34px }
  .ed-single .article-share__icons .dss-icon svg { width:13px; height:13px }
  .ed-single .article-share { gap:12px; flex-wrap:nowrap }
  .ed-single .faq { padding-left:18px; padding-right:18px }
  .ed-single .faq__q { font-size:16px }
  .ed-single .more-stacked__grid { grid-template-columns:1fr }
  .ed-single .more-stacked__grid > .ed-card { border-right:0; border-bottom:1px solid var(--border) }

  /* --- Long-form on a phone: slightly smaller type, MORE line-height. --- */
  .ed-single .article-body { font-size:17px; line-height:1.75 }
  .ed-single .article-body > p { margin-bottom:22px }
  .ed-single .article-body blockquote { font-size:22px; padding-left:16px; border-left-width:3px }

  /* --- FULL-BLEED, the one pattern this file must not get wrong ---
     Images run edge to edge while text stays in the gutter. Done with a negative
     inline margin rather than the usual 100vw/50% trick: 100vw COUNTS THE
     SCROLLBAR, so on any device that shows one the element is wider than the
     page and the whole document scrolls sideways. A negative gutter margin
     cannot overshoot, because it is defined in terms of the same padding it is
     cancelling. `width:calc(100% + …)` and never `width:auto` — auto collapses a
     not-yet-decoded <img> to 0px. */
  .ed-single .article-hero {
    margin-inline:calc(var(--gutter) * -1);
    width:calc(100% + var(--gutter) * 2);
    max-width:none;
  }
  /* The image goes full-bleed; its caption is metadata and stays in the gutter
     with the body text it describes. */
  .ed-single .article-hero .article-figcaption { padding-inline:var(--gutter) }

  /* nowrap keeps a data row readable instead of wrapping every cell to three
     lines; the container around it scrolls, so the width it forces is contained.
     The scroll container must therefore ALSO be full-bleed, or the reader loses
     a gutter's worth of table before they can swipe.
     max-width:none is load-bearing: the defensive `figure { max-width:100% }`
     cap above otherwise pins the container to the text column, so the negative
     margin slides it off the left edge without ever reaching the right one. */
  .ed-single .article-body th,
  .ed-single .article-body td { padding:9px 12px }
  .ed-single .article-body .wp-block-table,
  .ed-single .article-body .table-scroll,
  .ed-single .article-body > table {
    margin-inline:calc(var(--gutter) * -1);
    width:calc(100% + var(--gutter) * 2);
    max-width:none;
    padding-inline:var(--gutter);
    /* Padding inside a scroll container is only honoured on the leading edge in
       some engines; scroll-padding keeps the last column off the screen edge
       when the reader swipes to the end. */
    scroll-padding-right:var(--gutter);
  }

  /* Body figures go full-bleed too, matching the hero. Scoped to figures that
     are NOT a table (handled above with their own scroll behaviour) and not an
     embed, whose aspect box is already sized to the column. */
  .ed-single .article-body > figure.wp-block-image,
  .ed-single .article-body > figure.wp-block-gallery,
  .ed-single .article-body > .wp-block-image {
    margin-inline:calc(var(--gutter) * -1);
    width:calc(100% + var(--gutter) * 2);
    max-width:none;
  }
  .ed-single .article-body > figure.wp-block-image > figcaption,
  .ed-single .article-body > figure.wp-block-gallery > figcaption,
  .ed-single .article-body > .wp-block-image > figcaption { padding-inline:var(--gutter) }

  /* The gate is the page's conversion point, so its button takes the full-width
     CTA treatment rather than sitting as a small inline block. */
  .ed-single .ed-gate { padding:22px var(--gutter) 24px;
    margin-inline:calc(var(--gutter) * -1); width:calc(100% + var(--gutter) * 2); max-width:none }
  .ed-single .ed-gate__actions { display:block; margin-top:20px }
  .ed-single .ed-gate .ed-cta { display:block; width:100%; text-align:center;
    padding:16px 20px }                      /* ≥44px tap target */
  .ed-single .ed-gate__signin { display:block; text-align:center; margin-top:16px; padding:10px 0 }
}

/* The article title is still tall at 320px, where the gutter has eaten a third
   of the line. */
@media (max-width:360px) {
  .ed-single .article-title { font-size:25px }
  .ed-single .article-body { font-size:16.5px }
}

/* Intelligence: every featured image renders 16:9, including the read-next
   thumbnails, which are 4:3 by default and crop a 16:9 source hard. Scoped to
   the section rather than changed globally, because News/Reviews art is not
   produced to a single ratio and 4:3 suits it. `data-section` is set on <html>
   by templates/bof/single.php, so these match on the <html> element and the
   .ed-single scope comes from the body class beneath it. */
[data-section="intelligence"] .ed-single .read-next__img,
[data-section="intelligence"] .ed-single .rn-inline__img,
[data-section="intelligence"] .ed-single .article-body .rn-inline__img { aspect-ratio:16/9 }

/* ---------- "More from Stacked" (read-next-block plugin) -------------------
   The plugin injects its own markup into the body at the 50% word mark, using
   .read-next-block and friends — NOT the .read-next__* classes this track uses
   for the rail card. Unstyled, it landed mid-article as a bare heading, an
   unstyled paragraph and a naked "Read More" link.

   Styled here rather than changed in the plugin: the plugin serves the legacy
   theme and both other tracks, and its markup is what they already style. */

.ed-single .read-next-block {
  margin:34px 0;
  padding:22px 24px;
  background:var(--panel);
  border-left:3px solid var(--accent, #B0381C);
}
.ed-single .read-next-block .more-from {
  margin:0;
  font:700 9.5px/1 var(--f-body);
  letter-spacing:.14em; text-transform:uppercase;
  color:var(--text-2);
}
/* Overrides the article body's h2 scale — this is a card heading inside the
   prose, not a section break in it. */
.ed-single .read-next-block h2 {
  margin:10px 0 0;
  font:400 22px/1.25 var(--f-display), Georgia, serif;
  border:0; padding:0;
}
/* No underline on the card's own links.

   .article-body a is underlined on purpose — in prose that is what marks a link.
   This card is a UI object that happens to sit inside the body, so it inherited
   a rule meant for sentences: the headline came out underlined across two lines
   and the button had a line through its label. Overridden here, and only here.

   The headline still gets an underline on hover, so it is clearly a link. */
.ed-single .article-body .read-next-block a { text-decoration:none }
.ed-single .read-next-block h2 a { color:var(--ink-hard, var(--ink)) }
.ed-single .article-body .read-next-block h2 a:hover {
  color:var(--accent-text);
  text-decoration:underline;
  text-underline-offset:3px;
}
.ed-single .read-next-block > p {
  margin:8px 0 0;
  font:400 15px/1.55 var(--f-body);
  color:var(--body);
}
.ed-single .read-next-block .read-next-footer {
  display:flex; align-items:center; justify-content:space-between;
  gap:16px; flex-wrap:wrap;
  margin-top:16px;
}
.ed-single .read-next-block .read-more-button {
  display:inline-block;
  padding:10px 18px;
  font:700 10px/1 var(--f-body);
  letter-spacing:.14em; text-transform:uppercase;
  color:var(--ink);
  border:1px solid var(--structure);
}
.ed-single .read-next-block .read-more-button:hover { background:var(--structure); color:var(--sand) }
.ed-single .read-next-block .share-count,
.ed-single .read-next-block .meta {
  font:400 12px/1.5 var(--f-body);
  color:var(--text-2);
}
.ed-single .read-next-block .meta { margin-top:12px }

@media (max-width:700px) {
  .ed-single .read-next-block { padding:18px 18px; margin:26px 0 }
  .ed-single .read-next-block h2 { font-size:19px }
}
