    /* ─── Design tokens ─────────────────────────────────── */
    /* Zine / streetwear-editorial system. The page turns like a magazine:
       each section commits to its own flat, poster-like ground and scrolling
       through them reads as turning pages. Contrast comes from FLAT colour
       against TEXTURED photography, not from darkness. */
    :root {
      /* Grounds — expired-film palette, all slightly desaturated and warm. */
      --cream:    #EDE3D1;             /* paper                          */
      --cream-2:  #E3D7C0;             /* paper, one step down           */
      --orange:   #C9542A;             /* burnt / faded poster orange    */
      --teal:     #3F7D77;             /* washed teal                    */
      --ink:      #17150F;             /* warm off-black                 */
      --ink-2:    #221F17;

      /* Ink-on-paper and paper-on-ink text ramps. */
      --on-light:   #17150F;
      --on-light-2: #5A5245;
      --on-light-3: #8A8072;
      --on-dark:    #F2EADA;
      --on-dark-2:  #A79E8C;
      --on-dark-3:  #6E6657;

      /* Per-section variables. Each .band-* block re-points these, so every
         component below can be written once against --fg / --bg / --rule
         instead of being duplicated per colourway. */
      --bg:   var(--ink);
      --fg:   var(--on-dark);
      --fg-2: var(--on-dark-2);
      --fg-3: var(--on-dark-3);
      --rule:      rgba(242,234,218,0.16);
      --rule-soft: rgba(242,234,218,0.08);

      --display: 'Anton', 'Arial Narrow', sans-serif;
      --sans: 'Space Grotesk', sans-serif;
      --mono: 'Space Mono', 'Courier New', ui-monospace, monospace;

      --gutter: 48px;
      --measure: 1440px;

      --ease: cubic-bezier(0.22, 1, 0.36, 1);
    }

    /* ── Section grounds ─────────────────────────────────
       Applied per <section> to alternate the page like zine spreads. */
    .band-cream  { --bg: var(--cream);  --fg: var(--on-light); --fg-2: var(--on-light-2); --fg-3: var(--on-light-3);
                   --rule: rgba(23,21,15,0.18); --rule-soft: rgba(23,21,15,0.09); }
    .band-cream2 { --bg: var(--cream-2); --fg: var(--on-light); --fg-2: var(--on-light-2); --fg-3: var(--on-light-3);
                   --rule: rgba(23,21,15,0.18); --rule-soft: rgba(23,21,15,0.09); }
    .band-ink    { --bg: var(--ink);    --fg: var(--on-dark);  --fg-2: var(--on-dark-2);  --fg-3: var(--on-dark-3);
                   --rule: rgba(242,234,218,0.16); --rule-soft: rgba(242,234,218,0.08); }
    .band-orange { --bg: var(--orange); --fg: #FFF3E4;         --fg-2: rgba(255,243,228,0.82); --fg-3: rgba(255,243,228,0.62);
                   --rule: rgba(255,243,228,0.30); --rule-soft: rgba(255,243,228,0.16); }
    .band-teal   { --bg: var(--teal);   --fg: #F0F6F2;         --fg-2: rgba(240,246,242,0.82); --fg-3: rgba(240,246,242,0.60);
                   --rule: rgba(240,246,242,0.30); --rule-soft: rgba(240,246,242,0.16); }

    .band-cream, .band-cream2, .band-ink, .band-orange, .band-teal {
      background: var(--bg);
      color: var(--fg);
    }

    /* ─── Reset ─────────────────────────────────────────── */
    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
    /* No scroll-behavior here — Lenis owns scrolling (see js/motion.js).
       motion.js re-enables native smooth scroll if Lenis is unavailable. */
    html { scroll-behavior: auto; }
    body {
      background: var(--ink);
      color: var(--on-dark);
      font-family: var(--sans);
      overflow-x: hidden;
      -webkit-font-smoothing: antialiased;
    }
    a { color: inherit; text-decoration: none; }
    button { cursor: pointer; border: none; background: none; font-family: inherit; }
    input, select, textarea { font-family: inherit; }

    
    /* ─── Gradient utility ──────────────────────────── */
    .grad-bg {
      background: linear-gradient(135deg, #FF8C3A 0%, #FFD23F 28%, #A8E063 50%, #56CFE1 72%, #9B5FD4 100%);
    }
    .grad-border {
      border: 1.5px solid transparent;
      background-clip: padding-box;
      position: relative;
    }
    .grad-border::before {
      content: '';
      position: absolute; inset: -1.5px;
      border-radius: inherit;
      background: linear-gradient(135deg, #FF8C3A, #FFD23F, #A8E063, #56CFE1, #9B5FD4);
      z-index: -1;
    }

    /* ─── Film grain overlay ─────────────────────────── */
    body::after {
      content: '';
      position: fixed; inset: 0; z-index: 9990;
      pointer-events: none;
      background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
      opacity: 0.35;
      mix-blend-mode: overlay;
    }

    /* ─── Nav ───────────────────────────────────────── */
    nav {
      position: fixed; top: 0; left: 0; right: 0; z-index: 900;
      display: flex; align-items: center; justify-content: space-between;
      padding: 20px 48px;
      transition: background 0.4s ease, backdrop-filter 0.4s ease;
    }
    nav.scrolled {
      background: rgba(8,8,8,0.85);
      backdrop-filter: blur(16px);
      border-bottom: 1px solid rgba(255,255,255,0.06);
    }
    /* Original wordmark, using the trimmed file. The source logo.png is
       1224x818 but the mark only occupies 565x116 of it — 86% of that PNG is
       transparent padding, so a 48px height rendered a ~7px wordmark. Cropped
       to its alpha bounds, this height is the actual mark height. */
    .nav-logo__stack { position: relative; display: block; }
    .nav-logo img {
      height: 34px; width: auto; display: block;
      /* brightness(0) invert(1) flattens the artwork to pure white. */
      filter: brightness(0) invert(1);
    }
    /* Outline artwork — the "empty" state. Kept clearly legible rather than
       ghosted, so the wordmark always reads; the fill is what changes. */
    .nav-logo__base { opacity: 0.72; }
    /* SOLID letterforms, revealed left-to-right by scroll progress. Generated
       from the outline by filling its enclosed counters, so the two files are
       the same dimensions and register pixel-for-pixel. */
    .nav-logo__fill {
      position: absolute; top: 0; left: 0;
      clip-path: inset(0 calc(100% - var(--fill, 0%)) 0 0);
    }
    /* No transition on the clip — it is driven directly from scroll position,
       so easing it would make the fill lag the page. */
    .nav-links { display: flex; gap: 36px; font-size: 13px; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: rgba(255,255,255,0.7); }
    .nav-links a:hover { color: #fff; }
    .nav-right { display: flex; align-items: center; gap: 16px; }
    .nav-social {
      width: 36px; height: 36px; border-radius: 50%;
      background: rgba(255,255,255,0.07);
      border: 1px solid rgba(255,255,255,0.1);
      display: flex; align-items: center; justify-content: center;
      transition: background 0.2s, border-color 0.2s;
    }
    .nav-social:hover { background: rgba(255,255,255,0.14); border-color: rgba(255,255,255,0.2); }
    .nav-social svg { width: 15px; height: 15px; fill: rgba(255,255,255,0.7); }
    .nav-social:hover svg { fill: #fff; }
    .nav-divider { width: 1px; height: 20px; background: rgba(255,255,255,0.1); }
    .cart-btn {
      position: relative;
      width: 44px; height: 44px; border-radius: 50%;
      background: rgba(255,255,255,0.07);
      border: 1px solid rgba(255,255,255,0.12);
      display: flex; align-items: center; justify-content: center;
      transition: background 0.2s;
    }
    .cart-btn:hover { background: rgba(255,255,255,0.13); }
    .cart-btn svg { width: 20px; height: 20px; stroke: #fff; fill: none; }
    .cart-count {
      position: absolute; top: -4px; right: -4px;
      width: 18px; height: 18px; border-radius: 50%;
      background: linear-gradient(135deg,#FF8C3A,#9B5FD4);
      font-size: 10px; font-weight: 700;
      display: flex; align-items: center; justify-content: center;
      display: none;
    }
    .cart-count.show { display: flex; }

    /* ─── Ticker ─────────────────────────────────────── */
    /* Was a full-bleed rainbow bar. Now a hairline-bounded mono strip — it
       reads as a caption rule in a magazine rather than a banner ad. */
    .ticker-wrap {
      overflow: hidden; white-space: nowrap;
      background: var(--ink);
      border-top: 1px solid var(--rule-soft);
      border-bottom: 1px solid var(--rule-soft);
      padding: 18px 0;
    }
    .ticker-inner {
      display: inline-flex; gap: 0;
      animation: ticker 60s linear infinite;
    }
    .ticker-inner span {
      font-family: var(--mono);
      font-size: 11px; font-weight: 400; letter-spacing: 0.22em;
      text-transform: uppercase; color: var(--fg-3);
      padding: 0 28px;
    }
    .ticker-inner .dot { color: var(--fg-3); opacity: 0.45; padding: 0; }
    @keyframes ticker { from { transform: translateX(0); } to { transform: translateX(-50%); } }
    @media (prefers-reduced-motion: reduce) { .ticker-inner { animation: none; } }

    /* ─── Shared editorial primitives ─────────────────── */
    /* Mono metadata: the frame-number / ISO / location layer. Lifted from the
       brand's own poster art ("STORIES BEHIND THE LENS."). */
    .meta {
      font-family: var(--mono);
      font-size: 11px; font-weight: 400;
      letter-spacing: 0.22em; text-transform: uppercase;
      color: var(--fg-3);
    }

    /* ─── Hero ───────────────────────────────────────── */
    /* The rotating 3D render occupies the hero's right column — the slot the
       product photograph used to hold — at full column scale. Anton headline
       stacked left against it. */
    .hero {
      position: relative;
      min-height: 100svh;
      display: flex; flex-direction: column; justify-content: flex-end;
      padding: 0;
      overflow: hidden;
      isolation: isolate;
    }

    .hero-content {
      position: relative; z-index: 2;
      flex: 1;
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr);
      align-items: center;
      gap: 40px;
      width: 100%;
      padding: 118px var(--gutter) 0 var(--gutter);
    }

    /* ── The render ── */
    .hero-figure {
      position: relative;
      display: flex; flex-direction: column;
      align-items: center; justify-content: center;
      gap: 18px;
      min-height: 0;
      align-self: stretch;
    }
    #cam3d { position: relative; width: 100%; max-width: 720px; }
    /* Studio falloff behind the render. Without something to sit against, a
       dark product on a near-black page has no silhouette at all — the rim
       light in the shader separates the edges, and this separates the mass. */
    #cam3d::before {
      content: '';
      position: absolute;
      left: 50%; top: 50%;
      width: 86%; aspect-ratio: 1;
      transform: translate(-50%, -50%);
      border-radius: 50%;
      background: radial-gradient(circle,
        rgba(242,234,218,0.13) 0%,
        rgba(242,234,218,0.06) 40%,
        rgba(242,234,218,0.02) 62%,
        transparent 74%);
      pointer-events: none;
    }
    #cam3d-canvas {
      position: relative;
      display: block;
      width: 100%; height: auto;
      aspect-ratio: 1 / 1;
      filter: drop-shadow(0 18px 38px rgba(0,0,0,0.55));
      /* Drag to rotate. pan-y rather than none: a horizontal drag spins the
         model, but a vertical swipe still scrolls the page — trapping vertical
         touch inside a decorative canvas strands mobile users mid-hero. */
      cursor: grab;
      touch-action: pan-y;
    }
    #cam3d-canvas.is-grabbing { cursor: grabbing; }
    /* Retro pass. js/camera3d.js adds this class only when its RETRO flag is on,
       in which case the renderer draws into a small buffer and this upscales it
       nearest-neighbour so the pixels stay hard. */
    #cam3d-canvas.is-retro {
      image-rendering: pixelated;
      image-rendering: crisp-edges;
      filter: contrast(1.04) saturate(1.0) drop-shadow(0 18px 38px rgba(0,0,0,0.55));
    }
    .cam3d-meta {
      font-family: var(--mono);
      font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase;
      color: var(--fg-3);
      text-align: center;
    }

    .hero-text { padding-bottom: 0; max-width: 900px; }

    .hero-eyebrow {
      display: flex; align-items: center; gap: 14px;
      font-family: var(--mono);
      font-size: 11px; font-weight: 400; letter-spacing: 0.24em;
      text-transform: uppercase; color: var(--fg-2);
      margin-bottom: 26px;
    }
    .hero-eyebrow::before {
      content: ''; width: 40px; height: 1px;
      background: var(--rule); flex-shrink: 0;
    }

    /* Anton, stacked, one word per line, jammed tight. Negative leading is
       deliberate — poster lettering nests rather than sits on baselines. */
    .hero-headline {
      font-family: var(--display);
      font-weight: 400;
      font-size: clamp(64px, 12vw, 190px);
      line-height: 0.80;
      letter-spacing: -0.015em;
      text-transform: uppercase;
      color: var(--fg);
      margin-bottom: 30px;
      display: flex; flex-direction: column;
    }
    .hero-headline span { display: block; }
    /* Outlined word — classic zine cover device, and it lets the render read
       through the type instead of being blocked by it. */
    .hero-headline .outline {
      color: transparent;
      -webkit-text-stroke: 2px var(--fg);
      text-stroke: 2px var(--fg);
    }

    .hero-sub {
      font-size: 15px; line-height: 1.6;
      color: var(--fg-2);
      max-width: 38ch;
      margin-bottom: 32px;
      font-weight: 400;
      font-family: var(--sans);
    }
    .hero-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }


    /* ── Buttons: flat poster blocks ── */
    .btn-primary {
      display: inline-flex; align-items: center; gap: 10px;
      padding: 16px 30px;
      border-radius: 0;
      background: var(--orange);
      color: #FFF3E4; font-weight: 700; font-size: 12px;
      letter-spacing: 0.16em; text-transform: uppercase;
      font-family: var(--mono);
      border: 1px solid var(--orange);
      transition: background 0.3s var(--ease), color 0.3s var(--ease), border-color 0.3s var(--ease);
    }
    .btn-primary:hover { background: var(--fg); color: var(--bg); border-color: var(--fg); }

    .btn-ghost {
      display: inline-flex; align-items: center; gap: 8px;
      padding: 16px 30px; border-radius: 0;
      border: 1px solid var(--rule);
      color: var(--fg-2); font-size: 12px; font-weight: 400;
      letter-spacing: 0.16em; text-transform: uppercase;
      font-family: var(--mono);
      transition: border-color 0.3s var(--ease), color 0.3s var(--ease);
    }
    .btn-ghost:hover { border-color: var(--fg); color: var(--fg); }

    /* ── Bottom metadata rail: film-stamp data across the full width ── */
    .hero-meta {
      position: relative; z-index: 2;
      display: flex; align-items: center; gap: 32px; flex-wrap: wrap;
      border-top: 1px solid var(--rule);
      margin: 0 var(--gutter);
      padding: 20px 0 24px;
      font-family: var(--mono);
      font-size: 11px; letter-spacing: 0.22em; text-transform: uppercase;
      color: var(--fg-3);
    }
    .hero-meta b { font-weight: 400; color: var(--fg); }
    .hero-meta .spacer { margin-left: auto; }

    .scroll-cue {
      display: inline-flex; align-items: center; gap: 10px;
      color: var(--fg-3);
    }
    .scroll-line {
      width: 44px; height: 1px; background: var(--rule);
      position: relative; overflow: hidden;
    }
    .scroll-line::after {
      content: ''; position: absolute; inset: 0;
      background: var(--fg);
      transform: translateX(-100%);
      animation: scroll-sweep 2.6s var(--ease) infinite;
    }
    @keyframes scroll-sweep {
      0%   { transform: translateX(-100%); }
      55%  { transform: translateX(100%); }
      100% { transform: translateX(100%); }
    }
    @media (prefers-reduced-motion: reduce) { .scroll-line::after { animation: none; } }

    /* ─── Section base ──────────────────────────────── */
    section { position: relative; z-index: 2; }
    .container { max-width: 1280px; margin: 0 auto; padding: 0 48px; }
    .section-label {
      display: inline-flex; align-items: center; gap: 10px;
      font-size: 10px; font-weight: 700; letter-spacing: 0.3em;
      text-transform: uppercase; color: rgba(255,255,255,0.35);
      margin-bottom: 20px;
    }
    .section-label::before {
      content: ''; width: 20px; height: 1px;
      background: linear-gradient(90deg,#FF8C3A,#9B5FD4);
    }

    /* ─── Product section ────────────────────────────── */
    .product-section { padding: 100px 0 120px; }
    .product-section .section-header { margin-bottom: 64px; }
    .section-title {
      font-size: clamp(36px,4.5vw,64px);
      font-weight: 700; line-height: 1.05; letter-spacing: -0.02em;
      margin-bottom: 16px;
    }
    .section-desc {
      font-size: 16px; color: rgba(255,255,255,0.45);
      font-family: 'Inter', sans-serif; font-weight: 400;
      max-width: 520px; line-height: 1.65;
    }

    .product-grid {
      display: grid; grid-template-columns: repeat(3,1fr);
      gap: 20px;
    }

    .product-card {
      position: relative;
      background: #111;
      border-radius: 24px;
      border: 1px solid rgba(255,255,255,0.07);
      overflow: hidden;
      transition: transform 0.3s ease, border-color 0.3s;
    }
    .product-card:hover {
      transform: translateY(-6px);
      border-color: rgba(255,255,255,0.14);
    }
    .product-card.featured {
      border-color: transparent;
      background: linear-gradient(#111,#111) padding-box,
                  linear-gradient(135deg,#FF8C3A,#FFD23F,#A8E063,#56CFE1,#9B5FD4) border-box;
    }

    .card-badge {
      position: absolute; top: 20px; right: 20px; z-index: 2;
      background: linear-gradient(135deg,#FF8C3A,#9B5FD4);
      color: #fff; font-size: 10px; font-weight: 700;
      letter-spacing: 0.12em; text-transform: uppercase;
      padding: 5px 12px; border-radius: 100px;
    }

    .card-image {
      background: #fff;
      display: flex; align-items: center; justify-content: center;
      padding: 24px 16px; min-height: 300px;
      position: relative; overflow: hidden;
    }
    .card-image > img {
      max-height: 260px; max-width: 100%; object-fit: contain;
      position: relative; z-index: 1;
      transition: transform 0.4s cubic-bezier(0.34,1.56,0.64,1);
    }
    .product-card:hover .card-image > img { transform: scale(1.06) rotate(1.5deg); }
    .card-qty-display {
      position: absolute; top: 16px; left: 16px; z-index: 2;
      background: rgba(8,8,8,0.7); backdrop-filter: blur(8px);
      border: 1px solid rgba(255,255,255,0.1);
      border-radius: 8px; padding: 4px 10px;
      font-size: 11px; font-family: 'Courier New', monospace;
      color: rgba(255,255,255,0.5); letter-spacing: 0.08em;
    }

    .card-body { padding: 28px 28px 32px; }
    .card-name { font-size: 22px; font-weight: 700; margin-bottom: 6px; letter-spacing: -0.01em; }
    .card-tagline { font-size: 13px; color: rgba(255,255,255,0.4); font-family: 'Inter',sans-serif; margin-bottom: 20px; }
    .card-features { display: flex; flex-direction: column; gap: 8px; margin-bottom: 24px; }
    .card-feature {
      display: flex; align-items: center; gap: 8px;
      font-size: 13px; color: rgba(255,255,255,0.6); font-family:'Inter',sans-serif;
    }
    .card-feature::before {
      content: '';
      width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0;
      background: linear-gradient(135deg,#FF8C3A,#9B5FD4);
      display: flex; align-items: center; justify-content: center;
    }
    .card-feature svg { width: 8px; height: 8px; fill: #fff; }

    .card-footer { display: flex; align-items: center; justify-content: space-between; margin-top: 20px; }
    .card-price { font-size: 32px; font-weight: 700; letter-spacing: -0.02em; }
    .card-price .currency { font-size: 18px; vertical-align: super; font-weight: 500; }
    .card-price .per { font-size: 12px; color: rgba(255,255,255,0.35); font-weight: 400; margin-left: 4px; }

    .qty-control { display: flex; align-items: center; gap: 0; }
    .qty-btn {
      width: 32px; height: 32px; border-radius: 50%;
      background: rgba(255,255,255,0.08); color: #fff;
      font-size: 18px; font-weight: 300;
      display: flex; align-items: center; justify-content: center;
      transition: background 0.2s; border: none;
    }
    .qty-btn:hover { background: rgba(255,255,255,0.16); }
    .qty-val { width: 36px; text-align: center; font-size: 16px; font-weight: 600; }

    .add-to-cart {
      width: 100%; margin-top: 20px;
      padding: 14px; border-radius: 14px;
      background: linear-gradient(135deg,#FF8C3A 0%,#FFD23F 30%,#A8E063 55%,#56CFE1 78%,#9B5FD4 100%);
      color: #080808; font-size: 14px; font-weight: 700;
      letter-spacing: 0.06em; text-transform: uppercase;
      transition: transform 0.2s, box-shadow 0.2s;
      display: flex; align-items: center; justify-content: center; gap: 8px;
    }
    .add-to-cart:hover {
      transform: translateY(-2px);
      box-shadow: 0 12px 40px rgba(155,95,212,0.35);
    }
    .add-to-cart svg { width: 16px; height: 16px; }

    /* ─── Features section ───────────────────────────── */

    /* ─── How it works ──────────────────────────────── */
    /* No hard-coded background here. A class selector this far down the file
       out-ranks the .band-* rules, which left this section painting #0c0c0c
       while still using the light band's dark text colour — dark on dark.
       The band class on the <section> owns the colourway now. */

    /* ─── Gallery: 4x3 grid ───────────────────────────────
       Same behaviour as the live site — uniform grid, caption revealed on
       hover, click to open the lightbox — restyled onto the zine theme.
       The uniform grid keeps each tile near 330px, comfortably inside the
       ~542px source scans, which is what stopped the full-bleed versions
       from looking soft. */
    .gallery-section {
      position: relative;
      padding: 110px 0 100px;
    }

    .gallery-head {
      max-width: var(--measure); margin: 0 auto;
      padding: 0 var(--gutter) 52px;
      display: grid; grid-template-columns: minmax(0,1fr) minmax(0,320px);
      align-items: end; gap: 40px;
    }
    .gallery-head h2 {
      font-family: var(--display); font-weight: 400;
      font-size: clamp(44px, 7vw, 116px);
      letter-spacing: -0.015em; line-height: 0.82;
      text-transform: uppercase;
      color: var(--fg);
      display: flex; flex-direction: column;
    }
    .gallery-head h2 .outline {
      color: transparent;
      -webkit-text-stroke: 2px var(--fg);
      text-stroke: 2px var(--fg);
    }
    .gallery-head .gallery-index {
      text-align: right;
      border-top: 1px solid var(--rule);
      padding-top: 14px;
    }

    /* ── Set index ──────────────────────────────────────
       The cover plate. Sized like a spread rather than a thumbnail: at one
       set a small tile reads as an orphaned photo, where a full-measure
       plate reads as the cover of an archive that expects more. Add a
       second <article> and the grid splits to two columns on its own. */
    .set-index {
      max-width: var(--measure); margin: 0 auto;
      padding: 0 var(--gutter);
      display: grid;
      grid-template-columns: 1fr;
      gap: 20px;
      /* Each tile is as tall as its own cover. Grid items stretch to the row
         height by default, which would pad a landscape cover out to match a
         portrait one sharing its row and leave the plate floating off the
         image. */
      align-items: start;
    }

    /* Two columns and the row span are one decision, so they share a
       breakpoint. Driving the columns off auto-fit instead put the switch at
       a width the span rule could not see, and between the two thresholds the
       span opened a hole in a single-column grid.

       A portrait cover runs about twice the height of a landscape one, which
       left the tile beside it sitting over a column of dead space while the
       next set was pushed onto its own row. Spanning the tall tile across two
       rows stacks two landscape sets beside it instead. */
    @media (min-width: 1160px) {
      .set-index { grid-template-columns: repeat(2, 1fr); }
      .set-tile.is-tall { grid-row: span 2; }
    }

    .set-tile {
      position: relative;
      display: block;
      overflow: hidden;
      cursor: pointer;
      background: var(--ink-2);
      /* No fixed ratio: the cover sets the tile's shape, so a portrait frame
         stays whole instead of being cropped to a letterbox. min-height is a
         floor for the plate, not a shape — a very wide cover would otherwise
         be shorter than the title sitting on it. */
      min-height: 420px;
      border: 1px solid var(--rule);
      transition: transform 0.5s var(--ease), box-shadow 0.5s var(--ease),
                  border-color 0.5s var(--ease);
    }
    .set-tile:hover,
    .set-tile:focus-visible {
      transform: translateY(-4px);
      border-color: var(--fg-3);
      box-shadow: 0 26px 60px rgba(0,0,0,0.6);
      outline: none;
    }

    /* In flow, so its intrinsic height is what gives the tile its height. */
    .set-media { display: block; }
    .set-media img {
      width: 100%; height: auto; display: block;
      /* Nothing left to crop against now the tile follows the image, but a
         cover shorter than the 420px floor still has to fill it. */
      min-height: 420px;
      object-fit: cover;
      /* Same expired-film grade as the frames, so cover and contents read as
         one roll rather than two different stocks. */
      filter: sepia(0.22) saturate(1.16) contrast(0.93) brightness(1.05) hue-rotate(-6deg);
      transition: transform 0.7s var(--ease), filter 0.7s var(--ease);
    }
    .set-tile:hover .set-media img {
      transform: scale(1.045);
      filter: sepia(0.09) saturate(1.26) contrast(1.0) brightness(1.07) hue-rotate(-4deg);
    }

    /* The plate the title sits on. Weighted to the bottom so the scrim only
       darkens where type actually lands — a full-tile wash would flatten the
       photograph the cover is meant to be selling. */
    /* Overlays the cover now that the image, not the plate, sets the height. */
    .set-plate {
      position: absolute; inset: 0; z-index: 2;
      display: flex; flex-direction: column; justify-content: space-between;
      padding: 26px 30px 28px;
      background: linear-gradient(to top,
        rgba(23,21,15,0.90) 0%,
        rgba(23,21,15,0.55) 38%,
        rgba(23,21,15,0.10) 68%,
        rgba(23,21,15,0.28) 100%);
    }

    .set-plate-top,
    .set-plate-foot {
      display: flex; align-items: center; justify-content: space-between;
      gap: 16px;
      font-family: var(--mono);
      font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase;
      color: var(--on-dark-2);
    }
    .set-plate-top { border-bottom: 1px solid rgba(242,234,218,0.18); padding-bottom: 14px; }
    .set-plate-foot { border-top: 1px solid rgba(242,234,218,0.18); padding-top: 14px; }

    .set-title {
      font-family: var(--display); font-weight: 400;
      font-size: clamp(38px, 4.6vw, 74px);
      line-height: 0.84; letter-spacing: -0.015em;
      text-transform: uppercase;
      color: #F2EADA;
      display: flex; flex-direction: column;
      margin: 22px 0;
    }
    /* Last line hollow, matching the section headline's two-weight lockup. */
    .set-title .outline {
      color: transparent;
      -webkit-text-stroke: 1.5px #F2EADA;
      text-stroke: 1.5px #F2EADA;
    }
    /* The collab mark gets its own line between the two names. Set well below
       the display size deliberately: at full size a single "x" reads as a word
       in the title, where a small mark reads as the join between two names.
       Optically centred on the stroke rather than the em box, which is why the
       margins are uneven. */
    .set-title .set-x {
      font-family: var(--mono);
      font-size: 0.22em;
      line-height: 1;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      color: var(--on-dark-2);
      margin: 0.5em 0 0.62em;
    }

    .set-open { color: #F2EADA; display: inline-flex; align-items: center; gap: 8px; }
    .set-open i { font-style: normal; transition: transform 0.4s var(--ease); }
    .set-tile:hover .set-open i { transform: translateX(5px); }

    /* ── Set view ──────────────────────────────────────
       A full-screen takeover, not a panel that swaps in below the header.
       Opening a set should feel like going somewhere — leaving the frames
       inline meant the page still read as one long scroll with the archive
       sitting under it, which is exactly what the index is meant to replace.
       z-index sits under the lightbox (2000) so a frame still opens on top. */
    .set-view[hidden] { display: none; }
    .set-view {
      position: fixed; inset: 0; z-index: 1500;
      background: var(--ink);
      /* Re-point the band variables: fixed position takes this out of the
         .band-ink section, so --fg and --rule would otherwise fall back to
         :root and the bar would lose its contrast. */
      --fg: var(--on-dark); --fg-2: var(--on-dark-2); --fg-3: var(--on-dark-3);
      --rule: rgba(242,234,218,0.16);
      color: var(--fg);
      display: flex; flex-direction: column;
      animation: setIn 0.4s var(--ease) both;
    }
    @keyframes setIn {
      from { opacity: 0; transform: translateY(14px); }
      to   { opacity: 1; transform: none; }
    }

    /* Only the frames scroll; the bar is pinned, so the set title and the way
       back stay reachable however deep the set runs. */
    .set-scroll {
      flex: 1; min-height: 0;
      overflow-y: auto; -webkit-overflow-scrolling: touch;
      padding: 24px 0 60px;
    }

    .set-bar {
      flex-shrink: 0;
      width: 100%; max-width: var(--measure); margin: 0 auto;
      padding: 20px var(--gutter);
      /* Centred, not baseline: the back control is a tile now, and aligning a
         54px block to the title's baseline would hang it off the bar. */
      display: flex; align-items: center; gap: 24px;
      border-bottom: 1px solid var(--rule);
      background: var(--ink);
    }
    /* A tile, not a text link. This is the only way out of a full-screen
       takeover, so it gets a real target: a bordered block with its own
       ground, comfortably past the 44px minimum for touch. Still a <button>
       underneath — swapping in a div would cost keyboard and screen-reader
       support for the one control the view cannot do without. */
    .set-back {
      appearance: none;
      cursor: pointer;
      flex-shrink: 0;
      min-height: 54px;
      padding: 0 26px;
      background: rgba(242,234,218,0.07);
      border: 1px solid var(--rule);
      color: var(--fg);
      font-family: var(--mono);
      font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase;
      display: inline-flex; align-items: center; gap: 12px;
      align-self: center;
      transition: background 0.3s var(--ease), border-color 0.3s var(--ease),
                  color 0.3s var(--ease);
    }
    .set-back:hover,
    .set-back:focus-visible {
      background: var(--fg);
      border-color: var(--fg);
      color: var(--ink);
      outline: none;
    }
    .set-back i {
      font-style: normal;
      font-size: 16px;
      transition: transform 0.3s var(--ease);
    }
    .set-back:hover i { transform: translateX(-4px); }

    .set-bar-title {
      font-family: var(--display); font-weight: 400;
      font-size: clamp(22px, 2.4vw, 34px);
      letter-spacing: -0.01em; text-transform: uppercase;
      color: var(--fg);
      margin-right: auto;
    }
    .set-bar-meta { white-space: nowrap; }

    .gallery-grid {
      max-width: var(--measure); margin: 0 auto;
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      grid-auto-rows: 260px;
      gap: 12px;
      padding: 0 var(--gutter);
    }

    .photo-wrap {
      position: relative;
      overflow: hidden;
      cursor: pointer;
      background: var(--ink-2);
      transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
    }
    .photo-wrap:hover,
    .photo-wrap:focus-visible {
      transform: scale(1.025);
      z-index: 10;
      box-shadow: 0 18px 46px rgba(0,0,0,0.55);
      outline: none;
    }

    .photo-wrap img {
      width: 100%; height: 100%; display: block;
      object-fit: cover;
      /* Expired-film grade: warm, lifted blacks, slightly washed out. */
      filter: sepia(0.22) saturate(1.16) contrast(0.93) brightness(1.05) hue-rotate(-6deg);
      transition: transform 0.55s var(--ease), filter 0.55s var(--ease);
    }
    .photo-wrap:hover img {
      transform: scale(1.06);
      filter: sepia(0.09) saturate(1.26) contrast(1.0) brightness(1.07) hue-rotate(-4deg);
    }
    /* Warm flash bloom so every frame reads as the same stock. */
    .photo-wrap::after {
      content: '';
      position: absolute; inset: 0;
      background:
        radial-gradient(120% 90% at 50% 40%, rgba(255,214,160,0.14) 0%, rgba(255,214,160,0) 62%),
        linear-gradient(to bottom, rgba(201,84,42,0.05), rgba(63,125,119,0.07));
      mix-blend-mode: screen;
      pointer-events: none;
    }

    .photo-caption {
      position: absolute; bottom: 0; left: 0; right: 0;
      z-index: 2;
      padding: 30px 14px 12px;
      background: linear-gradient(to top, rgba(23,21,15,0.86) 0%, transparent 100%);
      font-family: var(--mono);
      font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
      color: #F7EFE0;
      opacity: 0;
      transform: translateY(6px);
      transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
    }
    .photo-wrap:hover .photo-caption,
    .photo-wrap:focus-visible .photo-caption { opacity: 1; transform: translateY(0); }

    @media (max-width: 1100px) {
      .gallery-grid { grid-template-columns: repeat(3, 1fr); grid-auto-rows: 240px; }
    }
    @media (max-width: 760px) {
      .gallery-section { padding: 70px 0 60px; }
      .gallery-head { grid-template-columns: 1fr; gap: 18px; padding: 0 var(--gutter) 32px; }
      .gallery-head .gallery-index { text-align: left; }
      .gallery-grid { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 190px; gap: 8px; }
      /* Touch has no hover, so captions stay on. */
      .photo-caption { opacity: 1; transform: none; }

      /* Single column is already the default; only the floors need easing. */
      .set-tile, .set-media img { min-height: 300px; }
      .set-plate { padding: 20px 22px 22px; }
      .set-title { margin: 18px 0; }
      /* The set label wraps under the back button rather than squeezing the
         title into two words per line. */
      .set-bar { flex-wrap: wrap; gap: 10px 18px; padding: 18px var(--gutter) 14px; }
      .set-bar-title { flex-basis: 100%; margin-right: 0; order: 3; }
    }

    /* The cover lifts and the set fades in; both are decoration, so neither
       survives a reduced-motion preference. */
    @media (prefers-reduced-motion: reduce) {
      .set-tile, .set-media img, .set-open i, .set-back i { transition: none; }
      .set-tile:hover, .set-tile:focus-visible { transform: none; }
      .set-tile:hover .set-media img { transform: none; }
      .set-view { animation: none; }
    }

    /* Lightbox */
    #lightbox {
      position: fixed; inset: 0; z-index: 2000;
      background: rgba(10,9,8,0.97);
      display: flex; align-items: center; justify-content: center;
      padding: 24px;
      opacity: 0; pointer-events: none;
      transition: opacity 0.45s var(--ease);
    }
    #lightbox.open { opacity: 1; pointer-events: all; }
    #lightbox img {
      max-width: 88vw; max-height: 86vh;
      object-fit: contain; border-radius: 0;
      transform: scale(0.98); transition: transform 0.5s var(--ease);
    }
    #lightbox.open img { transform: scale(1); }
    #lightbox-close {
      position: absolute; top: 28px; right: 28px;
      width: 40px; height: 40px; border-radius: 0;
      background: transparent; color: var(--fg-2);
      font-size: 24px; font-weight: 300;
      display: flex; align-items: center; justify-content: center; border: 1px solid var(--rule);
      transition: color 0.3s var(--ease), border-color 0.3s var(--ease);
    }
    #lightbox-close:hover { color: var(--fg); border-color: var(--fg); }
    /* Caption is part of the figure, not floated over the photo — it stays
       legible and always visible, which is the point of a contact sheet. */
    #lightbox-figure {
      display: flex; flex-direction: column; align-items: center; gap: 16px;
      max-width: 88vw;
    }
    #lightbox-caption {
      display: flex; align-items: baseline; gap: 14px;
      width: 100%; min-width: 260px;
      font-size: 11px; font-family: var(--mono);
      color: var(--fg-3); letter-spacing: 0.22em;
      text-transform: uppercase;
    }
    #lightbox-index { color: var(--fg); flex-shrink: 0; }
    #lightbox-caption .lb-rule {
      flex: 1; height: 1px; background: var(--rule);
      transform: translateY(-3px);
    }
    #lightbox-label { flex-shrink: 0; }

    /* Prev / next */
    #lightbox-prev, #lightbox-next {
      position: absolute; top: 50%; transform: translateY(-50%);
      width: 52px; height: 52px;
      display: flex; align-items: center; justify-content: center;
      background: transparent; border: 1px solid var(--rule);
      color: var(--fg-2); z-index: 5;
      transition: color 0.3s var(--ease), border-color 0.3s var(--ease), background 0.3s var(--ease);
    }
    #lightbox-prev { left: 28px; }
    #lightbox-next { right: 28px; }
    #lightbox-prev svg, #lightbox-next svg { width: 20px; height: 20px; }
    #lightbox-prev:hover, #lightbox-next:hover {
      color: var(--ink); background: var(--fg); border-color: var(--fg);
    }

    @media (max-width: 768px) {
      #lightbox-prev { left: 10px; }
      #lightbox-next { right: 10px; }
      #lightbox-prev, #lightbox-next { width: 42px; height: 42px; }
      #lightbox-caption { font-size: 10px; letter-spacing: 0.16em; gap: 10px; }
    }

    /* ─── Icons (Lucide, MIT) ────────────────────────── */
    /* Thin geometric strokes in bone. Replaces the emoji set — emoji render
       differently on every platform and carry another vendor's illustration
       style, which is the opposite of a controlled editorial system. */
    .ico {
      width: 26px; height: 26px;
      display: block;
      color: var(--fg);
      stroke-width: 1.4;
    }
    .cart-empty-icon { display: flex; justify-content: center; margin-bottom: 18px; }
    .cart-empty-icon .ico { width: 30px; height: 30px; color: var(--fg-3); }
    .success-ring { display: flex; justify-content: center; }
    .success-ring .ico { width: 34px; height: 34px; }

    /* ─── Community section ──────────────────────────── */
    .community-section {
      position: relative;
      padding: 140px 0;
      border-top: 1px solid var(--rule-soft);
      overflow: hidden;
      isolation: isolate;
    }

    /* The photograph IS the ground here — no colour wash over it. It carries
       the same expired-film grade as the gallery frames so it reads as one of
       the set rather than as stock art. */
    .community-bg {
      position: absolute; inset: 0; z-index: -1;
      pointer-events: none;
      background: var(--ink);   /* only shows through the scrim, never bare */
    }
    /* Graded to meet the grain rather than to hide the upscale. A soft scan
       blown up reads as a mistake; the same scan pushed — contrast up,
       colour pulled back, blacks lifted — reads as fast film shot in the
       dark, which is what the grain layer above then confirms. */
    .community-bg img {
      width: 100%; height: 100%;
      object-fit: cover; object-position: center 38%;
      opacity: 0.92;
      filter: sepia(0.3) saturate(0.85) contrast(1.32) brightness(0.86);
    }

    /* Film grain. An inline SVG feTurbulence rather than a noise JPEG: it is
       a few hundred bytes, resolution-independent, and needs no request.
       Two passes at different frequencies — a fine one for the emulsion and a
       coarse one for clumping — because single-frequency noise reads as
       digital dither, not as grain. */
    .community-bg::before {
      content: '';
      position: absolute; inset: 0; z-index: 1;
      background-image:
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E"),
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.32' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
      background-size: 190px 190px, 300px 300px;
      /* overlay keeps the grain tied to the picture's own tones — it bites in
         the midtones and leaves the blacks alone, the way real grain does,
         instead of laying a flat sheet of static over everything. */
      mix-blend-mode: overlay;
      opacity: 0.42;
      pointer-events: none;
    }

    /* Ink, not teal. Kept light and pushed to the edges so the middle of the
       photograph stays open — the copy is outlined, and outlined type needs
       something behind it or the counters fill with picture and stop being
       readable as letters. Above the grain, so the scrim damps it at the
       edges rather than the grain crawling over the vignette. */
    .community-bg::after {
      content: '';
      position: absolute; inset: 0; z-index: 2;
      background:
        radial-gradient(100% 78% at 50% 50%, rgba(23,21,15,0.24) 0%, rgba(23,21,15,0.58) 100%),
        linear-gradient(to bottom, rgba(23,21,15,0.40), rgba(23,21,15,0.08) 42%, rgba(23,21,15,0.50));
    }

    /* One centred column now that the cards are gone. */
    .community-inner {
      max-width: 720px; margin: 0 auto;
      text-align: center;
    }
    /* Promoted from a mono eyebrow to display scale and outlined to match the
       headline. At 10px mono over grain it was the least readable thing on
       the section; at this size the stroke is thick enough to hold its own
       against the picture. */
    /* !important throughout: the band-override block further down sets
       .section-label's family, size and colour with !important, so nothing
       short of the same wins here regardless of specificity. */
    .community-inner .section-label {
      justify-content: center;
      font-family: var(--display) !important; font-weight: 400 !important;
      font-size: clamp(30px, 4vw, 56px) !important;
      letter-spacing: 0.02em !important; line-height: 1;
      text-transform: uppercase;
      color: transparent !important;
      -webkit-text-stroke: 2px var(--fg);
      text-stroke: 2px var(--fg);
      margin-bottom: 6px;
    }
    /* The rule the label normally carries would cut straight through letters
       this size. */
    .community-inner .section-label::before,
    .community-inner .section-label::after { display: none; }

    /* Outlined, so the photograph reads straight through the headline. Stroke
       scales with the type — a 2px stroke that read as a hairline at 92px is
       what made this hard to read over grain. */
    .community-inner h2 {
      font-family: var(--display); font-weight: 400;
      font-size: clamp(56px, 8.4vw, 124px);
      letter-spacing: -0.015em; line-height: 0.88;
      text-transform: uppercase;
      color: transparent;
      -webkit-text-stroke: 3.5px var(--fg);
      text-stroke: 3.5px var(--fg);
      margin: 14px 0 28px;
    }
    /* Body copy stays solid — outlining it at 16px would close the counters
       and cost more legibility than the effect is worth. The shadow is what
       holds it against a photograph that has its own highlights. */
    .community-inner p {
      font-size: 17px; line-height: 1.75;
      color: var(--fg);
      margin: 0 auto;
      max-width: 58ch;
      text-shadow: 0 1px 16px rgba(23,21,15,0.92), 0 1px 3px rgba(23,21,15,0.8);
    }

    /* ─── CTA banner ─────────────────────────────────── */
    .cta-section { padding: 80px 0 100px; }
    .cta-inner {
      background: linear-gradient(135deg,#FF8C3A 0%,#FFD23F 28%,#A8E063 50%,#56CFE1 72%,#9B5FD4 100%);
      border-radius: 32px; padding: 80px;
      text-align: center; position: relative; overflow: hidden;
    }
    .cta-inner::before {
      content: '';
      position: absolute; inset: 0;
      background: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.08'/%3E%3C/svg%3E");
      mix-blend-mode: overlay; opacity:0.5;
    }
    .cta-inner h2 { font-size: clamp(36px,5vw,72px); font-weight:700; color:#080808; letter-spacing:-0.03em; line-height:1; margin-bottom:16px; position:relative; }
    .cta-inner p { font-size:16px; color:rgba(0,0,0,0.55); font-family:'Inter',sans-serif; margin-bottom:40px; position:relative; }
    .btn-dark {
      display: inline-flex; align-items: center; gap: 10px;
      padding: 16px 40px; border-radius: 100px;
      background: #080808; color: #fff;
      font-size: 14px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
      transition: transform 0.2s, box-shadow 0.2s; position:relative;
    }
    .btn-dark:hover { transform: translateY(-2px); box-shadow: 0 12px 40px rgba(0,0,0,0.5); }

    /* ─── Footer ─────────────────────────────────────── */
    footer {
      border-top: 1px solid rgba(255,255,255,0.06);
      padding: 60px 0 40px;
    }
    .footer-inner {
      display: flex; align-items: flex-start; justify-content: space-between;
      flex-wrap: wrap; gap: 40px; margin-bottom: 48px;
    }
    .footer-brand img { height: 28px; filter: brightness(0) invert(1); opacity:0.8; margin-bottom:12px; display:block; }
    .footer-brand p { font-size:13px; color:rgba(255,255,255,0.35); font-family:'Inter',sans-serif; max-width:240px; line-height:1.6; }
    .footer-links h4 { font-size:11px; font-weight:700; letter-spacing:0.2em; text-transform:uppercase; color:rgba(255,255,255,0.35); margin-bottom:16px; }
    .footer-links ul { list-style:none; display:flex; flex-direction:column; gap:10px; }
    .footer-links ul li a { font-size:14px; color:rgba(255,255,255,0.6); transition:color 0.2s; }
    .footer-links ul li a:hover { color:#fff; }
    .footer-bottom { display:flex; align-items:center; justify-content:space-between; padding-top:24px; border-top:1px solid rgba(255,255,255,0.05); }
    .footer-bottom p { font-size:12px; color:rgba(255,255,255,0.25); font-family:'Inter',sans-serif; }
    .footer-gradient { height:2px; background:linear-gradient(90deg,#FF8C3A,#FFD23F,#A8E063,#56CFE1,#9B5FD4); margin-bottom:40px; }

    /* ─── Cart Sidebar ───────────────────────────────── */
    .cart-overlay {
      position: fixed; inset: 0; z-index: 1000;
      background: rgba(0,0,0,0); backdrop-filter: blur(0px);
      pointer-events: none; transition: background 0.3s, backdrop-filter 0.3s;
    }
    .cart-overlay.open {
      background: rgba(0,0,0,0.6); backdrop-filter: blur(4px);
      pointer-events: all;
    }
    .cart-sidebar {
      position: fixed; top: 0; right: -480px; bottom: 0; width: 480px; z-index: 1001;
      background: #0f0f0f;
      border-left: 1px solid rgba(255,255,255,0.08);
      transition: right 0.4s cubic-bezier(0.25,0.8,0.25,1);
      display: flex; flex-direction: column;
    }
    .cart-sidebar.open { right: 0; }
    .cart-header {
      display: flex; align-items: center; justify-content: space-between;
      padding: 28px 32px; border-bottom: 1px solid rgba(255,255,255,0.06);
    }
    .cart-title { font-size: 18px; font-weight: 700; }
    .cart-close {
      width: 36px; height: 36px; border-radius: 50%;
      background: rgba(255,255,255,0.07); color: #fff;
      display: flex; align-items: center; justify-content: center;
      font-size: 18px; border: none; transition: background 0.2s;
    }
    .cart-close:hover { background: rgba(255,255,255,0.13); }
    .cart-items { flex: 1; overflow-y: auto; padding: 24px 32px; }
    .cart-items::-webkit-scrollbar { width: 4px; }
    .cart-items::-webkit-scrollbar-track { background: transparent; }
    .cart-items::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 2px; }
    .cart-empty { text-align: center; padding: 80px 20px; }
    .cart-empty-icon { font-size: 48px; margin-bottom: 16px; opacity: 0.3; }
    .cart-empty p { color: rgba(255,255,255,0.35); font-size:14px; }
    .cart-item {
      display: flex; align-items: center; gap: 16px;
      padding: 16px 0; border-bottom: 1px solid rgba(255,255,255,0.06);
    }
    .cart-item-img {
      width: 72px; height: 72px; border-radius: 12px; flex-shrink: 0;
      background: linear-gradient(135deg,rgba(255,140,58,0.1),rgba(155,95,212,0.1));
      display: flex; align-items: center; justify-content: center; overflow: hidden;
    }
    .cart-item-img img { width: 60px; object-fit: contain; }
    .cart-item-info { flex: 1; }
    .cart-item-name { font-size: 15px; font-weight: 600; margin-bottom: 4px; }
    .cart-item-price { font-size: 13px; color: rgba(255,255,255,0.45); }
    .cart-item-qty { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
    .cart-item-qty button {
      width: 24px; height: 24px; border-radius: 50%;
      background: rgba(255,255,255,0.08); color: #fff; font-size: 14px;
      display: flex; align-items: center; justify-content: center;
      transition: background 0.2s;
    }
    .cart-item-qty button:hover { background: rgba(255,255,255,0.15); }
    .cart-item-qty span { font-size: 14px; font-weight: 600; min-width: 20px; text-align: center; }
    .cart-item-remove { color: rgba(255,255,255,0.2); font-size: 20px; transition: color 0.2s; }
    .cart-item-remove:hover { color: rgba(255,80,80,0.7); }
    .cart-footer { padding: 24px 32px; border-top: 1px solid rgba(255,255,255,0.06); }
    .cart-total { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
    .cart-total-label { font-size: 14px; color: rgba(255,255,255,0.5); }
    .cart-total-amount { font-size: 24px; font-weight: 700; }
    .checkout-btn {
      width: 100%; padding: 16px;
      border-radius: 14px;
      background: linear-gradient(135deg,#FF8C3A,#FFD23F,#A8E063,#56CFE1,#9B5FD4);
      color: #080808; font-size: 15px; font-weight: 700;
      letter-spacing: 0.04em; text-transform: uppercase;
      transition: transform 0.2s, box-shadow 0.2s;
    }
    .checkout-btn:hover { transform: translateY(-1px); box-shadow: 0 8px 32px rgba(155,95,212,0.4); }
    .cart-note { text-align: center; margin-top: 12px; font-size: 12px; color: rgba(255,255,255,0.2); font-family:'Inter',sans-serif; }

    /* ─── Checkout Modal ─────────────────────────────── */
    .modal-overlay {
      position: fixed; inset: 0; z-index: 1100;
      background: rgba(0,0,0,0.8); backdrop-filter: blur(8px);
      display: flex; align-items: center; justify-content: center;
      padding: 24px;
      opacity: 0; pointer-events: none;
      transition: opacity 0.3s;
    }
    .modal-overlay.open { opacity: 1; pointer-events: all; }
    .modal {
      background: #111; border-radius: 28px;
      border: 1px solid rgba(255,255,255,0.09);
      width: 100%; max-width: 580px;
      max-height: 90vh; overflow-y: auto;
      transform: translateY(20px);
      transition: transform 0.3s;
    }
    .modal-overlay.open .modal { transform: translateY(0); }
    .modal::-webkit-scrollbar { width: 4px; }
    .modal::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 2px; }
    .modal-header {
      padding: 32px 36px 0;
      display: flex; align-items: center; justify-content: space-between;
    }
    .modal-title { font-size: 22px; font-weight: 700; }
    .modal-close { width:36px;height:36px;border-radius:50%;background:rgba(255,255,255,0.07);color:#fff;display:flex;align-items:center;justify-content:center;font-size:18px;border:none;transition:background 0.2s; }
    .modal-close:hover { background:rgba(255,255,255,0.13); }
    .modal-body { padding: 28px 36px 36px; }

    .form-section { margin-bottom: 28px; }
    .form-section-title {
      font-size: 11px; font-weight: 700; letter-spacing: 0.2em; text-transform: uppercase;
      color: rgba(255,255,255,0.35); margin-bottom: 16px;
    }
    .form-row { display: grid; gap: 12px; }
    .form-row.col-2 { grid-template-columns: 1fr 1fr; }
    .form-group { display: flex; flex-direction: column; gap: 6px; }
    .form-group label { font-size: 12px; font-weight: 500; color: rgba(255,255,255,0.5); letter-spacing: 0.04em; }
    .form-group input, .form-group select {
      background: rgba(255,255,255,0.05);
      border: 1px solid rgba(255,255,255,0.1);
      border-radius: 10px; padding: 12px 14px;
      color: #fff; font-size: 14px; font-family: 'Space Grotesk',sans-serif;
      outline: none; transition: border-color 0.2s;
      -webkit-appearance: none;
    }
    .form-group input:focus, .form-group select:focus { border-color: rgba(155,95,212,0.5); }
    .form-group input::placeholder { color: rgba(255,255,255,0.2); }
    .form-group select option { background: #111; }

    .order-summary {
      background: rgba(255,255,255,0.03);
      border: 1px solid rgba(255,255,255,0.07);
      border-radius: 16px; padding: 20px;
      margin-bottom: 24px;
    }
    .order-row { display: flex; justify-content: space-between; font-size: 14px; margin-bottom: 10px; color: rgba(255,255,255,0.6); }
    .order-row:last-child { margin-bottom: 0; padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.07); color: #fff; font-weight: 700; font-size: 16px; }

    .place-order-btn {
      width: 100%; padding: 16px;
      border-radius: 14px;
      background: linear-gradient(135deg,#FF8C3A,#FFD23F,#A8E063,#56CFE1,#9B5FD4);
      color: #080808; font-size: 15px; font-weight: 700;
      letter-spacing: 0.04em; text-transform: uppercase;
      transition: transform 0.2s, box-shadow 0.2s;
    }
    .place-order-btn:hover { transform: translateY(-1px); box-shadow: 0 8px 32px rgba(155,95,212,0.4); }

    /* Success state */
    .success-state {
      display: none; flex-direction: column; align-items: center;
      text-align: center; padding: 60px 36px;
    }
    .success-state.show { display: flex; }
    .success-ring {
      width: 96px; height: 96px; border-radius: 50%;
      background: linear-gradient(135deg,#FF8C3A,#9B5FD4);
      display: flex; align-items: center; justify-content: center;
      font-size: 40px; margin-bottom: 28px;
      animation: pop-in 0.5s cubic-bezier(0.34,1.56,0.64,1) both;
    }
    @keyframes pop-in { from{transform:scale(0);opacity:0} to{transform:scale(1);opacity:1} }
    .success-state h3 { font-size: 28px; font-weight: 700; margin-bottom: 12px; }
    .success-state p { color: rgba(255,255,255,0.45); font-family:'Inter',sans-serif; font-size: 15px; line-height: 1.6; max-width: 320px; }
    .success-ref { margin-top: 20px; font-family:'Courier New',monospace; font-size: 13px; color: rgba(255,255,255,0.3); }

    /* ─── Toast ──────────────────────────────────────── */
    #toast {
      position: fixed; bottom: 32px; left: 50%; transform: translateX(-50%) translateY(20px);
      z-index: 2000;
      background: #1a1a1a; border: 1px solid rgba(255,255,255,0.1);
      border-radius: 100px; padding: 12px 24px;
      font-size: 13px; font-weight: 600; color: #fff;
      display: flex; align-items: center; gap: 10px;
      opacity: 0; transition: opacity 0.3s, transform 0.3s;
      pointer-events: none;
    }
    #toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
    #toast .toast-dot {
      width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
      background: linear-gradient(135deg,#FF8C3A,#9B5FD4);
    }

    /* ─── Scroll Animations ───────────────────────────── */
    /* Visible by DEFAULT. The hidden start state is gated behind .js-reveal,
       which main.js only sets once it is actually running and about to wire
       the observer. Previously these were opacity:0 in plain CSS, so any JS
       failure — or an observer that never fired — left whole sections
       permanently invisible with no way to recover. Worst case now is "no
       animation", never "no content". */
    .fade-up { opacity: 1; transform: none; transition: opacity 0.6s ease, transform 0.6s ease; }
    html.js-reveal .fade-up { opacity: 0; transform: translateY(30px); }
    html.js-reveal .fade-up.visible { opacity: 1; transform: translateY(0); }
    .fade-up:nth-child(2) { transition-delay: 0.1s; }
    .fade-up:nth-child(3) { transition-delay: 0.2s; }
    .fade-up:nth-child(4) { transition-delay: 0.3s; }

    /* ─── Responsive ─────────────────────────────────── */
    @media(max-width: 1024px) {
      /* Hero stacks: type first (it carries the pitch), photo beneath it as a
         fixed-height band. Stays left-aligned — centring undoes the editorial
         feel the whole redesign is built on. */
      .hero { min-height: 0; }
      .hero-content {
        grid-template-columns: 1fr;
        align-items: start;
        gap: 40px;
        padding: 120px var(--gutter) 0;
      }
      .hero-text { order: 0; padding-bottom: 0; }
      .hero-figure { order: 1; height: 52vh; min-height: 320px; align-self: auto; }
      .hero-sub { margin-bottom: 36px; }
      .product-grid { grid-template-columns: 1fr 1fr; }
      /* Already a single centred column; only the band padding needs easing. */
      .community-section { padding: 90px 0; }
    }
    @media(max-width: 768px) {
      nav { padding: 16px 24px; }
      .nav-links { display: none; }
      .container { padding: 0 24px; }
      :root { --gutter: 24px; }
      .hero { padding: 0; }
      .hero-content { padding: 104px var(--gutter) 0; }
      .hero-meta { gap: 18px; padding: 16px 0 20px; font-size: 10px; }
      .hero-meta .spacer { margin-left: 0; }
      .product-grid { grid-template-columns: 1fr; }
      .cart-sidebar { width: 100%; right: -100%; }
      .cta-inner { padding: 48px 24px; }
      .footer-inner { flex-direction: column; }
      .modal { border-radius: 20px; }
      .modal-header, .modal-body { padding-left: 24px; padding-right: 24px; }
      .form-row.col-2 { grid-template-columns: 1fr; }
    }

    /* ─── Stripe Elements ─────────────────────────── */
    .stripe-card-element {
      background: rgba(255,255,255,0.05);
      border: 1px solid rgba(255,255,255,0.1);
      border-radius: 10px; padding: 14px 12px;
      transition: border-color 0.2s;
    }
    .stripe-card-element.StripeElement--focus { border-color: rgba(155,95,212,0.5); }
    .stripe-card-element.StripeElement--invalid { border-color: rgba(255,80,80,0.5); }
    .stripe-error { color: rgba(255,100,100,0.8); font-size: 12px; margin-top: 6px; min-height: 16px; }

    /* ─── Shipping preview ───────────────────────── */
    .shipping-preview {
      display: flex; justify-content: space-between; align-items: center;
      font-size: 13px; color: rgba(255,255,255,0.4);
      font-family: 'Inter', sans-serif;
      margin-top: 12px; padding-top: 12px;
      border-top: 1px solid rgba(255,255,255,0.06);
    }

    /* ─── Apple/Google Pay divider ───────────────── */
    .pay-divider {
      text-align: center; margin: 16px 0;
      position: relative;
    }
    .pay-divider::before {
      content: ''; position: absolute; top: 50%; left: 0; right: 0;
      height: 1px; background: rgba(255,255,255,0.08);
    }
    .pay-divider span {
      position: relative; background: #111;
      padding: 0 12px;
      font-size: 12px; color: rgba(255,255,255,0.3);
      font-family: 'Inter', sans-serif;
    }

    /* ─────────────────────────────────────────────────────────────────────
       ZINE PASS — overrides for the sections carried over from the previous
       system. Everything below re-points hard-coded white/black values onto
       the per-band --fg / --bg variables so each section inherits its own
       colourway, and swaps section headings onto Anton.
       ───────────────────────────────────────────────────────────────────── */

    /* Grain: sits above flat colour blocks, which is where it does the most
       work — it stops the poster grounds reading as digital-flat. */
    body::after { opacity: 0.5; mix-blend-mode: soft-light; }

    section { background: var(--bg); color: var(--fg); }

    /* ── Headings ── */
    .section-title {
      font-family: var(--display) !important;
      font-weight: 400 !important;
      text-transform: uppercase;
      letter-spacing: -0.015em !important;
      line-height: 0.86 !important;
      font-size: clamp(40px, 6.4vw, 104px) !important;
      color: var(--fg) !important;
    }
    .section-label, .meta {
      font-family: var(--mono) !important;
      font-size: 11px !important; font-weight: 400 !important;
      letter-spacing: 0.22em !important; text-transform: uppercase;
      color: var(--fg-3) !important;
      background: none !important;
    }
    .section-label::before, .section-label::after { display: none !important; }
    .section-desc { color: var(--fg-2) !important; font-family: var(--sans); }

    /* ── Nav ── */
    /* Fully transparent at all times — no fill, no blur, no hairline, even
       once scrolled. The nav floats over whichever band is behind it. */
    nav, nav.scrolled {
      background: transparent !important;
      backdrop-filter: none !important;
      border-bottom: none !important;
      box-shadow: none !important;
    }
    .nav-links { color: rgba(242,234,218,0.72); }
    .nav-links a:hover { color: #F2EADA; }
    .nav-social { background: rgba(242,234,218,0.08); border-color: rgba(242,234,218,0.14); }
    .nav-social svg { fill: rgba(242,234,218,0.75); }
    .nav-divider { background: rgba(242,234,218,0.14); }
    .cart-btn { background: rgba(242,234,218,0.08); border-color: rgba(242,234,218,0.16); border-radius: 0; }
    .cart-btn svg { stroke: #F2EADA; }
    .nav-social { border-radius: 0; }
    .cart-count {
      background: var(--orange);
      border-radius: 0;
      color: #FFF3E4;
    }

    /* ── Ticker: flat orange rule between spreads ── */
    .ticker-wrap {
      background: var(--orange);
      border-top: none; border-bottom: none;
      padding: 14px 0;
    }
    .ticker-inner span { color: #FFF3E4; font-weight: 700; letter-spacing: 0.2em; }
    .ticker-inner .dot { color: rgba(255,243,228,0.5); }

    /* ── Cards / panels: flat, squared, no glass ── */
    .product-card {
      background: transparent !important;
      backdrop-filter: none !important;
      border-radius: 0 !important;
      border: 1px solid var(--rule) !important;
      box-shadow: none !important;
      color: var(--fg);
    }
    .product-card { background: rgba(23,21,15,0.04) !important; }
    .band-orange .product-card, .band-teal .product-card,
    .band-ink .product-card { background: rgba(242,234,218,0.05) !important; }
    .product-card.featured { border-color: var(--fg) !important; }
    .card-image { background: transparent !important; border-radius: 0 !important; }
    .card-name { font-family: var(--display); font-weight: 400; text-transform: uppercase;
                 letter-spacing: 0.01em; font-size: 28px; color: var(--fg); }
    .card-tagline, .card-feature { color: var(--fg-2) !important; }
    .card-price { color: var(--fg) !important; }
    .card-price .per { color: var(--fg-3) !important; }
    .card-badge {
      background: var(--orange) !important; color: #FFF3E4 !important;
      border-radius: 0 !important; font-family: var(--mono);
      letter-spacing: 0.14em; text-transform: uppercase;
    }
    .qty-control, .qty-btn { border-radius: 0 !important; color: var(--fg); border-color: var(--rule) !important; }
    .qty-val { color: var(--fg); }
    .add-to-cart {
      border-radius: 0 !important;
      background: var(--fg) !important; color: var(--bg) !important;
      font-family: var(--mono); letter-spacing: 0.14em; text-transform: uppercase;
      font-size: 12px;
    }
    .ico { color: var(--fg); }

    /* ── CTA ── */
    .cta-inner { border-radius: 0 !important; background: var(--orange) !important; }
    .cta-inner h2 {
      font-family: var(--display); font-weight: 400; text-transform: uppercase;
      line-height: 0.84; letter-spacing: -0.015em; color: #FFF3E4;
    }
    .cta-inner p { color: rgba(255,243,228,0.85); }
    .btn-dark {
      border-radius: 0 !important;
      background: #17150F !important; color: #F2EADA !important;
      font-family: var(--mono); letter-spacing: 0.16em; text-transform: uppercase; font-size: 12px;
    }

    /* ── Footer ── */
    footer { background: var(--ink); color: var(--on-dark); border-top: 1px solid rgba(242,234,218,0.10); }
    .footer-gradient { display: none; }
    .footer-brand p, .footer-links a { color: var(--on-dark-2); }
    .footer-links h4 {
      font-family: var(--mono); font-size: 11px; letter-spacing: 0.22em;
      text-transform: uppercase; color: var(--on-dark-3);
    }
    .footer-links a:hover { color: var(--on-dark); }
    .footer-bottom { border-top: 1px solid rgba(242,234,218,0.10); color: var(--on-dark-3); }
    .footer-tag {
      font-family: var(--mono); letter-spacing: 0.2em; text-transform: uppercase;
      color: var(--orange); font-weight: 700;
    }

    /* ── Cart / modal chrome ── */
    .cart-sidebar, .modal { background: var(--ink) !important; border-radius: 0 !important; color: var(--on-dark); }
    .cart-title, .modal-title {
      font-family: var(--display); font-weight: 400; text-transform: uppercase; letter-spacing: 0.01em;
    }
    .checkout-btn, .place-order-btn {
      border-radius: 0 !important; background: var(--orange) !important; color: #FFF3E4 !important;
      font-family: var(--mono); letter-spacing: 0.14em; text-transform: uppercase;
    }
    .toast { border-radius: 0 !important; }

    /* ── Photography: one film stock everywhere ── */
    .card-image img {
      filter: sepia(0.18) saturate(1.14) contrast(0.94) brightness(1.04);
    }

    /* ─────────────────────────────────────────────────────────────────────
       VUNO CRT LOGO
       Wireframe globe + heavy italic wordmark behind a scanline/noise CRT
       treatment. Laid out at a fixed native pixel size and then scaled with a
       transform, so every internal proportion survives at any size — a nav
       mark and a hero-sized lockup are the same component, not two drawings.

       Sizing: set --s (scale). --w/--h are the native box.
       ───────────────────────────────────────────────────────────────────── */
    .vuno-logo {
      --w: 680px;
      --h: 400px;
      --s: 1;
      --globe: #5b7a99;
      --cream: #F0EAD6;
      position: relative;
      display: block;
      width: calc(var(--w) * var(--s));
      height: calc(var(--h) * var(--s));
      overflow: hidden;
      flex-shrink: 0;
    }
    .vuno-logo__inner {
      position: absolute; top: 0; left: 0;
      width: var(--w); height: var(--h);
      transform: scale(var(--s));
      transform-origin: 0 0;
      /* "Slight softening" — a real pixel downsample of live DOM isn't
         possible without rasterising to canvas, so this is a filter-based
         approximation: a sub-pixel blur plus a contrast push, which reads as
         a cheap CRT rather than a crisp vector. */
      filter: contrast(1.12) saturate(0.9) blur(0.35px);
    }

    /* ── Wireframe globe ── */
    .vuno-logo__globe {
      position: absolute; top: 50%; left: 50%;
      transform: translate(-50%, -50%);
      width: 460px; height: 190px;
    }
    .vuno-logo__globe svg { width: 100%; height: 100%; display: block; }
    .vuno-logo__globe ellipse,
    .vuno-logo__globe line,
    .vuno-logo__globe path {
      stroke: var(--globe);
      stroke-width: 2.5;
      fill: none;
      opacity: 0.85;
    }

    /* ── Wordmark ── */
    .vuno-logo__word {
      position: absolute; top: 46%; left: 50%;
      transform: translate(-50%, -50%) skewX(-6deg);
      font-family: 'Arial Black', 'Helvetica Neue', Helvetica, Arial, sans-serif;
      font-weight: 900;
      font-style: italic;
      font-size: 130px;
      line-height: 1;
      color: var(--cream);
      letter-spacing: 2px;
      white-space: nowrap;
    }
    /* Chromatic aberration. The original used content:attr(data-text) with no
       data-text attribute set, so both layers rendered empty and the effect
       never appeared — the attribute is now present and the layers are offset
       and tinted so the fringing is actually visible. */
    .vuno-logo__word::before,
    .vuno-logo__word::after {
      content: attr(data-text);
      position: absolute; top: 0; left: 0;
      width: 100%;
      pointer-events: none;
    }
    .vuno-logo__word::before {
      color: #ff2d2d;
      transform: translateX(-2.5px);
      mix-blend-mode: screen;
      opacity: 0.45;
    }
    .vuno-logo__word::after {
      color: #24e0ff;
      transform: translateX(2.5px);
      mix-blend-mode: screen;
      opacity: 0.4;
    }

    .vuno-logo__sub {
      position: absolute; top: 74%; left: 50%;
      transform: translate(-50%, -50%);
      font-family: 'Arial Black', 'Helvetica Neue', Helvetica, Arial, sans-serif;
      font-weight: 900;
      font-size: 34px;
      line-height: 1;
      color: var(--cream);
      letter-spacing: 6px;
      white-space: nowrap;
    }

    /* ── CRT overlays ──
       Scanline pitch is in SCALED space deliberately: scaling it with the
       logo would smear the lines into grey mush at small sizes. */
    .vuno-logo__scan {
      position: absolute; inset: 0; z-index: 3;
      pointer-events: none;
      background: repeating-linear-gradient(
        to bottom,
        rgba(0,0,0,0) 0px,
        rgba(0,0,0,0) 2px,
        rgba(0,0,0,0.25) 3px,
        rgba(0,0,0,0.25) 4px
      );
    }
    .vuno-logo__noise {
      position: absolute; inset: 0; z-index: 4;
      pointer-events: none;
      opacity: 0.08;
      mix-blend-mode: overlay;
      background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' seed='7'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
    }

    /* ── Compact variant: nav mark ──
       Drops the subtitle and crops the box. At nav scale the 34px subtitle
       would render around 4px tall — present but unreadable, which is worse
       than not being there. */
    /* Box hugs the artwork. At the full 680px width the empty margins meant
       the scanline overlay read as a faint rectangle floating in the nav. */
    .vuno-logo--compact {
      --w: 500px;
      --h: 215px;
      --s: 0.245;
    }
    .vuno-logo--compact .vuno-logo__sub { display: none; }
    .vuno-logo--compact .vuno-logo__word { top: 50%; }
    .vuno-logo--compact .vuno-logo__inner { filter: contrast(1.14) saturate(0.9); }
    /* Scanlines this fine turn to mush under 1px — widen the pitch instead. */
    .vuno-logo--compact .vuno-logo__scan {
      background: repeating-linear-gradient(
        to bottom,
        rgba(0,0,0,0) 0px,
        rgba(0,0,0,0) 1px,
        rgba(0,0,0,0.22) 2px,
        rgba(0,0,0,0.22) 3px
      );
    }

    .nav-logo { display: flex; align-items: center; }

    @media (max-width: 768px) {
      .vuno-logo--compact { --s: 0.16; }
    }
    @media (prefers-reduced-motion: reduce) {
      .vuno-logo__noise { display: none; }
    }

    /* ── CRT motion ───────────────────────────────────────
       Four independent layers, all cheap (transform/opacity only):
         1. scanlines roll slowly downward
         2. a bright "hum bar" sweeps through, like mains interference
         3. the picture flickers a fraction of a stop
         4. JS fires an occasional tracking tear at random intervals
       Randomised timing matters — a glitch on a fixed loop reads as a UI
       animation; irregular gaps read as a failing tube. */
    .vuno-logo__scan {
      background-size: 100% 4px;
      animation: crt-roll 7s linear infinite;
    }
    @keyframes crt-roll {
      from { background-position: 0 0; }
      to   { background-position: 0 4px; }
    }

    /* Hum bar. */
    .vuno-logo__scan::after {
      content: '';
      position: absolute; left: 0; right: 0;
      height: 22%;
      background: linear-gradient(
        to bottom,
        rgba(255,255,255,0) 0%,
        rgba(255,255,255,0.055) 45%,
        rgba(255,255,255,0.085) 55%,
        rgba(255,255,255,0) 100%);
      animation: crt-hum 5.5s linear infinite;
      pointer-events: none;
    }
    @keyframes crt-hum {
      from { top: -25%; }
      to   { top: 105%; }
    }

    .vuno-logo__inner { animation: crt-flicker 4.2s steps(1, end) infinite; }
    @keyframes crt-flicker {
      0%, 100%   { opacity: 1;    }
      6%         { opacity: 0.94; }
      7%         { opacity: 1;    }
      41%        { opacity: 0.97; }
      42%        { opacity: 1;    }
      73%        { opacity: 0.92; }
      74.5%      { opacity: 1;    }
    }

    /* Tracking tear — JS adds .is-glitch briefly. */
    .vuno-logo.is-glitch .vuno-logo__inner {
      animation: crt-flicker 4.2s steps(1, end) infinite, crt-tear 0.36s steps(2, end) 1;
    }
    @keyframes crt-tear {
      0%   { transform: scale(var(--s)) translateX(0);     filter: contrast(1.12) saturate(0.9) blur(0.35px); }
      15%  { transform: scale(var(--s)) translateX(-7px);  filter: contrast(1.5) saturate(0.35) blur(0.6px); }
      32%  { transform: scale(var(--s)) translateX(5px);   filter: contrast(0.85) saturate(1.6) blur(0.2px); }
      55%  { transform: scale(var(--s)) translateX(-2px);  filter: contrast(1.3) saturate(0.7) blur(0.5px); }
      100% { transform: scale(var(--s)) translateX(0);     filter: contrast(1.12) saturate(0.9) blur(0.35px); }
    }
    .vuno-logo.is-glitch .vuno-logo__word::before { transform: translateX(-7px); opacity: 0.8; }
    .vuno-logo.is-glitch .vuno-logo__word::after  { transform: translateX(7px);  opacity: 0.75; }

    /* Hover: hold a degauss-style wobble while pointing at it. */
    @media (hover: hover) {
      .vuno-logo:hover .vuno-logo__inner { animation: crt-flicker 0.9s steps(1, end) infinite; }
      .vuno-logo:hover .vuno-logo__word::before { transform: translateX(-4.5px); opacity: 0.7; }
      .vuno-logo:hover .vuno-logo__word::after  { transform: translateX(4.5px);  opacity: 0.65; }
      .vuno-logo:hover .vuno-logo__scan::after  { animation-duration: 1.6s; }
      .vuno-logo__word::before,
      .vuno-logo__word::after { transition: transform 0.18s steps(2, end), opacity 0.18s ease; }
    }

    /* On a paper ground the screen-blended fringes turn muddy purple — the
       blend needs light behind it. Multiply is the correct dual. */
    .stage--light .vuno-logo__word::before,
    .stage--light .vuno-logo__word::after,
    .band-cream .vuno-logo__word::before,
    .band-cream .vuno-logo__word::after {
      mix-blend-mode: multiply;
      opacity: 0.3;
    }

    @media (prefers-reduced-motion: reduce) {
      .vuno-logo__scan,
      .vuno-logo__scan::after,
      .vuno-logo__inner,
      .vuno-logo:hover .vuno-logo__inner { animation: none !important; }
    }


    /* ─── Utilities replacing inline style attributes ────
       style-src is enforced without 'unsafe-inline', which blocks style=""
       attributes as well as <style> blocks, so these moved out of the markup.
       Values are carried across unchanged. */
    .price-dec      { font-size: 24px; }
    .product-photo  { max-height: 260px; max-width: 100%; object-fit: contain; }
    .gallery-eyebrow{ margin-bottom: 20px; }
    .mt-12          { margin-top: 12px; }
    .mt-32          { margin-top: 32px; }
    .cursor-none    { cursor: none; }
    /* Toggled from JS via the .style property, which CSP does not govern —
       only attributes and <style> elements are in scope for style-src. */
    .is-hidden      { display: none; }

    /* Honeypot. Deliberately NOT display:none or hidden — some bots skip
       fields they can tell are hidden that way. Positioned off-canvas instead,
       which is invisible to people but looks like a normal field to a scraper.
       aria-hidden + tabindex=-1 in the markup keep assistive tech out of it. */
    .hp-field {
      position: absolute !important;
      left: -9999px !important;
      top: auto;
      width: 1px; height: 1px;
      overflow: hidden;
    }
