/* Lowerville.net
   Rules: square corners only. No glow, no blur, no gradient washes.
   Black, white, two greys. Red/cyan only as a hard misregistration during glitch moments. */

:root {
  --tape: #000000;      /* screens, tape plastic, ink */
  --paper: #FFFFFF;     /* page, J-cards, sheets */
  --toner: #A0A0A0;     /* secondary text on black only (8.0:1) */
  --dub: #5A5A5A;       /* secondary text on white only (6.9:1), thin lines */
  --misreg-r: #FF0000;  /* glitch moments only */
  --misreg-c: #00FFFF;  /* glitch moments only */
  --black: #000000;     /* fixed, never swapped */
  --white: #FFFFFF;     /* fixed, never swapped */
  --plastic: #5A5A5A;   /* TV cabinet, fixed */
  --grille: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='6' height='6'%3E%3Crect y='0' width='6' height='3'/%3E%3C/svg%3E");

  /* Display = Arial Black (owner pick, 2026-09-23) at -40 tracking. Computers use the installed Arial Black;
     phones get Archivo Black (free Google Font, near twin). To self-host a LICENSED Arial Black web file,
     add an @font-face named "Arial Black" pointing at assets/fonts/. */
  --display: "Arial Black", "Archivo Black", "Helvetica Neue", sans-serif;
  --display-track: -0.04em;
  --mono: "Chivo Mono", ui-monospace, "Courier New", monospace;

  --gutter: clamp(16px, 2.8vw, 40px);
  --bar: 52px;
  --dither: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2' height='2'%3E%3Crect width='1' height='1'/%3E%3Crect x='1' y='1' width='1' height='1'/%3E%3C/svg%3E");
  --scan: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4'%3E%3Crect y='3' width='4' height='1'/%3E%3C/svg%3E");

  /* Motion timing, taken from the tape: one frame (the tear is 4F) and one mechanical hit (the drawer is 4H).
     Every duration is a whole number of them. --snow is a 48x24 tile of 1-bit tape snow. */
  --f: 60ms;
  --hit: 40ms;
  --snow: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAYAQAAAACUhkNxAAAAs0lEQVR42gGoAFf/AEZQFASTBgII9DAPDp4CTvG8YWnZA/JnMZL3QQJIrKpYBiQBKPho+KjaAloVOQnkEAEDBgeUre8DYgw3NiASA9MkzdQaSgHa6hzqOv4ABIopVOOgACABAQBzAgARI2DDIYAAVtEBQIRAA8OmweP+MAECPEyWCvwCHkQmpNoFA/jwHoJv5wAzA2BSAhAAxABFAspOANw0TgIq4gBAEQAgJAACAIOA/BwMMJM4Kp+Zz70AAAAASUVORK5CYII=");
}

*, *::before, *::after { box-sizing: border-box; border-radius: 0 !important; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: var(--bar); color-scheme: dark; background: var(--black); scrollbar-gutter: stable; }
/* a tape-plastic thumb on a black track; the OS keeps the size and overlay behaviour. Inherited, so the sheet and
   the cart get it too (.tv-list keeps its own) */
html { scrollbar-color: var(--plastic) var(--black); }

/* Dark site (owner call, 2026-09-23): content sections and dialogs swap ink and paper,
   so every rule written as "ink on paper" renders white on pure black. Greys follow:
   secondary text becomes #A0A0A0 (8.0:1 on black). */
.section, dialog {
  --tape: #FFFFFF; --paper: #000000; --dub: #A0A0A0; --toner: #A0A0A0;
  background: var(--paper); color: var(--tape);
}

body {
  margin: 0;
  background: var(--black);
  color: var(--white);
  font: 400 clamp(15px, 0.2vw + 14.3px, 17px)/1.55 var(--mono);
  text-rendering: optimizeLegibility;
  overflow-anchor: inherit; /* Chrome reads the page's scroll anchoring off body too: it follows html (index.html holds it off while the shop fills) */
}

/* Selected text: a white block with black type, like a highlighted OSD line, never the system blue. On the white
   surfaces it is a tape-plastic block with white type (6.9:1), which still shows hovered, disabled or outlined,
   and so do the controls that flip to white on hover (buttons, the demo bar, the OSD chip). */
::selection { background: var(--white); color: var(--black); }
:is(.btn, .cta, .badge, .tape-label, .preview-bar, mark.todo, .issue-btn[aria-pressed="true"], .j-spine, .drawer-top, .size-opts input:checked + label, .shot .sold, .demo-bar, .osd-act)::selection,
:is(.btn, .cta, .badge, .tape-label, .preview-bar, mark.todo, .issue-btn[aria-pressed="true"], .j-spine, .drawer-top, .size-opts input:checked + label, .shot .sold, .demo-bar, .osd-act) ::selection { background: var(--plastic); color: var(--white); }

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-underline-offset: 3px; text-decoration-thickness: 2px; }
p { margin: 0 0 1em; max-width: 60ch; text-wrap: pretty; } /* no one-word last lines, whatever the client types */
ul { margin: 0; padding: 0; list-style: none; }
figure { margin: 0; }

button, input {
  font: inherit; color: inherit; margin: 0;
  -webkit-appearance: none; appearance: none;
  background: none; border: 0; padding: 0;
}
button { cursor: pointer; }

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 400;
  font-synthesis: none;
  letter-spacing: var(--display-track);
  line-height: 0.95;
  margin: 0;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
/* app.js hides whole blocks (empty sections, unused rows) with the hidden attribute; it always wins. */
[hidden] { display: none !important; }
.defs { position: absolute; }

/* Registered mark: small, top-aligned to the caps, never tracked */
.reg { display: inline-block; vertical-align: top; font-size: 0.3em; line-height: 1; letter-spacing: 0; margin: 0.14em 0 0 0.1em; }
.mark .reg { font-size: 0.42em; margin-top: 0.08em; }

/* Focus: a hard square ring, contrasting with whatever it sits on. */
:focus-visible { outline: 3px solid var(--tape); outline-offset: 3px; }
.bar :focus-visible, .hero :focus-visible, .foot :focus-visible {
  outline-color: var(--paper);
}
.hero :focus-visible { box-shadow: 0 0 0 3px var(--tape); } /* 0 blur: black gap then white ring, reads on any frame */

/* Presses: no system tap flash (a blue box). Buttons go down 2px like a deck key and text links drop to grey
   while held. They are states, not motion, so reduced motion keeps them. */
a, button, label, [role="tab"] { -webkit-tap-highlight-color: transparent; }
.btn:active:not(:disabled), .cta:active, .issue-btn:active, .qty button:active, .tape-label:active, .size-opts label:not(.out):active { translate: 0 2px; } /* composes with .tape-label's rotate */
a:not(.btn):not(.cta):not(.demo):not(.tape-label):active, .link:active, .close:active, .track:active, .shop-look:active { color: var(--toner); }
.drawer-top .close:active { color: var(--plastic); } /* the cart's white top bar */

.skip {
  position: absolute; left: 8px; top: -80px; z-index: 50;
  background: var(--tape); color: var(--paper); padding: 10px 14px; font-weight: 700;
}
.skip:focus { top: 8px; outline-color: var(--paper); }

.small { font-size: 13px; color: var(--dub); }

/* ---------- Intro: banner + loading meter, then the curtain tears open ---------- */
.intro { display: none; }
.intro-on .intro {
  display: block; position: fixed; inset: 0; z-index: 100; cursor: pointer;
  animation: intro-failsafe 0s linear 8s forwards; /* never cover the page if JS dies; index.html's 8s timer also frees the scroll */
}
@keyframes intro-failsafe { to { visibility: hidden; } }
.intro-on body { overflow: hidden; }
.intro-half { position: absolute; left: 0; right: 0; height: 50%; overflow: hidden; background: var(--black); color: var(--white); }
.intro-top { top: 0; border-bottom: 0; }
.intro-bot { bottom: 0; }
.intro-core {
  position: absolute; left: 0; right: 0; height: 200%;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  padding: 0 16px; text-align: center;
}
.intro-top .intro-core { top: 0; }
.intro-bot .intro-core { bottom: 0; }
.intro-smiley { width: clamp(64px, 7vw, 96px); height: auto; }
.intro-mark {
  position: relative; isolation: isolate; margin: 0; max-width: none;
  font-family: var(--display); letter-spacing: var(--display-track); font-size: clamp(36px, 9.6vw, 156px); line-height: 0.9;
  text-transform: uppercase; /* brand is always LOWERVILLE */
}
.intro-mark::before, .intro-mark::after { content: attr(data-text); position: absolute; left: 0; top: 0; z-index: -1; display: none; }
.intro.glitch .intro-mark::before { display: block; color: var(--misreg-r); transform: translateX(-7px); }
.intro.glitch .intro-mark::after { display: block; color: var(--misreg-c); transform: translateX(7px); }
.intro-load {
  display: flex; align-items: center; gap: 12px; margin: 10px 0 0; max-width: none;
  font-weight: 700; font-size: 14px; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.intro-load .g { width: 12px; height: 12px; fill: var(--white); }
.intro-segs { display: flex; gap: 3px; }
.intro-segs i { display: block; width: 8px; height: 14px; border: 2px solid var(--white); }
.intro-segs i.on { background: var(--white); }
.intro-tag { margin: 0; font-size: 13px; color: var(--toner); }
.intro.open .intro-top { animation: intro-lift 620ms steps(8, end) forwards; }
.intro.open .intro-bot { animation: intro-drop 620ms steps(8, end) forwards; }
@keyframes intro-lift { to { transform: translateY(-100%); } }
@keyframes intro-drop { to { transform: translateY(100%); } }
@media (max-width: 479px) { .intro-segs i { width: 6px; } .intro-load { font-size: 12px; gap: 8px; } }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 52px; padding: 12px 22px;
  background: var(--tape); color: var(--paper);
  border: 2px solid var(--tape);
  font-weight: 700; line-height: 1.1; text-decoration: none; text-align: center;
}
.btn-line { background: var(--paper); color: var(--tape); }
.btn-inv { background: var(--paper); color: var(--tape); border-color: var(--paper); }
.btn-wide { width: 100%; }
@media (hover: hover) and (pointer: fine) {
  .btn:hover { background: var(--paper); color: var(--tape); }
  .btn-line:hover { background: var(--tape); color: var(--paper); }
  .btn-inv:hover { background: var(--tape); color: var(--paper); }
}
.btn:disabled, .btn:disabled:hover { background: var(--paper); color: var(--dub); border-color: var(--dub); cursor: not-allowed; }

/* ---------- Admin preview bar (?preview=1) ---------- */
.preview-bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 2px 16px;
  padding: 7px var(--gutter); background: var(--white); color: var(--black);
  font-size: 13px; font-weight: 700; line-height: 1.35;
}
.preview-bar a { color: inherit; }
/* Reload, when the store can't be reached and the built-in catalog is showing */
.preview-bar button { color: inherit; background: none; border: 0; padding: 0; font: inherit; text-decoration: underline; cursor: pointer; min-height: 44px; }
.preview-bar :focus-visible { outline-color: var(--black); }

/* ---------- Header ---------- */
.bar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; gap: 32px;
  height: var(--bar); padding: 0 var(--gutter);
  background: var(--tape); color: var(--paper);
}
/* the registered mark never wraps away from the name (header, footer, legal pages) */
.mark { font-family: var(--display); letter-spacing: var(--display-track); font-size: 21px; line-height: 1; text-decoration: none; white-space: nowrap; flex: none; }
.bar nav ul { display: flex; gap: 28px; }
.bar nav a { font-size: 14px; text-decoration: none; white-space: nowrap; }
.nav-short { display: none; } /* "Music" for "Submit music" on the narrowest phones */
.bar nav a:hover { text-decoration: underline; }
/* the deck's tape counter after the nav, 960px and wider only (app.js initDeck). It steps, never tweens, in its own
   square window so it never reads as a nav item: PLAY at rest, FF / REW while goTo runs. Hidden (no layout change)
   above half the hero. */
