/* Cover motion from geniuskey/books, MIT. See LICENSE-MIT. */
/* svg.cover-art outranks the later .cv-* rules, whose animation shorthand would otherwise reset the play state to running. */
svg.cover-art * { animation-play-state: paused; }
.card:hover .cover-art *, .card:focus-within .cover-art *, .book:hover .cover-art *, .book:focus-within .cover-art * { animation-play-state: running; }
.cv-blink { animation: cv-blink 1.6s steps(1) infinite; }
@keyframes cv-blink { 50% { fill-opacity: .12; } }
.cv-fall { animation: cv-fall 1.8s ease-in infinite; }
@keyframes cv-fall { from { transform: translateY(-14px); opacity: 0; } 15% { opacity: 1; } 75% { opacity: 1; } to { transform: translateY(40px); opacity: 0; } }
.cv-grow { transform-box: fill-box; transform-origin: bottom; animation: cv-grow 2.4s ease-in-out infinite alternate; }
@keyframes cv-grow { from { transform: scaleY(.45); } }
.cv-pulse { animation: cv-pulse 2s ease-in-out infinite; }
@keyframes cv-pulse { 50% { fill-opacity: .1; } }
.cv-iris { animation: cv-iris 2.6s ease-in-out infinite alternate; }
@keyframes cv-iris { from { transform: scale(.55) rotate(-25deg); } to { transform: scale(1.12) rotate(10deg); } }
.cv-flow { animation: cv-flow 1s linear infinite; }
@keyframes cv-flow { to { stroke-dashoffset: -20; } }
.cv-drop { animation: cv-drop 2.4s ease-out infinite; }
@keyframes cv-drop { from { transform: translateY(-30px); opacity: 0; } 30% { transform: none; opacity: 1; } }
.cv-scan-lens { animation: cv-scan 3s ease-in-out infinite; }
@keyframes cv-scan { 0%, 100% { transform: translate(-40px, -30px); } 45%, 55% { transform: none; } }
.cv-wave { transform-box: fill-box; transform-origin: left center; animation: cv-wave 1.5s ease-out infinite; }
@keyframes cv-wave { from { opacity: 0; transform: scale(.6); } 40% { opacity: 1; } to { opacity: 0; transform: scale(1.2); } }
.cv-slide { animation: cv-slide 1.2s linear infinite; }
.cv-shear { animation: cv-shear 2.8s ease-in-out infinite alternate; }
@keyframes cv-shear { to { transform: skewX(-28deg) scaleY(1.15); } }
@keyframes cv-slide { to { transform: translateX(var(--dx)); } }
.cv-sweep { animation: cv-sweep 2.4s linear infinite; }
@keyframes cv-sweep { 90% { transform: translateX(var(--dx)); opacity: 1; } to { transform: translateX(var(--dx)); opacity: 0; } }
.cv-hit { transform-box: fill-box; transform-origin: center; animation: cv-hit 2.4s ease-out infinite; }
@keyframes cv-hit { 0%, 16%, 100% { transform: none; } 5% { transform: scale(1.35); } }
.cv-breathe { transform-box: fill-box; transform-origin: 100% 0; animation: cv-breathe 2.4s ease-in-out infinite; }
@keyframes cv-breathe { 50% { transform: scale(1.16); } }
.cv-run { animation: cv-run 1.6s linear infinite; }
@keyframes cv-run { from { opacity: 0; } 15%, 85% { opacity: 1; } to { opacity: 0; transform: translateX(var(--dx)); } }
.cv-turn { animation: cv-turn 6s linear infinite; }
@keyframes cv-turn { 25% { transform: scaleX(.7); } 50% { transform: scaleX(0); } 75% { transform: scaleX(-.7); } to { transform: scaleX(-1); } }
.cv-ping { animation: cv-ping 1.8s ease-out infinite; }
@keyframes cv-ping { 70%, to { transform: scale(2.2); opacity: 0; } }
.cv-bob { animation: cv-bob 3.2s ease-in-out infinite; }
@keyframes cv-bob { 25% { transform: translateY(1.5px) rotate(1.4deg); } 75% { transform: translateY(-1.5px) rotate(-1.2deg); } }
.cv-rise { transform-box: fill-box; transform-origin: center; animation: cv-rise 2.4s ease-out infinite; }
@keyframes cv-rise { to { transform: translate(-14px, -26px) scale(2.2); opacity: 0; } }
.cv-coin { animation: cv-coin 2.6s ease-in infinite; }
@keyframes cv-coin { from { transform: translateY(-34px); opacity: 0; } 22% { transform: none; opacity: 1; } 26% { transform: translateY(-2px); } 30%, to { transform: none; } }
.cv-draw { animation: cv-draw 2.6s ease-in-out infinite; }
@keyframes cv-draw { 6% { stroke-dashoffset: 0; opacity: 0; } 7% { stroke-dashoffset: 1; opacity: 1; } 80%, to { stroke-dashoffset: 0; } }
.cv-depth { transform-box: fill-box; transform-origin: right center; animation: cv-depth 1.8s ease-in-out infinite; }
@keyframes cv-depth { 50% { transform: scaleX(.5); } }

