/* ═══════════════════════════════════════════════════════════
   Theseus — Reader Stylesheet
   Immersive article reading experience
   ═══════════════════════════════════════════════════════════ */

/* ── Reader Shell ──────────────────────────────────────── */
.reader {
	min-height: 100vh;
	background: var(--bg-page);
	/* Desktop bottom breathing room so the end-of-content / "Saved with
	   Theseus" footer isn't slammed against the viewport bottom. The mobile
	   block below overrides this with the larger bottom-nav clearance. */
	padding-bottom: var(--space-12);
}

/* Clear the fixed mobile bottom nav (56px tall) plus the safe-area inset
   so the last paragraph / related-cards section stays fully visible.
   Matches the .content clearance in layout.css's mobile block.
   See docs/design-specs/reader-mobile-nav.md §4.2. */
@media (max-width: 767px) {
	.reader {
		padding-bottom: calc(var(--space-16) + env(safe-area-inset-bottom, 0px));
	}
}

.reader-header {
	position: sticky;
	top: 0;
	z-index: 10;
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	/* Tighter vertical padding (space-2, was space-3) so the header is a slim
	   control strip, not a thick band — it wasted vertical space and, in WCO,
	   double-stacked under the titlebar strip (fb-ux-reader-header-too-tall-wco).
	   The ghost-button box below is also slimmed to match. The TOC-scroll offset
	   + header popovers measure the header's RENDERED bottom live, so a shorter
	   header re-anchors them automatically (no JS change needed). */
	padding: var(--space-2) var(--space-6);
	background: var(--bg-page);
	border-bottom: 1px solid var(--border-subtle);
	transition: opacity var(--duration-normal) ease;
}

.reader-header-left {
	display: flex;
	align-items: center;
	gap: var(--space-3);
}

.reader-header-actions {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	justify-content: flex-end;
}

.reader-header-center {
	display: flex;
	align-items: center;
	justify-content: center;
}

.reader-header-logo {
	color: var(--text-secondary);
	transition: color var(--duration-fast);
}
.reader-header-logo:hover {
	color: var(--text-primary);
}

.reader-header .btn-ghost {
	border: none;
	background: none;
	/* Slimmer vertical box (space-1 block / space-2 inline) so the control row
	   doesn't force the header tall (fb-ux-reader-header-too-tall-wco). The mobile
	   block below restores a 44×44 hit target for touch (WCAG 2.5.5). */
	padding: var(--space-1) var(--space-2);
	border-radius: var(--radius-sm);
	font-size: var(--text-base);
}
.reader-header .btn-ghost:hover {
	background: var(--bg-inset);
}

/* Mobile: ensure 44×44 touch target on icon-only header buttons (WCAG 2.5.5) */
@media (max-width: 767px) {
	.reader-header .btn-ghost {
		min-width: 44px;
		min-height: 44px;
		display: inline-flex;
		align-items: center;
		justify-content: center;
	}
}

.reader-back {
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-secondary);
	display: flex;
	align-items: center;
	gap: var(--space-2);
	max-width: 200px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.reader-back:hover {
	color: var(--text-primary);
}

/* ── Article Meta ──────────────────────────────────────── */
/* Card → reader morph target. Purely structural — no visual styles.
 * Wraps the hero band (title + meta + lede image / video / social author)
 * so the View Transition Level 1 snapshot has a bounded bounding box.
 * The article body, summary, related, tags, and controls fade in via the
 * `root` group instead of being captured into the card-{id} snapshot.
 * See docs/design-specs/view-transitions-card-morph-target.md. */
.reader-hero {
	display: block;
	/* Breathing room above the title between the sticky reader header's divider
	   and the first content. The reader now renders inside AppLayout (Sprint 74:
	   reader.tsx -> AppLayout), so its sticky header sits directly under the app
	   shell chrome; without this inset the title reads as crammed against the
	   divider (fb-bug-reader-in-shell-followups). Lives on the hero wrapper —
	   the single first-content block shared by every layout (article / video /
	   list / social) — so the clearance is uniform and has one source of truth;
	   the inner blocks below no longer carry their own top inset. */
	padding-top: var(--space-10);
}

.reader-meta {
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin: 0 auto;
	/* Top inset moved up to .reader-hero (single source of truth) so all reader
	   variants share one clearance value above the title. */
	padding: 0 var(--space-6) var(--space-6);
	text-align: center;
}

.reader-meta h1 {
	/* One step down the major-third scale from the original --text-3xl
	   (fb-ux 99e1c9ad — trim the reader type ramp). Serves BOTH readers:
	   the authed reader AND the public /s/:code shared reader pull this
	   stylesheet. Hierarchy holds: in-content headings top out at
	   --text-xl (.reader-content h1/h2 below), one step under the title. */
	font-size: var(--text-2xl);
	line-height: 1.15;
	margin-bottom: var(--space-4);
}

.reader-meta .byline {
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-secondary);
	margin-bottom: var(--space-1);
}

.reader-meta .reading-info {
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-muted);
}

.reader-source-link {
	color: var(--accent);
	text-decoration: none;
	/* favicon + domain inline (fb-ux-card-favicon-everywhere §a — reader URL
	   line). inline-flex keeps the favicon aligned with the domain inside the
	   flex `.reader-meta-row`. */
	display: inline-flex;
	align-items: center;
	gap: var(--space-1);
}
.reader-source-link:hover {
	text-decoration: underline;
}
.reader-source-favicon {
	width: 14px;
	height: 14px;
	border-radius: 2px;
	object-fit: cover;
	flex-shrink: 0;
}

.reader .divider {
	width: 64px;
	height: 2px;
	background: var(--accent);
	margin: var(--space-6) auto;
	opacity: 0.6;
}

/* ── Article Content ───────────────────────────────────── */
.reader-content {
	font-family: var(--font-reading);
	font-size: var(--reader-font-size, var(--text-md));
	line-height: var(--reader-line-height, 1.7);
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin: 0 auto;
	/* Bottom padding kept minimal: the .reader-tags margin-top (--space-6)
	   already supplies the gap to the tag row, so a large content pad here
	   only stacked dead space above the tags (fb-ux 98cfc87c). */
	padding: 0 var(--space-6) var(--space-4);
	color: var(--text-primary);
	overflow-x: hidden;
}

.reader-content h1 {
	/* --text-xl, not 2xl: the page title (.reader-meta h1) moved down to
	   --text-2xl (fb-ux 99e1c9ad) and MUST stay above every in-content
	   heading — a 2xl content h1 would tie it. In-content h1s are rare
	   (Readability usually strips the lede h1); the larger top margin
	   still distinguishes them from h2s at the same size. */
	font-size: var(--text-xl);
	margin: var(--space-10) 0 var(--space-4);
}
.reader-content h2 {
	font-size: var(--text-xl);
	margin: var(--space-8) 0 var(--space-3);
}
.reader-content h3 {
	font-size: var(--text-lg);
	margin: var(--space-6) 0 var(--space-3);
}
.reader-content p {
	margin: 0 0 var(--space-4);
}

.reader-content blockquote {
	border-left: 3px solid var(--accent);
	padding-left: var(--space-5);
	margin: var(--space-6) 0;
	color: var(--text-secondary);
	font-style: italic;
}

.reader-content blockquote.pullquote {
	border-left: none;
	border-top: 2px solid var(--accent);
	border-bottom: 2px solid var(--accent);
	padding: var(--space-5) 0;
	text-align: center;
	font-size: 1.15em;
	color: var(--text-primary);
}

/* Set-apart publisher infobox / aside (funder disclosure, fact box, "about this
   project" embed). Re-tagged from the source container by the extractor so it no
   longer reads as the lede paragraph. Boxed + inset, distinct from a blockquote. */
.reader-content aside.reader-aside {
	display: block;
	background: var(--bg-inset);
	border: 1px solid var(--border);
	border-radius: var(--radius-md);
	padding: var(--space-4) var(--space-5);
	margin: var(--space-6) 0;
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-secondary);
}
.reader-content aside.reader-aside > :first-child {
	margin-top: 0;
}
.reader-content aside.reader-aside > :last-child {
	margin-bottom: 0;
}

.reader-content img,
.reader-content iframe {
	max-width: 100%;
	height: auto;
	border-radius: var(--radius-sm);
	margin: var(--space-6) 0;
}
/* <picture> wrappers in reader body: carry the vertical margin */
.reader-content picture {
	margin: var(--space-6) 0;
}
.reader-content picture > img {
	margin: 0;
}

.reader-content a {
	color: var(--link-color);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
}

.reader-content code {
	font-family: var(--font-mono);
	font-size: 0.9em;
	background: var(--bg-inset);
	padding: 1px var(--space-1);
	border-radius: var(--radius-sm);
}

.reader-content pre {
	background: var(--bg-inset);
	padding: var(--space-4);
	border-radius: var(--radius-md);
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	max-width: 100%;
	font-size: var(--text-sm);
	line-height: 1.5;
	margin: var(--space-6) 0;
}
.reader-content pre code {
	background: none;
	padding: 0;
}

.reader-content ul,
.reader-content ol {
	padding-left: var(--space-6);
	margin: 0 0 var(--space-4);
}
.reader-content li {
	margin-bottom: var(--space-2);
	list-style: disc;
}
.reader-content ol li {
	list-style: decimal;
}

.reader-content figure {
	margin: var(--space-6) 0;
}
.reader-content figcaption {
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-muted);
	text-align: center;
	/* Symmetric, on-grid spacing: the image→caption gap (margin-top) is mirrored
	   by an explicit caption→figure-edge gap (padding-bottom) so the space below
	   a captioned image no longer depends on the next element's margin — which
	   made it inconsistently tight (fb-bug-reader-srcset-variants-injected). */
	margin-top: var(--space-2);
	padding-bottom: var(--space-2);
}

.reader-content hr {
	border: none;
	border-top: 1px solid var(--border);
	margin: var(--space-8) 0;
}

.reader-content table {
	display: block;
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	max-width: 100%;
	border-top: 1px solid var(--border);
	border-left: 1px solid var(--border);
	margin: var(--space-6) 0;
	font-size: var(--text-sm);
}
.reader-content th,
.reader-content td {
	padding: var(--space-2) var(--space-3);
	border-right: 1px solid var(--border);
	border-bottom: 1px solid var(--border);
	text-align: left;
}
.reader-content th {
	font-weight: 600;
	background: var(--bg-inset);
}

