/* Design tokens + component styles, ported from the federate.ai/coder prototype. */
:root {
	--smoke: oklch(0.141 0.005 285.823 / 0.7);
	--wp-muted: rgba(10, 12, 12, 0.55);
	--faint: rgba(10, 12, 12, 0.4);
	--hair: rgba(10, 12, 12, 0.1);
	--hair-strong: rgba(10, 12, 12, 0.28);
	--measure: 46rem;
	--pad: clamp(1.4rem, 5vw, 3rem);
}
.wp-root,
.wp-root * {
	box-sizing: border-box;
}
/* Nothing on this page should ever scroll sideways. `clip` rather than
     `hidden`: hidden would turn the element into a scroll container and
     break every position:sticky on the page (hero, TOC, diagram stages).
     Applied to body only — setting overflow on <html> makes <body> the
     scroller, which zeroes out window.scrollY and stops the site header
     from switching to its solid state on scroll. */
body {
	overflow-x: clip;
	max-width: 100%;
}
html {
	scroll-behavior: smooth;
}
.wp-root {
	color: var(--smoke);
	font-family: var(--font-body);
	font-size: clamp(1rem, 0.97rem + 0.2vw, 1.125rem);
	line-height: 1.65;
	letter-spacing: 0.01em;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}
.wp-root a {
	color: inherit;
}
::selection {
	background: #ff8067;
	color: var(--color-black);
}
#bar {
	position: fixed;
	top: 0;
	left: 0;
	height: 2px;
	width: 100%;
	background: linear-gradient(
		90deg,
		#f4dfd4 0%,
		#ffc5c5 33%,
		#f0b0c9 73%,
		#c4c4f7 100%
	);
	background-size: 100vw 100%;
	background-position: left;
	z-index: 200;
	clip-path: inset(0 100% 0 0);
	transition: clip-path 0.08s linear;
}
.eyebrow {
	font-family: var(--font-mono);
	font-weight: 500;
	font-size: 0.75rem;
	letter-spacing: -0.02em;
	color: var(--wp-muted);
}

/* pixel strip — brand color motif */

/* ---- Cover ---- */
/* Back to native `position: sticky` for the pin — a JS-driven
     fixed/absolute toggle (tried in between) reads/writes layout on every
     scroll event and can drift out of sync with the page's other scroll
     listeners (progress bar, TOC collapse, reveal-panel width), which
     showed up as it losing the pin on scroll-up. Sticky is handled by the
     browser's own compositor, so it can't have that class of bug — it's
     just as reliable scrolling up as down.
     .hero-stick is the spacer that reserves the scroll distance. RevealPanel
     (higher z-index, opaque background) slides up and covers it while it's
     pinned — same overall idea as the sticky CinematicHero + page-content
     on the Vossen wheel pages. Sized generously (280vh vs. the hero's own
     100vh) so the whole pin → narrow-panel-appears → widen → cover
     sequence plays out over a couple of screens' worth of scroll rather
     than a couple hundred pixels — a normal scroll flick was covering the
     entire effect in one motion, landing on an end state with nothing
     visibly in between. See RevealPanel.tsx for the matching stretch on
     the width animation itself. */
.hero-stick {
	position: relative;
	height: 220vh;
}
/* Pinned at top: var(--navh) and sized to calc(100vh - navh) — sits
     directly below the nav with no gap underneath (fills the rest of the
     viewport exactly) and no overlap at the top either (the nav isn't a
     floating overlay here, it's a fixed bar the hero docks under). This
     also matches the hero's natural resting offset (body's
     padding-top: navh), so nothing jumps when it engages/releases. */
.cover {
	position: sticky;
	top: var(--navh);
	z-index: 1;
	height: calc(100vh - var(--navh));
	background: #0a0c0c;
	color: #fff;
	display: flex;
	flex-direction: column;
	padding: clamp(1.6rem, 5vw, 3.2rem);
	border-bottom: 1px solid rgba(255, 255, 255, 0.12);
	overflow: hidden;
}
/* NOTE: this stays in vh on purpose. The pin maths couples three
     values — .cover's height, .hero-stick's 280vh spacer and
     .doc-shell's -120vh pull. On mobile Chrome vh is the LARGE viewport
     and svh the small one, so sizing the hero in svh while the spacer
     stays in vh leaves the hero short by the toolbar's height: the hero
     stops filling the screen and you can scroll it up before the panel
     arrives. All three must use the same unit. */
