/* levitations.id — rebuilt from the clintbalcom.com teardown.
   Tokens and technique per balcom-rebuild/teardown.md. Content is Levi's. */

/* ---------- reset ---------- */
a, abbr, article, blockquote, body, code, dd, details, div, dl, dt, em, figure,
footer, form, header, html, h1, h2, h3, h4, iframe, label, li, main, ol, p,
section, span, strong, summary, table, tbody, td, th, thead, tr, ul {
	background: transparent; border: 0; margin: 0; outline: 0; padding: 0;
	vertical-align: baseline;
}
body { line-height: 1; -webkit-font-smoothing: antialiased }
ol, ul { list-style: none }
table { border-collapse: collapse; border-spacing: 0 }
a, :focus { outline: none }
details, footer, header, main, section, summary { display: block }
*, *:before, *:after { box-sizing: border-box }
img { display: block; width: 100% }

/* ---------- fonts ---------- */
/* ponytail: one self-hosted family. Mono + arrow glyphs come from the system
   stack — `ui-monospace` resolves to SF Mono on Apple hardware for free, which
   is what the original self-hosts a 51KB unlicensed copy of. */
@font-face {
	font-family: "Rethink Sans";
	src: url("fonts/RethinkSans.woff2") format("woff2");
	font-display: swap;
	font-style: normal;
	font-weight: 400 800;
}

/* ---------- tokens ---------- */
:root {
	--cb-bg: 224, 240, 242;
	--cb-fill: 0, 0, 0;

	--color-bg: rgba(var(--cb-bg), 1);
	--color-fill: rgba(var(--cb-fill), .84);
	--color-fill-light: #7ca9b8;      /* the original declares this twice; this is the value that wins */
	--color-bevel: rgba(var(--cb-fill), .69);
	--color-faint: color-mix(in srgb, var(--color-bg), transparent 34%);

	--colorSplitR: rgba(255, 34, 192, .93);
	--colorSplitB: rgba(24, 234, 255, .93);
	--colorSplitY: rgba(252, 237, 57, 1);
	--color-brilliant: #35ff92;

	--font-standard: "Rethink Sans", "SF Pro", "SF Pro Display", system-ui, Helvetica, sans-serif, "Apple Color Emoji";
	--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace, "Apple Color Emoji";
	--font-arrow: system-ui, "SF Pro", sans-serif, "Apple Color Emoji";

	--size-xl: 4.5rem;
	--size-l: 3rem;
	--size-m: 1.5rem;
	--size-s: 1rem;

	--outerBreakpoint: 1920px;
	--innerBreakpoint: 1650px;

	--outerPad: min(7.5vw, 124px);
	--centerMargin: calc(50% - 4.3rem);
	--vertGapLarge: 11.5rem;
	--vertGap: 7.5rem;
	--innerPad: 5.25rem;
	--headerPadTop: 5.25rem;
	--headerPadBtm: 0rem;
	--headerHeight: calc(var(--headerPadTop) + var(--headerPadBtm));

	--mainCvGap: calc(var(--size-m) * 1.4);
	--cvGap: var(--mainCvGap);
	--cvSmallGap: calc(var(--mainCvGap) / 2);

	--linkLineSlide: cubic-bezier(.57, 0, .12, 1);
	--linkLineSpeed: .21s;
	--linkBtnShowSpeed: .12s;
	--linkBtnBounceSpeed: .17s;
	--linkBtnBounce: cubic-bezier(.34, 1.56, .62, 1.2);
	--slideTime: .39s;
	--headerBounce: cubic-bezier(.12, .93, .42, 1.2);
	--enterDrift: 1.2em;
	--enterTiming: .48s;
	--enterBounce: cubic-bezier(.42, 0, .21, 1);
	--delayedStart: calc(var(--linkLineSpeed) * .48);
	--secondStepStart: calc(var(--delayedStart) + (var(--linkBtnShowSpeed) * 1.2));
	--doubleTime: calc(var(--linkBtnShowSpeed) * 2);

	--plax: 0px;
	--dotSize: 12px;
}

/* ---------- base type ---------- */
html, body { font-size: 16px; height: 100% }
body {
	background: var(--color-bg);
	color: var(--color-fill);
	font-family: var(--font-standard);
	font-weight: 400;
}

h1 {
	font-size: clamp(var(--size-l), 4.76vw, 78px);
	font-weight: 700;
	line-height: 1.2;
	text-wrap: pretty;
}
h2 {
	font-size: var(--size-l);
	line-height: 1.3;
	text-wrap: balance;
}
h2.margin-sml { margin-block-end: var(--cvGap) }
h3 { font-weight: 700; line-height: 1.2 }
p, h3 { font-size: var(--size-m) }
p, .list li { line-height: 1.4; text-wrap: pretty }
.list { margin-block-end: var(--size-m) }
.list li { font-size: var(--size-s) }
code { font-family: var(--font-mono); font-weight: 400; letter-spacing: -.02em; word-spacing: -.22em }
.arrow { font-family: var(--font-arrow) }
.nobr { white-space: nowrap }

