
/* ============================================
   UNCHAINED — design tokens
   ============================================ */
:root {
  --bg: #0a0a0a;
  --surface: #141414;
  --surface-2: #1c1c1c;
  --text: #f2f0ea;
  --text-dim: #8f8c86;
  --border: #2a2a2a;

  --accent: #f2429c;      /* default site accent (pink) */
  --rage: #e8383c;
  --acid: #c9ff3d;
  --pink: #f2429c;
  --vhs: #ffc700;
  --chrome: #7fd4ff;

  /* Three roles, not three decorations:
     display  — Unbounded, geometric and wide, for the shouting
     body     — Chakra Petch, squared off, the HUD voice; also the label role,
                which is why --font-mono is no longer strictly monospaced
                (anything with aligned digits sets font-variant-numeric instead)
     pixel    — Silkscreen, only on the two numeric readouts, where a device
                display is the point */
  --font-display: "Unbounded", "Arial Black", Impact, sans-serif;
  --font: "Chakra Petch", -apple-system, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono: "Chakra Petch", ui-monospace, "Courier New", monospace;
  --font-pixel: "Silkscreen", "Courier New", monospace;

  --container: 1180px;
  --radius: 0;
  --border-w: 2px;

  /* Motion tokens — the CSS half of the set in js/main.js (MOTION).
     --ease is the cubic-bezier equivalent of GSAP's power3.out, so a CSS
     transition and a GSAP tween on the same element move the same way. */
  --t-fast: .3s;
  --t-base: .6s;
  --ease: cubic-bezier(.165, .84, .44, 1);
}

* { box-sizing: border-box; }

/* Lenis handles smooth scroll in JS; native smooth-scroll would fight it */
html.lenis { scroll-behavior: auto; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* Safety net only. Clip here does NOT stop the viewport scrolling sideways —
     anything that overhangs has to be clipped by its own wrapper (see
     .slash-wrap). Kept because it costs nothing and catches lesser strays,
     and because `clip` avoids turning body into a scroll container the way
     `hidden` would, which breaks the sticky header. */
  overflow-x: clip;
}

/* Sections carry absolutely-positioned stickers */
.section { position: relative; }

img { max-width: 100%; display: block; }

a { color: inherit; text-decoration: none; }

/* Holds the SVG filter defs at the end of index.html out of layout */
.svg-defs { position: absolute; width: 0; height: 0; }

/* ============================================
   Preloader
   ============================================ */
body.is-loading { overflow: hidden; }
.preloader {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 26px;
  transition: opacity var(--t-base) var(--ease), visibility var(--t-base);
}
.preloader.done { opacity: 0; visibility: hidden; }
.preloader .chain {
  width: min(280px, 52vw);
  height: auto;
  color: var(--text);
  /* the halves fly past the viewBox when the joint gives */
  overflow: visible;
}
.preloader-bar {
  width: min(320px, 60vw);
  height: var(--border-w);
  background: var(--border);
  overflow: hidden;
}
.preloader-bar span {
  display: block;
  width: 100%; height: 100%;
  background: var(--text);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-fast) var(--ease);
}
.preloader-count {
  font-family: var(--font-pixel);
  font-size: 16px;
  letter-spacing: .1em;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 24px;
}

/* Custom cursor — desktop only, see js/main.js for the toggle */
.cursor-dot {
  position: fixed;
  top: 0; left: 0;
  width: 22px; height: 22px;
  border: 1.5px solid var(--accent);
  border-radius: 50%;
  pointer-events: none;
  z-index: 9999;
  transform: translate(-50%, -50%);
  transition: width var(--t-fast) var(--ease), height var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
  mix-blend-mode: difference;
}
.cursor-dot.hover { width: 40px; height: 40px; }
body.has-custom-cursor, body.has-custom-cursor a, body.has-custom-cursor button {
  cursor: none;
}

/* ============================================
   Header
   ============================================ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 500;
  background: rgba(10, 10, 10, 0.94);
  backdrop-filter: blur(6px);
  border-bottom: var(--border-w) solid var(--text);
}
.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 72px;
  gap: 24px;
}
.site-header .logo img { height: 26px; }
.site-nav { display: flex; gap: 28px; }
.site-nav a {
  font-size: 13px;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  transition: color var(--t-fast) var(--ease);
}
.site-nav a:hover { color: var(--text); }
.header-icons { display: flex; align-items: center; gap: 18px; font-size: 13px; color: var(--text-dim); }

/* ============================================
   Hero
   ============================================ */