/* ── Reading Progress ──────────────────────────────────────
   The reading-progress indicator IS the reader-header's bottom border,
   recoloured along its length as you read — not a separate, thicker bar.
   It's an absolute child of the position:sticky .reader-header, pinned over the
   header's 1px border-bottom, so it tracks the header in every display mode
   (including WCO, where the header is inset below the titlebar strip) and stays
   put as the header sticks. The header's own border-bottom (--border-subtle)
   shows through as the unfilled track; the accent fill colours the read portion.
   Hidden for video/social/list readers via the modifier rules below.
   (Markup lives inside <header class="reader-header"> — reader.tsx + shared.tsx.) */
.reader-progress {
	position: absolute;
	/* Span the header's full border-box width to match its full-width
	   border-bottom. The containing block of an absolutely-positioned child is the
	   header's PADDING box, whose horizontal edges already coincide with the border
	   box (the header has no left/right border) — so left:0/right:0 already reaches
	   the full width. Negating the horizontal padding (the old `calc(-1 * space-6)`)
	   OVERSHOT by space-6 on each side: on a full-width mobile reader header (no
	   sidebar margin) that pushed the bar past the viewport edge → 24px of phantom
	   horizontal scroll on every article. (fb-bug-reader-mobile-hscroll.) */
	left: 0;
	right: 0;
	/* Overlay the header's 1px border-bottom exactly: bottom:0 is the padding-box
	   edge (where the border paints inward from), so -1px drops onto the border. */
	bottom: -1px;
	height: 1px;
}
.reader-progress-bar {
	height: 100%;
	background: var(--accent);
	transition: width var(--duration-instant) linear;
}

/* ── Reader Controls Panel ─────────────────────────────── */
.reader-controls {
	position: fixed;
	top: 64px;
	right: var(--space-4);
	background: var(--bg-elevated);
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	padding: var(--space-4);
	box-shadow: 0 4px 16px var(--shadow-color);
	z-index: 20;
	min-width: 200px;
	display: none;
}
.reader-controls.open {
	display: block;
}

/* ── Table of Contents Popover ─────────────────────────── */
/* Trigger ships `hidden`; reader-init / shared-reader-init reveal it only when
   the body has ≥2 headings (fb-feature-reader-toc-menu). */
.reader-toc-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
}
/* `position`/`top`/`left` are set inline by attachLightDismiss (anchorToTrigger)
   so the panel opens below its button and flips up / clamps into the viewport,
   matching the other reader header menus. The stylesheet only owns the box. */
.reader-toc {
	position: fixed;
	/* Standard menu layer (matches the other reader header popovers). The panel no
	   longer needs to outrank the z-index:100 sidebar because it opens to the RIGHT of
	   its left-edge button (alignToTriggerLeft) and stays in the content column, clear
	   of the sidebar. It is also a child of `.reader`, not the sticky z-index:10
	   `.reader-header` (a stacking context that previously trapped it). */
	z-index: 20;
	min-width: 220px;
	max-width: min(92vw, 360px);
	max-height: min(70vh, 520px);
	overflow-y: auto;
	padding: var(--space-2) 0;
	background: var(--bg-elevated);
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	box-shadow: 0 4px 16px var(--shadow-color);
	display: none;
}
.reader-toc.open {
	display: block;
}
.reader-toc-list {
	list-style: none;
	margin: 0;
	padding: 0;
}
.reader-toc-item {
	margin: 0;
}
.reader-toc-link {
	display: block;
	padding: var(--space-2) var(--space-4);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	line-height: 1.4;
	color: var(--text-secondary);
	text-decoration: none;
	border-left: 2px solid transparent;
	transition:
		background var(--duration-fast) ease,
		color var(--duration-fast) ease;
}
.reader-toc-link:hover {
	background: var(--bg-inset);
	color: var(--text-primary);
}
.reader-toc-link:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: -2px;
}
/* Indent by heading depth (0–3), set as data-level by the JS that builds the
   list (normalised so the article's top heading level sits flush). */
.reader-toc-link[data-level="1"] {
	padding-left: var(--space-6);
}
.reader-toc-link[data-level="2"] {
	padding-left: var(--space-8);
}
.reader-toc-link[data-level="3"] {
	padding-left: var(--space-10);
}

.reader-controls-section {
	margin-bottom: var(--space-4);
}
.reader-controls-section:last-child {
	margin-bottom: 0;
}

.reader-controls-label {
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--text-muted);
	margin-bottom: var(--space-2);
}

.reader-controls-row {
	display: flex;
	gap: var(--space-1);
}

.reader-controls-btn {
	flex: 1;
	padding: var(--space-2);
	text-align: center;
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-primary);
	background: var(--bg-inset);
	border: 1px solid transparent;
	border-radius: var(--radius-sm);
	cursor: pointer;
}
.reader-controls-btn.active {
	border-color: var(--accent);
	color: var(--accent);
}

/* Mobile: ensure 44×44 touch target (WCAG 2.5.5) */
@media (max-width: 767px) {
	.reader-controls-btn {
		display: flex;
		align-items: center;
		justify-content: center;
		min-height: 44px;
	}
}

/* ── Font Size Variants ────────────────────────────────── */
/* Reader-specific type scale presets — these intentionally deviate from the
   global major-third scale; they're tuned to long-form reading comfort.
   See docs/05-design-system.md §8.5. */
[data-font-size="small"] {
	--reader-font-size: 0.9375rem;
}
[data-font-size="medium"] {
	--reader-font-size: 1.125rem;
}
[data-font-size="large"] {
	--reader-font-size: 1.3125rem;
}
[data-font-size="xlarge"] {
	--reader-font-size: 1.5rem;
}

/* ── Column Width Variants ─────────────────────────────── */
[data-column-width="narrow"] {
	--reader-column-width: 32rem;
}
[data-column-width="medium"] {
	--reader-column-width: 38rem;
}
[data-column-width="wide"] {
	--reader-column-width: 48rem;
}

/* ── Line Height Variants ──────────────────────────────── */
[data-line-height="compact"] {
	--reader-line-height: 1.5;
}
[data-line-height="normal"] {
	--reader-line-height: 1.7;
}
[data-line-height="relaxed"] {
	--reader-line-height: 1.9;
}

/* ── Article Meta Row ──────────────────────────────────── */
.reader-meta-row {
	color: var(--text-muted);
	font-size: var(--text-sm);
	font-family: var(--font-ui);
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	align-items: center;
	margin-top: var(--space-2);
}

.reader-meta-sep::before {
	/* Escaped rather than a literal `·` so the glyph survives any decoder that
	   doesn't resolve this sheet as UTF-8 (a literal renders as `Â·` when the
	   sheet is read as windows-1252). */
	content: "\00b7";
}

/* ── OG / Lede Image ──────────────────────────────────── */
.reader-og-image {
	display: block;
	width: 100%;
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin: var(--space-6) auto;
	border-radius: var(--radius-lg);
}
/* <picture> wrapper for OG image: carry centering + constraint */
picture:has(> .reader-og-image) {
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin: var(--space-6) auto;
}
picture > .reader-og-image {
	margin: 0;
}

/* ── Hero Caption ─────────────────────────────────────── */
.reader-hero-caption {
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	color: var(--text-muted);
	text-align: center;
	padding: var(--space-2) var(--space-4);
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin-inline: auto;
	/* Gap below the caption before the next block (.reader-summary, or the body
	   when there's no summary). The hero image carries a --space-6 BOTTOM margin
	   (picture:has(> .reader-og-image)), but a caption renders INSIDE that gap —
	   so without this the caption crowds the summary. Putting the 24px on the
	   caption itself keeps the spacing self-contained: a hero with NO caption
	   omits this element entirely, so it keeps the image's single --space-6 gap
	   with no double-tall space (fb-ux-hero-caption-padding-against-summary).
	   Applies to both the authenticated and the shared /s/:code reader, which
	   share this class + reader.css. */
	margin-bottom: var(--space-6);
}

/* ── AI Summary ───────────────────────────────────────────
   A collapsible disclosure (native <details>), collapsed by
   default so the article body stays front-and-center and the
   summary is opt-in. Works with no JS — the toggle is free.
   When the card is still enriching, reader-init.ts injects the
   same <details> structure once aiSummary arrives. */
.reader-summary {
	background: var(--bg-inset);
	border-radius: var(--radius-md);
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin: 0 auto var(--space-6);
}

/* The clickable affordance row. Drop the UA disclosure triangle and
   draw our own chevron so it sits flush with the label across browsers. */
.reader-summary-toggle {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	padding: var(--space-3) var(--space-4);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.15em;
	color: var(--text-secondary);
	cursor: pointer;
	list-style: none;
	border-radius: var(--radius-md);
	transition: color var(--duration-fast) ease;
}
.reader-summary-toggle::-webkit-details-marker {
	display: none;
}
.reader-summary-toggle::marker {
	content: "";
}
/* Chevron marker — points right when collapsed, down when open. */
.reader-summary-toggle::before {
	content: "";
	width: 0;
	height: 0;
	border-style: solid;
	border-width: 4px 0 4px 6px;
	border-color: transparent transparent transparent currentColor;
	transition: transform var(--duration-fast) ease;
}
.reader-summary[open] > .reader-summary-toggle::before {
	transform: rotate(90deg);
}
.reader-summary-toggle:hover {
	color: var(--text-primary);
}
.reader-summary-toggle:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

.reader-summary-body {
	padding: 0 var(--space-4) var(--space-4);
	font-size: calc(var(--reader-font-size, var(--text-md)) * 0.9);
	color: var(--text-secondary);
	line-height: 1.6;
}

@media (prefers-reduced-motion: reduce) {
	.reader-summary-toggle::before,
	.reader-summary-toggle {
		transition: none;
	}
}

/* ── Tags ─────────────────────────────────────────────── */
.reader-tags {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin: var(--space-6) auto;
	padding: 0 var(--space-6);
}

.reader-tags .tag-pill {
	background: var(--surface);
	text-decoration: none;
}
.reader-tags .tag-pill:hover {
	background: var(--surface-hover);
}

/* ── Content Placeholder / Loading ────────────────────── */
.reader-content-placeholder {
	text-align: center;
	padding: var(--space-8) var(--space-4);
	color: var(--text-muted);
	font-family: var(--font-ui);
}