/* The hero BOX has to stay 100vh so it stays in step with the 220vh
     spacer and the -118vh panel pull. But on mobile 100vh is the LARGE
     viewport — the one you only get once the browser toolbars have
     scrolled away — so with the toolbar and the Android nav bar on
     screen, the bottom of the hero (the "A Coder Whitepaper" line) sits
     below the fold, hidden behind them.
     `100vh - 100svh` is exactly that lost height, so padding the content
     up by it keeps the box the same size while lifting everything inside
     clear of the browser chrome. Both units are equal on desktop and
     whenever the toolbars are hidden, so this is a no-op there. The
     safe-area inset covers the iOS home indicator on top of that. */
@supports (height: 100svh) {
	.cover {
		padding-bottom: calc(
			clamp(1.6rem, 5vw, 3.2rem) + (100vh - 100svh) +
				env(safe-area-inset-bottom, 0px)
		);
	}
}
.cover-mid .eyebrow {
	color: rgba(255, 255, 255, 0.55);
}
.cover-mid {
	position: relative;
	z-index: 1;
	flex: 1;
	display: flex;
	flex-direction: column;
	justify-content: center;
	max-width: none;
}
.cover h1 {
	font-weight: 500;
	letter-spacing: -0.025em;
	line-height: 1.02;
	font-size: clamp(2.5rem, 9.5vw, 6.75rem);
	margin: 0.15em 0 0.3em;
	color: #fff;
}
.cover .sub {
	font-size: clamp(1.05rem, 2.2vw, 1.375rem);
	line-height: 1.4;
	letter-spacing: 0.02em;
	color: oklch(1 0 0);
	opacity: 0.55;
	max-width: 34ch;
	font-weight: 400;
	margin: 0;
}
.cover-foot {
	position: relative;
	z-index: 1;
	display: flex;
	justify-content: flex-start;
	align-items: flex-end;
	gap: 1rem;
}

/* Hero mask video — see HeroMaskVideo.tsx for how the two dot-mask SVGs
     are wired up. Anchored to the right edge at the mask art's native
     aspect ratio (900:1125) so the dot pattern isn't stretched. */