.deck { display: none; }
@media (min-width: 960px) {
  .deck {
    display: inline-flex; align-items: center; gap: 6px; min-width: calc(3ch + 16px);
    font: 700 13px/1 var(--mono); color: var(--toner); font-variant-numeric: tabular-nums; letter-spacing: 0.06em;
    contain: layout paint;
    margin-left: 12px; padding: 4px 7px 3px; border: 1px solid var(--plastic);
  }
}
.deck[data-off] { visibility: hidden; }
.deck .g { width: 10px; height: 10px; fill: currentColor; }
.cart-btn {
  margin-left: auto; display: flex; align-items: center; gap: 10px;
  min-height: 44px; font-size: 14px; font-weight: 700;
}
/* Sign in / Account, left of Cart (app.js initAccount). Signed in it reads "Account" with the Discord picture,
   20px, square and black and white like the rest of browsing. */
.acct {
  margin-left: auto; display: flex; align-items: center; gap: 8px; flex: none;
  min-height: 44px; font-size: 14px; font-weight: 700; text-decoration: none; white-space: nowrap;
}
.acct + .cart-btn { margin-left: 0; }
.acct-av-s { width: 20px; height: 20px; flex: none; filter: grayscale(1) contrast(1.08); background: var(--plastic); }
@media (hover: hover) and (pointer: fine) { .acct:hover { text-decoration: underline; } }
.badge {
  position: relative; display: inline-grid; place-items: center;
  min-width: 26px; height: 26px; padding: 0 6px;
  background: var(--paper); color: var(--tape); font-weight: 700;
  isolation: isolate;
}
/* add-to-cart hit: two frames of hard channel offset, red and cyan copies of the number (like the wordmark) */
.badge.hit::before, .badge.hit::after {
  content: attr(data-count); position: absolute; inset: 0; z-index: -1;
  display: grid; place-items: center;
}
.badge.hit::before { color: var(--misreg-r); transform: translate(-3px, 0); }
.badge.hit::after { color: var(--misreg-c); transform: translate(3px, 0); }
/* and before it, the counter wheel: the old number (.badge-o) rolls up and out as the new one rolls in */
.badge-n { display: block; }
.badge-o { position: absolute; inset: 0; display: grid; place-items: center; background: var(--paper); }
@media (prefers-reduced-motion: no-preference) {
  .badge.roll { clip-path: inset(0 -6px); }
  .badge.roll .badge-n { animation: ctr-in calc(var(--hit) * 3) steps(3, end); }
  .badge.roll .badge-o { animation: ctr-out calc(var(--hit) * 3) steps(3, end) forwards; }
}
@keyframes ctr-in { from { transform: translateY(100%); } }
@keyframes ctr-out { to { transform: translateY(-100%); } }

/* ---------- 1. Hero ---------- */
.hero {
  position: relative; overflow: hidden;
  /* always the first screen, so a phone in landscape still opens on the wordmark and Shop the drop;
     the floor only keeps the title clear of PLAY in very short windows */
  height: calc(100svh - var(--bar)); min-height: 240px;
  background: var(--tape); color: var(--paper);
}
.screen { position: absolute; inset: 0; }
.footage {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 64% 50%;
  image-rendering: pixelated;
}
.scan { position: absolute; inset: 0; background-image: var(--scan); background-size: 4px 4px; pointer-events: none; }

.osd {
  position: absolute; inset: 0; pointer-events: none;
  font-family: var(--mono); font-weight: 700;
  font-size: clamp(16px, 1vw + 12px, 26px); line-height: 1.25;
  --safe: max(16px, 5%);
}
.osd-t {
  color: var(--paper);
  -webkit-text-stroke: 0.2em var(--tape);
  paint-order: stroke fill;
}
.osd .g { width: 0.8em; height: 0.8em; fill: var(--paper); stroke: var(--tape); stroke-width: 1.6px; paint-order: stroke; overflow: visible; }
.osd-transport {
  position: absolute; left: var(--safe); top: var(--safe);
  display: flex; align-items: center; gap: 0.45em;
  min-height: 44px; pointer-events: auto;
}
/* the readout (PLAY / PAUSE) is the tape's state; this chip is what a press does. Square, white on black with a
   white edge so it reads over any frame. Hover or keyboard focus inverts it, like a camcorder menu highlight. */
.osd-act {
  margin-left: 0.5em; padding: 0.2em 0.6em;
  font-size: max(12px, 0.55em); font-weight: 400; line-height: 1;
  border: 1px solid var(--paper); background: var(--tape); color: var(--paper); -webkit-text-stroke: 0;
}
/* fixed fields, like a camcorder OSD: the readout (PLAY / PAUSE / FF / REW) and the chip (Play / Pause) never move under the pointer */
.osd-transport [data-transport-label] { min-width: 5ch; }
.osd-act { min-width: calc(5ch + 1.2em + 2px); text-align: center; }
@media (hover: hover) and (pointer: fine) { .osd-transport:hover .osd-act { background: var(--paper); color: var(--tape); } }
.osd-transport:focus-visible .osd-act { background: var(--paper); color: var(--tape); }
.osd-counter {
  position: absolute; right: var(--safe); top: var(--safe);
  display: flex; flex-direction: column; align-items: flex-end;
  font-variant-numeric: tabular-nums;
}
.osd-date {
  position: absolute; right: var(--safe); bottom: var(--safe);
  display: flex; flex-direction: column; align-items: flex-end;
}
.osd-tracking {
  position: absolute; left: 50%; bottom: 20%; transform: translateX(-50%);
  display: none; align-items: center; gap: 0.6em; white-space: nowrap;
}
.segs { display: flex; gap: 4px; }
.segs i { display: block; width: 10px; height: 14px; border: 2px solid var(--paper); outline: 2px solid var(--tape); }
.segs i.on { background: var(--paper); }

.title {
  position: absolute; left: max(16px, 8%); bottom: max(16px, 9%); right: max(16px, 8%);
  display: flex; flex-direction: column; align-items: flex-start; gap: 20px;
}
.wordmark {
  position: relative; isolation: isolate;
  font-size: clamp(38px, 7.4vw, 120px); line-height: 0.9;
  text-transform: uppercase;
  color: var(--paper);
  -webkit-text-stroke: 0.035em var(--tape);
  paint-order: stroke fill;
}
.wordmark::before, .wordmark::after {
  content: attr(data-text); position: absolute; left: 0; top: 0; z-index: -1; display: none;
}
.wordmark.glitch::before { display: block; color: var(--misreg-r); transform: translateX(-5px); }
.wordmark.glitch::after { display: block; color: var(--misreg-c); transform: translateX(5px); }

.tagline { margin: -6px 0 4px; font-family: var(--mono); font-weight: 700; font-size: clamp(15px, 0.8vw + 11px, 22px); line-height: 1.2; }
.cta {
  position: relative; /* above the wordmark's glyph box, which reaches 8px into the button at 1440 and took those clicks */
  display: inline-flex; align-items: center; gap: 10px; min-height: 52px; padding: 12px 22px;
  font-weight: 700; text-decoration: none; pointer-events: auto;
  /* the hero's buttons all follow the theme (owner call 2026-09-30): black tape with white type and a white
     edge in dark mode, readable on any frame of the footage; the Light mode block turns them white */
  background: var(--tape); color: var(--paper); border: 2px solid var(--paper);
}
@media (hover: hover) and (pointer: fine) {
  .cta:hover { background: var(--paper); color: var(--tape); border-color: var(--tape); }
}
.cta-row { display: flex; flex-wrap: wrap; gap: 12px; }
.dc-logo { width: 20px; height: 20px; flex: none; }
@media (max-width: 719px) {
  .cta-row { gap: 10px; }
  .cta-row .cta { min-height: 44px; padding: 8px 14px; font-size: 14px; }
}

/* load states (JS only; without JS everything shows) */
.js .hero[data-state="snow"] .osd > *,
.js .hero[data-state="snow"] .title > *,
.js .hero[data-state="roll"] .osd-date,
.js .hero[data-state="roll"] .title > *,
.js .hero[data-state="settle"] .title > *,
.js .hero[data-state="title"] .cta,
.js .hero[data-state="title"] .tagline { visibility: hidden; }
.hero[data-state="roll"] .osd-tracking { display: flex; }

/* ---------- Sections ---------- */
.section { padding: clamp(72px, 9vw, 136px) var(--gutter); }
/* one thin rule at every section boundary below the drop, like the footer's (--plastic stays #5A5A5A in here) */
.section + .section { border-top: 1px solid var(--plastic); }
.h2 { font-size: clamp(30px, 2.2vw + 20px, 56px); }

/* ---------- 2. Latest drop collage ---------- */
.collage {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: 24px; row-gap: clamp(56px, 7vw, 112px); align-items: start;
}
.items { display: contents; }
.drop-head { grid-column: 8 / 13; grid-row: 1; position: relative; }
.drop-head p { margin-top: 18px; }
/* the title card's block cursor (app.js typeOn sets its size and clips it down to one block as it moves).
   It sits on the head, so the heading's clip never cuts it. */
.drop-head .h2 { width: fit-content; }
.drop-head.mo-type::after {
  content: ""; position: absolute; left: 0; top: var(--cur-t); width: var(--cur-w); height: var(--cur-h);
  background: currentColor; pointer-events: none;
}

.slot-1 { grid-column: 1 / 7;  grid-row: 1; }
.slot-2 { grid-column: 8 / 12; grid-row: 1; margin-top: clamp(170px, 15vw, 230px); }
.slot-3 { grid-column: 2 / 5;  grid-row: 2; margin-top: clamp(60px, 6vw, 100px); }
.slot-4 { grid-column: 6 / 9;  grid-row: 2; }
.slot-5 { grid-column: 10 / 13; grid-row: 2; margin-top: clamp(120px, 12vw, 180px); }
.slot-6 { grid-column: 1 / 5;  grid-row: 3; margin-top: clamp(80px, 9vw, 140px); }
.slot-7 { grid-column: 6 / 13; grid-row: 3; margin-right: calc(-1 * var(--gutter)); }
/* the first tile 2 shares its cell with the heading: it starts below however tall the title and blurb run
   (--head-h is measured by app.js; phones stack, so the rule there wins) */
.items > li:nth-child(2) { margin-top: max(clamp(170px, 15vw, 230px), calc(var(--head-h, 0px) + 32px)); }

.item-btn { display: block; width: 100%; text-align: left; text-decoration: none; }
.shot { position: relative; display: block; overflow: hidden; background: var(--paper); }
.shot img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.shot .b { visibility: hidden; }
@media (hover: hover) and (pointer: fine) {
  .item-btn:hover .shot .b { visibility: visible; }
  .item-btn:hover .meta .name { text-decoration: underline; } /* every tile, one photo or two */
}
.item-btn:focus-visible .shot .b { visibility: visible; }
/* The cut: on a tile with a second photo, hover (mouse) or keyboard focus runs a band of tape snow down it in 3
   held positions, and the photo swaps under it at 80ms, the hero's own tape-edit cut. Leaving is instant.
   The band exists while the tile is hovered or focused; between runs it is parked 2px above the tile so its
   fractional height never rasterises into the photo's top row. */
.shot::after {
  position: absolute; left: 0; right: 0; top: 0; height: 14%; z-index: 2; pointer-events: none;
  background: var(--black) var(--snow); background-size: 96px 48px; image-rendering: pixelated;
  transform: translateY(calc(-100% - 2px));
}
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .item-btn:hover .shot:has(.b)::after { content: ""; animation: cut calc(var(--hit) * 4) steps(4, end); }
  .item-btn:hover .shot .b { transition: visibility 0s calc(var(--hit) * 2); }
}
@media (prefers-reduced-motion: no-preference) {
  .item-btn:focus-visible .shot:has(.b)::after { content: ""; animation: cut calc(var(--hit) * 4) steps(4, end); }
  .item-btn:focus-visible .shot .b { transition: visibility 0s calc(var(--hit) * 2); }
}
@keyframes cut { from { transform: translateY(calc(-100% - 2px)); } to { transform: translateY(714%); } }
/* a press drops the photo 3px, like a deck key (every width) */
.item-btn:active .shot { translate: 0 3px; }
.meta { display: flex; justify-content: space-between; gap: 16px; margin-top: 10px; font-size: 15px; }
.meta .name { font-weight: 500; }
.meta .price { display: flex; flex-direction: column; align-items: flex-end; text-align: right; }
.meta .flag { font-size: 13px; color: var(--dub); }
/* sold out: a rubber stamp on the tile corner, clear of the print */
.shot .sold { left: 12px; bottom: 14px; z-index: 1; background: var(--tape); color: var(--paper); transform: rotate(-3deg); pointer-events: none; }
.slot-7 .meta { padding-right: var(--gutter); }