.reader-loading-skeleton {
	background: linear-gradient(
		90deg,
		var(--surface) 25%,
		var(--surface-hover) 50%,
		var(--surface) 75%
	);
	background-size: 200% 100%;
	animation: skeleton-shimmer var(--duration-shimmer) ease-in-out infinite;
	border-radius: var(--radius-sm);
}

@keyframes skeleton-shimmer {
	0% {
		background-position: 200% 0;
	}
	100% {
		background-position: -200% 0;
	}
}

.reader-loading-bar {
	height: 2px;
	background: var(--accent);
	border-radius: 2px;
	animation: loading-progress var(--duration-pulse) ease-in-out infinite;
	margin-bottom: var(--space-4);
}

/* ── Processing / Repair overlay ───────────────────────────
   Painted by reader-init.ts over the whole reading column while the card is
   still being built (fetch → extract → enrich → embed) or just-repaired, so a
   half-built article is never shown (fb-feature-reader-processing-repair-state-
   overlay). Visual language mirrors the library grid's `.card-processing-overlay`
   (spinner + muted stage label over a translucent wash) so building cards read
   the same on the grid and in the reader.

   `position: fixed` with `z-index: 9` keeps the overlay BELOW the sticky
   `.reader-header` (z-index: 10) so the back button + display menu stay reachable
   while the article builds — the user can always escape.

   It is inset by the fixed sidebar's width on the LEFT so it centers over the
   READING PANE, not the whole viewport — otherwise the spinner sat shifted left,
   partly under the sidebar (fb-bug-repairing-overlay-centers-viewport-not-pane).
   The reader lives inside `.app .main` (margin-left: --sidebar-width), so the
   overlay tracks the same offset. The collapsed-sidebar + mobile + WCO blocks
   below adjust the inset to match each layout. */
.reader-processing-overlay {
	position: fixed;
	top: 0;
	right: 0;
	bottom: 0;
	/* Center over the reading pane, not under the fixed sidebar. */
	left: var(--sidebar-width);
	z-index: 9;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--space-4);
	background: var(--bg-page);
	font-family: var(--font-ui);
	text-align: center;
	padding: var(--space-6);
}

/* Collapsed sidebar: shrink the left inset to the collapsed rail width so the
   overlay still centers over the (now wider) reading pane. Both the committed
   `.sidebar-collapsed` state and the pre-paint `.sidebar-will-collapse` flash
   guard are covered, mirroring `.main`'s margin in layout.css. */
.app.sidebar-collapsed .reader-processing-overlay,
.sidebar-will-collapse .reader-processing-overlay {
	left: var(--sidebar-width-collapsed);
}

/* Mobile: the sidebar is hidden (.main margin-left: 0), so the overlay spans the
   full width and centers in the content — no left inset. The collapsed-state
   selectors are repeated here because `.app.sidebar-collapsed .reader-processing-overlay`
   (0,2,0) outscores a bare `.reader-processing-overlay` (0,1,0) — without matching
   their specificity, a collapsed sidebar restored from localStorage at mobile width
   would keep the rail inset and shove the overlay ~56px off-center (the exact bug
   this overlay reposition set out to fix). Equal specificity + later source order
   wins → left: 0. */
@media (max-width: 767px) {
	.reader-processing-overlay,
	.app.sidebar-collapsed .reader-processing-overlay,
	.sidebar-will-collapse .reader-processing-overlay {
		left: 0;
	}
}
@supports (background: color-mix(in srgb, red 50%, transparent)) {
	.reader-processing-overlay {
		background: color-mix(in srgb, var(--bg-page) 88%, transparent);
		backdrop-filter: blur(3px);
	}
}

.reader-processing-spinner {
	width: 36px;
	height: 36px;
	border: 3px solid var(--border);
	border-top-color: var(--accent);
	border-radius: 50%;
	animation: spin var(--duration-spinner) linear infinite;
}

.reader-processing-text {
	font-size: var(--text-sm);
	color: var(--text-muted);
	letter-spacing: 0.05em;
}

/* Spinner keyframes (mirrors layout.css's `spin`, redeclared here because the
   reader page does not load layout.css). */
@keyframes spin {
	to {
		transform: rotate(360deg);
	}
}

@media (prefers-reduced-motion: reduce) {
	.reader-processing-spinner {
		animation: none;
		/* Keep a visible static ring so the overlay still reads as "working"
		   without motion. */
		border-top-color: var(--accent);
	}
}

@keyframes loading-progress {
	0% {
		width: 0;
		opacity: 1;
	}
	50% {
		width: 70%;
		opacity: 1;
	}
	100% {
		width: 100%;
		opacity: 0;
	}
}

/* The reader's inline share popover was replaced by <theseus-share-dialog>
   (fb-feature-reader-overflow-menu-repair-share) — its styles live in the
   component's shadow DOM, so the old `.reader-share-panel` rules are retired. */

/* ── Remix (temporarily unshipped — UI entry points removed, styles kept for re-enablement) ── */
.reader-remix-panel {
	padding: var(--space-4);
	background: var(--surface);
	border-radius: var(--radius-md);
	margin-bottom: var(--space-4);
}

.reader-remix-result {
	margin-top: var(--space-6);
	padding: var(--space-5);
	background: var(--surface);
	border-radius: var(--radius-md);
}

.reader-remix-label {
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	text-transform: uppercase;
	letter-spacing: 0.15em;
	color: var(--text-muted);
	margin-bottom: var(--space-3);
}

/* ── Related Articles — Editorial Divider ──────────────── */
.reader-related-divider {
	text-align: center;
	/* ~32px above the divider (was --space-12 / 48px) — tightens the gap below
	   the tag row without collapsing the related-section separation (98cfc87c). */
	margin-top: var(--space-8);
	margin-bottom: var(--space-8);
	color: var(--text-muted);
	font-size: var(--text-base);
	letter-spacing: var(--space-3);
	user-select: none;
}

/* ── Related Articles — Section ───────────────────────── */
.reader-related {
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin-left: auto;
	margin-right: auto;
	padding: 0 var(--space-6);
	overflow-x: hidden;
}

.reader-related h3 {
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.15em;
	color: var(--text-muted);
	margin-bottom: var(--space-5);
}

/* ── Discovery Cards (Tier 1) ─────────────────────────── */
.reader-related-discovery {
	display: block;
	padding: var(--space-3);
	margin-left: calc(-1 * var(--space-3));
	margin-right: calc(-1 * var(--space-3));
	text-decoration: none;
	color: inherit;
	border-radius: var(--radius-md);
	transition: background var(--duration-fast);
	cursor: pointer;
}

.reader-related-discovery-border {
	border-top: 1px solid var(--border-subtle);
}

.reader-related-discovery:hover,
.reader-related-compact:hover {
	background: var(--surface);
}

.reader-related-discovery:focus-visible,
.reader-related-compact:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
	border-radius: var(--radius-md);
}

.reader-related-discovery:active,
.reader-related-compact:active {
	background: var(--surface-hover);
}

.reader-related-discovery .reader-related-title {
	display: block;
	font-family: var(--font-reading);
	font-size: var(--text-lg);
	font-weight: 400;
	color: var(--text-primary);
	letter-spacing: -0.01em;
	line-height: 1.3;
	margin-bottom: var(--space-1);
}

.reader-related-excerpt {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	font-family: var(--font-reading);
	font-size: var(--text-sm);
	color: var(--text-secondary);
	line-height: 1.5;
	margin-bottom: var(--space-2);
}

/* ── Tier Divider ─────────────────────────────────────── */
.reader-related-tier-divider {
	border: none;
	border-top: 1px solid var(--border);
	margin: var(--space-3) 0;
}

/* ── Compact List (Tier 2) ────────────────────────────── */
.reader-related-compact {
	display: block;
	padding: var(--space-2) var(--space-3);
	margin-left: calc(-1 * var(--space-3));
	margin-right: calc(-1 * var(--space-3));
	text-decoration: none;
	color: inherit;
	border-radius: var(--radius-md);
	transition: background var(--duration-fast);
	cursor: pointer;
}

.reader-related-compact .reader-related-title {
	display: block;
	font-family: var(--font-reading);
	font-size: var(--text-base);
	font-weight: 400;
	color: var(--text-primary);
	letter-spacing: -0.01em;
	line-height: 1.3;
}

/* ── Meta, Signal, Source ─────────────────────────────── */
.reader-related-meta {
	display: block;
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	color: var(--text-muted);
}

.reader-related-signal {
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	font-weight: 500;
	color: var(--text-muted);
	letter-spacing: 0.02em;
}

.reader-related-source {
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	font-weight: 400;
	color: var(--text-muted);
	letter-spacing: 0.02em;
}

/* ── Progressive Disclosure — Overflow ────────────────── */
.reader-related-overflow[data-enhanced] {
	overflow: hidden;
	max-height: 0;
	opacity: 0;
	transition:
		max-height var(--duration-normal) var(--ease-out),
		opacity var(--duration-normal) var(--ease-out);
}

.reader-related-overflow[data-expanded="true"] {
	max-height: 2000px;
	opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
	.reader-related-overflow[data-enhanced] {
		transition: none;
	}
	.reader-related-overflow[data-expanded="true"] {
		max-height: none;
	}
}

.reader-related-toggle {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: calc(100% + var(--space-3) * 2);
	padding: var(--space-2) var(--space-3);
	margin-left: calc(-1 * var(--space-3));
	margin-right: calc(-1 * var(--space-3));
	margin-top: var(--space-2);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	font-weight: 500;
	color: var(--text-secondary);
	background: none;
	border: none;
	border-radius: var(--radius-md);
	cursor: pointer;
	transition:
		background var(--duration-fast),
		color var(--duration-fast);
}

.reader-related-toggle:hover {
	background: var(--surface);
	color: var(--text-primary);
}

.reader-related-toggle:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

/* Mobile: ensure 44×44 touch target (WCAG 2.5.5) */
@media (max-width: 767px) {
	.reader-related-toggle {
		min-height: 44px;
	}
}

.reader-related-toggle-arrow {
	transition: transform var(--duration-fast);
}

.reader-related-toggle[aria-expanded="true"] .reader-related-toggle-arrow {
	transform: rotate(180deg);
}

/* ═══════════════════════════════════════════════════════════
   Video Reader — .reader--video modifier
   Embedded player, watch button, video-specific layout
   ═══════════════════════════════════════════════════════════ */

/* ── Video Modifier — Hidden Elements ─────────────────── */
.reader--video .reader-progress,
.reader--video .reader-controls,
.reader--video #controls-btn {
	display: none;
}