.hero {
  position: relative;
  min-height: 94vh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
  padding: 40px 24px 56px;
  border-bottom: var(--border-w) solid var(--text);
}
.hero-bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: 0;
  filter: grayscale(0.15) contrast(1.1);
}
.hero-bg-overlay {
  position: absolute; inset: 0;
  z-index: 1;
  background: linear-gradient(to top, rgba(10,10,10,.95) 5%, rgba(10,10,10,.35) 55%, rgba(10,10,10,.55) 100%);
}
.hero-topline {
  position: relative; z-index: 2;
  display: flex; align-items: center; justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--text);
  border-bottom: 1px solid var(--text);
  padding-bottom: 16px;
  margin-bottom: auto;
}
.hero-badge img { height: 30px; }
.hero-inner { position: relative; z-index: 2; }
.hero-headline {
  font-family: var(--font-display);
  /* Unbounded sets far wider than the system stack this replaced, so the scale
     comes down and the tracking tightens to keep "repeat." on one line. */
  font-size: clamp(38px, 8.2vw, 116px);
  font-weight: 900;
  line-height: 0.92;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  margin: 0 0 20px;
  max-width: 12ch;
}
/* Each line is its own mask so the intro can slide it up from behind the edge.
   The padding/margin pair buys room for descenders that the tight line-height
   would otherwise let overflow: hidden clip. */
.hero-headline .line {
  display: block;
  overflow: hidden;
  /* Unbounded drops deeper than the old stack — the mask needs more room */
  padding-bottom: .16em;
  margin-bottom: -.16em;
}
.hero-headline .line > span { display: block; }
.hero-headline .rule { color: var(--pink); }
.hero-tagline {
  font-size: 15px;
  color: var(--text);
  max-width: 480px;
  border-left: var(--border-w) solid var(--pink);
  padding-left: 14px;
}

/* Decorative floating chrome object — CSS-only pass 1.
   Upgrade path: swap for a Three.js scene reusing the MBARE can setup. */
.chrome-float {
  position: absolute;
  width: 120px;
  opacity: 0.9;
  z-index: 2;
  animation: float 7s ease-in-out infinite;
  filter: drop-shadow(0 12px 24px rgba(0,0,0,.6));
}
.chrome-float.a { top: 12%; left: 8%; animation-delay: 0s; }
.chrome-float.b { bottom: 10%; right: 8%; width: 100px; animation-delay: -3s; }
@keyframes float {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50% { transform: translateY(-18px) rotate(6deg); }
}

/* ============================================
   Ticker
   ============================================ */
.ticker {
  background: var(--acid);
  color: #0a0a0a;
  overflow: hidden;
  white-space: nowrap;
  border-top: var(--border-w) solid var(--text);
  border-bottom: var(--border-w) solid var(--text);
}
.ticker-track {
  display: inline-flex;
  animation: ticker 22s linear infinite;
}
.ticker-track span {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 10px 20px;
  text-transform: uppercase;
}
@keyframes ticker {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* ============================================
   Section shell + reveal
   ============================================ */
.section { padding: 96px 0; }
.section-head { margin-bottom: 40px; }
.section-num {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-dim);
  margin-bottom: 8px;
}
.section-title {
  font-family: var(--font-display);
  font-size: clamp(22px, 3.2vw, 38px);
  font-weight: 700;
  margin: 0;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  text-wrap: balance;
}

/* Entrance states are now owned by GSAP (see js/main.js).
   This is a no-JS / JS-failure fallback so content is never stuck invisible. */
.reveal { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .chrome-float, .ticker-track { animation: none; }
}

/* ============================================
   Manifesto
   ============================================ */
.manifesto { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 48px; align-items: center; }
.manifesto p { color: var(--text-dim); font-size: 15px; max-width: 46ch; }
.manifesto-list { list-style: none; margin: 24px 0 0; padding: 0; font-family: var(--font-mono); font-size: 13px; }
.manifesto-list li { padding: 8px 0; border-top: 1px solid var(--border); color: var(--text-dim); }
.manifesto-list li:last-child { border-bottom: 1px solid var(--border); }
.manifesto img { border-radius: var(--radius); }

/* ============================================
   Product grid
   ============================================ */