/* ---------- 3. Collections: cassette spines + J-card ---------- */
.collections .h2 { margin-bottom: clamp(32px, 4vw, 56px); }
.coll { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(24px, 4vw, 64px); align-items: start; }
.coll > * { min-width: 0; } /* a long label is cut short, never widens the shelf */
.spines { display: flex; flex-direction: column; gap: 8px; }
.spine {
  display: flex; align-items: center; gap: 14px;
  width: calc(100% - 32px); height: 68px; padding: 0 16px 0 10px;
  background: var(--tape); color: var(--paper); text-align: left;
  transition: transform calc(var(--hit) * 4) steps(4, end); /* the tape ejects in 4 clicks; keep it a transition */
}
.spine .lbl {
  flex: 1; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px;
  height: 46px; padding: 4px 14px 0;
  background: var(--paper); color: var(--tape);
  font-family: var(--display); letter-spacing: var(--display-track); font-size: clamp(19px, 0.7vw + 15px, 26px); line-height: 1;
}
/* long names (up to 60 characters in the admin) stay on one line and end in "..."; the count never wraps */
.spine .lbl .nm { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.spine .cnt { flex: none; white-space: nowrap; letter-spacing: 0; font-family: var(--mono); font-size: 13px; color: var(--dub); padding-bottom: 4px; }
.spine .g { width: 14px; height: 14px; fill: var(--paper); visibility: hidden; }
.spine[aria-selected="true"] { transform: translateX(32px); }
.spine[aria-selected="true"] .g { visibility: visible; }
@media (hover: hover) and (pointer: fine) {
  .spine[aria-selected="false"]:hover { transform: translateX(8px); }
}

.jcard {
  position: relative; overflow: hidden;
  display: grid; grid-template-columns: 64px minmax(0, 1fr) minmax(0, 1fr);
  border: 2px solid var(--tape); background: var(--paper);
}
.j-spine {
  background: var(--tape); color: var(--paper);
  writing-mode: vertical-rl; transform: rotate(180deg);
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 0; font-family: var(--display); letter-spacing: var(--display-track); font-size: 21px; line-height: 1;
  contain: size; /* as tall as the cover, never taller: a long name is cut short instead */
}
.j-spine span { min-height: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.j-spine small { flex: none; margin-top: 12px; letter-spacing: 0; font-family: var(--mono); font-size: 12px; color: var(--plastic); } /* #5A5A5A on white */
.j-cover { position: relative; border-right: 1px solid var(--dub); }
.j-cover img { width: 100%; aspect-ratio: 1; object-fit: cover; }
.j-cover .j-title {
  position: absolute; left: 14px; bottom: 14px; max-width: calc(100% - 28px);
  background: var(--paper); padding: 8px 14px 2px;
  font-size: clamp(24px, 1.8vw + 14px, 40px); transform: rotate(-2deg);
}
/* two lines at most on the cover (the clamp sits on the span, which carries the stamp filter) */
.j-cover .j-title span { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
.j-inside { padding: 22px 22px 18px; display: flex; flex-direction: column; }
.j-inside p { font-size: 14px; }
.tracks { margin-top: 6px; }
.track {
  display: flex; align-items: baseline; gap: 8px; width: 100%;
  min-height: 44px; padding: 8px 0; text-align: left; font-size: 15px; text-decoration: none;
  border-bottom: 1px solid var(--tape);
}
.track .lead { flex: 1; border-bottom: 1px dashed var(--dub); transform: translateY(-4px); min-width: 16px; }
.track .t-out { color: var(--dub); }
@media (hover: hover) and (pointer: fine) { .track:hover .t-name { text-decoration: underline; } }
/* a hovered (or keyboard-focused) piece pops up as a print laid over the cover, level with it, fed through the copier
   in 4 held frames with one off register, its name rubber-stamped on (app.js initCollections). Black and white in
   dark mode, colour in light mode, like the other photos. */
.t-peek {
  position: absolute; z-index: 3; width: clamp(150px, 16vw, 230px); aspect-ratio: 4 / 5;
  border: 2px solid var(--tape); background: var(--paper); rotate: -2deg; pointer-events: none;
}
.t-peek img { display: block; width: 100%; height: 100%; object-fit: cover; filter: grayscale(1) contrast(1.08); }
.t-peek-tag {
  position: absolute; left: 10px; right: 10px; bottom: 10px; margin: 0; max-width: none; rotate: -1deg;
  font-family: var(--display); letter-spacing: var(--display-track); font-size: 15px; line-height: 1.3;
  text-wrap: balance;
}
/* one strip of label tape per line, as long as its words (inline here, not the stamp's usual inline-block) */
.t-peek .t-peek-tag span {
  display: inline; background: var(--paper); color: var(--tape); padding: 3px 8px 1px;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
@media (prefers-reduced-motion: no-preference) { .t-peek.peek-in { animation: peek-in calc(var(--f) * 4) steps(1, end); } }
@keyframes peek-in {
  0% { clip-path: inset(0 0 100% 0); translate: 0 8px; }
  25% { clip-path: inset(0 0 62% 0); translate: 0 8px; }
  50% { clip-path: inset(0 0 24% 0); translate: 4px 2px; }
  75%, 100% { clip-path: inset(0); translate: 0 0; }
}

/* collection switch: 240ms tracking wipe, stepped like a tape */
.jcard.tear > * { animation: tear 240ms steps(1, end); }
.jcard.tear::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 16px;
  background: var(--tape); animation: band 240ms steps(4, end) forwards;
}
@keyframes tear {
  0%   { clip-path: inset(0 0 72% 0); transform: translateX(-22px); }
  25%  { clip-path: inset(0 0 48% 0); transform: translateX(12px); }
  50%  { clip-path: inset(0 0 24% 0); transform: translateX(-6px); }
  75%  { clip-path: inset(0 0 0 0);   transform: translateX(3px); }
  100% { clip-path: inset(0 0 0 0);   transform: none; }
}
.jcard.tear > .j-spine { animation-name: tear-spine; }
@keyframes tear-spine {
  0%   { transform: rotate(180deg) translateX(22px); }
  50%  { transform: rotate(180deg) translateX(-6px); }
  100% { transform: rotate(180deg); }
}
@keyframes band { from { top: 0; } to { top: 100%; } }

/* ---------- 4. Lookbook zine spread ---------- */
/* app.js builds it. No JS: not shown. Until the store data is in: a blank placeholder about its usual height,
   so the sections below don't jump when it arrives and the radio photo stays out of lazy-load range. */
html:not(.js) .lookbook { display: none; }
.lookbook[data-look-wait] { visibility: hidden; min-height: var(--hold-look, 1600px); }
/* A reload or Back while the shop fills: the built blocks keep the heights they had (index.html sets --hold-* from
   lv-h until motion is armed), so the spot the browser puts back is the one the shopper left and nothing moves */
.collage { min-height: var(--hold-drop, auto); }
.spines { min-height: var(--hold-spines, auto); }
.jcard { min-height: var(--hold-jcard, auto); }
.jcard:empty { visibility: hidden; } /* nothing to show yet: never an empty frame */
.look-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; flex-wrap: wrap; margin-bottom: clamp(32px, 4vw, 56px); }
.look-head p { margin: 0; }
.look-sub { display: grid; gap: 6px; }
.look-issue { font-size: 13px; color: var(--dub); } /* "Issue 1 / Fall 2026" */
.spread { position: relative; display: grid; grid-template-columns: 1fr 1fr; border: 2px solid var(--tape); }
.page { position: relative; }
.page-l { border-right: 1px solid var(--dub); }
.page-r {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  align-content: start; padding: clamp(24px, 3vw, 48px) 0 clamp(56px, 6vw, 96px) clamp(20px, 2.5vw, 40px);
}
/* .ph = one photo slot (placement, tilt), .ph-fig = the photo and its caption, .ph-foot = credits + Shop this look.
   Frames have fixed shapes; any photo is cropped into them at its focus point (object-position, set by app.js). */
.ph { position: relative; align-self: start; }
.ph-fig { position: relative; }
.ph img { width: 100%; background: var(--paper); object-fit: cover; } /* black while the photo loads, like the drop tiles */
.ph-l1 { height: 100%; display: flex; flex-direction: column; }
.ph-l1 .ph-fig { flex: 1 1 auto; min-height: 0; }
.ph-l1 img { height: 100%; aspect-ratio: 3 / 4; }
.ph-r1 img { aspect-ratio: 3 / 2; }
.ph-r2 img { aspect-ratio: 1; }
.ph-r3 img { aspect-ratio: 3 / 4; }
.ph-g img { aspect-ratio: 4 / 5; }
.ph-r1 { grid-column: 2 / 7; grid-row: 1; margin-right: calc(-1 * var(--gutter) - 2px); }
.ph-r2 { grid-column: 1 / 4; grid-row: 2; margin-top: clamp(48px, 5vw, 80px); transform: rotate(-1deg); }
.ph-r3 { grid-column: 4 / 7; grid-row: 2; margin: clamp(120px, 12vw, 180px) clamp(20px, 2.5vw, 40px) 0 clamp(16px, 2vw, 28px); transform: rotate(1deg); }
/* the print-in's sheet and lamp (Motion below) cover the photo only, never its caption. No box until then. */
.ph-l1 .ph-fig::before, .ph-l1 .ph-fig::after { bottom: 0; }
.ph-r1 .ph-fig::before, .ph-r1 .ph-fig::after { aspect-ratio: 3 / 2; }
.ph-r2 .ph-fig::before, .ph-r2 .ph-fig::after { aspect-ratio: 1; }
.ph-r3 .ph-fig::before, .ph-r3 .ph-fig::after { aspect-ratio: 3 / 4; }
.ph:focus { outline: 0; } /* "Seen in the lookbook" focuses the photo only to move the reading position */
/* an issue with a single photo */
.spread-solo { grid-template-columns: minmax(0, 1fr); max-width: 640px; }
.spread-solo .page-l { border-right: 0; }
/* switching issues: the same stepped tracking wipe as the J-card */
.spread.tear > * { animation: tear 240ms steps(1, end); }
.spread.tear::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 16px;
  background: var(--tape); animation: band 240ms steps(4, end) forwards;
}

.ph-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 0 18px; margin-top: 8px; }
.ph-l1 .ph-foot { margin: 0; padding: 8px 20px; border-top: 1px solid var(--dub); }
.credit { margin: 0; padding: 6px 0; max-width: none; font-size: 13px; line-height: 1.4; color: var(--dub); }
.shop-look {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px;
  font-weight: 700; font-size: 14px; line-height: 1.2; text-align: left;
  text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px;
}
.shop-look .g { flex: none; width: 12px; height: 12px; fill: currentColor; }
@media (hover: hover) and (pointer: fine) { .shop-look:hover { text-decoration: none; } }
.shop-many { display: flex; flex-wrap: wrap; align-items: center; gap: 0 18px; }
.shop-h { width: 100%; padding-top: 6px; font-size: 13px; color: var(--dub); }

/* photos 5 and up of an issue */
.look-more {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start;
  gap: clamp(40px, 5vw, 72px) clamp(20px, 2.5vw, 40px); margin-top: clamp(48px, 6vw, 96px);
}
.look-more .s-g { position: relative; display: inline-block; margin-top: 12px; font-size: clamp(13px, 0.3vw + 12px, 16px); transform: rotate(-1deg); }
.look-more .ph-g:nth-child(even) .s-g { transform: rotate(1deg); }

