/* Caveat, self-hosted (OFL, see media/fonts/LICENSE-OFL.txt). One variable-weight woff2, latin subset only: that is every
   glyph the handwritten notes use. Google Fonts serves this same file for both weights the site asks for, so one file
   carries the 500-600 range. */
@font-face {
  font-family: "Caveat";
  font-style: normal;
  font-weight: 500 600;
  font-display: swap;
  src: url("media/fonts/caveat-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* palette carried from an earlier mock */
  --ink: #17130D;
  --surface: #241E15;
  --line: #3A3122;
  --line-2: #4A3F2B;
  --paper: #F3ECDD;
  --muted: #AC9F88;
  --muted-2: #877C68;
  --marigold: #FFE097;       /* accent swap 2026-09-16: soft yellow (was amber #F6B24A) */
  --cool: #8AB0FF;
  --ok: #7FD1A6;
  /* desk objects */
  --kraft-ink: #2A1F12;
  --terracotta: #C4613A;
  /* terracotta deep enough for small text on the cream paper: 5.43:1 on --paper and 4.76:1 against the polaroid's
     grain-darkened cream, measured on the rendered page — so it clears WCAG AA's 4.5:1 without counting the grain
     darkening the text too (--terracotta itself is 3.49:1, fine for the swatch and the bullets, which are not text) */
  --terracotta-text: #9C4524;

  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --mono: "SF Mono", "SFMono-Regular", ui-monospace, Menlo, Consolas, monospace;
  --hand: "Caveat", "Bradley Hand", "Segoe Print", "Comic Sans MS", cursive;

  --container: 1160px;
  --pad-x: clamp(1.25rem, 5vw, 2.75rem);

  /* generated paper grain: SVG turbulence, tiled, used as an overlay on every paper object */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.55 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  /* no generated torn edges any more: the tapes, the note sheet both featured cards use and the kraft bio are photographed objects
     with real edges (see "physical devices" below) */
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
[id] { scroll-margin-top: 72px; }
body {
  margin: 0;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
/* the desk: a warm dark surface with a little grain. The lamp itself lives on .hero::before (page-anchored,
   not fixed) so it lights the hero and is fully gone by the marquee; the desk below stays dark. */
body::before {
  content: "";
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(70% 50% at 0% 100%, color-mix(in srgb, var(--cool) 5%, transparent), transparent 60%),
    linear-gradient(180deg, #1B1610, #15110C);
}
body::after {
  content: "";
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background: var(--grain);
  opacity: 0.16;
  mix-blend-mode: overlay;
}
body > * { position: relative; z-index: 1; }
::selection { background: var(--marigold); color: var(--ink); }

h1, h2, h3, p, figure { margin: 0; }
a { color: inherit; text-decoration: none; }
img { display: block; max-width: 100%; }
svg { display: block; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
/* visually hidden, still read by assistive tech (the Work board keeps its heading without a visible label) */
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

.wrap { max-width: var(--container); margin-inline: auto; padding-inline: var(--pad-x); width: 100%; }
.hand { font-family: var(--hand); font-weight: 500; }
.display { font-weight: 800; letter-spacing: -0.035em; line-height: 0.98; text-transform: uppercase; }

:focus-visible { outline: 3px solid var(--marigold); outline-offset: 3px; }

/* ---------- physical devices ---------- */
/* The tape, the binder clip and the note paper both featured cards use are the owner's real objects: torn strips of painter's tape, a green
   binder clip and a torn white sheet, photographed on his desk (iPhone JPEGs in ~/Desktop/jon-textures on Belinda's Mac,
   not in the repo), lifted off their backgrounds with macOS Vision (subject mask), edges eroded a few px to drop the
   background fringe, and exported as alpha WebP at 2x their largest on-screen size. The tape was shot in blue and
   recoloured to masking-tape tan during export (each pixel's brightness kept, hue moved to #DFC799, so the fibre texture
   and the torn edges are the real thing; the exports average #D9C597-#DCC597); the paper was tinted to the site's
   cream; the clip is untouched. media/ is cached immutable for a year, so a re-export gets a new filename
   (tape-tan-4.webp, clip-2.webp...). */

/* masking tape: three different torn strips (tape-tan-1 long, tape-tan-2 chunkier tear, tape-tan-3 short) spread across
   the instances so no two neighbours look stamped from one piece. Each box keeps its strip's own pixel aspect ratio
   (aspect-ratio = the export's size) so `100% 100%` never stretches the tear. */
.tape {
  position: absolute;
  width: 107px; aspect-ratio: 260 / 67;
  background: url("media/tape-tan-1.webp") center / 100% 100% no-repeat;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,0.35));
  z-index: 4;
  pointer-events: none;
}
.tape.tl { top: -13px; left: -30px; transform: rotate(-38deg); }
.tape.tr { top: -13px; right: -30px; transform: rotate(36deg); width: 92px; aspect-ratio: 260 / 78; background-image: url("media/tape-tan-2.webp"); }
.tape.top { top: -14px; left: 50%; transform: translateX(-50%) rotate(-3deg); }

/* torn paper: the shadow lives on a wrapper so it follows the clipped/masked edge */
.torn { position: relative; filter: drop-shadow(0 2px 2px rgba(0,0,0,0.45)) drop-shadow(0 16px 22px rgba(0,0,0,0.5)); }
/* the about/bio card is the owner's crumpled sheet of kraft paper (paper-kraft.webp, 1240x1661, from IMG_1723: Vision
   cutout, edges eroded 8px, perspective-corrected so the sheet's edges run square; low-frequency lighting flattened and the mean set to #BBA081, a warm nudge from the photo's
   greyish #BFB2A2 toward the site's kraft; creases pulled 55% toward the mean and a luminance floor applied so
   --kraft-ink reads at >= 4.5:1 even on the darkest crease pixel inside the text zone, 6.6:1 on average). The file is
   both the background and the mask, each at `100% 100%`, so the torn outline, the fibre fringe and the crumple
   register exactly and the card's shape is the sheet's real outline on all four sides at every width. The photo is
   3:4 and the card runs from ~0.37:1 (320px phones) to ~1.6:1 (desktop), so the sheet is stretched to the box: on
   desktop the creases run ~2x wider than tall and the side tears are ~2x deeper than the top ones, on phones the
   reverse at ~1.6x; it still reads as crumpled kraft. Chosen over drawing the sheet in halves or quarters: with a
   non-square photo the halves stop covering the card past 1.5:1, and quarters put a visible step in each edge where
   two different columns of the tear meet; one stretched layer has no seam, no step and one code path. No --grain
   overlay here now, the photo has its own. The masked shape is what .torn's drop-shadow follows. `mask` unprefixed is
   Baseline since Dec 2023 (Chrome 120, Safari 15.4, Firefox 53); the -webkit- form covers earlier Chrome. */
.kraft {
  position: relative;
  background: url("media/paper-kraft.webp") center / 100% 100% no-repeat;
  -webkit-mask: url("media/paper-kraft.webp") center / 100% 100% no-repeat;
  mask: url("media/paper-kraft.webp") center / 100% 100% no-repeat;
  color: var(--kraft-ink);
}
.print::after, .vcard::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: var(--grain); opacity: 0.22; mix-blend-mode: multiply;
}
/* the note paper on both featured cards: the owner's torn sheet (paper-torn.webp, 900x896, lighting flattened and tinted from photo-white to the
   --paper cream during export so it matches the print frames). The box's aspect changes with the viewport (2.4:1 at
   768, portrait at 1024) and the photo is square, so one stretched background would smear the tear. Instead the sheet
   is drawn twice, by the two pseudo-elements. Each is as tall as the box and, via aspect-ratio, as wide as the photo is
   at that height, but never narrower than 58% of the box (so the photo's far tear and the brighter deckle band beside
   it, ~120 of its 900 columns, always lie past the middle); it shows the photo `cover`-scaled and anchored to its outer
   edge and is clipped at the box's midline. The midline is 50cqw + the side padding: .scrap is an inline-size container
   and cqw measures its content box, so the padding (--scrap-pad-x, shared with the padding rule) is added back. Result:
   the left half always ends in the sheet's real left tear, the right half in its right tear, the two meet on 2px of
   plain paper (no seam: the export is one even tone), and the top and bottom tears show whenever the box is under about
   2:1; wider than that they crop straight, and they are only a few px deep in the photo anyway. overflow: clip keeps the
   taller-than-wide case (1024) from adding scrollable overflow. A 9-slice border-image was tried first and dropped:
   rotated tiles anti-alias at every slice edge and show hairline seams (WebKit especially). No grain overlay: the photo
   carries its own. */
.scrap {
  --scrap-pad-x: 0px;
  position: relative; isolation: isolate; container-type: inline-size; overflow: clip;
  color: var(--ink);
}
.scrap::before, .scrap::after {
  content: ""; position: absolute; top: 0; bottom: 0; z-index: -1; pointer-events: none;
  aspect-ratio: 900 / 896; min-width: 58%;
  background: url("media/paper-torn.webp") left center / cover no-repeat;
}
.scrap::before { left: 0; clip-path: inset(0 calc(100% - 50cqw - var(--scrap-pad-x) - 1px) 0 0); }
.scrap::after { right: 0; background-position: right center; clip-path: inset(0 0 0 calc(100% - 50cqw - var(--scrap-pad-x) - 1px)); }

/* taped 9:16 print frame — the video card */
.vcard {
  position: relative;
  width: 100%;
  background: var(--paper);
  padding: 10px 10px 16px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.45), 0 18px 30px -10px rgba(0,0,0,0.75);
}
.vcard .screen {
  position: relative; aspect-ratio: 9 / 16; background: #0d0b07; overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.35);
}
/* A keyboard user can tab to the video itself (it has native controls), but `overflow: hidden` above clips the ring the
   browser draws on it, so the video used to take focus invisibly. The ring is moved to the frame instead: an element's
   own outline is not clipped by its own overflow, and the 3px ring at 3px offset lands on the card's 10px cream margin.
   Ink, not marigold, for the same reason the sound control's ring is ink — 15.7:1 on that paper against 1.04:1.
   `:has()` is Baseline widely available (Dec 2023: Safari 15.4, Chrome/Edge 105, Firefox 121) and the page already
   depends on it for the at-home clip slots. */
.vcard .screen:has(video:focus-visible) { outline: 3px solid var(--ink); outline-offset: 3px; }
.vcard video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block;
}

