/* ==========================================================================
   John Ehlen — main stylesheet
   Dark, editorial, a little bit terminal. Mobile first.
   ========================================================================== */

@font-face {
	font-family: "Geist";
	src: url("../fonts/geist-latin-wght-normal.woff2") format("woff2");
	font-weight: 100 900;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Geist Mono";
	src: url("../fonts/geist-mono-latin-wght-normal.woff2") format("woff2");
	font-weight: 100 900;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Instrument Serif";
	src: url("../fonts/instrument-serif-latin-400-normal.woff2") format("woff2");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Instrument Serif";
	src: url("../fonts/instrument-serif-latin-400-italic.woff2") format("woff2");
	font-weight: 400;
	font-style: italic;
	font-display: swap;
}

:root {
	--bg: #0a0b0d;
	--bg-2: #111318;
	--bg-3: #181b21;
	--fg: #ecebe6;
	--fg-2: #b9bab5;
	--muted: #80848c;
	--line: rgb(255 255 255 / 0.09);
	--line-2: rgb(255 255 255 / 0.16);
	--accent: #c8ff3e;
	--accent-2: #7cf0c3;
	--accent-ink: #0a0b0d;
	--warn: #ffb547;
	--bad: #ff5d5d;
	--paper: #ebe8e0;
	--ink: #121316;

	--sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
	--mono: "Geist Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
	--serif: "Instrument Serif", "Iowan Old Style", Georgia, serif;

	--gutter: clamp(16px, 4vw, 48px);
	--max: 1360px;
	--radius: 18px;
	--radius-lg: 28px;
	--ease: cubic-bezier(0.22, 1, 0.36, 1);
	--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
	--header-h: 76px;

	color-scheme: dark;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-padding-top: calc(var(--header-h) + 8px); }
html:not(.lenis) { scroll-behavior: smooth; }
body {
	margin: 0;
	background: var(--bg);
	color: var(--fg);
	font-family: var(--sans);
	font-size: clamp(16px, 0.35vw + 14.8px, 18px);
	line-height: 1.6;
	font-feature-settings: "ss01", "cv11";
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	overflow-x: clip;
}
img, svg, video, canvas { display: block; max-width: 100%; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { margin: 0; font-weight: 500; line-height: 1.05; letter-spacing: -0.03em; text-wrap: balance; }
p { margin: 0 0 1em; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; list-style: none; }
dl, dd { margin: 0; }
kbd { font-family: var(--mono); font-size: 0.75em; padding: 0.1em 0.45em; border: 1px solid var(--line-2); border-radius: 6px; }
::selection { background: var(--accent); color: var(--accent-ink); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
[hidden] { display: none !important; }

.sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.skip { position: fixed; left: 12px; top: -60px; z-index: 1000; background: var(--accent); color: var(--accent-ink); padding: 10px 16px; border-radius: 10px; transition: top 0.2s; }
.skip:focus { top: 12px; }

.wrap { width: 100%; max-width: var(--max); margin-inline: auto; padding-inline: var(--gutter); }
.wrap--narrow { max-width: 820px; }
.mono { font-family: var(--mono); font-size: 0.78rem; letter-spacing: 0.02em; }

/* ---------- Atoms ---------- */
.eyebrow {
	display: inline-flex; align-items: center; gap: 0.6em;
	font-family: var(--mono); font-size: 0.8rem; font-weight: 450; letter-spacing: 0.14em; text-transform: uppercase;
	color: var(--muted); margin: 0 0 1.4rem;
}
.eyebrow .num { color: var(--accent); }
.eyebrow a:hover { color: var(--fg); }
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 4px rgb(200 255 62 / 0.14); flex: none; }

.btn {
	--bg-btn: var(--bg-3); --fg-btn: var(--fg);
	position: relative; display: inline-flex; align-items: center; gap: 0.75em;
	padding: 0.95em 1.1em 0.95em 1.4em; border-radius: 999px;
	background: var(--bg-btn); color: var(--fg-btn);
	font-weight: 500; font-size: 0.95rem; line-height: 1; white-space: nowrap;
	border: 1px solid transparent; isolation: isolate; overflow: hidden;
	transition: transform 0.4s var(--ease), background-color 0.6s, color 0.6s, border-color 0.6s;
}
.btn svg { width: 1.6em; height: 1.6em; padding: 0.3em; border-radius: 50%; background: var(--fg-btn); color: var(--bg-btn); transition: transform 0.4s var(--ease); }
.btn:hover svg { transform: rotate(45deg); }
.btn::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; background: var(--accent); transform: translateY(101%); transition: transform 1s var(--ease); }
.btn:hover::before { transform: translateY(0); }
.btn:hover { color: var(--accent-ink); }
.btn:hover svg { background: var(--accent-ink); color: var(--accent); }
.btn--accent { --bg-btn: var(--accent); --fg-btn: var(--accent-ink); }
.btn--accent::before { background: var(--fg); }
.btn--light { --bg-btn: var(--fg); --fg-btn: var(--bg); }
.btn--ghost { --bg-btn: transparent; border-color: var(--line-2); }
.btn--ghost svg { color: var(--bg); }
.btn--sm { font-size: 0.85rem; padding: 0.7em 0.8em 0.7em 1.1em; }
.btn[disabled] { opacity: 0.4; pointer-events: none; }

.link { position: relative; display: inline-flex; align-items: center; gap: 0.4em; color: var(--fg); background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat; transition: background-size 0.4s var(--ease); padding-bottom: 2px; }
.link:hover { background-size: 100% 1px; }
.link svg { width: 1.05em; height: 1.05em; }

.tags { display: flex; flex-wrap: wrap; gap: 6px; }
.tags li { font-family: var(--mono); font-size: 0.76rem; letter-spacing: 0.03em; padding: 0.35em 0.75em; border-radius: 999px; border: 1px solid var(--line-2); color: var(--fg-2); }

.chip { font-family: var(--mono); font-size: 0.72rem; padding: 0.5em 0.9em; border-radius: 999px; border: 1px solid var(--line-2); color: var(--fg); transition: background 0.2s, color 0.2s, border-color 0.2s; }
.chip:hover { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.badge { font-family: var(--mono); font-size: 0.68rem; padding: 0.25em 0.6em; border-radius: 6px; background: rgb(200 255 62 / 0.12); color: var(--accent); }

.status { display: inline-flex; align-items: center; gap: 0.6em; }
.status__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); flex: none; animation: pulse 2.4s infinite; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgb(200 255 62 / 0.5); } 70% { box-shadow: 0 0 0 8px rgb(200 255 62 / 0); } 100% { box-shadow: 0 0 0 0 rgb(200 255 62 / 0); } }

/* ---------- Overlays: grain, progress ---------- */
.grain {
	position: fixed; inset: -50%; z-index: 90; pointer-events: none; opacity: 0.05;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
	animation: grain 1.2s steps(6) infinite;
}
@keyframes grain { 0%,100% { transform: translate(0,0); } 20% { transform: translate(-3%,2%); } 40% { transform: translate(2%,-4%); } 60% { transform: translate(-4%,-2%); } 80% { transform: translate(3%,3%); } }

/* Reading progress runs along the bottom edge of the header strip, over its border, once the page scrolls. */
.progress { position: fixed; top: calc(var(--hdr-b, 0px) - 2px); left: 0; right: 0; height: 2px; z-index: 120; pointer-events: none; opacity: 0; transition: opacity 0.25s; }
.is-scrolled-page .progress { opacity: 1; }
.progress span { display: block; height: 100%; background: var(--accent); transform-origin: 0 50%; transform: scaleX(var(--p, 0)); }


/* ---------- Header / nav ---------- */
/* Always on screen. Once the page scrolls, a solid, blurred strip sits behind the nav so
   content never shows through. It's a pseudo-element because a backdrop-filter on the
   header itself would trap the fixed mobile menu inside the header's box. */
.site-header { position: fixed; top: 0; left: 0; right: 0; z-index: 100; padding: 14px var(--gutter); }
.site-header::before {
	content: ""; position: absolute; inset: 0; z-index: -2; pointer-events: none;
	background: rgb(10 11 13 / 0.9); border-bottom: 1px solid var(--line);
	backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
	opacity: 0; transition: opacity 0.25s;
}
.site-header.is-scrolled::before { opacity: 1; }
.nav {
	max-width: calc(var(--max) - 2 * var(--gutter) + 40px); margin-inline: auto;
	display: flex; align-items: center; justify-content: space-between; gap: 1rem;
	padding: 8px 8px 8px 14px; border-radius: 999px;
	background: rgb(17 19 24 / 0.62); border: 1px solid var(--line);
	backdrop-filter: blur(16px) saturate(140%); -webkit-backdrop-filter: blur(16px) saturate(140%);
}
.nav__brand { display: inline-flex; align-items: center; gap: 10px; font-weight: 600; letter-spacing: -0.02em; }
.nav__mark { display: block; flex: none; width: auto; height: 38px; transform: translateY(-1px); }
.nav__logo { display: block; flex: none; width: 172px; height: 30px; transition: opacity 0.3s; }
.nav__logo.is-waiting { opacity: 0; }
.js .nav__name--nojs, .no-js .nav__logo { display: none; }
@media (max-width: 400px) { .nav__logo { width: 140px; height: 25px; } .nav__mark { height: 32px; } }
@media (max-width: 340px) { .nav__logo { width: 122px; height: 22px; } }
.nav__links { display: none; gap: 2px; }
.nav__links a { display: block; padding: 0.55em 1em; white-space: nowrap; border-radius: 999px; font-size: 0.9rem; color: var(--fg-2); transition: color 0.2s, background 0.2s; }
.nav__links a:hover, .nav__links a.is-active { color: var(--fg); background: rgb(255 255 255 / 0.06); }
.nav__links a.is-active { box-shadow: inset 0 -2px 0 -0px transparent; }
.nav__actions { display: flex; align-items: center; gap: 8px; }
.nav__actions .btn { display: none; }
.nav__burger { width: 44px; height: 44px; border-radius: 50%; background: var(--fg); display: grid; place-content: center; gap: 5px; }
.nav__burger span:not(.sr-only) { display: block; width: 18px; height: 1.5px; background: var(--bg); transition: transform 0.4s var(--ease); }
.nav__burger[aria-expanded="true"] span:nth-of-type(2) { transform: translateY(3.25px) rotate(45deg); }
.nav__burger[aria-expanded="true"] span:nth-of-type(3) { transform: translateY(-3.25px) rotate(-45deg); }
.mobile-menu { position: fixed; inset: 0; z-index: -1; background: var(--bg); padding: calc(var(--header-h) + 40px) var(--gutter) 40px; display: flex; align-items: flex-end; }
.mobile-menu ol { width: 100%; }
.mobile-menu a { display: flex; align-items: baseline; gap: 1rem; padding: 0.15em 0; font-size: clamp(2.6rem, 12vw, 4.5rem); font-weight: 500; letter-spacing: -0.04em; border-bottom: 1px solid var(--line); line-height: 1.15; animation: menuIn 0.7s var(--ease) both; }
.mobile-menu li:nth-child(2) a { animation-delay: 0.04s; } .mobile-menu li:nth-child(3) a { animation-delay: 0.08s; } .mobile-menu li:nth-child(4) a { animation-delay: 0.12s; } .mobile-menu li:nth-child(5) a { animation-delay: 0.16s; } .mobile-menu li:nth-child(6) a { animation-delay: 0.2s; }
.mobile-menu small { font-family: var(--mono); font-size: 0.8rem; color: var(--accent); letter-spacing: 0; }
@keyframes menuIn { from { opacity: 0; transform: translateY(30px); } }

@media (min-width: 960px) {
	.nav__links { display: flex; }
	.nav__actions .btn { display: inline-flex; }
	.nav__burger { display: none; }
	.mobile-menu { display: none !important; }
}
@media (min-width: 960px) and (max-width: 1079px) {
	.nav__links a { padding-inline: 0.75em; }
}
@media (min-width: 560px) and (max-width: 959px) { .nav__actions .btn { display: inline-flex; } }

/* ---------- Word reveal ---------- */
/* Side padding keeps italic overhangs (the serif e, f, y) from being clipped. */
.w { display: inline-block; overflow: hidden; vertical-align: top; padding: 0 0.14em 0.08em; margin: 0 -0.14em -0.08em; }
.wi { display: inline-block; }
.js [data-reveal] .wi { transform: translateY(105%); transition: transform 1s var(--ease); transition-delay: calc(var(--i) * 45ms); }
.js [data-reveal].is-in .wi { transform: none; }
.accent { font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: -0.01em; color: var(--accent); }
.it { font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: -0.01em; }
.strong { font-weight: 800; color: var(--accent); }
.js [data-reveal-fade] { opacity: 0; transform: translateY(24px); transition: opacity 1s var(--ease), transform 1s var(--ease); }
.js [data-reveal-fade].is-in { opacity: 1; transform: none; }

/* ---------- Sections ---------- */
.section { position: relative; padding-block: clamp(64px, 8vw, 128px); }
.section__head { max-width: 980px; margin-bottom: clamp(40px, 6vw, 80px); }
.section__head h2, .about__statement, .contact h2 { font-size: clamp(2.4rem, 6.2vw, 5.6rem); letter-spacing: -0.045em; line-height: 0.98; }
.section__lead { margin-top: 1.4rem; max-width: 60ch; color: var(--fg-2); font-size: 1.1em; }

/* ---------- Hero ---------- */
/* Phones and tall screens: the field gets its own band above the text, and the hero is
   only as tall as its content, so the next section follows straight after. */