/* past issues: swaps the spread in place */
.issues {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 18px;
  margin-top: clamp(40px, 5vw, 72px); padding-top: 20px; border-top: 1px solid var(--dub);
}
.issues-h { margin: 0; font-weight: 700; }
.issues-row { display: flex; flex-wrap: wrap; gap: 8px; }
.issue-btn {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-height: 52px; padding: 8px 14px; border: 2px solid var(--tape); text-align: left; line-height: 1.15;
}
.issue-t { font-family: var(--display); letter-spacing: var(--display-track); font-size: 18px; }
.issue-btn small { font-size: 12px; color: var(--dub); }
.issue-btn[aria-pressed="true"] { background: var(--tape); color: var(--paper); }
.issue-btn[aria-pressed="true"] small { color: var(--plastic); } /* #5A5A5A on white */
@media (hover: hover) and (pointer: fine) { .issue-btn[aria-pressed="false"]:hover .issue-t { text-decoration: underline; } }

.strip {
  position: absolute; background: var(--paper); color: var(--tape);
  font-family: var(--display); letter-spacing: var(--display-track); font-size: clamp(14px, 0.4vw + 12px, 18px); line-height: 1.15;
  padding: 8px 12px 4px; max-width: 88%;
}
.stamp span { display: inline-block; filter: url(#stamp); }
.s-a { left: 20px; bottom: 24px; transform: rotate(-2deg); }
/* right-page captions sit under their photo, not on it */
.s-b, .s-c, .s-d { position: relative; display: inline-block; margin-top: 12px; font-size: clamp(13px, 0.3vw + 12px, 16px); }
.s-b { transform: rotate(1deg); }
.s-c { transform: rotate(-1deg); }
.s-d { transform: rotate(1.5deg); }

/* ---------- Music submissions: the demo tape (one big link to nero.fan) ---------- */
.submit { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(32px, 5vw, 80px); align-items: center; }
.sub-copy p { margin-top: 20px; }
.radio { width: clamp(180px, 22vw, 300px); height: auto; aspect-ratio: 1; object-fit: cover; margin-bottom: 28px; } /* square, whatever photo the admin picks */
.sub-copy .small { margin-top: 0; }
.demo { display: block; width: min(100%, 560px); text-decoration: none; }
.demo-tape { display: block; width: 100%; height: auto; outline: 2px solid var(--tape); outline-offset: -2px; }
.demo-bar {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  min-height: 68px; padding: 14px 22px;
  background: var(--paper); color: var(--tape); border: 2px solid var(--tape);
  font-weight: 700; font-size: clamp(17px, 0.5vw + 15px, 22px);
}
.demo:focus-visible { outline: 3px solid var(--tape); outline-offset: 6px; }
/* pushing the tape into the deck: an instant, user-triggered move */
@media (hover: hover) and (pointer: fine) {
  .demo:hover .demo-tape { transform: translateY(10px); }
  .demo:hover .demo-bar { background: var(--tape); color: var(--paper); }
}
.demo:active .demo-tape { transform: translateY(18px); }
/* and the cassette plays: both reels turn counter-clockwise, 12 held steps a turn. The site's one loop, and only
   while the pointer or keyboard focus is on it. */
.reel { transform-box: fill-box; transform-origin: center; }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .demo:hover .reel { animation: reel calc(var(--f) * 24) steps(12, end) infinite; }
}
@media (prefers-reduced-motion: no-preference) {
  .demo:focus-visible .reel { animation: reel calc(var(--f) * 24) steps(12, end) infinite; }
}
@keyframes reel { to { transform: rotate(-360deg); } }

/* Real photos come in colour. In dark mode browsing is black and white; the product sheet and cart show
   true colour so people see exactly what they are buying (owner call, 2026-09-22). Light mode shows every photo
   in colour (owner call, 2026-09-30): see the Light mode block at the end. */
.shot img, .j-cover img, .ph img { filter: grayscale(1) contrast(1.08); }

/* ---------- 5. Community CRT ---------- */
.community > * { min-width: 0; }
.community { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(32px, 5vw, 80px); align-items: center; }
.dc-copy p { margin-top: 20px; }
.tv {
  display: grid; grid-template-columns: minmax(0, 1fr) 176px; min-width: 0;
  width: min(100%, 720px); justify-self: end;
  background: var(--plastic); padding: 22px; gap: 22px;
}
.tv-bezel { background: var(--black); padding: 16px; }
.tv-screen {
  position: relative; aspect-ratio: 4 / 3; overflow: hidden;
  display: flex; flex-direction: column;
  background: var(--black); color: var(--white); border: 2px solid var(--toner);
}
.tv-screen::after { content: ""; position: absolute; inset: 0; background-image: var(--scan); background-size: 4px 4px; opacity: 0.35; pointer-events: none; }
.tv-osd {
  display: flex; justify-content: space-between; gap: 12px; margin: 0; max-width: none;
  padding: 10px 14px 8px; font-weight: 700; font-size: 15px; font-variant-numeric: tabular-nums;
  border-bottom: 1px solid var(--plastic);
}
.tv-list { flex: 1; overflow-y: auto; padding: 6px 0; scrollbar-width: thin; scrollbar-color: var(--toner) var(--black); }
.tv-list li { display: flex; align-items: center; gap: 10px; padding: 5px 14px; font-size: 14px; min-width: 0; }
.tv-list img { width: 26px; height: 26px; flex: none; filter: grayscale(1) contrast(1.1); background: var(--plastic); }
/* grayscale: colour emoji in member names and games come out grey on the black-and-white set */
.tv-list .who { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; filter: grayscale(1); }
.tv-list .doing { flex: none; max-width: 42%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--toner); font-size: 12px; filter: grayscale(1); }
/* status marks, square: online = solid, idle = grey, do not disturb = hollow */
.tv-list .st { flex: none; width: 9px; height: 9px; background: var(--white); }
.tv-list .st-idle { background: var(--toner); }
.tv-list .st-dnd { background: none; border: 2px solid var(--white); }
.tv-list .tv-more { color: var(--toner); font-size: 12px; }
/* touch screens and phones: not a scroller, so swipes over the list move the page (app.js caps the rows to the box) */
@media (max-width: 719px), (pointer: coarse) { .tv-list { overflow: hidden; } }
.tv-nosignal {
  position: absolute; inset: 0; display: grid; place-items: center; margin: 0; max-width: none;
  font-weight: 700; font-size: 22px; letter-spacing: 0;
  background: var(--black); color: var(--white);
}
.tv-nosignal[hidden] { display: none; }
.tv-panel { display: flex; flex-direction: column; align-items: stretch; gap: 20px; }
.tv-brand { font-family: var(--display); letter-spacing: var(--display-track); font-size: 17px; line-height: 1; color: var(--white); }
.tv-knobs { display: flex; gap: 14px; }
.tv-knobs i { position: relative; display: block; width: 40px; height: 40px; background: var(--black); }
.tv-knobs i::after { content: ""; position: absolute; left: 50%; top: 6px; width: 3px; height: 13px; margin-left: -1px; background: var(--white); }
.tv-knobs i + i::after { transform: rotate(60deg); transform-origin: 50% 14px; }
.tv-grille { flex: 1; min-height: 70px; background-image: var(--grille); background-size: 6px 6px; }
.tv-join { width: 100%; padding: 12px 10px; font-size: 14px; white-space: nowrap; }
.tv :focus-visible { outline-color: var(--white); }

/* ---------- 6. Newsletter ---------- */
.alerts { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: clamp(24px, 4vw, 64px); align-items: end; }
.alerts p { margin: 18px 0 0; }
.al-form label { display: block; font-weight: 700; margin-bottom: 8px; }
.field { display: flex; border: 2px solid var(--tape); }
/* 16px or more, so iOS doesn't zoom in on focus */
.field input { flex: 1; min-width: 0; height: 56px; padding: 0 16px; background: var(--paper); font-size: max(16px, 1em); }
/* a camcorder-style underscore cursor (a block covered the letter under it mid-address in Chrome) */
.field input { caret-color: var(--tape); caret-shape: underscore; }
.field input:focus-visible { outline: 3px solid var(--tape); outline-offset: -7px; }
.field .btn { border: 0; min-height: 56px; }
.field .btn:focus-visible { outline-offset: -7px; outline-color: var(--paper); }
.al-msg { min-height: 1.6em; margin-top: 12px; font-weight: 700; display: flex; align-items: center; gap: 10px; }
.al-msg .g { flex: none; width: 12px; height: 12px; fill: var(--tape); } /* never squeezed by the text beside it */
/* a signup's REC square blinks 3 times like a camcorder starting to record, then stays on (app.js puts in a fresh
   one each time). About 2 blinks a second on a 12px square. */
@media (prefers-reduced-motion: no-preference) { .al-msg .rec { animation: rec calc(var(--f) * 8) steps(1, end) 3; } }
@keyframes rec { 50% { opacity: 0; } }

/* ---------- 7. Footer ---------- */
.foot {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr); gap: 32px;
  padding: 64px var(--gutter) 28px; background: var(--tape); color: var(--paper); border-top: 1px solid var(--dub);
}
.foot .mark { font-size: 34px; display: inline-block; }
.foot-smiley { width: 84px; height: auto; }
.foot-brand { display: flex; flex-direction: column; align-items: flex-start; gap: 20px; }
.foot-tag { margin: -8px 0 8px; color: var(--toner); font-size: 14px; }
.tape-label {
  background: var(--paper); color: var(--tape);
  font-weight: 700; font-size: 15px; text-transform: uppercase; letter-spacing: 0.08em;
  padding: 8px 22px; min-height: 40px; transform: rotate(-2deg);
  clip-path: polygon(0 0, 100% 0, calc(100% - 6px) 50%, 100% 100%, 0 100%, 6px 50%);
}
.tape-label:focus-visible { outline: 3px solid var(--tape); outline-offset: -10px; } /* inset: the clip-path hides any outer ring */
.foot-h { letter-spacing: 0; font-family: var(--mono); font-size: 13px; font-weight: 400; color: var(--toner); margin-bottom: 14px; line-height: 1.2; }
.foot li + li { margin-top: 6px; }
.foot ul a { text-decoration: none; }
.foot ul a:hover { text-decoration: underline; }
.fine { grid-column: 1 / -1; margin: 32px 0 0; padding-top: 20px; border-top: 1px solid var(--dub); font-size: 13px; color: var(--toner); }
.fine p { margin: 0 0 4px; max-width: none; }

/* ---------- Legal pages (privacy, terms, shipping, returns, accessibility, contact) ---------- */
.bar-back { margin-left: auto; font-size: 14px; font-weight: 700; }
.legal-page .bar { height: 52px; flex-wrap: nowrap; }
a.tape-label { display: inline-block; text-decoration: none; }
.legal { max-width: 78ch; margin: 0 auto; padding-top: clamp(48px, 6vw, 88px); }
.legal h1 { font-size: clamp(32px, 2.6vw + 20px, 60px); margin-bottom: 10px; }
.legal .updated { font-size: 13px; color: var(--dub); margin-bottom: 40px; }
.legal h2 { font-size: clamp(19px, 0.8vw + 15px, 26px); margin: 48px 0 14px; scroll-margin-top: calc(var(--bar) + 16px); }
.legal h3 { font-family: var(--mono); font-weight: 700; font-size: 16px; letter-spacing: 0; margin: 24px 0 8px; line-height: 1.3; }
.legal p, .legal li { font-size: 16px; line-height: 1.7; max-width: 72ch; }
.legal ul, .legal ol { margin: 0 0 1em; padding-left: 1.4em; }
.legal ul { list-style: square; }
.legal ol { list-style: decimal; }
.legal li { margin-bottom: 6px; }
.legal a { text-decoration: underline; }
.legal address { font-style: normal; margin-bottom: 1em; }
mark.todo { background: var(--white); color: var(--black); padding: 0 0.3em; font-weight: 700; }