/* ── Video Player (embeddable) ────────────────────────── */
.reader-video-player {
	width: 100%;
	max-width: var(--reader-column-width, var(--max-width-reading));
	aspect-ratio: 16 / 9;
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: var(--color-ink);
	margin: var(--space-6) auto;
}

.reader-video-player iframe {
	width: 100%;
	height: 100%;
	border: none;
}

/* ── Video Player Loading State ───────────────────────── */
.reader-video-player--loading {
	display: flex;
	align-items: center;
	justify-content: center;
}

.reader-video-player--loading .reader-video-play-indicator {
	animation: reader-video-pulse var(--duration-pulse) var(--ease-in-out) infinite;
}

@keyframes reader-video-pulse {
	0% {
		opacity: 1;
	}
	50% {
		opacity: 0.4;
	}
	100% {
		opacity: 1;
	}
}

@media (prefers-reduced-motion: reduce) {
	.reader-video-player--loading .reader-video-play-indicator {
		animation: none;
		opacity: 0.4;
	}
}

/* ── Video Fallback (non-embeddable) ──────────────────── */
.reader-video-fallback {
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin: var(--space-6) auto;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-4);
}

/* ── Video Thumbnail ──────────────────────────────────── */
.reader-video-thumb {
	position: relative;
	width: 100%;
	aspect-ratio: 16 / 9;
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: var(--color-ink);
}

.reader-video-thumb-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.reader-video-thumb-placeholder {
	width: 100%;
	height: 100%;
}

.reader-video-thumb-overlay {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	pointer-events: none;
}

.reader-video-play-indicator {
	width: 64px;
	height: 64px;
	display: flex;
	align-items: center;
	justify-content: center;
	background: color-mix(in srgb, var(--color-ink) 60%, transparent);
	backdrop-filter: blur(4px);
	border-radius: var(--radius-full);
}

.reader-video-play-indicator svg {
	width: 28px;
	height: 28px;
	transform: translate(2px, 0);
}

/* ── Watch Button ─────────────────────────────────────── */
.reader-watch-btn {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	padding: var(--space-3) var(--space-5);
	background: var(--accent-strong);
	color: var(--color-parchment);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	font-weight: 600;
	border-radius: var(--radius-md);
	text-decoration: none;
	transition:
		background var(--duration-fast) ease,
		transform var(--duration-fast) ease;
}

.reader-watch-btn:hover {
	background: color-mix(in srgb, var(--accent-strong) 85%, var(--color-ink));
	transform: translateY(-1px);
}

.reader-watch-btn:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

@media (max-width: 639px) {
	.reader-watch-btn {
		display: flex;
		justify-content: center;
		width: 100%;
	}
}

/* ═══════════════════════════════════════════════════════════
   Social Reader — .reader--social modifier
   Narrower, author-forward, post-frame layout for social cards
   ═══════════════════════════════════════════════════════════ */

/* ── Social Modifier — Container ──────────────────────── */
.reader--social .reader-tags,
.reader--social .reader-related {
	max-width: var(--max-width-social);
}

/* ── Social Modifier — Hidden Elements ────────────────── */
.reader--social .reader-progress,
.reader--social .reader-controls,
.reader--social #controls-btn {
	display: none;
}

/* ── Social Author Display ────────────────────────────── */
.social-author {
	text-align: center;
	/* Top clearance now comes from .reader-hero padding-top (shared across all
	   reader variants); only the bottom margin remains here. */
	margin-top: 0;
	margin-bottom: var(--space-1);
	max-width: var(--max-width-social);
	margin-left: auto;
	margin-right: auto;
	padding: 0 var(--space-6);
}

.social-author-name {
	font-family: var(--font-reading);
	font-size: var(--text-xl);
	font-weight: 400;
	color: var(--text-primary);
	letter-spacing: -0.01em;
	line-height: 1.3;
}

/* ── Social Meta Row ──────────────────────────────────── */
.social-meta-row {
	text-align: center;
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-secondary);
	margin-bottom: var(--space-2);
	max-width: var(--max-width-social);
	margin-left: auto;
	margin-right: auto;
	padding: 0 var(--space-6);
}

/*
 * Social meta row uses `text-align: center` with inline content (not a
 * flex container with `gap` like `.reader-meta-row`), so the global
 * `.reader-meta-sep::before` glyph would double-render alongside the
 * inline `·` text node the JSX emits — visible as `Mastodon · · May 7`.
 *
 * Suppress the pseudo here and lean on the inline text node, then give
 * the span a little breathing room so neighbouring labels don't butt
 * against the glyph.
 */
.social-meta-row .reader-meta-sep::before {
	content: none;
}
.social-meta-row .reader-meta-sep {
	margin: 0 0.35em;
}

.social-platform-label {
	font-weight: 500;
	letter-spacing: 0.02em;
}

/* ── Post Frame ───────────────────────────────────────── */
.social-post-frame {
	background: var(--bg-elevated);
	border: 1px solid var(--border);
	border-left: 3px solid var(--accent);
	border-radius: var(--radius-lg);
	padding: var(--space-6);
	margin-top: var(--space-6);
	margin-bottom: var(--space-8);
	max-width: var(--max-width-social);
	margin-left: auto;
	margin-right: auto;
}

/* ── Content Tiers — oEmbed iframe ────────────────────── */
.social-oembed {
	width: 100%;
	border: none;
	min-height: 200px;
	display: block;
}

/* ── Content Tiers — Post Body (Tier 2 & 3) ──────────── */
.social-post-body {
	font-family: var(--font-reading);
	font-size: var(--text-base);
	line-height: 1.6;
	white-space: pre-wrap;
	overflow-wrap: break-word;
	color: var(--text-primary);
}

.social-post-body a {
	color: var(--accent);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
}

.social-post-body img {
	max-width: 100%;
	height: auto;
	border-radius: var(--radius-sm);
	margin-top: var(--space-4);
}

/* ── Post Media Attachments ──────────────────────────────── */
.social-post-media {
	margin-top: var(--space-4);
}

.social-post-media-grid {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--space-2);
	margin-top: var(--space-4);
}

.social-post-media-img {
	width: 100%;
	height: auto;
	max-height: 28rem;
	object-fit: contain;
	border-radius: var(--radius-md);
	display: block;
}

.social-post-media-grid .social-post-media-img {
	object-fit: cover;
	aspect-ratio: 1;
	max-height: none;
}

.social-post-media-video {
	position: relative;
	display: block;
	border-radius: var(--radius-md);
	overflow: hidden;
	text-decoration: none;
}

.social-post-media-video video {
	width: 100%;
	height: auto;
	max-height: 28rem;
	object-fit: contain;
	display: block;
	pointer-events: none;
}

.social-post-media-grid .social-post-media-video video {
	object-fit: cover;
	aspect-ratio: 1;
	max-height: none;
}

.social-post-media-play {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 3rem;
	height: 3rem;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgb(0 0 0 / 60%);
	color: #fff;
	border-radius: var(--radius-full);
	font-size: var(--text-lg);
	pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
	.social-post-media-video {
		aspect-ratio: 16 / 9;
		background: var(--bg-inset);
	}
	.social-post-media-video video {
		display: none;
	}
}

/* ── View Original Button ─────────────────────────────── */
.social-view-original {
	display: block;
	margin-inline: auto;
	width: fit-content;
	padding: var(--space-2) var(--space-5);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	font-weight: 500;
	color: var(--accent);
	background: transparent;
	border: 1px solid var(--accent);
	border-radius: var(--radius-full);
	text-decoration: none;
	text-align: center;
	transition:
		background var(--duration-fast) ease,
		color var(--duration-fast) ease;
	margin-bottom: var(--space-8);
}

.social-view-original:hover {
	background: var(--accent);
	color: var(--text-inverse);
}

.social-view-original:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

/* ── Social Responsive ────────────────────────────────── */
@media (max-width: 767px) {
	.social-post-frame {
		border-radius: var(--radius-md);
		padding: var(--space-4);
		margin-inline: var(--space-4);
	}

	.social-author {
		padding: 0 var(--space-4);
	}

	.social-meta-row {
		padding: 0 var(--space-4);
	}

	.social-post-media-grid {
		grid-template-columns: 1fr;
	}

	.social-post-media-grid .social-post-media-img {
		aspect-ratio: 16 / 9;
	}

	.social-post-media-grid .social-post-media-video video {
		aspect-ratio: 16 / 9;
	}
}

/* ── Mobile Adaptation ────────────────────────────────── */
@media (max-width: 639px) {
	.reader-related-divider {
		margin-top: var(--space-8);
		margin-bottom: var(--space-6);
	}

	.reader-related-compact {
		padding-top: var(--space-3);
		padding-bottom: var(--space-3);
	}

	.reader-related-excerpt {
		-webkit-line-clamp: 1;
	}
}

/* ── Keyboard Shortcuts ───────────────────────────────── */
.reader-shortcuts-overlay {
	position: fixed;
	inset: 0;
	background: var(--scrim);
	display: none;
	align-items: center;
	justify-content: center;
	z-index: 1000;
}
.reader-shortcuts-overlay:not(.hidden) {
	display: flex;
}

.reader-shortcuts-panel {
	background: var(--bg-page);
	border-radius: var(--radius-lg);
	padding: var(--space-6);
	max-width: 400px;
	width: 90%;
}

.reader-shortcuts-panel h3 {
	font-family: var(--font-ui);
	margin-bottom: var(--space-4);
}

.reader-shortcuts-table {
	width: 100%;
	margin-bottom: var(--space-4);
}

.reader-shortcuts-table td {
	padding: var(--space-2) var(--space-3);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
}

.reader-shortcuts-table td:first-child {
	white-space: nowrap;
	text-align: right;
	width: 40%;
}

.reader-shortcuts-table kbd {
	display: inline-block;
	padding: 2px 6px;
	background: var(--surface);
	border-radius: var(--radius-sm);
	font-family: var(--font-mono);
	font-size: var(--text-xs);
}

/* ── Paywall ──────────────────────────────────────────── */
.reader-paywall {
	margin-top: var(--space-4);
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin-left: auto;
	margin-right: auto;
	padding: 0 var(--space-6);
}

.reader-paywall-summary {
	background: var(--surface);
	border-radius: var(--radius-md);
	padding: var(--space-4) var(--space-5);
	margin-bottom: var(--space-5);
	line-height: 1.7;
}