.hero-mask-wrap {
	position: absolute;
	z-index: 0;
	top: 0;
	right: 0;
	height: 100%;
	aspect-ratio: 900/1125;
	pointer-events: none;
}
.hero-mask-svg {
	display: block;
	width: 100%;
	height: 100%;
}
.hero-mask-video {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	/* Mask the video through the animated dot pattern via CSS rather than an
	   SVG mask= attribute on the <foreignObject> wrapper: WebKit/Safari does
	   not apply SVG masks to foreignObject (the video rendered unmasked), but
	   it does honour a CSS mask on the video element itself. The mask lives
	   inline in HeroMaskVideo.tsx and its rects animate frame-by-frame. */
	-webkit-mask: url(#heroMaskMorph);
	mask: url(#heroMaskMorph);
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
}
/* The dot morph itself (rect x/y/width/height) is driven frame-by-frame
     from JS in HeroMaskVideo.tsx — see heroMaskMorph.ts for the matching
     logic. prefers-reduced-motion is also handled there (skips the rAF
     loop and holds on the first pattern). */
/* Mobile: keep the masked video — it's the signature of the page — and
     play it at full brightness. Only the horizontal offset changes: it
     shifts right so the dense middle of the dot field clears the
     headline. It must keep the base rule's top:0 / height:100% — pinning
     it to the bottom instead (with a height derived from a % width) left
     the pattern starting well below the nav on a tall phone hero. */
@media (max-width: 860px) {
	.hero-mask-wrap {
		right: -26%;
	}
	/* Copy drops to the bottom of the hero and sits on a dark scrim, so
       it reads cleanly over the (full-brightness) dot field above it.
       The scrim is ::after — a generated last child — so it paints over
       the mask at the same z-index while .cover-mid's z-index:1 keeps the
       text above it. */
	/* Copy sits at the bottom, with breathing room before the
       "A Coder Whitepaper" line rather than butting straight into it. */
	.cover-mid {
		justify-content: flex-end;
		padding-bottom: 1.5rem;
	}
	.cover::after {
		content: "";
		position: absolute;
		left: 0;
		right: 0;
		bottom: 0;
		height: 72%;
		pointer-events: none;
		z-index: 0;
		background: linear-gradient(
			to top,
			#0a0c0c 20%,
			rgba(10, 12, 12, 0.86) 46%,
			rgba(10, 12, 12, 0.55) 68%,
			rgba(10, 12, 12, 0) 100%
		);
	}
}
@media (max-width: 560px) {
	.hero-mask-wrap {
		right: -34%;
	}
}
.wordmark {
	font-weight: 500;
	font-size: 1.4rem;
	letter-spacing: -0.01em;
	text-transform: lowercase;
	color: var(--color-black);
}
.cover .meta {
	font-family: var(--font-mono);
	font-weight: 500;
	font-size: 0.75rem;
	letter-spacing: -0.02em;
	color: rgba(255, 255, 255, 0.55);
	text-align: left;
	line-height: 1.8;
}

/* The panel that scrolls up over the sticky hero. Width is driven by
     --reveal-inset (set in RevealPanel.tsx): narrower than the viewport
     while still below the fold, widening to full-bleed as it scrolls
     into place. Needs its own opaque background + higher z-index than
     .cover for the "covers the hero" effect to actually read. */
/* The -120vh margin-top is the key to the whole effect: it pulls the
     panel up so it OVERLAPS the hero's 120vh pin window (220vh spacer −
     100vh hero) instead of starting after it. Without this, the pin
     window and the panel's arrival are sequenced back-to-back — the
     entire pinned phase scrolls by with nothing visibly happening, and
     the hero releases at the exact moment the panel reaches the bottom
     of the viewport, so they scroll up together and the panel never
     rides over a pinned hero. With it, the panel enters the viewport
     immediately as scrolling starts, slides up over the still-pinned
     hero, and fully covers it right as the pin window ends. */
.doc-shell {
	position: relative;
	z-index: 2;
	background: #fff;
	width: 100%;
	margin: -118vh auto 0;
	padding-bottom: 120px;
	/* The reveal clips the panel's left/right edges (uncovering the pinned
	   dark hero in the gutters) instead of animating its width. Changing
	   width reflows the whole document subtree on every scroll frame, which
	   is what made the reveal feel clunky and lag the scroll; clip-path is a
	   compositor/paint op, so it stays smooth and both sides move at exactly
	   the same rate in and out. --reveal-inset is the total gutter (set in
	   RevealPanel.tsx), split evenly per side. */
	clip-path: inset(0 calc(var(--reveal-inset, 60px) / 2));
	will-change: clip-path;
}

/* ---- Doc layout ---- */
/* The sticky TOC's containing block is its grid row, which ends with
     the whitepaper content — so it releases exactly there and scrolls up
     with the page. Keep the bottom padding small: anything larger leaves
     a dead gap between the released TOC and the pre-footer. */
.doc {
	max-width: 1280px;
	margin: 0 auto;
	padding: 0 var(--pad);
	display: grid;
	grid-template-columns: 216px minmax(0, 1fr);
	gap: clamp(2rem, 5vw, 4.5rem);
}
.side {
	position: sticky;
	top: calc(var(--navh) + 24px);
	align-self: start;
	max-height: calc(100vh - var(--navh) - 24px);
	overflow: visible;
	padding: clamp(2.6rem, 4.5vw, 3.6rem) 0 0;
	scrollbar-width: thin;
	z-index: 2;
}

/* ---- Collapsing TOC (mechanic ported from workos.com/blog) ---- */
.side-inner {
	--toc-dur: 0.25s;
	--toc-ease: ease;
	--toc-line-w: 18px;
	--toc-line-h: 2px;
	--toc-line-color: var(--hair-strong);
	--toc-line-color-active: var(--color-ember);
	transition: transform var(--toc-dur) var(--toc-ease);
	will-change: transform;
}
.side-inner.toc-collapsed {
	transform: translateX(var(--collapse-shift, 0px));
}
.side-inner .lab {
	font-family: var(--font-mono);
	font-weight: 500;
	font-size: 0.75rem;
	letter-spacing: -0.02em;
	color: var(--wp-muted);
	margin-bottom: 1.6rem;
	transform-origin: left center;
	transition:
		opacity var(--toc-dur) var(--toc-ease),
		transform var(--toc-dur) var(--toc-ease);
}
.toc-collapsed .lab {
	opacity: 0;
	transform: scale(0.4);
}
.toc-list {
	list-style: none;
	margin: 0;
	padding: 0;
}
.toc-item {
	display: flex;
	align-items: start;
	padding-top: 0.85rem;
}
.toc-item:first-child {
	padding-top: 0;
}
.toc-sub {
	padding-left: 1.05rem;
	transition: padding-left var(--toc-dur) var(--toc-ease);
}
.toc-collapsed .toc-sub {
	padding-left: 0;
}
.toc-collapsed:hover .toc-sub {
	padding-left: 1.05rem;
}
.toc-a {
	position: relative;
	display: flex;
	align-items: center;
	text-decoration: none;
	color: var(--wp-muted);
	background: #fff;
	font-weight: 500;
	font-size: 0.875rem;
	line-height: 1.35;
	letter-spacing: -0.005em;
	min-height: var(--expanded-link-height, auto);
	height: var(--expanded-link-height, auto);
	transform-origin: left center;
	padding: 0.21rem 0 0.21rem 1.05rem;
	transition:
		color 0.15s,
		transform var(--toc-dur) var(--toc-ease),
		height var(--toc-dur) var(--toc-ease);
}
.toc-a:hover .toc-text {
	color: var(--color-black);
}
.toc-item.active > .toc-a {
	color: var(--color-black);
}
.toc-a::before {
	content: "";
	position: absolute;
	left: 0;
	top: 50%;
	transform: translateY(-50%);
	width: 5px;
	height: 7px;
	background: var(--color-black);
	opacity: 0;
	transition: opacity var(--toc-dur) var(--toc-ease);
}
.toc-item.active .toc-a::before {
	opacity: 1;
}

.toc-line {
	position: absolute;
	left: 1.05rem;
	top: calc(50% - var(--toc-line-h)/2);
	opacity: 0;
	width: var(--toc-line-w);
	height: var(--toc-line-h);
	background: var(--toc-line-color);
	border-radius: var(--toc-line-h);
	transform: scale(
		calc(var(--expanded-link-width, 60px) / var(--toc-line-w)),
		5
	);
	transform-origin: left center;
	will-change: transform;
	transition:
		transform var(--toc-dur) var(--toc-ease),
		opacity var(--toc-dur) var(--toc-ease),
		background-color var(--toc-dur) var(--toc-ease);
}
.toc-text {
	transform-origin: left center;
	will-change: transform;
	transition:
		transform var(--toc-dur) var(--toc-ease),
		opacity var(--toc-dur) var(--toc-ease),
		color 0.15s;
}
.toc-text-inner {
	display: inline;
}
.toc-collapsed .toc-line {
	transform: scaleX(1);
	opacity: 1;
}
.toc-collapsed .toc-item:not(.active) .toc-text {
	transform: scale(
		calc(var(--toc-line-w) / var(--expanded-link-width, 60px)),
		0.2
	);
	opacity: 0;
}
.toc-collapsed .toc-item.active .toc-line {
	opacity: 0;
}
.toc-collapsed .toc-item.active .toc-a::before {
	opacity: 0;
}
.toc-collapsed .toc-item.active .toc-text {
	transform: scale(1);
	opacity: 1;
	color: var(--color-black);
}
.toc-collapsed:hover .toc-line {
	transform: scale(
		calc(var(--expanded-link-width, 60px) / var(--toc-line-w)),
		5
	);
	opacity: 0;
}
.toc-collapsed:hover .toc-item .toc-text {
	transform: scale(1);
	opacity: 1;
}
.toc-collapsed:hover .toc-item.active .toc-a::before {
	opacity: 1;
}
.mtoc {
	display: none;
}
.content {
	min-width: 0;
}
.content > section:last-of-type {
	padding-bottom: 0;
}
.content > section {
	position: relative;
	padding-block: clamp(2.6rem, 4.5vw, 3.6rem);
}
.content > section + section {
	border-top: 1px solid var(--hair);
}
.wp-root strong {
	font-weight: 500;
	color: var(--color-black);
}

/* ---- Diagrams ---- */
.diag {
	margin: 2.4rem 0 0.6rem;
	max-width: var(--measure);
}
/* Scroll-told diagram (stack story): tall wrapper gives the scroll
     distance, sticky stage pins the artwork while the phases play. */
.diag-scroll {
	height: 260vh;
	margin: 1.2rem 0;
	/* Isolate each diagram's layout so a relayout inside one tall pinned
	   track (or elsewhere on the page) doesn't force the others to reflow. */
	contain: layout;
}
/* longer track for chaptered stories — more dwell per chapter */
.diag-scroll.diag-long {
	height: 460vh;
}
.diag-stick {
	position: sticky;
	top: var(--navh);
	height: calc(100vh - var(--navh));
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	justify-content: center;
}
/* Card hangs 32px past the text container on both sides, and scales up
     as the story plays (transform set from StackDiagram's scroll loop). */
/* Zoom-on-scroll: the figure is laid out at its LARGEST size (1.15x) and
     the scroll loop scales it DOWN from 0.87 back up to exactly 1. Scaling
     a rasterised layer down stays crisp — blur only happens upscaling past
     native size — and at full zoom it's 1:1 pixels. */
/* Default: the card fills the text column exactly. The 1.15x bleed past
     the column (below) only kicks in once the viewport is wide enough to
     absorb it — between ~860px and 1180px the content column sits offset
     to the right of the sidebar gutter, so a fixed 920px card runs off
     the right edge of the page and gives the document a horizontal
     scrollbar. */
.diag-stick .diag {
	width: 100%;
	max-width: none;
	margin: 0;
	transform-origin: 50% 50%;
	will-change: transform;
}
@media (min-width: 1180px) {
	.diag-stick .diag {
		width: calc((var(--measure) + 64px) * 1.15);
		margin-left: calc((var(--measure) - (var(--measure) + 64px) * 1.15) / 2);
	}
}
/* Narrow screens: the sticky scroll story is off (see staticMode.ts —
     JS adds .diag-static), so the figure sits inline. The 1400-unit
     viewBox would shrink the labels to a few px at phone width, so the
     SVG holds a legible minimum width and the figure pans horizontally
     instead — same treatment as the wide tables. No negative-margin
     bleed here either: at these widths it pushed past the viewport and
     produced a horizontal scrollbar on the whole page. */
.diag-static .diag {
	transform: none !important;
}
.diag-stick .diag svg {
	max-height: calc(100vh - var(--navh) - 7rem);
}
.diag-scroll.diag-static {
	height: auto;
}
.diag-static .diag-stick {
	position: static;
	height: auto;
	display: block;
}
.diag svg {
	width: 100%;
	height: auto;
	display: block;
}

/* NOTE: this block must stay AFTER the base .diag rules above. Equal
     specificity means source order decides, and when it sat earlier the
     base `max-height` won — which clamped tall portrait diagrams by
     height, shrinking them well inside the screen width. */
@media (max-width: 860px) {
	/* Full-bleed: the card escapes the document's side padding and uses
       the whole screen width, which is ~14% more room for the artwork.
       Derived from the element's own width rather than 100vw, so it can't
       overshoot by the scrollbar width on a narrow desktop window. */
	.diag-stick .diag,
	.diag {
		width: calc(100% + var(--pad) * 2);
		margin-left: calc(var(--pad) * -1);
		max-width: none;
	}
	/* Diagrams scale to fit — no horizontal scroll box. Where a figure is
       a left-to-right series, its component redraws stacked at this width
       (narrow, tall viewBox) so the type stays readable. */
	.diag svg {
		width: 100%;
		height: auto;
	}
	/* Portrait diagrams are sized by width, so they run edge to edge.
       The cap is only a backstop against overflowing the pinned stage on
       short phones — far looser than the desktop 7rem allowance, which
       was clamping them by height and pulling them in from the edges. */
	.diag-stick .diag svg {
		max-height: calc(100vh - var(--navh) - 2.5rem);
	}
	.diag figcaption {
		padding: 0 var(--pad);
	}
}
.diag text {
	font-family: var(--font-mono);
	font-weight: 500;
	letter-spacing: -0.01em;
}
.diag .bt {
	font-family: var(--font-body);
	font-weight: 500;
}
.diag .cap {
	font-size: 20px;
	fill: var(--color-black);
}
.diag .capn {
	font-family: var(--font-body);
	font-weight: 400;
	font-size: 18px;
	fill: rgba(10, 12, 12, 0.55);
	letter-spacing: 0.01em;
}
.diag figcaption {
	font-family: var(--font-mono);
	font-weight: 500;
	font-size: 0.72rem;
	letter-spacing: -0.01em;
	color: var(--faint);
	margin-top: 1rem;
	line-height: 1.6;
}
.diag.dark {
	background: var(--color-cinder);
	border-radius: 5px;
	padding: clamp(1rem, 3vw, 1.8rem);
}
.diag.dark figcaption {
	color: rgba(248, 242, 241, 0.5);
}
.diag.dark .cap {
	fill: #fff;
}
.diag.dark .capn {
	fill: rgba(255, 255, 255, 0.55);
}

/* ---- Section lists ---- */
h3.sub + .acc {
	margin-top: 0.9rem;
}
.acc {
	margin: 1.8rem 0 2.2rem;
	max-width: var(--measure);
	border-top: 1px solid var(--hair);
}
.ai {
	display: grid;
	grid-template-columns: 2.6ch minmax(0, 1fr) auto;
	gap: 0 0.9rem;
	align-items: baseline;
	padding: 0.95rem 0;
	border-bottom: 1px solid var(--hair);
	text-decoration: none;
	color: inherit;
}
.ai .n {
	font-family: var(--font-mono);
	font-weight: 500;
	font-size: 0.72rem;
	color: var(--wp-muted);
}
.ai .t {
	font-weight: 500;
	color: var(--color-black);
	letter-spacing: -0.005em;
}
.ai .d {
	display: block;
	font-weight: 400;
	font-size: 0.95rem;
	line-height: 1.55;
	color: var(--smoke);
	margin-top: 0.35rem;
}
.ai .x {
	font-family: var(--font-mono);
	font-weight: 500;
	color: var(--faint);
	transition:
		transform 0.15s,
		color 0.15s;
}
a.ai:hover .t {
	color: var(--color-twilight);
}
a.ai:hover .x {
	color: var(--color-twilight);
	transform: translateX(4px);
}

/* ---- Tables ---- */
/* The native scrollbar is hidden and redrawn by ScrollX (Section.tsx) —
     see the note there for why it can't be styled directly. */
.tw-wrap {
	margin: 1.7rem 0 1.6rem;
	max-width: var(--measure);
}
.tw {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	overscroll-behavior-x: contain;
	scrollbar-width: none;
	-ms-overflow-style: none;
}
.tw::-webkit-scrollbar {
	display: none;
	width: 0;
	height: 0;
}
.tw-bar {
	position: relative;
	height: 3px;
	margin-top: 0.9rem;
	border-radius: 99px;
	background: var(--hair);
	cursor: pointer;
	touch-action: none;
}
.tw-bar span {
	position: absolute;
	top: -2px;
	height: 7px;
	min-width: 32px;
	border-radius: 99px;
	background: var(--hair-strong);
	transition: background 0.15s;
}
.tw-bar:hover span {
	background: var(--color-black);
}

/* ---- Incident (card that flips dark while in view) ---- */
/* Wrap + escape field: hero-style halftone squares that spread outward
     from behind the dark card into the surrounding white as you scroll —
     data leaving the container. */
.incident-wrap {
	position: relative;
}
.incident-field {
	position: absolute;
	pointer-events: none;
	z-index: 0;
}
/* The escape field needs gutters beside the card to read at all; at
     tablet width and below the card fills the measure, so it's hidden
     rather than rendered as a meaningless sliver. */
@media (max-width: 860px) {
	.incident-field {
		display: none;
	}
}
.incident-wrap .incident {
	position: relative;
	z-index: 1;
}
/* Starts as a plain light card; .is-dark is toggled by an
     IntersectionObserver in Section.tsx while the block is anywhere in the
     viewport, and removed again once it's fully scrolled past — so it reads
     as a deliberate callout rather than a static dark box. */
/* no visible border — the card should butt cleanly against the dot
     field with nothing ringing it */
.incident {
	background: #fff;
	color: var(--color-black);
	border-radius: 5px;
	padding: clamp(1.7rem, 4vw, 2.6rem);
	border: 1px solid transparent;
	transition:
		background-color 0.6s ease,
		border-color 0.6s ease;
}
.incident .snum {
	color: var(--wp-muted);
	transition: color 0.6s ease;
}
.incident h2 {
	color: var(--color-black);
	transition: color 0.6s ease;
}
.incident p {
	color: var(--smoke);
	transition: color 0.6s ease;
}
.incident strong {
	color: var(--color-black);
	transition: color 0.6s ease;
}
.incident .tag {
	display: inline-block;
	font-family: var(--font-mono);
	font-weight: 500;
	font-size: 0.68rem;
	letter-spacing: -0.01em;
	color: var(--color-ember);
	border: 1px solid var(--hair-strong);
	border-radius: 100px;
	padding: 0.35rem 0.8rem;
	margin-bottom: 1.3rem;
	transition:
		color 0.6s ease,
		border-color 0.6s ease;
}
.incident .src {
	font-family: var(--font-mono);
	font-weight: 500;
	font-size: 0.72rem;
	letter-spacing: -0.01em;
	line-height: 1.7;
	color: var(--faint);
	margin-top: 1.5rem;
	padding-top: 1.1rem;
	border-top: 1px solid var(--hair);
	max-width: 46rem;
	transition:
		color 0.6s ease,
		border-color 0.6s ease;
}

.incident.is-dark {
	background: var(--color-cinder);
	border-color: transparent;
}
.incident.is-dark .snum {
	color: #c4c4f7;
}
.incident.is-dark h2 {
	color: #fff;
}
.incident.is-dark p {
	color: rgba(248, 242, 241, 0.8);
}
.incident.is-dark strong {
	color: #fff;
}
.incident.is-dark .tag {
	color: #c4c4f7;
	border-color: rgba(196, 196, 247, 0.45);
}
.incident.is-dark .src {
	color: rgba(248, 242, 241, 0.5);
	border-top-color: rgba(255, 255, 255, 0.14);
}

:focus-visible {
	outline: 2px solid var(--color-twilight);
	outline-offset: 3px;
	border-radius: 5px;
}

@media (max-width: 860px) {
	.doc {
		grid-template-columns: 1fr;
		gap: 0;
	}
	.side {
		display: none;
	}
	.mtoc {
		display: block;
		margin: 0;
		padding: clamp(2rem, 6vw, 3rem) 0 0;
	}
	.mtoc summary {
		font-family: var(--font-mono);
		font-weight: 500;
		font-size: 0.75rem;
		letter-spacing: -0.02em;
		color: var(--wp-muted);
		cursor: pointer;
		padding: 0.6rem 0;
		border-bottom: 1px solid var(--hair);
	}
	.mtoc ol {
		list-style: none;
		margin: 0.6rem 0 0;
		padding: 0;
	}
	.mtoc a {
		display: flex;
		gap: 0.7rem;
		text-decoration: none;
		color: var(--wp-muted);
		font-weight: 500;
		font-size: 1rem;
		padding: 0.5rem 0;
		border-bottom: 1px solid var(--hair);
	}
	.mtoc a .n {
		font-family: var(--font-mono);
		font-size: 0.78rem;
		color: var(--faint);
		min-width: 2.2ch;
	}
	.content > section:first-of-type {
		border-top: 1px solid var(--hair);
	}
}
/* Landscape phones can be wider than the 860px breakpoint (932x430 on a
     Pro Max) but far too short for a sticky rail — it ends up taller than
     the viewport and collides with the content. Drop it whenever the
     viewport is short, and fall back to the mobile accordion. */
@media (max-height: 560px) {
	.doc {
		grid-template-columns: 1fr;
		gap: 0;
	}
	.side {
		display: none;
	}
	.mtoc {
		display: block;
		margin: 0;
		padding: clamp(2rem, 6vw, 3rem) 0 0;
	}
	.mtoc summary {
		font-family: var(--font-mono);
		font-weight: 500;
		font-size: 0.75rem;
		letter-spacing: -0.02em;
		color: var(--wp-muted);
		cursor: pointer;
		padding: 0.6rem 0;
		border-bottom: 1px solid var(--hair);
	}
	.mtoc ol {
		list-style: none;
		margin: 0.6rem 0 0;
		padding: 0;
	}
	.mtoc a {
		display: flex;
		gap: 0.7rem;
		text-decoration: none;
		color: var(--wp-muted);
		font-weight: 500;
		font-size: 1rem;
		padding: 0.5rem 0;
		border-bottom: 1px solid var(--hair);
	}
	.mtoc a .n {
		font-family: var(--font-mono);
		font-size: 0.78rem;
		color: var(--faint);
		min-width: 2.2ch;
	}
}

@media (max-width: 560px) {
	.cover-foot {
		flex-direction: column;
		align-items: flex-start;
		gap: 1.1rem;
	}
	.cover .meta {
		text-align: left;
	}
}
/* --navh mirrors the fixed site header height (see the page's
     headerOptions): 64px by default, 80px at the desktop-nav breakpoint.
     It offsets the pinned hero, sticky TOC and diagram stages below the
     header, and positions the reading progress bar just under it. */
:root {
	--navh: 64px;
}
@media (min-width: 1100px) {
	:root {
		--navh: 80px;
	}
}
.wp-root {
	padding-top: var(--navh);
}
#bar {
	top: var(--navh);
}
.eyebrow {
	font-family: var(--font-mono);
	font-weight: 500;
	font-size: 0.75rem;
	letter-spacing: -0.02em;
	color: var(--wp-muted);
}

/* Reduced motion. The scroll-told diagrams, the hero dot-mask morph and
   the reveal panel already jump straight to their finished state in JS
   when prefers-reduced-motion is set (and the hero video is paused on its
   first frame). This handles what's left — the CSS transitions (the TOC
   collapse/expand, the incident card's dark flip, the reading progress
   bar) and smooth scrolling — collapsing them so everything lands on its
   end state instantly instead of animating. Scoped to .wp-root so the
   global site header/footer keep their own behaviour. */
@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}
	.wp-root *,
	.wp-root *::before,
	.wp-root *::after {
		transition-duration: 0.01ms !important;
		transition-delay: 0ms !important;
		animation-duration: 0.01ms !important;
		animation-delay: 0ms !important;
		animation-iteration-count: 1 !important;
	}
}