/* binder clip: the owner's green clip, arms folded up (clip.webp, 140x163, an <img> with width/height so nothing shifts
   while it loads). The green body is the lower half of the picture; .card-side .clip sets `top` so the body's top edge
   sits just over the paper's edge and the jaw reads as gripping it. */
.clip { position: absolute; z-index: 6; width: 54px; height: auto; filter: drop-shadow(0 4px 5px rgba(0,0,0,0.6)); pointer-events: none; }

/* hand-drawn arrows: stroke/fill are attributes on the #hand-arrow symbol paths; only the colour is set here */
.arrow { width: 70px; height: 46px; color: var(--paper); }

/* ---------- header ---------- */
.site-header { position: sticky; top: 0; z-index: 50; background: rgba(23,19,13,0.78); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }
.header-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; height: 64px; }
.brand { font-weight: 800; letter-spacing: -0.035em; text-transform: uppercase; font-size: 1.4rem; line-height: 1; }

/* ---------- HERO ---------- */
/* hero warm layer (carried from an earlier mock): a second, softer glow top-right plus a warm fade down the top 60% */
.hero {
  position: relative; isolation: isolate;
  padding-block: clamp(2.5rem, 6vw, 5rem) clamp(3rem, 7vw, 5.5rem);
  background:
    radial-gradient(60% 70% at 88% 0%, color-mix(in srgb, var(--marigold) 14%, transparent), transparent 60%),  /* follows the accent token */
    linear-gradient(180deg, rgba(44,37,25,0.35), transparent 60%);
}
/* the lamp: one strong amber glow, high and centred-to-slightly-right, reaching up under the translucent header.
   The box is the hero itself, so the glow is fully out by the marquee at every breakpoint. */