.reader-paywall-summary-label {
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--text-muted);
	margin-bottom: var(--space-2);
}

.reader-paywall-excerpt {
	color: var(--text-secondary);
	font-style: italic;
	line-height: 1.7;
	margin-bottom: var(--space-5);
}

.reader-paywall-notice {
	text-align: center;
	padding: var(--space-6) var(--space-4);
	border: 1px dashed var(--border);
	border-radius: var(--radius-md);
	color: var(--text-secondary);
}

.reader-paywall-icon {
	display: block;
	font-size: var(--text-xl);
	margin-bottom: var(--space-2);
}

.reader-paywall-notice p {
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	margin-bottom: var(--space-3);
	line-height: 1.5;
}

.reader-paywall-link {
	display: inline-block;
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	font-weight: 500;
	color: var(--accent);
	text-decoration: none;
	padding: var(--space-2) var(--space-4);
	border: 1px solid var(--accent);
	border-radius: var(--radius-sm);
	transition:
		background var(--duration-fast),
		color var(--duration-fast);
}
.reader-paywall-link:hover {
	background: var(--accent);
	color: var(--bg-page);
}

/* ── Shared Reader Footer ─────────────────────────────── */
.shared-footer {
	margin-top: var(--space-10);
	padding-top: var(--space-6);
	border-top: 1px solid var(--border);
	text-align: center;
	color: var(--text-muted);
	font-size: var(--text-sm);
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin-left: auto;
	margin-right: auto;
}

/* In-text link: underline + --link-color per the axe link-in-text-block
   ruling (docs/design/a11y-axe-baseline-triage.md §3) — never color-only. */
.shared-footer a {
	color: var(--link-color);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
}
.shared-footer a:hover {
	color: var(--accent-hover);
}

/* ── Highlights ────────────────────────────────────────── */
.theseus-highlight {
	background: var(--highlight-amber);
	/* Highlighted text colour. inherit on light themes (keeps article ink),
	   deep ink on dark themes where a light inherit fails AA on the amber wash
	   (fb-bug 077d9dc4 — token defined in themes.css). */
	color: var(--highlight-text, inherit);
	border-radius: 2px;
	padding: 1px 0;
	cursor: pointer;
	transition: background var(--duration-fast);
}

.theseus-highlight:hover {
	background: var(--highlight-amber-strong);
}

.theseus-highlight[data-has-note]::after {
	content: "\25cf";
	font-size: var(--text-micro);
	/* Follow the highlight text colour (currentColor) rather than --accent: on
	   the brighter dark-theme amber the mid-orange accent washed out (1.5:1),
	   whereas currentColor is the dark ink (8.4:1+ every theme). fb-bug 077d9dc4. */
	color: currentColor;
	vertical-align: super;
	margin-left: 2px;
}

/* Inline code inside highlights: use semi-transparent bg so the
   highlight colour shows through (opaque --bg-inset hides it).
   color-mix on --text-primary makes it adapt to dark themes
   (light overlay on dark bg) without vanishing. */
.theseus-highlight code,
.shared-highlight code {
	background: color-mix(in srgb, var(--text-primary) 10%, transparent);
}

/* ── Shared View Highlights ──────────────────────────── */
.shared-highlight {
	background: var(--highlight-amber);
	/* Same dark-theme ink override as .theseus-highlight (fb-bug 077d9dc4).
	   Native <mark> also forces UA color:black — this keeps it token-driven. */
	color: var(--highlight-text, inherit);
	border-radius: 2px;
	padding: 1px 0;
}

.shared-highlight-attribution {
	display: flex;
	align-items: center;
	/* Center the dot + label within the reading column
	   (fb-ux-shared-reader-curator-highlights-label) — the block was already
	   centered via `margin: 0 auto`, but the flex row content was left-aligned,
	   reading as awkwardly off-center. */
	justify-content: center;
	gap: var(--space-2);
	font-size: var(--text-sm);
	color: var(--text-muted);
	font-style: italic;
	text-align: center;
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin: 0 auto var(--space-4);
}

.shared-highlight-dot {
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--highlight-amber-strong);
	flex-shrink: 0;
}

/* ── Focused Highlight Emphasis ─────────────────────────── */

@keyframes highlight-emphasis {
	0% {
		background: var(--highlight-amber-strong);
		box-shadow: 0 0 0 4px var(--highlight-amber);
	}
	100% {
		background: var(--highlight-amber);
		box-shadow: 0 0 0 4px transparent;
	}
}

mark.shared-highlight[data-focused] {
	animation: highlight-emphasis var(--duration-pulse) ease-out forwards;
}

@media (prefers-reduced-motion: reduce) {
	mark.shared-highlight[data-focused] {
		animation: none;
		background: var(--highlight-amber-strong);
	}
}

/* ═══════════════════════════════════════════════════════════
   Curator Notes — shared article annotations
   Card-level introduction notes and margin / inline notes
   on highlights. Mobile-first: inline callouts by default,
   margin notes alongside highlights at ≥ 960px.
   ═══════════════════════════════════════════════════════════ */

/* ── Card Note — "From the curator" introduction ──────── */

.curator-note--card {
	background: var(--bg-inset);
	border-left: 3px solid var(--accent);
	border-radius: var(--radius-sm);
	padding: var(--space-4);
	margin: 0 var(--space-4) var(--space-6);
}

@media (min-width: 640px) {
	.curator-note--card {
		max-width: var(--reader-column-width, var(--max-width-reading));
		margin: 0 auto var(--space-6);
	}
}

/* ── Curator Note Label — attribution line ───────────── */

.curator-note-label {
	display: flex;
	align-items: center;
	gap: var(--space-1);
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	text-transform: uppercase;
	letter-spacing: 0.15em;
	color: var(--text-muted);
	margin: 0 0 var(--space-2);
	line-height: 1.4;
}

/* Accent icon preceding the label text */
.curator-note-label::before {
	content: "\2726";
	color: var(--accent);
	font-size: 0.75em;
}

/* ── Curator Note Text — the annotation body ─────────── */

.curator-note-text {
	font-family: var(--font-reading);
	font-size: var(--text-sm);
	font-style: italic;
	color: var(--text-secondary);
	line-height: 1.7;
	margin: 0;
}

/* High Contrast: remove italic to improve legibility;
   container border + background + label carry the meaning */
[data-theme="high-contrast"] .curator-note-text {
	font-style: normal;
}

/* ── Curator Note Header — icon + label row ──────────── */

.curator-note-header {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--text-muted);
	margin: 0 0 var(--space-2);
	line-height: 1.4;
}

/* When label is inside a header, suppress its ::before icon
   since the icon is an explicit element */
.curator-note-header .curator-note-label {
	margin: 0;
}

.curator-note-header .curator-note-label::before {
	display: none;
}

/* ── Curator Note Icon — accent star ─────────────────── */

.curator-note-icon {
	color: var(--accent);
	font-style: normal;
}

/* ── Curator Note Body — annotation text ─────────────── */

.curator-note-body {
	font-family: var(--font-reading);
	font-size: var(--text-sm);
	font-style: italic;
	color: var(--text-secondary);
	line-height: 1.7;
	margin: 0;
}

[data-theme="high-contrast"] .curator-note-body {
	font-style: normal;
}

/* ── Inline Callout — mobile-first base ──────────────── */

.curator-note {
	display: block;
	background: var(--bg-inset);
	border-left: 3px solid var(--accent);
	border-radius: var(--radius-sm);
	padding: var(--space-3);
	margin: var(--space-3) 0 var(--space-4);
}

/* ── Desktop Margin Notes (≥ 960px — intentional one-off; see docs/05-design-system.md §4.4) ──────────────────── */

@media (min-width: 960px) {
	/* Allow margin notes to paint outside the reading column */
	.reader-content:has(.curator-note--margin) {
		overflow: visible;
		position: relative;
	}

	.curator-note--margin {
		--curator-margin-width: 14rem;
		--curator-margin-gap: var(--space-4);

		float: right;
		clear: right;
		width: var(--curator-margin-width);
		margin-right: calc(-1 * (var(--curator-margin-width) + var(--curator-margin-gap)));
		margin-left: var(--space-4);
		margin-bottom: var(--space-4);
		margin-top: 0;

		/* Reset inline-callout appearance for sidebar treatment */
		background: transparent;
		border-left: 2px solid var(--accent);
		border-radius: 0;
		padding: 0 0 0 var(--space-3);
	}

	/* Tighter type in the margin — smaller measure demands it */
	.curator-note--margin .curator-note-text,
	.curator-note--margin .curator-note-body {
		font-size: var(--text-sm);
		line-height: 1.6;
	}

	/* Tighter label spacing in margin context */
	.curator-note--margin .curator-note-label {
		margin-bottom: var(--space-1);
	}
}

/* ── Note Edit Mode ───────────────────────────────────── */
.reader-edit-btn {
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	font-weight: 500;
	color: var(--text-secondary);
}

.reader-edit-hide {
	display: none;
}

.reader-edit-fields {
	max-width: var(--reader-column-width, var(--max-width-reading));
	margin: 0 auto;
	padding: var(--space-10) var(--space-6) var(--space-16);
	position: relative;
}

.reader-edit-title {
	display: block;
	width: 100%;
	font-family: var(--font-reading);
	/* Mirrors .reader-meta h1 (--text-2xl, fb-ux 99e1c9ad) so the title
	   doesn't jump size when note edit mode toggles. */
	font-size: var(--text-2xl);
	font-weight: 700;
	line-height: 1.15;
	color: var(--text-primary);
	background: transparent;
	border: none;
	border-bottom: 2px solid var(--border-subtle);
	padding: 0 0 var(--space-2);
	margin-bottom: var(--space-6);
	outline: none;
	transition: border-color var(--duration-fast);
}

.reader-edit-title::placeholder {
	color: var(--text-muted);
}

.reader-edit-title:focus {
	border-bottom-color: var(--accent);
}

.reader-edit-content {
	display: block;
	width: 100%;
	min-height: 200px;
	font-family: var(--font-reading);
	font-size: var(--reader-font-size, var(--text-md));
	line-height: var(--reader-line-height, 1.7);
	color: var(--text-primary);
	background: transparent;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-sm);
	padding: var(--space-4);
	resize: vertical;
	outline: none;
	transition: border-color var(--duration-fast);
}

.reader-edit-content::placeholder {
	color: var(--text-muted);
}