/* 404: NO SIGNAL. A 4:3 screen; the snow band rolls through once (reduced motion leaves it still). At rest it is
   parked 2px above the screen, so sub-pixel snapping never leaks a row of snow under the top border. */
.lost { max-width: 78ch; margin: 0 auto; display: flex; flex-direction: column; align-items: flex-start; gap: 20px; }
.nosig { position: relative; width: min(100%, 560px); aspect-ratio: 4 / 3; overflow: hidden; background: var(--black); color: var(--white); border: 2px solid var(--toner); font-weight: 700; font-size: clamp(16px, 1vw + 12px, 22px); font-variant-numeric: tabular-nums; }
.nosig::after { content: ""; position: absolute; inset: 0; background-image: var(--scan); background-size: 4px 4px; opacity: 0.35; pointer-events: none; }
.nosig-osd { position: absolute; top: 14px; left: 16px; display: flex; align-items: center; gap: 0.45em; }
.nosig-osd .g { width: 0.8em; height: 0.8em; fill: currentColor; }
.nosig-t { position: absolute; top: 14px; right: 16px; }
.nosig-msg { position: absolute; inset: 0; display: grid; place-items: center; margin: 0; max-width: none; animation: rec 1s steps(1, end) 3; }
.nosig::before { content: ""; position: absolute; left: 0; right: 0; top: -2px; height: 14%; z-index: 1; background: var(--black) var(--snow); background-size: 96px 48px; image-rendering: pixelated; transform: translateY(-100%); animation: nosig-roll calc(var(--f) * 8) steps(8, end) 200ms backwards; }
@keyframes nosig-roll { from { transform: translateY(-100%); } to { transform: translateY(715%); } }

/* ---------- Account pages (account/index.php, order.php, track.php) ----------
   The legal pages' shell. The order status is the deck's on-screen display: PLAY (EJECT once delivered, STOP when
   refunded or canceled) and the step count on top, then four tracking segments that light up in held frames, no
   colour. The Dub No. is rubber-stamped once. Order photos show in true colour, like the cart; the Discord
   picture is black and white, like the rest of browsing. */
.account { max-width: 880px; margin: 0 auto; padding-top: clamp(48px, 6vw, 88px); }
.account h1 { font-size: clamp(32px, 2.6vw + 20px, 60px); margin-bottom: 24px; overflow-wrap: anywhere; }
.account h2 { font-size: clamp(21px, 0.8vw + 17px, 28px); margin: 0 0 16px; }
.account p { max-width: 62ch; }
.acct-lead { font-size: 17px; }
.acct-note { display: flex; align-items: flex-start; gap: 10px; margin: 0 0 24px; padding: 12px 16px; border: 2px solid var(--tape); font-weight: 700; }
.acct-note-quiet { border-width: 1px; border-color: var(--dub); font-weight: 400; }
.acct-note .g, .field-err .g { flex: none; width: 10px; height: 10px; margin-top: 0.5em; fill: currentColor; }
.acct-signin { display: flex; flex-direction: column; align-items: flex-start; gap: 18px; }
.acct-signin p { margin: 0; }
.acct-discord { min-width: min(100%, 300px); }
.acct-alt { margin: 28px 0 0; }
.acct-signin .acct-alt { margin-top: 8px; }
.acct-alt a, .acct-crumb a { font-weight: 700; }
.acct-box { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--plastic); }
.acct-box p { margin: 0; }
.acct-who { display: flex; align-items: center; gap: 18px; min-width: 0; }
.acct-who > div { min-width: 0; }
.acct-who p { margin: 0; }
.acct-av { flex: none; width: 64px; height: 64px; border: 2px solid var(--tape); background: var(--plastic); filter: grayscale(1) contrast(1.08); }
.acct-av-blank { display: grid; place-items: center; background: var(--paper); filter: none; font-family: var(--display); font-size: 30px; line-height: 1; }
.account .acct-name { margin-bottom: 6px; font-family: var(--display); letter-spacing: var(--display-track); font-size: clamp(22px, 1vw + 18px, 32px); line-height: 1.05; overflow-wrap: anywhere; }
.acct-mail { margin: 18px 0 0; overflow-wrap: anywhere; }
.acct-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px; }
.acct-actions form { margin: 0; }
.acct-box .acct-actions { margin-top: 0; } /* .acct-box already spaces its children */
.acct-back { margin: 0 0 24px; } /* "Back to checkout" and friends, under the notice */
.acct-forget { margin-top: 32px; }
.acct-orders { margin-top: clamp(48px, 6vw, 72px); }
.acct-empty { margin-bottom: 6px; font-weight: 700; }
.acct-crumb { margin: 0 0 18px; font-size: 14px; }
.acct-nosig { width: min(100%, 420px); margin-bottom: 28px; }

/* Your orders: one row per order, the whole row is the link */
.orders { border-top: 2px solid var(--tape); }
.orders li { border-bottom: 1px solid var(--plastic); }
.order-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: 4px 16px; padding: 16px 0; text-decoration: none; }
.or-no { font-size: 17px; font-weight: 700; }
.or-total { font-weight: 700; text-align: right; }
.or-meta { font-size: 13px; color: var(--dub); }
.or-status { display: inline-flex; align-items: center; justify-self: end; gap: 6px; font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; }
.or-status .g, .tape-osd .g { flex: none; width: 9px; height: 9px; fill: currentColor; }
@media (hover: hover) and (pointer: fine) { .order-row:hover .or-no { text-decoration: underline; } }

/* One order */
.account .order-h { margin: 6px 0 20px; font-size: clamp(28px, 2.4vw + 18px, 50px); }
.order-stamp { display: inline-block; padding: 0.16em 0.28em 0.06em; border: 4px solid var(--tape); transform: rotate(-2deg); }
.order-stamp span { display: inline-block; filter: url(#stamp); }
@media (prefers-reduced-motion: no-preference) {
  .order-stamp { animation: stamp-in calc(var(--f) * 3) steps(1, end) 120ms both; }
}
.order-sub { color: var(--dub); }
.tape-osd {
  position: relative; overflow: hidden; margin: 32px 0 0; padding: 14px 16px 16px;
  background: var(--black); color: var(--white); border: 2px solid var(--toner);
  font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: 0.04em; text-transform: uppercase;
}
.tape-osd::after { content: ""; position: absolute; inset: 0; background-image: var(--scan); background-size: 4px 4px; opacity: 0.35; pointer-events: none; }
.account .tape-osd-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px 16px; max-width: none; margin: 0 0 14px; font-size: 15px; }
.steps, .order-log { margin: 0; padding: 0; list-style: none; }
.tape-osd-mode { display: inline-flex; align-items: center; gap: 8px; }
.tape-osd-n { color: var(--toner); }
.steps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.steps li { display: grid; gap: 8px; min-width: 0; font-size: 13px; }
.seg { position: relative; display: block; height: 14px; border: 2px solid var(--white); }
.steps .done .seg::before { content: ""; position: absolute; inset: 0; background: var(--white); }
.steps .todo { color: var(--toner); }
.steps .todo .seg { border-color: var(--plastic); }
.step-l { display: inline-flex; align-items: center; gap: 6px; min-width: 0; overflow-wrap: anywhere; }
.step-t { font-size: 12px; font-weight: 400; color: var(--toner); }
/* the segments light up in turn, two held frames each, after the stamp */
@media (prefers-reduced-motion: no-preference) {
  .steps .done .seg::before { animation: seg-in calc(var(--f) * 2) steps(2, end) calc(240ms + var(--i, 0) * var(--f) * 2) both; }
}
@keyframes seg-in { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0); } }
.order-part { margin-top: clamp(40px, 5vw, 64px); }
.order-items { border-top: 2px solid var(--tape); }
.order-item-name { margin: 0; font-weight: 500; overflow-wrap: anywhere; }
.line-ph { display: block; width: 76px; aspect-ratio: 4 / 5; border: 1px dashed var(--plastic); }
.order-sum { max-width: 360px; margin: 18px 0 0 auto; }
.order-sum div { display: flex; justify-content: space-between; gap: 16px; padding: 3px 0; }
.order-sum dt { color: var(--dub); }
.order-sum dd { margin: 0; font-weight: 700; }
.order-sum .order-total { margin-top: 8px; padding-top: 10px; border-top: 2px solid var(--tape); font-size: 18px; }
.order-sum .order-total dt { color: inherit; font-weight: 700; }
.order-info { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px; margin-top: clamp(40px, 5vw, 64px); }
.order-info address { margin: 0 0 12px; font-style: normal; line-height: 1.6; overflow-wrap: anywhere; }
.order-info p { margin: 0 0 12px; }
.order-trk { font-weight: 700; letter-spacing: 0.04em; overflow-wrap: anywhere; }
.order-log { border-top: 2px solid var(--tape); }
.order-log li { display: grid; grid-template-columns: 15em minmax(0, 1fr); gap: 2px 16px; padding: 10px 0; border-bottom: 1px solid var(--plastic); font-size: 14px; }
.order-log time { color: var(--dub); font-variant-numeric: tabular-nums; }
.order-help { margin-top: 40px; }

/* Guest tracking form */
.acct-form { display: grid; gap: 22px; max-width: 480px; margin-top: 28px; }
.acct-form .acct-note { margin: 0; }
.acct-field label { display: block; margin-bottom: 8px; font-weight: 700; }
.acct-field input {
  display: block; width: 100%; height: 56px; padding: 0 16px; border: 2px solid var(--tape); background: var(--paper);
  font-size: max(16px, 1em); caret-color: var(--tape); caret-shape: underscore; /* 16px or more: iOS doesn't zoom */
}
.acct-field input[aria-invalid="true"] { border-width: 4px; padding: 0 14px; }
/* the browser's autofill tint would be the only colour on the page: paint the field black again (a fill, 0 blur) */
.acct-field input:-webkit-autofill { -webkit-box-shadow: inset 0 0 0 100px var(--paper); -webkit-text-fill-color: var(--tape); }
.acct-field input:autofill { box-shadow: inset 0 0 0 100px var(--paper); -webkit-text-fill-color: var(--tape); }
.acct-hint { margin: 8px 0 0; }
.field-err { display: flex; align-items: flex-start; gap: 8px; margin: 8px 0 0; font-size: 14px; font-weight: 700; }
.acct-form .btn { justify-self: start; min-width: 200px; }

@media (max-width: 719px) {
  .order-info { grid-template-columns: 1fr; }
}
@media (max-width: 559px) {
  .order-log li { grid-template-columns: 1fr; }
}
/* phones: the status strip runs down, one step a row */
@media (max-width: 479px) {
  .steps { grid-template-columns: 1fr; gap: 10px; }
  .steps li { grid-template-columns: 34px minmax(0, 1fr) auto; align-items: center; gap: 12px; }
  .acct-form .btn, .acct-discord { width: 100%; }
}

/* ---------- Dialogs ---------- */
dialog { padding: 0; border: 0; max-width: none; max-height: none; }
dialog::backdrop { background-color: transparent; background-image: var(--dither); background-size: 2px 2px; image-rendering: pixelated; }
/* the page behind an open sheet or cart stays put (html's scrollbar-gutter keeps it from shifting sideways) */
html:has(dialog[open]) { overflow: hidden; }
.sheet, .drawer { overscroll-behavior: contain; }
.close { min-height: 44px; padding: 0 4px; font-weight: 700; text-decoration: underline; }