/* The print table of contents is hidden on screen (the page has its own
   sticky + mobile TOC) and only shown in the print layout below. */
.print-toc {
	display: none;
}

/* Print: render the page as a flowing whitepaper PDF. This stylesheet only
   loads on the AI Operating Layer route, so these rules are page-scoped.
   The scroll-driven pinning/animation is unwound so nothing is clipped or
   stuck mid-animation, the interactive chrome is dropped, and the diagrams
   are jumped to their finished state in JS (addPrintFinalState in each
   diagram, fired on beforeprint) so the complete artwork prints. */
@media print {
	/* Preserve the brand backgrounds/colours (dark cover, incident callout,
	   diagram plates) instead of letting the browser drop them for print. */
	.wp-root,
	.wp-root * {
		-webkit-print-color-adjust: exact !important;
		print-color-adjust: exact !important;
	}

	/* Drop the site nav/footer and the page's interactive-only chrome. */
	#site-header,
	footer,
	#bar,
	.side,
	.mtoc,
	.hero-mask-wrap,
	.incident-field {
		display: none !important;
	}

	html {
		scroll-behavior: auto;
	}
	body {
		overflow: visible !important;
	}
	.wp-root {
		padding-top: 0 !important;
	}

	/* Hero becomes a static cover page. */
	.hero-stick {
		height: auto !important;
	}
	.cover {
		position: static !important;
		height: auto !important;
		break-after: page;
		padding: 2.5rem;
		/* Print the cover on white with dark text instead of the on-screen
		   full-bleed black background — saves ink and keeps it readable. */
		background: #fff !important;
		color: var(--color-black) !important;
		border-bottom: 1px solid var(--hair);
	}
	.cover::after {
		display: none !important;
	}
	.cover h1 {
		color: var(--color-black) !important;
	}
	.cover .sub {
		color: var(--smoke) !important;
		opacity: 1 !important;
	}
	.cover .eyebrow,
	.cover-mid .eyebrow,
	.cover .meta {
		color: var(--wp-muted) !important;
	}

	/* Contents page (after the cover). */
	.print-toc {
		display: block;
		break-after: page;
		padding-top: 0.5rem;
	}
	.print-toc-title {
		font-family: var(--font-mono);
		font-weight: 500;
		font-size: 0.8rem;
		letter-spacing: -0.02em;
		color: var(--wp-muted);
		margin: 0 0 1.6rem;
	}
	.print-toc-list {
		list-style: none;
		margin: 0;
		padding: 0;
		max-width: var(--measure);
	}
	.print-toc-item {
		display: flex;
		gap: 1rem;
		align-items: baseline;
		padding: 0.55rem 0;
		border-bottom: 1px solid var(--hair);
		font-weight: 500;
		font-size: 1.05rem;
		color: var(--color-black);
		break-inside: avoid;
	}
	.print-toc-sub {
		padding-left: 2.1rem;
		font-weight: 400;
		font-size: 0.98rem;
		color: var(--smoke);
	}
	.print-toc-n {
		flex: none;
		min-width: 2ch;
		font-family: var(--font-mono);
		font-weight: 500;
		font-size: 0.72rem;
		color: var(--wp-muted);
	}
	.print-toc-label {
		color: inherit;
		text-decoration: none;
	}

	/* Reveal panel: no clip, full width, no negative pull over the hero. */
	.doc-shell {
		clip-path: none !important;
		width: 100% !important;
		margin: 0 !important;
	}

	/* Single column, full width — the sticky TOC rail is hidden above. */
	.doc {
		display: block !important;
		max-width: none !important;
		padding: 0 !important;
	}
	.content {
		min-width: 0;
	}
	.content > section {
		padding-block: 1.4rem !important;
	}

	/* Unpin the scroll-told diagram stages and show them at natural size;
	   addPrintFinalState() has already drawn each at its finished state. */
	.diag-scroll,
	.diag-scroll.diag-long {
		height: auto !important;
	}
	.diag-stick {
		position: static !important;
		height: auto !important;
		display: block !important;
	}
	.diag-stick .diag,
	.diag {
		transform: none !important;
		width: 100% !important;
		max-width: var(--measure);
		margin: 1.4rem 0 !important;
	}
	.diag svg,
	.diag-stick .diag svg {
		max-height: none !important;
	}

	/* Incident: print light-on-white (ink-friendly) regardless of the
	   on-screen scroll-driven dark flip. !important beats the .incident.is-dark
	   rules whether or not that class is present at print time. */
	.incident {
		background: #fff !important;
		color: var(--color-black) !important;
		border: 1px solid var(--hair) !important;
	}
	.incident .snum {
		color: var(--wp-muted) !important;
	}
	.incident h2 {
		color: var(--color-black) !important;
	}
	.incident p {
		color: var(--smoke) !important;
	}
	.incident strong {
		color: var(--color-black) !important;
	}
	.incident .tag {
		color: var(--color-ember) !important;
		border-color: var(--hair-strong) !important;
	}
	.incident .src {
		color: var(--faint) !important;
		border-top-color: var(--hair) !important;
	}

	/* Show the full table — no horizontal scroll box or custom scrollbar. */
	.tw {
		overflow: visible !important;
	}
	.tw-bar {
		display: none !important;
	}

	/* Pagination: keep headings with their content and don't split figures,
	   tables, quotes or accordions across pages. */
	h2,
	h3.sub {
		break-after: avoid;
	}
	figure,
	.diag,
	.tw-wrap,
	table,
	.acc,
	blockquote {
		break-inside: avoid;
	}

	@page {
		margin: 16mm;
	}
}