/* ---------- links ---------- */
a, [role="button"] {
	color: inherit;
	cursor: pointer;
	position: relative;
	text-decoration: none;
}
a:not(.noline):before, [role="button"]:not(.noline):before {
	background: currentColor;
	bottom: 0;
	content: "";
	height: 1px;
	left: 0;
	position: absolute;
	transform-origin: center left;
	transition: transform var(--linkLineSpeed) var(--linkLineSlide);
	width: 100%;
	will-change: transform;
	z-index: 10;
}
a:not(.noline):hover:before, [role="button"]:not(.noline):hover:before {
	transform: scaleX(0);
	transform-origin: center right;
}

/* glass pill */
.jelly {
	cursor: pointer;
	display: inline-block;
	font-size: var(--size-m);
	position: relative;
	transform: scale(1);
	transition: transform .17s ease;
	user-select: none;
}
.jelly:before {
	backdrop-filter: saturate(142%) blur(20px);
	background: color-mix(in srgb, var(--color-bg), transparent 39%);
	border-radius: .43em;
	box-shadow: #00000008 0 3px, #00000008 0 0 0 1px, #00000036 0 3px 66px,
		inset #ffffff1f 1px 2px, inset #ffffff57 0 2px 12px;
	content: "";
	inset: -.62em -.75em;
	position: absolute;
	transition: box-shadow .21s ease;
	z-index: -1;
}
.jelly:active { transform: scale(.984) }

/* company link with the green sweep */
a.brilliant {
	font-weight: 500;
	margin-inline-start: .075em;
	margin-inline-end: .125em;
}
a.brilliant:not(.noline):before { height: 2px; left: .62ch; width: calc(100% - 1.24ch) }
a.brilliant:after {
	background: var(--color-brilliant);
	content: "";
	height: 100%;
	position: absolute;
	left: -.24ch;
	right: -.24ch;
	top: 0;
	transform: scaleX(0);
	transform-origin: center right;
	transition: transform var(--linkLineSpeed) var(--linkLineSlide);
	z-index: -1;
}
a.brilliant:hover:after {
	transform: scaleX(1);
	transform-origin: center left;
	transition: transform var(--doubleTime) var(--secondStepStart) ease;
}

/* rgb-split hover.
   ponytail: hover tier only. The original's click-to-media tier is ~200 lines of
   JS driving photos and a video we don't have. Add when the assets exist. */