.hero::before {
  content: "";
  position: absolute; left: 0; right: 0; top: -64px; bottom: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(80% 100% at 58% -12%,
    color-mix(in srgb, var(--marigold) 28%, transparent) 0%,   /* must follow the accent token */
    color-mix(in srgb, var(--marigold) 12%, transparent) 36%,
    transparent 100%);
}
.hero-grid { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: clamp(2rem, 6vw, 5rem); align-items: center; }
/* the handle is a tape label and a link to Instagram: ink text on the tan tape (contrast ~11:1). The label is as wide as
   its text, so the strip is a 3-slice border-image: the torn ends are sliced at their real extent in the 260px export
   (26px left, 72px right: the right tear is a long diagonal) and drawn at 0.64x, the scale that fits this 43px-tall line
   (17px and 46px caps), so only the plain middle of the tape stretches to the text. Solid tape starts 15px in on the
   left and 44px in on the right; the padding is that plus 10px so the text never sits on the tear. Hover and focus
   show as the same subtle scale the footer's tape (.credit) and the sound controls use: the strip grows 3% about its
   centre, keeping its rotation (a bare scale would drop it). No underline — an underline inside a torn strip of tape reads
   as a mistake, and the scale is the one affordance every taped/handwritten control now shares. Keyboard focus is NOT
   carried by the scale: the page's marigold :focus-visible ring draws around the box as well. */
.hero-handle { position: relative; display: inline-flex; align-items: center; gap: 0.35em; font-size: 1.3rem; color: var(--ink); border: 0; border-image: url("media/tape-tan-1.webp") 0 72 0 26 fill / 0 46px 0 17px stretch; padding: 0.05em 55px 0.05em 25px; transform: rotate(-2deg); margin-bottom: 1.4rem; white-space: nowrap; transition: transform .18s ease; }
.hero-handle .ig { width: 0.95em; height: 0.95em; flex: none; }
.hero-handle:hover, .hero-handle:focus-visible { transform: rotate(-2deg) scale(1.03); }
.hero h1 { font-size: clamp(2.6rem, 6.4vw, 5rem); }
.hero .sells { font-size: clamp(2rem, 4.2vw, 3.25rem); margin-top: 0.15em; }
.rotator-line { display: block; margin-top: 0.34em; }
/* stacked-measurement rotator: every word sits in the same grid cell,
   so line height never changes when the active word swaps */