.sheet {
  width: min(1120px, calc(100% - 2 * var(--gutter)));
  max-height: calc(100dvh - 32px); overflow: auto;
  border: 2px solid var(--tape);
}
.sheet[open] { animation: sheet-in 180ms steps(1, end); }
@keyframes sheet-in {
  0%   { clip-path: inset(0 0 66% 0); transform: translateX(-14px); }
  33%  { clip-path: inset(0 0 33% 0); transform: translateX(8px); }
  66%  { clip-path: inset(0);         transform: translateX(-3px); }
  100% { clip-path: inset(0);         transform: none; }
}
.sheet-top { position: sticky; top: 0; z-index: 2; display: flex; justify-content: space-between; align-items: center; padding: 6px 16px; background: var(--paper); border-bottom: 2px solid var(--tape); }
.pd-count { margin: 0; } /* "Photo 1 of 2" */
.sheet-top .close { margin-left: auto; } /* stays top right when the photo counter is hidden (1-photo pieces) */
.sheet-body { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
.pd-photos { display: grid; gap: 2px; background: var(--tape); border-right: 2px solid var(--tape); }
.pd-photos img { width: 100%; height: auto; background: var(--paper); } /* whole photo, uncropped, true colour */
.pd-info { padding: clamp(20px, 3vw, 40px); }
/* two columns with room for the buy block: it stays in view while the photos scroll by */
@media (min-width: 720px) and (min-height: 700px) {
  .pd-info { position: sticky; top: 58px; align-self: start; } /* 58px = .sheet-top: 6 + 44 + 6 + 2px border */
}
.pd-flag { display: inline-block; margin: 0 0 14px; padding: 4px 10px; border: 2px solid var(--tape); font-size: 13px; font-weight: 700; }
.pd-name { font-size: clamp(28px, 1.8vw + 18px, 46px); }
.pd-name:focus { outline: 0; } /* Also in focuses the new name only to move the reading position */
.pd-price { font-size: 20px; font-weight: 700; margin: 14px 0 4px; }
.pd-desc { margin: 14px 0 0; }
.pd-also { display: flex; flex-wrap: wrap; align-items: center; gap: 0 6px; margin: 8px 0 0; font-size: 14px; }
.pd-info .link { min-height: 44px; font-weight: 700; text-decoration: underline; }
.pd-seen { margin: 12px 0 0; font-size: 14px; }
.sizes { border: 0; padding: 0; margin: 26px 0 22px; min-width: 0; }
.sizes legend { font-weight: 700; margin-bottom: 10px; padding: 0; }
/* Add to cart with no size picked: the row jumps one frame, like a tracking error (app.js). Inside .pd-info's padding. */
@media (prefers-reduced-motion: no-preference) { .sizes.jolt { animation: jolt var(--f) steps(1, end); } }
@keyframes jolt { from { translate: -6px 0; } to { translate: 0 0; } }
.size-opts { display: flex; flex-wrap: wrap; gap: 8px; }
.size-opts input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.size-opts label {
  display: grid; place-items: center; min-width: 56px; height: 48px; padding: 0 12px;
  border: 2px solid var(--tape); font-weight: 700; cursor: pointer;
}
.size-opts input:checked + label { background: var(--tape); color: var(--paper); }
.size-opts input:focus-visible + label { outline: 3px solid var(--tape); outline-offset: 3px; }
/* sold out sizes stay on the rack, struck through, and can't be picked; nearly gone ones say how many are left */
.size-opts label.out, .size-opts label.low { align-content: center; gap: 3px; line-height: 1; }
.size-opts label.out { border-style: dashed; border-color: var(--dub); color: var(--dub); cursor: not-allowed; }
.size-opts label.out s { text-decoration-thickness: 2px; }
.size-opts label small { display: block; font: 400 10px/1 var(--mono); letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; }
/* Windows High Contrast drops the fill, so mark the picked size with system colours */
@media (forced-colors: active) {
  .size-opts input:checked + label { forced-color-adjust: none; background: Highlight; color: HighlightText; border-color: Highlight; }
}
.pd-soldout { margin: 12px 0 0; }
.pd-status { min-height: 1.6em; margin: 12px 0; font-weight: 700; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; }
.pd-status .link { text-decoration: underline; font-weight: 700; min-height: 44px; }
.details { margin: 26px 0 0; border-top: 2px solid var(--tape); }
.details div { display: flex; gap: 8px; padding: 10px 0; border-bottom: 1px solid var(--dub); font-size: 14px; }
.details dt { flex: 0 0 7.5em; color: var(--dub); }
.details dd { margin: 0; }
.details.pd-fit { margin: -8px 0 22px; } /* Fit and Measurements, under the sizes */

.drawer {
  margin: 0 0 0 auto; height: 100dvh; max-height: 100dvh; width: min(460px, 100%);
  border-left: 2px solid var(--tape); overflow: auto;
}
.drawer[open] { animation: drawer-in 160ms steps(4, end); }
@keyframes drawer-in { from { transform: translateX(100%); } to { transform: none; } }
.drawer-top { position: sticky; top: 0; z-index: 2; display: flex; align-items: center; justify-content: space-between; padding: 12px 20px; background: var(--tape); color: var(--paper); }
.drawer-top .close:focus-visible { outline-color: var(--paper); }
.drawer-h { font-size: 28px; }
.drawer-top .drawer-h:focus { outline: 0; } /* focused after a line is removed, only to hold the reading position */
.cart-view, .checkout-view { padding: 20px; }
.cart-dropped { margin: 0 0 6px; }
.line { display: grid; grid-template-columns: 76px minmax(0, 1fr) auto; gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--tape); }
.line img { width: 76px; aspect-ratio: 4 / 5; object-fit: cover; border: 1px solid var(--tape); }
/* photo and name open the piece again */
.line-photo { display: block; align-self: start; }
.line-name { display: block; font-weight: 500; text-align: left; }
.line-name:hover, .line-name:focus-visible { text-decoration: underline; }
.line-size { font-size: 13px; color: var(--dub); margin: 2px 0 10px; }
/* a line that can't be bought right now (sold out, or that size is gone): greyed, the photo keeps its colour */
.line-out .line-name, .line-out .line-price { color: var(--dub); }
/* - qty + stay one square set; Remove is a text button and wraps under it, flush left, when the line is narrow */
.qty { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }
.step { display: flex; align-items: center; }
.qty button:not(.remove) { flex: none; width: 36px; height: 36px; border: 2px solid var(--tape); font-weight: 700; }
.qty button:disabled { color: var(--dub); border-color: var(--dub); cursor: not-allowed; }
.qty output { min-width: 36px; text-align: center; font-weight: 700; }
.remove { font-size: 13px; text-decoration: underline; min-height: 44px; padding: 0 4px; }
.line-price { font-weight: 700; }
.empty { margin: 8px 0 0; }
.cart-sum { margin-top: 18px; }
.sum-row { display: flex; justify-content: space-between; font-weight: 700; font-size: 18px; max-width: none; margin-bottom: 4px; }
.cart-sum .btn { margin-top: 14px; }
/* kept for the phase 2 /thanks page (give it its own stamp-in rule there, gated on prefers-reduced-motion) */
.dub-no { display: inline-block; border: 3px solid var(--tape); padding: 8px 14px 4px; font-weight: 700; font-size: 20px; transform: rotate(-2deg); margin: 8px 0 22px; }
.checkout-view .drawer-h { margin-bottom: 14px; }
.checkout-view .drawer-h:focus { outline: 0; } /* focused when the step opens, only to move the reading position */
/* the checkout step (CHECKOUT_LIVE): sign in with Discord or continue as a guest; signed in, "Checking out as" */
.co-pick { display: grid; gap: 18px; margin: 0 0 18px; }
.co-opt .small { margin: 8px 0 0; }
.co-as { margin: 0 0 18px; }
.co-as .small { margin: 8px 0 0; }
.co-name { overflow-wrap: anywhere; }
.co-msg { font-weight: 700; }
.co-msg:empty { display: none; }
/* "Back to cart" is a way out, not a third option: underlined text like the drawer's Close, 44px tall */
.checkout-view .link { min-height: 44px; padding: 0 4px; font-weight: 700; text-decoration: underline; }

/* ---------- Responsive ---------- */
@media (max-width: 1080px) {
  .bar { gap: 20px; }
  .bar nav ul { gap: 18px; }
  .jcard { grid-template-columns: 52px minmax(0, 1fr); }
  .j-inside { grid-column: 2; border-top: 1px solid var(--dub); }
  .j-cover { border-right: 0; }
  .j-spine { grid-row: 1 / 3; }
  .community { grid-template-columns: 1fr; }
}

/* the one-row desktop header still fits at 720-799 (a 1440 window at 200% zoom), and a short collection
   name like "Hoodies" stays whole on its narrow spine */
@media (min-width: 720px) and (max-width: 799px) {
  .bar { gap: 16px; }
  .bar nav ul { gap: 12px; }
  .spine .lbl { gap: 8px; padding-left: 10px; padding-right: 10px; }
  .shop-bar { column-gap: 12px; } /* mark, nav, Sign in and Cart on one row from 720px */
}
/* 720-959 (no deck yet): Sign in joined the one-row header, so "Submit music" reads "Music", as on phones, and
   the Discord picture waits for 800px */
@media (min-width: 720px) and (max-width: 959px) {
  .shop-bar .nav-full { display: none; }
  .shop-bar .nav-short { display: inline; }
}
@media (min-width: 720px) and (max-width: 799px), (max-width: 389px) {
  .acct-av-s { display: none; }
}

/* 720-1023: the brand block (smiley, mark, tagline, tape) takes its own row, and Follow / Help / Legal sit three
   across, so the tape and the "YikeMike" labels stay on one line */