.reader-edit-content:focus {
	border-color: var(--accent);
}

.reader-edit-feedback {
	position: absolute;
	bottom: var(--space-8);
	right: var(--space-6);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-secondary);
	background: var(--bg-elevated);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-sm);
	padding: var(--space-1) var(--space-3);
	opacity: 1;
	transition: opacity var(--duration-normal);
}

.reader-edit-feedback.hidden {
	opacity: 0;
	pointer-events: none;
}

/* ── List Reader Modifier ─────────────────────────────── */
.reader--list .reader-progress,
.reader--list .reader-controls,
.reader--list #controls-btn {
	display: none;
}

.reader--list .reader-meta {
	max-width: 540px;
	margin-left: auto;
	margin-right: auto;
	padding: 0 var(--space-6);
}

/* ── Checklist ────────────────────────────────────────── */
.list-checklist {
	max-width: 540px;
	margin: var(--space-6) auto 0;
	padding: 0 var(--space-6);
}

.list-item {
	display: flex;
	align-items: flex-start;
	gap: var(--space-3);
	padding: var(--space-3) 0;
	border-bottom: 1px solid var(--border-subtle);
	cursor: pointer;
	transition: opacity var(--duration-fast);
}

.list-item:last-child {
	border-bottom: none;
}

.list-item-checkbox {
	flex-shrink: 0;
	width: 16px;
	height: 16px;
	margin-top: 2px;
	accent-color: var(--accent);
	cursor: pointer;
}

.list-item-text {
	font-family: var(--font-reading);
	font-size: var(--text-base);
	line-height: 1.5;
	color: var(--text-primary);
	transition:
		opacity var(--duration-fast),
		text-decoration var(--duration-fast);
}

.list-item--done .list-item-text {
	text-decoration: line-through;
	opacity: 0.6;
}

/* ── Add Item ─────────────────────────────────────────── */
.list-add-form {
	max-width: 540px;
	margin: var(--space-4) auto 0;
	padding: 0 var(--space-6);
}

.list-add-input {
	width: 100%;
	padding: var(--space-3) var(--space-4);
	font-family: var(--font-reading);
	font-size: var(--text-base);
	color: var(--text-primary);
	background: var(--bg-inset);
	border: 1px solid var(--border);
	border-radius: var(--radius-md);
	outline: none;
	transition: border-color var(--duration-fast);
}

.list-add-input::placeholder {
	color: var(--text-muted);
}

.list-add-input:focus {
	border-color: var(--accent);
}

/* ── List Summary ─────────────────────────────────────── */
.list-summary {
	max-width: 540px;
	margin: var(--space-6) auto 0;
	padding: 0 var(--space-6);
	display: flex;
	align-items: center;
	gap: var(--space-4);
}

.list-summary-text {
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-muted);
	white-space: nowrap;
}

.list-progress-bar {
	flex: 1;
	height: 4px;
	background: var(--bg-inset);
	border-radius: var(--radius-full);
	overflow: hidden;
}

.list-progress-fill {
	height: 100%;
	background: var(--accent);
	border-radius: var(--radius-full);
	transition: width var(--duration-normal);
}

/* ── List Responsive ──────────────────────────────────── */
@media (max-width: 767px) {
	.list-checklist,
	.list-add-form,
	.list-summary,
	.reader--list .reader-meta {
		padding: 0 var(--space-4);
	}
}

/* ════════════════════════════════════════════════════════
   Interview Dialogue
   Implements docs/design-specs/interview-dialogue-visual.md.
   Bubbles render in the UI register (--font-ui, quiet tinted
   surfaces, monogram avatars) inside the reader column; the
   surrounding prose stays untouched in --font-reading. The
   register shift (serif→sans, full-column→inset, loose→tight)
   IS the seam — no divider chrome (Decision 3). Zero animation
   (§10): nothing for prefers-reduced-motion to reduce.
   ════════════════════════════════════════════════════════ */

/* Interview options popover (enhancement-only). The controls were dropped at
   the top of the article body; they now live in a light-dismiss menu next to
   the "Aa" display controls, opened by #dialogue-controls-btn in the header.
   Mirrors the .reader-controls popover chrome. Controls ship `hidden` and are
   revealed by reader-init.ts once wired, so the no-JS default has no dead
   control (the popover can't open without JS). */
.reader-dialogue-controls-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
}

.reader-dialogue-controls {
	position: fixed;
	top: 64px;
	right: var(--space-4);
	z-index: 20;
	min-width: 220px;
	max-width: min(92vw, 360px);
	max-height: min(70vh, 520px);
	overflow-y: auto;
	padding: var(--space-3);
	background: var(--bg-elevated);
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	box-shadow: 0 4px 16px var(--shadow-color);
	display: none;
	flex-direction: column;
	gap: var(--space-1);
}
.reader-dialogue-controls.open {
	display: flex;
}

/* Menu items: full-width, left-aligned rows rather than the inline ghost
   buttons of the old end-aligned toolbar. */
.reader-dialogue-controls .btn {
	width: 100%;
	justify-content: flex-start;
	font-family: var(--font-ui);
	font-size: var(--text-sm);
}

.reader-dialogue-toggle[hidden],
.reader-dialogue-relabel-btn[hidden],
.reader-dialogue-redetect[hidden] {
	display: none;
}

/* ── Manual "Format as interview" rescue CTA ─────────────────────────
   Sprint 119 Lane B (feature-reader-manual-format-as-interview).

   Prose-card escalate to the AI force-detect endpoint for false-negative
   interview detection (e.g. label-less Verge Decoder shape). Renders at
   the end of the article body as a quiet, deliberate CTA — labelled
   heading + short explainer + one text button. Ships `hidden` so no
   dead control shows without JS (reader-init.ts un-hides once wired). */
.reader-format-interview-cta {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--space-2);
	margin: var(--space-6) 0 var(--space-4);
	padding: var(--space-4);
	background: var(--bg-inset);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-md);
	font-family: var(--font-ui);
}

.reader-format-interview-cta[hidden] {
	display: none;
}

.reader-format-interview-cta-heading {
	margin: 0;
	font-size: var(--text-sm);
	font-weight: 600;
	color: var(--text-primary);
}

.reader-format-interview-cta-hint {
	margin: 0;
	font-size: var(--text-sm);
	color: var(--text-secondary);
}

.reader-format-interview-btn[aria-busy="true"] {
	/* One-request guarding keeps focus on the button; we signal the pending
	   state with aria-busy + a text swap rather than `disabled`, so a keyboard
	   user's focus is not ejected mid-request. */
	cursor: progress;
	opacity: 0.7;
}

/* The relabel editor renders into #dialogue-relabel-mount inside the popover;
   drop its standalone bottom margin so it sits flush in the menu. */
.reader-dialogue-controls .dialogue-relabel-panel {
	margin: var(--space-1) 0 0;
}

/* Inline relabel / merge editor (built client-side into #dialogue-relabel-
   mount; never server-rendered, so the shared renderer stays edit-free). */
.dialogue-relabel-panel {
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	margin-bottom: var(--space-6);
	padding: var(--space-4);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	background: var(--bg-inset);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-md);
}

.dialogue-relabel-heading {
	margin: 0;
	font-weight: 600;
	color: var(--text-secondary);
}

.dialogue-relabel-row {
	display: flex;
	align-items: center;
	gap: var(--space-2);
}

.dialogue-relabel-input {
	flex: 1;
	min-width: 0;
	padding: var(--space-2) var(--space-3);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-primary);
	background: var(--bg-page);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
}

.dialogue-relabel-input:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 1px;
}

.dialogue-merge-row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-2);
	padding-top: var(--space-3);
	border-top: 1px solid var(--border-subtle);
}

.dialogue-merge-label {
	flex-basis: 100%;
	color: var(--text-secondary);
}

.dialogue-merge-connector {
	color: var(--text-muted);
}

.dialogue-merge-select {
	padding: var(--space-1) var(--space-2);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	color: var(--text-primary);
	background: var(--bg-page);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
}

.dialogue-merge-select:focus-visible,
.dialogue-merge-btn:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 1px;
}

/* In-page "View original" toggle: swap the dialogue for the original prose
   body. The original body is hidden by default (the dialogue is the no-JS
   default); the toggle sets data-view-original on .reader to swap them. */
.reader-content--original {
	display: none;
}

.reader[data-view-original="true"] .reader-dialogue {
	display: none;
}

.reader[data-view-original="true"] .reader-content--original {
	display: block;
}

.dialogue-run {
	margin-block: var(--space-8);
	font-family: var(--font-ui);
	font-size: 0.9em; /* relative to reader body — scales with the user's font-size pref */
	/* Inherit the reader's line-height preference (the DialogueRenderer root is a
	   .reader-content, so --reader-line-height is in scope). Falls back to 1.5
	   when unset. Without this the dialogue ignored the Line Height control. */
	line-height: var(--reader-line-height, 1.5);
}

.dialogue-cluster {
	--dialogue-accent: var(--dialogue-accent-1);
	display: grid;
	grid-template-columns: var(--space-10) 1fr;
	column-gap: var(--space-3);
}

.dialogue-cluster + .dialogue-cluster {
	margin-top: var(--space-4);
}

.dialogue-cluster[data-accent="2"] {
	--dialogue-accent: var(--dialogue-accent-2);
}

.dialogue-cluster[data-accent="3"] {
	--dialogue-accent: var(--dialogue-accent-3);
}

.dialogue-cluster[data-accent="4"] {
	--dialogue-accent: var(--dialogue-accent-4);
}

.dialogue-cluster[data-accent="5"] {
	--dialogue-accent: var(--dialogue-accent-5);
}

