/* Hasköy (SIL OFL 1.1), see fonts/OFL.txt */
@font-face {
  font-family: "Haskoy";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/Haskoy-variable.woff2") format("woff2");
}

@view-transition { navigation: auto; }

:root {
  --page: #f1ece4;

  --sky: oklch(82.8% 0.111 230.3);
  --sky-deep: oklch(68.5% 0.169 237.3);
  --clover: #77db89;
  --yolk: #f1cf63;
  --magenta: #f0628d;
  --lavender: #aeaeff;
  --clover-deep: color-mix(in display-p3, var(--clover), #000 25%);
  --yolk-deep: color-mix(in display-p3, var(--yolk), #000 25%);
  --magenta-deep: color-mix(in display-p3, var(--magenta), #000 25%);
  --lavender-deep: color-mix(in display-p3, var(--lavender), #000 25%);

  /* card surface */
  --bevel-w: 2px;
  --bevel-r: 1.5rem;
  --scanlines: repeating-linear-gradient(
    to bottom,
    rgb(255 255 255 / 0.15) 0 1px,
    transparent 1px 3px
  );
  --grain: url("assets/noise.png");
  --grain-size: 96px;
  --checker: 18px;
  --ink: 0 0 0;

  /* motion: four speeds and the curves to go with them */
  --dur-press: 80ms;
  --dur-quick: 150ms;
  --dur-base: 250ms;
  --dur-slow: 450ms;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in: cubic-bezier(0.5, 0, 0.75, 0);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* one light for the whole page. The head script leans it with the hour: from the left in the morning,
     overhead at noon, from the right by evening. Every bevel, sheen and gloss reads its angle from here. */
  --light: 180deg;
  --glow: 255 255 255;
  --glow-k: 1;
}
/* the blobs take the colour of the hour */
[data-daypart="dawn"] { --glow: 255 236 222; }
[data-daypart="dusk"] { --glow: 255 226 196; }
[data-daypart="night"] { --glow: 206 214 255; }

/* after hours (or when the system asks) the table goes dark and the cards stay lit, like toys under a lamp */
.dark {
  --page: #1b1815;
  --ink: 236 229 218;
  --glow-k: 0.16;
  color-scheme: dark;
}
.card, .pill, .peek, .sticker, .lost-card { --ink: 0 0 0; color: rgb(var(--ink)); }
/* rings and selections are drawn on the page, so they take the page's ink even around a card */
:root { --ring: rgb(0 0 0 / 0.45); }
.dark { --ring: rgb(236 229 218 / 0.6); }
::selection { background: color-mix(in srgb, var(--magenta) 38%, transparent); }
.dark ::selection { background: color-mix(in srgb, var(--magenta) 50%, transparent); }

*, *::before, *::after { box-sizing: border-box; }
/* the whole page reads at 110%: every size is in rem, so this is the one dial */
html { font-size: 110%; -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; }
body, h1, h2, p, ul, figure { margin: 0; }
ul { padding: 0; list-style: none; }
a { color: inherit; text-decoration: inherit; }
img { display: block; max-width: 100%; }
h1, h2 { font-size: inherit; font-weight: inherit; }

body {
  font-family: "Haskoy", ui-sans-serif, system-ui, sans-serif;
  color: rgb(var(--ink));
  background: var(--page);
  overscroll-behavior: none;
  -webkit-font-smoothing: auto;
  -moz-osx-font-smoothing: auto;
}

/* ---------- drifting dot grid + slow light blobs ---------- */
/* Both loops step instead of gliding. The dots move one device pixel per step (--dot-steps comes from the
   head script), so they stay crisp and the GPU draws about seven frames a second instead of sixty. */
body::before,
body::after,
.page::before {
  content: "";
  position: fixed;
  z-index: -1;
  pointer-events: none;
  will-change: transform;
}
body::before {
  --tile: 18px;
  inset: calc(-1 * var(--tile));
  background: radial-gradient(rgb(var(--ink) / 0.07) 15%, transparent 15%) 0 0 / var(--tile) var(--tile);
  animation: dots 5s steps(var(--dot-steps, 36)) var(--dots-at, 0s) infinite;
}
/* each blob is its own small layer, sized to its light, rather than one sheet bigger than the screen */
.page::before,
body::after {
  width: calc(2 * var(--rx));
  height: calc(2 * var(--ry));
  left: calc(var(--cx) - var(--rx));
  top: calc(var(--cy) - var(--ry));
  background: radial-gradient(closest-side, rgb(var(--glow) / calc(var(--a) * var(--glow-k))), transparent);
}
.page::before {
  --rx: 28rem; --ry: 22rem; --cx: 26%; --cy: 21.2%; --a: 0.5;
  animation: glow-a 60s steps(20) var(--glow-at, 0s) infinite;
}
body::after {
  --rx: 24rem; --ry: 20rem; --cx: 72.4%; --cy: 75.6%; --a: 0.35;
  animation: glow-b 60s steps(20) var(--glow-at, 0s) infinite;
}
.resting body::before,
.resting body::after,
.resting .page::before { animation-play-state: paused; }
@keyframes dots { to { transform: translate(-18px, -18px); } }
/* the old single sheet's path (three eased waypoints, scaled about the middle), sampled every 5s per blob */
@keyframes glow-a {
  0%, 100% { transform: none; }
  8.33% { transform: translate(2.2vw, 1.5vh) scale(1.013); }
  16.67% { transform: translate(8.4vw, 5.8vh) scale(1.050); }
  25% { transform: translate(14.6vw, 10.0vh) scale(1.087); }
  33.33% { transform: translate(16.8vw, 11.5vh) scale(1.100); }
  41.67% { transform: translate(12.9vw, 13.1vh) scale(1.081); }
  50% { transform: translate(1.8vw, 17.7vh) scale(1.025); }
  58.33% { transform: translate(-9.3vw, 22.2vh) scale(0.969); }
  66.67% { transform: translate(-13.2vw, 23.8vh) scale(0.950); }
  75% { transform: translate(-11.5vw, 20.8vh) scale(0.956); }
  83.33% { transform: translate(-6.6vw, 11.9vh) scale(0.975); }
  91.67% { transform: translate(-1.7vw, 3.1vh) scale(0.994); }
}
@keyframes glow-b {
  0%, 100% { transform: none; }
  8.33% { transform: translate(2.8vw, 2.2vh) scale(1.013); }
  16.67% { transform: translate(10.7vw, 8.5vh) scale(1.050); }
  25% { transform: translate(18.7vw, 14.8vh) scale(1.087); }
  33.33% { transform: translate(21.4vw, 17.0vh) scale(1.100); }
  41.67% { transform: translate(16.7vw, 17.5vh) scale(1.081); }
  50% { transform: translate(3.0vw, 19.0vh) scale(1.025); }
  58.33% { transform: translate(-10.7vw, 20.6vh) scale(0.969); }
  66.67% { transform: translate(-15.5vw, 21.1vh) scale(0.950); }
  75% { transform: translate(-13.5vw, 18.4vh) scale(0.956); }
  83.33% { transform: translate(-7.8vw, 10.6vh) scale(0.975); }
  91.67% { transform: translate(-2.0vw, 2.7vh) scale(0.994); }
}

/* ---------- page shell ---------- */
.page {
  max-width: 28rem;
  margin-inline: auto;
  padding: 1rem 1rem 6rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
  letter-spacing: 0.015rem;
}

.intro {
  display: grid;
  gap: 0.75rem;
  padding: 2rem 0;
}
.intro h1 { font-size: 1.25rem; line-height: 1.3333; font-weight: 500; }
.links { display: flex; gap: 1rem; }
.links a,
.intro a.inline {
  text-decoration: underline rgb(var(--ink) / 0.2);
}
.links a:hover,
.intro a.inline:hover { text-decoration: none; }

@media (min-width: 768px) {
  .intro { padding-top: 3rem; }
}

.stack { display: flex; flex-direction: column; gap: 2.25rem; } /* room for the stickers that stick out over a card's edge */

.label {
  margin: 0.5rem 0;
  text-transform: uppercase;
  font-weight: 700;
  color: rgb(var(--ink) / 0.58);
}

/* ---------- bevelled card ---------- */
.card {
  --tone: var(--sky);
  --tone-deep: var(--sky-deep);
  position: relative;
  border-radius: calc(var(--bevel-r) + var(--bevel-w));
  background: var(--tone);
}
.card.sky { --tone: var(--sky); --tone-deep: var(--sky-deep); }
.card.clover { --tone: var(--clover); --tone-deep: var(--clover-deep); }
.card.yolk { --tone: var(--yolk); --tone-deep: var(--yolk-deep); }
.card.magenta { --tone: var(--magenta); --tone-deep: var(--magenta-deep); }
.card.lavender { --tone: var(--lavender); --tone-deep: var(--lavender-deep); }

.card-body {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding: 1rem;
  border-radius: inherit;
  background-color: var(--tone);
  background-image: var(--scanlines);
  background-blend-mode: soft-light;
  box-shadow:
    0 10px 15px -3px color-mix(in srgb, var(--tone-deep) 30%, transparent),
    0 4px 6px -4px color-mix(in srgb, var(--tone-deep) 30%, transparent);
}

/* soft highlight hugging the top edge */
.shine {
  position: absolute;
  z-index: 1;
  top: 3px;
  left: 0.625rem;
  right: 0.625rem;
  height: 1.75rem;
  border-radius: 1.125rem 1.125rem 0.75rem 0.75rem;
  background: linear-gradient(rgb(255 255 255 / 0.4), transparent);
  filter: blur(1.5px);
  pointer-events: none;
}

/* rings drawn with a two-layer mask: keep the border box, cut the content box */
.edge,
.sheen {
  position: absolute;
  z-index: 10;
  padding: var(--bevel-w);
  pointer-events: none;
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0) border-box;
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#fff 0 0) content-box exclude,
    linear-gradient(#fff 0 0) border-box;
}
.edge {
  inset: 0;
  border-radius: calc(var(--bevel-r) + var(--bevel-w));
  background: linear-gradient(var(--light), rgb(var(--ink) / 0.1), rgb(var(--ink) / 0.3));
}
.sheen {
  inset: var(--bevel-w);
  border-radius: var(--bevel-r);
  background: linear-gradient(var(--light), rgb(255 255 255 / 0.5), rgb(255 255 255 / 0.05));
  filter: blur(5px);
  mix-blend-mode: overlay;
}

.ink {
  position: relative;
  text-shadow: 0 -0.5px rgb(var(--ink) / 0.12), 0 1px rgb(255 255 255 / 0.4);
}

.divider {
  margin: 0.75rem -10rem;
  border: 1px solid rgb(var(--ink) / 0.2);
  box-shadow: 0 2px 0 rgb(255 255 255 / 0.3);
}

/* ---------- entries ---------- */
.entry {
  --band-top: 0.75rem;
  --band-bottom: 0.75rem;
  --band-x: calc(1rem - 2 * var(--bevel-w));
  --r-top: 0;
  --r-bottom: 0;
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.entry:first-child {
  --band-top: calc(1rem - 2 * var(--bevel-w));
  --r-top: calc(var(--bevel-r) - var(--bevel-w));
}
.entry:last-child {
  --band-bottom: calc(1rem - 2 * var(--bevel-w));
  --r-bottom: calc(var(--bevel-r) - var(--bevel-w));
}

/* each row sits on its own band of film grain */
.entry::after,
.entry-link::before,
.entry-link .title a::before {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--band-top)) calc(-1 * var(--band-x)) calc(-1 * var(--band-bottom));
  border-radius: var(--r-top) var(--r-top) var(--r-bottom) var(--r-bottom);
  pointer-events: none;
}
.entry::after {
  z-index: -1;
  background: var(--grain) 0 0 / var(--grain-size);
  mix-blend-mode: hard-light;
  opacity: 0.6;
}

.entry-text {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}
.title { font-weight: 600; }
.desc { color: rgb(var(--ink) / 0.6); overflow-wrap: break-word; }
.entry.muted { opacity: 0.6; }

/* whole band is the hit area */
.entry-link .title a::before { z-index: 1; pointer-events: auto; }
.entry-link .title a:focus-visible { outline: none; }

/* hover: a checkerboard wipes open from the middle and starts sliding. The band is a deeper stripe of the
   card's own colour with lighter checks on it. On a dark page the cards glow, and light checks there sat
   right behind the black text and broke every letter up, so at night both squares are shades of the
   stripe, close together: you still see it move, and the words stay whole on top of it. */
.card {
  --band-base: color-mix(in display-p3, var(--tone), var(--tone-deep) 30%);
  --band-check: color-mix(in display-p3, var(--tone), #fff 26%);
}
.dark .card {
  --band-base: color-mix(in display-p3, var(--tone), var(--tone-deep) 42%);
  --band-check: color-mix(in display-p3, var(--tone), var(--tone-deep) 24%);
}

.entry-link::before {
  z-index: -1;
  background-color: var(--band-base);
  background-image: var(--scanlines), repeating-conic-gradient(var(--band-check) 0 25%, transparent 0 50%);
  background-size: auto, calc(2 * var(--checker)) calc(2 * var(--checker));
  background-blend-mode: soft-light, normal;
  clip-path: inset(50% 0);
  transition: clip-path 0.2s cubic-bezier(0.2, 0.9, 0.3, 1), filter 0.1s;
  animation: checker 3.4s linear infinite paused;
}
@keyframes checker {
  to { background-position: 0 0, calc(2 * var(--checker)) calc(2 * var(--checker)); }
}
.entry-link:has(a:focus-visible)::before { clip-path: inset(0); }
.entry-link:active::before { filter: brightness(0.94); }

.arrow {
  position: relative;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 1.375rem;
  height: 1.375rem;
  color: color-mix(in display-p3, var(--tone), #000 55%);
  transition: scale 0.35s var(--spring);
}
.arrow svg { position: relative; }
.arrow::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 9999px;
  background: linear-gradient(rgb(255 255 255 / 0.75), color-mix(in display-p3, var(--tone), #fff 35%));
  box-shadow:
    inset 0 1px #fff,
    inset 0 -1px rgb(var(--ink) / 0.12),
    0 0 0 1px rgb(var(--ink) / 0.1),
    0 1px 3px rgb(var(--ink) / 0.2);
  opacity: 0;
  scale: 0.5;
  transition: opacity 0.1s, scale 0.35s cubic-bezier(0.34, 1.26, 0.64, 1);
}
.entry-link:has(a:focus-visible) .arrow::before { opacity: 1; scale: 1; }
.entry-link:active .arrow { scale: 0.9; transition-duration: 80ms; }

@media (hover: hover) {
  html:not(.selecting, .scrolling, .motion) .entry-link:hover::before { clip-path: inset(0); animation-play-state: running; }
  html:not(.selecting, .scrolling, .motion) .entry-link:hover .arrow::before { opacity: 1; scale: 1; transition-delay: 80ms; }
}
/* with motion on, script.js lights the band: it wipes in from the edge you came through, leaves through
   the edge you left by, and runs at the pointer's speed, so a sweep down the card reads as one band travelling */
.motion .entry-link::before { transition: filter 0.1s; }
.entry-link.lit::before { clip-path: inset(0); animation-play-state: running; }
.entry-link.lit .arrow::before { opacity: 1; scale: 1; transition-delay: 80ms; }

/* ---------- top songs: late-arriving block ---------- */
.arrives {
  --enter-delay: 0.6s;
  display: grid;
  grid-template-rows: 1fr;
  animation: expand 0.5s var(--ease-out) backwards;
}
.arrives > * { min-height: 0; }
/* opening it moves everything under it, which lays the page out again every frame; phones get the block in
   place from the start, with its contents still fading up */
.lite .arrives { animation: none; }
@keyframes expand {
  from { grid-template-rows: 0fr; margin-bottom: -1rem; overflow: clip; }
  99% { overflow: clip; }
  to { grid-template-rows: 1fr; margin-bottom: 0; overflow: visible; }
}

.fade-in { animation: fade-in 0.5s var(--ease-out) var(--enter-delay, 0s) both; }
@keyframes fade-in {
  from { opacity: 0; filter: blur(12px); transform: translateY(4px) scale(0.9); }
  to { opacity: 1; filter: none; transform: none; }
}

.grainy::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background: var(--grain) 0 0 / var(--grain-size);
  mix-blend-mode: hard-light;
  opacity: 0.6;
  pointer-events: none;
}

.marquee {
  --fade: 2.5rem;
  margin-inline: -1rem;
  overflow: hidden;
  contain: inline-size;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--fade), #000 calc(100% - var(--fade)), transparent);
  mask-image: linear-gradient(to right, transparent, #000 var(--fade), #000 calc(100% - var(--fade)), transparent);
}
/* the track keeps its own layer for good, so pausing, resuming and turning over never re-rasterize it mid-drift */
.marquee-track {
  display: flex;
  width: max-content;
  will-change: transform;
  animation: scroll 24s linear infinite;
}
/* a tap leaves :hover and focus stuck on phones, so only a real hover or keyboard focus holds it */
@media (hover: hover) { .marquee:hover .marquee-track { animation-play-state: paused; } }
.marquee:has(:focus-visible) .marquee-track,
.marquee.away .marquee-track,
.resting .marquee-track { animation-play-state: paused; }
.marquee-track ul { display: flex; flex-shrink: 0; }
.marquee-track li { flex-shrink: 0; padding-left: 1rem; }
@keyframes scroll { to { transform: translateX(-50%); } }

.track {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 11rem;
  transition: transform var(--dur-quick) var(--ease-standard);
  animation: track-in 0.45s var(--ease-out) calc(var(--enter-delay, 0s) + var(--stagger, 0s)) backwards;
}
@media (hover: hover) { html:not(.selecting) .track:hover { transform: scale(0.97); } }
@keyframes track-in {
  from { opacity: 0; filter: blur(8px); transform: translateY(6px) scale(0.9); }
  to { opacity: 1; filter: none; transform: none; }
}

.cover {
  position: relative;
  flex-shrink: 0;
  width: 3rem;
  height: 3rem;
  overflow: clip;
  border: 1.5px solid rgb(var(--ink) / 0.2);
  border-radius: 0.5rem;
  transform-style: preserve-3d;
  animation: flip 1s cubic-bezier(0.34, 1.4, 0.8, 1) calc(var(--enter-delay, 0s) + var(--stagger, 0s)) both;
}
.cover img,
.cover svg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
@keyframes flip {
  from { transform: rotateY(-90deg); }
  to { transform: none; }
}
/* the flash as a sleeve comes flat: a white sheet over the art that fades out. Brightening the art itself
   with a filter looked the same and cost a redraw of every sleeve on every frame. */
.cover::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 6;
  background: #fff;
  opacity: 0;
  pointer-events: none;
  animation: flash 0.7s var(--ease-out) calc(var(--enter-delay, 0s) + var(--stagger, 0s)) both;
}
@keyframes flash { from { opacity: 0.9; } }
/* tiles off the edge when a shelf lands skip the entrance nobody would see (script.js marks them) */
.still .track,
.still .cover,
.still .cover::after { animation: none; }
/* and the shelf waits, held on its first frame, until its card scrolls in */
.reveal:not(.in) .track,
.reveal:not(.in) .cover,
.reveal:not(.in) .cover::after { animation-play-state: paused; }

/* glassy rim on artwork */
.gloss {
  position: absolute;
  inset: 0;
  z-index: 5;
  border-radius: inherit;
  outline: 1.5px solid rgb(255 255 255 / 0.5);
  outline-offset: -1px;
  mix-blend-mode: overlay;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(var(--light), #000, rgb(0 0 0 / 0.2) 70%);
  mask-image: linear-gradient(var(--light), #000, rgb(0 0 0 / 0.2) 70%);
}

.track-meta { display: flex; flex-direction: column; min-width: 0; }
.track-meta p { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.track-name { font-weight: 500; }
.track-artist { color: rgb(var(--ink) / 0.7); }

/* ---------- article page ---------- */
.page.post { max-width: 36rem; padding: 3rem 1rem; line-height: 1.5rem; }

.pill {
  --bevel-r: 9999px;
  --tone: var(--magenta);
  --tone-deep: var(--magenta-deep);
  position: relative;
  display: block;
  width: fit-content;
  margin-bottom: 2rem;
  padding: 0.375rem 1.125rem;
  border-radius: 9999px;
  font-weight: 600;
  text-shadow: 0 1px rgb(255 255 255 / 0.3);
  background-color: var(--tone);
  background-image: var(--scanlines);
  background-blend-mode: soft-light;
  box-shadow:
    0 4px 6px -1px color-mix(in srgb, var(--tone-deep) 30%, transparent),
    0 2px 4px -2px color-mix(in srgb, var(--tone-deep) 30%, transparent);
  transition: scale 0.35s var(--spring), translate 0.35s var(--spring), box-shadow 0.1s;
}
.pill .shine { height: 50%; top: 2px; border-radius: 9999px; transition: opacity 0.1s; }
.pill .label-text { position: relative; }
.pill::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  transition: background-color 0.1s, box-shadow 0.1s;
}
.pill:hover { scale: 1.05; }
.pill:active {
  scale: 0.95;
  translate: 0 1px;
  transition-duration: var(--dur-press);
  transition-timing-function: ease-out;
  box-shadow:
    0 1px 3px 0 color-mix(in srgb, var(--tone-deep) 30%, transparent),
    0 1px 2px -1px color-mix(in srgb, var(--tone-deep) 30%, transparent);
}
.pill:active::after { background-color: rgb(var(--ink) / 0.12); box-shadow: inset 0 2px 4px rgb(var(--ink) / 0.3); }
.pill:active .shine { opacity: 0.3; }
.pill:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }

.post-head { margin-bottom: 2rem; }
.post-head h1 { font-size: 1.875rem; line-height: 1.2; font-weight: 600; text-wrap: balance; }
.post-head .dek { margin-top: 0.5rem; font-size: 1rem; line-height: 1.5556; color: rgb(var(--ink) / 0.7); }
.post-head time { display: block; margin-top: 0.5rem; color: rgb(var(--ink) / 0.6); }

.post-cover { margin-bottom: 2rem; container-type: inline-size; }
.post-cover-frame {
  position: relative;
  display: block;
  width: fit-content;
  margin-inline: auto;
  overflow: clip;
  border: 1.5px solid rgb(var(--ink) / 0.2);
  border-radius: 0.75rem;
}
.post-cover-frame svg,
.post-cover-frame img { display: block; width: auto; max-width: 100%; height: auto; max-height: 100cqw; }

.prose { line-height: 1.6; }
.prose p { margin-bottom: 1rem; }
.prose > :last-child { margin-bottom: 0; }
.prose a { text-decoration: underline rgb(var(--ink) / 0.3); text-underline-offset: 2px; }
.prose a:hover { text-decoration: none; }
.prose strong { font-weight: 600; }
.prose h2 { font-size: 1.25rem; font-weight: 600; margin-block: 2rem 1rem; }
.prose blockquote {
  margin: 1rem 0;
  padding-left: 1rem;
  border-left: 4px solid rgb(var(--ink) / 0.2);
  color: rgb(var(--ink) / 0.7);
  font-style: italic;
}
.prose hr { border: 0; border-top: 1px solid rgb(var(--ink) / 0.2); box-shadow: 0 2px rgb(255 255 255 / 0.3); margin-block: 2rem; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .marquee-track { animation: none; }
}

/* keep single words off the last line of short copy */
.intro p, .dek, .prose p { text-wrap: pretty; }
.desc { text-wrap: balance; }

/* project pages: outbound links under the write-up */
.post .links { flex-wrap: wrap; margin-top: 2rem; }

/* ---------- motion ---------- */
/* ch.sh-style press: links nudge down a pixel (rows stay put, the arrow does the pressing) */
.track:active { transform: scale(0.94); }
.links a { display: inline-block; transition: translate 0.1s var(--ease-out); }
.links a:active { translate: 0 1px; }


.motion .intro > * { animation: rise 0.6s var(--ease-out) calc(0.05s + var(--i) * 90ms) both; }
.motion .intro .links a { animation: pop 0.5s var(--spring) calc(0.3s + var(--i) * 70ms) both; }
@keyframes rise {
  from { opacity: 0; filter: blur(8px); transform: translateY(10px); }
  to { opacity: 1; filter: none; transform: none; }
}
@keyframes pop {
  from { opacity: 0; transform: translateY(6px) scale(0.7); }
  to { opacity: 1; transform: none; }
}

/* cards: hidden until they scroll in */
.motion .reveal:not(.in) .label,
.motion .reveal:not(.in) .card,
.motion .reveal:not(.in) .entry-text,
.motion .reveal:not(.in) .arrow svg,
.motion .reveal:not(.in) .divider { opacity: 0; }

.motion .reveal.in .label { animation: label-in 0.5s var(--ease-out) both; }
@keyframes label-in {
  from { opacity: 0; clip-path: inset(0 100% 0 0); transform: translateX(-6px); }
  to { opacity: 1; clip-path: inset(0 0 0 0); transform: none; }
}

.stack > section { perspective: 900px; }
.motion .reveal.in .card {
  transform-origin: 50% 0;
  animation: card-in 0.9s cubic-bezier(0.3, 1.3, 0.5, 1) 0.08s both;
}
@keyframes card-in {
  from { opacity: 0; filter: blur(6px); transform: translateY(28px) rotateX(14deg) scale(0.96); }
  60% { opacity: 1; filter: none; }
  to { opacity: 1; filter: none; transform: none; }
}

/* one pass of light across the card as it lands */
/* the band slides across as its own layer, so the card is never repainted while the light moves */
.card-body::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 20%, rgb(255 255 255 / 0.55) 50%, transparent 80%);
  transform: translateX(-150%);
  mix-blend-mode: soft-light;
}
.motion .reveal.in .card-body::after { animation: sweep 1.3s var(--ease-out) 0.35s both; }
@keyframes sweep { from { transform: translateX(-150%); } to { transform: translateX(165%); } }
/* switching shelves runs the same light across the films card, and the new shelf lands behind it */
.motion .card.sweeping .card-body::after {
  /* the films card is long and short, so the band is drawn tighter to read as the same glint */
  background-image: linear-gradient(105deg, transparent 34%, rgb(255 255 255 / 0.7) 50%, transparent 66%);
  animation: sweep 1.1s var(--ease-out) both;
}

/* animate the row's contents, not the row: a transformed row would cut its grain off from the card */
.motion .reveal.in .entry-text { animation: row-in 0.55s var(--ease-out) calc(0.3s + var(--row) * 90ms) both; }
@keyframes row-in {
  from { opacity: 0; filter: blur(6px); transform: translateY(10px); }
  to { opacity: 1; filter: none; transform: none; }
}
.motion .reveal.in .divider { animation: draw 0.6s var(--ease-out) calc(0.3s + var(--row) * 90ms) both; }
@keyframes draw {
  from { opacity: 0; clip-path: inset(0 50%); }
  to { opacity: 1; clip-path: inset(0 0); }
}
.motion .reveal.in .arrow svg { animation: arrow-in 0.6s var(--spring) calc(0.5s + var(--row) * 90ms) both; }
@keyframes arrow-in {
  from { opacity: 0; transform: translate(-6px, 6px) scale(0.4); }
  to { opacity: 1; transform: none; }
}

/* project pages */
.motion .post > .pill { animation: pop 0.5s var(--spring) both; }
.motion .post .reveal:not(.in) { opacity: 0; }
.motion .post .reveal.in { animation: rise 0.6s var(--ease-out) both; }
.motion .post .post-cover.reveal { perspective: 1200px; }
.motion .post .post-cover.reveal.in { animation: none; }
.motion .post .post-cover.reveal.in .post-cover-frame { transform-origin: 50% 100%; animation: cover-in 1s cubic-bezier(0.3, 1.25, 0.5, 1) both; }
@keyframes cover-in {
  from { opacity: 0; filter: brightness(1.6) blur(10px); transform: rotateX(-24deg) translateY(24px) scale(0.94); }
  to { opacity: 1; filter: none; transform: none; }
}
.motion .post .links.reveal.in { animation: none; }
.motion .post .links.reveal.in a { animation: pop 0.5s var(--spring) calc(var(--i, 0) * 70ms) both; }
.motion .post .links.reveal:not(.in) { opacity: 1; }
.motion .post .links.reveal:not(.in) a { opacity: 0; }

/* ---------- click spark (after ch.sh's ClickSpark) ---------- */
.spark {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
  width: 48px;
  height: 48px;
  margin: -24px 0 0 -24px;
  color: rgb(var(--ink));
  pointer-events: none;
  visibility: hidden;
  contain: strict;
}
.spark line { stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; opacity: 0.3; stroke-dasharray: 6 40; }
.spark.go { visibility: visible; }
/* t * (2 - t), the same ease-out ClickSpark uses */
.spark.go line { animation: spark 0.3s cubic-bezier(0.5, 1, 0.89, 1) forwards; }
@keyframes spark {
  from { stroke-dasharray: 6 40; stroke-dashoffset: 0; }
  to { stroke-dasharray: 0 40; stroke-dashoffset: -12; }
}

/* ---------- films: portrait posters in the marquee ---------- */
/* same height as the square covers, 2:3 like a one-sheet; tiles size to their titles with one even gap between films */
.cover.poster { width: 2rem; height: 3rem; border-radius: 0.3125rem; }
.track:has(.poster) { width: auto; }
.marquee-track li:has(.poster) { padding-left: 2rem; }

/* ---------- email: rolls to the address on hover, copies on click (after timothymaarv.me) ---------- */
.roll-link { --roll-ease: cubic-bezier(0.65, 0, 0, 1); --roll-tone: color-mix(in display-p3, var(--magenta), #000 30%); }
/* the address is small text straight on the page, so it lifts toward white after dark (7.6:1) */
.dark .roll-link { --roll-tone: color-mix(in display-p3, var(--magenta), #fff 25%); }
.links a.roll-link { text-decoration: none; }
.roll {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  width: var(--w0, auto);
  height: 1lh;
  overflow: clip;
  overflow-clip-margin: 2px;
  vertical-align: top;
  transition: width 0.45s var(--roll-ease);
}
.roll-line {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  width: max-content;
  height: 1lh;
  flex-shrink: 0;
  white-space: nowrap;
  transition: translate 0.45s var(--roll-ease);
}
.roll-line:first-child { text-decoration: underline rgb(var(--ink) / 0.2); }
.roll-icon { flex-shrink: 0; opacity: 0.45; }
.roll-line + .roll-line { color: var(--roll-tone); }
.roll-line + .roll-line .roll-icon { opacity: 1; }
/* outbound links: the arrow leans the way you are about to go */
.roll-icon.out { transition: translate 0.2s var(--ease-out); }
.roll-link:active .roll-icon.out { translate: 1.5px -1.5px; transition-duration: 60ms; }
.check path { stroke-dasharray: 20; stroke-dashoffset: 20; }

@media (hover: hover) and (pointer: fine) {
  /* .open is hover with intent (script.js): the last link you touched stays open while you're on the row */
  html:not(.selecting) .roll-link.open .roll { width: var(--w1, auto); }
  html:not(.selecting) .roll-link.open .roll-line { translate: 0 -100%; }
}
.roll-link:focus-visible .roll { width: var(--w1, auto); }
.roll-link:focus-visible .roll-line { translate: 0 -100%; }
/* copied wins over hover: it has to show while the pointer is still on the link */
.copy-email[data-state="copied"] .roll,
html:not(.selecting) .copy-email.open[data-state="copied"] .roll { width: var(--w2, auto); }
.copy-email[data-state="copied"] .roll-line,
html:not(.selecting) .copy-email.open[data-state="copied"] .roll-line { translate: 0 -200%; }
.copy-email[data-state="copied"] .check path { animation: check-draw 0.2s var(--ease-io) 0.15s forwards; }
@keyframes check-draw { to { stroke-dashoffset: 0; } }

@media (prefers-reduced-motion: reduce) {
  .roll, .roll-line { transition: none; }
  .check path { stroke-dashoffset: 0; animation: none !important; }
}

.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* refresh: the page glides back to the top first, then the intro plays */
.rewinding .intro > *,
.rewinding .intro .links a { animation-play-state: paused; }

/* ---------- peek: a project's screenshots, dealt out of its arrow as glossy cards ---------- */
.peek {
  --pad: 5px;
  --tone: var(--sky);
  --tone-deep: var(--sky-deep);
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60;
  width: 0;
  height: 0;
  pointer-events: none;
  visibility: hidden;
}
.peek.on { visibility: visible; }
.peek-tilt {
  position: absolute;
  translate: -50% -50%;
  perspective: 700px;
}
.peek-deck { display: grid; }
.peek-card {
  position: relative;
  grid-area: 1 / 1;
  z-index: calc(3 - var(--i));
  isolation: isolate;
  width: calc(var(--w) + 2 * var(--pad));
  height: calc(var(--h) + 2 * var(--pad));
  padding: var(--pad);
  border-radius: 14px;
  background-color: var(--tone);
  background-image: var(--scanlines);
  background-blend-mode: soft-light;
  box-shadow:
    inset 0 1px rgb(255 255 255 / 0.55),
    inset 0 -1.5px rgb(var(--ink) / 0.14),
    0 0 0 1px rgb(var(--ink) / 0.1),
    0 20px 34px -14px color-mix(in srgb, var(--tone-deep) 70%, transparent),
    0 6px 12px -6px rgb(var(--ink) / 0.22);
  transition: transform 0.55s var(--spring) calc(var(--i) * 50ms);
}
/* stacked while it flies, fanned once it lands */
.peek.dealt .peek-card { transform: translate(var(--x), var(--y)) rotate(var(--r)); }
.peek-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--grain) 0 0 / var(--grain-size);
  mix-blend-mode: hard-light;
  opacity: 0.5;
}
.peek-card img {
  width: var(--w);
  height: var(--h);
  border-radius: 9px;
  object-fit: cover;
  background: #fff;
  box-shadow: 0 0 0 1px rgb(var(--ink) / 0.16);
}
/* the card's landing sweep, parked under the pointer: slide along the row and the light slides with you */
.peek-glare {
  position: absolute;
  inset: var(--pad);
  border-radius: 9px;
  background: linear-gradient(105deg, transparent 38%, rgb(255 255 255 / 0.5) 50%, transparent 62%) no-repeat;
  background-size: 260% 100%;
  background-position: calc(100% - var(--gx, 0.5) * 100%) 0;
  mix-blend-mode: soft-light;
}
.peek-rim { inset: var(--pad); border-radius: 9px; }
/* a lone shot shows the card's back: the row's own hover checker, still sliding */
.peek-back {
  display: grid;
  place-items: center;
  background-image:
    var(--scanlines),
    repeating-conic-gradient(color-mix(in display-p3, var(--tone), #fff 15%) 0 25%, transparent 0 50%);
  background-size: auto, calc(2 * var(--checker)) calc(2 * var(--checker));
  background-blend-mode: soft-light, normal;
  animation: checker 3.4s linear infinite;
}
/* a folded deck stays in the page between hovers; its checker shouldn't keep sliding out of sight */
.peek:not(.on) .peek-back { animation-play-state: paused; }
.peek-knob {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 9999px;
  color: color-mix(in display-p3, var(--tone), #000 55%);
  background: linear-gradient(rgb(255 255 255 / 0.75), color-mix(in display-p3, var(--tone), #fff 35%));
  box-shadow:
    inset 0 1px #fff,
    inset 0 -1px rgb(var(--ink) / 0.12),
    0 0 0 1px rgb(var(--ink) / 0.1),
    0 1px 3px rgb(var(--ink) / 0.2);
}
@media (hover: none), (pointer: coarse) { .peek { display: none; } }

/* ---------- films / music: the label is a switch, the marquee turns over to the other shelf ---------- */
.shelf-switch { display: flex; align-items: baseline; gap: 0.375rem; }
.shelf-rest { display: contents; }
.shelf-rest[hidden] { display: none; }
.shelf {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: rgb(var(--ink) / 0.36);
  cursor: pointer;
  transition: color 0.2s var(--ease-out), translate 0.1s var(--ease-out);
}
.shelf[aria-pressed="true"] { cursor: default; }
html:not(.selecting) .shelf[aria-pressed="false"]:hover { color: rgb(var(--ink) / 0.56); }
.shelf[aria-pressed="false"]:active { translate: 0 1px; }
.shelf:focus-visible { outline: 2px solid var(--magenta-deep); outline-offset: 3px; border-radius: 3px; }
.shelf-slash { color: rgb(var(--ink) / 0.22); }

/* albums: square sleeves, tiles size to their titles like the films do */
.track:has(.album) { width: auto; }
.marquee-track li:has(.album) { padding-left: 2rem; }

/* ---------- behind the sleeves: albums slide their record out, films their ticket stub ---------- */
/* both tuck into the gap left of the sleeve, so nothing on the shelf has to move for them */
.vinyl,
.stub {
  position: absolute;
  top: 50%;
  pointer-events: none;
  transition: translate var(--dur-slow) var(--spring), rotate var(--dur-slow) var(--spring);
}
.vinyl { left: 2px; width: 44px; height: 44px; margin-top: -22px; }
.vinyl-disc {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: repeating-radial-gradient(circle, #141414 0 1px, #232323 1px 2px);
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.35), 0 2px 5px rgb(0 0 0 / 0.3);
}
/* the sleeve art doubles as the centre label, with the spindle hole punched through */
.vinyl-disc img { position: absolute; inset: 14px; width: 16px; height: 16px; border-radius: 50%; object-fit: cover; }
.vinyl-disc::after {
  content: "";
  position: absolute;
  inset: calc(50% - 1.5px);
  border-radius: 50%;
  background: var(--tone);
}
/* the shine stays put while the record turns under it, same as a real one under a lamp */
.vinyl::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(from calc(var(--light) - 150deg), transparent 0 6%, rgb(255 255 255 / 0.22) 12%, transparent 19% 50%, rgb(255 255 255 / 0.14) 62%, transparent 69%);
}
html:not(.selecting) .track:hover .vinyl { translate: -20px 0; }
/* 33 1/3 rpm is 1.8 seconds a turn */
.motion .track:hover .vinyl-disc { animation: spin 1.8s linear 0.2s infinite; }
@keyframes spin { to { rotate: 1turn; } }

.stub {
  left: 5px;
  display: grid;
  place-items: center;
  width: 22px;
  height: 40px;
  margin-top: -20px;
  padding-right: 6px;
  border-radius: 3px;
  writing-mode: vertical-rl;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
  color: var(--magenta-deep);
  /* a dotted tear line where it came off the rest of the ticket */
  background:
    linear-gradient(#f7f0e3 50%, transparent 50%) 15px 0 / 1px 4px repeat-y,
    linear-gradient(rgb(0 0 0 / 0.22), rgb(0 0 0 / 0.22)) 15px 0 / 1px 100% no-repeat,
    #f7f0e3;
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.25);
  rotate: -3deg;
  /* the two notches of a torn-off stub */
  -webkit-mask: radial-gradient(circle at 50% 0, transparent 3px, #000 3.5px) top / 100% 51% no-repeat,
    radial-gradient(circle at 50% 100%, transparent 3px, #000 3.5px) bottom / 100% 51% no-repeat;
  mask: radial-gradient(circle at 50% 0, transparent 3px, #000 3.5px) top / 100% 51% no-repeat,
    radial-gradient(circle at 50% 100%, transparent 3px, #000 3.5px) bottom / 100% 51% no-repeat;
}
html:not(.selecting) .track:hover .stub { translate: -18px 0; rotate: -9deg; }

/* ---------- stickers: die-cut, slapped on a corner, a little crooked ---------- */
.sticker {
  --tone: var(--sky);
  position: absolute;
  z-index: 12;
  top: -0.625rem;
  right: -0.5rem;
  display: grid;
  justify-items: center;
  padding: 0.25rem 0.5rem 0.3rem;
  border: 3px solid #fff;
  border-radius: 0.75rem;
  font-family: "Haskoy", "Hiragino Sans", "Yu Gothic", ui-sans-serif, sans-serif;
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: 0.02em;
  white-space: nowrap;
  background: linear-gradient(var(--light), rgb(255 255 255 / 0.35), transparent 60%), var(--tone);
  box-shadow: 0 0 0 0.5px rgb(0 0 0 / 0.12), 0 4px 10px -3px rgb(0 0 0 / 0.35);
  rotate: 7deg;
  transition: rotate var(--dur-slow) var(--spring), scale var(--dur-slow) var(--spring), opacity var(--dur-base) var(--ease-out);
}
.sticker small { font-size: 0.625rem; font-weight: 600; letter-spacing: 0.04em; opacity: 0.7; }
.sticker.bottom { top: auto; bottom: -0.625rem; rotate: -6deg; }
.sticker.magenta { --tone: var(--magenta); }
.sticker.yolk { --tone: var(--yolk); }
.sticker:hover { rotate: 2deg; scale: 1.08; }
.sticker.bottom:hover { rotate: -1deg; }
/* the five-star sticker belongs to the films shelf and peels off for music */
section:has(.shelf[data-shelf="music"][aria-pressed="true"]) .films-only { opacity: 0; scale: 0.6; rotate: 30deg; }

/* ---------- keys: M and E sit by what they press, P and R live down here ---------- */
.keys {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  margin-top: 3rem;
  color: rgb(var(--ink) / 0.58);
}
.keys p { display: flex; align-items: center; gap: 0.5rem; }
kbd {
  display: inline-grid;
  place-items: center;
  min-width: 1.5rem;
  height: 1.5rem;
  padding: 0 0.375rem;
  border-radius: 0.375rem;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 700;
  color: rgb(0 0 0 / 0.6);
  background: linear-gradient(var(--light), #fff, #e9e3d8);
  box-shadow:
    inset 0 1px #fff,
    inset 0 -1.5px rgb(0 0 0 / 0.08),
    0 0 0 1px rgb(0 0 0 / 0.14),
    0 2px 0 rgb(0 0 0 / 0.14),
    0 3px 5px -1px rgb(0 0 0 / 0.18);
  transition: translate var(--dur-press) ease-out, box-shadow var(--dur-press) ease-out;
}
kbd.down {
  translate: 0 2px;
  box-shadow:
    inset 0 1px #fff,
    inset 0 -1px rgb(0 0 0 / 0.06),
    0 0 0 1px rgb(0 0 0 / 0.14),
    0 0 0 rgb(0 0 0 / 0.14),
    0 1px 2px -1px rgb(0 0 0 / 0.18);
}
/* the small caps that sit next to what they press: grey and flat, there if you look for them */
kbd.hint {
  min-width: 1.125rem;
  height: 1.125rem;
  margin-left: 0.5rem;
  padding: 0 0.25rem;
  border-radius: 0.3rem;
  font-size: 0.625rem;
  vertical-align: 0.1em;
  letter-spacing: 0;
  text-transform: none;
  color: rgb(0 0 0 / 0.5);
  background: linear-gradient(var(--light), #fbf8f3, #e9e3d8);
  box-shadow: inset 0 1px #fff, 0 0 0 1px rgb(0 0 0 / 0.1), 0 1px 0 rgb(0 0 0 / 0.1);
  opacity: 0.5;
  transition: opacity 0.2s, scale 0.2s var(--ease-out), translate var(--dur-press) ease-out, box-shadow var(--dur-press) ease-out;
}
.intro .links kbd.hint { align-self: center; margin-left: -0.5rem; }
/* F and M sit right after their word, on its line */
.shelf-switch kbd.hint { align-self: center; margin-left: -0.125rem; translate: 0 -0.05em; }
.shelf:hover + kbd.hint, .shelf:focus-visible + kbd.hint, kbd.hint.down { opacity: 0.85; }
/* the shelf you're on wears its colour, and so does its cap */
.shelf[aria-pressed="true"] {
  color: rgb(var(--ink));
  background: linear-gradient(transparent 58%, color-mix(in srgb, var(--magenta) 32%, transparent) 58% 92%, transparent 92%);
}
.shelf[aria-pressed="true"] + kbd.hint {
  opacity: 1;
  color: rgb(0 0 0 / 0.72);
  background: linear-gradient(color-mix(in display-p3, var(--magenta), #fff 55%), var(--magenta));
  box-shadow: inset 0 1px rgb(255 255 255 / 0.6), 0 0 0 1px color-mix(in srgb, var(--magenta-deep) 55%, transparent), 0 1px 0 color-mix(in srgb, var(--magenta-deep) 45%, transparent);
}
/* once the email has rolled over to the address, the E has done its job and steps out of the way */
.links:has(.copy-email.open, .copy-email:focus-visible, .copy-email[data-state]) kbd.hint { opacity: 0; scale: 0.7; }
@media (hover: none), (pointer: coarse) { .keys p, .keys .key:not([data-press="a"]), kbd.hint { display: none; } }
.keys { align-items: center; }

/* the theme change spreads out of the switch instead of cross-fading the page */
.theming::view-transition-old(root),
.theming::view-transition-new(root) { animation: none; mix-blend-mode: normal; }

/* ---------- project pages: Home rides along the top and fills as you read ---------- */
.post > .pill { position: sticky; top: 1rem; z-index: 20; overflow: clip; }
.post > .pill::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgb(255 255 255 / 0.3);
  transform-origin: left;
  scale: var(--read, 0) 1;
}
@supports (animation-timeline: scroll()) {
  .post > .pill::before { animation: read linear both; animation-timeline: scroll(root); }
}
@keyframes read { from { scale: 0 1; } to { scale: 1 1; } }

/* ---------- 404: the page you wanted, face down ---------- */
.lost { display: grid; justify-items: start; gap: 1rem; padding-top: 6rem; }
.lost .label { margin: 0; }
.lost .pill { margin: 0.5rem 0 0; }
.lost-card {
  --tone: var(--clover);
  --tone-deep: var(--clover-deep);
  --pad: 6px;
  position: relative;
  width: 16rem;
  height: 11rem;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
  perspective: 900px;
  transition: translate var(--dur-slow) var(--spring), rotate var(--dur-slow) var(--spring);
}
.lost-card:hover { translate: 0 -3px; rotate: -1.5deg; }
.lost-card:focus-visible { outline: 2px solid var(--ring); outline-offset: 4px; border-radius: 1.1rem; }
.lost-face {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: 1rem;
  background-color: var(--tone);
  background-image: var(--scanlines);
  background-blend-mode: soft-light;
  box-shadow:
    inset 0 1px rgb(255 255 255 / 0.55),
    inset 0 -1.5px rgb(0 0 0 / 0.14),
    0 0 0 1px rgb(0 0 0 / 0.1),
    0 20px 34px -14px color-mix(in srgb, var(--tone-deep) 70%, transparent),
    0 6px 12px -6px rgb(0 0 0 / 0.22);
  backface-visibility: hidden;
  transition: rotate 0.7s var(--spring);
}
.lost-back {
  background-image:
    var(--scanlines),
    repeating-conic-gradient(color-mix(in display-p3, var(--tone), #fff 15%) 0 25%, transparent 0 50%);
  background-size: auto, calc(2 * var(--checker)) calc(2 * var(--checker));
  background-blend-mode: soft-light, normal;
  animation: checker 3.4s linear infinite paused;
}
.lost-card:hover .lost-back { animation-play-state: running; }
.lost-front { rotate: y -180deg; align-content: center; gap: 0.25rem; padding: 1.5rem; text-align: center; }
.lost-front strong { font-weight: 600; }
.lost-front span { color: rgb(0 0 0 / 0.6); text-wrap: balance; }
.lost-card[aria-pressed="true"] .lost-back { rotate: y 180deg; }
.lost-card[aria-pressed="true"] .lost-front { rotate: y 0deg; }

/* ---------- print: the home page comes out as a one-page resume ---------- */
@media print {
  html { font-size: 100%; }
  @page { size: A4; margin: 14mm 16mm; }
  html, html.dark { --ink: 0 0 0; --page: #fff; color-scheme: light; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
  body { background: #fff; }
  body::before, body::after, .page::before,
  .peek, .spark, .keys, .sticker, .arrives,
  .shine, .edge, .sheen, .arrow, .card-body::after, .entry-link::before,
  .links .resume, .intro p:has(.inline), .post > .pill { display: none !important; }
  .motion .reveal:not(.in) :is(.label, .card, .entry-text, .divider) { opacity: 1 !important; }
  .page { max-width: none; padding: 0; font-size: 9.5pt; line-height: 1.35; letter-spacing: 0; }
  .intro { gap: 3pt; padding: 0 0 4pt; }
  .intro h1 { font-size: 20pt; line-height: 1.1; font-weight: 600; }
  .links { gap: 12pt; }
  .links a { text-decoration: none; }
  .roll { width: auto !important; height: auto; }
  .roll-line { display: none; }
  .roll-line:nth-child(2) { display: inline; color: rgb(0 0 0 / 0.7); }
  .roll-icon { display: none; }
  .links [data-print] { font-size: 0; }
  .links [data-print]::after { content: attr(data-print); font-size: 9.5pt; color: rgb(0 0 0 / 0.7); }
  .stack { gap: 0; }
  .label { margin: 9pt 0 4pt; padding-bottom: 2pt; border-bottom: 0.75pt solid rgb(0 0 0 / 0.25); font-size: 8pt; letter-spacing: 0.1em; color: rgb(0 0 0 / 0.6); }
  .card, .card-body { background: none !important; box-shadow: none !important; border-radius: 0; padding: 0; }
  .ink { text-shadow: none; }
  .divider { margin: 3pt 0; border: 0; box-shadow: none; }
  .entry { break-inside: avoid; }
  .title span { font-weight: 400; color: rgb(0 0 0 / 0.7); }
}

/* ---------- arriving from a deck (script.js): the cover dashes in, focus lines flash round it ---------- */
/* the usual cover entrance stands down for the dash */
.dash .post .post-cover.reveal:not(.in) { opacity: 1; }
.dash .post .post-cover-frame { animation: none !important; }
.focus-lines {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  transform-origin: var(--cx) var(--cy);
  background:
    repeating-conic-gradient(at var(--cx) var(--cy), rgb(var(--ink) / 0.13) 0 0.5deg, transparent 0.5deg 3.1deg),
    repeating-conic-gradient(from 1.3deg at var(--cx) var(--cy), rgb(var(--ink) / 0.09) 0 1.1deg, transparent 1.1deg 7.3deg);
  -webkit-mask-image: radial-gradient(circle at var(--cx) var(--cy), transparent var(--r), #000 calc(var(--r) + 60px), transparent calc(var(--r) + 380px));
  mask-image: radial-gradient(circle at var(--cx) var(--cy), transparent var(--r), #000 calc(var(--r) + 60px), transparent calc(var(--r) + 380px));
}

/* ---------- stories: charts, drafts and gaps ---------- */
.chart { margin-block: 2.75rem; }
.chart figcaption { font-size: 0.875rem; line-height: 1.4; font-weight: 600; margin-bottom: 1rem; text-wrap: balance; }
.chart ul { list-style: none; display: grid; grid-template-columns: max-content 1fr max-content; gap: 0.5rem 0.75rem; align-items: center; }
.chart li { display: contents; }
.chart-label { font-size: 0.875rem; color: rgb(var(--ink) / 0.7); }
.chart-value { font-size: 0.875rem; font-variant-numeric: tabular-nums; text-align: right; }
.chart-track { height: 0.75rem; border-radius: 9999px; background: rgb(var(--ink) / 0.06); overflow: hidden; }
.chart-bar {
  display: block;
  height: 100%;
  width: calc(var(--v) * 100%);
  border-radius: inherit;
  background: rgb(var(--ink) / 0.28);
  transform-origin: left;
}
.chart-bar.now { background: var(--magenta); box-shadow: inset 0 1px rgb(255 255 255 / 0.35); }
.chart-bar.gap { width: 100%; background: repeating-linear-gradient(-45deg, rgb(var(--ink) / 0.1) 0 4px, transparent 4px 8px); }
.chart-note { margin-top: 1rem; font-size: 0.875rem; color: rgb(var(--ink) / 0.6); }
.motion .chart.reveal.in .chart-bar:not(.gap) { animation: grow 0.9s var(--ease-out) calc(0.15s + var(--i) * 110ms) both; }
@keyframes grow { from { scale: 0 1; } }

.draft {
  margin-block: 2rem;
  padding: 1rem 1.25rem 1.25rem;
  border: 1.5px dashed rgb(var(--ink) / 0.25);
  border-radius: 1rem;
}
.draft > h2:first-of-type { margin-top: 0.5rem; }
.draft > .chart:nth-child(2) { margin-top: 0.5rem; }
.draft .draft-tag {
  width: fit-content;
  margin-bottom: 0;
  padding: 0.125rem 0.5rem;
  border-radius: 9999px;
  background: rgb(var(--ink) / 0.07);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: rgb(var(--ink) / 0.7);
}
.draft .draft-tag + .chart { margin-top: 1rem; }
.slot {
  padding: 0 0.375em;
  border: 1px dashed var(--magenta-deep);
  border-radius: 0.375em;
  color: var(--magenta-deep);
  font-size: 0.875em;
  white-space: nowrap;
  cursor: help;
}
.dark .slot { border-color: color-mix(in display-p3, var(--magenta), #fff 25%); color: color-mix(in display-p3, var(--magenta), #fff 25%); }

/* metric tree: the one number, and what moves it */
.tree { margin-block: 2.75rem; }
.tree figcaption { font-size: 0.875rem; line-height: 1.4; font-weight: 600; margin-bottom: 1rem; }
.prose .tree-top {
  position: relative;
  width: fit-content;
  max-width: 100%;
  margin: 0 auto 1.25rem;
  padding: 0.5rem 1rem;
  border-radius: 0.75rem;
  background: var(--magenta);
  color: #000;
  font-size: 0.875rem;
  line-height: 1.4;
  font-weight: 600;
  text-align: center;
  text-wrap: balance;
  box-shadow: inset 0 1px rgb(255 255 255 / 0.35), 0 1px 2px rgb(0 0 0 / 0.12);
}
.tree-top::after { content: ""; position: absolute; left: 50%; top: 100%; width: 1.5px; height: 1.25rem; background: rgb(var(--ink) / 0.2); }
.tree ul {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
  padding-top: 0.75rem;
  border-top: 1.5px solid rgb(var(--ink) / 0.2);
}
.tree li { display: grid; align-content: start; gap: 0.125rem; padding: 0.5rem 0.625rem; border-radius: 0.625rem; background: rgb(var(--ink) / 0.05); font-size: 0.8125rem; line-height: 1.35; }
.tree li span { color: rgb(var(--ink) / 0.65); text-wrap: pretty; }
.motion .tree.reveal.in li { animation: rise 0.5s var(--ease-out) calc(0.15s + var(--i, 0) * 70ms) both; }

/* drawings: one small inline picture per idea, in the page's own candy colours, so dark mode needs nothing extra.
   Pieces marked .p pop in one after another (--i), and lines marked .d draw themselves (pathLength="1"). */
.art { margin-block: 2.75rem; }
.art figcaption { font-size: 0.875rem; line-height: 1.4; font-weight: 600; margin-bottom: 1.25rem; text-wrap: balance; }
.art svg { display: block; width: 100%; max-width: 30rem; height: auto; margin-inline: auto; overflow: visible; }
.art .m { fill: var(--magenta); }
.art .y { fill: var(--yolk); }
.art .c { fill: var(--clover); }
.art .l { fill: var(--lavender); }
.art .s { fill: var(--sky); }
.art .ink { fill: rgb(var(--ink) / 0.1); }
.art .ink2 { fill: rgb(var(--ink) / 0.22); }
.art .page { fill: rgb(var(--ink) / 0.04); stroke: rgb(var(--ink) / 0.18); stroke-width: 1.5; }
.art .line { fill: none; stroke: rgb(var(--ink) / 0.35); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.art .line.bold { stroke: rgb(var(--ink) / 0.7); stroke-width: 2.5; }
.art .line.pink { stroke: var(--magenta); stroke-width: 2.5; }
.art .line.dash { stroke-dasharray: 3 5; }
.art .ring { fill: none; stroke-width: 2; }
.art .ring.m { stroke: var(--magenta); } .art .ring.c { stroke: var(--clover); } .art .ring.y { stroke: var(--yolk-deep); }
.art text { fill: rgb(var(--ink) / 0.72); font-size: 11px; font-weight: 500; }
.art text.b { fill: rgb(var(--ink)); font-weight: 650; }
.art text.big { fill: rgb(var(--ink)); font-size: 22px; font-weight: 700; letter-spacing: -0.02em; }
.art text.on { fill: #000; font-weight: 650; }
.art .mid { text-anchor: middle; }
.art .end { text-anchor: end; }
.art .track { fill: none; stroke: rgb(var(--ink) / 0.1); stroke-width: 18; stroke-linecap: round; }
.art .track.m { stroke: var(--magenta); }
.art text.mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 10.5px; }
.art text.sm { font-size: 9.5px; }
.art-note { margin-top: 1.25rem; font-size: 0.875rem; color: rgb(var(--ink) / 0.6); text-wrap: pretty; }
.art .p { transform-box: fill-box; transform-origin: center; }
.motion .art.reveal.in .p { animation: art-pop 0.5s var(--spring) calc(0.15s + var(--i, 0) * 45ms) both; }
.motion .art.reveal.in .d { stroke-dasharray: 1; animation: art-draw 1.1s var(--ease-out) calc(0.2s + var(--i, 0) * 120ms) both; }
@keyframes art-pop { from { opacity: 0; scale: 0.4; } }
@keyframes art-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }

/* ---------- screens: a row of real screenshots you can swipe, drag or step through, and open one at a time ---------- */
.screens { margin-block: 2.75rem; }
.screens figcaption { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; font-size: 0.875rem; line-height: 1.4; font-weight: 600; text-wrap: balance; }
.screens-nav { display: flex; align-items: center; gap: 0.25rem; flex-shrink: 0; font: 600 0.6875rem / 1 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.04em; color: rgb(var(--ink) / 0.55); }
.screens-count { min-width: 3.4em; text-align: center; font-variant-numeric: tabular-nums; }
.screens-step {
  display: grid; place-items: center; width: 1.75rem; height: 1.75rem; padding: 0;
  border: 0; border-radius: 50%; font: inherit; font-size: 0.8rem; color: rgb(var(--ink) / 0.75);
  background: rgb(var(--ink) / 0.06); cursor: pointer;
  transition: background-color var(--dur-quick), color var(--dur-quick), scale 0.3s var(--spring), opacity var(--dur-quick);
}
.screens-step:hover { background: rgb(var(--ink) / 0.12); color: rgb(var(--ink)); }
.screens-step:active { scale: 0.88; }
.screens-step:disabled { opacity: 0.35; cursor: default; }
.screens-step:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
/* the row bleeds to the edge of the column on a phone, so the next shot peeks in and says "swipe" */
.screens-track {
  --gap: 0.875rem;
  display: flex; gap: var(--gap); margin: 0; padding: 0.25rem 0 0.5rem; list-style: none;
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scrollbar-width: none;
  cursor: grab;
}
.screens-track::-webkit-scrollbar { display: none; }
.screens-track:focus-visible { outline: 2px solid var(--ring); outline-offset: 4px; border-radius: 0.75rem; }
.screens-track.dragging { cursor: grabbing; scroll-snap-type: none; }
.screens-track.dragging .shot-open { pointer-events: none; }
@media (max-width: 40rem) { .screens-track { margin-inline: -1rem; padding-inline: 1rem; scroll-padding-inline: 1rem; } }
.shot { flex: 0 0 auto; width: 86%; scroll-snap-align: start; }
.shot.phone { width: min(44%, 13.5rem); }
.phones .shot.phone { width: min(40%, 12.5rem); }
.shot-open {
  position: relative; display: block; width: 100%; aspect-ratio: var(--ar); padding: 0; overflow: hidden;
  border: 0; border-radius: 0.75rem; background: rgb(var(--ink) / 0.05); cursor: zoom-in;
  box-shadow: 0 0 0 1px rgb(var(--ink) / 0.1), 0 10px 24px -14px rgb(0 0 0 / 0.45);
  transition: translate 0.35s var(--spring), box-shadow 0.35s var(--ease-out);
}
.shot-open img { display: block; width: 100%; height: 100%; object-fit: cover; user-select: none; -webkit-user-drag: none; }
/* a browser's top bar on web shots, and a phone's rounded bezel on app shots */
.shot.web .shot-open { padding-top: 1.1rem; aspect-ratio: auto; background: rgb(var(--ink) / 0.07); }
.shot.web .shot-open::before { content: ""; position: absolute; top: calc(0.55rem - 3px); left: 0.6rem; width: 6px; height: 6px; border-radius: 50%; background: var(--magenta); box-shadow: 10px 0 var(--yolk), 20px 0 var(--clover); }
.shot.web .shot-open img { height: auto; aspect-ratio: 16 / 10; object-fit: cover; object-position: top; }
.shot.phone .shot-open { border-radius: 1.4rem; border: 5px solid #16130f; background: #16130f; }
.shot.phone .shot-open img { border-radius: calc(1.4rem - 5px); }
.shot.doc .shot-open { aspect-ratio: 4 / 3; border-radius: 0.5rem; background: #fff; }
.shot.doc .shot-open img { object-fit: contain; }
@media (hover: hover) {
  .shot-open:hover { translate: 0 -3px; box-shadow: 0 0 0 1px rgb(var(--ink) / 0.14), 0 16px 30px -14px rgb(0 0 0 / 0.5); }
}
.shot-open:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
.shot-cap { margin-top: 0.625rem; font-size: 0.8125rem; line-height: 1.4; color: rgb(var(--ink) / 0.62); text-wrap: balance; }
.shot.phone .shot-cap { font-size: 0.75rem; }

/* one screen at a time, full size. It grows out of the shot you tapped (script.js), and the arrows or a swipe move on. */
.lightbox {
  width: 100vw; max-width: none; height: 100dvh; max-height: none; margin: 0; padding: 0; border: 0;
  color: #f7f3ec; background: transparent; overflow: hidden;
}
.lightbox::backdrop { background: rgb(18 15 12 / 0.9); backdrop-filter: blur(6px); }
.lightbox[open] { display: grid; grid-template-rows: 1fr auto; }
.lightbox-stage { position: relative; display: grid; place-items: center; min-height: 0; padding: 3.5rem 1rem 0.5rem; }
.lightbox-stage img { max-width: min(100%, 72rem); max-height: calc(100dvh - 9rem); width: auto; height: auto; object-fit: contain; border-radius: 0.75rem; box-shadow: 0 30px 60px -20px rgb(0 0 0 / 0.7); background: #fff; }
.lightbox-bar { display: flex; align-items: center; gap: 1rem; max-width: 46rem; width: 100%; margin: 0 auto; padding: 0.75rem 1rem calc(1rem + env(safe-area-inset-bottom)); }
.lightbox-cap { flex: 1; font-size: 0.875rem; line-height: 1.45; color: rgb(247 243 236 / 0.85); text-wrap: pretty; }
.lightbox-count { font: 600 0.6875rem / 1 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.04em; color: rgb(247 243 236 / 0.6); font-variant-numeric: tabular-nums; }
.lightbox button {
  display: grid; place-items: center; width: 2.25rem; height: 2.25rem; flex-shrink: 0; padding: 0; border: 0; border-radius: 50%;
  font: 600 0.95rem / 1 inherit; color: #f7f3ec; background: rgb(255 255 255 / 0.1); cursor: pointer;
  transition: background-color var(--dur-quick), scale 0.3s var(--spring);
}
.lightbox button:hover { background: rgb(255 255 255 / 0.2); }
.lightbox button:active { scale: 0.88; }
.lightbox button:focus-visible { outline: 2px solid var(--yolk); outline-offset: 2px; }
.lightbox-close { position: absolute; top: 0.875rem; right: 0.875rem; }

/* ---------- the drawings you can play with: sliders under the drawing, and a readout that follows them ---------- */
.playable svg { touch-action: pan-y; }
.play { display: grid; gap: 0.625rem; margin: 1.25rem auto 0; max-width: 30rem; }
.knob { display: grid; grid-template-columns: minmax(7rem, auto) 1fr 3.8rem; align-items: center; gap: 0.75rem; font-size: 0.8125rem; color: rgb(var(--ink) / 0.72); }
.knob-label { font-weight: 600; color: rgb(var(--ink) / 0.85); }
.knob-value { font: 600 0.75rem / 1 ui-monospace, SFMono-Regular, Menlo, monospace; text-align: right; color: rgb(var(--ink)); font-variant-numeric: tabular-nums; }
.knob input { --fill: 50%; width: 100%; height: 1.5rem; margin: 0; background: none; appearance: none; -webkit-appearance: none; cursor: pointer; }
.knob input::-webkit-slider-runnable-track { height: 6px; border-radius: 3px; background: linear-gradient(90deg, var(--magenta) var(--fill), rgb(var(--ink) / 0.12) var(--fill)); }
.knob input::-moz-range-track { height: 6px; border-radius: 3px; background: linear-gradient(90deg, var(--magenta) var(--fill), rgb(var(--ink) / 0.12) var(--fill)); }
.knob input::-webkit-slider-thumb {
  -webkit-appearance: none; width: 1.125rem; height: 1.125rem; margin-top: -6px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #fff, var(--yolk) 60%, color-mix(in display-p3, var(--yolk), #b3530f 40%));
  box-shadow: 0 0 0 2px #fff, 0 2px 5px rgb(0 0 0 / 0.3); transition: scale 0.25s var(--spring);
}
.knob input::-moz-range-thumb { width: 1.125rem; height: 1.125rem; border: 0; border-radius: 50%; background: var(--yolk); box-shadow: 0 0 0 2px #fff, 0 2px 5px rgb(0 0 0 / 0.3); }
.knob input:active::-webkit-slider-thumb { scale: 1.25; }
.knob input:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 4px; }
.play-row { display: flex; flex-wrap: wrap; gap: 0.375rem; justify-content: center; }
.chip {
  padding: 0.4rem 0.75rem; border: 0; border-radius: 9999px; font: 600 0.75rem / 1.2 inherit; color: rgb(var(--ink) / 0.75);
  background: rgb(var(--ink) / 0.06); cursor: pointer; transition: background-color var(--dur-quick), color var(--dur-quick), scale 0.3s var(--spring);
}
.chip:hover { background: rgb(var(--ink) / 0.12); color: rgb(var(--ink)); }
.chip:active { scale: 0.94; }
.chip[aria-pressed="true"] { color: #000; background: var(--yolk); }
.chip:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.play-readout { min-height: 2.8em; font-size: 0.875rem; line-height: 1.4; text-align: center; color: rgb(var(--ink) / 0.8); text-wrap: balance; }
.play-readout b { color: rgb(var(--ink)); font-weight: 650; }
.play-hint { font: 600 0.625rem / 1 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.08em; text-transform: uppercase; text-align: center; color: rgb(var(--ink) / 0.45); }
.art [data-hit] { cursor: pointer; }
.art .grab { cursor: grab; touch-action: none; }
.art .grab:active { cursor: grabbing; }
.art .live { transition: opacity 0.25s var(--ease-out); }
@media (prefers-reduced-motion: reduce) { .shot-open, .screens-step, .chip { transition: none; } }

/* ---------- the intro's E pops in with the links it belongs to, not ahead of them ---------- */
.motion .intro .links kbd.hint { animation: pop-in 0.5s var(--spring) calc(0.3s + var(--i) * 70ms) both; }
/* no end frame, so it lands on the cap's own resting opacity */
@keyframes pop-in { from { opacity: 0; transform: translateY(6px) scale(0.7); } }

/* ---------- the lights: the dot on the i is the switch ---------- */
/* The tittle sits where Haskoy draws the i's dot: 0.118em in from the letter's left edge and 0.645em above
   the baseline, which with this line height is 0.37em down from the top of the line. By day it's a yolk
   sweet, at night a pale moon, and at this size either one just reads as a dot. */
.tittle { position: relative; display: inline-block; }
.lights {
  position: absolute;
  left: 0.118em;
  top: 0.371em;
  width: 1.3em;
  height: 1.3em;
  translate: -50% -50%;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.lights:focus-visible { outline: none; }
.lights-dot {
  isolation: isolate;
  position: absolute;
  left: 50%;
  top: 50%;
  display: grid;
  place-items: center;
  width: 0.15em;
  height: 0.15em;
  margin: -0.075em 0 0 -0.075em;
  border-radius: 50%;
  color: color-mix(in display-p3, var(--yolk), #000 45%);
  background: radial-gradient(circle at 35% 30%, color-mix(in display-p3, var(--yolk), #fff 55%), var(--yolk) 55%, color-mix(in display-p3, var(--yolk), #b3530f 45%));
  box-shadow: 0 0 0 0.5px color-mix(in srgb, #b3530f 50%, transparent);
  transition: width 0.4s var(--spring), height 0.4s var(--spring), margin 0.4s var(--spring), box-shadow var(--dur-base), background var(--dur-base);
}
.dark .lights-dot {
  color: color-mix(in display-p3, var(--lavender), #000 50%);
  background: radial-gradient(circle at 35% 30%, #fff, #ece7ff 55%, color-mix(in display-p3, var(--lavender), #fff 30%));
  box-shadow: 0 0 4px rgb(214 214 255 / 0.55);
}
.lights-dot svg { position: absolute; width: 60%; height: 60%; opacity: 0; scale: 0.3; transition: opacity var(--dur-quick), scale 0.4s var(--spring); }
/* point at it (or tab to it) and the dot swells into a sweet with its sun or moon showing */
.lights:is(:hover, :focus-visible) .lights-dot {
  width: 0.62em;
  height: 0.62em;
  margin: -0.31em 0 0 -0.31em;
  box-shadow: inset 0 -1px rgb(0 0 0 / 0.15), 0 0 0 1px rgb(0 0 0 / 0.12), 0 2px 4px rgb(0 0 0 / 0.25);
}
.dark .lights:is(:hover, :focus-visible) .lights-dot { box-shadow: inset 0 -1px rgb(0 0 0 / 0.15), 0 0 10px rgb(214 214 255 / 0.6), 0 2px 4px rgb(0 0 0 / 0.4); }
.lights:focus-visible .lights-dot { outline: 2px solid var(--ring); outline-offset: 2px; }
.lights:is(:hover, :focus-visible) .sun, .dark .lights:is(:hover, :focus-visible) .moon { opacity: 1; scale: 1; }
.dark .lights:is(:hover, :focus-visible) .sun { opacity: 0; scale: 0.3; }
.lights:active .lights-dot { scale: 0.85; }
/* stay on it and it charges: it keeps swelling, wobbles faster, and a ring of every candy colour spins up
   around it, brighter the longer you wait. script.js times the same 1.8s to size the blast on click. */
.lights-dot::before {
  content: "";
  position: absolute;
  inset: -3px;
  z-index: -1;
  border-radius: 50%;
  background: conic-gradient(var(--magenta), var(--yolk), var(--clover), var(--sky), var(--lavender), var(--magenta));
  -webkit-mask: radial-gradient(closest-side, transparent 72%, #000 76%);
  mask: radial-gradient(closest-side, transparent 72%, #000 76%);
  opacity: 0;
  pointer-events: none;
}
@media (hover: hover) {
  .motion .lights:hover:not(.spent) .lights-dot {
    animation: lights-swell 1.8s cubic-bezier(0.55, 0, 0.75, 0.3) 0.35s forwards, lights-jelly 0.9s ease-in-out 0.35s infinite;
  }
  .motion .lights:hover:not(.spent) .lights-dot::before {
    animation: lights-halo 1.8s ease-in 0.35s forwards, lights-spin 0.8s linear infinite;
  }
}
@keyframes lights-swell {
  to { scale: 2.1; }
}
@keyframes lights-jelly {
  0%, 100% { transform: scale(1, 1); }
  25% { transform: scale(1.08, 0.93); }
  50% { transform: scale(0.95, 1.06); }
  75% { transform: scale(1.04, 0.97); }
}
@keyframes lights-halo {
  to { opacity: 1; inset: -5px; filter: drop-shadow(0 0 4px rgb(255 255 255 / 0.7)); }
}
@keyframes lights-spin { to { rotate: 1turn; } }
/* the burst's own layer: fixed over the page and named, so during the flood it's drawn live on top of it */
.lights-burst {
  position: fixed;
  z-index: 100;
  inset: 0;
  pointer-events: none;
  view-transition-name: lights-burst;
}
::view-transition-old(lights-burst) { display: none; }
::view-transition-new(lights-burst) { animation: none; }
::view-transition-group(lights-burst) { animation: none; z-index: 10; }
.lights-ring {
  position: fixed;
  z-index: 100;
  width: 28px;
  height: 28px;
  margin: -14px 0 0 -14px;
  border: 6px solid transparent;
  border-radius: 50%;
  background: conic-gradient(var(--magenta), var(--yolk), var(--clover), var(--sky), var(--lavender), var(--magenta)) border-box;
  -webkit-mask: linear-gradient(#000 0 0) padding-box exclude, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) padding-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}
/* the word it says when it goes off is a sticker, cut the same way as the ones on the cards: a white die-cut
   edge, the tone under a sheen that takes the page's light, and a soft shadow where it lifts off the page */
.lights-word {
  --tone: var(--yolk);
  position: fixed;
  z-index: 101;
  display: grid;
  justify-items: center;
  padding: 0.14em 0.42em 0.2em;
  border: 0.14em solid #fff;
  border-radius: 0.5em;
  font-family: "Haskoy", "Hiragino Sans", "Yu Gothic", ui-sans-serif, sans-serif;
  font-weight: 750;
  line-height: 1.1;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: rgb(0 0 0 / 0.86);
  background: linear-gradient(var(--light), rgb(255 255 255 / 0.4), transparent 55%), var(--tone);
  box-shadow: 0 0 0 0.5px rgb(0 0 0 / 0.12), 0 0.2em 0.5em -0.15em rgb(0 0 0 / 0.4);
  pointer-events: none;
}
.lights-word small { font-size: 0.36em; font-weight: 600; letter-spacing: 0.06em; opacity: 0.7; }
.lights-word.magenta { --tone: var(--magenta); }
.lights-word.sky { --tone: var(--sky); }
.lights-word.clover { --tone: var(--clover); }
.lights-word.lavender { --tone: var(--lavender); }
/* the little spray that pops off the dot */
.lights-bit {
  position: fixed;
  z-index: 100;
  width: 5px;
  height: 5px;
  border-radius: 1.5px;
  box-shadow: inset 0 1px rgb(255 255 255 / 0.6), 0 0 0 0.5px rgb(0 0 0 / 0.15);
  pointer-events: none;
}
.lights-bit.round { border-radius: 50%; }

/* ---------- one band per card: script.js clips it to whichever row is lit and slides it between them ---------- */
.band {
  position: absolute;
  z-index: -1;
  inset: 0;
  background-color: var(--band-base);
  background-image: var(--scanlines), repeating-conic-gradient(var(--band-check) 0 25%, transparent 0 50%);
  background-size: auto, calc(2 * var(--checker)) calc(2 * var(--checker));
  background-blend-mode: soft-light, normal;
  pointer-events: none;
  visibility: hidden;
  animation: checker 3.4s linear infinite paused;
}
.band.on { visibility: visible; animation-play-state: running; }
/* the rows keep their own band box, so its position can still be read, but it paints nothing */
.banded .entry-link::before { background: none; animation: none; }

/* ---------- keys in the footer: one line, and each one presses when you click it ---------- */
.keys { flex-wrap: nowrap; gap: 1.25rem; white-space: nowrap; }
.key {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: color var(--dur-quick);
}
.key:hover { color: rgb(var(--ink) / 0.85); }
.key:focus-visible { outline: 2px solid var(--ring); outline-offset: 4px; border-radius: 0.375rem; }
.key:active kbd {
  translate: 0 2px;
  box-shadow: inset 0 1px #fff, inset 0 -1px rgb(0 0 0 / 0.06), 0 0 0 1px rgb(0 0 0 / 0.14), 0 1px 2px -1px rgb(0 0 0 / 0.18);
}
/* R gives one nudge once the band has been through the best work */
kbd.nudge { animation: nudge 0.9s var(--spring); }
@keyframes nudge {
  0%, 100% { scale: 1; }
  30% { scale: 1.3; box-shadow: inset 0 1px #fff, 0 0 0 1px rgb(0 0 0 / 0.14), 0 2px 0 rgb(0 0 0 / 0.14), 0 0 0 5px color-mix(in srgb, var(--magenta) 45%, transparent); }
  60% { scale: 0.94; }
}

/* ---------- Home and its Esc, on one line ---------- */
.pill:has(kbd.hint) { display: flex; align-items: center; gap: 0.5rem; }
.pill kbd.hint {
  position: relative;
  margin: 0;
  vertical-align: 0;
  color: rgb(0 0 0 / 0.55);
  background: rgb(255 255 255 / 0.4);
  box-shadow: inset 0 1px rgb(255 255 255 / 0.55), 0 0 0 1px rgb(0 0 0 / 0.12);
  text-shadow: none;
  opacity: 1;
  /* centre the capitals themselves, not the font's line box, which sits them low in the cap */
  line-height: 1;
  text-box: trim-both cap alphabetic;
}
/* Esc: Home presses in and the page goes soft and sugary for a beat before the next one arrives */
.pill.pressed { scale: 0.95; translate: 0 1px; transition-duration: var(--dur-press); }
.leaving main {
  filter: blur(5px) saturate(1.35);
  scale: 0.99;
  opacity: 0.8;
  transition: filter 0.19s var(--ease-in), scale 0.19s var(--ease-in), opacity 0.19s linear;
}
.lite.leaving main { opacity: 0.6; }

/* phones (html.lite, from the head script): every entrance and exit keeps its move and its fade, but not its
   blur, which is the one part the GPU has to redraw on every frame. Important beats the animations. */
.lite :is(.fade-in, .intro > *, .reveal, .card, .entry-text, .track, .post-cover-frame, main) { filter: none !important; }
.lite.to-md::view-transition-old(root),
.lite.to-md::view-transition-new(root) { filter: none !important; }

/* ---------- ?r: the short version, docked at the bottom ---------- */
.dock {
  --tone: var(--lavender);
  --tone-deep: var(--lavender-deep);
  position: fixed;
  z-index: 40;
  left: 50%;
  bottom: 1rem;
  translate: -50% 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  max-width: calc(100vw - 2rem);
  padding: 0.375rem 0.375rem 0.375rem 1rem;
  border-radius: 9999px;
  font-size: 0.875rem;
  font-weight: 600;
  color: #000;
  white-space: nowrap;
  background-color: var(--tone);
  background-image: var(--scanlines);
  background-blend-mode: soft-light;
  box-shadow:
    inset 0 1px rgb(255 255 255 / 0.5),
    inset 0 -1.5px rgb(0 0 0 / 0.12),
    0 0 0 1px rgb(0 0 0 / 0.1),
    0 12px 24px -8px color-mix(in srgb, var(--tone-deep) 60%, transparent);
}
.dock[hidden] { display: none; }
.motion .dock { animation: dock-in 0.6s var(--spring) 0.5s both; }
@keyframes dock-in { from { opacity: 0; translate: -50% 1.5rem; scale: 0.9; } }
.dock-hi { margin: 0 0.25rem 0 0; }
.dock-key {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.625rem 0.25rem 0.25rem;
  border: 0;
  border-radius: 9999px;
  font: inherit;
  color: inherit;
  text-decoration: none;
  background: rgb(255 255 255 / 0.45);
  box-shadow: inset 0 1px rgb(255 255 255 / 0.6), 0 0 0 1px rgb(0 0 0 / 0.08);
  cursor: pointer;
  transition: background-color var(--dur-quick), scale 0.3s var(--spring);
}
.dock-key:hover { background: rgb(255 255 255 / 0.7); }
.dock-key:active { scale: 0.95; transition-duration: var(--dur-press); }
.dock-key kbd { min-width: 1.25rem; height: 1.25rem; font-size: 0.6875rem; }
.dock-close {
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 0;
  border-radius: 50%;
  color: rgb(0 0 0 / 0.55);
  background: none;
  cursor: pointer;
}
.dock-close:hover { color: #000; background: rgb(255 255 255 / 0.35); }
.dock :focus-visible { outline: 2px solid rgb(0 0 0 / 0.5); outline-offset: 2px; }
@media (max-width: 34rem) { .dock-hi { display: none; } .dock { padding-left: 0.375rem; } }

/* ---------- machine: the page as its markdown, typed out in one column between two rails ---------- */
.md-view { display: none; }
.as-md main > :not(.md-view) { display: none !important; }
.as-md .md-view { display: block; }
.md-column {
  max-width: 34rem;
  min-height: calc(100vh - 6rem);
  margin-inline: auto;
  padding: 0 1.5rem 3rem;
  border-inline: 1px solid rgb(var(--ink) / 0.14);
  font: 0.8125rem / 1.6 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: rgb(var(--ink) / 0.66);
}
/* the way back stays at the top of the column however far down you read */
.md-bar {
  position: sticky;
  z-index: 5;
  top: 0;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0 -1.5rem 1.25rem;
  padding: 0.75rem 1.5rem;
  background: color-mix(in srgb, var(--page) 88%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid rgb(var(--ink) / 0.1);
}
.md-file { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; color: rgb(var(--ink) / 0.45); }
.md-back {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.3125rem 0.5rem 0.3125rem 0.4375rem;
  border: 0;
  border-radius: 999px;
  font: 600 0.6875rem / 1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #000;
  background: linear-gradient(color-mix(in display-p3, var(--lavender), #fff 45%), var(--lavender));
  box-shadow: inset 0 1px rgb(255 255 255 / 0.55), 0 0 0 1px rgb(0 0 0 / 0.12), 0 2px 0 rgb(0 0 0 / 0.12);
  cursor: pointer;
  transition: translate var(--dur-press) ease-out, box-shadow var(--dur-press) ease-out;
}
.md-back svg { transition: translate 0.3s var(--spring); }
.md-back:hover svg { translate: -2px 0; }
.md-back:active { translate: 0 2px; box-shadow: inset 0 1px rgb(255 255 255 / 0.45), 0 0 0 1px rgb(0 0 0 / 0.12); }
.md-back:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
.md-back kbd.hint { line-height: 1; text-box: trim-both cap alphabetic; margin: 0 0 0 0.125rem; height: 1rem; font-size: 0.5625rem; background: rgb(255 255 255 / 0.45); box-shadow: 0 0 0 1px rgb(0 0 0 / 0.12); opacity: 1; color: rgb(0 0 0 / 0.55); }
.md-back-end { display: flex; margin: 1.25rem auto 0; }
/* the copy button's label slides over the file name, so the name steps aside for it */
.md-file { transition: opacity var(--dur-quick); }
.md-bar:has(.md-copy:is(:hover, :focus-visible, [data-state="copied"])) .md-file { opacity: 0; }
.md-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.25rem 1rem;
  margin: 0 0 2rem;
  font-size: 0.75rem;
  color: rgb(var(--ink) / 0.4);
}
.md-meta.md-end { margin: 3rem 0 0; justify-content: center; }
.md-meta a { color: inherit; text-underline-offset: 3px; }
.md-meta a:hover { color: rgb(var(--ink)); }
.md-text > span { display: block; white-space: pre-wrap; overflow-wrap: anywhere; }
.md-text .md-gap { height: 1.6em; }
.md-p { color: rgb(var(--ink) / 0.32); }
.md-h { font-weight: 600; color: rgb(var(--ink)); }
.md-h1 { font-size: 1.125em; }
.md-h .md-p { color: color-mix(in display-p3, var(--magenta), rgb(var(--ink)) 20%); }
.md-li { padding-left: 2ch; text-indent: -2ch; }
.md-bullet { color: color-mix(in display-p3, var(--magenta), rgb(var(--ink)) 20%); }
.md-q { font-style: italic; }
.md-text b { font-weight: 600; color: rgb(var(--ink)); }
.md-text i { color: rgb(var(--ink) / 0.8); }
/* a link keeps its markdown shape: the label sits on a little candy highlight, the address trails after it */
.md-link { color: inherit; text-decoration: none; }
.md-label {
  padding: 0.1em 0.15em;
  border-radius: 0.25rem;
  color: rgb(var(--ink));
  background: color-mix(in srgb, var(--magenta) 24%, transparent);
  box-shadow: inset 0 -1px color-mix(in srgb, var(--magenta) 40%, transparent);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  transition: background-color var(--dur-quick);
}
.md-label .md-p { color: color-mix(in display-p3, var(--magenta), rgb(var(--ink)) 35%); }
.md-link:hover .md-label { background: color-mix(in srgb, var(--magenta) 42%, transparent); }
.md-url { color: rgb(var(--ink) / 0.38); }
.md-link:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 0.25rem; }
.md-copy {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  font: inherit;
  color: #000;
  background: radial-gradient(circle at 35% 25%, #fff 0 20%, transparent 60%), linear-gradient(var(--light), #fff, #efe9df);
  box-shadow: inset 0 -1.5px rgb(0 0 0 / 0.08), 0 0 0 1px rgb(0 0 0 / 0.12), 0 2px 0 rgb(0 0 0 / 0.12), 0 4px 10px -4px rgb(0 0 0 / 0.3);
  cursor: pointer;
  transition: translate var(--dur-press) ease-out, box-shadow var(--dur-press) ease-out, background-color var(--dur-base);
}
.md-copy:active { translate: 0 2px; box-shadow: inset 0 -1px rgb(0 0 0 / 0.06), 0 0 0 1px rgb(0 0 0 / 0.12); }
.md-copy:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
.md-copy-icons { display: grid; }
.md-copy-icons > svg { grid-area: 1 / 1; transition: opacity var(--dur-quick), scale 0.4s var(--spring), rotate 0.4s var(--spring); }
.md-check { opacity: 0; scale: 0.4; }
.md-check path { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 0.3s var(--ease-out); }
/* the sweet goes green, the copy icon spins out and the tick draws in */
.md-copy[data-state="copied"] {
  background: radial-gradient(circle at 35% 25%, rgb(255 255 255 / 0.8) 0 18%, transparent 60%), linear-gradient(var(--light), color-mix(in display-p3, var(--clover), #fff 40%), var(--clover));
}
.md-copy[data-state="copied"] .md-copy-icons > svg:first-child { opacity: 0; scale: 0.4; rotate: -60deg; }
.md-copy[data-state="copied"] .md-check { opacity: 1; scale: 1; }
.md-copy[data-state="copied"] .md-check path { stroke-dashoffset: 0; transition-delay: 0.08s; }
.md-copy::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 2px var(--clover);
  opacity: 0;
  pointer-events: none;
}
.md-copy[data-state="copied"]::after { animation: copied-ring 0.6s var(--ease-out); }
@keyframes copied-ring { from { opacity: 1; scale: 1; } to { opacity: 0; scale: 1.8; } }
/* its label slides out to the left on hover, and says Copied after a copy */
.md-copy-say {
  position: absolute;
  right: calc(100% + 0.5rem);
  padding: 0.25rem 0.5rem;
  border-radius: 0.375rem;
  font: 600 0.6875rem / 1.2 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.04em;
  white-space: nowrap;
  color: rgb(var(--ink) / 0.7);
  background: color-mix(in srgb, rgb(var(--ink)) 8%, var(--page));
  opacity: 0;
  translate: 6px 0;
  pointer-events: none;
  transition: opacity var(--dur-quick), translate 0.35s var(--spring), color var(--dur-quick), background-color var(--dur-quick);
}
.md-copy:is(:hover, :focus-visible, [data-state="copied"]) .md-copy-say { opacity: 1; translate: 0 0; }
.md-copy[data-state="copied"] .md-copy-say { color: #000; background: color-mix(in srgb, var(--clover) 55%, var(--page)); }

/* the switch at the bottom: a cream candy pill, and the side you're on is a lavender sweet that slides across */
.mode {
  position: fixed;
  z-index: 35;
  left: 50%;
  bottom: 1rem;
  translate: -50% 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font: 600 0.6875rem / 1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.motion .mode { animation: dock-in 0.6s var(--spring) 0.9s both; }
.mode-pill {
  position: relative;
  display: flex;
  padding: 3px;
  border-radius: 9999px;
  background-color: #f7f2ea;
  background-image: var(--scanlines);
  background-blend-mode: soft-light;
  box-shadow:
    inset 0 1px #fff,
    inset 0 -1.5px rgb(0 0 0 / 0.07),
    0 0 0 1px rgb(0 0 0 / 0.1),
    0 8px 18px -8px rgb(0 0 0 / 0.35);
}
.dark .mode-pill { background-color: #2a2622; box-shadow: inset 0 1px rgb(255 255 255 / 0.08), 0 0 0 1px rgb(0 0 0 / 0.5), 0 8px 18px -8px rgb(0 0 0 / 0.6); }
.mode-chip {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  width: calc(50% - 3px);
  border-radius: 9999px;
  background-color: var(--lavender);
  background-image: var(--scanlines), linear-gradient(rgb(255 255 255 / 0.45), transparent 60%);
  background-blend-mode: soft-light, normal;
  box-shadow: inset 0 -1.5px rgb(0 0 0 / 0.12), 0 0 0 1px color-mix(in srgb, var(--lavender-deep) 60%, transparent), 0 2px 4px -1px color-mix(in srgb, var(--lavender-deep) 70%, transparent);
  transition: translate 0.45s var(--spring);
}
.as-md .mode-chip { translate: 100% 0; }
.mode-side {
  position: relative;
  display: flex;
  flex: 1 1 0;
  justify-content: center;
  align-items: center;
  gap: 0.4rem;
  min-width: 6.25rem;
  padding: 0.5rem 0.875rem;
  border: 0;
  border-radius: 9999px;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: rgb(var(--ink) / 0.55);
  background: none;
  cursor: pointer;
  transition: color var(--dur-base);
}
.mode-side[aria-pressed="true"] { color: #000; }
.mode-side:hover:not([aria-pressed="true"]) { color: rgb(var(--ink) / 0.85); }
.mode-side:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }
/* a face for each side. The one you're on is awake: the human blinks, the machine's antenna pulses and its
   eyes scan. The other one looks across at it, and whichever you switch to gives a little hop. */
.mode-face {
  width: 1.05rem;
  height: 1.05rem;
  margin: -0.2rem 0;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.mode-face .eyes, .mode-face .bulb { fill: currentColor; stroke: none; }
.mode-face .eyes, .mode-face .bulb, .mode-face .mouth { transform-box: fill-box; transform-origin: center; transition: translate 0.4s var(--spring), scale 0.3s var(--spring); }
.mode-side[aria-pressed="true"] .head { fill: rgb(255 255 255 / 0.55); }
/* the one you're not on looks over at the one you are */
.mode-side[data-side="human"][aria-pressed="false"] .eyes { translate: 1px 0; }
.mode-side[data-side="machine"][aria-pressed="false"] .eyes { translate: -1.1px 0; }
.mode-side[data-side="human"][aria-pressed="false"] .mouth { scale: 0.7 0.5; }
.mode-side[data-side="machine"][aria-pressed="false"] .bulb { opacity: 0.4; }
.motion .mode-side[aria-pressed="true"] .mode-face { animation: face-hop 0.55s var(--spring); }
.motion .mode-side[data-side="human"][aria-pressed="true"] .eyes { animation: face-blink 3.6s 1s infinite; }
.motion .mode-side[data-side="machine"][aria-pressed="true"] .eyes { animation: face-scan 2.4s steps(1) infinite; }
.motion .mode-side[data-side="machine"][aria-pressed="true"] .bulb { animation: face-pulse 1.2s ease-in-out infinite; }
.motion .mode-side:hover[aria-pressed="false"] .mode-face { rotate: -10deg; transition: rotate 0.3s var(--spring); }
.mode-face { transition: rotate 0.3s var(--spring); }
@keyframes face-hop { 35% { translate: 0 -3px; rotate: -12deg; } 70% { translate: 0 0.5px; rotate: 4deg; } }
@keyframes face-blink { 0%, 94%, 100% { scale: 1 1; } 97% { scale: 1 0.12; } }
@keyframes face-scan { 0% { translate: 0 0; } 30% { translate: -1px 0; } 55% { translate: 1px 0; } 80% { translate: 0 0; } }
@keyframes face-pulse { 50% { scale: 1.35; filter: drop-shadow(0 0 2px var(--magenta)); fill: var(--magenta); } }
.mode kbd.hint { margin: 0; }
/* the recruiter dock sits just above it */
.dock { bottom: 4.25rem; }
body { padding-bottom: 4.5rem; }
.docked body { padding-bottom: 8rem; }

/* going to and from the markdown: the page blurs out and the file rises in, softly */
.to-md::view-transition-old(root) { animation: md-out 0.26s var(--ease-in) both; }
.to-md::view-transition-new(root) { animation: md-in 0.42s var(--ease-out) 0.08s both; }
@keyframes md-out { to { opacity: 0; filter: blur(6px); scale: 0.99; } }
@keyframes md-in { from { opacity: 0; filter: blur(6px); translate: 0 12px; } }

/* ---------- stickers peel off and stay where you put them ---------- */
.sticker:not(.ghost) {
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  transform: rotate(var(--tilt, 0deg));
  transition:
    rotate var(--dur-slow) var(--spring), scale var(--dur-slow) var(--spring), opacity var(--dur-base) var(--ease-out),
    transform 0.35s var(--spring), box-shadow var(--dur-base) var(--ease-out);
}
.sticker.peeled {
  z-index: 30;
  cursor: grabbing;
  scale: 1.15;
  box-shadow: 0 0 0 0.5px rgb(0 0 0 / 0.12), 0 18px 28px -8px rgb(0 0 0 / 0.45);
  transition: rotate var(--dur-slow) var(--spring), scale 0.25s var(--spring), transform 0.12s ease-out, box-shadow var(--dur-base);
}
/* the pale patch left behind where it was stuck */
.sticker.ghost {
  color: transparent;
  border-color: rgb(255 255 255 / 0.55);
  background: rgb(255 255 255 / 0.22);
  box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.08);
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--dur-base);
}
.sticker.ghost * { visibility: hidden; }
.sticker.ghost.on { visibility: visible; opacity: 1; }
section:has(.sticker.away) { position: relative; z-index: 5; }
section:has(.sticker.peeled) { z-index: 6; }

@media (prefers-reduced-motion: reduce) {
  .lights-dot, .lights-dot svg, .sticker:not(.ghost), .leaving main { transition: none; }
  .motion .dock, .motion .mode, kbd.nudge { animation: none; }
  .mode-chip { transition: none; }
}
@media print {
  .lights, .lights-burst, .dock, .band, .sticker.ghost, .md-view, .mode { display: none !important; }
}
/* OneIITP's drawings: the students a roll call keeps waiting, and the tiles you can tap */
.art .dot { transition: fill 0.2s var(--ease-out); }
.art .dot.on { fill: var(--magenta); }
.art .tile { cursor: pointer; outline: none; }
.art .tile rect { transition: stroke-width 0.2s var(--ease-out); stroke: rgb(var(--ink)); stroke-width: 0; }
@media (hover: hover) { .art .tile:hover rect { stroke-width: 1.5; } }
.art .tile.sel rect, .art .tile:focus-visible rect { stroke-width: 2.5; }
/* Critter's profit line: the part below zero is shaded, and the marker turns red when you're there */
.art .loss { fill: var(--magenta); opacity: 0.16; }
.art .now { stroke: #fff; stroke-width: 2; transition: fill 0.2s; }
.art .now.in-red { fill: var(--magenta-deep); }
.art text.none { fill: rgb(var(--ink) / 0.45); font-style: italic; }
/* Feet's geofence: people outside the ring are faint, people it counts are bold */
.art .who { opacity: 0.35; transition: opacity 0.2s, r 0.2s; }
.art .who.in { opacity: 1; }
.art .walker.in { fill: var(--magenta); }
.art .fence { fill: color-mix(in srgb, var(--magenta) 10%, transparent); stroke: var(--magenta); stroke-width: 2; }
.art .knobdot { stroke: #fff; stroke-width: 2.5; filter: drop-shadow(0 2px 3px rgb(0 0 0 / 0.3)); outline: none; }
.art .knobdot:focus-visible { stroke: rgb(var(--ink)); }
.art .client { transition: fill 0.25s var(--ease-out), scale 0.35s var(--spring); transform-box: fill-box; transform-origin: center; }
.art .client.on { fill: var(--magenta); }
.art .shape { transition: points 0.3s var(--ease-out); }
.art .hour { transition: fill 0.2s var(--ease-out); }
.art .hour.on { fill: var(--magenta); }

/* ---------- one thing to do with every drawing, and a way back ---------- */
.art.playable { position: relative; }
.art.playable figcaption { padding-right: 5rem; }
.undo {
  position: absolute; top: -0.3rem; right: 0; z-index: 2;
  display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.35rem 0.65rem 0.35rem 0.55rem;
  border: 0; border-radius: 9999px; font: 600 0.75rem / 1 inherit; color: rgb(var(--ink) / 0.85);
  background: var(--page); cursor: pointer;
  box-shadow: inset 0 1px rgb(255 255 255 / 0.6), 0 0 0 1px rgb(var(--ink) / 0.14), 0 6px 14px -6px rgb(0 0 0 / 0.35);
  transition: color var(--dur-quick), box-shadow var(--dur-quick), scale 0.3s var(--spring);
}
.dark .undo { box-shadow: inset 0 1px rgb(255 255 255 / 0.06), 0 0 0 1px rgb(var(--ink) / 0.18), 0 6px 14px -6px rgb(0 0 0 / 0.6); }
.undo:hover { color: rgb(var(--ink)); box-shadow: inset 0 1px rgb(255 255 255 / 0.6), 0 0 0 1px rgb(var(--ink) / 0.3), 0 8px 18px -6px rgb(0 0 0 / 0.4); }
.undo:active { scale: 0.92; }
.undo:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.undo svg { transition: rotate 0.35s var(--spring); }
.undo:hover svg { rotate: -40deg; }
/* tap to focus: the part you picked stays, the rest steps back */
.art [data-why] { cursor: pointer; outline: none; transition: opacity 0.3s var(--ease-out); }
.art [data-why] :is(rect, circle, path, polygon) { transition: stroke-width 0.2s var(--ease-out); }
@media (hover: hover) { .art [data-why]:hover :is(rect, circle, polygon):first-child { stroke: rgb(var(--ink)); stroke-width: 1.5; } }
.art.focused [data-why]:not(.sel) { opacity: 0.3; }
.art [data-why].sel :is(rect, circle, polygon):first-child,
.art [data-why]:focus-visible :is(rect, circle, polygon):first-child { stroke: rgb(var(--ink)); stroke-width: 2.5; }
/* flip: two versions of one drawing, crossfaded */
.art .only-a, .art .only-b { transition: opacity 0.35s var(--ease-out); }
.art .only-b { opacity: 0; visibility: hidden; }
.art.flipped .only-b { opacity: 1; visibility: visible; }
.art.flipped .only-a { opacity: 0; }
@media (prefers-reduced-motion: reduce) { .art .only-a, .art .only-b, .art [data-why], .undo { transition: none; } }
.art .fade-b { transition: opacity 0.35s var(--ease-out); }
.art.flipped .fade-b { opacity: 0.12; }
.art .ghost { fill: rgb(var(--ink) / 0.35); font-weight: 500; transition: fill 0.3s var(--ease-out); }
.art.flipped .ghost { fill: rgb(var(--ink)); font-weight: 650; }
.art [data-step] { transition: opacity 0.3s var(--ease-out); }
.art [data-step].hid { opacity: 0; visibility: hidden; }
.chip:disabled { opacity: 0.55; cursor: default; }
.art .sos { cursor: pointer; outline: none; }
.art .sos:focus-visible rect { stroke: rgb(var(--ink)); stroke-width: 2.5; }
.art.focused :is(.one, .two):not(.sel) { opacity: 0.3; }
.art :is(.one, .two) { transition: opacity 0.3s var(--ease-out); }
.art :is(.one, .two).sel rect { stroke: rgb(var(--ink)); stroke-width: 2; }

/* a film behind its poster: one press swaps in the player (script.js), so nothing from Vimeo loads until then */
.film { margin-block: 2.75rem; }
.film figcaption { margin-bottom: 1rem; font-size: 0.875rem; line-height: 1.4; font-weight: 600; text-wrap: balance; }
.film-open {
  position: relative; display: block; aspect-ratio: 16 / 9; overflow: hidden; border-radius: 0.75rem;
  background: #16130f; text-decoration: none;
  box-shadow: 0 0 0 1px rgb(var(--ink) / 0.1), 0 14px 30px -16px rgb(0 0 0 / 0.5);
  transition: translate 0.35s var(--spring), box-shadow 0.35s var(--ease-out);
}
.film-open img, .film-open iframe { display: block; width: 100%; height: 100%; border: 0; object-fit: cover; }
.film-play {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.7rem 1.1rem 0.7rem 0.95rem;
  border-radius: 999px; font-size: 0.9375rem; font-weight: 650; color: #f7f3ec;
  background: rgb(18 15 12 / 0.78); backdrop-filter: blur(8px);
  box-shadow: 0 0 0 1px rgb(255 255 255 / 0.12), 0 10px 24px -10px rgb(0 0 0 / 0.6);
  transition: scale 0.35s var(--spring), background-color var(--dur-quick);
}
.film-play small { font: 600 0.6875rem / 1 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.04em; opacity: 0.6; }
.film-open.playing { cursor: default; }
@media (hover: hover) {
  .film-open:not(.playing):hover { translate: 0 -3px; box-shadow: 0 0 0 1px rgb(var(--ink) / 0.14), 0 18px 34px -16px rgb(0 0 0 / 0.55); }
  .film-open:hover .film-play { scale: 1.06; background: rgb(18 15 12 / 0.9); }
}
.film-open:active .film-play { scale: 0.94; }
.film-open:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