.hero { position: relative; display: flex; flex-direction: column; padding-top: var(--header-h); padding-bottom: clamp(48px, 8vw, 80px); overflow: hidden; }
.hero__canvas { position: relative; display: block; width: 100%; height: clamp(200px, 60vw, 560px); max-height: 40svh; }
.hero__inner { position: relative; z-index: 2; pointer-events: none; container-type: inline-size; }
.hero__inner a, .hero__inner button { pointer-events: auto; }
.hero__eyebrow { color: var(--fg-2); }
.hero__title { font-size: clamp(2.6rem, min(13vw, 16cqi), 11.5rem); font-weight: 600; letter-spacing: -0.06em; line-height: 0.88; margin-bottom: 2rem; }
.hero__title .line { display: block; }
.hero__title .accent { font-weight: 400; letter-spacing: -0.03em; padding-right: 0.06em; }
.hero__lead { max-width: 46ch; font-size: clamp(1.05rem, 1.2vw + 0.6rem, 1.35rem); color: var(--fg-2); line-height: 1.5; margin-bottom: 2rem; }
.hero__ctas { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 2rem; }
.hero__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.hero__chips li { display: inline-flex; align-items: center; gap: 0.6em; padding: 0.55em 0.95em; border-radius: 999px; background: rgb(255 255 255 / 0.05); border: 1px solid var(--line); font-size: 0.85rem; color: var(--fg-2); backdrop-filter: blur(6px); }
.hero__chips .dot { width: 6px; height: 6px; box-shadow: none; }
@keyframes modeBar { to { transform: scaleX(1); } }
.hero__scroll { display: none; position: absolute; z-index: 3; right: var(--gutter); bottom: 32px; align-items: center; gap: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.2em; font-size: 0.68rem; }
.hero__scroll i { width: 26px; height: 40px; border-radius: 20px; border: 1px solid var(--line-2); position: relative; }
.hero__scroll i::after { content: ""; position: absolute; left: 50%; top: 8px; width: 3px; height: 7px; margin-left: -1.5px; border-radius: 2px; background: var(--accent); animation: scrollDot 1.8s var(--ease) infinite; }
@keyframes scrollDot { 0% { transform: translateY(0); opacity: 0; } 30% { opacity: 1; } 100% { transform: translateY(16px); opacity: 0; } }

/* Wide, landscape screens: full-height hero, the field fills it with the shapes to the right of the text. */
@media (min-width: 960px) and (min-aspect-ratio: 1/1) {
	.hero { min-height: 100svh; justify-content: center; padding-top: calc(var(--header-h) + 40px); padding-bottom: 120px; }
	.hero__canvas { position: absolute; inset: 0; height: 100%; max-height: none; margin: 0; }
	.hero::after { content: ""; position: absolute; inset: auto 0 0; height: 30%; background: linear-gradient(transparent, var(--bg)); pointer-events: none; }
	.hero__inner { padding-right: min(34vw, 480px); }
	/* Capped by the text column (cqi) so each headline line stays on one row. */
	.hero__title { font-size: clamp(4.5rem, min(9.6vw, 16cqi), 11.5rem); }
	.hero__scroll { display: inline-flex; }
}

/* ---------- Marquee ---------- */
.marquee { overflow: hidden; border-block: 1px solid var(--line); -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); }
.marquee__track { display: flex; width: max-content; animation: marquee var(--marquee-s, 40s) linear infinite; }
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee ul { display: flex; flex: none; }
.marquee li { display: flex; align-items: center; gap: 1.6rem; padding: 1.4rem 0 1.4rem 1.6rem; font-size: clamp(1.4rem, 3vw, 2.4rem); font-weight: 500; letter-spacing: -0.03em; color: var(--fg-2); white-space: nowrap; transition: color 0.3s; }
.marquee li:hover { color: var(--fg); }
.marquee li span { color: var(--accent); font-size: 0.5em; }
@keyframes marquee { to { transform: translateX(-50%); } }

/* ---------- About ---------- */
.about__statement { max-width: 18ch; font-size: clamp(2.2rem, 5.4vw, 5rem); margin-bottom: clamp(48px, 7vw, 100px); }
.about__grid { display: grid; gap: clamp(40px, 6vw, 96px); }
.about__body { color: var(--fg-2); font-size: 1.08em; max-width: 62ch; }
.about__links { display: flex; flex-wrap: wrap; gap: 1.4rem; margin-top: 1.8rem; }
.stats { display: grid; grid-template-columns: 1fr 1fr; border-top: 1px solid var(--line); }
.stat { padding: 1.6rem 1rem 1.6rem 0; border-bottom: 1px solid var(--line); }
.stat:nth-child(odd) { border-right: 1px solid var(--line); }
.stat:nth-child(even) { padding-left: 1.2rem; }
.stat dt { font-size: clamp(2.4rem, 5vw, 4.2rem); font-weight: 600; letter-spacing: -0.05em; line-height: 1; font-variant-numeric: tabular-nums; }
.stat dd { margin-top: 0.6rem; color: var(--muted); font-size: 0.88rem; max-width: 22ch; }
@media (min-width: 960px) { .about__grid { grid-template-columns: 1.1fr 1fr; align-items: start; } }

/* ---------- Capabilities ---------- */
.caps { background: var(--bg-2); border-block: 1px solid var(--line); }
.caps__grid { display: grid; gap: 24px; }
.caps__tabs { display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; margin-inline: calc(-1 * var(--gutter)); padding-inline: var(--gutter); scroll-padding-inline: var(--gutter); scroll-snap-type: x mandatory; }
.caps__tabs::-webkit-scrollbar { display: none; }
.cap-tab { position: relative; flex: none; display: flex; align-items: center; gap: 0.8rem; text-align: left; padding: 0.8rem 1.1rem; border-radius: 14px; border: 1px solid var(--line); color: var(--muted); scroll-snap-align: start; transition: color 0.3s, background 0.3s, border-color 0.3s; overflow: hidden; }
.cap-tab__num { color: inherit; }
.cap-tab__text strong { display: block; font-weight: 500; font-size: 0.95rem; color: inherit; white-space: nowrap; }
.cap-tab__text span { display: none; }
.cap-tab__bar { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; }
.cap-tab__bar i { display: block; height: 100%; background: var(--accent); transform-origin: 0 50%; transform: scaleX(0); }
.cap-tab.is-active { color: var(--fg); background: var(--bg-3); border-color: var(--line-2); }
.cap-tab.is-active .cap-tab__num { color: var(--accent); }
.cap-tab.is-active .cap-tab__bar i { animation: modeBar var(--cap-ms, 9000ms) linear forwards; }
.caps.is-paused .cap-tab.is-active .cap-tab__bar i { animation: none; transform: scaleX(1); }
.cap-tab:hover { color: var(--fg); }
.cap-panel { border-radius: var(--radius-lg); border: 1px solid var(--line); background: var(--bg); padding: clamp(18px, 3vw, 36px); display: grid; gap: 28px; animation: panelIn 0.6s var(--ease); }
@keyframes panelIn { from { opacity: 0; transform: translateY(12px); } }
.cap-panel__head h3 { font-size: clamp(1.6rem, 3vw, 2.4rem); margin-bottom: 0.8rem; }
.cap-panel__head p { color: var(--fg-2); max-width: 54ch; }
.demo { position: relative; border-radius: var(--radius); background: var(--bg-2); border: 1px solid var(--line); padding: clamp(14px, 2vw, 24px); min-height: 340px; overflow: hidden; }

@media (min-width: 1080px) {
	.caps__grid { grid-template-columns: 360px 1fr; gap: 32px; align-items: start; }
	.caps__tabs { flex-direction: column; overflow: visible; margin: 0; padding: 0; position: sticky; top: calc(var(--header-h) + 24px); }
	.cap-tab { padding: 1.1rem 1.2rem; align-items: flex-start; }
	.cap-tab__text strong { white-space: normal; font-size: 1.05rem; margin-bottom: 0.2rem; }
	.cap-tab__text span { display: block; font-size: 0.85rem; line-height: 1.45; color: var(--muted); }
	.cap-panel { grid-template-columns: 1fr; }
}