.dialogue-speaker-name {
	grid-column: 2;
	font-size: var(--text-xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.15em;
	line-height: 1.2;
	color: var(--dialogue-accent);
	margin-bottom: var(--space-1);
}

.dialogue-avatar {
	position: relative;
	grid-column: 1;
	grid-row: 2; /* explicit — auto-placement would seat it beside the name */
	align-self: start; /* top edge flush with the first bubble */
	width: var(--space-10);
	height: var(--space-10);
	border-radius: var(--radius-full);
	background: var(--dialogue-accent);
	color: var(--dialogue-avatar-text);
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: var(--text-base);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.02em;
	line-height: 1;
	overflow: hidden; /* clips the photo variant to the circle */
}

.dialogue-avatar-photo {
	position: absolute;
	inset: 0;
	border-radius: var(--radius-full);
	/* Photo as a background image layered over the monogram: a URL that fails
	   to load paints nothing and the initials show through (CSP-clean, no JS,
	   no broken-image icon). */
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
	box-shadow: inset 0 0 0 1px var(--border-subtle); /* hairline ring seats arbitrary photo edges */
}

.dialogue-bubble {
	grid-column: 2;
	width: fit-content;
	max-width: 85%;
	padding: var(--space-3) var(--space-4);
	background: var(--bg-dialogue-bubble);
	border-radius: var(--radius-sm) var(--radius-lg) var(--radius-lg) var(--radius-sm);
	color: var(--text-primary);
}

.dialogue-bubble + .dialogue-bubble {
	margin-top: var(--space-1);
}

.dialogue-bubble p {
	margin: 0;
}

.dialogue-bubble p + p {
	margin-top: var(--space-2);
}

/* Links inside bubbles: ink text + ember underline (NOT ember text — ember as
   text on the bubble surface fails AA at 3.57:1; §4/§7). */
.dialogue-bubble a {
	color: inherit;
	text-decoration: underline;
	text-decoration-color: var(--accent);
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
}

.dialogue-bubble a:hover {
	color: var(--accent);
}

.dialogue-bubble img {
	max-width: 100%;
	border-radius: var(--radius-sm);
	margin: var(--space-2) 0;
}

/* Curator share-marks baked into bubbles (public shared page —
   fb-bug-interview-dialogue-no-highlight-popover): a curator note inside a
   bubble keeps the inline-callout treatment at ALL widths. The ≥960px
   .curator-note--margin float (negative right margin) is calibrated to the
   prose column edge; from inside a fit-content bubble it would poke past the
   bubble surface into the opposite speaker's lane. Higher specificity than
   the media-scoped .curator-note--margin rule, so no !important needed. */
@media (min-width: 960px) {
	.dialogue-bubble .curator-note--margin {
		float: none;
		clear: none;
		width: auto;
		margin: var(--space-3) 0 var(--space-2);
		background: var(--bg-inset);
		border-left: 3px solid var(--accent);
		border-radius: var(--radius-sm);
		padding: var(--space-3);
	}
}

/* Interviewer cluster: mirrored to the right, ember-tinted surface. */
.dialogue-cluster--interviewer {
	grid-template-columns: 1fr var(--space-10);
}

.dialogue-cluster--interviewer .dialogue-avatar {
	grid-column: 2;
}

.dialogue-cluster--interviewer .dialogue-speaker-name {
	grid-column: 1;
	text-align: right;
}

.dialogue-cluster--interviewer .dialogue-bubble {
	grid-column: 1;
	justify-self: end; /* bubble text itself stays left-aligned */
	background: var(--bg-dialogue-bubble-interviewer);
	border-radius: var(--radius-lg) var(--radius-sm) var(--radius-sm) var(--radius-lg);
}

/* High Contrast: tints alone don't satisfy HC; borders carry the structure. */
[data-theme="high-contrast"] .dialogue-bubble,
[data-theme="high-contrast"] .dialogue-avatar {
	border: 1px solid var(--border);
}

/* Forced-colors (Windows High Contrast) strips background-color, erasing both
   surfaces and the avatar fill — borders are the minimum viable structure. */
@media (forced-colors: active) {
	.dialogue-bubble,
	.dialogue-avatar {
		border: 1px solid CanvasText;
	}
}

/* Mobile (≤640px, --bp-sm): smaller avatar, full-width bubbles. */
@media (max-width: 640px) {
	.dialogue-cluster {
		grid-template-columns: var(--space-8) 1fr;
		column-gap: var(--space-2);
	}

	.dialogue-cluster--interviewer {
		grid-template-columns: 1fr var(--space-8);
	}

	.dialogue-avatar {
		width: var(--space-8);
		height: var(--space-8);
		font-size: var(--text-sm);
	}

	.dialogue-bubble {
		max-width: 100%;
	}
}

/* ═══════════════════════════════════════════════════════════
   Structured Social Thread Reader
   Shared by authenticated Reader and public shared pages
   ═══════════════════════════════════════════════════════════ */

.reader--social-thread.reader--social-thread-multi .reader-progress {
	display: block;
}

.reader--social-thread .reader-tags,
.reader--social-thread .reader-related {
	max-width: var(--max-width-social);
}

.social-thread-reader {
	padding-bottom: var(--space-2);
}

.social-thread-hero {
	max-width: var(--max-width-reading);
	margin-inline: auto;
	padding-inline: var(--space-6);
	padding-bottom: var(--space-6);
	text-align: center;
}

.social-thread-kicker {
	margin: 0 0 var(--space-2);
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	font-weight: 600;
	line-height: 1.2;
	letter-spacing: 0.15em;
	text-transform: uppercase;
	color: var(--text-secondary);
}

.social-thread-hero h1 {
	margin: 0;
	font-family: var(--font-reading);
	font-size: var(--text-2xl);
	font-weight: 400;
	line-height: 1.2;
	letter-spacing: -0.02em;
	color: var(--text-primary);
	overflow-wrap: anywhere;
}

.social-thread-meta {
	margin: var(--space-2) 0 0;
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	line-height: 1.5;
	color: var(--text-secondary);
}

.social-thread-meta strong {
	color: var(--text-primary);
	font-weight: 600;
}

.social-thread-summary {
	max-width: var(--max-width-social);
	margin-bottom: var(--space-6);
}

.social-thread-summary-placeholder {
	max-width: var(--max-width-social);
	margin: 0 auto;
}

.social-thread-list {
	display: flex;
	flex-direction: column;
	gap: var(--space-5);
	width: 100%;
	max-width: calc(var(--max-width-social) + var(--space-12) + var(--space-3));
	margin: 0 auto;
	padding: 0;
	list-style: none;
}

.social-thread-item {
	position: relative;
	isolation: isolate;
	display: grid;
	grid-template-columns: var(--space-12) minmax(0, var(--max-width-social));
	gap: var(--space-3);
	align-items: start;
	min-width: 0;
}

.social-thread-rail {
	position: relative;
	align-self: stretch;
	display: flex;
	justify-content: center;
	min-height: 100%;
}

.social-thread-connector {
	position: absolute;
	z-index: 0;
	inset: 0 0 calc(0px - var(--space-5));
	width: 100%;
	height: calc(100% + var(--space-5));
	overflow: visible;
	pointer-events: none;
}

.social-thread-connector path {
	fill: none;
	stroke-linecap: round;
	vector-effect: non-scaling-stroke;
}

.social-thread-connector-underlay {
	stroke: var(--bg-page);
	stroke-width: 4px;
}

.social-thread-connector-line {
	stroke: var(--accent);
	stroke-width: 2px;
}

.social-thread-avatar {
	position: relative;
	z-index: 2;
	display: inline-flex;
	flex: 0 0 var(--space-10);
	align-items: center;
	justify-content: center;
	width: var(--space-10);
	height: var(--space-10);
	border: 1px solid var(--border);
	border-radius: var(--radius-full);
	background: var(--bg-inset);
	box-shadow: 0 0 0 2px var(--bg-page);
	color: var(--text-secondary);
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	font-weight: 600;
	line-height: 1;
	object-fit: cover;
}

.social-thread-avatar--compact {
	flex-basis: var(--space-8);
	width: var(--space-8);
	height: var(--space-8);
	box-shadow: none;
}

.social-thread-post {
	position: relative;
	z-index: 0;
	min-width: 0;
	padding: var(--space-5);
	background: var(--bg-elevated);
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	box-shadow: 0 1px 2px var(--shadow-color);
	transition:
		border-color var(--duration-fast) ease,
		background var(--duration-fast) ease,
		box-shadow var(--duration-fast) ease;
}

@media (hover: hover) {
	.social-thread-item:hover .social-thread-post {
		border-color: var(--accent);
		box-shadow: 0 4px 12px var(--shadow-color);
	}
}

.social-thread-item:has(.social-thread-permalink:active) .social-thread-post {
	border-color: var(--accent-active);
	background: var(--bg-inset);
}

.social-thread-post-header,
.social-thread-quoted-post-header {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--space-3);
	min-width: 0;
	margin-bottom: var(--space-3);
}

.social-thread-author {
	display: flex;
	flex-wrap: wrap;
	gap: 0 var(--space-2);
	min-width: 0;
	margin: 0;
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	line-height: 1.3;
}

.social-thread-author strong {
	color: var(--text-primary);
	font-weight: 600;
	overflow-wrap: anywhere;
}

.social-thread-author span {
	color: var(--text-secondary);
	overflow-wrap: anywhere;
}

.social-thread-permalink,
.social-thread-quote-permalink {
	flex: 0 0 auto;
	color: var(--link-color);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	line-height: 1.3;
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
	transition: color var(--duration-fast) ease;
}

.social-thread-permalink::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	border-radius: var(--radius-lg);
}

.social-thread-permalink:hover,
.social-thread-quote-permalink:hover {
	color: var(--accent-hover);
}

.social-thread-permalink:focus-visible {
	outline: none;
}

.social-thread-permalink:focus-visible::after {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
	box-shadow: 0 0 0 4px var(--focus-ring);
}

.social-thread-quote-permalink:focus-visible,
.social-thread-quote a:focus-visible,
.social-thread-link-preview:focus-visible,
.social-thread-media-link:focus-visible,
.social-thread-video-link:focus-visible,
.social-thread-media-fallback:focus-visible,
.social-thread-truncation a:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

.social-thread-quote,
.social-thread-quoted-post blockquote {
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
	color: var(--text-primary);
	font-family: var(--font-reading);
	font-size: var(--text-base);
	font-style: normal;
	line-height: 1.6;
	overflow-wrap: anywhere;
}

.social-thread-quote p,
.social-thread-quoted-post blockquote p {
	margin: 0;
	white-space: pre-wrap;
}

.social-thread-quote p + p,
.social-thread-quoted-post blockquote p + p {
	margin-top: var(--space-3);
}

.social-thread-quote a,
.social-thread-media-link,
.social-thread-link-preview,
.social-thread-video-link,
.social-thread-media-fallback {
	position: relative;
	z-index: 2;
	color: var(--link-color);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
}

.social-thread-attachments {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--space-2);
	margin-top: var(--space-4);
}

.social-thread-attachments > :only-child,
.social-thread-attachments > :nth-child(3):last-child {
	grid-column: 1 / -1;
}