.rotator { display: inline-grid; justify-items: start; align-items: start; vertical-align: top; }
.rotator .word {
  grid-area: 1 / 1;
  color: var(--ink); background: var(--marigold);
  padding: 0.05em 0.22em; border-radius: 0.06em; white-space: nowrap;
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
  opacity: 0; visibility: hidden; transform: translateY(0.22em);
  transition: opacity .34s ease, transform .34s ease;
}
.rotator .word.is-active { opacity: 1; visibility: visible; transform: none; }
.rotator .word.leaving { opacity: 0; visibility: visible; transform: translateY(-0.26em); }
.hero-sub { font-family: var(--serif); font-size: clamp(1.15rem, 1.7vw, 1.38rem); line-height: 1.5; color: var(--muted); max-width: 40ch; margin-top: 1.15rem; }
.hero-cta { display: flex; flex-wrap: wrap; gap: 0.9rem; margin-top: 2rem; align-items: center; }
.btn {
  display: inline-flex; align-items: center; gap: 0.5em; font-weight: 700; font-size: 1rem; line-height: 1;
  padding: 0.95em 1.4em; border-radius: 100px; border: 1px solid transparent; cursor: pointer; white-space: nowrap;
  transition: transform .18s ease, background .2s ease;
}
.btn-primary { background: var(--marigold); color: var(--ink); box-shadow: 0 10px 26px -12px color-mix(in srgb, var(--marigold) 70%, transparent); }
.btn-primary:hover { background: #FFE8B0; transform: translateY(-2px); }
.btn-ghost { background: transparent; color: var(--paper); border-color: var(--line-2); }
.btn-ghost:hover { border-color: var(--muted-2); background: var(--surface); }
.btn-sm { padding: 0.7em 1.1em; font-size: 0.9rem; }

.hero-visual { position: relative; width: 100%; max-width: 320px; margin-inline: auto; padding: 74px 10px 0; }
.hero-visual .vcard { transform: rotate(2.2deg); }
.hero-note { position: absolute; left: -6px; top: 0; display: flex; align-items: flex-start; gap: 2px; font-size: 1.4rem; line-height: 1.05; color: var(--paper); transform: rotate(-4deg); white-space: nowrap; }
.hero-note .arrow { transform: rotate(28deg); margin-top: -4px; }
.vcard-cap { margin-top: 10px; font-size: 1.25rem; line-height: 1; color: var(--ink); text-align: center; }
/* the caption as the sound control (a <button>): same handwriting in the same spot, sitting exactly where a .vcard-cap
   would (margin-top 10px), so the card's height and the caption's position do not move. Hover and focus grow it about its
   centre, the same affordance the two tapes use; the label itself flips ("sound on" / "mute") to say what a tap does next,
   and keyboard focus additionally draws an ink ring (see below).
   8% here, not the tapes' 3%: a scale is felt as how far an edge travels, and this control is a third of the tape's width,
   so the same percentage would move it a third as far and read as nothing happening. 8% on this 85px box travels 3.4px,
   against the hero tape's 3.9px and the footer tape's 3.1px at 3% — the same nudge, matched by eye rather than by number.
   The box hugs its label and ::before carries the 44px tap target (6px above, 18px below — asymmetric because the label
   sits 10px under the picture on both cards: an even 12/12 would push the top of the overlay 2px over the bottom of the
   video, so a click aimed at the picture would toggle the sound instead, while below the label there is the card's own
   16px of bottom padding to grow into — 6/18 clears the picture by 4px and runs 2px past the paper's edge, measured on
   the rendered page at 1440 and 390). That split is what keeps the focus ring honest: padding the box out to 44px instead
   pushed the ring 4px off the bottom of the polaroid (measured on the built page, both cards), where its lower bar drew
   on the dark background. Ring at offset 0 for the same reason — the page's 3px offset costs 12px of height this card
   does not have. The overlay is invisible, changes no layout, and nothing here hides overflow, so it is not clipped. */
.sound-toggle {
  appearance: none; background: none; border: 0; cursor: pointer; color: var(--ink);
  position: relative; display: block; margin: 10px auto 0; padding: 0 0.6em;
  outline-offset: 0;
  transition: transform .18s ease;
}
.sound-toggle::before { content: ""; position: absolute; inset: -6px 0 -18px; }
.sound-toggle:hover, .sound-toggle:focus-visible { transform: scale(1.08); }
/* the ring goes ink here, not the page's marigold: this is the one control that sits on the cream paper, and marigold on
   cream is a 1.04:1 difference — a hue change, not an outline, and under WCAG 1.4.11's 3:1 for a focus indicator. Ink on
   the same paper is 15.7:1 (sampled from the rendered page, both cards). Everything else about the ring is unchanged. */
.sound-toggle:focus-visible { outline-color: var(--ink); }

/* ---------- MARQUEE ---------- */
/* clip only sideways: the wave text scrolls past the edges, but glyphs at the wave peaks/troughs must never be cut vertically */
.marquee { padding-block: clamp(1rem, 3vw, 2rem) 0; overflow-x: clip; overflow-y: visible; }
/* viewBox is 250 units tall (50 units headroom above and below the old 150) — height scales 250/150 so the type stays the same size,
   and the negative margin gives the 20% headroom back so the surrounding layout doesn't move.
   96px floor: ~20px type, two phrases visible on a 390px phone; tablets 524-818px scale with 18.334vw; >=819px unchanged */
.marquee svg { --mq-h: clamp(96px, 18.334vw, 250px); width: 100%; height: var(--mq-h); margin-block: calc(var(--mq-h) * -0.2); overflow: visible; }
.marquee text { font-family: var(--serif); font-style: italic; font-size: 52px; fill: var(--paper); }

/* ---------- WORK PINBOARD ---------- */
.board-sec { padding-block: clamp(1rem, 3vw, 2rem) clamp(4rem, 8vw, 6rem); }
.board {
  position: relative;
  background:
    radial-gradient(90% 80% at 30% 0%, rgba(255,255,255,0.045), transparent 60%),
    linear-gradient(180deg, #221B12, #1A150E);
  border-radius: 6px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.05), inset 0 0 120px rgba(0,0,0,0.55), 0 30px 60px -30px rgba(0,0,0,0.9);
  padding: clamp(1.6rem, 4vw, 3.2rem);
  display: grid;
  grid-template-columns: 210px 1fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: start;
}
.board::before { content: ""; position: absolute; inset: 0; pointer-events: none; background: var(--grain); opacity: 0.2; mix-blend-mode: overlay; border-radius: 6px; }

/* legend rail — the four trinkets never move. Each is a category tab (a <button> with aria-pressed):
   lit = that category has at least one card; unlit (disabled) = nothing shipped yet. Computed at runtime in the script. */
.legend { position: relative; display: grid; gap: 1.4rem; padding-top: 1rem; }
.legend-head { font-size: 1.45rem; line-height: 1.05; color: var(--paper); transform: rotate(-2deg); margin-bottom: 0.2rem; }
.trinket {
  display: grid; grid-template-columns: 74px 1fr; gap: 0.9rem; align-items: center;
  /* button reset */
  appearance: none; background: none; border: 0; padding: 0; margin: 0; width: 100%; text-align: left;
  color: inherit; font: inherit; cursor: pointer; border-radius: 6px;
  transition: transform .18s ease, opacity .2s ease;
}
.trinket:not(:disabled):hover { transform: translateY(-2px); }
.trinket:disabled { opacity: 0.45; cursor: default; }
.trinket svg { --trinket-shadow: drop-shadow(0 1px 1px rgba(0,0,0,0.5)) drop-shadow(0 8px 9px rgba(0,0,0,0.55)); width: 74px; height: 74px; filter: var(--trinket-shadow); }
.trinket:disabled svg { filter: grayscale(1) var(--trinket-shadow); }
.trinket .lbl { font-family: var(--serif); font-style: italic; font-size: 1.05rem; color: var(--paper); line-height: 1.2; }
/* current tab: a soft-yellow highlighter swipe under the category word */
.trinket .cat { padding: 0 0.1em; }
.trinket[aria-pressed="true"] .cat { background: linear-gradient(transparent 58%, color-mix(in srgb, var(--marigold) 60%, transparent) 58%); }
/* a card outside the selected category is hidden (also beats .card.featured's display: grid) */
.card[hidden] { display: none !important; }
.trinket[data-cat="gardening"] svg { transform: rotate(-7deg); }
.trinket[data-cat="kitchen"] svg { transform: rotate(18deg); }
.trinket[data-cat="pets"] svg { transform: rotate(-4deg); }
.trinket[data-cat="home"] svg { transform: rotate(6deg); }

/* card grid — two columns; a featured card spans both so ONE card fills a complete row. Each category leads with its
   own featured card and only the selected tab's cards show, so (with JS on) one featured card is on screen at a time. Every later
   card in a tab takes one cell and appends below it. Nothing else moves. */
.cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(1.5rem, 3vw, 2.5rem); align-content: start; }
.card { position: relative; }
.card .vcard { max-width: 300px; margin-inline: auto; transform: rotate(-1.6deg); }
.card.featured { grid-column: 1 / -1; display: grid; grid-template-columns: 300px 1fr; gap: clamp(1.5rem, 3vw, 2.6rem); align-items: start; }
.card.featured .vcard { margin: 0; }
.card-side { position: relative; padding-top: 3.6rem; }
/* top padding clears the centred binder clip (jaw reaches ~31px into the paper), so the clip grips empty margin, not the brand line */
/* side padding 2.4rem: the deepest point of the sheet's right-hand tear is 43px into the 900px export, i.e. up to 22px
   on screen at the largest `cover` scale (the 795px-wide box at 960), so 38px keeps every line at least 16px on solid
   paper at 641-1440; the top and bottom tears are under 6px deep */
.card-side .scrap { --scrap-pad-x: 2.4rem; padding: 2.8rem var(--scrap-pad-x) 1.5rem; transform: rotate(1.2deg); }
.card-side .torn { margin-top: 0.4rem; }
/* -32px: the clip picture is 63px tall at this width and its green body starts 30px down, so the body's top edge lands
   2px above the paper's edge (the hinge wraps the edge) and the arms stand 32px proud of the sheet, inside .card-side's
   top padding */