/* demo: pipeline */
.pipe__flow { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 18px; }
.pipe__flow i { flex: 1 1 12px; min-width: 12px; height: 1px; background: var(--line-2); position: relative; overflow: hidden; }
.pipe__flow i::after { content: ""; position: absolute; inset: 0; background: var(--accent); transform: translateX(-100%); }
.pipe__flow i.is-on::after { animation: flowLine 0.7s var(--ease) forwards; }
@keyframes flowLine { to { transform: translateX(0); } }
.pipe__node { font-family: var(--mono); font-size: 0.72rem; padding: 0.45em 0.8em; border-radius: 8px; border: 1px solid var(--line-2); color: var(--muted); transition: all 0.3s; }
.pipe__node.is-run { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }
.pipe__node.is-done { color: var(--accent); border-color: rgb(200 255 62 / 0.4); }
.pipe__log { margin: 0; height: 220px; overflow: hidden; font-size: 0.74rem; line-height: 1.75; color: var(--fg-2); white-space: pre-wrap; -webkit-mask-image: linear-gradient(transparent, #000 30%); mask-image: linear-gradient(transparent, #000 30%); display: flex; flex-direction: column; justify-content: flex-end; }
.pipe__log .ok { color: var(--accent); } .pipe__log .warn { color: var(--warn); } .pipe__log .dim { color: var(--muted); }
.pipe__foot { display: flex; align-items: center; gap: 10px; margin-top: 14px; color: var(--muted); }
.pipe__foot .chip { margin-left: auto; }

/* demo: infra */
.infra__top { display: flex; flex-wrap: wrap; gap: 6px 22px; color: var(--muted); margin-bottom: 16px; }
.infra__top b, .infra__top strong { color: var(--fg); font-weight: 500; }
.infra__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 6px; }
.svc { width: 100%; display: flex; align-items: center; gap: 8px; padding: 0.6em 0.7em; border-radius: 10px; background: var(--bg); border: 1px solid var(--line); font-family: var(--mono); font-size: 0.68rem; color: var(--fg-2); text-align: left; transition: border-color 0.2s, transform 0.2s; }
.svc:hover { border-color: var(--line-2); transform: translateY(-1px); }
.svc i { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; box-shadow: 0 0 10px rgb(200 255 62 / 0.6); }
.svc span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svc.is-busy i { background: var(--warn); box-shadow: 0 0 10px rgb(255 181 71 / 0.7); animation: blink 0.4s infinite; }
.svc.is-down i { background: var(--bad); box-shadow: 0 0 10px rgb(255 93 93 / 0.7); }
.svc.is-blip { animation: blip 0.6s var(--ease); }
@keyframes blink { 50% { opacity: 0.3; } }
@keyframes blip { 30% { border-color: var(--accent); } }

/* ---------- Filters ---------- */
.filters { display: flex; flex-wrap: wrap; gap: 6px; }
.filter { font-size: 0.85rem; padding: 0.55em 1.1em; border-radius: 999px; border: 1px solid var(--line-2); color: var(--fg-2); transition: all 0.25s; }
.filter:hover { color: var(--fg); border-color: var(--fg-2); }
.filter.is-active { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.filter sup { font-size: 0.7em; color: var(--muted); margin-left: 0.2em; }
.filter.is-active sup { color: var(--bg); opacity: 0.6; }

/* ---------- Consulting ---------- */
.clients { margin-top: clamp(48px, 7vw, 96px); }
.clients ul { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); border-top: 1px solid var(--line); border-left: 1px solid var(--line); }
.clients li { position: relative; padding: 1.3rem 1.2rem; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); font-size: clamp(1rem, 1.3vw, 1.15rem); line-height: 1.35; color: var(--fg-2); transition: color 0.3s, background 0.3s; }
.clients li::before { content: ""; display: block; width: 6px; height: 6px; margin-bottom: 0.9rem; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 4px rgb(200 255 62 / 0.12); }
.clients li:hover { color: var(--fg); background: rgb(255 255 255 / 0.025); }
.roles { border-top: 1px solid var(--line); }
.role { border-bottom: 1px solid var(--line); }
.role summary { list-style: none; display: grid; grid-template-columns: 1fr auto; gap: 4px 20px; align-items: center; padding: 1.6rem 0; cursor: pointer; }
.role summary::-webkit-details-marker { display: none; }
.role__when { color: var(--accent); grid-column: 1; }
.role__area { grid-column: 1; font-size: clamp(1.6rem, 3.4vw, 2.8rem); font-weight: 500; letter-spacing: -0.04em; line-height: 1.1; }
.role__title { grid-column: 1; color: var(--muted); }
.role__icon { grid-column: 2; grid-row: 1 / span 3; width: 46px; height: 46px; border-radius: 50%; border: 1px solid var(--line-2); display: grid; place-items: center; transition: transform 0.5s var(--ease), background 0.3s, color 0.3s; }
.role__icon svg { width: 18px; height: 18px; }
.role[open] .role__icon { transform: rotate(45deg); background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.role summary:hover .role__area { color: var(--accent); }
.role__body { padding: 0 0 2rem; display: grid; gap: 1.2rem; color: var(--fg-2); max-width: 900px; }
.role__body ul { display: grid; gap: 0.6rem; }
.role__body li { position: relative; padding-left: 1.6rem; }
.role__body li::before { content: "→"; position: absolute; left: 0; color: var(--accent); font-family: var(--mono); }
@media (min-width: 900px) {
	.role summary { grid-template-columns: 140px 1fr 1fr 46px; }
	.role__when, .role__area, .role__title { grid-column: auto; }
	.role__icon { grid-column: auto; grid-row: auto; }
	.role__body { padding-left: 160px; grid-template-columns: 1fr 1fr; gap: 2rem; }
}
.groups { margin-top: clamp(56px, 8vw, 110px); }
.groups ul { display: grid; gap: 10px; }
.groups li, .cred { position: relative; display: flex; flex-direction: column; gap: 0.5rem; padding: 1.4rem; border-radius: var(--radius); background: var(--bg-2); border: 1px solid var(--line); overflow: hidden; isolation: isolate; }
.groups li strong { font-weight: 500; font-size: 1.05rem; line-height: 1.3; }
.groups li span { color: var(--accent); }
[data-spotlight]::before { content: ""; position: absolute; inset: 0; z-index: -1; opacity: 0; transition: opacity 0.3s; background: radial-gradient(320px circle at var(--mx, 50%) var(--my, 50%), rgb(200 255 62 / 0.14), transparent 60%); }
[data-spotlight]:hover::before { opacity: 1; }
@media (min-width: 720px) { .groups ul { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .groups ul { grid-template-columns: repeat(4, 1fr); } }

/* ---------- Teaching (paper) ---------- */
/* Printed dot grid for cream frames (the teaching section, project cards and figures). It does not react to the cursor. */
:root { --dots: radial-gradient(circle, rgb(18 19 22 / 0.13) 1.1px, transparent 1.6px) 0 0 / 22px 22px; }
.teaching { background: var(--dots), var(--paper); color: var(--ink); --line: rgb(18 19 22 / 0.12); --line-2: rgb(18 19 22 / 0.22); --muted: #65676c; --fg-2: #3d3f44; --fg: var(--ink); color-scheme: light; }
.teaching .eyebrow .num { color: #5a7d00; }
.teaching .accent { color: #3f5d00; }
.teaching ::selection { background: var(--ink); color: var(--paper); }
.faculty { display: grid; gap: 24px; margin-bottom: clamp(60px, 8vw, 120px); }
.faculty__card { padding: clamp(24px, 3.5vw, 48px); border-radius: var(--radius-lg); background: var(--ink); color: var(--paper); }
.faculty__card .eyebrow { color: #a3a6ab; }
.faculty__card h3 { font-family: var(--serif); font-weight: 400; font-size: clamp(2.2rem, 4.4vw, 3.8rem); letter-spacing: -0.02em; line-height: 1; margin-bottom: 1.2rem; }
.faculty__course { display: inline-block; color: var(--accent); margin-bottom: 1.2rem; font-size: 0.85rem; }
.faculty__card .faculty__body { color: #c2c3c0; margin: 0; }
.faculty__list { margin: 1.4rem 0 0; padding: 0; list-style: none; display: grid; gap: 0.55rem; color: #c2c3c0; font-size: 0.95rem; }
.faculty__list + .faculty__body { margin-top: 1.4rem; }
.faculty__list li { position: relative; padding-left: 1.1rem; }
.faculty__list li::before { content: ""; position: absolute; left: 0; top: 0.6em; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.faculty__quote { margin: 1.8rem 0 1rem; padding-left: 1rem; border-left: 2px solid var(--accent); }
.faculty__quote blockquote { margin: 0; }
.faculty__quote blockquote p { font-family: var(--serif); font-size: clamp(1.3rem, 2vw, 1.6rem); line-height: 1.25; color: var(--paper); margin: 0; }
.faculty__quote figcaption { margin-top: 0.5rem; font-size: 0.75rem; color: #a3a6ab; }
@media (min-width: 900px) { .faculty { grid-template-columns: 1.1fr 1fr; gap: clamp(32px, 5vw, 80px); } }
.talks__head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 10px; margin-bottom: 1rem; }
.talks__head h3 { font-size: clamp(2rem, 4vw, 3.2rem); letter-spacing: -0.04em; }
.talks__head p { color: var(--muted); margin: 0; }
.talks__list, .archive { border-top: 1px solid var(--line); }
.talks__list li, .archive li { border-bottom: 1px solid var(--line); }
.talk { position: relative; display: grid; grid-template-columns: 3.8em 1fr auto; gap: 4px 16px; align-items: center; padding: 1.3rem 0; isolation: isolate; }
.talk::before { content: ""; position: absolute; inset: 0 calc(-1 * var(--gutter)); z-index: -1; background: var(--ink); transform: scaleY(0); transform-origin: 50% 100%; transition: transform 0.45s var(--ease); }
.talk__year { color: var(--muted); grid-row: span 2; align-self: start; padding-top: 0.45em; }
.talk__title { font-size: clamp(1.15rem, 2vw, 1.6rem); font-weight: 500; letter-spacing: -0.025em; line-height: 1.2; transition: color 0.3s, transform 0.45s var(--ease); }
.talk__event { grid-column: 2; color: var(--muted); font-size: 0.88rem; transition: color 0.3s; }
.talk__media { grid-column: 3; grid-row: 1 / span 2; display: inline-flex; align-items: center; gap: 0.4em; padding: 0.4em 0.8em; border-radius: 999px; border: 1px solid var(--line-2); color: var(--fg-2); white-space: nowrap; transition: all 0.4s var(--ease); }
.talk__media svg { width: 12px; height: 12px; }
@media (hover: hover) {
	.talk:hover::before { transform: scaleY(1); transform-origin: 50% 0; }
	.talk:hover .talk__title { color: var(--paper); transform: translateX(10px); }
	.talk:hover .talk__event, .talk:hover .talk__year { color: #9a9ca1; }
	.talk:hover .talk__media { background: var(--accent); color: var(--ink); border-color: var(--accent); }
	.is-inner .talk:hover .talk__title, .archive .talk:hover .talk__title { color: var(--bg); }
}
@media (min-width: 900px) {
	.talk { grid-template-columns: 5em 1.5fr 1fr auto; }
	.talk__year { grid-row: auto; padding: 0; align-self: center; }
	.talk__event { grid-column: auto; }
	.talk__media { grid-column: auto; grid-row: auto; }
}
.talk--static { grid-template-columns: 3.8em 1fr; }
.talk--static::before { content: none; }
@media (min-width: 900px) { .talk--static { grid-template-columns: 5em 1.5fr 1fr; } }
@media (hover: hover) {
	.talk--static:hover .talk__title { color: inherit; transform: none; }
	.talk--static:hover .talk__event, .talk--static:hover .talk__year { color: var(--muted); }
}
.teach-more { display: grid; gap: 28px; margin-top: clamp(60px, 8vw, 110px); }
.teach-more h4 { font-size: 1.15rem; letter-spacing: -0.02em; margin-bottom: 0.6rem; }
.teach-more p, .teach-more li { color: var(--fg-2); font-size: 0.96rem; }
.teach-more li { margin-bottom: 0.5rem; }
.teach-more__label { margin: 1rem 0 0.4rem; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; }
.teach-more .link { color: var(--ink); }
.teach-more .mono { color: var(--muted); }
@media (min-width: 720px) { .teach-more { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .teach-more { grid-template-columns: repeat(3, 1fr); } }

/* ---------- Organizations band ---------- */
.orgs { padding-block: clamp(36px, 5vw, 64px); }
.orgs__title { margin-bottom: 1.1rem; }
/* Newest first, and the box shrinks with age: the current employer gets the large box, the next two
   medium boxes and the rest small ones. */
.orgs__list { display: grid; grid-template-columns: minmax(0, 1fr); border-top: 1px solid var(--line); border-left: 1px solid var(--line); }
.orgs__item { min-width: 0; position: relative; display: flex; flex-direction: column; justify-content: space-between; gap: 0.7rem; padding: 1.4rem 1.2rem; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); overflow: hidden; isolation: isolate; }
.orgs__name { font-size: clamp(1.15rem, 1.55vw, 1.4rem); font-weight: 500; letter-spacing: -0.03em; line-height: 1.15; }
.orgs__role { display: grid; gap: 0.25rem; color: var(--fg-2); font-size: 0.86rem; line-height: 1.3; }
.orgs__role .mono { color: var(--muted); font-size: 0.72rem; }
.orgs__item:first-child { padding: clamp(1.6rem, 3vw, 2.4rem) clamp(1.3rem, 2.4vw, 2rem); gap: 1.4rem; }
.orgs__item:first-child .orgs__name { font-size: clamp(1.9rem, 3.4vw, 3rem); letter-spacing: -0.04em; }
.orgs__item:first-child .orgs__role { font-size: 1rem; }
.orgs__item:first-child .orgs__role .mono { font-size: 0.8rem; }
.orgs__item:nth-child(n + 4) { padding: 1rem 1.1rem; gap: 0.5rem; }
.orgs__item:nth-child(n + 4) .orgs__name { font-size: clamp(1rem, 1.2vw, 1.1rem); }
.orgs__item:nth-child(n + 4) .orgs__role { font-size: 0.8rem; }
@media (min-width: 560px) {
	.orgs__list { grid-template-columns: repeat(6, minmax(0, 1fr)); }
	.orgs__item { grid-column: span 2; }
	.orgs__item:first-child { grid-column: 1 / -1; }
	.orgs__item:nth-child(2), .orgs__item:nth-child(3) { grid-column: span 3; }
}
@media (min-width: 960px) and (min-aspect-ratio: 1/1) {
	.orgs__list { grid-template-columns: repeat(12, minmax(0, 1fr)); }
	.orgs__item:first-child { grid-column: span 6; grid-row: span 2; }
}
.orgs__service { margin-top: 1rem; color: var(--muted); font-size: 0.72rem; letter-spacing: 0.04em; }

/* ---------- Credentials ---------- */
.creds { padding-block: clamp(70px, 9vw, 130px); }
.creds__list { display: grid; gap: 10px; }
.cred strong { font-weight: 500; font-size: 1.1rem; line-height: 1.3; }
.cred span { color: var(--muted); font-size: 0.9rem; }
.cred__kind { color: var(--accent) !important; font-size: 0.72rem !important; }
.cred__link { color: var(--fg-2); text-decoration: underline; text-decoration-color: var(--line-2); text-underline-offset: 3px; transition: color 0.3s; }
.cred__link:hover { color: var(--accent); }
.cred__link { align-self: flex-start; margin-top: auto; font-size: 0.72rem; }
@media (min-width: 720px) { .creds__list { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 720px) and (max-width: 899px) { .creds__list > :last-child:nth-child(odd) { grid-column: 1 / -1; } }
@media (min-width: 900px) { .creds__list { grid-template-columns: repeat(3, 1fr); } }
.creds__group { margin-top: clamp(40px, 6vw, 80px); }
.creds__group:first-child { margin-top: 0; }
.creds__group > h2 { margin-bottom: 1rem; }
.creds__more { margin-top: clamp(40px, 6vw, 72px); color: var(--muted); }
.creds__more a { color: var(--fg); text-decoration: underline; text-underline-offset: 3px; }

/* ---------- Contact ---------- */
.contact { border-top: 1px solid var(--line); }
.contact__grid { display: grid; gap: clamp(40px, 6vw, 90px); }
.contact h2 { margin-bottom: 0; }
.contact__links { display: flex; gap: 1.6rem; margin-top: 2rem; }
.form { display: grid; gap: 14px; align-content: start; }
.field { position: relative; }
.field input, .field textarea { width: 100%; padding: 1.5rem 1.1rem 0.7rem; border-radius: 14px; background: var(--bg-2); border: 1px solid var(--line); color: var(--fg); outline: none; resize: vertical; transition: border-color 0.25s, background 0.25s; }
.field textarea { min-height: 160px; }
.field label { position: absolute; left: 1.1rem; top: 1.05rem; color: var(--muted); pointer-events: none; transform-origin: 0 0; transition: transform 0.25s var(--ease), color 0.25s; }
.field input:focus, .field textarea:focus { border-color: var(--accent); background: var(--bg-3); }
.field input:focus + label, .field textarea:focus + label, .field input:not(:placeholder-shown) + label, .field textarea:not(:placeholder-shown) + label { transform: translateY(-0.6rem) scale(0.74); color: var(--accent); }
.field.is-bad input, .field.is-bad textarea { border-color: var(--bad); }
.field--hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form .btn { justify-self: start; }
.form__status { min-height: 1.4em; margin: 0; color: var(--muted); }
.form__status.is-ok { color: var(--accent); }
.form__status.is-bad { color: var(--bad); }
@media (min-width: 960px) { .contact__grid { grid-template-columns: 1fr 1fr; } }

/* ---------- Footer ---------- */
.site-footer { border-top: 1px solid var(--line); padding: clamp(60px, 9vw, 120px) 0 28px; overflow: hidden; }
.site-footer__big { display: block; font-size: clamp(2.6rem, 9vw, 9.5rem); font-weight: 600; letter-spacing: -0.06em; line-height: 0.92; margin-bottom: clamp(50px, 7vw, 100px); transition: color 0.4s; }
.site-footer__big em { font-family: var(--serif); font-weight: 400; letter-spacing: -0.03em; color: var(--accent); }
.site-footer__big:hover span { color: var(--fg-2); }
.site-footer__row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px 28px; padding-top: 24px; border-top: 1px solid var(--line); color: var(--muted); }
.site-footer__row p { margin: 0; }
.site-footer--plain { padding-top: 24px; }
.site-footer--plain .site-footer__row { border-top: 0; padding-top: 0; }
.site-footer__links { display: flex; flex-wrap: wrap; gap: 8px 22px; font-size: 0.9rem; }
.site-footer__links a:hover { color: var(--fg); }
.site-footer__fine { margin: 18px 0 0; color: var(--muted); opacity: 0.7; }

/* ---------- Inner pages (old posts) ---------- */
.inner { padding: calc(var(--header-h) + clamp(60px, 9vw, 120px)) 0 clamp(80px, 10vw, 140px); min-height: 70svh; }
.inner__head { margin-bottom: clamp(32px, 5vw, 64px); }
.inner__head h1 { font-size: clamp(2.4rem, 6vw, 5rem); letter-spacing: -0.05em; }
.inner--404 h1 { font-size: clamp(2.6rem, 7vw, 6.5rem); max-width: 16ch; margin-bottom: 2.5rem; }
.inner--404 h1 em { font-family: var(--serif); font-weight: 400; color: var(--accent); }
.prose { color: var(--fg-2); font-size: 1.06em; }
.prose > * + * { margin-top: 1.2em; }
.prose h2:not(:where(.pdemo *)), .prose h3:not(:where(.pdemo *)), .prose h4:not(:where(.pdemo *)) { color: var(--fg); margin-top: 2em; letter-spacing: -0.03em; }
.prose h2:not(:where(.pdemo *)) { font-size: 2rem; } .prose h3:not(:where(.pdemo *)) { font-size: 1.5rem; }
.prose a:not(:where(.pdemo *)) { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.prose img:not(:where(.pdemo *)), .prose iframe:not(:where(.pdemo *)), .prose video:not(:where(.pdemo *)) { border-radius: 14px; max-width: 100%; height: auto; }
.prose iframe:not(:where(.pdemo *)) { width: 100%; aspect-ratio: 16 / 9; height: auto; border: 0; }
.prose ul:not(:where(.pdemo *)), .prose ol:not(:where(.pdemo *)) { padding-left: 1.4em; list-style: revert; }
.prose blockquote { margin: 1.6em 0; padding-left: 1.2em; border-left: 2px solid var(--accent); font-family: var(--serif); font-style: italic; font-size: 1.4em; color: var(--fg); }
.prose code:not(:where(.pdemo *)) { font-family: var(--mono); font-size: 0.88em; background: var(--bg-3); padding: 0.15em 0.4em; border-radius: 6px; }
.prose pre:not(:where(.pdemo *)) { background: var(--bg-2); padding: 1rem; border-radius: 12px; overflow-x: auto; border: 1px solid var(--line); }
.prose .wp-block-button__link, .prose .elementor-button { border-radius: 999px; }
.archive .talk::before { background: var(--fg); }
.pager { margin-top: 2rem; }

/* ---------- Motion preferences ---------- */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
	.marquee__track { animation: none; }
	.grain { display: none; }
	.js [data-reveal] .wi, .js [data-reveal-fade] { transform: none; opacity: 1; }
}

/* ---------- Canvas fields (fields.js) ---------- */
.about, .consulting, .teaching, .contact, .phead { overflow: clip; isolation: isolate; }
.about > .wrap, .consulting > .wrap, .teaching > .wrap, .contact > .wrap, .phead > .wrap { position: relative; z-index: 1; }
.pfield { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; z-index: 0; }
.site-footer { padding-bottom: 0; }
.site-footer__mark { position: relative; height: clamp(110px, 15vw, 260px); margin-top: clamp(24px, 4vw, 56px); }
.site-footer__mark .pfield { pointer-events: none; }

/* ---------- Homepage intro (fields.js) ----------
   html.intro is set before first paint by header.php. If the script never
   takes over, the page fades in by itself after a few seconds. */
html.intro :is(.site-header, #main, .site-footer) { animation: introIn 0.5s 4.5s both; }
html.intro-reveal :is(.site-header, #main, .site-footer) { animation: introFade 0.8s var(--ease) both; }
@keyframes introIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes introFade { from { opacity: 0; } to { opacity: 1; } }
html.intro [data-reveal].is-in .wi { transform: translateY(105%); }
html.intro [data-reveal-fade].is-in { opacity: 0; transform: translateY(24px); }
.intro-layer { position: fixed; inset: 0; z-index: 1000; background: var(--bg); cursor: pointer; transition: background-color 0.7s var(--ease), opacity 0.35s; }
.intro-layer canvas { display: block; width: 100%; height: 100%; }
.intro-layer.is-clear { background-color: transparent; pointer-events: none; }
.intro-layer.is-gone { opacity: 0; }

/* ---------- Live demos ---------- */
.hp { position: absolute !important; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.demo__label { display: inline-flex; align-items: center; gap: 0.6em; margin-bottom: 16px; padding: 0.35em 0.8em; border-radius: 999px; border: 1px solid var(--line); color: var(--muted); font-size: 0.7rem; }
.live-dot { position: relative; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; }
.live-dot::after { content: ""; position: absolute; inset: -4px; border-radius: 50%; border: 1px solid var(--accent); opacity: 0; animation: livePing 2s var(--ease) infinite; }
@keyframes livePing { 0% { transform: scale(0.5); opacity: 0.8; } 100% { transform: scale(1.8); opacity: 0; } }
.chip--accent { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.chip--accent:hover { background: var(--fg); border-color: var(--fg); }
.chip.is-active { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.chip:disabled { opacity: 0.5; pointer-events: none; }
.demo input[type="text"], .demo input[type="email"], .demo textarea {
	width: 100%; min-width: 0; padding: 0.7em 0.9em; border-radius: 10px; border: 1px solid var(--line-2); background: var(--bg);
	color: var(--fg); font: inherit; font-size: 0.9rem; transition: border-color 0.2s;
}
.demo input:focus, .demo textarea:focus { outline: none; border-color: var(--accent); }
.demo textarea { resize: vertical; min-height: 96px; line-height: 1.5; }
.demo label.mono { display: block; color: var(--muted); margin-bottom: 8px; }

/* pipeline */
.pipe__form { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)) auto; gap: 10px; align-items: end; }
.pipe__field { display: grid; gap: 6px; min-width: 0; }
.pipe__field span { color: var(--muted); font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.08em; }
.pipe__field select {
	width: 100%; min-width: 0; padding: 0.6em 2em 0.6em 0.8em; border-radius: 10px; border: 1px solid var(--line-2); background-color: var(--bg); font-size: 0.82rem;
	appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
	background-position: calc(100% - 15px) 55%, calc(100% - 10px) 55%; background-size: 5px 5px; background-repeat: no-repeat; cursor: pointer;
}
.pipe__field select:focus-visible { outline: none; border-color: var(--accent); }
.pipe__run { padding: 0.75em 1.1em; }
.pipe__src { margin: 10px 0 16px; color: var(--muted); font-size: 0.7rem; }
.pipe__src a { color: var(--fg); text-decoration: underline; text-decoration-color: var(--line-2); text-underline-offset: 3px; }
@media (max-width: 760px) {
	.pipe__form { grid-template-columns: 1fr 1fr; }
	.pipe__run { grid-column: 1 / -1; justify-self: start; }
}
.pipe__body { display: grid; gap: 14px; }
.pipe__map { margin: 0; position: relative; border-radius: 12px; border: 1px solid var(--line); background: var(--bg); overflow: hidden; }
.pipe__map canvas { display: block; width: 100%; aspect-ratio: 2 / 1; }
.pipe__map figcaption { padding: 8px 12px; border-top: 1px solid var(--line); color: var(--muted); font-size: 0.7rem; }
.pipe__out { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--line); display: grid; gap: 16px; animation: lineIn 0.5s var(--ease) both; }
.pipe__times { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 16px; margin: 0; font-size: 0.7rem; }
.pipe__times dt { color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.62rem; }
.pipe__times dd { margin: 2px 0 0; color: var(--fg); }
.pipe__cols { display: grid; gap: 16px; }
.pipe__h { margin: 0 0 8px; color: var(--muted); font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.08em; }
.pipe__h span { text-transform: none; letter-spacing: 0; }
.pipe__h span i { display: inline-block; width: 8px; height: 8px; margin: 0 4px 0 8px; border-radius: 2px; background: var(--accent-2); opacity: 0.75; vertical-align: -0.05em; }
.pipe__h span i.is-sched { background: var(--accent); opacity: 1; }
.pipe__latest { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; font-size: 0.7rem; }
.pipe__latest li { display: grid; grid-template-columns: 3.4em minmax(0, 1fr) auto; gap: 10px; color: var(--fg-2); }
.pipe__latest b { color: var(--accent); font-weight: 500; }
.pipe__latest span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pipe__latest time { color: var(--muted); }
.pipe__hist { display: flex; align-items: flex-end; gap: 3px; height: 44px; margin-bottom: 16px; }
.pipe__hist i { flex: 1; min-width: 3px; max-width: 14px; border-radius: 2px; background: var(--accent-2); opacity: 0.75; }
.pipe__hist i.is-sched { background: var(--accent); opacity: 1; }
.pipe__dl { display: flex; gap: 8px; margin: 0; }
@media (min-width: 700px) { .pipe__times { grid-template-columns: repeat(4, minmax(0, 1fr)); } .pipe__cols { grid-template-columns: 1.4fr 1fr; } }
.pipe__foot span:nth-child(2) { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (min-width: 900px) {
	.pipe__body { grid-template-columns: 1fr 1.05fr; align-items: start; }
	.pipe__body:has(.pipe__map[hidden]) { grid-template-columns: 1fr; }
}

/* health board */
.infra__top { align-items: center; }
.infra__top .chip { margin-left: auto; }
.infra__grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 170px), 1fr)); gap: 8px; }
.infra__grid.is-blip .hc { animation: blip 0.6s var(--ease); }
.hc { display: grid; grid-template-columns: 1fr auto; gap: 2px 8px; padding: 0.75em 0.85em 0.6em; border-radius: 12px; background: var(--bg); border: 1px solid var(--line); font-family: var(--mono); font-size: 0.7rem; color: var(--fg-2); }
.hc__name { display: flex; align-items: center; gap: 7px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg); }
.hc__name i { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; box-shadow: 0 0 10px rgb(200 255 62 / 0.55); }
.hc b { font-weight: 500; color: var(--accent); text-align: right; white-space: nowrap; }
.hc__note { grid-column: 1 / -1; color: var(--muted); }
.hc__ip { grid-column: 1 / -1; color: var(--fg-2); font-size: 0.92em; letter-spacing: 0.02em; }
.hc__ip::before { content: 'IP '; color: var(--muted); }
.hc svg { grid-column: 1 / -1; width: 100%; height: 26px; margin-top: 6px; overflow: visible; }
.hc polyline { fill: none; stroke: var(--accent-2); stroke-width: 1.4; stroke-linejoin: round; vector-effect: non-scaling-stroke; opacity: 0.8; }
.hc.is-down { border-color: rgb(255 93 93 / 0.4); }
.hc.is-down .hc__name i { background: var(--bad); box-shadow: 0 0 10px rgb(255 93 93 / 0.7); animation: blink 0.9s infinite; }
.hc.is-down b { color: var(--bad); }

/* GIS: address QA */
.gis__switch { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 18px; }
.geo { display: grid; gap: 16px; }
.geo__row { display: flex; gap: 8px; }
.geo__row input { flex: 1; }
.geo__privacy { margin: 10px 0 0; color: var(--muted); font-size: 0.68rem; line-height: 1.5; }
.geo__status { margin: 10px 0 0; padding: 8px 10px; border-left: 2px solid var(--accent); background: color-mix(in srgb, var(--fg) 4%, transparent); color: var(--fg-2); font-size: 0.72rem; line-height: 1.5; }
.geo__status.is-bad { border-left-color: var(--bad); }
.geo__row .chip[aria-busy="true"] { opacity: 1; cursor: progress; }
@media (max-width: 560px) { .geo__row { flex-wrap: wrap; } .geo__row input { flex-basis: 100%; } }
.geo__out { display: grid; gap: 14px; }
.geo__table { width: 100%; border-collapse: collapse; font-size: 0.72rem; }
.geo__table th, .geo__table td { text-align: left; padding: 0.5em 0.6em; border-bottom: 1px solid var(--line); vertical-align: top; word-break: break-word; }
.geo__table thead th { color: var(--muted); font-weight: 450; text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.64rem; }
.geo__table tbody th { color: var(--accent-2); font-weight: 450; white-space: nowrap; }
.geo__table td { color: var(--fg); }
.geo__table tbody tr { animation: lineIn 0.4s var(--ease) both; }
.geo__table tr.is-fix td:last-child { color: var(--warn); }
.geo__table tr.is-fix td:nth-child(2) { color: var(--muted); text-decoration: line-through; text-decoration-color: rgb(255 181 71 / 0.6); }
.geo__map { position: relative; margin: 0; border-radius: 12px; border: 1px solid var(--line); background: var(--bg); overflow: hidden; isolation: isolate; }
/* Loading: a radar sweep over the map, a scanning bar along its top edge, and what is happening in words. */
.geo__loading { position: absolute; inset: 0; z-index: 500; display: grid; place-content: center; justify-items: center; gap: 18px; background: rgb(14 15 18 / 0.72); backdrop-filter: blur(3px); animation: lineIn 0.3s var(--ease) both; }
.geo__loading[hidden] { display: none; }
.geo__loading::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px; background: linear-gradient(90deg, transparent, var(--accent), transparent); background-size: 40% 100%; background-repeat: no-repeat; animation: scanBar 1.1s var(--ease-in-out) infinite; }
.geo__radar { position: relative; width: 96px; height: 96px; border-radius: 50%; border: 1px solid rgb(200 255 62 / 0.25); background: radial-gradient(circle, rgb(200 255 62 / 0.08), transparent 70%); }
.geo__radar::before { content: ""; position: absolute; inset: 0; border-radius: 50%; background: conic-gradient(from 0deg, rgb(200 255 62 / 0.55), transparent 28%); animation: radarSpin 1.4s linear infinite; }
.geo__radar::after { content: ""; position: absolute; left: 50%; top: 0; bottom: 0; border-left: 1px dashed rgb(200 255 62 / 0.2); }
.geo__radar i { position: absolute; inset: 0; border-radius: 50%; border: 1px solid var(--accent); opacity: 0; animation: livePing 2.1s var(--ease) infinite; }
.geo__radar i:nth-child(2) { animation-delay: 0.7s; }
.geo__radar i:nth-child(3) { animation-delay: 1.4s; }
.geo__radar b { position: absolute; left: 50%; top: 50%; width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 14px rgb(200 255 62 / 0.8); }
.geo__loading-label { color: var(--fg-2); font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase; }
.geo__loading-label::after { content: ""; display: inline-block; width: 1.2em; text-align: left; animation: ellipsis 1.2s steps(4) infinite; }
@keyframes scanBar { from { background-position: -40% 0; } to { background-position: 140% 0; } }
@keyframes radarSpin { to { transform: rotate(1turn); } }
@keyframes ellipsis { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "..."; } }
/* A small spinner inside a button that is working. */
.chip[aria-busy="true"]::before { content: ""; display: inline-block; vertical-align: -0.12em; width: 0.9em; height: 0.9em; margin-right: 0.5em; border-radius: 50%; border: 1.5px solid currentColor; border-right-color: transparent; animation: radarSpin 0.7s linear infinite; flex: none; }
@media (prefers-reduced-motion: reduce) { .geo__radar::before, .geo__radar i, .geo__loading::before, .chip[aria-busy="true"]::before { animation: none; } .geo__radar i:first-child { opacity: 0.5; } }
.geo__leaflet { width: 100%; aspect-ratio: 4 / 3; background: #0e0f12; }
.geo__leaflet.leaflet-container { font: inherit; background: #0e0f12; }
.geo__leaflet .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) grayscale(0.6) brightness(0.8) contrast(0.9); } /* OSM's light tiles, darkened to match the page. */
.geo__leaflet .leaflet-control-attribution { background: rgb(14 15 18 / 0.8); color: var(--muted); font-size: 0.58rem; }
.geo__leaflet .leaflet-control-attribution a { color: var(--fg-2); }
.geo__leaflet .leaflet-bar a { background: var(--bg-2); color: var(--fg); border-color: var(--line); }
.geo__leaflet .leaflet-bar a:hover { background: var(--bg-3); }
.geo__leaflet .leaflet-tooltip { background: var(--bg-2); color: var(--fg); border: 1px solid var(--line-2); font-family: var(--mono); font-size: 0.68rem; box-shadow: none; }
.geo__leaflet .leaflet-tooltip-top::before { border-top-color: var(--line-2); }
.geo__h { margin: 0 0 6px; color: var(--accent-2); font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; }
.geo__note { margin: 0 0 10px; color: var(--muted); font-size: 0.78rem; line-height: 1.5; }
.geo__table tbody th small { display: block; color: var(--muted); font-size: 0.62rem; font-weight: 400; margin-top: 1px; }
.geo__census { display: grid; gap: 18px; padding-top: 16px; border-top: 1px solid var(--line); animation: lineIn 0.5s var(--ease) both; }
.geo__dl { margin: 0; display: grid; gap: 0; font-size: 0.72rem; }
.geo__dl div { display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: 10px; padding: 0.45em 0; border-bottom: 1px solid var(--line); }
.geo__dl dt { color: var(--muted); font-family: var(--mono); }
.geo__dl dd { margin: 0; color: var(--fg); font-family: var(--mono); word-break: break-word; }
.geo__dl dd span { display: block; color: var(--muted); font-size: 0.62rem; }
@media (min-width: 900px) { .geo__census { grid-template-columns: 1fr 1fr; } }
.geo__pin { position: relative; }
.geo__pin-dot { position: absolute; inset: 11px; border-radius: 50%; background: var(--accent); border: 3px solid #0b0c0e; box-shadow: 0 0 0 2px var(--accent), 0 4px 14px rgb(0 0 0 / 0.5); }
.geo__pin-ring { position: absolute; inset: 0; border-radius: 50%; border: 2px solid var(--accent); animation: livePing 2s ease-out infinite; }
.geo__levels { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.geo__levels .chip[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.geo__levels .chip:disabled { opacity: 0.35; }
@media (prefers-reduced-motion: reduce) { .geo__pin-ring { animation: none; opacity: 0.6; } }
.geo__map figcaption { padding: 8px 12px; border-top: 1px solid var(--line); color: var(--muted); font-size: 0.68rem; }
.geo__checks { display: grid; gap: 4px; font-size: 0.72rem; }
.geo__checks li { position: relative; padding-left: 1.5em; color: var(--fg-2); animation: lineIn 0.4s var(--ease) both; }
.geo__checks li::before { position: absolute; left: 0; font-family: var(--mono); }
.geo__checks .ok::before { content: "✓"; color: var(--accent); }
.geo__checks .fix::before { content: "→"; color: var(--warn); }
.geo__checks .warn::before { content: "!"; color: var(--bad); }
@media (min-width: 900px) { .geo__out { grid-template-columns: 1.25fr 1fr; align-items: start; } }

/* ---------- Live GitHub activity: a slim strip on /work/ ---------- */
.ghstrip { padding-bottom: clamp(24px, 3vw, 36px); }
.ghstrip__in { display: grid; gap: 14px; padding: 16px 18px; border-radius: var(--radius); border: 1px solid var(--line); background: var(--bg-2); }
.ghstrip__title { margin: 0 0 0.5rem; }
.ghstrip__num { margin: 0; color: var(--fg-2); font-size: 1rem; }
.ghstrip__num span { display: inline-block; margin-right: 0.15em; color: var(--fg); font-size: 2.2rem; font-weight: 500; letter-spacing: -0.04em; line-height: 1; font-variant-numeric: tabular-nums; }
.ghstrip__num .is-bump { animation: bump 0.9s var(--ease); }
@keyframes bump { 20% { color: var(--accent); transform: translateY(-4px); } }
.ghstrip__label { margin: 0.4rem 0 0; color: var(--fg-2); font-size: 0.9rem; }
.ghstrip__label span { color: var(--fg); }
.ghstrip__meta { display: flex; flex-wrap: wrap; column-gap: 1em; margin: 0.4rem 0 0; color: var(--muted); font-size: 0.72rem; }
.ghstrip__meta span { white-space: nowrap; }
.ghstrip__meta a { color: var(--fg-2); text-decoration: underline; text-decoration-color: var(--line-2); text-underline-offset: 3px; transition: color 0.3s; }
.ghstrip__meta a:hover { color: var(--accent); }
.ghstrip__refresh { padding: 0; border: 0; background: none; color: var(--fg-2); font: inherit; text-decoration: underline; text-decoration-color: var(--line-2); text-underline-offset: 3px; cursor: pointer; transition: color 0.3s; }
.ghstrip__refresh:hover, .ghstrip__refresh:focus-visible { color: var(--accent); }
.ghstrip__refresh[aria-disabled="true"] { cursor: progress; text-decoration: none; }
.ghstrip__refresh-status:empty { display: none; }
.ghstrip__cal { margin: 0; min-width: 0; }
.ghstrip__cal canvas { display: block; width: 100%; height: auto; aspect-ratio: 53 / 7.6; max-height: 112px; }
.ghstrip__cal figcaption { margin-top: 6px; color: var(--muted); font-size: 0.7rem; min-height: 1.4em; }
.ghstrip__narrow { display: none; }
@media (max-width: 519px) {
	.ghstrip__in { gap: 10px; padding: 14px 16px; }
	.ghstrip__title { margin-bottom: 0.35rem; }
	.ghstrip__num span { font-size: 1.8rem; }
	.ghstrip__label { font-size: 0.85rem; margin-top: 0.25rem; }
	.ghstrip__meta { margin-top: 0.25rem; }
	.ghstrip__cal canvas { aspect-ratio: 27 / 7.6; }
	.ghstrip__wide { display: none; }
	.ghstrip__narrow { display: inline; }
}
@media (min-width: 900px) {
	.ghstrip__in { grid-template-columns: minmax(200px, 0.34fr) minmax(0, 1fr); align-items: center; gap: 24px; padding: 18px 24px; }
}

/* ---------- Consulting top: coverage map ---------- */
.consulting__top { display: grid; gap: 24px; margin-bottom: clamp(32px, 5vw, 64px); }
.consulting__top .section__head { margin-bottom: 0; }
.cov { position: relative; margin: 0; display: flex; flex-direction: column; border-radius: var(--radius-lg); border: 1px solid var(--line); background: radial-gradient(80% 70% at 50% 40%, var(--bg-3), var(--bg-2)); overflow: hidden; }
.cov__head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; padding: 14px 14px 0; }
.cov__head .demo__label { margin: 0; }
.cov__tabs { display: flex; flex-wrap: wrap; gap: 6px; }
.cov__tab { position: relative; overflow: hidden; }
.cov__bar { position: absolute; left: 12px; right: 12px; bottom: 3px; height: 1px; }
.cov__bar i { display: block; height: 100%; background: currentColor; opacity: 0.6; transform-origin: 0 50%; transform: scaleX(0); }
.cov__tab.is-active .cov__bar i { animation: modeBar var(--cov-ms, 7000ms) linear forwards; }
.cov.is-paused .cov__bar i { animation: none; transform: scaleX(0); }
.cov__map { position: relative; flex: 1 1 auto; min-height: clamp(260px, 52vw, 420px); cursor: pointer; }
/* Every panel shares one grid cell, so the map keeps one size whichever is showing. */
.cov__panels { display: grid; }
.cov__panel { grid-area: 1 / 1; padding: 4px 18px 18px; animation: panelIn 0.5s var(--ease) both; }
.cov__panel[hidden] { display: block; visibility: hidden; animation: none; }
.cov__title { margin: 0 0 4px; font-size: 0.8rem; color: var(--muted); font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.06em; }
.cov__num { margin: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.4em; font-size: clamp(2.4rem, 5vw, 3.6rem); line-height: 1; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.cov__unit { font-size: 0.95rem; letter-spacing: 0; color: var(--muted); }
.cov__facts { display: flex; flex-wrap: wrap; gap: 6px 22px; margin: 12px 0 10px; }
.cov__facts > div { display: flex; align-items: baseline; gap: 0.45em; }
.cov__facts dt { font-family: var(--mono); color: var(--accent); }
.cov__facts dd { margin: 0; color: var(--muted); font-size: 0.9rem; }
.cov__line { margin: 0; display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 16px; font-size: 0.9rem; }
.cov__src { color: var(--muted); font-size: 0.68rem; }
.cov__src a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.cov__src a:hover { color: var(--fg); }
@media (max-width: 520px) {
	.cov__head .demo__label { display: none; }
	.cov__tab { font-size: 0.68rem; padding: 0.5em 0.75em; }
}
@media (min-width: 960px) {
	.consulting__top { grid-template-columns: 1.15fr 1fr; align-items: stretch; }
	.cov__map { min-height: 330px; }
}

/* ---------- Teaching stats & credentials head ---------- */
.teach-stats { display: grid; align-content: center; gap: 0; margin: 0; border-top: 1px solid var(--line); }
.teach-stats > div { display: grid; grid-template-columns: 3ch 1fr; align-items: center; gap: 1.4rem; padding: 1.4rem 0; border-bottom: 1px solid var(--line); }
.teach-stats dt { min-width: 2ch; font-size: clamp(2.8rem, 5vw, 4.4rem); font-weight: 500; letter-spacing: -0.05em; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
.teach-stats dd { margin: 0; color: var(--fg-2); max-width: 32ch; }
.creds__head { margin-bottom: clamp(20px, 3vw, 36px); }
/* The page title is set as a small label, so Degrees comes straight after it. */
.section--page .section__head h1.eyebrow { font-size: 0.95rem; letter-spacing: 0.14em; line-height: 1.4; margin: 0; color: var(--fg); }

/* ==========================================================================
   Multi-page structure (2.0)
   ========================================================================== */
.nav__links a[aria-current="page"] { color: var(--fg); }
.nav__links a[aria-current="page"]::after { content: ""; display: block; height: 1px; margin-top: 2px; background: var(--accent); }
.mobile-menu a[aria-current="page"] { color: var(--accent); }

/* A part used as a whole page clears the fixed header. */
.section--page { padding-top: calc(var(--header-h) + clamp(48px, 7vw, 104px)); }
.section--page .section__head h1, .section--page h1 { font-size: clamp(2.6rem, 6.6vw, 6rem); letter-spacing: -0.045em; line-height: 0.98; }
.contact.section--page { min-height: 100svh; }
.section--tight { padding-top: 0; }
.section__head--row { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 24px; max-width: none; }
.section__head--row > div { max-width: 900px; }

/* Page header */
.phead { position: relative; padding: calc(var(--header-h) + clamp(48px, 7vw, 104px)) 0 clamp(36px, 5vw, 64px); }
.phead__title { font-size: clamp(2.6rem, 6.6vw, 6rem); letter-spacing: -0.045em; line-height: 0.98; max-width: 18ch; }

/* Shared page top (Experience, Projects, Education, Live demos): the same label,
   headline scale, accent and lede. On the pages without a visual the text runs
   the full width and the content starts close below it. */
.ptop__title, .section--page .section__head h1.ptop__title { font-size: clamp(2.6rem, 5.4vw, 5.2rem); font-weight: 500; letter-spacing: -0.045em; line-height: 0.98; max-width: 16ch; }
.ptop__title .accent { padding-right: 0.06em; }
.ptop__lead, .section__lead.ptop__lead { margin-top: 1.4rem; max-width: 56ch; color: var(--fg-2); font-size: 1.12em; }
.phead.ptop { padding: calc(var(--header-h) + clamp(32px, 4.5vw, 64px)) 0 clamp(28px, 3.5vw, 44px); }
.phead.ptop .ptop__title { max-width: none; }
.phead.ptop .ptop__lead { max-width: 80ch; }
.caps--page { padding-top: 0; background: none; border-top: 0; }
.phead--project .phead__title { font-size: clamp(2.2rem, 5.4vw, 4.8rem); max-width: 22ch; }
.phead__lead { margin-top: 1.4rem; max-width: 64ch; color: var(--fg-2); font-size: 1.12em; }
.crumbs { margin-bottom: 1.6rem; }
.crumbs a { display: inline-flex; align-items: center; gap: 0.5em; color: var(--muted); transition: color 0.2s; }
.crumbs a:hover { color: var(--fg); }
.crumbs svg { width: 14px; height: 14px; }
.pmeta { display: flex; flex-wrap: wrap; gap: 14px 40px; margin-top: 2rem; padding-top: 1.4rem; border-top: 1px solid var(--line); }
.pmeta dt { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
.pmeta dd { margin: 0.2rem 0 0; }
.pmeta a { color: var(--accent); }

/* Project cards (home and work index) */
.filters { margin-bottom: 28px; }
.filters__empty { color: var(--muted); }
.pgrid { display: grid; gap: 18px; }
@media (min-width: 720px) { .pgrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .pgrid { grid-template-columns: repeat(3, 1fr); } }
.pcard[hidden] { display: none; }
.pcard__link { position: relative; display: flex; flex-direction: column; height: 100%; border-radius: var(--radius); overflow: hidden; background: var(--bg-2); border: 1px solid var(--line); transition: border-color 0.3s, transform 0.5s var(--ease); }
.pcard__link:hover { border-color: var(--line-2); transform: translateY(-4px); }
.pcard__media { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: var(--dots), var(--paper); border-bottom: 1px solid var(--line); }
.pcard__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.8s var(--ease); }
.pcard__link:hover .pcard__media img { transform: scale(1.04); }
.pcard__badge { position: absolute; left: 12px; top: 12px; display: inline-flex; align-items: center; gap: 0.4em; padding: 0.35em 0.7em; border-radius: 999px; background: rgb(10 11 13 / 0.78); color: var(--fg); backdrop-filter: blur(6px); }
.pcard__badge svg { width: 11px; height: 11px; color: var(--accent); }
.pcard__text { display: flex; flex-direction: column; gap: 0.6rem; padding: 20px 22px 22px; flex: 1; }
.pcard__meta { color: var(--accent); }
.pcard__title { font-size: clamp(1.25rem, 1.8vw, 1.55rem); letter-spacing: -0.03em; line-height: 1.15; }
.pcard__org { color: var(--fg); font-size: 0.9rem; font-weight: 500; }
.pcard__summary { color: var(--fg-2); font-size: 0.94rem; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.pcard__topics { color: var(--muted); margin-top: auto; padding-top: 0.6rem; }

/* Project page */
.pbody { padding-block: clamp(32px, 4vw, 56px) clamp(64px, 8vw, 120px); }
/* Summary band under the project header: headline numbers, results, role and stack. Never sticky. */
.psum { display: grid; gap: clamp(20px, 3vw, 32px); padding-block: clamp(8px, 1.5vw, 16px) 0; }
.psum__stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); gap: 10px; margin: 0; }
.psum__stats > div { padding: clamp(14px, 2vw, 18px) clamp(14px, 2vw, 20px); border-radius: 14px; background: var(--bg-2); border: 1px solid var(--line); }
.psum__stats dt { font-size: clamp(1.7rem, 3vw, 2.4rem); font-weight: 500; letter-spacing: -0.03em; line-height: 1.05; color: var(--fg); }
.psum__stats dd { margin: 0.45rem 0 0; font-size: 0.86rem; color: var(--fg-2); line-height: 1.4; }
.psum__grid { display: grid; gap: clamp(24px, 3vw, 48px); padding-top: clamp(20px, 2.5vw, 28px); border-top: 1px solid var(--line); }
@media (min-width: 900px) { .psum__grid { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); } }
.psum__block .eyebrow { margin-bottom: 0.9rem; }
.psum__block .eyebrow:not(:first-child) { margin-top: 1.6rem; }
.psum__role { margin: 0; color: var(--fg-2); max-width: 60ch; }
/* Placeholder figures (inc/placeholders.php). Marked only when the page is opened with ?ph. */
.show-ph .ph { outline: 1px dashed var(--accent); outline-offset: 2px; }
.outcomes { display: grid; gap: 0.9rem; }
.outcomes li { position: relative; padding-left: 1.3em; color: var(--fg-2); font-size: 0.95rem; line-height: 1.5; }
.outcomes li::before { content: ""; position: absolute; left: 0; top: 0.6em; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.pmain { min-width: 0; max-width: 960px; }
.pmain > h2 { font-size: clamp(1.5rem, 2.4vw, 2rem); }
.pmain > p, .pmain > ul, .pmain > ol { max-width: 68ch; }
.pmain ol li:not(:where(.pdemo *)), .pmain ul li:not(:where(.pdemo *)) { margin-bottom: 0.5em; }
.video { margin: 0 0 1.6em; }
.video video { display: block; width: 100%; aspect-ratio: 16 / 9; background: #000; border-radius: 14px; border: 1px solid var(--line); }
.video figcaption, .fig figcaption { display: flex; align-items: center; gap: 0.5em; margin-top: 0.6rem; font-size: 0.86rem; color: var(--muted); }
.video figcaption svg { width: 12px; height: 12px; color: var(--accent); flex: none; }
.fig { margin: 1.6em 0; }
.fig a { display: block; border-radius: 14px; overflow: hidden; background: var(--dots), var(--paper); border: 1px solid var(--line); }
.fig img { display: block; width: 100%; height: auto; border-radius: 0; transition: transform 0.6s var(--ease); }
.fig a:hover img { transform: scale(1.02); }
.gallery { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); margin: 1.6em 0; }
.gallery .fig { margin: 0; }
.fig--tile a { aspect-ratio: 4 / 3; }
.fig--tile img { height: 100%; object-fit: cover; }
.code { font-family: var(--mono); font-size: 0.82rem; line-height: 1.6; color: var(--fg); background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px; padding: 1.1rem 1.2rem; overflow-x: auto; tab-size: 4; }
.code code { background: none; padding: 0; font-size: inherit; }
.talkcard { display: grid; gap: 18px; padding: 18px; margin: 1.6em 0; border-radius: var(--radius); background: var(--bg-2); border: 1px solid var(--line); }
.talkcard .fig { margin: 0; }
.talkcard h3 { font-size: 1.3rem; margin: 0 0 0.5rem; }
.talkcard p { color: var(--fg-2); margin: 0 0 1rem; font-size: 0.96rem; }
@media (min-width: 720px) { .talkcard { grid-template-columns: 0.9fr 1fr; align-items: center; } }
.downloads { margin-top: 3em; padding-top: 2em; border-top: 1px solid var(--line); }
.prose .downloads h2 { margin: 0 0 0.8em; }
.dl { display: grid; gap: 8px; padding: 0 !important; list-style: none !important; }
.dl a { display: flex; align-items: center; gap: 14px; padding: 0.85em 1em; border-radius: 12px; border: 1px solid var(--line-2); color: var(--fg); text-decoration: none !important; transition: background 0.25s, border-color 0.25s; }
.dl a:hover { background: var(--bg-3); border-color: var(--accent); }
.dl__type { flex: none; min-width: 3.6em; text-align: center; padding: 0.25em 0.5em; border-radius: 6px; background: rgb(200 255 62 / 0.12); color: var(--accent); }
.dl__label { flex: 1; font-size: 0.95rem; }
.dl svg { width: 18px; height: 18px; color: var(--muted); flex: none; }
.pnav { display: grid; gap: 12px; padding-bottom: clamp(64px, 8vw, 120px); }
.pnav__title { margin-bottom: 4px; }
@media (min-width: 720px) { .pnav { grid-template-columns: 1fr 1fr; } .pnav__title { grid-column: 1 / -1; } }
/* Each card reads as a button: a filled panel, a round arrow and a pressed state. */
.pnav__link { display: flex; align-items: center; gap: 16px; min-height: 88px; padding: 18px 20px; border-radius: var(--radius); border: 1px solid var(--line-2); background: var(--bg-2); -webkit-tap-highlight-color: transparent; transition: border-color 0.3s, background 0.3s, transform 0.15s; }
.pnav__link:hover, .pnav__link:focus-visible { border-color: var(--accent); background: var(--bg-3); }
.pnav__link:active { transform: scale(0.98); background: var(--bg-3); border-color: var(--accent); }
.pnav__text { display: grid; gap: 0.4rem; flex: 1; min-width: 0; }
.pnav__text .mono { color: var(--fg-2); font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; }
.pnav__text strong { font-size: 1.1rem; font-weight: 500; letter-spacing: -0.02em; line-height: 1.3; }
.pnav__arrow { flex: none; display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; background: var(--accent); color: var(--accent-ink); transition: transform 0.3s var(--ease); }
.pnav__arrow svg { width: 18px; height: 18px; }
.pnav__link--prev:hover .pnav__arrow { transform: translateX(-3px); }
.pnav__link--next:hover .pnav__arrow { transform: translateX(3px); }
@media (min-width: 720px) { .pnav__link--next { text-align: right; } }

/* Project pages: Newer/Older arrows pinned to the screen edges until the Newer/Older cards come into view (wide screens, where the side margin can hold them) */
.pedge { display: none; }
@media (min-width: 1400px) and (hover: hover) {
	.pedge { display: block; --pedge-x: max(8px, calc((100vw - var(--max)) / 4 + var(--gutter) / 2 - 22px)); }
	.pedge__btn { position: fixed; top: 50%; z-index: 80; display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--line-2); background: rgb(17 19 24 / 0.82); backdrop-filter: blur(8px); color: var(--fg); opacity: 0; pointer-events: none; transform: translateY(-50%) scale(0.85); transition: opacity 0.3s, transform 0.4s var(--ease), background 0.2s, border-color 0.2s, color 0.2s; }
	.pedge__btn--prev { left: var(--pedge-x); }
	.pedge__btn--next { right: var(--pedge-x); }
	.pedge.is-on .pedge__btn { opacity: 1; pointer-events: auto; transform: translateY(-50%) scale(1); }
	.pedge__btn:hover, .pedge__btn:focus-visible { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
	.pedge__btn svg { width: 18px; height: 18px; }
	.pedge__tip { position: absolute; top: 50%; display: grid; gap: 0.2rem; width: max-content; max-width: 260px; padding: 0.7rem 0.9rem; border-radius: 12px; border: 1px solid var(--line-2); background: var(--bg-2); color: var(--fg); font-size: 0.9rem; line-height: 1.3; opacity: 0; pointer-events: none; transform: translateY(-50%); transition: opacity 0.2s, transform 0.3s var(--ease); }
	.pedge__tip .mono { font-size: 0.7rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; }
	.pedge__btn--prev .pedge__tip { left: calc(100% + 10px); transform: translate(-6px, -50%); }
	.pedge__btn--next .pedge__tip { right: calc(100% + 10px); text-align: right; transform: translate(6px, -50%); }
	.pedge__btn:hover .pedge__tip { opacity: 1; transform: translate(0, -50%); }
}

/* Before/after slider */
.compare { margin: 0 0 2.4em; }
.compare > h2 { font-size: clamp(1.5rem, 2.4vw, 2rem); }
.compare__tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 1rem; }
.compare__tabs .chip.is-active { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.compare.is-auto .compare__tabs .chip { position: relative; overflow: hidden; }
.compare.is-auto .compare__tabs .chip.is-active::after { content: ""; position: absolute; left: 0; bottom: 0; height: 2px; width: 100%; background: var(--accent); transform-origin: left; transform: scaleX(var(--prog, 0)); }
.compare__fig { margin: 0; }
.compare__stage { position: relative; aspect-ratio: 1440 / 848; border-radius: 14px; overflow: hidden; border: 1px solid var(--line); background: var(--paper, var(--bg-2)); touch-action: pan-y; user-select: none; }
.compare__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: top left; border-radius: 0; pointer-events: none; }
.compare__img--after { clip-path: inset(0 0 0 var(--pos, 50%)); }
.compare__handle { position: absolute; top: 0; bottom: 0; left: var(--pos, 50%); width: 2px; margin-left: -1px; background: var(--accent); box-shadow: 0 0 0 1px rgb(0 0 0 / 0.25); pointer-events: none; }
.compare__handle::after { content: "\2039\203A"; position: absolute; top: 50%; left: 50%; display: grid; place-items: center; width: 42px; height: 42px; border-radius: 50%; background: var(--accent); color: var(--accent-ink); font: 600 1.1rem/1 var(--mono); letter-spacing: 0.1em; transform: translate(-50%, -50%); box-shadow: 0 4px 18px rgb(0 0 0 / 0.35); transition: transform 0.2s var(--ease); }
.compare__stage:hover .compare__handle::after { transform: translate(-50%, -50%) scale(1.08); }
.compare__range { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: ew-resize; -webkit-appearance: none; appearance: none; background: transparent; }
.compare__range::-webkit-slider-thumb { -webkit-appearance: none; width: 48px; height: 100vh; }
.compare__range::-moz-range-thumb { width: 48px; height: 100vh; border: 0; }
.compare__stage:has(.compare__range:focus-visible) { outline: 2px solid var(--accent); outline-offset: 3px; }
.compare__tag { position: absolute; top: 12px; padding: 0.35em 0.7em; border-radius: 999px; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; background: rgb(10 11 13 / 0.78); color: var(--fg); pointer-events: none; }
.compare__tag--before { left: 12px; }
.compare__tag--after { right: 12px; background: var(--accent); color: var(--accent-ink); }
.compare__fig figcaption { margin-top: 0.6rem; font-size: 0.86rem; color: var(--muted); }
.compare__note { margin: 0.8rem 0 0; font-size: 0.74rem; color: var(--muted); }

/* Home: explore tiles and closing call to action */
.explore__grid { display: grid; gap: 12px; }
@media (min-width: 720px) { .explore__grid { grid-template-columns: repeat(2, 1fr); } }
.about + .explore { padding-top: 0; }
@media (min-width: 1100px) { .explore__grid { grid-template-columns: repeat(4, 1fr); } }
.explore__tile { position: relative; display: grid; align-content: start; gap: 0.8rem; height: 100%; padding: 26px 26px 64px; border-radius: var(--radius); border: 1px solid var(--line); background: var(--bg-2); transition: border-color 0.3s, transform 0.5s var(--ease); }
.explore__tile:hover { border-color: var(--accent); transform: translateY(-4px); }
.explore__label { font-size: 1.6rem; font-weight: 500; letter-spacing: -0.03em; }
.explore__text { color: var(--fg-2); font-size: 0.95rem; }
.explore__icon { position: absolute; right: 22px; bottom: 22px; width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--line-2); display: grid; place-items: center; transition: all 0.4s var(--ease); }
.explore__icon svg { width: 15px; height: 15px; }
.explore__tile:hover .explore__icon { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.cta { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 28px; margin-top: clamp(64px, 9vw, 140px); padding-top: clamp(40px, 5vw, 64px); border-top: 1px solid var(--line); }
.cta__title { font-size: clamp(2rem, 4.8vw, 4.2rem); letter-spacing: -0.04em; line-height: 1; max-width: 18ch; }

/* Teaching: podcast with click-to-load YouTube */
.podcast { display: grid; gap: 24px; margin-top: clamp(60px, 8vw, 110px); align-items: center; }
@media (min-width: 900px) { .podcast { grid-template-columns: 1fr 1.2fr; gap: clamp(32px, 5vw, 80px); } }
.podcast h3 { font-size: clamp(1.6rem, 3vw, 2.4rem); letter-spacing: -0.03em; margin-bottom: 0.8rem; }
.podcast p { color: var(--fg-2); }
.yt { position: relative; aspect-ratio: 16 / 9; border-radius: var(--radius); overflow: hidden; background: var(--ink); }
.yt img { width: 100%; height: 100%; object-fit: cover; opacity: 0.85; }
.yt iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.yt__play { position: absolute; inset: 0; margin: auto; width: 74px; height: 74px; border-radius: 50%; background: var(--accent); color: var(--ink); display: grid; place-items: center; transition: transform 0.4s var(--ease); }
.yt__play:hover { transform: scale(1.08); }
.yt__play svg { width: 28px; height: 28px; margin-left: 4px; }
.yt__note { position: absolute; left: 14px; bottom: 12px; margin: 0; color: var(--paper); text-shadow: 0 1px 4px rgb(0 0 0 / 0.6); }
.talks__list a.talk { color: inherit; }

/* Lightbox */
.lightbox { padding: 0; border: 0; max-width: none; max-height: none; width: 100vw; height: 100svh; background: rgb(6 7 9 / 0.94); color: var(--fg); }
.lightbox::backdrop { background: rgb(6 7 9 / 0.8); }
.lightbox figure { display: grid; place-items: center; gap: 12px; height: 100%; margin: 0; padding: 56px 16px 24px; }
.lightbox img { max-width: min(100%, 1600px); max-height: calc(100svh - 120px); object-fit: contain; border-radius: 10px; background: var(--paper); }
.lightbox figcaption { color: var(--fg-2); text-align: center; max-width: 80ch; }
.lightbox__close, .lightbox__nav { position: absolute; width: 46px; height: 46px; border-radius: 50%; background: var(--bg-3); color: var(--fg); font-size: 1.6rem; line-height: 1; display: grid; place-items: center; }
.lightbox__close { top: 14px; right: 14px; }
.lightbox__nav { top: 50%; transform: translateY(-50%); }
.lightbox__nav--prev { left: 14px; }
.lightbox__nav--next { right: 14px; }
.lightbox__close:hover, .lightbox__nav:hover { background: var(--accent); color: var(--accent-ink); }

/* ---------- Project page: a published stats block (figures copied as published) ---------- */
.sstats { margin: 2.4em 0; padding: clamp(18px, 3vw, 28px); border: 1px solid var(--line); border-radius: 18px; background: var(--bg-2, rgb(255 255 255 / 0.02)); }
.prose .sstats h2 { margin-top: 0; font-size: 1.5rem; }
.sstats__note { color: var(--muted); font-size: 0.74rem; line-height: 1.6; margin: 0.4em 0 1.4em; }
.sstats__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; margin: 0; background: var(--line); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.sstats__grid > div { background: var(--bg); padding: 14px; }
@media (min-width: 760px) { .sstats__grid { grid-template-columns: repeat(3, 1fr); } .sstats__grid > div { padding: 16px; } }
.sstats__grid dt { font-size: clamp(1.4rem, 2.6vw, 1.9rem); font-weight: 500; letter-spacing: -0.03em; color: var(--accent); font-variant-numeric: tabular-nums; }
.sstats__grid dd { margin: 4px 0 0; color: var(--fg-2); font-size: 0.86rem; line-height: 1.4; }
@media (max-width: 480px) { .sstats__grid dt { font-size: 1.2rem; } .sstats__grid dd { font-size: 0.78rem; } }
.sstats__wrap { margin-top: 1.4em; overflow-x: auto; }
.sstats__table { width: 100%; border-collapse: collapse; font-size: 0.78rem; font-variant-numeric: tabular-nums; }
.sstats__table th, .sstats__table td { padding: 0.55em 0.6em; border-bottom: 1px solid var(--line); text-align: right; white-space: nowrap; }
.sstats__table th:first-child { text-align: left; }
.sstats__table thead th { white-space: normal; vertical-align: bottom; color: var(--muted); font-weight: 450; text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.64rem; }
.sstats__table tbody th { color: var(--fg); font-weight: 450; }
.sstats__table td { color: var(--fg-2); }
.sstats__table tbody tr:last-child th, .sstats__table tbody tr:last-child td { color: var(--fg); border-bottom: 0; border-top: 1px solid var(--line-2, var(--line)); }

/* demo: site analytics (2.11). The visitor's own facts, then the site's GA4 totals. */
.ga { display: grid; gap: clamp(20px, 2.6vw, 32px); }
.ga__bar { display: flex; justify-content: space-between; align-items: baseline; flex-wrap: wrap; gap: 6px 16px; margin-bottom: 12px; color: var(--muted); font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; }
.ga__bar h4 { margin: 0; font: inherit; color: var(--fg); }
.ga__facts { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 190px), 1fr)); column-gap: 24px; margin: 0; border-top: 1px solid var(--line); }
.ga__facts > div { min-width: 0; padding: 0.7rem 0; border-bottom: 1px solid var(--line); }
.ga__facts dt { color: var(--muted); font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.08em; text-transform: uppercase; }
.ga__facts dd { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em 0.7em; margin: 0.3rem 0 0; color: var(--fg); overflow-wrap: anywhere; }
.ga__facts .chip { padding: 0.3em 0.75em; font-size: 0.66rem; }
.ga__note { margin: 14px 0 0; max-width: 74ch; color: var(--muted); font-size: 0.8rem; line-height: 1.6; }
.ga__dash { padding-top: clamp(18px, 2.4vw, 28px); border-top: 1px solid var(--line-2); }
.ga__state { padding: 28px 0; color: var(--fg-2); }
.ga__state p { margin: 0; }
.ga__state b { display: block; margin-bottom: 0.3rem; color: var(--fg); font-weight: 500; }
.ga__kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0 0 18px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.ga__kpi { min-width: 0; padding: 14px; border-left: 1px solid var(--line); }
.ga__kpi:first-child { border-left: 0; padding-left: 0; }
.ga__kpi dt { color: var(--muted); font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase; }
.ga__kpi dd { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.2em 0.5em; margin: 0.5rem 0 0; }
.ga__num { font-size: clamp(1.5rem, 2.6vw, 2.2rem); font-weight: 500; letter-spacing: -0.04em; line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ga__delta { color: var(--accent); font-size: 0.66rem; }
.ga__delta.is-down { color: var(--muted); }
.ga__spark { display: block; flex-basis: 100%; width: 100%; height: 24px; margin-top: 8px; overflow: visible; }
.ga__spark polyline { fill: none; stroke: var(--accent); stroke-width: 1.5; stroke-linejoin: round; vector-effect: non-scaling-stroke; opacity: 0.7; }
.ga__trend { margin: 0 0 22px; padding: 14px 14px 8px; border: 1px solid var(--line); border-radius: 14px; background: var(--bg); }
.ga__trend-top { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 8px; }
.ga__trend figcaption { color: var(--muted); font-size: 0.64rem; letter-spacing: 0.08em; text-transform: uppercase; }
.ga__toggles { display: flex; flex-wrap: wrap; gap: 10px; }
.ga__seg { display: inline-flex; gap: 4px; }
.ga__seg .chip { padding: 0.32em 0.75em; font-size: 0.66rem; }
.ga__plot { position: relative; touch-action: pan-y; cursor: crosshair; }
.ga__plot svg { display: block; width: 100%; height: auto; overflow: visible; }
.ga__plot svg:focus { outline: none; }
.ga__plot svg:focus-visible { outline: 1px solid var(--accent); outline-offset: 4px; border-radius: 6px; }
.ga__grid { stroke: var(--line); stroke-width: 1; }
.ga__ylab, .ga__xlab { fill: var(--muted); font-family: var(--mono); font-size: 10px; }
.ga__area { fill: color-mix(in srgb, var(--accent) 12%, transparent); }
.ga__line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.ga__cross { stroke: var(--fg-2); stroke-width: 1; stroke-dasharray: 3 3; }
.ga__dot { fill: var(--accent); stroke: var(--bg); stroke-width: 2; }
.ga__tip { position: absolute; top: 0; z-index: 2; display: grid; gap: 2px; padding: 6px 9px; border: 1px solid var(--line-2); border-radius: 8px; background: var(--bg-3); color: var(--fg-2); font-size: 0.64rem; white-space: nowrap; pointer-events: none; transform: translateX(-50%); }
.ga__tip[hidden] { display: none; }
.ga__tip b { color: var(--fg); font-weight: 500; }
.ga__lists { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); gap: 22px 28px; }
.ga__list { min-width: 0; }
.ga__list h5 { margin: 0 0 8px; color: var(--muted); font-size: 0.62rem; font-weight: 400; letter-spacing: 0.08em; text-transform: uppercase; }
.ga__list ol { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.ga__list li { position: relative; display: flex; justify-content: space-between; gap: 1rem; padding: 0.55rem 0; border-bottom: 1px solid var(--line); font-size: 0.86rem; }
.ga__list li span { min-width: 0; color: var(--fg-2); overflow-wrap: anywhere; }
.ga__list li b { color: var(--fg); font-size: 0.76rem; font-weight: 400; font-variant-numeric: tabular-nums; }
.ga__list li i { position: absolute; left: 0; bottom: -1px; width: var(--w); height: 2px; border-radius: 2px; background: var(--accent); opacity: 0.75; transform: scaleX(0); transform-origin: 0 50%; transition: transform 0.8s var(--ease); }
.ga.is-drawn .ga__list li i { transform: scaleX(1); }
.ga__list li.is-sub span { padding-left: 1em; color: var(--muted); }
.ga__none { margin: 0; color: var(--muted); font-size: 0.82rem; }
.ga__foot { margin: 20px 0 0; max-width: 80ch; color: var(--muted); font-size: 0.64rem; line-height: 1.6; }
@media (max-width: 640px) {
	.ga__facts { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 16px; }
	.ga__kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.ga__kpi:nth-child(3) { border-left: 0; padding-left: 0; }
	.ga__kpi:nth-child(n + 3) { border-top: 1px solid var(--line); }
}
@media (prefers-reduced-motion: reduce) {
	.ga__list li i { transition: none; }
}

/* Crawler log tab: shares the analytics tab's styles, plus the latest-visits table */
.crawl { grid-template-columns: minmax(0, 1fr); }
.demo--crawlers { min-height: 0; }
.crawl__recent { margin-top: 22px; }
.crawl__scroll { overflow-x: auto; border-top: 1px solid var(--line); }
.crawl__table { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
.crawl__table th { padding: 0.55rem 0.8rem 0.55rem 0; color: var(--muted); font-family: var(--mono); font-size: 0.6rem; font-weight: 400; letter-spacing: 0.08em; text-align: left; text-transform: uppercase; white-space: nowrap; border-bottom: 1px solid var(--line); }
.crawl__table td { padding: 0.55rem 0.8rem 0.55rem 0; color: var(--fg-2); border-bottom: 1px solid var(--line); vertical-align: top; white-space: nowrap; }
.crawl__table td.mono { font-size: 0.72rem; }
.crawl__path { max-width: 22ch; overflow: hidden; text-overflow: ellipsis; }
.crawl__kind { margin-left: 0.4em; color: var(--muted); font-size: 0.62rem; letter-spacing: 0.06em; text-transform: uppercase; }
.crawl__sub { display: none; }
/* Phones: When and Crawler only, with the page under the crawler's name. */
@media (max-width: 599px) {
	.crawl__table th:nth-child(n + 3), .crawl__table td:nth-child(n + 3) { display: none; }
	.crawl__table td:nth-child(-n + 2) { white-space: normal; }
	.crawl__table td:first-child { width: 7.5em; }
	.crawl__sub { display: block; max-width: 100%; margin-top: 0.15rem; overflow: hidden; color: var(--muted); font-size: 0.7rem; text-overflow: ellipsis; white-space: nowrap; }
}

/* Walkthrough: screenshots that play through a workflow (a plain list of figures without JS) */
.walk { margin: 0 0 2.4em; }
.walk > h2 { font-size: clamp(1.5rem, 2.4vw, 2rem); }
.walk__step { margin: 0 0 1.2rem; }
.walk__step a { display: block; border-radius: 14px; overflow: hidden; border: 1px solid var(--line); }
.walk__step img { display: block; width: 100%; height: auto; border-radius: 0; }
.walk__step figcaption { margin-top: 0.6rem; font-size: 0.86rem; color: var(--muted); }
.walk__cursor, .walk__bar, .walk__cap { display: none; }
.walk.is-live .walk__stage { position: relative; aspect-ratio: 1727 / 947; border-radius: 14px; overflow: hidden; border: 1px solid var(--line); background: var(--bg-2); }
.walk.is-live .walk__step { position: absolute; inset: 0; margin: 0; opacity: 0; visibility: hidden; transition: opacity 0.7s var(--ease), visibility 0s 0.7s; }
.walk.is-live .walk__step.is-active { opacity: 1; visibility: visible; transition: opacity 0.7s var(--ease); }
.walk.is-live .walk__step a { height: 100%; border: 0; border-radius: 0; }
.walk.is-live .walk__step img { height: 100%; object-fit: cover; object-position: var(--fx) var(--fy); transform-origin: var(--fx) var(--fy); transform: scale(1); transition: transform 0.8s var(--ease); }
.walk.is-live.is-auto .walk__step.is-active img { transform: scale(1.07); transition: transform var(--dur, 5600ms) linear; }
.walk.is-live .walk__step figcaption { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.walk.is-live .walk__cursor { display: block; position: absolute; left: 50%; top: 50%; width: 30px; height: 30px; margin: -15px 0 0 -15px; border-radius: 50%; border: 2px solid var(--accent); background: rgb(200 255 62 / 0.18); box-shadow: 0 2px 12px rgb(0 0 0 / 0.4); pointer-events: none; transition: left 0.9s var(--ease-in-out), top 0.9s var(--ease-in-out); }
.walk__cursor.is-click::after { content: ""; position: absolute; inset: -2px; border-radius: 50%; border: 2px solid var(--accent); animation: walk-ping 0.7s var(--ease) forwards; }
@keyframes walk-ping { from { transform: scale(1); opacity: 1; } to { transform: scale(2.4); opacity: 0; } }
.walk.is-live .walk__bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin: 0.9rem 0 0; }
.walk .walk__steps { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.walk .walk__steps li { margin: 0; }
.walk__go { position: relative; overflow: hidden; padding: 0.45em 0.85em; border-radius: 999px; border: 1px solid var(--line-2); background: none; color: var(--muted); font: inherit; font-size: 0.8rem; cursor: pointer; transition: color 0.3s, border-color 0.3s, background-color 0.3s; }
.walk__go:hover { color: var(--fg); border-color: var(--fg); }
.walk__go .mono { color: var(--accent); margin-right: 0.2em; }
.walk__go.is-active { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.walk__go.is-active .mono { color: inherit; }
.walk.is-auto .walk__go.is-active::after { content: ""; position: absolute; left: 0; bottom: 0; height: 2px; width: 100%; background: var(--accent); transform-origin: left; transform: scaleX(var(--prog, 0)); }
.walk__play { padding: 0.45em 0.85em; border-radius: 999px; border: 1px solid var(--line-2); background: none; color: var(--muted); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; cursor: pointer; }
.walk__play:hover { color: var(--fg); border-color: var(--fg); }
.walk.is-live .walk__cap { display: block; min-height: 3em; margin: 0.8rem 0 0; color: var(--fg); }
.walk__note { margin: 0.4rem 0 0; font-size: 0.74rem; color: var(--muted); }
/* Phones: a square stage cropped to each step's focus point, so the screenshot stays readable. */
@media (max-width: 640px) {
	.walk.is-live .walk__stage { aspect-ratio: 1 / 1; }
	.walk__go { font-size: 0.74rem; }
}
@media (prefers-reduced-motion: reduce) {
	.walk.is-live .walk__step, .walk.is-live .walk__step img, .walk.is-live .walk__cursor { transition: none; }
	.walk__cursor.is-click::after { animation: none; }
	.walk.is-live.is-auto .walk__step.is-active img { transform: none; }
}

/* Drop cards: a figure counted down from where it started to where it settled */
.drop__cut { display: block; width: fit-content; margin-bottom: 0.55rem; padding: 0.3em 0.65em; border-radius: 999px; background: var(--accent); color: var(--accent-ink); font: 600 0.72rem/1.2 var(--mono); letter-spacing: 0.04em; text-transform: uppercase; }
.drop__val { font-variant-numeric: tabular-nums; }
.drop__from { color: var(--muted); }
.drop.is-done .drop__val { animation: drop-settle 0.6s var(--ease); }
@keyframes drop-settle { 40% { color: var(--accent); } }
/* Line a plain card's figure up with the figures under the drop labels beside it. */
@media (min-width: 641px) { .psum__stats:has(.drop) > div:not(.drop) dt { margin-top: calc(0.72rem * 1.2 + 0.72rem * 0.6 + 0.55rem); } }

/* Maintenance mode: shown to signed-in administrators only (inc/maintenance.php). */
.maint-bar { position: fixed; left: 50%; bottom: 16px; z-index: 1000; transform: translateX(-50%); display: flex; gap: 10px; align-items: center; max-width: calc(100% - 32px); padding: 10px 16px; border-radius: 999px; background: var(--accent); color: var(--accent-ink); font: 500 0.82rem/1.3 var(--sans); box-shadow: 0 8px 30px rgb(0 0 0 / 0.4); }
.maint-bar span { text-decoration: underline; text-underline-offset: 2px; white-space: nowrap; }
.maint-bar--preview { flex-wrap: wrap; justify-content: center; border-radius: 18px; text-align: center; }
.maint-bar--preview a { color: inherit; text-decoration: underline; text-underline-offset: 2px; white-space: nowrap; }
.maint-bar--raised { bottom: 64px; }

/* A live demo on a project page: the same panel as on Live demos, kept clear of the write-up's prose styles. */
.pdemo { margin: 2.4em 0; padding: clamp(18px, 3vw, 32px); border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--bg); display: grid; gap: 20px; }
.prose .pdemo h2 { margin: 0; font-size: 1.5rem; color: var(--fg); letter-spacing: -0.03em; }
.pdemo__note { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 0; font-size: 0.78rem; color: var(--fg-2); }
.pdemo__note a { color: var(--accent); }
.pdemo .demo { font-size: calc(1em / 1.06); color: var(--fg-2); min-width: 0; }
.pdemo .infra__grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr)); }

/* ---------- One centred column ----------
   Every page reads as one centred column at every width: headings, labels, leads, rows of
   buttons and the footer are centred, a short last row of cards or images sits in the middle or
   stretches, and short pages (Contact, 404) fill the screen. Running text stays left-aligned inside
   its centred column. On wide landscape screens (the hero's own test: 960 px or wider and at least
   as wide as tall) the side-by-side layouts stay side by side, with their text left-aligned in its
   own column: the hero (text beside the dot field), About (text beside the figures), Contact (text
   beside the form), the Experience top (text beside the map), Teaching (the faculty card beside the
   figures), the podcast (text beside the video) and a project's results beside its role and stack.
   A project write-up's paragraphs, lists, headings and quotes share one centred measure. */
@property --je-measure { syntax: '<length>'; inherits: true; initial-value: 0px; }
/* Centred headings, labels and leads */
.section__head, .phead, .ptop, .orgs__title, .orgs__service, .creds__more,
.about > .wrap > .eyebrow, .about__statement, .talks__head,
.inner--404 .wrap, .inner__head, .site-footer__big, .site-footer__fine, .pnav__title, .cta, .filters__empty,
.creds__group > h2, .creds__group > .eyebrow, .clients > .eyebrow, .groups > .eyebrow, .ghstrip__title,
.explore > .wrap > .eyebrow, .psum__block > .eyebrow { text-align: center; }
.section__lead, .ptop__lead, .phead__lead, .phead__title, .ptop__title, .about__statement,
.inner--404 h1, .inner__head h1, .cta__title, .section__head, .psum__role { margin-inline: auto; }
.contact__links, .pmeta, .filters, .talks__head,
.section__head--row, .cta, .site-footer__row, .site-footer__links { justify-content: center; }
.site-footer__row { flex-direction: column; text-align: center; }
.talks__head { flex-direction: column; align-items: center; }
.section__head--row > div { max-width: none; }
.cta { flex-direction: column; align-items: center; }
.pmeta { text-align: center; }
/* Section labels, unless they sit inside a card or a write-up */
.eyebrow:not(:where(.faculty__card, .psum__block, .cap-panel, .demo, .pdemo, .cov, .pcard, .explore__tile, .cred, .prose, .teach-more) *) { display: block; text-align: center; }
.eyebrow:not(:where(.faculty__card, .psum__block, .cap-panel, .demo, .pdemo, .cov, .pcard, .explore__tile, .cred, .prose, .teach-more) *) > .dot { display: inline-block; margin-right: 0.6em; vertical-align: 0.1em; }
/* Centred labels wrap into even lines */
.eyebrow { text-wrap: balance; }
/* Live demos tabs wrap into centred rows instead of running off the right edge */
.caps__tabs { flex-wrap: wrap; justify-content: center; overflow: visible; margin-inline: 0; padding-inline: 0; }
/* Agencies served: a short last row stretches across */
.clients ul { display: flex; flex-wrap: wrap; }
.clients li { flex: 1 1 260px; }
/* Certificate cards: a short last row stretches to the full width */
.creds__list { display: flex; flex-wrap: wrap; }
.creds__list > * { flex: 1 1 280px; }
@media (min-width: 900px) { .creds__list > * { flex-basis: calc((100% - 20px) / 3); } }
/* A project with only one neighbour: its card takes the whole row */
.pnav:not(:has(.pnav__link--prev)) .pnav__link--next, .pnav:not(:has(.pnav__link--next)) .pnav__link--prev { grid-column: 1 / -1; }
/* Headline figures sit centred in their cells */
.stat { text-align: center; padding-inline: 1rem; }
.stat dd { margin-inline: auto; }
/* A summary with only one block (no results) is centred across the page */
.psum__grid > .psum__block:only-child { grid-column: 1 / -1; text-align: center; }
.psum__grid > .psum__block:only-child .tags { justify-content: center; }
/* Image galleries: rows of equal tiles, and a short last row sits in the middle */
.gallery { display: flex; flex-wrap: wrap; justify-content: center; }
.gallery > * { flex: 0 0 100%; }
@media (min-width: 560px) { .gallery > * { flex-basis: calc((100% - 12px) / 2); } }
@media (min-width: 900px) { .gallery > * { flex-basis: calc((100% - 24px) / 3); } }
/* Teaching figures spread down the height of the faculty card beside them */
.teach-stats { align-content: stretch; }
/* Short pages (Contact, 404) fill the screen: the footer sits at the bottom and the content is
   centred in the space above it, instead of a fixed minimum height leaving a gap in one place */
.contact.section--page, .inner { min-height: 0; }
body:has(> main > .contact.section--page, > main.inner--404) { display: flex; flex-direction: column; min-height: 100svh; }
body:has(> main > .contact.section--page, > main.inner--404) > main { flex: 1 0 auto; display: flex; flex-direction: column; }
main.inner--404, main > .contact.section--page { flex: 1 0 auto; display: flex; flex-direction: column; justify-content: center; }
/* Project figure cards: a short last row stretches across */
.psum__stats { display: flex; flex-wrap: wrap; }
/* Teaching extras flow down balanced columns, so one long list doesn't leave the others' columns half empty */
@media (min-width: 720px) {
	.teach-more { display: block; columns: 2; column-gap: 28px; }
	.teach-more > * { margin-bottom: 28px; }
	.teach-more :is(li, p, h4) { break-inside: avoid-column; }
	.teach-more h4, .teach-more__label { break-after: avoid-column; }
}
@media (min-width: 1100px) { .teach-more { columns: 3; } }
.psum__stats > div { flex: 1 1 150px; }
/* Projects index: a short last row (after a topic filter) sits in the middle */
@media (min-width: 720px) { .pgrid { display: flex; flex-wrap: wrap; justify-content: center; } .pgrid > * { flex: 0 0 calc((100% - 18px) / 2); } }
@media (min-width: 1100px) { .pgrid > * { flex-basis: calc((100% - 36px) / 3); } }
/* A project's write-up is a centred column; its text stays left-aligned inside it */
.pmain { margin-inline: auto; }

/* Wide landscape screens */
@media (min-width: 960px) and (min-aspect-ratio: 1/1) {
	/* The write-up's text keeps a readable measure and sits in the middle of the column, under
	   centred figures, demos and galleries */
	/* 68ch of the write-up's own text, worked out on .pmain so headings in a bigger size match it */
	.pmain { --je-measure: 68ch; }
	.pmain > :is(p, ul, ol, h2, h3, h4, blockquote) { max-width: var(--je-measure); margin-inline: auto; }
	.psum__grid > .psum__block:not(:only-child) > .eyebrow { text-align: start; }
	.psum__grid > .psum__block:not(:only-child) .psum__role { margin-inline: 0; }
	/* The side-by-side layouts keep their text left-aligned in its own column */
	:is(.hero__inner, .contact__grid, .consulting__top, .podcast__text) :is(.eyebrow, .section__head, .section__lead, h1, h2) { text-align: start; margin-inline: 0; }
	.contact__grid .contact__links { justify-content: flex-start; }
	/* An opened role's two columns run to the row's right edge */
	.role__body { max-width: none; }
}

/* ---------- Portrait screens and phones ----------
   Anything that isn't a wide landscape screen stacks the hero (text under its dot field), About,
   Contact and the Experience top, and centres their text; the podcast keeps its two columns from
   900 px with its text centred. Text columns that were capped for wide screens run the width of
   the page. */
@media not all and (min-width: 960px) and (min-aspect-ratio: 1/1) {
	.hero__inner, .podcast__text, .contact__grid > div:first-child { text-align: center; }
	.hero__lead { margin-inline: auto; }
	.ptop__title, .section--page .section__head h1.ptop__title, .phead__title { max-width: 20ch; }
	.hero__ctas, .hero__chips, .cov__tabs, .cov__head { justify-content: center; }
	.form .btn { justify-self: center; }
	/* About is one column here, so its links sit under the centred text */
	.about__links { justify-content: center; }

	/* Text columns fill the page instead of stopping short of the right edge */
	.about__body, .pmain, .pmain > p, .pmain > ul, .pmain > ol, .role__body, .teach-stats dd,
	.cap-panel__head p, .ga__note, .ga__foot { max-width: none; }

	/* Text beside a visual: stack, text first */
	.consulting__top, .contact__grid { grid-template-columns: 1fr; }
	.consulting__top .section__head { max-width: 46rem; }
	/* Project summary: results beside role and stack from tablet width up */
	@media (min-width: 640px) { .psum__grid { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); } }
	.psum__role { max-width: none; }
	/* About: text, then the figures across the page under it */
	.about__grid { grid-template-columns: minmax(0, 1fr); }
	.about__grid > * { min-width: 0; }
	.stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	@media (max-width: 559px) { .stat { padding-inline: 0.5rem; } .stat dt { font-size: min(2.4rem, 8.5vw); } }
	/* Dashboard lists flow down columns, so a short list doesn't leave a hole beside a long one */
	.ga__lists { display: block; columns: 2 230px; column-gap: 28px; }
	.ga__list { display: inline-block; width: 100%; break-inside: avoid; margin-bottom: 22px; }
	/* Crawler log: the two long lists side by side, the short By kind list across the page under them */
	.ga__lists[data-crawl-lists] { display: grid; grid-template-columns: minmax(0, 1fr); gap: 22px 28px; columns: auto; }
	@media (min-width: 560px) { .ga__lists[data-crawl-lists] { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
	.ga__lists[data-crawl-lists] > .ga__list { margin-bottom: 0; }
	.ga__lists[data-crawl-lists] > .ga__list:nth-child(2) { order: 1; grid-column: 1 / -1; }
}