.social-thread-media {
	min-width: 0;
	margin: 0;
}

.social-thread-media picture,
.social-thread-video-link picture,
.social-thread-link-preview picture {
	display: contents;
}

.social-thread-media-link,
.social-thread-video-link {
	display: block;
	min-width: 0;
	border-radius: var(--radius-md);
}

.social-thread-media-image,
.social-thread-video-poster {
	display: block;
	width: 100%;
	max-width: 100%;
	height: auto;
	max-height: calc(var(--max-width-social) - var(--space-8));
	border-radius: var(--radius-md);
	background: var(--bg-inset);
	object-fit: contain;
}

.social-thread-media figcaption {
	margin-top: var(--space-2);
	color: var(--text-secondary);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	line-height: 1.5;
}

.social-thread-video-link {
	position: relative;
	overflow: hidden;
	min-height: var(--space-12);
	background: var(--bg-inset);
}

.social-thread-video-poster {
	aspect-ratio: 16 / 9;
}

.social-thread-video-play {
	position: absolute;
	z-index: 2;
	inset: 50% auto auto 50%;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: var(--space-12);
	height: var(--space-12);
	border-radius: var(--radius-full);
	background: color-mix(in srgb, var(--color-ink) 72%, transparent);
	color: var(--color-parchment);
	transform: translate(-50%, -50%);
	pointer-events: none;
}

.social-thread-link-preview {
	display: grid;
	grid-template-columns: var(--space-24) minmax(0, 1fr);
	min-width: 0;
	overflow: hidden;
	background: var(--bg-inset);
	border: 1px solid var(--border);
	border-radius: var(--radius-md);
	color: var(--text-primary);
	text-decoration: none;
	transition:
		border-color var(--duration-fast) ease,
		background var(--duration-fast) ease;
}

.social-thread-link-preview:not(:has(.social-thread-link-preview-image)) {
	grid-template-columns: minmax(0, 1fr);
}

.social-thread-link-preview:hover {
	border-color: var(--accent-hover);
	background: var(--surface-hover);
}

.social-thread-link-preview-image {
	display: block;
	width: var(--space-24);
	height: 100%;
	min-height: var(--space-24);
	object-fit: cover;
}

.social-thread-link-preview-copy {
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: var(--space-1);
	min-width: 0;
	padding: var(--space-3);
}

.social-thread-link-preview-domain {
	color: var(--text-secondary);
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	font-weight: 500;
	line-height: 1.3;
	letter-spacing: 0.02em;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.social-thread-link-preview-copy strong {
	display: -webkit-box;
	overflow: hidden;
	font-family: var(--font-reading);
	font-size: var(--text-base);
	font-weight: 400;
	line-height: 1.3;
	letter-spacing: -0.01em;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
}

.social-thread-link-preview-description {
	display: -webkit-box;
	overflow: hidden;
	color: var(--text-secondary);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	line-height: 1.4;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
}

.social-thread-media-fallback {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	min-height: var(--space-24);
	padding: var(--space-4);
	background: var(--bg-inset);
	border: 1px solid var(--border);
	border-radius: var(--radius-md);
	color: var(--text-secondary);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	line-height: 1.4;
	text-align: center;
}

.social-thread-media-fallback--video {
	aspect-ratio: 16 / 9;
}

.social-thread-media-fallback-icon {
	font-size: var(--text-xl);
	line-height: 1;
}

.social-thread-quoted-post {
	position: relative;
	z-index: 2;
	margin-top: var(--space-4);
	padding: var(--space-4);
	background: var(--bg-inset);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-md);
}

.social-thread-quoted-post-header {
	display: grid;
	grid-template-columns: var(--space-8) minmax(0, 1fr) auto;
	gap: var(--space-2);
	align-items: center;
}

.social-thread-quoted-post blockquote {
	font-size: var(--text-sm);
}

.social-thread-truncation {
	max-width: var(--max-width-social);
	margin: var(--space-5) auto 0;
	padding: var(--space-3) var(--space-4);
	background: var(--bg-inset);
	border: 1px solid var(--border);
	border-radius: var(--radius-md);
	color: var(--text-secondary);
	font-family: var(--font-ui);
	font-size: var(--text-sm);
	line-height: 1.5;
}

.social-thread-truncation p {
	margin: 0;
}

.social-thread-truncation p + p {
	margin-top: var(--space-1);
}

.social-thread-truncation a {
	display: inline-block;
	min-height: var(--space-12);
	margin-top: var(--space-2);
	color: var(--link-color);
	line-height: var(--space-12);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
}

@media (max-width: 767px) {
	.social-thread-hero {
		padding-top: var(--space-8);
		padding-inline: var(--space-4);
		padding-bottom: var(--space-5);
	}

	.social-thread-hero h1 {
		font-size: var(--text-xl);
	}

	.social-thread-list {
		padding-inline: var(--space-4);
	}

	.social-thread-item {
		grid-template-columns: var(--space-8) minmax(0, 1fr);
		gap: var(--space-2);
	}

	.social-thread-avatar {
		flex-basis: var(--space-8);
		width: var(--space-8);
		height: var(--space-8);
	}

	.social-thread-post {
		padding: var(--space-4);
	}

	.social-thread-attachments {
		grid-template-columns: minmax(0, 1fr);
	}

	.social-thread-attachments > * {
		grid-column: 1;
	}

	.social-thread-summary,
	.social-thread-summary-placeholder,
	.social-thread-truncation {
		margin-inline: var(--space-4);
	}
}

@media (max-width: 639px) {
	.social-thread-post-header {
		flex-wrap: wrap;
		gap: var(--space-2);
	}

	.social-thread-permalink {
		flex-basis: 100%;
		min-height: var(--space-12);
		line-height: var(--space-12);
	}

	.social-thread-link-preview {
		grid-template-columns: minmax(0, 1fr);
	}

	.social-thread-link-preview-image {
		width: 100%;
		height: auto;
		max-height: var(--max-width-social);
		aspect-ratio: 16 / 9;
	}

	.social-thread-quoted-post-header {
		grid-template-columns: var(--space-8) minmax(0, 1fr);
	}

	.social-thread-quote-permalink {
		grid-column: 2;
		min-height: var(--space-12);
		line-height: var(--space-12);
	}
}

@media (prefers-reduced-motion: reduce) {
	.social-thread-post,
	.social-thread-permalink,
	.social-thread-quote-permalink,
	.social-thread-link-preview {
		transition: none;
	}
}

@media (forced-colors: active) {
	.social-thread-post,
	.social-thread-avatar,
	.social-thread-link-preview,
	.social-thread-media-fallback,
	.social-thread-quoted-post,
	.social-thread-truncation {
		border-color: CanvasText;
		forced-color-adjust: auto;
	}

	.social-thread-connector-underlay {
		stroke: Canvas;
	}

	.social-thread-connector-line {
		stroke: CanvasText;
	}

	.social-thread-permalink:focus-visible::after,
	.social-thread-quote a:focus-visible,
	.social-thread-link-preview:focus-visible,
	.social-thread-media-link:focus-visible,
	.social-thread-video-link:focus-visible,
	.social-thread-media-fallback:focus-visible,
	.social-thread-truncation a:focus-visible {
		outline-color: Highlight;
	}
}

/* ═══════════════════════════════════════════════════════════
   Window Controls Overlay (WCO) — reader-in-app-shell
   docs/design-specs/wco-titlebar.md §7 + home-nav-reading-ia.md §3

   The reader now renders inside AppLayout (reader-in-app-shell), so the
   sidebar + the APP-variant WCO strip own the OS band (the old reader-variant
   full-width strip is retired with the reader's BaseLayout). All that remains
   here is to inset the reader's position:sticky header below the app strip so
   its action buttons never fall under the OS controls. (The content flow is
   inset via .content-reader's padding-top in layout.css — a sticky top inset
   only moves the element, not the document flow. The reading-progress bar needs
   nothing here: it's an absolute child of .reader-header now, so it rides the
   header's inset automatically.) `--wco-strip-h` is defined on `.app` (the
   AppLayout root the reader lives under) as `env(titlebar-area-height) +
   space-4`; it resolves to the taller app band, not the bare OS height. Gated on
   the display-mode query, so off-WCO this is inert and the reader is byte-identical.
   ═══════════════════════════════════════════════════════════ */
/* stylelint-disable-next-line media-feature-name-value-no-unknown */
@media (display-mode: window-controls-overlay) {
	/* Inset the sticky header below the app strip (spec §7). --wco-strip-h is
	   0-based off env(.., 0px) off-WCO, so this is a no-op there. */
	.reader-header {
		top: var(--wco-strip-h, env(titlebar-area-height, 0px));
		/* In WCO the OS titlebar strip is already a full band above the header,
		   so the header must read as a thin control strip — not a SECOND thick
		   bar stacked under it (fb-ux-reader-header-too-tall-wco). Drop the block
		   padding to the minimum the controls need; the slim ghost-button box
		   carries the touch height. */
		padding-top: var(--space-1);
		padding-bottom: var(--space-1);
	}

	/* Drop the processing/repair overlay below the OS titlebar strip so it
	   centers over the visible reading pane (not under the band) and never paints
	   over the OS window controls (fb-bug-repairing-overlay-centers-viewport-not-
	   pane). Left inset is already the sidebar width from the base rule. */
	.reader-processing-overlay {
		top: var(--wco-strip-h, env(titlebar-area-height, 0px));
	}
}

/* ── iOS focus-zoom guard (mobile) ─────────────────────── */
/* iOS Safari auto-zooms when a focused control's font-size computes under
 * 16px. Reader-surface offenders at mobile widths: the dialogue relabel
 * input + merge selects (--text-sm ≈ 12.8px), and the edit-content textarea
 * whose var(--reader-font-size) is 0.9375rem (15px) when the user's reader
 * font pref is "small". max() keeps larger prefs untouched. This block sits
 * at the END of the file so it wins the same-specificity cascade. Pinch-zoom
 * stays enabled — input sizing only, no viewport scale limits (WCAG 1.4.4).
 * Keep this block LAST in the file.
 * (fb-bug-mobile-interaction-followups, feedback 93fd6741) */
@media (max-width: 767px) {
	.dialogue-relabel-input,
	.dialogue-merge-select {
		font-size: var(--text-base);
	}

	.reader-edit-content {
		font-size: max(var(--text-base), var(--reader-font-size, var(--text-md)));
	}
}