.drop-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 20px;
}
.product-card {
  --card-accent: var(--accent);
  position: relative;
  background: var(--surface);
  border: var(--border-w) solid var(--card-accent);
  overflow: hidden;
  cursor: pointer;
}
.product-card[data-accent="rage"]   { --card-accent: var(--rage); }
.product-card[data-accent="acid"]   { --card-accent: var(--acid); }
.product-card[data-accent="pink"]   { --card-accent: var(--pink); }
.product-card[data-accent="vhs"]    { --card-accent: var(--vhs); }
.product-card[data-accent="chrome"] { --card-accent: var(--chrome); }

.product-badge {
  position: absolute;
  top: 0; left: 0;
  background: var(--card-accent);
  color: #0a0a0a;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.05em;
  padding: 5px 10px;
  z-index: 2;
}
.product-photo { position: relative; aspect-ratio: 4 / 5; overflow: hidden; background: #000; }
.product-photo > img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}

/* Hover glitch: two channel-isolated copies of the shot (filters live at the
   end of index.html) screen-blended back into a whole, then pulled apart.
   The base image steps aside on hover so the two halves recombine cleanly
   instead of washing out against it. */
.product-photo .ghost {
  position: absolute; inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  mix-blend-mode: screen;
  pointer-events: none;
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.product-photo .ghost-r { filter: url(#chan-r); }
.product-photo .ghost-c { filter: url(#chan-c); }

.product-card:hover .product-photo > img,
.product-card.is-glitching .product-photo > img { opacity: 0; transform: scale(1.04); }
.product-card:hover .ghost,
.product-card.is-glitching .ghost { opacity: 1; }
.product-card:hover .ghost-r { transform: translate(4px, -2px) scale(1.04); }
.product-card:hover .ghost-c { transform: translate(-4px, 2px) scale(1.04); }

/* Touch has no hover, so the effect is driven by position instead — see
   setupTouchGlitch(). The split is halved: on hover it is a moment, here it is
   a state the photo has to stay readable in. */
.product-card.is-glitching .ghost-r { transform: translate(2px, -1px) scale(1.02); }
.product-card.is-glitching .ghost-c { transform: translate(-2px, 1px) scale(1.02); }

.product-info { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; }
.product-info .name { font-size: 13px; }
.product-info .price { font-size: 13px; color: var(--text-dim); }

/* ============================================
   Featured banner
   ============================================ */
.featured {
  position: relative;
  min-height: 60vh;
  display: flex;
  align-items: flex-end;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
}
.featured img.bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: .6;
}
.featured-content { position: relative; z-index: 2; padding: 48px; }
.featured-content h3 {
  font-family: var(--font-display);
  font-size: clamp(24px, 3vw, 34px);
  font-weight: 700;
  letter-spacing: -0.03em;
  margin: 0 0 20px;
  max-width: 13ch;
  line-height: 1.15;
  text-wrap: balance;
}
.featured-content .accent { color: var(--rage); }
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  border: var(--border-w) solid var(--text);
  padding: 12px 20px;
  font-size: 13px;
  letter-spacing: 0.04em;
  border-radius: 2px;
  background: transparent;
  color: var(--text);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.btn:hover { background: var(--text); color: var(--bg); }

/* ============================================
   Poster archive
   ============================================ */
/* Pinned horizontal run. The section holds still while the track is scrubbed
   sideways; below 720px it drops back to an ordinary stacked grid, where a
   pinned sideways scroll fights the thumb rather than rewarding it. */
.archive {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 36px;
  overflow: hidden;
}
.archive .section-head { margin-bottom: 0; }
.archive-meta {
  display: flex;
  align-items: center;
  gap: 16px;
}
.archive-count {
  font-family: var(--font-pixel);
  font-size: 15px;
  letter-spacing: .08em;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.archive-progress {
  flex: 1;
  height: var(--border-w);
  background: var(--border);
  overflow: hidden;
}
.archive-progress span {
  display: block;
  width: 100%; height: 100%;
  background: var(--text);
  transform: scaleX(0);
  transform-origin: left;
}

/* The stage is one poster-shaped frame; the four posters stack inside it and
   the scrub deals them one over the next. Sized off viewport height so the
   whole sequence always fits the pinned frame at any resolution. */
.poster-grid {
  position: relative;
  height: min(66vh, 700px);
  aspect-ratio: 3 / 4;
  margin: 0 auto;
  overflow: hidden;
  border: var(--border-w) solid var(--text);
}
.poster-card {
  position: absolute;
  inset: 0;
  cursor: pointer;
}
.poster-card img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--t-base) var(--ease); }
.poster-card:hover img { transform: scale(1.05); }
.poster-label {
  position: absolute; bottom: 0; left: 0; right: 0;
  padding: 14px;
  background: linear-gradient(to top, rgba(0,0,0,.85), transparent);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-dim);
}

/* ============================================
   Footer
   ============================================ */
.site-footer { border-top: var(--border-w) solid var(--text); padding: 32px 0; }
.site-footer .wrap {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 16px;
}
.site-footer .logo img { height: 20px; }
.footer-links { display: flex; gap: 20px; font-size: 12px; color: var(--text-dim); }
.footer-social { display: flex; gap: 14px; }

/* ============================================
   Product modal
   ============================================ */
.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(0,0,0,.8);
  display: none;
  align-items: center; justify-content: center;
  z-index: 1000;
  padding: 24px;
}
.modal-overlay.open { display: flex; }
.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  max-width: 720px;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  overflow: hidden;
  max-height: 86vh;
}
.modal img { width: 100%; height: 100%; object-fit: cover; }
.modal-body { padding: 32px; position: relative; }
.modal-body .price { color: var(--text-dim); margin: 8px 0 20px; }
.modal-close {
  position: absolute; top: 16px; right: 16px;
  background: none; border: none; color: var(--text);
  font-size: 20px; cursor: pointer;
}
.modal-cart-note {
  margin-top: 24px; font-size: 12px; color: var(--text-dim);
  border-top: 1px solid var(--border); padding-top: 16px;
}