/* fab · process · etch: made for SemiBooks and shared with the books portal, MIT.
   Their un-animated markup equals the first frame, so dropping the animation still leaves a finished picture. */
/* fab: OHT travels the ceiling rail, stops over the load port and lowers its FOUP. */
.fb-oht { animation: fb-oht 6s ease-in-out infinite; }
@keyframes fb-oht { 0% { transform: translateX(0); opacity: 0; } 5% { opacity: 1; } 40%, 64% { transform: translateX(calc(var(--dx) / 2)); opacity: 1; } 95% { opacity: 1; } 100% { transform: translateX(var(--dx)); opacity: 0; } }
.fb-hoist { animation: fb-hoist 6s ease-in-out infinite; }
@keyframes fb-hoist { 0%, 42%, 62%, 100% { transform: none; } 48%, 56% { transform: translateY(10px); } }
.fb-belt { transform-box: fill-box; transform-origin: top; animation: fb-belt 6s ease-in-out infinite; }
@keyframes fb-belt { 0%, 42%, 62%, 100% { transform: none; } 48%, 56% { transform: scaleY(6); } }

/* process: deposit → expose → etch → implant → wire in one 7 s cycle; 0–6 % and 92–100 % hold the finished transistor. */
.pr-progress { transform-box: fill-box; transform-origin: left; animation: pr-progress 7s ease-in-out infinite; }
@keyframes pr-progress { 0%, 6% { transform: scaleX(1); } 10%, 25% { transform: scaleX(0); } 27%, 43% { transform: scaleX(.25); } 45%, 59% { transform: scaleX(.5); } 61%, 75% { transform: scaleX(.75); } 77%, 100% { transform: scaleX(1); } }
.pr-node { animation: pr-node 7s ease-in-out infinite; }
@keyframes pr-node { 0%, 6% { transform: none; } 10%, 25% { transform: translateX(-120px); } 27%, 43% { transform: translateX(-90px); } 45%, 59% { transform: translateX(-60px); } 61%, 75% { transform: translateX(-30px); } 77%, 100% { transform: none; } }
.pr-sd { animation: pr-sd 7s ease-in-out infinite; }
@keyframes pr-sd { 0%, 6% { opacity: 1; } 10%, 64% { opacity: 0; } 74%, 100% { opacity: 1; } }
.pr-gate { transform-box: fill-box; transform-origin: bottom; animation: pr-gate 7s ease-in-out infinite; }
@keyframes pr-gate { 0%, 6% { opacity: 1; transform: scaleY(1); } 10% { opacity: 0; transform: scaleY(1); } 10.1%, 12% { opacity: 1; transform: scaleY(0); } 26%, 100% { opacity: 1; transform: scaleY(1); } }
.pr-film { transform-box: fill-box; transform-origin: bottom; animation: pr-film 7s ease-in-out infinite; }
@keyframes pr-film { 0%, 12% { opacity: 1; transform: scaleY(0); } 26%, 46% { opacity: 1; transform: scaleY(1); } 56%, 100% { opacity: 1; transform: scaleY(0); } }
.pr-spacer, .pr-ild { animation: pr-late 7s ease-in-out infinite; }
@keyframes pr-late { 0%, 6% { opacity: 1; } 10%, 77% { opacity: 0; } 81%, 100% { opacity: 1; } }
.pr-contact { transform-box: fill-box; transform-origin: bottom; animation: pr-contact 7s ease-in-out infinite; }
@keyframes pr-contact { 0%, 6% { opacity: 1; transform: scaleY(1); } 10% { opacity: 0; transform: scaleY(1); } 10.1%, 80% { opacity: 0; transform: scaleY(0); } 80.1% { opacity: 1; transform: scaleY(0); } 86%, 100% { opacity: 1; transform: scaleY(1); } }
.pr-metal { animation: pr-metal 7s ease-in-out infinite; }
@keyframes pr-metal { 0%, 6% { opacity: 1; transform: none; } 10%, 86% { opacity: 0; transform: translateY(-5px); } 92%, 100% { opacity: 1; transform: none; } }
.pr-resist-c { animation: pr-resist-c 7s ease-in-out infinite; }
@keyframes pr-resist-c { 0%, 26% { opacity: 0; } 30%, 56% { opacity: 1; } 60%, 100% { opacity: 0; } }
.pr-resist-s { animation: pr-resist-s 7s ease-in-out infinite; }
@keyframes pr-resist-s { 0%, 26% { opacity: 0; } 30%, 35% { opacity: 1; } 41% { opacity: .3; } 45%, 100% { opacity: 0; } }
.pr-mask { animation: pr-mask 7s ease-in-out infinite; }
@keyframes pr-mask { 0%, 28% { opacity: 0; transform: translateY(-8px); } 32%, 41% { opacity: 1; transform: none; } 44%, 100% { opacity: 0; transform: none; } }
.pr-ray { animation: pr-ray 7s ease-in-out infinite, cv-flow .8s linear infinite; }
@keyframes pr-ray { 0%, 32% { opacity: 0; } 34%, 41% { opacity: 1; } 43%, 100% { opacity: 0; } }
.pr-etch { animation: pr-etch 7s ease-in infinite; }
@keyframes pr-etch { 0%, 46% { opacity: 0; transform: none; } 47% { opacity: 1; transform: none; } 51% { opacity: 1; transform: translateY(40px); } 52%, 100% { opacity: 0; transform: translateY(40px); } }
.pr-ion { animation: pr-ion 7s ease-in infinite; }
@keyframes pr-ion { 0%, 60% { opacity: 0; transform: none; } 61% { opacity: 1; transform: none; } 66% { opacity: 1; transform: translateY(74px); } 67%, 100% { opacity: 0; transform: translateY(74px); } }