.rgbsplit {
	display: inline-block;
	isolation: isolate;
	position: relative;
	transition: transform .17s ease;
}
.rgbsplit:before { z-index: 30 }
.rgbsplit:after,
.rgbsplit .split-b, .rgbsplit .split-r { pointer-events: none }
.rgbsplit .hover-effect {
	backface-visibility: hidden;
	border-radius: .43em;
	inset: -.24em -.34em;
	opacity: 0;
	pointer-events: none;
	position: absolute;
	transition: opacity var(--linkBtnShowSpeed) var(--delayedStart) ease;
	z-index: -1;
}
.rgbsplit.noline .hover-effect { inset: -.37em -.62em }
.rgbsplit .hover-effect .fill {
	background: color-mix(in srgb, var(--color-bg), #fff 34%);
	border-radius: inherit;
	box-shadow: inset #fced3900 0 0;
	position: absolute;
	inset: 0;
	transition: background var(--doubleTime) var(--secondStepStart) ease,
		box-shadow var(--doubleTime) var(--secondStepStart) ease;
	z-index: 2;
}
.rgbsplit .hover-effect:before, .rgbsplit .hover-effect:after {
	--zDrift: 0px;
	--zScale: .93;
	border-radius: inherit;
	content: "";
	inset: 0;
	opacity: .93;
	position: absolute;
	transform: translate3d(var(--zDrift), var(--zDrift), 0) scale(var(--zScale));
	transform-style: preserve-3d;
	transition: transform calc(var(--linkBtnBounceSpeed) * 2) var(--secondStepStart) var(--linkBtnBounce);
	will-change: transform;
	z-index: 1;
}
.rgbsplit .hover-effect:before { background: var(--colorSplitB) }
.rgbsplit .hover-effect:after { background: var(--colorSplitR) }
.rgbsplit:hover .hover-effect { opacity: 1 }
.rgbsplit:hover .hover-effect .fill {
	background: #fff;
	box-shadow: inset var(--colorSplitY) -2px -2px 0;
}
.rgbsplit:hover .hover-effect:before { --zDrift: -.12em; --zScale: 1 }
.rgbsplit:hover .hover-effect:after { --zDrift: .142em; --zScale: 1 }
.rgbsplit:active { transform: scale(.984) }

/* ---------- layout ---------- */
.wrap {
	margin: 0 auto;
	max-width: var(--innerBreakpoint);
	padding: 0 var(--outerPad);
}
.push { margin-inline-start: var(--centerMargin) }
.pull { width: 75% }
[class*="cluster"], [class*="stack"] { --cluster-gap: .5em; --stack-gap: .5em; display: flex; flex-wrap: nowrap }
.cluster { align-items: center; flex-direction: row; gap: var(--cluster-gap) }
.cluster\:wrap { flex-wrap: wrap }
.stack { flex-direction: column; gap: var(--stack-gap) }

main { padding: var(--vertGap) 0 }
main .wrap { display: flex; flex-direction: column; gap: var(--vertGap) }
main .wrap > section:not(.cv-timeline) p:not(:last-child) { margin-block-end: 1em }

/* ---------- entrance ---------- */
/* Gated on .js — without it the page renders fully visible rather than blank. */
.js .drift {
	opacity: 0;
	position: relative;
	transition: left var(--enterTiming) var(--enterBounce), opacity var(--enterTiming) ease;
}
.js .drift.left { left: var(--enterDrift) }
.js .drift.right { left: calc(var(--enterDrift) * -1) }
.js .loaded .drift:not(.onscroll),
.js .loaded .drift.onscroll.shown,
.js .loaded .shown .drift.onscroll { opacity: 1; left: 0 }

.js .loading main .wrap > section:first-child {
	--delayedEnterTiming: calc(var(--enterTiming) * 1.2);
	opacity: 0;
	position: relative;
	top: calc(var(--enterDrift) * 2);
	transition: top var(--delayedEnterTiming) var(--delayedEnterTiming) var(--enterBounce),
		opacity var(--delayedEnterTiming) var(--delayedEnterTiming) ease;
}
.js .loaded main .wrap > section:first-child { opacity: 1; top: 0 }

/* ---------- header ---------- */
header {
	left: 0;
	padding-block-start: var(--headerPadTop);
	padding-block-end: var(--headerPadBtm);
	position: fixed;
	right: 0;
	top: 0;
	transition: transform var(--slideTime) var(--headerBounce);
	z-index: 200;
}
.me { font-weight: 700; top: 0; transition: top .12s ease, transform .17s ease }
.me:before { opacity: 0; transition: opacity var(--slideTime) var(--headerBounce), box-shadow .21s ease }
body:not(.scrolled) .me { cursor: default; pointer-events: none }
.scrolled header { transform: translateY(calc(var(--headerPadTop) / -2)) }
.scrolled .me:before { opacity: 1 }

/* ---------- mast ---------- */
.mast {
	margin: 0 auto;
	max-width: var(--outerBreakpoint);
	overflow: hidden;
	padding-block-start: var(--headerHeight);
	position: relative;
}
/* The portrait: a cut-out PNG on transparency, so it needs no mask and no
   brightness lifting — the alpha channel already dissolves it into the page,
   and there's no background left to fight the headline for contrast.
   Waist-up crop, bottom-anchored so it bleeds through the mast's bevel hairline
   — the same composition the original uses.
   (images/portrait-fullbody.webp is the head-to-shoes alternative: it stands on
   the bevel rather than through it, and wants `86% bottom / auto 92%`.) */
.mast:before {
	/* Height carries a vw term, like the original's clamp(165%, 84vw, 200%): sized
	   off mast height alone he stays wide as the viewport narrows and collides
	   with the headline around 1024. The vw term shrinks him in step instead.
	   Bottom-anchored, not top: he must always meet the bevel. Top-anchored he
	   floats with a gap beneath him whenever he's shorter than the mast. The cap
	   is set so the overflow above never exceeds the crop's headspace. */
	background: url(images/portrait.webp) 96% bottom / auto clamp(420px, 52vw, 760px) no-repeat;
	filter: grayscale(1) contrast(.94);
	opacity: .92;
	content: "";
	inset: 0 -2% 0 0;
	position: absolute;
	transform: translateY(var(--plax));
	transition: opacity .48s ease, right .48s ease;
	will-change: transform;
	z-index: 1;
}
.mast:after {
	--breakpointDelta: calc(var(--outerBreakpoint) - var(--innerBreakpoint));
	background: var(--color-bevel);
	bottom: 0;
	content: "";
	height: 1px;
	left: calc(var(--outerPad) + clamp(0px, calc((100% - var(--innerBreakpoint)) / 2), var(--breakpointDelta)));
	mix-blend-mode: overlay;
	position: absolute;
	right: 0;
	transition: opacity .48s ease;
	z-index: 2;
}
/* 34%, not the original's 30%: this portrait is a crisp cut-out rather than a
   pale wash, so the headline can't run under it — the text column has to end
   before he starts. The 3:4 crop is wide, so this is 38% rather than 34%. */
.mast h1 {
	padding: calc(var(--vertGapLarge) - var(--size-l)) 38% var(--vertGapLarge) 0;
	position: relative;
	z-index: 3;
}
.js body:not(.loaded) .mast:before, .js body:not(.loaded) .mast:after { opacity: 0 }

.pull[data-section="specialty"] { max-width: 930px }

/* ---------- simple / detailed toggle ---------- */
.option-toggle {
	--switchH: 2.6rem;
	--switchW: 5.7rem;
	--inset: .1rem;
	--knobSize: calc(var(--switchH) - (var(--inset) * 2));
	--radius: calc(var(--switchH) / 2);
	--speed: .24s;
	align-items: center;
	cursor: pointer;
	display: none;
	flex-direction: row;
	font-weight: 500;
	gap: 1em;
	justify-content: center;
	user-select: none;
}
.option-toggle span.label { transition: color var(--speed) ease }
.option-toggle:not(:has(input[type="checkbox"]:checked)) span.label:last-of-type { color: var(--color-fill-light) }
.option-toggle:has(input[type="checkbox"]:checked) span.label:first-of-type { color: var(--color-fill-light) }

.toggle input[type="checkbox"] { opacity: 0; position: absolute }
.toggle .switch {
	--smallShadow: calc(var(--inset) * 1.25);
	--bigShadow: calc(var(--inset) * 4);
	background: var(--color-bg);
	border-radius: var(--radius);
	box-shadow:
		inset 0 0 var(--switchH) var(--switchH) color-mix(in srgb, currentColor, transparent 93%),
		inset 0 var(--smallShadow) var(--bigShadow) color-mix(in srgb, currentColor, transparent 69%),
		inset 0 calc(var(--knobSize) / 3) var(--bigShadow) color-mix(in srgb, currentColor, transparent 84%),
		0 calc(var(--inset) * -1) var(--inset) color-mix(in srgb, currentColor, transparent 81%),
		0 var(--inset) var(--inset) #ffffffbf;
	display: block;
	height: var(--switchH);
	position: relative;
	transition: background var(--speed) ease;
	width: var(--switchW);
}
.toggle .switch:before, .toggle .switch:after {
	border-radius: var(--radius);
	content: "";
	display: block;
	height: var(--knobSize);
	left: var(--inset);
	position: absolute;
	top: var(--inset);
	width: var(--knobSize);
	z-index: 50;
	transition: left var(--speed) ease, background var(--speed) ease;
}
.toggle .switch:before {
	background-color: color-mix(in srgb, currentColor, var(--color-bg) 93%);
	box-shadow: inset 0 var(--inset) var(--inset) #ffffffbf,
		inset 0 calc(var(--inset) * -1) var(--inset) color-mix(in srgb, currentColor, transparent 81%),
		0 calc(var(--inset) * 2) calc(var(--inset) * 2) color-mix(in srgb, currentColor, transparent 62%);
}
.toggle .switch:after { opacity: .4; transition: opacity var(--speed) ease }
.toggle input[type="checkbox"]:checked ~ .switch { background: var(--color-fill-light) }
.toggle input[type="checkbox"]:checked ~ .switch:before,
.toggle input[type="checkbox"]:checked ~ .switch:after { left: calc(var(--switchW) - var(--knobSize) - var(--inset)) }
.toggle input[type="checkbox"]:checked ~ .switch:after { opacity: .8 }
.toggle input[type="checkbox"]:focus-visible ~ .switch { outline: 2px solid var(--color-fill); outline-offset: 3px }

/* ---------- cv timeline ---------- */
.cv-intro { margin-block-end: var(--cvGap) }
.cv { display: flex; flex-direction: column }
.cv .exp { align-items: baseline; display: flex; gap: var(--innerPad); width: 100% }
.cv .time {
	align-self: baseline;
	text-align: right;
	white-space: nowrap;
	min-width: calc(var(--centerMargin) - var(--innerPad));
}
.cv .time abbr:before { content: "20" }
.cv .time abbr._90s:before { content: "19" }
.cv .details, .cv .title { position: relative }
.cv .role { padding-block-end: .5em }
.cv .role h3 { display: inline }
.cv .role .title { padding-inline-end: .125em }
.cv .role .company { white-space: nowrap }
.cv .role .company:before { content: "at"; display: inline-block; font-weight: 400; padding-inline-end: .25em }

.cv .info p {
	font-size: var(--size-s);
	margin-block-end: 0;
	padding-block-end: var(--cvGap);
	position: relative;
}
.cv .info p:has(+ p) { padding-block-end: 1em }

/* the rail: a 2px bar and a 12px node, both pseudo-elements */
.cv > li:not(:last-child) .info p:before,
.cv .details:before {
	background: var(--color-fill);
	content: "";
	height: 100%;
	left: calc((var(--innerPad) - 1px) / -2);
	mix-blend-mode: overlay;
	position: absolute;
	top: 0;
	width: 2px;
	z-index: 10;
}
.cv > li:first-child .details:before { height: calc(100% - 1em); top: 1em }
.cv > li:last-child .details:before { height: 1.125em }
.cv > li:last-child .info p:last-child { padding-block-end: 0 }
.cv .title:before {
	--dotCenter: calc((var(--size-m) * 1.4 - var(--dotSize)) / 2);
	background: var(--color-bg);
	border: 2px solid var(--color-fill);
	border-radius: 100%;
	content: "";
	height: var(--dotSize);
	left: calc((var(--innerPad) + var(--dotSize) - 3px) / -2);
	position: absolute;
	top: var(--dotCenter);
	width: var(--dotSize);
	z-index: 20;
}

/* early-career fade + collapse */
.cv > li.faded {
	--alphaColor: color-mix(in srgb, currentColor, transparent 39%);
	--alphaBg: color-mix(in srgb, var(--color-bg), transparent 100%);
	color: var(--alphaColor);
	position: relative;
	transition: color .48s ease;
}
.cv > li.faded .title:before { border-color: var(--alphaColor); transition: border-color .48s ease }
.cv > li.faded:after {
	background: linear-gradient(180deg, var(--alphaBg) 0%, var(--color-bg) 84%, var(--color-bg) 100%);
	content: "";
	inset: 0;
	opacity: 1;
	position: absolute;
	transition: opacity .48s ease;
	z-index: 50;
}
/* ponytail: plain display toggle, not the 0fr/1fr height animation the original
   uses. That trick needs `overflow: hidden` on the grid item to collapse, and
   that same property zeroes the row's automatic minimum so `1fr` resolves to 0
   and it never expands. Verified both ways in Chrome. Ceiling: no slide, it
   snaps. Upgrade path: `transition-behavior: allow-discrete` plus
   `@starting-style` once that's baseline, which animates display directly. */
.cv > li.faded ~ li { display: none }
.cv.show-all > li.faded { --alphaColor: currentColor }
.cv.show-all > li.faded:after { opacity: 0 }
.cv.show-all > li.faded ~ li { display: list-item }

.cv-timeline .more { font-size: var(--size-s); font-weight: 700; margin-inline-start: .75em; z-index: 51 }
.cv-timeline .more .state:after { content: "Early Career" }
.cv-timeline .more .arrow { display: inline-block; margin-inline-end: .25em; transition: transform .24s ease }
.cv-timeline p:has(.more) { margin-block-start: -1em; transition: margin-block-start .24s ease }
.cv-timeline:has(.cv.show-all) .more .state:after { content: "Less, Please" }
.cv-timeline:has(.cv.show-all) .more .arrow { transform: rotate(180deg) }
.cv-timeline:has(.cv.show-all) p:has(.more) { margin-block-start: 1em }

/* ---------- this & that ---------- */
/* ponytail: native <details> for the five sport expanders. Five independent
   disclosures don't need the checkbox+:has() rig — that one earns its keep only
   where a single control drives many rows, i.e. the CV toggle above. */
/* The expanders are no longer shown: the lightbox panels replaced them. They stay
   in the markup as the panels' data source, and as the no-JS fallback — hence
   `.js`, not a plain `display: none`. Without JS there is no lightbox, so the
   numbers have to render somewhere. */
.js .expanders { display: none }
.expanders {
	display: flex;
	flex-direction: column;
	margin-block: var(--cvGap);
}
.expanders details { border-block-start: 1px solid color-mix(in srgb, var(--color-fill), transparent 84%) }
.expanders details:last-of-type { border-block-end: 1px solid color-mix(in srgb, var(--color-fill), transparent 84%) }
.expanders summary {
	align-items: baseline;
	cursor: pointer;
	display: flex;
	gap: 1em;
	list-style: none;
	padding-block: .84em;
	position: relative;
	user-select: none;
}
.expanders summary::-webkit-details-marker { display: none }
.expanders summary:after {
	content: "+";
	font-family: var(--font-mono);
	margin-inline-start: auto;
	transition: transform .24s ease;
}
.expanders details[open] summary:after { transform: rotate(45deg) }
/* The reset's `display: block` on details/summary defeats the UA rule that hides
   closed content. One explicit line beats depending on the UA stylesheet. */
.expanders details:not([open]) .ex-body { display: none }
.ex-label { font-size: var(--size-m); font-weight: 700 }
.ex-teaser { color: var(--color-fill-light); font-size: var(--size-s) }
.ex-body { padding-block-end: 1.34em }
:is(.expanders, .lightbox-body) .data { font-size: var(--size-s); width: 100%; max-width: 620px }
:is(.expanders, .lightbox-body) .data :is(th, td) { padding-block: .34em; text-align: left; vertical-align: baseline }
:is(.expanders, .lightbox-body) .data th[scope="row"] { font-weight: 400; padding-inline-end: 2em; width: 42% }
:is(.expanders, .lightbox-body) .data td { font-family: var(--font-mono) }
:is(.expanders, .lightbox-body) .data thead th { color: var(--color-fill-light); font-weight: 400 }
:is(.expanders, .lightbox-body) .pace { color: var(--color-fill-light); margin-inline-start: .62em }
:is(.expanders, .lightbox-body) .where {
	color: var(--color-fill-light);
	display: block;
	font-family: var(--font-standard);
	padding-block-start: .21em;
}
:is(.expanders, .lightbox-body) :is(.note, .asof) {
	font-size: var(--size-s);
	max-width: 620px;
	padding-block-start: 1em;
}
:is(.expanders, .lightbox-body) .asof { color: var(--color-fill-light) }

.tag {
	backdrop-filter: saturate(142%) blur(20px);
	background: color-mix(in srgb, #fff, transparent 75%);
	border-radius: .43em;
	box-shadow: #00000012 0 0 0 1px, inset #ffffff1f 1px 1px, inset #ffffff57 0 1px 6px;
	font-size: var(--size-s);
	margin-inline-end: .2em;
	padding: .2em .6em;
	position: relative;
	top: -.1em;
}
.tag:has(.emoji) { padding: .2em .4em .2em .6em }
.emoji:not(.color) { filter: saturate(0) }
.emoji.invert { filter: saturate(0) invert(1) }
.list .emoji { margin-inline-end: .5em }
.lightning { padding-block-start: 1em; padding-block-end: 1.25em }

.music [role="button"] { cursor: pointer }
.music [role="button"] svg { display: block; position: relative }
.music [role="button"] svg path { fill: var(--color-fill); transition: fill .21s ease }
.music [role="button"].active { cursor: default }
.music [role="button"]:not(.active) svg path { fill: var(--color-fill-light) }
.music [role="button"]:not(.active):hover svg path { fill: var(--color-fill) }
.music .spotify svg { top: -1px }
.music .apple svg { top: -3px }

.player { height: 450px; position: relative; width: 100% }
.player iframe {
	background: transparent;
	border-radius: 12px;
	height: 450px;
	left: 0;
	mix-blend-mode: luminosity;   /* blends third-party branding into the palette */
	opacity: .93;
	overflow: hidden;
	position: absolute;
	top: 0;
	transition: left var(--enterTiming) var(--enterBounce), opacity var(--enterTiming) ease;
	width: 100%;
}
.player iframe:not(.active) {
	left: calc(var(--enterDrift) * -1);
	opacity: 0;
	pointer-events: none;
}

.note-inline { font-size: var(--size-s) }

/* Confirmation that the address reached the clipboard, for when the mailto
   itself did nothing. */
.copied {
	background: color-mix(in srgb, var(--color-bg), #fff 42%);
	border-radius: .43em;
	box-shadow: #00000012 0 0 0 1px;
	display: block;
	font-family: var(--font-mono);
	font-size: var(--size-s);
	margin-block-start: 1em;
	padding: .34em .62em;
	white-space: nowrap;
	width: fit-content;
}

/* ---------- lightbox ---------- */
.rgbsplit[data-media], .rgbsplit[data-panel] { cursor: pointer }
.lightbox {
	background: transparent;
	border: 0;
	max-height: 100dvh;
	max-width: 100vw;
	overflow: visible;
	padding: 0;
}
.lightbox::backdrop {
	backdrop-filter: saturate(142%) blur(21px);
	background: color-mix(in srgb, var(--color-bg), transparent 42%);
}
/* [hidden] has to be re-asserted: the display rules below would otherwise win
   over the UA stylesheet and a panel with no photo would show a broken image. */
.lightbox [hidden] { display: none }
.lightbox-inner {
	background: color-mix(in srgb, var(--color-bg), #fff 42%);
	border-radius: 12px;
	box-shadow: #00000008 0 3px, #00000036 0 3px 66px;
	max-height: 86dvh;
	overflow-y: auto;
	padding-block-end: 1.34em;
	width: min(92vw, 560px);
}
.lightbox img {
	border-radius: 12px 12px 0 0;
	display: block;
	filter: grayscale(1) contrast(.94);
	max-height: 44dvh;
	object-fit: cover;
	object-position: center 22%;
	width: 100%;
}
.lightbox-title {
	font-size: var(--size-m);
	padding: .84rem 1.12rem .21rem;
}
.lightbox-body { padding-inline: 1.12rem }
.lightbox-body .data { max-width: none }
.lightbox-body :is(.note, .asof) { max-width: none }
.lightbox-note {
	color: var(--color-fill);
	font-size: var(--size-s);
	line-height: 1.4;
	padding: 1.12rem 1.12rem 0;
	text-wrap: pretty;
}
.lightbox-note strong { font-family: var(--font-mono); font-weight: 400 }
.lightbox-close {
	background: transparent;
	border: 0;
	color: var(--color-fill);
	cursor: pointer;
	font-size: 2rem;
	line-height: 1;
	padding: .25em;
	position: absolute;
	right: -.1em;
	top: -2.1em;
}
@media screen and (width < 768px) {
	.lightbox img { max-height: 34dvh }
	.lightbox-close { right: 0; top: -1.9em }
}

/* ---------- footer ---------- */
footer { padding-block-end: var(--innerPad) }
footer .wrap { align-items: baseline; display: flex; padding-block-start: 2em; position: relative }
footer .wrap:before {
	background: var(--color-fill);
	content: "";
	height: 1px;
	left: var(--outerPad);
	mix-blend-mode: overlay;
	position: absolute;
	right: var(--outerPad);
	top: 0;
}
footer p { font-size: var(--size-s); flex: 0; white-space: nowrap }
footer ul { display: flex; flex: 1; gap: 1.5em; justify-content: flex-end; white-space: nowrap }
footer .hello {
	--startAngle: 17deg;
	--helloScale: scale(1.69);
	--helloTranslate: translateX(.34em) translateY(.125em);
	animation-fill-mode: forwards;
	display: inline-block;
	transform: rotate(var(--startAngle)) scale(1);
	transform-origin: 69% 73%;
	transition: transform .24s ease-out;
}
footer:hover .hello { animation: waveHello 1.34s ease-in-out forwards }
footer:not(:hover) .hello { animation: waveHelloReverse .24s var(--linkBtnBounce) forwards }

@keyframes waveHello {
	0%   { transform: rotate(var(--startAngle)) scale(1) }
	15%  { transform: var(--helloTranslate) rotate(var(--startAngle)) var(--helloScale) }
	25%  { transform: var(--helloTranslate) rotate(calc(var(--startAngle) + 9deg)) var(--helloScale) }
	35%  { transform: var(--helloTranslate) rotate(calc(var(--startAngle) + -12deg)) var(--helloScale) }
	45%  { transform: var(--helloTranslate) rotate(calc(var(--startAngle) + 21deg)) var(--helloScale) }
	55%  { transform: var(--helloTranslate) rotate(calc(var(--startAngle) + -9deg)) var(--helloScale) }
	65%  { transform: var(--helloTranslate) rotate(calc(var(--startAngle) + 17deg)) var(--helloScale) }
	75%  { transform: var(--helloTranslate) rotate(var(--startAngle)) var(--helloScale) }
	100% { transform: var(--helloTranslate) rotate(var(--startAngle)) var(--helloScale) }
}
@keyframes waveHelloReverse {
	0%   { transform: var(--helloTranslate) rotate(var(--startAngle)) var(--helloScale) }
	100% { transform: rotate(var(--startAngle)) scale(1) }
}

/* ---------- focus ---------- */
a:focus-visible, [role="button"]:focus-visible, summary:focus-visible {
	outline: 2px solid var(--color-fill);
	outline-offset: 4px;
	border-radius: 2px;
}

/* ---------- breakpoints ---------- */
@media screen and (width > 1650px) {
	.mast h1 { padding-inline-end: 20% }
}

@media screen and (width > 1920px) {
	.mast { border-radius: 0 0 1em }
	.mast:after {
		background: transparent;
		border-radius: 0 0 1em;
		bottom: 0;
		box-shadow: inset var(--color-bevel) -1px 0 0, inset var(--color-bevel) 0 -1px 0;
		height: auto;
		top: 0;
	}
}

@media screen and (width < 1024px) {
	* { -webkit-tap-highlight-color: transparent }
	header .push { margin-inline-start: 0 }
	main section.push { margin-inline-start: 0 }
	main section.pull { width: 100% }
	main .pull[data-section="specialty"] { max-width: none }
	main .cv-timeline .cv .time { min-width: 120px; width: 120px }
	main .cv-timeline .push { margin-inline-start: calc(120px + var(--innerPad)) }
	main h2 { text-wrap: pretty }
}

@media screen and (width < 768px) {
	:root { --size-l: 2.1rem; --size-m: 1.25rem; --headerPadTop: 3.4rem; --vertGapLarge: 7.5rem; --vertGap: 5.7rem }

	.mast { min-height: 100lvh }
	.mast .wrap {
		display: flex;
		flex-direction: column;
		justify-content: flex-start;
		min-height: calc(100lvh - var(--headerHeight));
		padding-block-start: 4vh;
	}
	.mast h1 {
		margin-block-start: 0;
		max-width: 300px;
		padding-block: 0;
		padding-inline-end: 0;
		position: relative;
	}
	/* The original slides its photo off the right edge at this width. A cut-out
	   can't be cropped that way without bisecting him, so the hero restacks
	   instead: headline top, runner bottom, no overlap. */
	.mast:before {
		background-position: 94% bottom;
		background-size: auto 52%;
	}
	.mast h1:after {
		animation: arrowDrift .84s ease-in-out infinite alternate;
		content: "\2193";
		font-family: var(--font-arrow);
		font-size: var(--size-m);
		left: 0;
		position: absolute;
		top: calc(100% + 1em);
	}
	.mast:after { left: 0 }

	main .cv-timeline {
		margin-block-start: calc((var(--vertGap) * -1) + (var(--cvGap) * 1.75));
	}
	main .cv-timeline .cv-intro { display: none }
	main .cv-timeline .option-toggle {
		display: flex;
		margin-block-start: calc(var(--cvGap) * -.25);
		margin-block-end: calc(var(--cvGap) * 1.5);
	}
	main .cv-timeline .cv-wrap .time { transition: padding-block-end .24s ease }

	/* Simple mode: hide every entry's detail. Still zero JS — :has() reads the
	   checkbox. See the ponytail note on .faded for why this is display, not a
	   height animation. */
	main .cv-timeline:not(:has(.toggle input[type="checkbox"]:checked)) .cv-wrap .info { display: none }
	main .cv-timeline:not(:has(.toggle input[type="checkbox"]:checked)) .cv-wrap .time { padding-block-end: 2.5em }
	main .cv-timeline:not(:has(.toggle input[type="checkbox"]:checked)) .cv li:first-child .details:before { height: calc(100% + 3em) }
	main .cv-timeline:not(:has(.toggle input[type="checkbox"]:checked)) .cv li:not(:first-child):not(:last-child) .details:before { height: calc(100% + 4em) }

	main .cv-timeline .exp {
		flex-direction: column;
		gap: .5em;
		margin-inline-start: 48px;
		width: auto;
	}
	main .cv-timeline .exp .details { order: 1 }
	main .cv-timeline .exp .details .role { padding-block-end: 0 }
	main .cv-timeline .exp .time { color: var(--color-fill-light); order: 2; padding-block-end: 1em; text-align: left }
	main .cv-timeline .push { margin-inline-start: 0 }
	main .cv-timeline .cv .push { margin-inline-start: 48px }
	main .cv-timeline .cv li:not(:first-child) .details:before { height: calc(100% + 2.5em); top: 0 }
	main .cv-timeline .cv li:first-child .details:before { height: calc(100% + 1.5em); top: 1em }
	main .cv-timeline .cv li:last-child .details:before { height: 1em }

	:is(.expanders, .lightbox-body) .data th[scope="row"] { width: 50%; padding-inline-end: 1em }
	.player, .player iframe { height: 380px }

	footer { padding-block-end: calc(var(--innerPad) / 2) }
	footer .wrap { flex-direction: column; gap: 1em }
	footer ul { justify-content: flex-start }
}

@keyframes arrowDrift {
	0%   { transform: translateY(0) }
	100% { transform: translateY(.5em) }
}

/* ---------- motion preference ----------
   The original ships no reduced-motion block. This is the one place the rebuild
   deliberately diverges. */
@media (prefers-reduced-motion: reduce) {
	*, *:before, *:after {
		animation-duration: .01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .01ms !important;
		scroll-behavior: auto !important;
	}
	.drift { opacity: 1 !important; left: 0 !important }
	.loading main .wrap > section:first-child { opacity: 1; top: 0 }
	.mast:before { transform: none !important }
}