/* ============================================
   Mobile navigation

   Below 720px the desktop nav is hidden, and until now nothing replaced it —
   the site had no navigation at all on a phone.
   ============================================ */
.nav-toggle {
  display: none;
  font-family: var(--font);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text);
  background: transparent;
  border: var(--border-w) solid var(--text);
  padding: 7px 12px;
  cursor: pointer;
}
.nav-toggle:focus-visible { outline: 2px solid var(--pink); outline-offset: 3px; }

.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: 800;
  background: var(--bg);
  display: flex;
  flex-direction: column;
}
/* higher specificity than the display:flex above, so the attribute really hides it */
.mobile-nav[hidden] { display: none; }
.mobile-nav-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 72px;
  padding: 0 24px;
  border-bottom: var(--border-w) solid var(--text);
}
.mobile-nav-head img { height: 26px; }
.mobile-nav-links {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 24px;
}
.mobile-nav-links a {
  display: flex;
  align-items: baseline;
  gap: 14px;
  font-family: var(--font-display);
  font-size: clamp(26px, 9vw, 44px);
  font-weight: 700;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  padding: 14px 0;
  border-bottom: 1px solid var(--border);
}
.mobile-nav-links a span {
  font-family: var(--font-pixel);
  font-size: 13px;
  color: var(--pink);
  letter-spacing: 0;
}
.mobile-nav-foot .spec { margin: 0; border: 0; padding: 16px 24px 24px; }

/* ============================================
   Texture kit

   The density is five reusable parts, not a pile of one-offs: the noise layer,
   the marquee, the tape rule, the sticker and the spec row. Every sticker
   caption is copy that already exists elsewhere on the site — poster titles,
   ticker lines, manifesto points — so the clutter reads as the brand talking
   over itself rather than as filler.
   ============================================ */

/* Full-page grain + CRT scanlines. Sits above the header, below the modal,
   and never eats a click. Plain opacity rather than a blend mode: the page
   already carries enough compositing work. */
.fx-layer {
  position: fixed;
  inset: 0;
  z-index: 900;
  pointer-events: none;
}
.fx-layer::before,
.fx-layer::after { content: ""; position: absolute; }
.fx-layer::before {
  /* oversized so the drift never exposes an edge */
  inset: -50%;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: .14;
  animation: grain 5s steps(5) infinite;
}
.fx-layer::after {
  inset: 0;
  background: repeating-linear-gradient(to bottom, rgba(0,0,0,.30) 0 1px, transparent 1px 3px);
  opacity: .5;
}
@keyframes grain {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(-3%, 2%); }
  40%  { transform: translate(2%, -3%); }
  60%  { transform: translate(-2%, -2%); }
  80%  { transform: translate(3%, 1%); }
  100% { transform: translate(0, 0); }
}