/* etch: trenches deepen at a constant rate (narrow ones lag, ARDE), hold, then refill while the plasma dims. */
.et-front { transform-box: fill-box; transform-origin: bottom; animation: et-front 6s linear infinite; }
@keyframes et-front { 0% { transform: scaleY(1); } 18% { transform: scaleY(var(--k1)); } 50% { transform: scaleY(var(--k1)); animation-timing-function: ease-in-out; } 58% { transform: scaleY(var(--kf)); } 100% { transform: scaleY(1); } }
.et-wall { transform-box: fill-box; transform-origin: top; animation: et-wall 6s linear infinite; }
@keyframes et-wall { 0% { transform: scaleY(1); } 18% { transform: scaleY(1.4286); } 50% { transform: scaleY(1.4286); animation-timing-function: ease-in-out; } 58% { transform: scaleY(0); } 100% { transform: scaleY(1); } }
.et-glow { animation: et-glow 6s ease-in-out infinite; }
@keyframes et-glow { 0%, 48% { opacity: 1; } 52%, 56% { opacity: .25; } 60%, 100% { opacity: 1; } }
.et-gate { animation: et-gate 6s ease-in-out infinite; }
@keyframes et-gate { 0%, 48% { opacity: 1; } 50%, 58% { opacity: 0; } 60%, 100% { opacity: 1; } }
.et-ion { animation: et-ion .9s cubic-bezier(.55, 0, 1, .45) infinite; }
@keyframes et-ion { 0% { transform: none; opacity: 0; } 12%, 85% { opacity: 1; } 100% { transform: translateY(var(--dy)); opacity: 0; } }
.et-out { transform-box: fill-box; transform-origin: center; animation: et-out 2.2s ease-out infinite; }
@keyframes et-out { 0% { transform: scale(.6); opacity: 0; } 20% { opacity: .95; } 100% { transform: translate(var(--ox), -46px) scale(1.25); opacity: 0; } }
.et-drift { animation: et-drift 2.4s ease-in-out infinite alternate; }
@keyframes et-drift { to { transform: translate(4px, -2px); } }

