/* Speedskull. A record label catalogue: cream page, red wordmark, and every
   release printed its own way. 24 Sept 2026. */

:root {
  --cream: #FEFBF4;
  --red: #B72D23;
  --ink: #221C18;
  --soft: #6E6259;
  --gutter: 16px;
  -webkit-text-size-adjust: 100%; /* 25 Sept: iPhone Safari must never grow the text after the fine pages are measured */
  --sans: 'Inter Tight', 'Helvetica Neue', Arial, sans-serif;
  --serif: var(--sans);
  --type: 'Courier Prime', 'Courier New', monospace;

  /* Paper grain, drawn once as an image and laid over things */
  --grain: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .6 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  /* Coarser speckle, for toner and riso ink */
  --speckle: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='300' height='300'><filter id='s'><feTurbulence type='fractalNoise' baseFrequency='1.6' numOctaves='1' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0'/><feComponentTransfer><feFuncA type='discrete' tableValues='0 0 0 0 0 0 0 .8 1'/></feComponentTransfer></filter><rect width='100%' height='100%' filter='url(%23s)'/></svg>");
  /* Worn rubber stamp: mostly ink, a few gaps */
  --wear: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='w'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0'/><feComponentTransfer><feFuncA type='discrete' tableValues='0 1 1 1 1 1'/></feComponentTransfer></filter><rect width='100%' height='100%' filter='url(%23w)'/></svg>");
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
  min-height: 100vh;
  position: relative;
}
/* NOTHING INSIDE MAIN CAN WIDEN THE PAGE, 28 Sept 2026. body's clip above is
   not enough in Safari: while a Speeding Fine page tears off, its folded
   corner swings out past the right of the window, the page became 848 wide in
   a 390 window for half a second and could be slid 458px sideways (Chrome
   held it). main is as wide as the window, so the tear is still drawn right
   to the edge of the screen. Proved by tools/widthcheck.mjs, which measures
   mid-tear */
main { overflow-x: clip; }
a { color: inherit; }
img { display: block; max-width: 100%; }

/* ---------- Header and hero, the slick pass (Karl, 24 Sept 2026: "looks
   a bit like a website from the 00s"). One sans for everything around the
   releases, left aligned, a header pinned to the top, no shadows or page
   grain; the objects carry the personality ---------- */
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px var(--gutter);
  background: rgba(254,251,244,.94); -webkit-backdrop-filter: blur(12px) saturate(1.4); backdrop-filter: blur(12px) saturate(1.4);
  border-bottom: 1px solid transparent; transition: border-color .3s;
}
.bar.scrolled { border-bottom-color: rgba(34,28,24,.1); }
.bar-mark { display: block; width: clamp(130px, 14vw, 190px); }
.bar-mark img { width: 100%; height: auto; }
.nav { display: flex; gap: 4px clamp(14px, 2.4vw, 28px); flex-wrap: wrap; justify-content: flex-end; }
.nav a { font: 500 15px/1 var(--sans); text-decoration: none; padding: 8px 0; color: var(--ink); transition: color .2s; }
.nav a:hover { color: var(--red); }
.hero { padding: clamp(36px, 7vw, 96px) var(--gutter) clamp(32px, 5vw, 64px); max-width: 1440px; margin: 0 auto; text-align: center;
  --fs: clamp(34px, 5.6vw, 80px); }
/* the wordmark back on top, centred, the same size as the spinner's words:
   the artwork runs S top to p tail, which matches a word's cap to descender,
   about .95 of the font size (Karl, 24 Sept) */
.hero-mark { display: flex; justify-content: center; }
.hero-mark img { height: calc(var(--fs) * .95); width: auto; }
/* the small header logo only shows once the big one has scrolled away */

/* THE WORD SPINNER, Karl's own from the Squarespace homepage: same words,
   timings and blur, now in the page's sans at display size. Words are 1.1em
   tall and a spin runs five of them; the left reel is as wide as the
   longest speed word (set by site.js), so the pair always joins in one place */
.reels {
  --wh: 1.5em; /* tall enough that p, j, g and y clear the fade (Karl, 24 Sept) */
  display: flex; justify-content: center;
  font: 600 var(--fs)/1 var(--sans); letter-spacing: -.035em; color: var(--ink);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%);
}
.reel { position: relative; height: var(--wh); overflow: hidden; }
.reel-l, .reel-r { width: var(--lw, 3.6em); flex: none; }
.strip { position: absolute; top: 0; left: 0; right: 0; will-change: transform, filter; }
.reel-l .strip { right: .12em; }
.reel-r .strip { left: .12em; }
.word { height: var(--wh); line-height: var(--wh); white-space: nowrap; }
.reel-l .word { text-align: right; }
.reel-r .word { text-align: left; color: var(--red); }
.strip.spin-1 { animation: reel-spin 2s cubic-bezier(.4,0,.2,1) forwards; }
.strip.spin-2 { animation: reel-spin 2s cubic-bezier(.4,0,.2,1) .4s forwards; }
@keyframes reel-spin {
  0% { transform: translateY(0); filter: blur(0); }
  12% { filter: blur(2px); }
  35% { filter: blur(7px); }
  65% { filter: blur(7px); }
  85% { filter: blur(2px); }
  100% { transform: translateY(calc(var(--wh) * -5)); filter: blur(0); }
}
.line { margin-top: clamp(12px, 1.6vw, 20px); font: 400 clamp(18px, 1.8vw, 22px)/1.3 var(--sans); color: var(--soft); }
/* who's behind it, for people arriving from a product, socials or LinkedIn
   (Karl, 24 Sept: "go as fast as you think" alone was too little) */
.about-go { font-weight: 600; color: var(--red); text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px; }
.about-go:hover { text-decoration-thickness: 2.5px; }
/* the product names in the about paragraph jump to their releases: glide
   there, and stop with the tile clear of the pinned header */
html { scroll-behavior: smooth; }
.rel { scroll-margin-top: 84px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
.about { max-width: 34em; margin: clamp(18px, 2.4vw, 30px) auto 0; font: 400 clamp(17px, 1.5vw, 19px)/1.55 var(--sans); color: var(--ink); text-wrap: pretty; }

/* ---------- The crate of releases ---------- */
.crate-wrap {
  container-type: inline-size;
  max-width: 1440px; margin: 0 auto; padding: 0 var(--gutter);
}
.crate { display: grid; grid-template-columns: 1fr; gap: 28px 12px; }

.rel { position: relative; isolation: isolate; display: grid; }
.sleeve {
  position: relative; display: block; aspect-ratio: 1; width: 100%;
  /* the front is a button (it turns over), so undo the button look */
  padding: 0; border: 0; border-radius: 0; font: inherit; color: inherit; text-align: left;
  background: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
  container-type: inline-size;
  overflow: hidden; text-decoration: none;
  box-shadow: 0 1px 1px rgba(40,20,10,.10), 0 22px 34px -18px rgba(40,20,10,.45);
  transform: rotate(var(--tilt, 0deg));
  transition: transform .35s cubic-bezier(.3,.7,.3,1), box-shadow .35s;
}
/* every sleeve is printed paper: grain over the top, a little edge wear */
.sleeve::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: var(--grain); opacity: .16; mix-blend-mode: multiply;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.06), inset 0 0 3cqi rgba(60,30,10,.18);
}
button.sleeve:hover, button.sleeve:focus-visible {
  transform: translateY(-4px);
  box-shadow: 0 1px 1px rgba(40,20,10,.10), 0 30px 40px -18px rgba(40,20,10,.5);
}
.sleeve:focus-visible, .sleeve :focus-visible { outline: 3px solid var(--red); outline-offset: 4px; }


@media (min-width: 900px) {
  .crate {
    grid-template-columns: 1fr 1fr;
    gap: 36px 12px; /* lined up, two across, thin gutters (Karl, 24 Sept) */
  }

}

/* ONE LENGTH FOR EVERY TURN, 25 Sept 2026 (Karl: all the animations exactly the
   same length, every reverse seamless). Each release opens in 1.2s and closes
   in 1.2s, the close the exact reverse of its open: the monitor's static and
   lean-in, the print's slide out of the slot (and back into it), the dash's rev
   then lean-in (lean-out on the way back), the card's turn. The + turns to a
   x over the same 1.2s. The hold in the demo is in site.js */
/* the words on a back cover and the way through to the product */
.bk-go { text-decoration: none; align-self: flex-start; transition: background .2s, color .2s, transform .2s; }
.bk-go span { display: inline-block; transition: transform .25s cubic-bezier(.3,.7,.3,1); }
.bk-go:hover span { transform: translateX(.25em); }
/* LINKS MUST BE OBVIOUS (Karl, 24 Sept, "espec on roll the die"): every way
   through to a product is a solid button with an arrow, and it gives one
   nudge once the liner notes have landed, so the eye goes to it */