/* Marquee variants on the existing .ticker component */
.ticker--rage { background: var(--rage); color: var(--text); }
.ticker--chrome { background: var(--chrome); color: #0a0a0a; }
.ticker--reverse .ticker-track { animation-direction: reverse; }
/* The tilt makes the bar overhang on both sides and stand taller than its own
   box, so it is clipped here rather than at body level — an overhang that
   reaches the viewport lets the whole page be dragged sideways. The vertical
   padding is the room the rotation needs. */
.slash-wrap {
  overflow: hidden;
  padding: 46px 0;
  margin: 26px 0;
}
.ticker--slash {
  /* scaled past the viewport so the tilt leaves no bare corners */
  transform: rotate(-2.6deg) scaleX(1.08);
  position: relative;
  z-index: 4;
}

/* Hazard rule */
.tape {
  height: 24px;
  background: repeating-linear-gradient(45deg, var(--vhs) 0 14px, #0a0a0a 14px 28px);
  border-top: var(--border-w) solid var(--text);
  border-bottom: var(--border-w) solid var(--text);
}
.tape--rage { background: repeating-linear-gradient(45deg, var(--rage) 0 14px, #0a0a0a 14px 28px); }

/* Sticker */
.sticker {
  position: absolute;
  z-index: 5;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 6px 10px;
  white-space: nowrap;
  background: var(--bg);
  color: var(--text);
  border: var(--border-w) solid currentColor;
}
.sticker.is-acid   { color: var(--acid); }
.sticker.is-rage   { color: var(--rage); }
.sticker.is-chrome { color: var(--chrome); }
.sticker.is-pink   { color: var(--pink); }
.sticker.is-solid-acid { background: var(--acid); border-color: var(--acid); color: #0a0a0a; }
.sticker.is-solid-vhs  { background: var(--vhs);  border-color: var(--vhs);  color: #0a0a0a; }
.sticker.is-solid-pink { background: var(--pink); border-color: var(--pink); color: #0a0a0a; }
.rot-a { rotate: -7deg; }
.rot-b { rotate: 5deg; }
.rot-c { rotate: -12deg; }
.rot-d { rotate: 9deg; }

/* Spec row — the care-label voice, used wherever a section needs a footnote */
.spec {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-dim);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: 8px 0;
  margin-top: 18px;
}
.spec b { color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; }

/* Barcode, drawn from a seed string in js/main.js */
.barcode {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 40px;
}
.barcode i { display: block; background: var(--text); height: 100%; }

/* Halftone ground behind the manifesto */
.section--dots { position: relative; overflow: hidden; }
.section--dots > .dots {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: radial-gradient(var(--border) 1.5px, transparent 1.5px);
  background-size: 14px 14px;
  opacity: .55;
  pointer-events: none;
}
.section--dots > .wrap { position: relative; z-index: 1; }

/* Y2K chrome type. The child .accent keeps its own solid colour, which is what
   makes the pairing read. */
.chrome-type {
  background: linear-gradient(180deg, #ffffff 0%, #b9c6d2 26%, #6b7a89 46%, #eaf3fb 54%, #8fa2b3 74%, #ffffff 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.footer-spec {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  flex-wrap: wrap;
  padding-bottom: 24px;
  margin-bottom: 24px;
  border-bottom: 1px solid var(--border);
}

@media (prefers-reduced-motion: reduce) {
  .fx-layer::before { animation: none; }
}

@media (max-width: 720px) {
  .site-nav { display: none; }
  .nav-toggle { display: block; }
  .sticker { font-size: 9px; padding: 4px 7px; }
  .slash-wrap { padding: 34px 0; margin: 12px 0; }
  .footer-spec { flex-direction: column; align-items: flex-start; }
  .manifesto { grid-template-columns: 1fr; }
  .modal { grid-template-columns: 1fr; overflow-y: auto; }
  .hero { min-height: 70vh; padding: 60px 20px; }

  /* Swipe archive: no pin, no stack. Native scroll-snap does the work the
     scrub does on desktop — the thumb is already the right instrument. */
  .archive { min-height: 0; display: block; overflow: visible; }
  .archive .section-head { margin-bottom: 28px; }
  .poster-grid {
    position: static;
    display: flex;
    gap: 14px;
    height: auto;
    aspect-ratio: auto;
    border: 0;
    padding: 0 24px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .poster-grid::-webkit-scrollbar { display: none; }
  .poster-card {
    position: relative;
    flex: 0 0 78%;
    aspect-ratio: 3 / 4;
    scroll-snap-align: center;
    border: var(--border-w) solid var(--text);
  }
  .archive-meta { margin-top: 20px; }
}