.card-side .clip { top: -32px; left: 50%; transform: translateX(-50%) rotate(3deg); }
.brand-line { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--terracotta-text); }
.card h3 { font-family: var(--serif); font-size: 1.45rem; line-height: 1.15; margin-top: 0.4rem; letter-spacing: -0.01em; }
.card-side .scrap p { font-family: var(--mono); font-size: 0.86rem; line-height: 1.55; margin-top: 0.7rem; color: #3B3020; }
.card-side .scrap p.brand-line { margin-top: 0; }
/* the format/length line on a featured scrap (Pestie's "spec ad · 65s"): the template's format line (.card-cap p),
   sized and coloured the same, on the scrap's cream (#6B5B45 on it is 5.57:1) */
.card-side .scrap p.scrap-format { font-size: 0.74rem; line-height: 1.4; color: #6B5B45; margin-top: 0.9rem; }
.note { display: flex; align-items: center; gap: 8px; font-size: 1.5rem; line-height: 1; color: var(--paper); text-shadow: 0 1px 2px rgba(0,0,0,0.6); z-index: 3; white-space: nowrap; }
/* the handwritten arrow note beside a featured card's video ("no dead seconds", "real black widow") */
.note-lead { position: relative; margin: 1.5rem 0 0 0.5rem; transform: rotate(2deg); }
.note-lead .arrow { transform: scaleX(-1) rotate(-42deg); }
/* compact caption under non-featured cards */
.card-cap { margin-top: 0.9rem; text-align: center; color: var(--ink); }
/* restated rather than inherited from .brand-line, because `.card-cap p` below outranks a single class. The caption
   sits on the polaroid's cream, so it is the text terracotta — not marigold, which is 1.09:1 on this cream */
.card-cap .brand-line { color: var(--terracotta-text); }
.card-cap h3 { font-size: 1.15rem; margin-top: 0.15rem; }
.card-cap p { font-family: var(--mono); font-size: 0.74rem; color: #6B5B45; margin-top: 0.3rem; }


/* ---------- ABOUT ---------- */
.about { padding-block: clamp(2rem, 5vw, 3.5rem) clamp(4rem, 8vw, 6rem); }
.about .torn { max-width: 760px; margin-inline: auto; transform: rotate(-0.8deg); }
/* the sheet's right tear reaches 70/1240 of its width (5.6% of the card) and its bottom tear 48/1661 of its height, so the
   side and bottom padding follow the card: measured 320-1440, the text stays >= 14px inside the visible torn edge */
.about .kraft { padding: clamp(1.8rem, 4vw, 3rem) clamp(3.2rem, 5.5vw, 3.6rem) clamp(2.45rem, 4vw, 3rem); }
.about .tape.top { top: -16px; left: 14%; transform: rotate(-4deg); }
.about .tape.tr { top: -12px; right: 12%; transform: rotate(5deg); width: 90px; }
.about h2 { font-family: var(--mono); font-weight: 700; font-size: clamp(1.25rem, 2.6vw, 1.7rem); line-height: 1.25; letter-spacing: -0.01em; max-width: 26ch; }
.facts { list-style: none; padding: 0; margin: 1.6rem 0 0; display: grid; gap: 0.85rem; font-family: var(--mono); font-size: 0.95rem; line-height: 1.55; max-width: 62ch; }
.facts li { padding-left: 1.6rem; position: relative; }
.facts li::before { content: "x"; position: absolute; left: 0.2rem; top: 0; font-weight: 700; color: var(--terracotta); }
.about .line { font-family: var(--mono); font-size: 0.95rem; line-height: 1.55; max-width: 60ch; margin-top: 1.5rem; padding-top: 1.2rem; border-top: 1px dashed rgba(42,31,18,0.45); }
.sig { font-size: 1.9rem; line-height: 1; margin-top: 1.1rem; color: var(--kraft-ink); transform: rotate(-3deg); display: inline-block; }

/* ---------- AT HOME ---------- */
.at-home { padding-block: clamp(1rem, 3vw, 2rem) clamp(4rem, 8vw, 6rem); }
/* row gap is the phone case (the subline drops under the header, then wraps once more at 320-390): tight, so the three
   handwritten lines read as one stack */
.at-home-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem 1.5rem; flex-wrap: wrap; margin-bottom: clamp(1.6rem, 3vw, 2.4rem); }
/* header and subline are one handwritten pair: both Caveat at the same size (the header's pre-round-2 2.1rem, 1.9rem on
   phones), the header in the heavier weight and paper, the subline in the lighter weight and muted so it still reads as
   the second line. The subline's line-height leaves room for the two lines it becomes on phones. */
.at-home-head h2, .at-home-head p { font-size: 2.1rem; }
.at-home-head h2 { font-weight: 600; line-height: 1; color: var(--paper); transform: rotate(-2deg); display: inline-block; }
.at-home-head p { line-height: 1.15; color: var(--muted); }
.at-home-head a { color: var(--paper); border-bottom: 1px solid var(--marigold); white-space: nowrap; }
/* three to a row, and a fourth clip simply starts a second row of three. The row gap is much bigger than the column gap
   because a second row needs clearance for its own tape (which sticks up past the paper) and for the drop shadow of the
   print above it; side by side, prints only need to look taped near each other. */
.strip {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start;
  column-gap: clamp(1rem, 2vw, 1.6rem); row-gap: clamp(2.2rem, 3.4vw, 3rem);
}
/* a few pixels of drift so a tidy three-column grid still reads as taped up by hand. Every row drifts the same way,
   which is what a person doing it by eye actually does. (Block margins only: an auto INLINE margin on a grid item
   collapses the print to the width of its caption.) */
.print:nth-child(3n+2) { margin-top: 18px; }
.print:nth-child(3n) { margin-top: 6px; }
/* percentage padding, not the 8px that was drawn for a 160px-wide print: at 306px that 8px reads as a hairline and the
   polaroid stops looking like a polaroid. A percentage holds the same proportion at every width — an even margin on
   three sides, a deeper band under the picture with the handwritten caption sitting in it (see figcaption below). */
.print {
  position: relative; background: var(--paper); padding: 5% 5% 3%;
  box-shadow: 0 1px 2px rgba(0,0,0,0.45), 0 14px 24px -10px rgba(0,0,0,0.7);
}
/* the angles key to absolute child index, not to a 3n cycle, and that is the intent: the drift above repeats per row so
   a second row sits the same way on the board, while its rotations and tape angles come out differently from the first
   row's, which is what a wall of hand-taped prints actually looks like. (A -1.2deg rule for a fifth print was dropped
   with the 2x3 wall this row replaced: it was live but unreachable with three prints, and arbitrary with six.) */
.print:nth-child(odd) { transform: rotate(-2deg); }
.print:nth-child(even) { transform: rotate(1.6deg); }
.print:nth-child(3) { transform: rotate(2.6deg); }
/* the prints get the short piece (tape-tan-3), mirrored on the even prints and turned round on the third so a row
   doesn't read as one stamp repeated */
.print .tape.top { width: 62px; aspect-ratio: 120 / 66; top: -16px; background-image: url("media/tape-tan-3.webp"); }
.print:nth-child(even) .tape.top { transform: translateX(-50%) rotate(4deg) scaleX(-1); }
.print:nth-child(3) .tape.top { transform: translateX(-50%) rotate(-3deg) scale(-1); }
.print-slot { position: relative; aspect-ratio: 9 / 16; background: #D9CFBB; box-shadow: inset 0 0 0 1px rgba(0,0,0,0.12), inset 0 0 26px rgba(70,50,25,0.25); overflow: hidden; display: grid; place-items: center; }
.print-slot::before { content: ""; position: absolute; inset: 0; background: var(--grain); opacity: 0.35; mix-blend-mode: multiply; }
/* drop-in clip slot: add a src and the empty label hides itself. Never autoplays: hover (desktop) or tap (touch) plays it. */
.print-clip { display: none; position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 2; background: #0d0b07; }
.print-clip[src]:not([src=""]) { display: block; }
.print-slot:has(.print-clip[src]:not([src=""])) .print-empty { display: none; }
.print-slot:has(.print-clip[src]:not([src=""])) { cursor: pointer; }
/* an empty slot was a small blank square at 4:5 and 160px wide; at 9:16 and twice the size it is a hole in the page. So
   it is drawn the way a layout artist marks a picture box: two faint pencil diagonals corner to corner with the
   handwritten line sitting on the paper where they cross. It reads as reserved on purpose rather than broken. 0.7px at
   30% and not the 0.5px at 22% a small slot wanted — a pencil line that reads at 160px across vanishes at 306px. The
   cross sits under the clip (z-index 2) so a slot that gets filled covers it, and over the slot's grain. */
.print-slot:has(.print-empty)::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background-image:
    linear-gradient(to bottom right, transparent calc(50% - 0.7px), rgba(107,86,54,0.30) 50%, transparent calc(50% + 0.7px)),
    linear-gradient(to bottom left, transparent calc(50% - 0.7px), rgba(107,86,54,0.30) 50%, transparent calc(50% + 0.7px));
}
/* the label sits on its own patch of the slot's paper, which is what stops the two pencil lines running through the
   words. max-width keeps a long label wrapping to a second line instead of banding right across the slot. */
.print-empty {
  position: relative; z-index: 2; font-size: 1.2rem; line-height: 1.15; color: #6B5636; text-align: center;
  max-width: 74%; padding: 0.35em 0.6em; background: #D9CFBB; transform: rotate(-3deg);
}
/* tiny play glyph: touch / no-hover devices only, and only while a clip is loaded and not playing */
.print-play { display: none; position: absolute; right: 8px; bottom: 8px; z-index: 3; width: 26px; height: 26px; border-radius: 50%; background: rgba(23,19,13,0.6); border: 1px solid rgba(255,255,255,0.7); pointer-events: none; }
.print-play::after { content: ""; position: absolute; left: 9px; top: 6px; width: 0; height: 0; border-left: 9px solid #fff; border-top: 6px solid transparent; border-bottom: 6px solid transparent; }
@media (hover: none) {
  .print-slot:has(.print-clip[src]:not([src=""])):not(.is-playing) .print-play { display: block; }
}
/* the row's sound control, drawn on the clips it governs. It is the .print-play recipe — a dark disc with a hairline
   paper ring and a symbol inside it — scaled from 26px to 44px so a speaker reads at arm's length, and given the two
   shadows documented below, which are what keep its edge visible over a frame of video of any brightness.
   pointer-events: none, exactly like .print-play: the glyph is the sign and the whole print is the button. That is what
   keeps one control per print rather than a button nested inside one, it hands the visitor the whole picture as a target
   instead of a 44px disc, and — the reason the control sits here at all — it puts the press on the <video> element
   itself, which is what WebKit's per-element gesture memory wants. See the SOUND comment in index.html. */
.print-sound {
  position: absolute; right: 10px; bottom: 10px; z-index: 4;
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(23,19,13,0.72);
  border: 1.5px solid rgba(243,236,221,0.85);
  /* two shadows doing two jobs. The 1px hairline is an even dark ring immediately outside the paper one, so the disc's
     edge always has ONE high-contrast pair against the video whatever the frame is doing: on a dark frame the paper ring
     reads against the frame, on a blown-out near-white frame the hairline does. Measured on the rendered page, the worst
     step across that edge is 7.99:1 on a normal frame and 5.3:1 on a deliberately blown-out one, sampled on 36 rays
     round the circle (the paper ring on its own managed 1.81:1 and 1.01:1). The soft drop shadow underneath is what
     lifts the disc off the picture. The speaker symbol against its own disc is 12.7-13.3:1 on a normal frame and never
     below 8.16:1 on a blown-out one, against WCAG 1.4.11's 3:1 for a non-text control. */
  box-shadow: 0 0 0 1px rgba(0,0,0,0.5), 0 2px 8px rgba(0,0,0,0.55);
  color: var(--paper);
  pointer-events: none;
  opacity: 0; transform: scale(0.88);
  transition: opacity .16s ease, transform .16s ease;
}
.print-sound svg { width: 22px; height: 22px; display: block; }
.print-sound .spk-on { display: none; }
/* only a print that holds a clip has anything to unmute */
.print-slot:not(:has(.print-clip[src]:not([src=""]))) .print-sound { display: none; }
/* pointer devices: the glyph arrives with the hover that starts the clip, so the picture that plays and the control that
   turns its sound on appear in the same moment. Focus reveals it too, or a keyboard visitor could never see the control
   they are about to press. Those two states are also exactly when audio can be running here, so the control is on screen
   for the whole time there is anything to silence (WCAG 1.4.2). */
@media (hover: hover) {
  .print-slot:hover .print-sound,
  .print-slot:focus-visible .print-sound { opacity: 1; transform: scale(1); }
}
/* touch: a tap starts a clip that then plays with nothing held, so there is no hover to reveal the control at the moment
   it is needed — it stays on the print for as long as a clip can be playing, which is what 1.4.2 requires there. The
   play triangle moves to the opposite corner rather than stacking underneath it.
   It is also marigold-with-waves from the moment the page loads, not crossed out: main.js starts the row sound-on on a
   device with no hover, because the first tap there plays audible. The speaker is the only cue a sighted phone visitor
   gets, so it has to warn before the tap rather than describe the state after it. */
@media (hover: none) {
  .print-sound { opacity: 1; transform: none; }
  .print-play { right: auto; left: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .print-sound { transition: none; }
}
/* sound is on: the speaker turns marigold and shows its waves, so "on" reads the same colour it does everywhere else on
   the page. The class sits on every filled print, because the flag is the row's and not one clip's — and on a device
   with no hover it is there from load, since the row starts sound-on there (see the @media (hover: none) block above). */
.print-slot.is-sound-on .print-sound {
  color: var(--marigold);
  border-color: color-mix(in srgb, var(--marigold) 80%, transparent);
  background: rgba(23,19,13,0.78);
}
.print-slot.is-sound-on .print-sound .spk-off { display: none; }
.print-slot.is-sound-on .print-sound .spk-on { display: block; }
/* the print IS the sound control, so its focus ring has to be seen. The page's marigold ring goes ink here for the same
   reason the .sound-toggle on the video cards does: at the page's 3px offset the ring draws on the print's cream paper,
   and marigold on cream is 1.04:1 — a hue change, not an outline, and under WCAG 1.4.11's 3:1. Ink on that paper is
   15.7:1. Drawing outside the slot also means the ring never has to fight the video, at any brightness. */
.print-slot:focus-visible { outline-color: var(--ink); }
/* the caption sits inside the deep bottom band of the paper border, so its margin is a percentage too — otherwise the
   band grows with the print while the writing stays pinned to the picture's edge */
.print figcaption { margin-top: 3.5%; font-size: 1.3rem; line-height: 1; color: var(--ink); text-align: center; }

/* ---------- CONTACT ---------- */
.contact { padding-block: 0 clamp(4rem, 8vw, 6rem); }
.contact-card {
  background: linear-gradient(160deg, #2A2318 0%, #1A140C 60%, #14100A 100%);
  border: 1px solid var(--line-2);
  border-radius: clamp(20px, 3vw, 30px);
  padding: clamp(2.5rem, 6vw, 4.5rem);
  text-align: center; position: relative; overflow: hidden;
}
.contact-card::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(60% 80% at 84% 6%, color-mix(in srgb, var(--marigold) 22%, transparent), transparent 58%),
    radial-gradient(50% 70% at 8% 104%, color-mix(in srgb, var(--cool) 14%, transparent), transparent 60%);  /* follows --cool */
}
.contact-card > * { position: relative; }
.contact-card .kicker { font-size: 1.6rem; line-height: 1; color: var(--marigold); display: inline-block; transform: rotate(-3deg); margin-bottom: 0.8rem; }
.contact-card h2 { font-size: clamp(2rem, 4.6vw, 3.4rem); line-height: 1.02; letter-spacing: -0.035em; text-transform: uppercase; max-width: 20ch; margin-inline: auto; }
.contact-cta { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.8rem; margin-top: 2.2rem; }
.contact-mail { display: flex; width: fit-content; align-items: center; margin: 1.6rem auto 0; font-family: var(--mono); font-size: 0.92rem; color: var(--paper); border-bottom: 1px solid var(--line-2); padding-bottom: 3px; }
.contact-mail:hover { color: var(--marigold); border-color: var(--marigold); }
.contact-fine { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.06em; color: var(--muted-2); margin: 1.4rem auto 0; display: flex; width: fit-content; align-items: center; gap: 0.5em; }
.contact-fine .d { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); }

footer { border-top: 1px solid var(--line); padding-block: 2rem; }
.footer-row { display: flex; align-items: center; justify-content: space-between; gap: 1.2rem; flex-wrap: wrap; font-size: 0.9rem; color: var(--muted); }
.footer-row a:hover { color: var(--marigold); }
.footer-links { display: flex; gap: 1.3rem; flex-wrap: wrap; }
/* designer credit: a tape label, real text, sits opposite the © line. Same 3-slice construction as .hero-handle, on
   tape-tan-2 so the two labels are different pieces: its torn ends are 46px (left) and 17px (right) of the 260px export,
   drawn at 0.53x for this 41.5px-tall line (25px and 9px caps). Solid tape starts 23px in on the left and 7px on the
   right; padding is that plus 10px. Ink text, contrast ~11:1. */
.credit {
  display: inline-flex; align-items: baseline; gap: 0.4em; white-space: nowrap;
  color: var(--ink); border: 0; border-image: url("media/tape-tan-2.webp") 0 17 0 46 fill / 0 9px 0 25px stretch;
  padding: 0.3em 18px 0.35em 33px; transform: rotate(-2deg);
  transition: transform .18s ease;
}
.credit .hand { font-size: 1.3rem; line-height: 1; }
.credit-name { font-family: var(--serif); font-style: italic; font-weight: 600; font-size: 1.02rem; letter-spacing: 0.01em; }
/* same treatment as the hero tape: 3% about the centre, rotation kept, no underline. The .footer-row prefix is what keeps
   the ink colour from the generic `.footer-row a:hover` marigold; :focus-visible is listed so the keyboard state matches
   the pointer one (the ring is what actually announces focus). */
.footer-row .credit:hover, .footer-row .credit:focus-visible { color: var(--ink); transform: rotate(-2deg) scale(1.03); }

/* ---------- responsive ---------- */
@media (max-width: 960px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-visual { margin-top: 2.5rem; max-width: 300px; }
  .board { grid-template-columns: 1fr; }
  .legend { grid-template-columns: repeat(2, 1fr); gap: 1rem 1.5rem; padding-top: 1.6rem; }
  .legend-head { grid-column: 1 / -1; }
  .card.featured { grid-template-columns: 1fr; }
  .card.featured .vcard { margin-inline: auto; }
  /* tablet keeps the three-across row; only the tape and the handwriting come down a size with the prints. Two across
     was tried here first and rendered worse: with three clips it strands the odd one alone on a second row beside an
     empty half-row of board, and because the odd one is a placeholder that second row is entirely dead space. Three
     across holds the single row the section is built around, and even at the bottom of this range (641px) a print is
     about 184px wide — a whole 9:16 clip, taller than the 4:5 prints this replaced were at any width. */
  .print .tape.top { width: 52px; top: -14px; }
  .print figcaption { font-size: 1.15rem; }
  .print-empty { font-size: 1.05rem; }
  /* the print is the sound control's target, not the disc, so the disc can follow the print's size the way the tape and
     the handwriting do: a 44px disc on a ~182px-wide print is a quarter of the picture. */
  .print-sound { width: 34px; height: 34px; right: 8px; bottom: 8px; }
  .print-sound svg { width: 17px; height: 17px; }
}
@media (max-width: 640px) {
  body { font-size: 16px; }
  /* header stays one line down to 320px: the name shrinks with the viewport, the button keeps a 44px tap height */
  .brand { font-size: clamp(1.05rem, 5.5vw, 1.4rem); }
  .btn-sm { padding-block: 1em; }
  .hero h1 { font-size: 2.6rem; }
  /* widest rotator word ("raised garden bed") must fit inside the copy column at 320px */
  .hero .sells { font-size: clamp(1.5rem, 7.5vw, 1.85rem); }
  .hero-visual { max-width: 260px; padding-top: 64px; }
  .hero-note { font-size: 1.2rem; left: -10px; }
  .cards { grid-template-columns: 1fr; }
  /* legend keeps the 960 rule's two columns; smaller trinkets so the four categories read as two short rows */
  .legend { gap: 0.9rem 0.75rem; }
  .trinket { grid-template-columns: 48px 1fr; gap: 0.5rem; }
  .trinket svg { width: 48px; height: 48px; }
  .trinket .lbl { font-size: 0.9rem; }
  .note { font-size: 1.3rem; }
  /* bio card: side padding = the 5.6% right tear + 14px, bottom = the ~3% bottom tear + 14px (see .about .kraft) */
  .about .kraft { padding-inline: calc(5.7vw + 16px); padding-bottom: clamp(2.35rem, 3vw + 14px, 3rem); }
  /* featured card stacks: the arrow note ("no dead seconds", "real black widow") moves up under the video (its arrow points up at the
     video, not at the description below it) and the desktop alignment padding goes. The note is centred under the video and
     the arrow (no mirror here, unlike desktop) points up-right at ~47deg: from where its head sits, that line meets
     the video's bottom edge at its centre, at 320px through 640px. */
  .card-side { padding-top: 1rem; display: flex; flex-direction: column; }
  .note-lead { order: -1; align-self: center; margin: 0 0 1.2rem; }
  .note-lead .arrow { transform: rotate(-90deg); }
  /* phones drop the cream paper on each featured card's description: stacked, the scrap sat directly above the kraft about-card,
     two paper textures back to back. So here it is plain light text on the board (same colours the board's legend and
     the hero body copy use; brand line in the page's yellow, which reads on the dark board) and the kraft bio directly below
     is the only paper block on screen. The binder clip goes with the paper, and with it the top margin that cleared it. */
  .card-side .torn { margin-top: 0; filter: none; }
  .card-side .clip { display: none; }
  .card-side .scrap { transform: none; padding: 0.4rem 0 0; color: var(--paper); }
  .card-side .scrap::before, .card-side .scrap::after { content: none; }
  /* the format line keeps --muted here with the rest: --muted-2, the obvious step down, is 4.15:1 on the board and fails AA */
  .card-side .scrap p, .card-side .scrap p.scrap-format { color: var(--muted); }
  .card-side .scrap p.brand-line { color: var(--marigold); }
  /* at-home strip: one print per row, full width, scrolled down through — no sideways row. A 9:16 clip at the full
     column width is the size the phone was always going to show it best at, and the horizontal scroll-snap carousel
     this replaces (which bled to the window edges with negative margins and restored the page padding inside itself)
     is gone entirely, scroll rules and all: the strip is a plain one-column grid again, so nothing here can leak into
     the page's horizontal scroll. The drift goes too — a few px of offset says "taped up by hand" in a row and says
     nothing at all in a single column. */
  .strip { grid-template-columns: minmax(0, 1fr); row-gap: 2.4rem; }
  .print, .print:nth-child(3n+2), .print:nth-child(3n) { margin-top: 0; }
  /* one print now owns the full column width, so the tape and the handwriting go up rather than down */
  .print .tape.top { width: 72px; top: -18px; }
  .print figcaption { font-size: 1.35rem; }
  .print-empty { font-size: 1.25rem; }
  /* a print owns the full column here, so the disc goes back to full size — and on a phone it is the permanently
     visible sound control rather than a hover reveal, so it is the one that most needs to read */
  .print-sound { width: 44px; height: 44px; right: 10px; bottom: 10px; }
  .print-sound svg { width: 22px; height: 22px; }
  .at-home-head h2, .at-home-head p { font-size: 1.9rem; }
  /* tap targets / legibility: email link and footer links reach 44px tall (Apple HIG), fine print reaches 12px */
  .contact-mail { margin-top: 0.6rem; padding-top: 1.1rem; }
  .contact-fine { font-size: 0.75rem; }
  .footer-links a { padding-block: 0.7rem; }
  .footer-row { flex-direction: column; align-items: flex-start; }
  .credit { margin-top: 0.6rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; animation: none !important; }
}