@media (min-width: 720px) and (max-width: 1023px) {
  .foot { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .foot-brand { grid-column: 1 / -1; }
}

@media (max-width: 719px) {
  :root { --bar: 84px; }
  .bar { flex-wrap: wrap; height: var(--bar); row-gap: 0; padding-top: 4px; padding-bottom: 4px; align-content: center; }
  .bar nav { order: 3; width: 100%; }
  .bar nav ul { gap: 20px; overflow-x: auto; white-space: nowrap; scrollbar-width: none; }
  .bar nav a { display: inline-block; padding: 6px 0; }
  .submit { grid-template-columns: 1fr; }
  .demo { width: 100%; }

  .collage { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 14px; row-gap: 40px; }
  .collage > *, .items > li { grid-row: auto !important; margin-top: 0 !important; }
  .drop-head { grid-column: 1 / -1; }
  .slot-1 { grid-column: 1 / -1; }
  .slot-2, .slot-4, .slot-6 { grid-column: 1 / 2; }
  .slot-3, .slot-5, .slot-7 { grid-column: 2 / 3; }
  .items > .slot-3, .items > .slot-5, .items > .slot-7 { margin-top: 56px !important; }
  .slot-7 { margin-right: 0 !important; }
  .slot-7 .meta { padding: 0; }
  .meta { flex-direction: column; gap: 0; font-size: 14px; }
  .meta .price { align-items: flex-start; text-align: left; }

  .coll { grid-template-columns: 1fr; }
  .spine { width: calc(100% - 20px); }
  .spine[aria-selected="true"] { transform: translateX(20px); }

  .spread { grid-template-columns: 1fr; border: 0; }
  .page-l { border-right: 0; margin: 0 calc(-1 * var(--gutter)); }
  .page-r { padding: 48px 0 40px; }
  .ph-r1 { grid-column: 1 / 7; margin-right: calc(-1 * var(--gutter)); }
  .ph-r2 { grid-column: 1 / 5; }
  /* own row on phones, so it never covers the caption and Shop this look of the photo before it */
  .ph-r3 { grid-column: 3 / 7; grid-row: 3; margin: 32px 0 0; }
  .ph-l1 .ph-foot { padding: 8px var(--gutter); }
  .spread-solo { max-width: none; }
  .look-more { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px 14px; margin-top: 40px; }
  .issues { margin-top: 40px; }

  .tv { grid-template-columns: minmax(0, 1fr); padding: 12px; gap: 14px; margin: 0 calc(-1 * var(--gutter)); width: auto; justify-self: stretch; }
  .tv-bezel { padding: 10px; }
  .tv-screen { aspect-ratio: auto; height: 420px; }
  .tv-panel { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 12px; }
  .tv-brand { font-size: 17px; }
  .tv-knobs i { width: 30px; height: 30px; }
  .tv-knobs i::after { top: 4px; height: 10px; }
  .tv-knobs i + i::after { transform-origin: 50% 11px; }
  .tv-grille { display: none; }
  .tv-join { width: auto; margin-left: auto; }

  .alerts { grid-template-columns: 1fr; }
  .foot { grid-template-columns: 1fr 1fr; column-gap: 16px; } /* "YouTube: YikeMike" stays on one line from 360px */
  .foot-brand, .foot .fine { grid-column: 1 / -1; }

  .sheet { width: 100%; max-height: 100dvh; height: 100dvh; border: 0; }
  .sheet-body { grid-template-columns: 1fr; }
  /* first photo, then the name, price, sizes and Add to cart, then the other photos */
  .pd-photos { display: contents; }
  .pd-photos img { order: 2; border-top: 2px solid var(--tape); }
  .pd-photos img:first-child { order: 0; border-top: 0; max-height: 55svh; object-fit: contain; }
  .pd-info { order: 1; }
}

@media (max-width: 479px) {
  /* all five links fit at 13px from 360px up; the 359px block takes them to 12px so they fit down to 320px;
     narrower than that, the row scrolls sideways */
  .bar nav ul { gap: 12px; justify-content: space-between; }
  .bar nav a { font-size: 13px; }
  .nav-full { display: none; }
  .nav-short { display: inline; }
  .shop-bar { column-gap: 16px; } /* the mark, Sign in and Cart share the top row */
  .field { flex-direction: column; }
  .field input { flex: none; } /* in a column, flex: 1 would squash it to a strip; its 56px height applies again */
  .field .btn { width: 100%; }
  .osd-date { display: none; }
  .drawer { border-left: 0; } /* the cart fills the screen here, so no edge line */
}

/* the smallest phones: a cart line's price goes under its controls, so - qty + and Remove keep their width */
@media (max-width: 359px) {
  .line { grid-template-columns: 76px minmax(0, 1fr); }
  .line-price { grid-column: 2; margin: 0; }
  .tape-label { font-size: 14px; letter-spacing: 0.04em; padding: 8px 16px; } /* the tape stays one strip */
  .bar nav ul { gap: 6px; } /* at 12px all five links fit down to 320px */
  .bar nav a { font-size: 12px; }
  /* the top row keeps the mark, Sign in (or Account) and Cart on one line down to 320px */
  .shop-bar { column-gap: 12px; }
  .shop-bar .mark { font-size: 18px; }
  .acct { font-size: 13px; }
}

/* ---------- Motion: entrances, once each (app.js initMotion) ----------
   html.mo = the engine is on (JS, IntersectionObserver and motion allowed). .mo-arm = the hidden pre-state, set
   only below the fold; .mo-play = playing. Every pre-state starts with html.mo and lives in here, so print,
   reduced motion and a dead script all get the still page. Held frames only; transform, opacity, clip-path. */
@media screen and (prefers-reduced-motion: no-preference) {
  /* Latest drop: the title card types on (the cursor is .drop-head.mo-type::after) */
  html.mo #drop-h.mo-arm { clip-path: inset(0 100% 0 0); }

  /* Collections: the selected tape ejects in 4 clicks (.spine's transition), the J-card unfolds panel by panel
     off its spine, then the name is stamped */
  html.mo .coll.mo-arm .spine[aria-selected="true"] { transform: none; }
  html.mo .coll.mo-arm .jcard > .j-cover, html.mo .coll.mo-arm .jcard > .j-inside { clip-path: inset(0 100% 0 0); }
  /* the whole card, frame included, folds to its spine (2px frame + 64px spine); the frame opens with the panels, never ahead */
  html.mo .coll.mo-arm .jcard { clip-path: inset(0 calc(100% - 66px) 0 0); }
  .coll.mo-play .jcard { animation: unfold-card calc(var(--f) * 6) steps(1, end) 100ms both; }
  .coll.mo-play .jcard > .j-cover { animation: unfold calc(var(--f) * 3) steps(1, end) 100ms both; }
  .coll.mo-play .jcard > .j-inside { animation: unfold calc(var(--f) * 3) steps(1, end) 280ms both; }
  .coll.mo-play .j-title { animation: stamp-in calc(var(--f) * 3) steps(1, end) 460ms both; }

  /* Lookbook spread: a black unprinted sheet, then a copier lamp runs down it in 6 steps, printing the photo
     above it; the caption is stamped after */
  html.mo .ph.mo-arm .ph-fig::before, .ph.mo-play .ph-fig::before, .ph.mo-play .ph-fig::after {
    content: ""; position: absolute; left: 0; right: 0; top: 0; z-index: 3; pointer-events: none;
  }
  html.mo .ph.mo-arm .ph-fig::before, .ph.mo-play .ph-fig::before { background: var(--black); transform-origin: 50% 100%; }
  html.mo .ph.mo-arm .strip, html.mo .strip.mo-arm { opacity: 0; }
  .ph.mo-play .ph-fig::before { transform: scaleY(0); animation: print-sheet calc(var(--f) * 6) steps(6, end); }
  .ph.mo-play .ph-fig::after { z-index: 4; border-top: 3px solid var(--white); visibility: hidden; animation: print-lamp calc(var(--f) * 6) steps(6, end); }
  .strip.mo-play { animation: stamp-in calc(var(--f) * 3) steps(1, end) both; }

  /* The Discord: the TV clicks on. Knob, dot, line, a band, a taller band, full screen. */
  html.mo .tv.mo-arm .tv-screen { clip-path: inset(50%); }
  html.mo .tv.mo-arm .tv-knobs i:first-child::after { transform: rotate(-60deg); transform-origin: 50% 14px; }
  .tv.mo-play .tv-screen { animation: crt calc(var(--f) * 6) steps(1, end); }
  /* the beam is shown and hidden by clip-path too, so it always steps in the same frame as the screen's clip */
  .tv.mo-play .tv-screen::before {
    content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 2px; margin-top: -1px; z-index: 4; pointer-events: none;
    background: var(--white); clip-path: inset(0 50%); animation: crt-beam calc(var(--f) * 6) steps(1, end);
  }
}
@media screen and (max-width: 1080px) and (prefers-reduced-motion: no-preference) {
  /* 52px spine here; the panels stack, so the frame follows the cover */
  html.mo .coll.mo-arm .jcard { clip-path: inset(0 calc(100% - 54px) 0 0); }
  .coll.mo-play .jcard { animation: unfold-card-s calc(var(--f) * 3) steps(1, end) 100ms both; }
}
@media screen and (max-width: 719px) and (prefers-reduced-motion: no-preference) {
  html.mo .tv.mo-arm .tv-knobs i:first-child::after { transform-origin: 50% 11px; }
}
@keyframes unfold {
  0%     { clip-path: inset(0 100% 0 0); }
  33.33% { clip-path: inset(0 58% 0 0); }
  66.67% { clip-path: inset(0 14% 0 0); }
  100%   { clip-path: inset(0); }
}
/* the J-card's frame follows the cover's 3 frames, then the track list's 3 (42%, 86%, 100% of each panel) */
@keyframes unfold-card {
  0%     { clip-path: inset(0 calc(100% - 66px) 0 0); }
  16.67% { clip-path: inset(0 calc((100% - 66px) * 0.79) 0 0); }
  33.33% { clip-path: inset(0 calc((100% - 66px) * 0.57) 0 0); }
  50%    { clip-path: inset(0 calc((100% - 66px) * 0.5) 0 0); }
  66.67% { clip-path: inset(0 calc((100% - 66px) * 0.29) 0 0); }
  83.33% { clip-path: inset(0 calc((100% - 66px) * 0.07) 0 0); }
  100%   { clip-path: inset(0); }
}
@keyframes unfold-card-s {
  0%     { clip-path: inset(0 calc(100% - 54px) 0 0); }
  33.33% { clip-path: inset(0 calc((100% - 54px) * 0.58) 0 0); }
  66.67% { clip-path: inset(0 calc((100% - 54px) * 0.14) 0 0); }
  100%   { clip-path: inset(0); }
}
/* one off-register strike, then rest (translate and rotate compose with the element's own tilt) */
@keyframes stamp-in {
  0%            { opacity: 0; }
  33.33%        { opacity: 1; translate: 2px 2px; rotate: -1deg; }
  66.67%, 100%  { opacity: 1; translate: 0 0; rotate: 0deg; }
}
@keyframes print-sheet { from { transform: none; } to { transform: scaleY(0); } }
@keyframes print-lamp { from { transform: none; visibility: visible; } to { transform: translateY(100%); visibility: visible; } }
@keyframes crt {
  0%           { clip-path: inset(50%); }
  16.67%       { clip-path: inset(calc(50% - 1px) 44%); }
  33.33%       { clip-path: inset(calc(50% - 1px) 0); }
  50%          { clip-path: inset(34% 0); }
  66.67%       { clip-path: inset(8% 0); }
  83.33%, 100% { clip-path: inset(0); }
}
@keyframes crt-beam { 0% { clip-path: inset(0 50%); } 16.67%, 33.33% { clip-path: inset(0); } 50%, 100% { clip-path: inset(0 50%); } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---------- Print: the photocopy ----------
   Black ink on white paper, for the shop, the legal pages and the 404. The screen-only parts go (the intro, the nav,
   the hero, the TV, the forms, the dialogs); legal links print their address. app.js disarms motion on beforeprint. */
@media print {
  :root, .section, dialog { --tape: #000; --paper: #FFF; --dub: #5A5A5A; --toner: #5A5A5A; }
  html, body, .bar, .foot, .section { background: #FFF !important; color: #000 !important; }
  .intro, .skip, .preview-bar, .bar nav, .bar-back, .acct, .cart-btn, .deck, .hero, .tv, .al-form, .demo, dialog, .issues, .tape-label, .foot-smiley, .nosig, .foot > div:not(.foot-brand):not(.fine) { display: none !important; }
  .bar, .legal-page .bar { position: static; height: auto; padding: 0 0 10px; border-bottom: 2px solid #000; }
  .legal a[href^="http"]::after, .legal a[href^="mailto:"]::after { content: " (" attr(href) ")"; font-size: 0.85em; word-break: break-all; }
  /* the demo link is gone on paper, so its new-tab note goes too and the address prints instead (keep it the same
     as the demo's href in index.html) */
  .sub-copy .small { display: none !important; }
  .sub-copy::after { content: "Submit at www.nero.fan/lowerville"; display: block; margin-top: 8px; font-size: 13px; color: #5A5A5A; }
  .legal h2, .legal h3 { break-after: avoid; }
  .items > li, .ph, .details div { break-inside: avoid; }
  mark.todo { outline: 1px solid #000; }
  .fine::after { content: "Printed from lowerville.net"; display: block; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
/* Print, the 2-column layout only: keep the Lookbook head and its spread on one sheet. The phone-width spread is taller than a page, so it is left alone. */
@media print and (min-width: 720px) {
  .lookbook { padding-bottom: 0; }
  .look-head { break-after: avoid; margin-bottom: 16px; }
  .spread { break-inside: avoid; }
  .page-r { padding-bottom: 24px; }
}

/* ---------- Coming soon (gate.php, while the store is locked) ----------
   The deck on standby, centered: a black-and-white screen in both themes (2:1, square on phones) with the OSD in
   its corners, the wordmark in the middle glitching in red and cyan like the hero's title (three short bursts,
   all over within 5s, and again when the screen is hovered), the title generator's cursor after Coming soon,
   then the words, the buttons and the password in one column. */
.gate { max-width: 960px; margin: 0 auto; padding-top: clamp(24px, 4vw, 56px); display: flex; flex-direction: column; align-items: center; gap: clamp(28px, 4vw, 44px); text-align: center; }
.gate-screen {
  position: relative; overflow: hidden; width: 100%; aspect-ratio: 2 / 1;
  display: grid; place-items: center; container-type: inline-size;
  background: var(--black); color: var(--white); border: 2px solid var(--plastic);
  font-weight: 700; font-size: clamp(14px, 0.8vw + 10px, 20px); font-variant-numeric: tabular-nums;
}
.gate-screen::after { content: ""; position: absolute; inset: 0; background-image: var(--scan); background-size: 4px 4px; opacity: 0.35; pointer-events: none; }
/* one roll of tape snow on arrival, like the NO SIGNAL page (reduced motion leaves it off screen) */
.gate-screen::before { content: ""; position: absolute; left: 0; right: 0; top: -2px; height: 14%; z-index: 1; background: var(--black) var(--snow); background-size: 96px 48px; image-rendering: pixelated; transform: translateY(-100%); animation: nosig-roll calc(var(--f) * 8) steps(8, end) 200ms backwards; }
.gate-osd { position: absolute; top: 14px; left: 18px; margin: 0; display: flex; align-items: center; gap: 0.5em; }
.gate-osd .g { width: 0.8em; height: 0.8em; fill: currentColor; }
.gate-ctr { position: absolute; top: 14px; right: 18px; margin: 0; }
.gate-date { position: absolute; right: 18px; bottom: 14px; margin: 0; }
/* the photo from admin > Site text and pictures, behind the readout and the name: black and white and darkened so
   LOWERVILLE stays readable, in both themes like the rest of the screen (object-position: its focus point) */
.gate-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; filter: grayscale(1) contrast(1.08) brightness(0.55); }
/* the slideshow (gate.js): every photo stacked, one on at a time, swapped by a hard tape cut: a frame of tracking
   snow, then a band of it (reduced motion: the plain cut) */
.gate-slides { position: absolute; inset: 0; }
.gate-slides .gate-photo { visibility: hidden; }
.gate-slides .gate-photo.is-on { visibility: visible; }
.gate-slides::after {
  content: ""; position: absolute; inset: 0; z-index: 1; visibility: hidden;
  background: var(--black) var(--snow); background-size: 96px 48px; image-rendering: pixelated;
}
@media (prefers-reduced-motion: no-preference) { .gate-slides.is-cut::after { animation: gate-cut calc(var(--f) * 3) steps(1, end); } }
@keyframes gate-cut {
  0% { visibility: visible; clip-path: inset(0); }
  34% { visibility: visible; clip-path: inset(28% 0 52% 0); }
  67%, 100% { visibility: hidden; clip-path: inset(0); }
}
/* the readout as a button: PLAY or PAUSE, then the chip that says what a press does, like the hero's camcorder */
button.gate-osd {
  top: 4px; left: 12px; z-index: 2; min-height: 44px; padding: 0 6px;
  background: none; border: 0; color: var(--white); font: inherit; letter-spacing: inherit; cursor: pointer;
}
.gate-play .g-pause, .gate-play.is-paused .g-play { display: none; }
.gate-play.is-paused .g-pause { display: block; }
.gate-state { min-width: 5ch; text-align: left; }
.gate-act {
  margin-left: 0.2em; min-width: calc(5ch + 1.2em + 2px); padding: 0.2em 0.6em; text-align: center;
  font-size: max(12px, 0.6em); font-weight: 400; line-height: 1;
  border: 1px solid var(--white); background: var(--black); color: var(--white);
}
@media (hover: hover) and (pointer: fine) { .gate-play:hover .gate-act { background: var(--white); color: var(--black); } }
.gate-play:focus-visible { outline: 3px solid var(--white); outline-offset: 2px; }
.gate-play:focus-visible .gate-act { background: var(--white); color: var(--black); }
.gate-title { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 16px; padding: 0 16px; }
.gate-mark {
  position: relative; isolation: isolate; white-space: nowrap;
  font-size: clamp(30px, 10vw, 128px); line-height: 0.9; color: var(--white);
  font-size: 11.5cqi; /* sized to the screen, not the window, so the name and its mark always fit inside it */
  -webkit-text-stroke: 0.035em var(--black); paint-order: stroke fill;
}
/* the glitch: red and cyan copies of the name, knocked off register for a frame at a time */
.gate-mark::before, .gate-mark::after {
  content: attr(data-text); position: absolute; left: 0; top: 0; z-index: -1;
  -webkit-text-stroke: 0; visibility: hidden;
}
.gate-mark::before { color: var(--misreg-r); }
.gate-mark::after { color: var(--misreg-c); }
@media (prefers-reduced-motion: no-preference) {
  .gate-mark::before { animation: gate-glitch-r 4.2s steps(1, end) 500ms; }
  .gate-mark::after { animation: gate-glitch-c 4.2s steps(1, end) 500ms; }
  .gate-screen:hover .gate-mark::before { animation: gate-hover-r calc(var(--f) * 4) steps(1, end); }
  .gate-screen:hover .gate-mark::after { animation: gate-hover-c calc(var(--f) * 4) steps(1, end); }
}
@keyframes gate-glitch-r {
  0% { visibility: visible; transform: translate(-6px, 0); }
  2% { visibility: visible; transform: translate(-3px, 2px); }
  3%, 44% { visibility: hidden; transform: none; }
  45% { visibility: visible; transform: translate(-5px, 0); }
  47%, 88% { visibility: hidden; transform: none; }
  89% { visibility: visible; transform: translate(-4px, -2px); }
  91%, 100% { visibility: hidden; transform: none; }
}
@keyframes gate-glitch-c {
  0% { visibility: visible; transform: translate(6px, 0); }
  2% { visibility: visible; transform: translate(3px, -2px); }
  3%, 44% { visibility: hidden; transform: none; }
  45% { visibility: visible; transform: translate(5px, 0); }
  47%, 88% { visibility: hidden; transform: none; }
  89% { visibility: visible; transform: translate(4px, 2px); }
  91%, 100% { visibility: hidden; transform: none; }
}
@keyframes gate-hover-r { 0% { visibility: visible; transform: translate(-6px, 0); } 50% { visibility: visible; transform: translate(-3px, 2px); } 75%, 100% { visibility: hidden; transform: none; } }
@keyframes gate-hover-c { 0% { visibility: visible; transform: translate(6px, 0); } 50% { visibility: visible; transform: translate(3px, -2px); } 75%, 100% { visibility: hidden; transform: none; } }
.gate-soon {
  margin: 0; max-width: none; display: flex; align-items: center; justify-content: center; gap: 0.25em;
  font-family: var(--mono); font-size: clamp(16px, 1.2vw + 10px, 28px); text-transform: uppercase; letter-spacing: 0.06em;
}
.gate-cur { display: inline-block; width: 0.6em; height: 1em; background: var(--white); }
@media (prefers-reduced-motion: no-preference) { .gate-cur { animation: rec calc(var(--f) * 10) steps(1, end) 6; } }
.gate-body { width: 100%; max-width: 560px; display: flex; flex-direction: column; align-items: center; gap: 28px; }
.gate-copy p { margin: 0 0 8px; max-width: none; }
.gate-lead { font-weight: 700; }
.gate-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin-top: 18px; }
.gate-links .btn { gap: 10px; }
.gate-form { width: 100%; margin: 0; }
.gate-form label { text-align: center; }
/* Enter is a paper button like the others, set off from the field by a rule */
.gate-form .field .btn { border-left: 2px solid var(--tape); }
.gate-form .al-msg { justify-content: center; }
.gate-foot { grid-template-columns: minmax(0, 1fr); }
@media (max-width: 719px) {
  .gate-screen { aspect-ratio: 1 / 1; }
}
@media (max-width: 479px) {
  .gate-form .field .btn { border-left: 0; border-top: 2px solid var(--tape); }
}

/* ---------- Light mode ("xerox paper", owner call 2026-09-30) ----------
   Dark stays the default. <html data-theme="light"> (set in every page's <head> from localStorage 'lv-theme', before
   the first paint; theme.js switches it) turns the page into black toner on white paper: the section and dialog
   tokens flip back to ink on paper, the header and footer become white bars with black type, and secondary text
   uses #5A5A5A (#A0A0A0 fails on white). Screens stay screens: the hero footage and its OSD, the intro tape, the
   Discord TV, the order OSD strip and the NO SIGNAL page keep their dark tokens. */
.theme-btn { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; font-size: 14px; font-weight: 700; line-height: 1.1; white-space: nowrap; }
.theme-btn .g { flex: none; width: 12px; height: 12px; fill: currentColor; }
.theme-btn:active { color: var(--toner); }
@media (hover: hover) and (pointer: fine) { .theme-btn:hover { text-decoration: underline; } }
html[data-theme="light"] .to-light, html:not([data-theme="light"]) .to-dark { display: none; }
html:not([data-theme]) [data-theme-btn] { display: none; } /* no JS: nothing to switch, the site stays dark */
/* in the header only where it fits beside the nav, Sign in and Cart; the footer always has one */
.theme-top { display: none; }
@media (min-width: 1280px) {
  .theme-top { display: inline-flex; margin-left: auto; flex: none; }
  .theme-top + :is(.acct, .bar-back) { margin-left: 0; }
}
@media (min-width: 480px) {
  .legal-page .theme-top { display: inline-flex; margin-left: auto; flex: none; }
  .legal-page .theme-top + .bar-back { margin-left: 0; }
}
.theme-foot { font-size: 13px; }
@media screen {
  html[data-theme="light"] { color-scheme: light; background: var(--white); scrollbar-color: var(--plastic) var(--white); }
  html[data-theme="light"] body { background: var(--white); color: var(--black); }
  html[data-theme="light"] :is(.section, dialog) { --tape: #000000; --paper: #FFFFFF; --dub: #5A5A5A; --toner: #5A5A5A; }
  html[data-theme="light"] :is(.bar, .foot) { --tape: #FFFFFF; --paper: #000000; --dub: #5A5A5A; --toner: #5A5A5A; }
  html[data-theme="light"] :is(.tv, .tape-osd, .nosig) { --tape: #FFFFFF; --paper: #000000; --dub: #A0A0A0; --toner: #A0A0A0; color-scheme: dark; }
  /* a black rule under the white header, so it never melts into the page */
  html[data-theme="light"] .bar::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--paper); pointer-events: none; }
  html[data-theme="light"] ::selection { background: var(--plastic); color: var(--white); }
  html[data-theme="light"] .skip:focus { outline-color: var(--black); }
  html[data-theme="light"] .preview-bar { background: var(--black); color: var(--white); }
  html[data-theme="light"] .preview-bar :focus-visible { outline-color: var(--white); }
  html[data-theme="light"] .j-spine small,
  html[data-theme="light"] .issue-btn[aria-pressed="true"] small,
  html[data-theme="light"] .drawer-top .close:active { color: #A0A0A0; }
  html[data-theme="light"] mark.todo { background: var(--black); color: var(--white); }
  /* the dialog scrim: white pixels over the page instead of black */
  html[data-theme="light"] dialog::backdrop { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2' height='2'%3E%3Crect width='1' height='1' fill='%23FFF'/%3E%3Crect x='1' y='1' width='1' height='1' fill='%23FFF'/%3E%3C/svg%3E"); }
  /* the copier prints onto white paper, under a black lamp line */
  html.mo[data-theme="light"] .ph.mo-arm .ph-fig::before, html[data-theme="light"] .ph.mo-play .ph-fig::before { background: var(--white); }
  html[data-theme="light"] .ph.mo-play .ph-fig::after { border-top-color: var(--black); }
  /* every photo in true colour (the drop, the J-card, the lookbook, Discord pictures on the account pages);
     the camcorder footage and the Discord TV are black-and-white screens in both themes */
  html[data-theme="light"] :is(.shot img, .j-cover img, .ph img, .t-peek img, .acct-av, .acct-av-s) { filter: none; }
  /* the footer smiley is white on black: printed on paper it turns black on white */
  html[data-theme="light"] .foot-smiley { filter: invert(1); }
  /* the hero's buttons follow the theme: white with black type and edge in light mode */
  html[data-theme="light"] .hero .cta { background: var(--white); color: var(--black); border-color: var(--black); }
  @media (hover: hover) and (pointer: fine) {
    html[data-theme="light"] .hero .cta:hover { background: var(--black); color: var(--white); border-color: var(--white); }
  }
}