.rel.turned .bk-go { animation: nudge .9s cubic-bezier(.3,.7,.3,1) 1.3s 1; }
@keyframes nudge { 0%, 100% { transform: none; } 35% { transform: scale(1.07); } 60% { transform: scale(.98); } }
.bk-go:active { transform: scale(.97); }

/* ============ The objects ============
   Karl, 24 Sept 2026: each release as its own medium rather than a sleeve.
   Each object sits straight on the page in a square the size a sleeve was,
   carries its catalogue number on a little plate, and does its own thing
   when tapped to show the liner notes. No. 005 stays a record. */
.obj-body {
  position: relative; aspect-ratio: 1; container-type: inline-size;
  transform: rotate(var(--tilt, 0deg)); cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.plate { /* the brushed metal model plate every object carries */
  font: 700 3cqi/1 var(--type); letter-spacing: .08em; color: var(--ink);
  background: linear-gradient(180deg, #f1efe9, #bdb8ad 55%, #e2ded5);
  padding: 1cqi 1.8cqi .8cqi; border-radius: .5cqi;
  box-shadow: inset 0 0 0 .2cqi rgba(0,0,0,.18), 0 .2cqi 0 rgba(255,255,255,.5);
}

/* ---------- The photographs, 24 Sept 2026 ----------
   Karl: drawn objects looked "too vector art", so 001 to 003 are real photos
   (Pexels, free licence, graded to one warm look in the build script) with
   our moving parts laid onto the flat bits: the screen, the print, the dash
   display. Each photo is laid out on a 1000px stage and scaled to the tile
   by site.js (--k), so every coordinate below is a pixel of that photo.
   Inside the stage, 1cqi is 10 of those pixels. */
.photo { overflow: hidden; background: var(--ink); }
/* the frame clips the tile, so hover can zoom slowly inside it */
.frame { position: relative; overflow: hidden; border-radius: 2px; }
.frame > .obj-body { transition: transform 1.1s cubic-bezier(.2,.7,.2,1); }
@media (hover: hover) { .frame:hover > .obj-body { transform: scale(1.035); } }
/* the catalogue line under every release */
.cap { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 14px; margin-top: 12px; font: 400 15px/1.35 var(--sans); }
.cap-no { color: var(--soft); font-variant-numeric: tabular-nums; }
.cap-name { font-weight: 600; }
.cap-hook { color: var(--soft); }
/* THE + BUTTON (Karl, 24 Sept: on a phone the tiles "just look like gifs of
   photos", nobody knew to tap them). A "Tap to find out more" sticker lasted an
   hour: Karl found it clunky and old, and telling people to click is exactly
   what usability research has said not to do since 1996. The current way is a
   signifier: something that looks pressable. So each tile carries a round +,
   raised off the photo, that turns into a x once the release is open, which
   also shows how to close it. The whole tile stays the button; the + only
   says so. The plain link under each tile went the same day */
.more {
  position: absolute; right: 12px; bottom: 12px; z-index: 7; width: 44px; height: 44px;
  border-radius: 50%; background: var(--cream); cursor: pointer; -webkit-tap-highlight-color: transparent;
  box-shadow: 0 1px 2px rgba(0,0,0,.25), 0 8px 18px -8px rgba(0,0,0,.6);
  transition: transform 1.2s cubic-bezier(.3,.7,.3,1);
}
.more::before, .more::after {
  content: ""; position: absolute; left: 50%; top: 50%; width: 16px; height: 2px; margin: -1px 0 0 -8px;
  border-radius: 1px; background: var(--red);
}
.more::after { transform: rotate(90deg); }
.rel.turned .more { transform: rotate(135deg); }
@media (min-width: 900px) {
  .more { right: 16px; bottom: 16px; width: 48px; height: 48px; }
  .more::before, .more::after { width: 18px; margin-left: -9px; }
}
@media (hover: hover) {
  .frame:hover .more { transform: scale(1.08); }
  .rel.turned .frame:hover .more { transform: rotate(135deg) scale(1.08); }
}
/* THE TEASE, same day: as each release first scrolls into view it does a
   second of its own hover once, so a phone (which has no hover) sees that
   these are things that move when touched. The monitor and the camera borrow
   their tap classes (zap, snap), the Shotluck card its hover lift */
.stage {
  position: absolute; left: 0; top: 0; width: 1000px; height: 1000px;
  transform-origin: 0 0; transform: scale(var(--k, .5)); container-type: inline-size;
}
.zoom { position: absolute; inset: 0; transition: transform 1.2s cubic-bezier(.3,.7,.2,1); }
.ph { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; }
.num { position: absolute; left: 4%; bottom: 4%; z-index: 5; pointer-events: none; }
/* 001: amber VT323 glowing on a strip of black glass, like Idea Download itself */
.num-id {
  font: 400 5cqi/1 'VT323', monospace; letter-spacing: .024em; text-transform: uppercase; color: #ffbc43;
  text-shadow: 0 0 .06em #ff9a00, 0 0 .4em rgba(255,154,0,.6);
  background: linear-gradient(180deg, #120a02, #050200); padding: 1cqi 2cqi .8cqi; border-radius: .6cqi;
  box-shadow: inset 0 0 0 .25cqi rgba(255,173,39,.25), 0 .4cqi 1cqi rgba(0,0,0,.45);
}
/* 002: typed on masking tape, like the Die zine */
.num-die {
  font: 700 4cqi/1 var(--type); letter-spacing: .06em; color: var(--ink);
  background: rgba(236,226,196,.92); padding: 1.1cqi 2.4cqi 1cqi; transform: rotate(-3deg);
  box-shadow: 0 .2cqi .4cqi rgba(0,0,0,.25);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 .8cqi, #000 calc(100% - .8cqi), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 .8cqi, #000 calc(100% - .8cqi), transparent 100%);
}
/* 003: a Paindriver label, DM Mono capitals on cream with the orange topic stripe */
.num-pd {
  font: 500 3.2cqi/1 'DM Mono', monospace; letter-spacing: .1em; text-transform: uppercase; color: var(--ink);
  background: var(--cream); padding: 1.6cqi 2.2cqi 1.3cqi; border-radius: .8cqi;
  box-shadow: inset 0 .7cqi 0 #FF4F00, 0 .4cqi 1cqi rgba(0,0,0,.45);
}
.hit { position: absolute; width: 1px; height: 1px; padding: 0; border: 0; opacity: 0; overflow: hidden; }
.hit:focus-visible { width: auto; height: auto; inset: 0; opacity: 1; background: none; outline: 3px solid var(--red); outline-offset: -3px; }

/* ---------- No. 001: our screen on the real Apple's glass ----------
   A 400 x 300 screen warped onto the four corners of the glass in the photo
   (300,205) (840,210) (860,655) (330,705), worked out as a homography. The
   photo's own reflections sit over it again in 001-glass.png */
.crt-screen {
  position: absolute; left: 0; top: 0; width: 400px; height: 300px; transform-origin: 0 0;
  transform: matrix3d(1.612888,0.078222,0,0.000313,0.115558,1.699905,0,0.000047,0,0,1,0,300,205,0,1);
  overflow: hidden; container-type: inline-size; border-radius: 9% / 12%;
  background: radial-gradient(120% 100% at 45% 40%, rgba(40,20,0,.35), rgba(0,0,0,.2) 70%);
  color: #ffbc43; font-family: 'VT323', monospace;
}
.crt-screen::before { /* scanlines */
  content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: repeating-linear-gradient(to bottom, rgba(0,0,0,0) 0 1.4px, rgba(0,0,0,.28) 1.4px 2.1px);
}
.ph-over { z-index: 4; }
/* tap: we lean in so the screen fills the photo, while it changes channel */
/* the glass's centre is (582,444); scale about it, then slide it to the middle */
.r1 .zoom { transform-origin: 582px 444px; }
.rel.r1.turned .zoom { transform: translate(-82px, 56px) scale(1.5); }
.ch {
  position: absolute; inset: 0; z-index: 2; padding: 7% 7.5%;
  display: flex; flex-direction: column;
  text-shadow: 0 0 .06em #ff9a00, 0 0 .4em rgba(255,154,0,.45);
  transition: filter .35s ease, visibility 0s linear .2s;
}
.ch2 { visibility: hidden; }
.rel.turned .ch1 { visibility: hidden; }
.rel.turned .ch2 { visibility: visible; }
/* channel one, the poster. VT323 letters are .4em wide with the app's own
   1px-at-42px tracking (.024em), so each line is sized to fit on one line */
.ch1 .id-no { font-size: 6cqi; color: #df8b00; letter-spacing: .024em; }
.ch1 .id-hook { margin-top: 2.5cqi; font-size: 5.4cqi; color: #ffad27; text-transform: uppercase; letter-spacing: .024em; white-space: nowrap; }
.ch1 .id-name { margin-top: auto; font-size: 13.5cqi; line-height: 1; text-transform: uppercase; letter-spacing: .024em; white-space: nowrap; }
.ch1 .id-url { margin-top: 3cqi; font-size: 4.8cqi; color: #df8b00; letter-spacing: .024em; text-transform: uppercase; }
.cur { /* the app's own cursor, idea-download/src/index.css .cursor */
  display: inline-block; width: .28em; height: .72em; margin-left: .15em;
  vertical-align: middle; position: relative; bottom: .05em;
  background: #ffad27; box-shadow: 0 0 .12em #ffad27;
  animation: cursor-fade 2.4s ease-in-out infinite;
}
@keyframes cursor-fade { 0%, 100% { opacity: 1; } 50% { opacity: .15; } }
/* channel two, the liner notes */
.ch2 .bk-no { font-size: 4.8cqi; color: #df8b00; letter-spacing: .024em; text-transform: uppercase; }
.ch2 .bk-text { margin-top: 2.5cqi; font-size: 4.7cqi; line-height: 1.02; color: #ffad27; letter-spacing: .024em; }
.ch2 .bk-go {
  margin-top: auto; font-size: 6cqi; line-height: 1; text-transform: uppercase; letter-spacing: .024em;
  background: #ffbc43; color: #080400; text-shadow: none; padding: 1.4cqi 2.6cqi 1.1cqi;
  box-shadow: 0 0 1.6cqi rgba(255,154,0,.7);
}
.ch2 .bk-go:hover { background: #ffd27a; }
/* changing channel: a burst of static and the picture rolls. The channels
   swap at .2s, the middle of the burst */
.crt-static {
  position: absolute; inset: 0; z-index: 4; pointer-events: none; opacity: 0;
  background: url(/assets/static.png) 0 0 / 160px 160px, #6d6a66;
  background-blend-mode: normal;
}
.rel.zap .crt-static { animation: static .44s steps(1) forwards; }
.rel.zap .ch { animation: roll .44s ease-out; }
@keyframes static {
  0% { opacity: .95; background-position: 0 0; }
  15% { background-position: -53px 31px; }
  30% { background-position: 71px -44px; }
  45% { opacity: .9; background-position: -22px 90px; }
  60% { background-position: 96px 12px; }
  75% { opacity: .6; background-position: -80px -61px; }
  100% { opacity: 0; }
}
@keyframes roll {
  0%, 40% { transform: translateY(-12%) scaleY(1.08); filter: brightness(1.8) blur(1px); }
  70% { transform: translateY(3%); filter: brightness(1.2); }
  100% { transform: none; filter: none; }
}
.crt-osd {
  position: absolute; top: 6%; right: 7%; z-index: 4; opacity: 0;
  font: 6cqi/1 'VT323', monospace; color: #7dff8a; text-shadow: 0 0 .3em rgba(125,255,138,.7);
}
.rel.zap .crt-osd { animation: osd 1.2s steps(1) forwards; }
@keyframes osd { 0% { opacity: 0; } 20% { opacity: 1; } 100% { opacity: 0; } }
/* ---------- No. 002: the real OneStep ----------
   The print comes out of the black front slot (y 790 in the photo), then
   is lifted in front of the camera and develops */
.flash { position: absolute; inset: 0; z-index: 6; background: #fff; opacity: 0; pointer-events: none; }
.rel.snap .flash { animation: flash .5s ease-out; }
@keyframes flash { 0% { opacity: 0; } 10% { opacity: .75; } 100% { opacity: 0; } }

/* the print: comes out of the slot, then lifts in front of the camera and
   develops. A face on top, something underneath, in one frame */
.print { /* 25 Sept, Karl: Roll the die was cropped, the print ran 8cqi past the tile. Starts higher, sits tighter */
  position: absolute; left: 18cqi; top: 2.5cqi; width: 64cqi; z-index: 3; transform-origin: 50% 0;
  background: linear-gradient(170deg, rgba(34,28,24,0), rgba(34,28,24,.06)) var(--cream);
  padding: 3.2cqi 3.6cqi 0; border-radius: .6cqi;
  box-shadow: 0 .3cqi .6cqi rgba(0,0,0,.25), 0 2cqi 4cqi -1cqi rgba(20,10,5,.4);
  visibility: hidden; transform: translateY(0);
  cursor: pointer;
}
.print-photo { position: relative; aspect-ratio: 64 / 44; overflow: hidden; background: var(--ink); }
.print-photo img { display: block; width: 100%; height: 50%; object-fit: cover; filter: grayscale(1) contrast(1.15); }
.print-photo img[data-die=face] { object-position: 50% 40%; }
.print-develop { position: absolute; inset: 0; background: linear-gradient(160deg, #8e897f, #7b766c); opacity: 0; }
.print-hand {
  font: 600 4cqi/1.05 'Caveat', cursive; color: var(--ink);
  padding: 1.8cqi .6cqi 2cqi; transform: rotate(-.6deg);
}
.print-go { /* a proper button across the foot of the print, not a strip off its edge */
  display: block; align-self: stretch; text-align: center; margin: 0 0 3cqi;
  font: 900 6.4cqi/1 'Inter', 'Helvetica Neue', Arial, sans-serif; letter-spacing: -.03em;
  background: var(--ink); color: var(--cream); padding: 2.4cqi 3cqi 2.6cqi; border-radius: .6cqi;
}
.print-go:hover { filter: brightness(1.35); }
/* THE DIE LOGO, 5 Oct 2026 (Karl): lowercase "die" in Inter Tight 800 with a drawn die as the dot on the i, the
   die exactly the stem's width, cream face, ink outline and pips. Built into the page from the kit's own outlines
   (die/brand/logos/die-wordmark, so no font is loaded for it); the reference is die/animated/die-logo-240x136.gif.
   The die hops, spins once and lands on a new number (.hop, set by site.js); the pips are redrawn at the top of the
   hop. The same markup and rules sit in the Die page (speedskull-die/site/index.html). Letters take currentColor.
   THE VIEWBOX HAS HEADROOM (y from -320, the letters' top is -200): a CSS filter on an ancestor clips whatever
   spills past the box, and the die hopped out of sight on the Die page until the hop was given room inside it */
.dl { display: block; overflow: visible; }
.dl-word { fill: currentColor; }
.dl-face { fill: var(--cream); stroke: var(--ink); stroke-width: 2.87; }
.dl-pips { fill: var(--ink); }
.dl-die { transform-box: fill-box; transform-origin: 50% 50%; }
.dl.hop .dl-die { animation: dl-hop .7s both; }
@keyframes dl-hop {
  0%   { transform: translateY(0) rotate(0); animation-timing-function: cubic-bezier(.2,.6,.4,1); }
  46%  { transform: translateY(-72px) rotate(190deg); animation-timing-function: cubic-bezier(.5,0,.85,.45); }
  86%  { transform: translateY(0) rotate(360deg); animation-timing-function: ease-out; }
  93%  { transform: translateY(0) rotate(360deg) scale(1.1, .86); }
  100% { transform: translateY(0) rotate(360deg); }
}
/* THE BADGE ON THE POLAROID: the camera's own name plate, where DIE was painted into the photo on 25 Sept, now
   wears the logo. An ink plate over the painted one (the photo is black and white, the plate is the kit's ink like
   every other dark on the site), at the plate's own one degree lean, measured on the 1000px stage. It hops when
   the camera fires (site.js), rising over the camera body, so nothing clips it */
.cam-badge {
  position: absolute; left: 195px; top: 414px; width: 175px; height: 79px; z-index: 2; transform: rotate(-1deg);
  display: flex; align-items: center; justify-content: center; border-radius: 5px; color: var(--cream);
  background: radial-gradient(ellipse 14% 30% at 6% 10%, rgba(255,255,255,.28), rgba(255,255,255,0)), var(--ink);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08), 0 1px 1px rgba(0,0,0,.35);
}
.cam-badge .dl { position: absolute; left: 50%; bottom: 7px; width: 108px; transform: translateX(-50%); }
/* THE DIE ON THE BUTTON (Karl, 25 Sept): a small die like Die's own next to the
   arrow. Press the button and it tumbles for a second before the Die page opens;
   on a mouse it turns slowly under the pointer so you can see it will */
.go-die { display: inline-block; width: 1em; height: 1em; vertical-align: -.14em; margin: 0 .1em 0 .3em; perspective: 6em; } /* after the arrow, so the arrow points at it (Karl) */
.go-die b { display: block; width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transform: rotateX(-25deg) rotateY(-35deg); }
.go-die i {
  /* 25 Sept 2026: matched to the kit's rendered die (die/brand/logos): corners a tenth of the edge, pips a fifth of
     the face wide at the quarter points, cream lit from the top left (top brightest, front next, right darkest) with an
     ink wash per face (--w), dimpled pips */
  position: absolute; inset: 0; border-radius: .1em; backface-visibility: hidden; --w: .08;
  background-color: var(--cream); box-shadow: inset 0 0 0 1em rgba(34,28,24,var(--w)), inset 0 0 0 1px rgba(34,28,24,.18), inset 0 0 .12em rgba(34,28,24,.12);
  --dot: var(--ink) 0 .09em, transparent .1em;
}
.go-die .f1 { --w: .05; transform: translateZ(.5em); background-image: radial-gradient(circle at 50% 50%, var(--dot)); }
.go-die .f6 { --w: .16; transform: rotateY(180deg) translateZ(.5em); background-image: radial-gradient(circle at 27% 25%, var(--dot)), radial-gradient(circle at 73% 25%, var(--dot)), radial-gradient(circle at 27% 50%, var(--dot)), radial-gradient(circle at 73% 50%, var(--dot)), radial-gradient(circle at 27% 75%, var(--dot)), radial-gradient(circle at 73% 75%, var(--dot)); }
.go-die .f3 { --w: .16; transform: rotateY(90deg) translateZ(.5em); background-image: radial-gradient(circle at 25% 25%, var(--dot)), radial-gradient(circle at 50% 50%, var(--dot)), radial-gradient(circle at 75% 75%, var(--dot)); }
.go-die .f4 { --w: .1; transform: rotateY(-90deg) translateZ(.5em); background-image: radial-gradient(circle at 25% 25%, var(--dot)), radial-gradient(circle at 75% 25%, var(--dot)), radial-gradient(circle at 25% 75%, var(--dot)), radial-gradient(circle at 75% 75%, var(--dot)); }
.go-die .f2 { --w: 0; transform: rotateX(90deg) translateZ(.5em); background-image: radial-gradient(circle at 25% 25%, var(--dot)), radial-gradient(circle at 75% 75%, var(--dot)); }
.go-die .f5 { --w: .22; transform: rotateX(-90deg) translateZ(.5em); background-image: radial-gradient(circle at 25% 25%, var(--dot)), radial-gradient(circle at 75% 25%, var(--dot)), radial-gradient(circle at 50% 50%, var(--dot)), radial-gradient(circle at 25% 75%, var(--dot)), radial-gradient(circle at 75% 75%, var(--dot)); }
@keyframes tumble { to { transform: rotateX(360deg) rotateY(540deg) rotateZ(200deg); } }
.print-go.rolling .go-die b { animation: tumble .6s linear infinite; }
@media (hover: hover) { .print-go:hover .go-die b { animation: tumble 2.4s linear infinite; } .print-go.rolling:hover .go-die b { animation-duration: .6s; } }
/* 25 Sept 2026, Karl: about 30% faster (eject 2.8s, develop 4.2s from .3s, the picture 3.85s from 1.4s),
   then the same day the WHOLE thing halved again: eject 1.4s, develop 2.1s from .15s, the picture 1.9s from .7s */
.rel.turned .print { visibility: visible; animation: eject 1.2s both; }
.rel.turned .print-develop { animation: develop 1s cubic-bezier(.4,0,.3,1) .2s both; }
/* THE PRINT, third version (Karl, 24 Sept: come out at the camera's angle,
   almost straight ahead, then flip up; and develop over a few seconds).
   The print is a rigid card hinged at the slot (79cqi down the photo, 71cqi
   below where it rests). It slides out along its own plane while tilted
   almost flat towards you (--tilt), only the part past the slot showing
   (--out, clipped in the card's own coordinates), then swings up to face
   you and rises into place (--y). Custom properties so each part can be
   timed on its own; blur while it's close to the lens, sharp once it's up */
@property --out  { syntax: '<percentage>'; inherits: false; initial-value: 100%; }
@property --tilt { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
@property --py   { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --rot  { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.print {
  transform: perspective(1500px) translateY(var(--py)) rotateX(var(--tilt)) translateY(calc(var(--out) - 100%)) rotate(var(--rot));
  clip-path: inset(calc(100% - var(--out)) -30% -30% -30%);
}
@keyframes eject {
  0%   { --out: 0%;   --tilt: 74deg; --py: 765px; --rot: 0deg; filter: blur(9px); animation-timing-function: cubic-bezier(.3,.05,.45,1); }
  46%  { --out: 100%; --tilt: 74deg; --py: 765px; --rot: 0deg; filter: blur(8px); animation-timing-function: linear; }
  54%  { --out: 100%; --tilt: 70deg; --py: 767px; --rot: 0deg; filter: blur(8px); animation-timing-function: cubic-bezier(.5,.05,.3,1); }
  100% { --out: 100%; --tilt: 0deg;  --py: 0px;   --rot: -3deg; filter: blur(0); }
}
/* developing: pale and flat as it comes out, the picture rising over about
   four seconds after it lands, the way a real Polaroid slowly comes up */
@keyframes develop { from { opacity: .94; } 30% { opacity: .78; } to { opacity: 0; } }
@keyframes develop-img { from { filter: grayscale(1) contrast(.35) brightness(1.35); } to { filter: grayscale(1) contrast(1.15) brightness(1); } }
.rel.turned .print-photo img { animation: develop-img .9s cubic-bezier(.4,0,.3,1) .3s both; }
/* closing (Karl, 25 Sept, late: "the photo should float down, it just
   disappears"): the print falls away from the camera like a dropped photo,
   swaying a little as it goes, and only fades in the last stretch. 1.2s,
   the one length. It used to drop straight down in .45s, then for a few
   hours played the eject backwards */
@keyframes floatdown {
  0%   { transform: translate(0, 0) rotate(-3deg); opacity: 1; animation-timing-function: cubic-bezier(.4,0,.7,.5); }
  35%  { transform: translate(-2cqi, 16cqi) rotate(3deg); opacity: 1; animation-timing-function: cubic-bezier(.3,.3,.6,1); }
  70%  { transform: translate(3cqi, 40cqi) rotate(-5deg); opacity: 1; animation-timing-function: cubic-bezier(.4,0,.7,.6); }
  100% { transform: translate(-1cqi, 72cqi) rotate(2deg); opacity: 0; }
}
.rel.dropping .print { visibility: visible; animation: floatdown .7s forwards; } /* .7s, Karl: faster than the one length */

/* ---------- No. 004: the card game ----------
   25 Sept 2026, Karl: match the real site. shotluck.com is one pile of cards
   on the table and the top card turns over, so that is what this is: two
   cards under, the top card face up with the release on it, and a tap turns
   it over to the liner notes on its other side. The turn is shotluck.com's
   never-past-side-on one: the face goes to edge on and hides, then the other
   side comes round from edge on. Turning back runs it in reverse. The deal
   (two cards out either side, a big notes card landing) is retired */
.table::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: var(--grain); opacity: .25; mix-blend-mode: soft-light;
}
.defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.pile, .sl-card { position: absolute; left: 18cqi; top: 5.2cqi; width: 64cqi; aspect-ratio: 5 / 7; }
.pile { z-index: 1; display: block; }
.pile i {
  position: absolute; inset: 0; display: block; border-radius: 3cqi; overflow: hidden; font-style: normal;
  box-shadow: 0 .3cqi .6cqi rgba(0,0,0,.35);
}
.pile i:nth-child(1) { transform: translate(1.8cqi, 1.8cqi) rotate(-3deg); }
.pile i:nth-child(2) { transform: translate(.9cqi, .9cqi) rotate(-1.5deg); }
.pile svg { width: 100%; height: 100%; display: block; }
.sl-card { z-index: 2; transition: transform .5s cubic-bezier(.34,1.5,.64,1); }
.sl-face, .sl-notes {
  position: absolute; inset: 0; border-radius: 3cqi; overflow: hidden;
  box-shadow: 0 .4cqi 0 rgba(0,0,0,.18), 0 3cqi 5cqi -1cqi rgba(0,0,0,.55);
  background: linear-gradient(160deg, #F8F0E0, #F4EBD9 50%, #EFE4CF);
  display: flex; flex-direction: column; align-items: center; text-align: center;
  color: var(--ink); font-family: 'Barlow Semi Condensed', sans-serif;
}
.sl-face { justify-content: center; }
/* 25 Sept, Karl: the face is shotluck.com's red card (.face.red there: the same
   gradient, cream type, the rules in cream), the notes side stays cream */
.sl-face { color: #F4EBD9; } /* the red itself is in the grime pass at the foot, where the dust goes over it */
.sl-face::before { border-color: #F4EBD9; box-shadow: inset 0 0 0 .9cqi #B44636, inset 0 0 0 1.2cqi #F4EBD9; }
.sl-face .sl-name { color: #F4EBD9; text-shadow: 0 -.25cqi 0 rgba(60,20,10,.5), 0 .3cqi 0 rgba(255,255,255,.22); }
.sl-face .sl-url { color: rgba(244,235,217,.78); }
.sl-face .sl-idx { color: #F4EBD9; }
.sl-mark { display: block; width: 54%; height: auto; margin: 0 auto; color: #B44636; }
.sl-face::before, .sl-notes::before { /* the printed double frame */
  content: ""; position: absolute; inset: 3cqi; border-radius: 1.6cqi; pointer-events: none;
  border: .5cqi solid #B44636; box-shadow: inset 0 0 0 .9cqi #F4EBD9, inset 0 0 0 1.2cqi #B44636;
}
.sl-name {
  font: 400 15cqi/1 'Manufacturing Consent', serif; color: #B44636;
  /* pressed into the card: shadow above, light below */
  text-shadow: 0 -.25cqi 0 rgba(60,20,10,.35), 0 .3cqi 0 rgba(255,255,255,.8);
}
.sl-hook { margin-top: 3.2cqi; font-weight: 700; font-size: 3.6cqi; letter-spacing: .12em; text-transform: uppercase; max-width: 36cqi; line-height: 1.3; }
.sl-url { margin-top: 2.6cqi; font-size: 3.6cqi; color: #5B4A41; }
.sl-idx {
  position: absolute; display: flex; flex-direction: column; align-items: center;
  font: 700 3cqi/1 'Barlow Semi Condensed', sans-serif; color: #B44636; letter-spacing: .06em;
}
.sl-idx b { font-size: 6.4cqi; line-height: .95; }
.sl-tl { top: 5.5cqi; left: 5.5cqi; }
/* THE TURN. Each side's transition is the one for arriving in its state, so
   whichever side is leaving goes to edge on first and the other follows */
.sl-face { transform: perspective(900px) rotateY(0deg); transition: transform .6s ease-out .6s, visibility 0s .6s; }
.rel.turned .sl-face { transform: perspective(900px) rotateY(90deg); visibility: hidden; transition: transform .6s ease-in, visibility 0s .6s; }
.sl-notes { transform: perspective(900px) rotateY(-90deg); visibility: hidden; transition: transform .6s ease-in, visibility 0s .6s; }
.rel.turned .sl-notes { transform: perspective(900px) rotateY(0deg); visibility: visible; transition: transform .6s ease-out .6s, visibility 0s .6s; }
/* the notes side */
.sl-notes { justify-content: flex-start; padding: 7.5cqi 7cqi 7cqi; }
.sl-notes .bk-text { margin-top: 2.6cqi; font-size: 3.6cqi; line-height: 1.28; } /* 3.9 until 25 Sept, Karl: more room round the button */
.sl-notes .bk-go {
  margin-top: auto; align-self: center; position: relative; z-index: 1; white-space: nowrap;
  font-weight: 700; font-size: 4.2cqi; letter-spacing: .1em; text-transform: uppercase;
  background: #B44636; color: #F4EBD9; padding: 2.4cqi 5cqi; border-radius: 1cqi;
  box-shadow: 0 .6cqi 1.4cqi rgba(120,30,20,.35);
}
.sl-notes .bk-go:hover { background: #c4503f; }

/* ---------- No. 003: the real dash ----------
   The Paindriver mark replaces the rev counter (centre 206,492 in the photo,
   which the build script cleared; 25 Sept, Karl: the logo must show before a
   tap, and the closed dash is zoomed in a quarter so it can be read) and our
   screen replaces the middle display (369,369 to 642,635). The real speedo
   stays. Tap: the needle revs off the redline and settles back, then we lean
   in and the middle screen grows into the liner notes */
.pd-gauge { position: absolute; left: 36px; top: 322px; width: 340px; height: 340px; overflow: visible; z-index: 2;
  filter: drop-shadow(0 0 3px rgba(255,255,255,.15)); }
.dash-needle {
  transform-box: view-box; transform-origin: 20px 20px; transform: rotate(0deg); /* sitting on the redline, as the mark does */
  transition: transform .6s cubic-bezier(.3,.7,.3,1);
  filter: drop-shadow(0 0 3px rgba(255,255,255,.5));
}
.rel.turned .dash-needle { transform: rotate(0deg); animation: revup .6s cubic-bezier(.3,.7,.3,1); }
@keyframes revup {
  0% { transform: rotate(0deg); }
  45% { transform: rotate(68deg); }
  70% { transform: rotate(-12deg); }
  100% { transform: rotate(0deg); }
}
.dash-lcd {
  position: absolute; left: 372px; top: 372px; width: 268px; height: 262px; overflow: hidden; z-index: 3;
  border-radius: 10px; background: linear-gradient(180deg, rgba(14,19,24,.92), rgba(8,11,14,.96));
  box-shadow: 0 0 0 1px rgba(154,163,171,.18);
  color: var(--cream);
  transition: left 1.2s cubic-bezier(.3,.7,.3,1), top 1.2s cubic-bezier(.3,.7,.3,1), width 1.2s cubic-bezier(.3,.7,.3,1), height 1.2s cubic-bezier(.3,.7,.3,1);
}
.rel.turned .dash-lcd { left: 300px; top: 330px; width: 410px; height: 345px; transition-duration: .6s; transition-delay: .6s; }
/* closed: zoomed in a quarter, nudged right so the mark keeps its left edge; open: as before */
.r3 .zoom { transform-origin: 505px 502px; transform: translate(44px, 0) scale(1.25); }
.rel.r3.turned .zoom { transform: translate(0, 0) scale(2.2); transition-duration: .6s; transition-delay: .6s; }
.lcd { position: absolute; inset: 0; padding: 18px 20px; display: flex; flex-direction: column; }
/* opening: the release fades at .6s, the notes come up at .9s; closing: the notes fade first, the release back by .6s */
.lcd1 { transition: visibility 0s linear .3s, opacity .3s .3s; }
.lcd2 { visibility: hidden; opacity: 0; transition: visibility 0s linear .3s, opacity .3s 0s; }
.rel.turned .lcd1 { visibility: hidden; opacity: 0; transition: visibility 0s linear .9s, opacity .3s .6s; }
.rel.turned .lcd2 { visibility: visible; opacity: 1; transition: visibility 0s linear .9s, opacity .3s .9s; }
.lcd1 { justify-content: center; align-items: center; text-align: center; }
.pd-name { display: flex; font: 800 34px/1 'Archivo', sans-serif; text-transform: uppercase; letter-spacing: .04em; }
.pd-a { color: #FF4F00; }
.pd-b { color: var(--cream); }
.pd-hook { margin-top: 10px; font: 500 15px 'Archivo', sans-serif; color: var(--cream); }
.pd-url { margin-top: 6px; font: 500 11px 'DM Mono', monospace; letter-spacing: .1em; text-transform: uppercase; color: #9aa3ab; }
.lcd2 .bk-no {
  display: flex; justify-content: space-between;
  font: 500 10px 'DM Mono', monospace; letter-spacing: .1em; text-transform: uppercase; color: #9aa3ab;
}
.lcd2 .bk-text { margin-top: 10px; font: 500 15.5px/1.34 'Archivo', sans-serif; }
.bk-foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; }
.lcd2 .bk-go {
  font: 600 17px/1 'Archivo', sans-serif; background: #FF4F00; color: var(--ink);
  padding: 11px 18px; border-radius: 5px; box-shadow: 0 0 14px rgba(255,79,0,.45);
}
.lcd2 .bk-go:hover { background: #ff6a26; }
/* ---------- No. 005, the next one ---------- */
.surface { background: url(/assets/photos/005-wood.jpg) center / cover, #3a2a1e; }
@media (min-width: 900px) {
  .r5 { grid-column: 1 / -1; }
  .r5 .surface { aspect-ratio: 2 / 1; }
  .r5 .surface > .sleeve { width: 38%; left: 31%; top: 12%; }
}
.surface > .sleeve { position: absolute; left: 12%; top: 12%; width: 76%; transform: rotate(-4deg);
  box-shadow: 0 1px 2px rgba(0,0,0,.4), 0 2cqi 3.5cqi -.6cqi rgba(0,0,0,.6), 0 5cqi 8cqi -3cqi rgba(0,0,0,.5); }
.s-blank {
  background: linear-gradient(135deg, #cfae80, #c29f70 55%, #b8935f);
}
.s-blank::before { /* card fibres */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: var(--speckle); opacity: .18;
}
.bl-ring { /* where a record has pressed through over the years */
  position: absolute; inset: 5cqi; border-radius: 50%;
  box-shadow: inset 0 0 0 1.4cqi rgba(90,60,25,.10), 0 0 0 .6cqi rgba(255,240,210,.12);
}
.bl-hole {
  position: absolute; top: 50%; left: 50%; width: 40cqi; aspect-ratio: 1; transform: translate(-50%, -50%);
  border-radius: 50%;
  background: repeating-radial-gradient(circle, rgba(0,0,0,0) 0 .8%, rgba(0,0,0,.4) .9% 1.6%) var(--ink);
  box-shadow: inset 0 1cqi 2cqi rgba(0,0,0,.6), 0 -.3cqi 0 rgba(255,245,225,.35);
}
.bl-label {
  position: absolute; top: 50%; left: 50%; width: 46%; aspect-ratio: 1; transform: translate(-50%, -50%);
  border-radius: 50%; background: var(--cream);
}
.bl-label::after {
  content: ""; position: absolute; top: 50%; left: 50%; width: 12%; aspect-ratio: 1; transform: translate(-50%, -50%);
  border-radius: 50%; background: #b8935f;
}
.bl-stamp {
  position: absolute; top: 8cqi; right: 8cqi;
  font: 700 6.4cqi/1 var(--type); letter-spacing: .06em; color: var(--red);
  border: .6cqi solid currentColor; padding: 1.4cqi 2.4cqi 1.2cqi;
  transform: rotate(-6deg); opacity: .88;
  -webkit-mask-image: var(--wear); mask-image: var(--wear);
}

.shrink { /* still sealed: shrink wrap catching the light */
  position: absolute; inset: 0; pointer-events: none; z-index: 4;
  background:
    linear-gradient(118deg, rgba(255,255,255,0) 18%, rgba(255,255,255,.34) 24%, rgba(255,255,255,.06) 29%, rgba(255,255,255,0) 34%),
    linear-gradient(118deg, rgba(255,255,255,0) 56%, rgba(255,255,255,.18) 60%, rgba(255,255,255,0) 66%),
    radial-gradient(40% 12% at 12% 4%, rgba(255,255,255,.35), rgba(255,255,255,0)),
    radial-gradient(30% 10% at 92% 97%, rgba(255,255,255,.3), rgba(255,255,255,0));
  background-size: 220% 100%, 220% 100%, 100% 100%, 100% 100%;
  background-position: 30% 0, 30% 0, 0 0, 0 0;
  box-shadow: inset 0 0 0 .5cqi rgba(255,255,255,.12), inset 0 0 3cqi rgba(255,255,255,.08);
  transition: background-position 1.2s cubic-bezier(.3,.7,.3,1);
}
.hype { /* a sticker on the wrap, not on the sleeve */
  position: absolute; left: 8cqi; bottom: 8cqi; z-index: 5; width: 22cqi; height: 22cqi; border-radius: 50%;
  display: grid; place-items: center; text-align: center;
  font: 700 3.6cqi/1.05 var(--type); letter-spacing: .06em; text-transform: uppercase;
  background: var(--red); color: var(--cream); transform: rotate(-12deg);
  box-shadow: 0 .3cqi .5cqi rgba(0,0,0,.25), inset 0 0 0 .6cqi rgba(254,251,244,.35);
}


/* ============ Grime, 24 Sept 2026 ============
   Karl: "make all the items look grungy and photoreal". The textures in
   assets/grime are drawn by a script for this site (scratches, dust,
   fingerprints, edge grime, felt, shrink-wrap creases, a coffee ring), laid
   over each surface in the right blend: light marks on dark things, dirt on
   light things. The light comes from the top left everywhere. */
.g { position: absolute; inset: 0; border-radius: inherit; pointer-events: none; }
/* every object casts a soft shadow on the page, darkest where it touches */
/* ONE CREAM, ONE INK, 25 Sept 2026 (Karl, logo kit): paper is --cream and ink is --ink everywhere on the site; the
   shading that gave paper its depth is now a transparent ink wash over the cream, never a second off-white */
.print { background: url(/assets/grime/dust-paper.png) 0 0 / 200px, linear-gradient(170deg, rgba(34,28,24,.02), rgba(34,28,24,.08)) var(--cream); }
/* 004: real felt, rubbed paler in the middle where hands go, cards handled */
.table { background: url(/assets/photos/004-felt.jpg) center / cover, var(--ink); }
.table::after { background: radial-gradient(90% 80% at 45% 40%, rgba(255,230,200,.10), rgba(0,0,0,0) 55%, rgba(0,0,0,.35) 100%); opacity: 1; mix-blend-mode: normal; }
/* the face is shotluck.com's red card (25 Sept, Karl), handled darker at the edges, the dust over it */
.sl-face { background: url(/assets/grime/dust-paper.png) 0 0 / 200px, radial-gradient(140% 120% at 50% 50%, rgba(0,0,0,0) 60%, rgba(40,10,8,.28) 100%), linear-gradient(180deg, #BB4C3B 0%, #B44636 38%, #A93F31 100%); }
.sl-notes { background: url(/assets/grime/dust-paper.png) 0 0 / 240px, radial-gradient(140% 120% at 50% 50%, rgba(0,0,0,0) 62%, rgba(120,90,40,.2) 100%), linear-gradient(160deg, #F8F0E0, #F4EBD9 50%, #EFE4CF); }
.pile i::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: url(/assets/grime/dust-light.png) 0 0 / 160px; opacity: .45; mix-blend-mode: screen;
  box-shadow: inset 0 0 1.2cqi rgba(255,240,220,.25);
}
/* 005: kraft card that has been about, a coffee ring, creased wrap, a torn corner */
.g-kraft {
  background: url(/assets/grime/coffee-ring.png) 88% 92% / 38% no-repeat, url(/assets/grime/edge-grime.png) 0 0 / 100% 100%, url(/assets/grime/dust-dark.png) 0 0 / 240px;
  opacity: .55; mix-blend-mode: multiply;
}
.shrink { background:
    url(/assets/grime/crinkle.png) 0 0 / 100% 100%,
    linear-gradient(118deg, rgba(255,255,255,0) 18%, rgba(255,255,255,.34) 24%, rgba(255,255,255,.06) 29%, rgba(255,255,255,0) 34%),
    linear-gradient(118deg, rgba(255,255,255,0) 56%, rgba(255,255,255,.18) 60%, rgba(255,255,255,0) 66%),
    radial-gradient(40% 12% at 12% 4%, rgba(255,255,255,.35), rgba(255,255,255,0)),
    radial-gradient(30% 10% at 92% 97%, rgba(255,255,255,.3), rgba(255,255,255,0));
  background-size: 100% 100%, 220% 100%, 220% 100%, 100% 100%, 100% 100%;
  background-position: 0 0, 30% 0, 30% 0, 0 0, 0 0;
  -webkit-mask-image: linear-gradient(225deg, transparent 0 9%, #000 9.2%); mask-image: linear-gradient(225deg, transparent 0 9%, #000 9.2%);
}
.tear { /* the wrap torn back from the top right corner, a curled flap catching the light */
  position: absolute; top: 0; right: 0; z-index: 5; width: 16cqi; height: 16cqi; pointer-events: none;
  background: linear-gradient(225deg, rgba(255,255,255,0) 40%, rgba(255,255,255,.55) 52%, rgba(255,255,255,.15) 60%, rgba(255,255,255,0) 70%);
  clip-path: polygon(0 0, 100% 100%, 92% 90%, 86% 94%, 78% 82%, 70% 86%, 60% 72%, 52% 76%, 44% 62%, 34% 64%, 26% 50%, 16% 52%, 10% 36%, 4% 30%);
  filter: drop-shadow(0 .4cqi .4cqi rgba(0,0,0,.2));
}

/* ---------- Speeding Fine ----------
   Every note is a sheet on a carbon-copy pad (Karl, 24 Sept 2026): the form's
   own printing in Speedskull red, the words typed through in carbon blue, a
   gummed binding across the top. A Speedskull parody: Speedskull is the issuer, no
   government names or crests, no payment details.
   25 Sept 2026, night, Karl: PAGED TICKETS like the social cards. Every note
   is open, no accordion. Each page is a 3:4 ticket; the pages sit stacked
   under the binding, and Next Page tears the top one off the pad (it lifts
   from the bottom, peels up and away, hinged at the glued top); Previous
   drops it back. site.js splits the note into pages by measuring */
:root { --form: #B72D23; --carbon: #2a3584; }
.fines { max-width: 1440px; margin: clamp(80px, 10vw, 140px) auto 0; padding: 0 var(--gutter); position: relative;
  display: grid; grid-template-columns: 1fr; gap: 28px; align-items: start; }
@media (min-width: 900px) { .fines { grid-template-columns: 1fr 1fr; gap: 36px 12px; } }
/* 25 Sept 2026, Karl: three across on a desktop (two was leaving a laptop half empty); two from 900, three from 1200 */
@media (min-width: 1200px) { .fines { grid-template-columns: 1fr 1fr 1fr; } }
.fines-label { grid-column: 1 / -1; }
/* 25 Sept 2026, Karl: "Weekly Speeding Fine", the same face as SPEEDING FINE on each sheet, bigger */
.fines-label { font: 700 36px/1 'Barlow Semi Condensed', sans-serif; letter-spacing: .12em; text-transform: uppercase; color: var(--form); margin-bottom: 8px; }
.fines { padding-bottom: clamp(64px, 8vw, 120px); }
.fine { position: relative; color: var(--carbon); border-top: 18px solid var(--ink); scroll-margin-top: 84px; /* every sheet under its own gummed strip; the margin keeps a /blog landing clear of the header */ }
.fine::before { /* perforations along the top, where the sheets tear off the pad */
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px; opacity: .55; z-index: 60; pointer-events: none;
  background: radial-gradient(circle at 3px 1.5px, rgba(60,40,30,.55) 1px, transparent 1.4px) 0 0 / 7px 3px repeat-x;
}
/* the ticket clips only at its top edge, under the glue strip; a curling
   sheet may lean out sideways and is cut off only as it leaves over the top */
.ticket { position: relative; aspect-ratio: 3 / 4; clip-path: inset(0 -80% -80% -80%); }
.page {
  position: absolute; inset: 0; display: flex; flex-direction: column; padding: 18px 20px 16px;
  background: url(/assets/grime/dust-paper.png) 0 0 / 260px, linear-gradient(180deg, rgba(34,28,24,0), rgba(34,28,24,.04)) var(--cream);
  box-shadow: 0 1px 0 rgba(0,0,0,.08), 0 20px 30px -16px rgba(40,20,10,.45);
}
.page.probe { visibility: hidden; pointer-events: none; }
.page.gone { visibility: hidden; }
/* THE TEAR, third version (Karl, 25 Sept, on the live site: "the top page
   needs to curl away from the bottom corner, there needs to be shadow under
   each page when it turns"), then made NATURAL the same night (Karl: "a bit
   too smooth and robotic"). A CORNER CURL, no 3D: the sheet folds over from a
   bottom corner along a line running up across the sheet, the folded part
   showing the plain paper back, until the whole sheet has curled away past
   the far corner and is gone. --f is how far the fold has travelled. The
   front keeps the part not yet folded (a clip-path); the folded part is a
   separate element, .curl, the same triangle mirrored across the fold line,
   with paper on it, a shadow along the fold, a drop shadow on the page
   beneath, and a blur that grows as the edge lifts (Karl: "a bit out of
   focus"). Karl's final word the same night: Next always from
   the bottom right, Previous back from the top right to the bottom left (the
   left-hand geometry played backwards), one clean movement, and only the
   FOLD ANGLE varies, one of five between 35 and 65 degrees. site.js sets
   --kx and --ky (how far the fold travels along each edge) from the angle,
   and with them the line angle --th, the gradient angle --ga and the fold's
   place along the gradient --g. Reduced motion swaps pages. Each tear leaves
   a ragged stub of paper under the glue (.stub, site.js) */
@property --f { syntax: '<number>'; inherits: false; initial-value: 0; }
/* one clean movement (Karl: no double movement), .9s */
@keyframes curl { from { --f: 0; } to { --f: 1.04; } }
/* THE CLIP SHAPES are half-planes, never the ticket's own corners: a polygon
   that lists the corners crosses itself once the fold's points leave the
   edges (past halfway), and a crossed polygon clips everything (found in
   the WebKit frames). So each shape is a long quadrilateral: two points far
   along the fold line either side of the ticket (A and B, --e beyond the
   fold points, never less than 2.4 tickets so the shape is never thin), and
   those two pushed twenty tickets away on the side to keep. The front keeps
   the side away from the corner, the curl the corner's side */
.page.tearing, .page.dropping {
  --kx: 2; --ky: 2; --g: 1; --ga: 126.87deg; --e: calc((var(--f) + .3) * 8); z-index: 50 !important;
  clip-path: polygon(
    calc(100% + var(--e) * var(--kx) * 100%) calc(100% - (var(--f) + var(--e)) * var(--ky) * 100%),
    calc(100% - (var(--f) + var(--e)) * var(--kx) * 100%) calc(100% + var(--e) * var(--ky) * 100%),
    calc(100% - (var(--f) + var(--e)) * var(--kx) * 100% - 2000% * var(--ky)) calc(100% + var(--e) * var(--ky) * 100% - 2000% * var(--kx)),
    calc(100% + var(--e) * var(--kx) * 100% - 2000% * var(--ky)) calc(100% - (var(--f) + var(--e)) * var(--ky) * 100% - 2000% * var(--kx)));
}
.page.tearing.from-left, .page.dropping.from-left {
  clip-path: polygon(
    calc(0% - var(--e) * var(--kx) * 100%) calc(100% - (var(--f) + var(--e)) * var(--ky) * 100%),
    calc((var(--f) + var(--e)) * var(--kx) * 100%) calc(100% + var(--e) * var(--ky) * 100%),
    calc((var(--f) + var(--e)) * var(--kx) * 100% + 2000% * var(--ky)) calc(100% + var(--e) * var(--ky) * 100% - 2000% * var(--kx)),
    calc(0% - var(--e) * var(--kx) * 100% + 2000% * var(--ky)) calc(100% - (var(--f) + var(--e)) * var(--ky) * 100% - 2000% * var(--kx)));
}
.page.tearing, .curl.tearing { animation: curl .9s cubic-bezier(.5,0,.4,1) forwards; }
.page.dropping, .curl.dropping { animation: curl .9s cubic-bezier(.5,0,.4,1) reverse both; }
/* the shadow the lifted fold throws back onto the front, just before the fold */
.page.tearing::before, .page.dropping::before {
  opacity: 1;
  background: linear-gradient(var(--ga), rgba(0,0,0,0) calc((1 - var(--f) * var(--g)) * 100% - 14%), rgba(30,15,5,.28) calc((1 - var(--f) * var(--g)) * 100%), rgba(0,0,0,0) calc((1 - var(--f) * var(--g)) * 100% + 1%));
}
.page::before { content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 5; opacity: 0; }
.curl {
  position: absolute; inset: 0; z-index: 51; pointer-events: none;
  --f: 0; --kx: 2; --ky: 2; --g: 1; --th: 126.87deg; --ga: 126.87deg; --wob: 0deg; --e: calc((var(--f) + .3) * 8);
  clip-path: polygon(
    calc(100% + var(--e) * var(--kx) * 100%) calc(100% - (var(--f) + var(--e)) * var(--ky) * 100%),
    calc(100% - (var(--f) + var(--e)) * var(--kx) * 100%) calc(100% + var(--e) * var(--ky) * 100%),
    calc(100% - (var(--f) + var(--e)) * var(--kx) * 100% + 2000% * var(--ky)) calc(100% + var(--e) * var(--ky) * 100% + 2000% * var(--kx)),
    calc(100% + var(--e) * var(--kx) * 100% + 2000% * var(--ky)) calc(100% - (var(--f) + var(--e)) * var(--ky) * 100% + 2000% * var(--kx)));
  transform-origin: 100% calc(100% - var(--ky) * 100% * var(--f));
  transform: rotate(var(--wob)) rotate(var(--th)) scaleY(-1) rotate(calc(-1 * var(--th)));
  background:
    linear-gradient(var(--ga), rgba(0,0,0,0) calc((1 - var(--f) * var(--g)) * 100% - 1%), rgba(30,15,5,.34) calc((1 - var(--f) * var(--g)) * 100%), rgba(30,15,5,.06) calc((1 - var(--f) * var(--g)) * 100% + 16%), rgba(0,0,0,0) calc((1 - var(--f) * var(--g)) * 100% + 40%)),
    url(/assets/grime/dust-paper.png) 0 0 / 260px, linear-gradient(180deg, rgba(34,28,24,.04), rgba(34,28,24,0)) var(--cream);
  filter: drop-shadow(-7px 7px 9px rgba(30,15,5,.42)) blur(calc(var(--f) * 2px));
}
.curl.from-left {
  clip-path: polygon(
    calc(0% - var(--e) * var(--kx) * 100%) calc(100% - (var(--f) + var(--e)) * var(--ky) * 100%),
    calc((var(--f) + var(--e)) * var(--kx) * 100%) calc(100% + var(--e) * var(--ky) * 100%),
    calc((var(--f) + var(--e)) * var(--kx) * 100% - 2000% * var(--ky)) calc(100% + var(--e) * var(--ky) * 100% + 2000% * var(--kx)),
    calc(0% - var(--e) * var(--kx) * 100% - 2000% * var(--ky)) calc(100% - (var(--f) + var(--e)) * var(--ky) * 100% + 2000% * var(--kx)));
  transform-origin: 0 calc(100% - var(--ky) * 100% * var(--f));
  filter: drop-shadow(7px 7px 9px rgba(30,15,5,.42)) blur(calc(var(--f) * 2px));
}
/* what a torn sheet leaves behind: a ragged stub of paper under the glue,
   one per tear, its edge drawn by site.js */
.stub {
  position: absolute; left: 0; right: 0; top: 0; height: 12px; z-index: 55; pointer-events: none;
  background: url(/assets/grime/dust-paper.png) 0 0 / 260px, linear-gradient(180deg, rgba(34,28,24,.07), rgba(34,28,24,.04)) var(--cream);
  filter: drop-shadow(0 1px 1px rgba(40,20,10,.35));
}
.fine-head { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  border-bottom: 2.5px solid var(--form); padding-bottom: 8px; }
.fine-kind { font: 700 24px/1 'Barlow Semi Condensed', sans-serif; letter-spacing: .12em; text-transform: uppercase; color: var(--form); }
.fine-issuer { height: 20px; width: auto; }
/* the boxes: Date, Name (Karl, 25 Sept, in place of a signature at the end) and Page on the right ("1/2"); the No. box went 25 Sept */
.fine-row { display: grid; grid-template-columns: auto 1fr auto; margin-top: 12px; border: 1px solid var(--form); }
.fine-field { display: flex; flex-direction: column; gap: 4px; padding: 7px 12px 8px; border-right: 1px solid var(--form); min-width: 0; }
.fine-field:last-child { border-right: 0; }
.fine-field i { font: 700 10px/1 'Barlow Semi Condensed', sans-serif; font-style: normal; letter-spacing: .12em; text-transform: uppercase; color: var(--form); }
/* typed through the carbon: blue, a little soft, a little uneven */
.fine-field b, .fine .note-body, .fine-nav button {
  color: var(--carbon); text-shadow: 0 0 .5px rgba(42,53,132,.7), .3px .2px .6px rgba(42,53,132,.25);
}
.fine-field b { font: 700 17px/1.2 var(--type); letter-spacing: .02em; }
.fine .note-body { flex: 1; min-height: 0; overflow: hidden; margin-top: 12px; font-family: var(--type); font-size: 16px; line-height: 1.6; }
.note-body p + p { margin-top: .75em; }
/* Next Page, Previous Page: the note's own type and blue, above the foot line */
.fine-nav { display: flex; justify-content: space-between; margin-top: 10px; min-height: 26px; }
.fine-nav button {
  font: 400 16px/1.6 var(--type); background: none; border: 0; padding: 0; cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; -webkit-tap-highlight-color: transparent;
}
.fine-nav button:hover { text-decoration-thickness: 2px; }
.fine-nav button:focus-visible { outline: 2px solid var(--carbon); outline-offset: 3px; }
.fine-nav .fine-next { margin-left: auto; }
.page.first .fine-prev, .page.last .fine-next { display: none; }
.fine[data-pages="1"] .fine-nav { display: none; }
.fine-foot { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; margin-top: 8px;
  padding-top: 12px; border-top: 1px solid rgba(183,45,35,.35); }
.fine-code { display: block; line-height: 0; }
.fine-bars { width: 170px; max-width: 55%; height: 34px; fill: var(--carbon); opacity: .85; display: block; }
.fine-site { font: 700 10px/1 'Barlow Semi Condensed', sans-serif; letter-spacing: .12em; text-transform: uppercase; color: var(--form); }
@media (max-width: 560px) {
  .fines-label { font-size: 28px; }
  .fine-kind { font-size: 19px; }
  .fine-issuer { height: 16px; }
  .fine .note-body, .fine-nav button { font-size: 15px; }
  .fine-field b { font-size: 14px; } /* Date, Name and Page across a phone */
  .fine-field { padding: 6px 9px 7px; }
  .page { padding: 14px 16px 12px; }
  .fine-bars { width: 150px; height: 30px; }
}
/* THE SMALLEST PHONES, 28 Sept 2026: at 320 the three boxes needed 280 and had
   254, so the name wrapped to "Karl / Sheridan" and made the row a line
   taller. A size down and tighter boxes keep Date, Name and Page on one line
   each. tools/widthcheck.mjs asks for one line in every box */
@media (max-width: 340px) {
  .fine-field b { font-size: 13px; letter-spacing: 0; }
  .fine-field { padding: 6px 6px 7px; }
}

/* ---------- Moving ---------- */
/* Pages cross-fade into each other where the browser can (Chrome, Safari 18) */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .3s; }

/* Sleeves are dealt onto the page as they scroll in. Only with JS on, so
   nothing is ever hidden from a browser that cannot run it */
.js .rel { opacity: 0; transform: translateY(32px); }
.js .rel.in {
  opacity: 1; transform: none;
  transition: opacity .7s ease, transform .9s cubic-bezier(.2,.8,.2,1);
}
.js .rel.in .sleeve, .js .rel.in .obj-body { animation: settle 1s cubic-bezier(.2,.8,.2,1) backwards; animation-delay: inherit; }
@keyframes settle { from { transform: translateY(10px); } }

/* Pressing a button on the way out pushes it in a touch */
.rel.go .bk-go { transform: scale(.95); transition-duration: .15s; }

/* Each sleeve does its own small thing on hover */
.ch { transition: filter .35s ease; }
/* Karl: make every hover brighter, Idea Download's is the one he likes */
@media (hover: hover) {
  .r1:hover .ch { filter: brightness(1.3); }
  .r3:not(.turned):hover .dash-needle { transform: rotate(-72deg); } /* a blip of throttle */
  .r4:not(.turned):hover .sl-card { transform: translateY(-1.5cqi); }
  .r5:hover .shrink { background-position: 0 0, -60% 0, -60% 0, 0 0, 0 0; }
}


@media (prefers-reduced-motion: reduce) {
  .cur, .dash-needle, .strip, .rel.turned .bk-go, .go-die b { animation: none !important; }
  .page.tearing, .page.dropping, .curl { animation: none !important; }
  .sleeve, .zoom, .sl-card, .sl-face, .sl-notes, .dash-lcd, .lcd, .dash-needle, .shrink { transition: none !important; }
  .js .rel { opacity: 1; transform: none; }
  .dl.hop .dl-die { animation: none !important; }
  .rel.zap .crt-static, .rel.zap .ch, .rel.zap .crt-osd, .rel.turned .print, .rel.turned .print-develop, .rel.turned .print-photo img, .rel.dropping .print, .rel.snap .flash { animation-duration: .01s !important; animation-delay: 0s !important; }
  .js .rel.in .sleeve, .js .rel.in .obj-body { animation: none; }
}

/* ---------- Contact, the foot of the page ----------
   Karl, 24 Sept 2026: Hire Karl in the header became Contact, and comes here */
.foot {
  max-width: 1440px; margin: 0 auto; padding: 36px var(--gutter) clamp(48px, 6vw, 80px);
  border-top: 1px solid rgba(34,28,24,.12);
  display: grid; gap: 12px; font: 400 15px/1.4 var(--sans); color: var(--ink);
}
.foot-label { font: 600 15px/1 var(--sans); margin: 0 0 6px; }
.foot-mail { margin: 0; }
.foot-mail a { font: 600 clamp(22px, 3vw, 32px)/1.1 var(--sans); color: var(--red); text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 5px; overflow-wrap: anywhere; }
/* 25 Sept 2026: Donate came down from the header with its reason; Instagram is off until there are followers */
.foot-give { margin: 4px 0 0; max-width: 46ch; font: 400 15px/1.5 var(--sans); color: var(--ink); }
.foot-give a { color: var(--red); font-weight: 500; text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px; }
.foot-give a:hover { color: var(--ink); }
.foot-where { margin: 0; color: var(--soft); }