/* guitar · piano · drums: MusicBooks instrument covers, MIT. Like fab · process · etch, the un-animated markup is a finished picture. */
/* guitar: the pick strums eighth notes; on the hit beats of ↓ ↓↑ ↑↓↑ the six string envelopes swell and decay, and the arrow lights. */
.gt-pick { animation: gt-pick .6s ease-in-out infinite; }
@keyframes gt-pick { 50% { transform: translateY(var(--dy)); } }
.gt-ring { transform-box: fill-box; transform-origin: center; animation: gt-ring 2.4s ease-out infinite; }
@keyframes gt-ring { 0%, 25%, 37.5%, 62.5%, 75%, 87.5% { opacity: .8; transform: none; } 12.4%, 37.4%, 49.9%, 74.9%, 87.4%, 100% { opacity: .22; transform: scaleY(.45); } 24.9%, 62.4% { opacity: 0; transform: scaleY(.2); } }
.gt-beat { animation: gt-beat 2.4s ease-out infinite; }
@keyframes gt-beat { 0% { stroke: #ffd27a; stroke-opacity: 1; } 25%, 100% { stroke: currentColor; stroke-opacity: .45; } }
/* piano: the left hand changes chord every beat (0.8 s), the right-hand melody every eighth note (0.4 s). */
.pn-chord { animation: pn-chord 3.2s infinite; }
@keyframes pn-chord { 0%, 22% { opacity: 1; } 25%, 100% { opacity: 0; } }
.pn-note { animation: pn-note 3.2s infinite; }
@keyframes pn-note { 0%, 10% { opacity: 1; } 12.5%, 100% { opacity: 0; } }
/* drums: one 2.4 s bar at 100 BPM. Rings mark hits; the kick head thumps, the hi-hat dips each eighth, the crash swings after the fill. */
.dr-ring { transform-box: fill-box; transform-origin: center; animation: dr-ring 2.4s ease-out infinite; }
@keyframes dr-ring { 0% { opacity: .95; transform: none; } 22%, 100% { opacity: 0; transform: scale(1.6); } }
.dr-kick { transform-box: fill-box; transform-origin: center; animation: dr-kick 1.2s ease-out infinite; }
@keyframes dr-kick { 0% { transform: scale(1.03); } 20%, 100% { transform: none; } }
.dr-hat { animation: dr-hat .3s ease-out infinite; }
@keyframes dr-hat { 0% { transform: translateY(1.3px); } 60%, 100% { transform: none; } }
.dr-crash { transform-box: fill-box; transform-origin: center; animation: dr-crash 2.4s ease-out infinite; }
@keyframes dr-crash { 0% { transform: rotate(8deg); } 10% { transform: rotate(-5deg); } 22% { transform: rotate(3deg); } 36% { transform: rotate(-1.5deg); } 50%, 100% { transform: none; } }

/* bass: two fingers alternate every eighth note (0.3 s); each plucked string's envelope swells and decays, and the degree chips light beat by beat over one 2.4 s bar. */
.bs-finger { animation: bs-finger .6s ease-in-out infinite; }
@keyframes bs-finger { 0%, 100% { transform: none; } 45% { transform: translateY(-7px); } }
.bs-ring { transform-box: fill-box; transform-origin: center; animation: bs-ring 1.2s ease-out infinite; }
@keyframes bs-ring { 0% { opacity: .85; transform: none; } 70% { opacity: .3; transform: scaleY(.4); } 100% { opacity: 0; transform: scaleY(.15); } }
.bs-beat { animation: bs-beat 2.4s ease-out infinite; }
@keyframes bs-beat { 0% { opacity: 1; } 22%, 100% { opacity: .35; } }

@media (prefers-reduced-motion: reduce) { .cover-art * { animation: none !important; } .cover-art { transition: none; } }
/* SciBook covers (science-books), MIT: the same cv- motions renamed sc- so they do not collide with the cv- set above. */
.sc-spin { transform-box: view-box; transform-origin: 100px 65px; animation: sc-spin 6s linear infinite; }
@keyframes sc-spin { to { transform: rotate(360deg); } }
.sc-flow { animation: sc-flow 1.2s linear infinite; }
@keyframes sc-flow { to { stroke-dashoffset: -20; } }
.sc-pulse { animation: sc-pulse 1.8s ease-in-out infinite; }
@keyframes sc-pulse { 50% { opacity: .25; } }
.sc-fly { offset-rotate: 0deg; animation: sc-fly 2.6s ease-in-out infinite; }
@keyframes sc-fly { from { offset-distance: 0%; } to { offset-distance: 100%; } }
.sc-run { stroke-dasharray: 22 100; animation: sc-run 1.6s linear infinite; }
@keyframes sc-run { from { stroke-dashoffset: 22; } to { stroke-dashoffset: -100; } }
.sc-sway { animation: sc-sway 1.6s ease-in-out infinite alternate; }
@keyframes sc-sway { from { transform: translateX(-3px); } to { transform: translateX(3px); } }
.sc-hop { animation: sc-hop 2.2s ease-in-out infinite; }
@keyframes sc-hop { 0%, 15% { transform: none; } 50%, 80% { transform: translateY(-46px); } 100% { transform: translateY(-46px); opacity: 0; } }
.sc-travel { animation: sc-travel 1.8s linear infinite; }
@keyframes sc-travel { to { transform: translateX(56px); } }
.sc-grow { transform-box: fill-box; transform-origin: 50% 100%; animation: sc-grow 2.4s ease-in-out infinite alternate; }
@keyframes sc-grow { from { transform: scaleY(.35); } }
.sc-fall { animation: sc-fall 2.4s ease-in infinite; }
@keyframes sc-fall { from { transform: translateY(0); opacity: 0; } 15% { opacity: 1; } 80% { opacity: 1; } to { transform: translateY(56px); opacity: 0; } }
.sc-piston { animation: sc-piston 2s ease-in-out infinite alternate; }
@keyframes sc-piston { to { transform: translateY(14px); } }
.sc-jit { animation: sc-jit .9s steps(4) infinite; }
@keyframes sc-jit { 0% { transform: translate(0, 0); } 25% { transform: translate(3px, -2px); } 50% { transform: translate(-2px, 3px); } 75% { transform: translate(2px, 2px); } }
