/* ═══ TOKENS — pulled from the Y2K reveal art ═════════ */
:root{
  --night:#160840;         /* deepest sky */
  --violet:#3A1187;        /* base field */
  --violet-mid:#6B2BD9;
  --violet-lt:#9B45FF;
  --lilac:#C9A8FF;

  --acid:#B8F02A;          /* portal green */
  --acid-hi:#E9FF9C;       /* portal core */
  --acid-dp:#5E8F0A;

  --ink:#140634;
  --paper:#F1E9FF;
  --putty:#CFC4EE;         /* computer plastic */
  --putty-hi:#FFFFFF;
  --putty-sh:#6B5CA8;

  --mag:#FF2FB9;
  --red:#FF3B57;

  --pad:clamp(18px,5vw,80px);
  --mono:"Cascadia Mono",ui-monospace,"SF Mono","Roboto Mono",Menlo,Consolas,monospace;
  --sans:"Arial Black","Helvetica Neue",Helvetica,Arial,sans-serif;
  --ui:"Helvetica Neue",Inter,Arial,system-ui,sans-serif;
}
*,*::before,*::after{box-sizing:border-box}
/* overflow-x:clip on the root — `hidden` on body alone propagates to the
   viewport and breaks position:fixed + ScrollTrigger. Native smooth-scroll
   stays off: it fights ScrollTrigger's scrub. */
html{overflow-x:clip}
body{
  margin:0;background:var(--night);color:var(--paper);
  font-family:var(--ui);overflow-x:clip;-webkit-font-smoothing:antialiased;
}
a{color:inherit;text-decoration:none}
button,input{font:inherit;color:inherit}
h1,h2,h3,p,ol{margin:0}
img{max-width:100%;display:block}

/* ═══ CHROME TYPE ═════════════════════════════════════ */
.chrome{
  font-family:var(--sans);font-weight:900;text-transform:uppercase;
  letter-spacing:-.045em;line-height:.82;
  background:linear-gradient(177deg,
    #ffffff 0%, #F0E6FF 12%, #C3A6F5 27%, #7B44D6 42%,
    #2E0D6B 50%, #9B62EE 57%, #E4D4FF 70%, #ffffff 82%, #BFA6EE 100%);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
  filter:drop-shadow(0 2px 0 rgba(12,3,36,.6)) drop-shadow(0 0 28px rgba(155,69,255,.45));
  background-size:100% 200%;
}
/* Acid variant — the portal green.
   The `background` shorthand resets background-clip/size, so both must be
   restated here or the gradient paints the box instead of the glyphs. */
.chrome--acid{
  background:linear-gradient(177deg,
    #FFFFFF 0%, #F2FFC9 12%, #D4FF5C 26%, #9FD91A 42%,
    #3F6A05 50%, #B4EE2A 58%, #EAFFAE 72%, #FFFFFF 84%, #C6F556 100%);
  -webkit-background-clip:text;background-clip:text;
  background-size:100% 200%;
  filter:drop-shadow(0 2px 0 rgba(12,3,36,.6)) drop-shadow(0 0 30px rgba(184,240,42,.5));
}
.chrome--sm{font-size:clamp(30px,5.2vw,68px);letter-spacing:-.035em;line-height:.88}

/* ═══ LAYERS ══════════════════════════════════════════ */
#bg{position:fixed;inset:0;width:100%;height:100%;z-index:0;display:block}
.grain,.scanlines{position:fixed;inset:0;z-index:1;pointer-events:none}
/* static + unblended: an animated full-viewport blend layer re-composites the
   whole screen every frame and wrecks scrolling */
.grain{
  opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
.scanlines{opacity:.2;background:repeating-linear-gradient(to bottom,transparent 0 2px,rgba(10,0,30,.32) 2px 3px)}
main,.nav,.foot,.marq{position:relative;z-index:2}

/* ═══ Y2K PANEL ═══════════════════════════════════════ */
.win{
  background:var(--putty);color:var(--ink);
  border:1px solid var(--ink);
  box-shadow:
    inset 1.5px 1.5px 0 var(--putty-hi),
    inset -1.5px -1.5px 0 var(--putty-sh),
    6px 6px 0 rgba(12,3,36,.6);
}
.win__bar{
  display:flex;align-items:center;gap:12px;
  padding:5px 6px 5px 10px;
  background:linear-gradient(90deg,#2C0B6E 0%,var(--violet-mid) 55%,var(--violet-lt) 100%);
  color:#fff;font-family:var(--mono);font-size:11px;letter-spacing:.14em;
}
.win__btns{margin-left:auto;display:flex;gap:3px}
.win__btns i{
  width:18px;height:16px;display:grid;place-items:center;font-style:normal;font-size:10px;
  background:var(--putty);color:var(--ink);border:1px solid var(--ink);
  box-shadow:inset 1px 1px 0 var(--putty-hi),inset -1px -1px 0 var(--putty-sh);
}
#dlgClose{cursor:pointer}
.win__body{padding:clamp(18px,3vw,32px)}

.sunken{
  background:#fff;border:1px solid var(--putty-sh);
  box-shadow:inset 1.5px 1.5px 0 rgba(107,92,168,.6),inset -1px -1px 0 #fff;
}
.sunken--in{display:flex;align-items:center;gap:10px;padding:12px 14px;margin-top:10px}

/* ═══ BOOT ════════════════════════════════════════════ */
.boot{position:fixed;inset:0;z-index:80;background:var(--night);display:grid;place-items:center;padding:20px}
.win--boot{width:min(420px,90vw)}
.boot__line{font-family:var(--mono);font-size:11px;letter-spacing:.16em}
.boot .sunken{height:20px;margin-top:14px;padding:2px}
.boot__bar{height:100%;width:0;background:repeating-linear-gradient(90deg,var(--acid) 0 10px,transparent 10px 13px)}
.boot__pct{margin-top:10px;font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-align:right}
.boot__enter{display:block;width:100%;margin-top:16px;padding:14px 20px}
.boot__enter[hidden]{display:none}

/* ═══ NAV ═════════════════════════════════════════════ */
.nav{
  position:fixed;top:0;left:0;right:0;z-index:40;
  display:flex;align-items:center;justify-content:space-between;
  padding:16px var(--pad);
  font-family:var(--mono);font-size:11px;letter-spacing:.2em;
}
.nav__mark{display:flex;align-items:center;gap:9px;font-weight:700}
.blip{width:7px;height:7px;background:var(--acid);border-radius:50%;box-shadow:0 0 12px var(--acid);animation:blip 1.5s infinite}
@keyframes blip{0%,60%{opacity:1}80%{opacity:.1}100%{opacity:1}}
/* music toggle, sits beside the wordmark top-left */
.snd{
  /* margin-right:auto keeps it grouped with the wordmark instead of being
     centred by the nav's space-between */
  display:inline-flex;align-items:center;gap:6px;margin-left:14px;margin-right:auto;
  padding:5px 9px;cursor:pointer;color:var(--paper);
  background:rgba(241,233,255,.07);border:1px solid rgba(241,233,255,.3);
  font-family:var(--mono);font-size:9px;letter-spacing:.16em;
  transition:color .25s,border-color .25s,background .25s;
}
.snd:hover{color:var(--acid);border-color:var(--acid);background:rgba(184,240,42,.1)}
.snd__ico{width:15px;height:12px;flex:0 0 auto}
.snd__on{opacity:0}
.snd.is-on .snd__on{opacity:1}
.snd.is-on .snd__off{opacity:0}
.snd.is-on{color:var(--acid);border-color:rgba(184,240,42,.55)}
/* browser blocked autoplay: invite the tap that unlocks it */
.snd.is-pending{color:var(--acid);border-color:var(--acid);animation:sndPulse 1.7s ease-in-out infinite}
@keyframes sndPulse{50%{background:rgba(184,240,42,.22)}}
@media (max-width:680px){.snd__txt{display:none}.snd{margin-left:10px;padding:5px 7px}}
/* Three destination tabs plus the mark and the sound key is a lot for a 375px
   bar, and the nav's .2em tracking is expensive at that size. Tighten the tabs
   rather than dropping one - below 680px they are the only navigation left. */
@media (max-width:520px){
  .nav{padding:14px 13px}
  .nav__links{gap:6px}
  .nav__links a.nav__store,.nav__links a.nav__tab,
  .nav__links .chip{
    padding:5px 6px;font-size:9px;letter-spacing:.07em;
  }
  /* On the terminal page the bar carries three tabs AND the connect button,
     which will not fit a 375px phone however tight the padding gets. The row
     scrolls instead: min-width:0 is what lets a flex item shrink below its
     content, and nothing is dropped or clipped out of reach. The scrollbar is
     hidden because the bar is 28px tall. */
  .nav__links{
    min-width:0;overflow-x:auto;overscroll-behavior-x:contain;
    scrollbar-width:none;-ms-overflow-style:none;
  }
  .nav__links::-webkit-scrollbar{display:none}
}

.nav__links{display:flex;align-items:center;gap:clamp(12px,2.4vw,26px)}
.nav__links a{opacity:.75;transition:opacity .25s,color .25s}
.nav__links a:hover{opacity:1;color:var(--acid)}
/* Nav tabs: read as destinations rather than section numbers. A tab with no
   href yet carries a SOON badge, so nobody clicks into nothing. */
.nav__store,.nav__tab{
  position:relative;padding:7px 12px;font-weight:700;
  border:1px solid rgba(241,233,255,.32);
}
.nav__store:hover,.nav__tab:hover{border-color:var(--acid)}
.nav__store[aria-disabled="true"],.nav__tab[aria-disabled="true"]{cursor:default}
.nav__store[aria-disabled="true"]::after,.nav__tab[aria-disabled="true"]::after{
  content:"SOON";position:absolute;top:-7px;right:-10px;
  padding:1px 4px;font-size:7px;letter-spacing:.1em;
  background:var(--acid);color:var(--ink);border:1px solid var(--ink);
}
.nav__store.is-current,.nav__tab.is-current{color:var(--acid);border-color:var(--acid);opacity:1}

/* ── store page ────────────────────────────────────── */
.store__head{padding-bottom:clamp(28px,5vh,52px)}
.store__head h1{margin-top:16px}
/* the chrome THE SHOP wordmark, in place of a type-set heading */
.store__mark{display:block;width:clamp(230px,38vw,470px);margin-top:18px}
.store__mark img{
  display:block;width:100%;height:auto;
  filter:drop-shadow(0 14px 26px rgba(6,0,22,.6));
}
/* The same specular sweep as the hero wordmark on the terminal page, masked to
   this artwork's own glyphs so it only lights the metal. Points at the webp
   the <picture> has already fetched - the png would pull a second, larger copy
   of the same artwork purely to be used as a mask. */
.store__mark{position:relative}
.store__mark picture{display:block;line-height:0}
.store__mark::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(102deg,transparent 36%,rgba(255,255,255,.75) 46%,
             rgba(214,190,255,.5) 51%,transparent 60%);
  background-size:260% 100%;
  -webkit-mask:url("../img/store/the-shop.webp") center/100% 100% no-repeat;
          mask:url("../img/store/the-shop.webp") center/100% 100% no-repeat;
  mix-blend-mode:overlay;
  animation:sheen 6.5s linear infinite;
}
.store__head p{margin-top:18px;max-width:52ch;font-size:15px;line-height:1.6;opacity:.78}

/* ── media page ────────────────────────────────────── */
.media__head{padding-bottom:clamp(20px,3vh,36px)}
.media__head h1{margin-top:16px}
/* the chrome Media wordmark, in place of a type-set heading. wider and
   shorter than the store's mark, so it is sized larger to carry the same
   weight on the page */
.media__mark{display:block;width:clamp(240px,44vw,520px)}
.media__mark img{
  display:block;width:100%;height:auto;
  filter:drop-shadow(0 14px 26px rgba(6,0,22,.6));
}
/* The same specular sweep as the hero wordmark on the terminal page, masked to
   this artwork's own glyphs so it only lights the metal. Points at the webp
   the <picture> has already fetched - the png would pull a second, larger copy
   of the same artwork purely to be used as a mask. */
.media__mark{position:relative}
.media__mark picture{display:block;line-height:0}
.media__mark::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(102deg,transparent 36%,rgba(255,255,255,.75) 46%,
             rgba(214,190,255,.5) 51%,transparent 60%);
  background-size:260% 100%;
  -webkit-mask:url("../img/media/media-mark.webp") center/100% 100% no-repeat;
          mask:url("../img/media/media-mark.webp") center/100% 100% no-repeat;
  mix-blend-mode:overlay;
  animation:sheen 6.5s linear infinite;
}
.media__tv-sec{padding-top:clamp(6px,1.5vh,24px)}
/* the set, deliberately oversized: it is the whole page */
.media__tv{display:block;width:min(1000px,90vw);margin-inline:auto}
.media__tv-img{
  display:block;width:100%;height:auto;
  filter:drop-shadow(0 40px 54px rgba(6,0,22,.75));
}

/* ── collection page ───────────────────────────────── */
.collection__head{padding-bottom:clamp(20px,3vh,36px)}
.collection__head h1{margin-top:16px}
/* widest of the three chrome marks at nearly 3:1, so it is sized larger again
   to sit at the same optical height as the store's and media's */
.collection__mark{display:block;width:clamp(260px,54vw,660px)}
.collection__mark img{
  display:block;width:100%;height:auto;
  filter:drop-shadow(0 14px 26px rgba(6,0,22,.6));
}
/* The same specular sweep as the hero wordmark on the terminal page, masked to
   this artwork's own glyphs so it only lights the metal. Points at the webp
   the <picture> has already fetched - the png would pull a second, larger copy
   of the same artwork purely to be used as a mask. */
.collection__mark{position:relative}
.collection__mark picture{display:block;line-height:0}
.collection__mark::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(102deg,transparent 36%,rgba(255,255,255,.75) 46%,
             rgba(214,190,255,.5) 51%,transparent 60%);
  background-size:260% 100%;
  -webkit-mask:url("../img/collection/collection-mark.webp") center/100% 100% no-repeat;
          mask:url("../img/collection/collection-mark.webp") center/100% 100% no-repeat;
  mix-blend-mode:overlay;
  animation:sheen 6.5s linear infinite;
}

/* ── the krew grid ─────────────────────────────────────
   Two rows of the collection drifting in opposite directions. Each track holds
   its set twice and animates to exactly -50%, which lands on the second copy,
   so there is never a visible seam or jump. */
/* .sec is declared further down the file with the same specificity, so a
   plain .krewgrid-sec loses the padding fight on source order and the rows end
   up inset instead of running off both edges. Doubling up on .sec wins it. */
.sec.krewgrid-sec{
  padding-left:0;padding-right:0;
  padding-top:clamp(18px,3vh,44px);
  padding-bottom:clamp(40px,7vh,90px);
  overflow:hidden;
}
.krewgrid{display:flex;flex-direction:column;gap:clamp(12px,1.6vw,22px)}
.krewgrid__row{
  overflow:hidden;
  /* fade the tiles out at both ends rather than cutting them off square */
  -webkit-mask:linear-gradient(90deg,transparent 0,#000 9%,#000 91%,transparent 100%);
          mask:linear-gradient(90deg,transparent 0,#000 9%,#000 91%,transparent 100%);
}
.krewgrid__track{
  display:flex;align-items:center;width:max-content;
  /* Spacing is a margin on each tile, NOT flex gap. With gap the track is
     46 tiles + 45 gaps, so half of it falls half a gap short of the second
     copy and the loop jumps once per cycle. As a margin every tile carries
     its own trailing space, both halves are identical, and -50% lands exactly. */
  /* The row clips its overflow to keep the marquee inside its own edges, so it
     has to be tall enough to contain a tile at full hover scale plus the wave
     offset - otherwise the magnified tile gets its top and bottom sliced off. */
  padding:clamp(54px,7.5vw,96px) 0;
  animation:krewscroll 78s linear infinite;
  will-change:transform;
}
.krewgrid__tile{margin-right:clamp(10px,1.5vw,20px)}
.krewgrid__row--rev .krewgrid__track{animation-direction:reverse}
@keyframes krewscroll{
  from{transform:translate3d(0,0,0)}
  to  {transform:translate3d(-50%,0,0)}
}
.krewgrid__tile{
  flex:0 0 auto;display:block;position:relative;
  width:clamp(120px,16.5vw,230px);height:auto;aspect-ratio:1;
  object-fit:cover;
  /* the squircle of the reference, not a plain rounded rect */
  border-radius:23%;
  background:rgba(241,233,255,.05);
  box-shadow:0 10px 24px rgba(6,0,22,.55);
  /* The wave and the dock magnification have to share one transform, so the
     wave lives in custom properties and krew.js only ever writes --dock. If the
     wave were written straight into transform, setting it from JS would wipe
     the wave out.
     NOT --mag: that name is already the brand magenta on :root, so var(--mag,1)
     inherited a colour, calc() went invalid and the whole transform - wave and
     all - silently computed to none. */
  transform:translateY(var(--wave-y,0px)) scale(calc(var(--wave-s,1) * var(--dock,1)));
  transition:transform .24s cubic-bezier(.2,.8,.25,1), box-shadow .24s ease;
  will-change:transform;
}
/* The wave. A six step cycle so it reads as a drift rather than a zigzag, with
   the sizes nudged too so the rows have some depth to them. */
.krewgrid__tile:nth-child(6n+1){--wave-y:-17px;--wave-s:.94}
.krewgrid__tile:nth-child(6n+2){--wave-y:9px;  --wave-s:1}
.krewgrid__tile:nth-child(6n+3){--wave-y:-6px; --wave-s:1.04}
.krewgrid__tile:nth-child(6n+4){--wave-y:18px; --wave-s:.97}
.krewgrid__tile:nth-child(6n+5){--wave-y:-11px;--wave-s:1.02}
.krewgrid__tile:nth-child(6n+6){--wave-y:5px;  --wave-s:.95}
/* Dock style pop: ONLY the tile under the pointer grows. z-index lifts it
   clear so its neighbours cannot overlap the enlarged square.
   Gated on a real pointer: on a touchscreen :hover latches after a tap and the
   tile would stay stuck at full size until something else was tapped. */
@media (hover:hover){
  .krewgrid__tile:hover{
    --dock:1.55;
    z-index:3;
    /* No bigger shadow here on purpose. The tile's own shadow scales with it,
       and a deeper one would reach past the row's clearance and get sliced off
       by the row's overflow clip. */
  }
}
/* no pointer, no magnification: on touch the rows just drift */
@media (hover:none){
  .krewgrid__tile{transition:none}
}
/* let someone stop the drift to look at one */
.krewgrid:hover .krewgrid__track{animation-play-state:paused}
@media (prefers-reduced-motion: reduce){
  .krewgrid__track{animation:none}
  .krewgrid__row{overflow-x:auto;scrollbar-width:none}
  .krewgrid__row::-webkit-scrollbar{display:none}
}

/* ── the TV screen ─────────────────────────────────────
   tv.js sizes and maps .tv__screen onto the glass with a matrix3d, so nothing
   here should set its width, height or transform. */
.tv{position:relative}
.tv__screen{
  position:absolute;left:0;top:0;
  transform-origin:0 0;
  overflow:hidden;background:#000;
  /* the tube is not flat, so the corners fall away */
  border-radius:2.4% / 3%;
}
.tv__video{
  width:100%;height:100%;display:block;
  /* the masters are 16:9 and the tube is nearer 5:4, so letterbox rather than
     crop - which is exactly what widescreen looked like on one of these */
  object-fit:contain;background:#000;
  filter:saturate(.88) contrast(1.06) brightness(.94);
}
/* phosphor lines. tied to the element, so they scale with the mapped screen */
.tv__scan{
  position:absolute;inset:0;pointer-events:none;opacity:.34;
  background:repeating-linear-gradient(to bottom,
    rgba(0,0,0,.42) 0 1px, transparent 1px 3px);
  mix-blend-mode:multiply;
}
/* the curve of the glass, plus the reflection along the top left */
.tv__glass{
  position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(143deg,
      rgba(255,255,255,.20) 0%,
      rgba(255,255,255,.07) 12%,
      transparent 30%),
    radial-gradient(128% 108% at 46% 40%, transparent 52%, rgba(0,0,0,.62) 100%);
}
/* the burst between channels */
.tv__static{
  position:absolute;inset:0;pointer-events:none;opacity:0;
  background:
    repeating-linear-gradient(to bottom,
      rgba(255,255,255,.10) 0 2px, rgba(0,0,0,.10) 2px 4px),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.85'/%3E%3C/svg%3E");
  background-size:100% 4px, 180px 180px;
}
.tv.is-tuning .tv__static{opacity:1;animation:tvsnow .18s steps(3) infinite}
/* the picture tears and rolls while it retunes */
.tv.is-tuning .tv__video{filter:contrast(1.5) brightness(1.2) saturate(.2)}
@keyframes tvsnow{
  0%  {background-position:0 0,      0 0}
  33% {background-position:0 -2px, -46px 38px}
  66% {background-position:0 1px,   37px -29px}
  100%{background-position:0 -1px, -18px 12px}
}
/* channel readout, the way a set from this era drew it */
.tv__osd{
  position:absolute;left:5.5%;top:6%;margin:0;pointer-events:none;
  font-family:var(--mono);font-size:clamp(9px,1.5vw,15px);letter-spacing:.14em;
  color:#dfffb8;text-shadow:0 0 8px rgba(184,240,42,.75),0 2px 0 rgba(0,0,0,.7);
  opacity:0;
}
.tv__osd.is-on{animation:tvosd 3.1s ease forwards}
@keyframes tvosd{0%,72%{opacity:1}100%{opacity:0}}

/* The two live keys on the set's control strip, in percentages of the
   artwork so they stay on their keys at any width. Fast-forward changes
   channel; stop mutes the TV. Both are transparent - the button you see is
   the one in the picture. */
.tv__ff,.tv__mute{
  position:absolute;top:83.5%;height:3.0%;
  padding:0;border:0;background:transparent;cursor:pointer;
  border-radius:2px;
}
.tv__ff  {left:46.85%;width:3.6%}
.tv__mute{left:43.24%;width:3.2%}
.tv__ff:hover,.tv__ff:focus-visible,
.tv__mute:hover,.tv__mute:focus-visible{
  outline:none;
  box-shadow:0 0 0 1px rgba(184,240,42,.85),0 0 14px 3px rgba(184,240,42,.5);
  background:rgba(184,240,42,.16);
  animation:none;                 /* the attract glow must not fight a hover */
}

/* Attract glow. The keys are part of the photograph, so nothing signals that
   they are live. A glow passes along the strip - stop first, then fast-forward
   a beat later, which reads as one light travelling rather than two blinking.
   Idle for most of the cycle so it stays a hint, not a strobe. tv.js drops
   .is-hinting the first time either key is used.

   It is a radial gradient on a pseudo-element, NOT a box-shadow: a shadow on a
   rectangular button draws a rectangle, and the outline of that box was
   showing through the key. This fades to nothing in every direction, so only
   the light is visible. Sized past the key so the falloff has somewhere to go. */
.tv__ff::before,.tv__mute::before{
  content:"";position:absolute;inset:-70% -45%;
  pointer-events:none;opacity:0;
  background:radial-gradient(closest-side,
    rgba(184,240,42,.36) 0%, rgba(184,240,42,.15) 42%, rgba(184,240,42,0) 76%);
}
@keyframes tvhint{
  0%,62%,100%{opacity:0}
  74%        {opacity:1}
  86%        {opacity:0}
}
.tv.is-hinting .tv__mute::before{animation:tvhint 5.2s ease-in-out infinite}
.tv.is-hinting .tv__ff::before  {animation:tvhint 5.2s ease-in-out .42s infinite}
/* a hover, or a TV already making noise, outranks the hint */
.tv__ff:hover::before,.tv__ff:focus-visible::before,
.tv__mute:hover::before,.tv__mute:focus-visible::before,
.tv.is-hinting .tv__mute.is-on::before{animation:none;opacity:0}
@media (prefers-reduced-motion: reduce){
  .tv.is-hinting .tv__mute::before,.tv.is-hinting .tv__ff::before{animation:none}
}
/* while the TV is actually making noise the key stays lit, so it is obvious
   which of the two sound controls on the page is the live one */
.tv__mute.is-on{
  background:rgba(184,240,42,.30);
  box-shadow:0 0 0 1px rgba(184,240,42,.9),0 0 16px 4px rgba(184,240,42,.55);
}
.tv__tip{
  position:absolute;left:50%;bottom:calc(100% + 9px);transform:translateX(-50%);
  padding:4px 7px;white-space:nowrap;
  font-family:var(--mono);font-size:9px;letter-spacing:.12em;
  color:var(--ink);background:var(--acid);border:1px solid var(--ink);
  opacity:0;transition:opacity .2s;pointer-events:none;
}
.tv__ff:hover .tv__tip,.tv__ff:focus-visible .tv__tip,
.tv__mute:hover .tv__tip,.tv__mute:focus-visible .tv__tip{opacity:1}
@media (max-width:680px){
  /* The keys are only ~13px across on a phone. Each target is grown to about
     44px, splitting the strip between them so they do not overlap each other.
     They are invisible and no other key does anything, so covering their
     neighbours costs nothing. */
  .tv__ff  {left:47.5%;top:80.1%;width:13%;height:13%}
  .tv__mute{left:34.5%;top:80.1%;width:13%;height:13%}
  .tv__tip{display:none}
}

/* ── merch fan ─────────────────────────────────────────
   Cards spread along an arc like a dealt hand. Positions come from rack.js
   so the geometry can adapt to the viewport. */
.rack-sec{padding-top:clamp(20px,3vh,40px)}
.rack{position:relative}
.rack__stage{
  position:relative;height:clamp(470px,66vh,700px);
  overflow:hidden;                       /* cards leaving the fan are clipped */
}
.rack__ring{
  position:absolute;inset:0;
  cursor:grab;touch-action:pan-y;
}
.rack__ring.is-drag{cursor:grabbing}

.fan__card{
  position:absolute;left:50%;top:50%;margin:0;
  width:clamp(240px,33vw,390px);
  aspect-ratio:3/4;
  border-radius:28px;
  background:linear-gradient(165deg,#2A1160 0%,#1A0940 60%,#120630 100%);
  border:1px solid rgba(241,233,255,.14);
  box-shadow:0 26px 40px rgba(6,0,22,.65);
  display:flex;flex-direction:column;
  overflow:hidden;cursor:pointer;
  transition:opacity .35s, box-shadow .35s, border-color .35s;
  will-change:transform;
}
/* soft sheen so the cards read as physical */
.fan__card::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(150deg,rgba(255,255,255,.14),transparent 42%);
}
/* two-view cards: a 3D flipper holding a front and a back face */
.fan__flip{
  position:absolute;inset:0;transform-style:preserve-3d;
  transition:transform .6s cubic-bezier(.2,.8,.2,1);
}
.fan__card.is-flipped .fan__flip{transform:rotateY(180deg)}
.fan__face{
  position:absolute;inset:0;display:flex;flex-direction:column;
  backface-visibility:hidden;
}
.fan__face--back{transform:rotateY(180deg)}
/* turn control, only on the centred two-view card */
.fan__turn{
  position:absolute;right:8px;bottom:8px;z-index:3;
  width:26px;height:26px;border-radius:50%;cursor:pointer;
  font-size:13px;line-height:1;color:var(--ink);background:var(--acid);
  border:1px solid var(--ink);opacity:0;pointer-events:none;
  transition:opacity .3s, transform .3s;
}
.fan__card.is-front.has-alt .fan__turn{opacity:1;pointer-events:auto}
.fan__card.is-front.has-alt:hover .fan__turn{transform:rotate(90deg)}

.fan__art{flex:1 1 auto;display:grid;place-items:center;padding:8% 8% 2%}
.fan__art img{
  width:100%;height:100%;object-fit:contain;display:block;pointer-events:none;
  filter:drop-shadow(0 10px 16px rgba(0,0,0,.55));
}
.fan__label{
  padding:0 12px 12px;text-align:center;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;
  text-transform:uppercase;opacity:.65;
}
/* the card in the middle */
.fan__card.is-front{
  border-color:rgba(184,240,42,.5);
  box-shadow:0 30px 46px rgba(6,0,22,.7),0 0 34px rgba(184,240,42,.22);
}
.fan__card.is-front .fan__label{opacity:1;color:var(--acid)}

/* ── the camera's right key ─────────────────────────────
   The D-pad on the camera art is a photograph, so nothing says it can be
   pressed. This puts a transparent button exactly on the right key and gives
   it the same passing glow the TV keys use - a radial gradient on a pseudo
   element, never a box-shadow, so no rectangle shows through the artwork.
   cam.js drops .is-hinting the first time it is used. */
.cam{position:relative}
.cam__next{
  position:absolute;left:83.2%;top:57.5%;width:3.6%;height:13.5%;
  padding:0;border:0;background:transparent;cursor:pointer;
}
.cam__next::before{
  content:"";position:absolute;inset:-85% -150%;
  pointer-events:none;opacity:0;
  background:radial-gradient(closest-side,
    rgba(184,240,42,.40) 0%, rgba(184,240,42,.16) 42%, rgba(184,240,42,0) 76%);
}
@keyframes camhint{
  0%,60%,100%{opacity:0}
  72%        {opacity:1}
  85%        {opacity:0}
}
.cam.is-hinting .cam__next::before{animation:camhint 4.6s ease-in-out infinite}
.cam__next:hover::before,.cam__next:focus-visible::before{animation:none;opacity:1}
.cam__next:focus-visible{outline:none}
.cam__next-tip{
  position:absolute;left:50%;bottom:calc(100% + 10px);transform:translateX(-50%);
  padding:4px 7px;white-space:nowrap;
  font-family:var(--mono);font-size:9px;letter-spacing:.12em;
  color:var(--ink);background:var(--acid);border:1px solid var(--ink);
  opacity:0;transition:opacity .2s;pointer-events:none;
}
.cam__next:hover .cam__next-tip,.cam__next:focus-visible .cam__next-tip{opacity:1}
@media (prefers-reduced-motion: reduce){
  .cam.is-hinting .cam__next::before{animation:none}
}
@media (max-width:680px){
  /* the key is about 11px across on a phone, so grow the tap target around
     its own centre without moving the thing you can see */
  .cam__next{left:77.5%;top:53.2%;width:15%;height:22%}
  .cam__next-tip{display:none}
}

/* ── zoomed product ────────────────────────────────────
   No card, no panel: just the garment on the dimmed page. */
.pop{
  position:fixed;inset:0;z-index:120;display:none;
  place-items:center;padding:clamp(16px,4vw,48px);
  background:rgba(14,4,42,.93);backdrop-filter:blur(14px);
  opacity:0;transition:opacity .3s;
}
.pop.on{display:grid}
.pop.is-open{opacity:1}
.pop__img{
  max-width:min(92vw,900px);max-height:80vh;width:auto;height:auto;
  display:block;
  filter:drop-shadow(0 40px 60px rgba(0,0,0,.8))
         drop-shadow(0 0 70px rgba(184,240,42,.16));
  transform-origin:center center;
  will-change:transform;
}
.pop__close{
  position:absolute;top:clamp(12px,2.5vw,26px);right:clamp(12px,2.5vw,26px);
  width:42px;height:42px;cursor:pointer;font-size:22px;line-height:1;
  color:var(--ink);background:var(--putty);border:1px solid var(--ink);
  box-shadow:inset 1.5px 1.5px 0 var(--putty-hi),inset -1.5px -1.5px 0 var(--putty-sh);
}
.pop__close:hover{background:#DED6F5}
.pop__turn{
  position:absolute;bottom:clamp(76px,11vh,104px);left:50%;transform:translateX(-50%);
  padding:11px 18px;cursor:pointer;
  font-family:var(--mono);font-size:10px;letter-spacing:.16em;font-weight:700;
  color:var(--ink);background:var(--acid);border:1px solid var(--ink);
  box-shadow:inset 1.5px 1.5px 0 rgba(255,255,255,.7),inset -1.5px -1.5px 0 var(--acid-dp);
}
.pop__turn[hidden]{display:none}
.pop__meta{position:absolute;bottom:clamp(18px,4vh,38px);left:0;right:0;text-align:center}
.pop__name{
  font-family:var(--sans);font-size:clamp(18px,3vw,30px);
  letter-spacing:-.02em;text-transform:uppercase;
}
.pop__cat{
  margin-top:5px;font-family:var(--mono);font-size:9px;
  letter-spacing:.26em;color:var(--acid);text-transform:uppercase;
}

/* pool of light under the fan */
.rack__floor{
  position:relative;height:64px;margin-top:-30px;pointer-events:none;
  background:radial-gradient(46% 100% at 50% 0%,rgba(184,240,42,.14),transparent 72%);
}

.rack__caption{text-align:center;margin-top:6px;min-height:78px}
.rack__name{
  font-family:var(--sans);font-size:clamp(18px,2.6vw,26px);
  letter-spacing:-.02em;text-transform:uppercase;
}
.rack__meta{
  margin-top:5px;font-family:var(--mono);font-size:9px;
  letter-spacing:.26em;color:var(--acid);text-transform:uppercase;
}
/* Trait-unlock items only. Boxed and violet so it reads as a status, not
   another category line. */
.rack__tag,.pop__tag{
  display:inline-block;margin-top:7px;padding:3px 9px;
  font-family:var(--mono);font-size:8.5px;letter-spacing:.24em;
  text-transform:uppercase;color:var(--violet-lt);
  border:1px solid rgba(155,69,255,.55);border-radius:3px;
  background:rgba(155,69,255,.12);
}
.rack__tag[hidden],.pop__tag[hidden]{display:none}

.rack__ctrls{display:flex;align-items:center;justify-content:center;gap:16px;margin-top:12px}
.rack__btn{
  width:40px;height:36px;cursor:pointer;font-size:18px;line-height:1;
  color:var(--ink);background:var(--putty);border:1px solid var(--ink);
  box-shadow:inset 1.5px 1.5px 0 var(--putty-hi),inset -1.5px -1.5px 0 var(--putty-sh);
}
.rack__btn:hover{background:#DED6F5}
.rack__btn:active{box-shadow:inset -1.5px -1.5px 0 var(--putty-hi),inset 1.5px 1.5px 0 var(--putty-sh)}
.rack__pos{font-family:var(--mono);font-size:10px;letter-spacing:.2em;opacity:.75;min-width:52px;text-align:center}
.rack__hint{
  margin-top:12px;text-align:center;font-family:var(--mono);
  font-size:9px;letter-spacing:.24em;opacity:.5;transition:opacity .4s;
}


.store__grid{
  list-style:none;padding:0;margin:0;display:grid;gap:clamp(14px,2.4vw,22px);
  grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
}
.card{
  background:var(--putty);color:var(--ink);border:1px solid var(--ink);
  box-shadow:inset 1.5px 1.5px 0 var(--putty-hi),inset -1.5px -1.5px 0 var(--putty-sh),
             6px 6px 0 rgba(12,3,36,.55);
  display:flex;flex-direction:column;
}
.card__art{
  aspect-ratio:1/1;display:grid;place-items:center;margin:8px;
  background:linear-gradient(160deg,#2A1160,#160840);
  border:1px solid var(--putty-sh);
  box-shadow:inset 2px 2px 0 rgba(0,0,0,.45);
}
.card__art img{width:100%;height:100%;object-fit:cover;display:block}
.card__ph{font-family:var(--mono);font-size:9px;letter-spacing:.26em;color:rgba(241,233,255,.35)}
.card__body{padding:12px 14px 14px;display:flex;flex-direction:column;gap:4px;flex:1 1 auto}
.card__name{font-size:16px;font-weight:700;letter-spacing:-.01em}
.card__meta{font-family:var(--mono);font-size:9px;letter-spacing:.2em;opacity:.6}
.card__row{margin-top:auto;padding-top:12px;display:flex;align-items:center;justify-content:space-between;gap:10px}
.card__price{font-family:var(--mono);font-size:13px;font-weight:700}
.card__cta{
  font-family:var(--mono);font-size:10px;letter-spacing:.14em;font-weight:700;
  padding:8px 12px;background:var(--acid);color:var(--ink);border:1px solid var(--ink);
  box-shadow:inset 1.5px 1.5px 0 rgba(255,255,255,.7),inset -1.5px -1.5px 0 var(--acid-dp);
}
.card__cta--soon{background:var(--putty);box-shadow:inset 1.5px 1.5px 0 var(--putty-hi),inset -1.5px -1.5px 0 var(--putty-sh);opacity:.75}
.card--soon .card__art{filter:saturate(.5)}

/* ── camera ────────────────────────────────────────────
   Large and centred under the rack. A transparent cutout, so it gets a cast
   shadow rather than a panel: it should read as an object sitting on the
   field, the same way the merch does. */
.store__cam-sec{padding-top:clamp(10px,2vh,34px)}
.cam{position:relative;width:min(880px,82vw);margin-inline:auto}
.store__cam{display:block;width:100%}
.store__cam-img{
  display:block;width:100%;height:auto;
  filter:drop-shadow(0 34px 46px rgba(6,0,22,.72));
}

/* ── the LCD ───────────────────────────────────────────
   Measured off the camera art, so these percentages are not arbitrary: the
   glass sits at 9.5%/30% and runs 48% x 57% of the image. Keeping them in
   percentages means the screen tracks the photo at any width. */
.cam__screen{
  position:absolute;left:9.5%;top:30%;width:48%;height:57%;
  overflow:hidden;border-radius:2.2% / 2.8%;
  background:#05060a;
  /* the glass is inset in the bezel, so it catches a hard inner shadow */
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.9), inset 0 2px 10px rgba(0,0,0,.85);
}
.cam__shots{position:absolute;inset:0}
.cam__shots img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .9s ease;
  /* a 2000s LCD: cool, soft, slightly crushed, never quite accurate. the
     blur is deliberate - these panels were low resolution and nothing on
     them ever looked properly sharp */
  filter:saturate(.74) contrast(1.04) brightness(.88) hue-rotate(-5deg) blur(.35px);
}
.cam__shots img.is-on{opacity:1}
/* LCD blacks are never black. lifting them is most of what separates a panel
   from a hole cut in the camera */
.cam__shots::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:rgba(126,146,186,.16);
  mix-blend-mode:screen;
}
/* the pixel lattice of a cheap TFT, only just visible */
.cam__grid{
  position:absolute;inset:0;pointer-events:none;opacity:.32;
  background:
    repeating-linear-gradient(to bottom, rgba(0,0,0,.22) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(to right,  rgba(0,0,0,.14) 0 1px, transparent 1px 3px);
  mix-blend-mode:multiply;
}
/* The cover glass. A sheet of scratched plastic sitting a couple of
   millimetres above the panel: a hard specular streak where the light lands,
   a narrower second reflection below it, an overall haze because glass is
   never perfectly clear, and the darkening into the bezel. */
.cam__glass{
  position:absolute;inset:0;pointer-events:none;
  background:
    /* the main reflection, with a defined trailing edge */
    linear-gradient(147deg,
      rgba(255,255,255,.60) 0%,
      rgba(255,255,255,.46) 5%,
      rgba(255,255,255,.26) 11%,
      rgba(255,255,255,.13) 16%,
      rgba(255,255,255,.05) 21%,
      transparent 27%),
    /* a second, narrower bar of reflected light */
    linear-gradient(147deg,
      transparent 33%,
      rgba(255,255,255,.05) 37%,
      rgba(255,255,255,.20) 42%,
      rgba(255,255,255,.06) 47%,
      transparent 52%),
    /* off-axis wash toward the far corner */
    linear-gradient(318deg, rgba(176,198,232,.20) 0%, transparent 44%),
    /* the haze of the sheet itself */
    linear-gradient(rgba(198,214,238,.07), rgba(198,214,238,.07)),
    /* into the bezel */
    radial-gradient(125% 96% at 50% 44%, transparent 40%, rgba(0,0,0,.62) 100%);
}
/* the room reflected along the top edge, where the glass meets the bezel */
.cam__glass::after{
  content:"";position:absolute;left:0;right:0;top:0;height:30%;
  background:linear-gradient(to bottom, rgba(255,255,255,.22), transparent);
  pointer-events:none;
}
@media (prefers-reduced-motion: reduce){
  .cam__shots img{transition:none}
}
.chip{
  font-family:var(--mono);font-size:10px;letter-spacing:.16em;cursor:pointer;
  padding:8px 14px;color:var(--ink);background:var(--acid);border:1px solid var(--ink);
  box-shadow:inset 1.5px 1.5px 0 rgba(255,255,255,.7),inset -1.5px -1.5px 0 var(--acid-dp);
  font-weight:700;
}
.chip:active{box-shadow:inset -1.5px -1.5px 0 rgba(255,255,255,.6),inset 1.5px 1.5px 0 var(--acid-dp)}

/* ═══ HERO ════════════════════════════════════════════ */
.hero{min-height:100svh;padding:0 var(--pad);display:flex;flex-direction:column;justify-content:center;gap:clamp(24px,5vh,54px)}
.hero__meta{display:flex;align-items:center;gap:12px;font-family:var(--mono);font-size:10px;letter-spacing:.24em;opacity:.85}
.rule{flex:1 1 auto;height:1px;background:repeating-linear-gradient(90deg,currentColor 0 5px,transparent 5px 10px);opacity:.5}
.hero__title{display:flex;flex-direction:column}
.line{display:block;overflow:hidden}
/* chrome wordmark artwork, sized to fill the hero */
/* margin-inline:auto — without it the capped width pins the mark to the left
   edge on any viewport wider than 1180px */
.hero__mark{display:block;position:relative;width:100%;max-width:1180px;margin-inline:auto}
/* No drop-shadow here. `.line` clips overflow to mask the reveal, so any glow
   wider than the artwork gets cut off square at the image box and reads as a
   faint rectangle behind the letters. The chrome carries its own depth. */
.hero__mark img{width:100%;height:auto}
/* specular sweep, masked to the glyphs so it only lights the metal */
.hero__mark::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(102deg,transparent 36%,rgba(255,255,255,.75) 46%,
             rgba(214,190,255,.5) 51%,transparent 60%);
  background-size:260% 100%;
  /* masked with the webp the <picture> already fetched — pointing this at the
     png would pull a second, much larger copy of the same artwork */
  -webkit-mask:url("../img/wordmark.webp") center/100% 100% no-repeat;
          mask:url("../img/wordmark.webp") center/100% 100% no-repeat;
  mix-blend-mode:overlay;
  animation:sheen 6.5s linear infinite;
}
.hero__foot{display:flex;flex-wrap:wrap;gap:clamp(20px,5vw,60px);align-items:flex-end;justify-content:space-between}
.hero__sub{font-size:clamp(14px,1.6vw,18px);line-height:1.5;max-width:34ch}
.hero__krew{
  display:inline-block;margin-top:14px;
  font-family:var(--mono);font-size:11px;letter-spacing:.22em;
  text-transform:uppercase;color:var(--acid);
  border-bottom:1px solid rgba(184,240,42,.45);padding-bottom:3px;
  transition:border-color .25s,opacity .25s;
}
.hero__krew:hover{border-color:var(--acid);opacity:.85}
.hero__scroll{
  display:inline-flex;align-items:center;gap:12px;text-align:right;
  font-family:var(--mono);font-size:10px;letter-spacing:.2em;line-height:1.7;
  border-bottom:1px solid rgba(241,233,255,.35);padding-bottom:6px;transition:color .25s,border-color .25s;
}
.hero__scroll:hover{color:var(--acid);border-color:var(--acid)}
.hero__scroll svg{animation:bob 1.7s ease-in-out infinite}
@keyframes bob{50%{transform:translateY(4px)}}

/* ═══ MARQUEE ═════════════════════════════════════════ */
.marq{
  overflow:hidden;padding:9px 0;
  border-top:1px solid rgba(241,233,255,.22);border-bottom:1px solid rgba(241,233,255,.22);
}
.marq--alt{background:var(--acid);color:var(--ink);border-color:var(--ink)}
.marq__t{display:flex;white-space:nowrap;font-family:var(--mono);font-weight:700;font-size:clamp(11px,1.5vw,15px);letter-spacing:.22em}
.marq__t span{padding:0 18px;display:inline-block}
.marq__t .dot{color:var(--mag)}
.marq--alt .dot{color:var(--violet)}

/* ═══ ART BAND ════════════════════════════════════════ */
.art{position:relative;overflow:hidden}
.art__img{width:100%;height:auto;display:block}
/* feather the art into the field top and bottom */
.art::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,var(--night) 0%,transparent 12%,transparent 90%,var(--night) 100%);
}
.art__cap{
  position:absolute;left:var(--pad);bottom:clamp(20px,4vh,44px);z-index:2;
  font-family:var(--mono);font-size:10px;letter-spacing:.24em;color:var(--acid-hi);
  text-shadow:0 2px 12px rgba(12,3,36,.9);
}

/* ═══ STATEMENT ═══════════════════════════════════════ */
.stmt{padding:clamp(70px,13vh,150px) var(--pad)}
/* each statement holds its own line — no measure cap, and the type scales
   off viewport width so the longest line always fits */
.stmt p{
  font-family:var(--mono);font-size:clamp(9px,2.55vw,30px);line-height:1.45;
  letter-spacing:.01em;text-transform:uppercase;text-wrap:balance;
}
.stmt p br{display:none}          /* spacing comes from the lines themselves */
.stmt .ln{display:block}
.stmt .ln + .ln{margin-top:1.15em}
.stmt em{font-style:normal;color:var(--acid)}
/* the block is uppercased, so the brand needs an exemption to keep its casing */
.brand{text-transform:none}

/* ═══ SECTIONS ════════════════════════════════════════ */
.sec{padding:clamp(70px,12vh,150px) var(--pad)}
.sec__head{margin-bottom:clamp(30px,6vh,60px);max-width:60ch}
.tag{font-family:var(--mono);font-size:10px;letter-spacing:.26em;color:var(--acid)}
.sec__head h2{margin-top:16px}
.sec__head p{margin-top:18px;max-width:46ch;font-size:15px;line-height:1.6;opacity:.78}

/* ═══ 3D STAGE ════════════════════════════════════════ */
.stage{position:relative;width:100%;perspective:1600px}
/* the CRT artwork; the live screen is mapped onto its glass by crt.js */
.crt{
  position:relative;width:min(100%,860px);margin:0 auto;
  aspect-ratio:1300/1196;transform-style:preserve-3d;
  filter:drop-shadow(0 26px 30px rgba(8,0,30,.55));
}
.crt__img{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}

/* the HTML mapped onto the CRT glass */
/* authored at the size computer.js scales into world units — keeps the
   projected UI at roughly 1:1 so the text stays sharp */
.screen{
  position:absolute;left:0;top:0;transform-origin:0 0;
  width:460px;height:340px;overflow:hidden;background:var(--night);
  /* Elliptical, percentage-based so it scales with the element — a CRT face
     curves into its corners rather than turning a fixed radius. */
  border-radius:6% / 8%;
}
/* Y2K desktop wallpaper. The file is pre-cropped to the screen's exact 460:340
   ratio, so 100% 100% fills it with no stretch and nothing cropped at runtime. */
.desktop{
  position:relative;width:100%;height:100%;
  /* window sits low so the Y2K atom in the wallpaper stays visible above it */
  padding:15px;display:grid;place-items:end center;
  background-image:image-set(url("../img/wallpaper.webp") type("image/webp"),
                             url("../img/wallpaper.jpg")  type("image/jpeg"));
  background-size:100% 100%;background-position:center;background-repeat:no-repeat;
}
/* Sticker slapped on the case, left of the screen. Sized as a % of the CRT so
   it scales with the artwork instead of drifting at other viewport widths. */
.sticker{
  position:absolute;left:4.2%;top:37%;width:15%;height:auto;z-index:2;
  transform:rotate(-8deg);
  border-radius:3px;
  filter:drop-shadow(2px 4px 5px rgba(8,0,30,.55));
}

/* Period pointing-hand cursor, but only over the machine itself. The PNG is a
   hand-plotted 32x32 bitmap; the hotspot sits on the fingertip. */
.crt, .crt *{cursor:url("../img/cursor-hand.png") 5 0, pointer}
.crt input{cursor:text}                 /* an I-beam is far easier to type against */

/* CRT glass. Kept light — a heavy vignette crushes the wallpaper. */
.glass{
  position:absolute;inset:0;pointer-events:none;
  background:
    repeating-linear-gradient(to bottom,rgba(0,0,0,.15) 0 1px,transparent 1px 3px),
    radial-gradient(135% 125% at 50% 48%,transparent 64%,rgba(10,0,30,.45) 100%);
  mix-blend-mode:multiply;
}
.glass::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(170deg,rgba(255,255,255,.22),transparent 38%);
  mix-blend-mode:screen;
}
/* fixed sizes inside the CRT: vw units would scale to the browser viewport,
   not the 460px screen, and blow the layout apart */
.screen .win__body{padding:14px}
.screen .win__bar{font-size:10px;padding:4px 5px 4px 8px}
.screen .fld__label{font-size:9px;letter-spacing:.2em}
.screen .sunken--in{padding:9px 10px;margin-top:8px}
.screen .sunken--in input{font-size:12px}
.screen .fld__hint{font-size:9px;margin-top:8px}
.screen .fld__row{gap:7px;margin-top:13px}
.screen .btn{padding:9px 13px;font-size:9.5px;letter-spacing:.12em}

/* ── desktop mail folder ───────────────────────────── */
.folder{
  position:absolute;right:7px;bottom:5px;z-index:4;
  display:grid;justify-items:center;gap:1px;
  background:none;border:0;padding:3px;cursor:pointer;
}
.folder__ico{width:26px;height:auto;display:block;filter:drop-shadow(1px 1px 0 rgba(0,0,0,.5))}
.folder__label{
  font-family:var(--mono);font-size:7.5px;letter-spacing:.12em;color:#fff;
  text-shadow:1px 1px 0 rgba(0,0,0,.9);
}
.folder__badge{
  position:absolute;top:0;right:0;min-width:13px;height:13px;padding:0 2px;
  border-radius:50%;background:#FF2B2B;border:1px solid #4E0000;color:#fff;
  font-family:var(--mono);font-size:8px;font-weight:700;line-height:1;
  display:grid;place-items:center;
  transform:scale(0);transition:transform .4s cubic-bezier(.2,1.6,.3,1);
}
.folder.has-mail .folder__badge{transform:scale(1)}
.folder__toast{
  position:absolute;right:0;bottom:calc(100% + 5px);white-space:nowrap;
  background:var(--putty);color:var(--ink);border:1px solid var(--ink);
  box-shadow:inset 1px 1px 0 var(--putty-hi),inset -1px -1px 0 var(--putty-sh),2px 2px 0 rgba(0,0,0,.45);
  font-family:var(--mono);font-size:7.5px;letter-spacing:.12em;padding:4px 6px;
  opacity:0;transform:translateY(4px);transition:opacity .3s,transform .3s;pointer-events:none;
}
.folder.has-mail .folder__toast{opacity:1;transform:translateY(0)}
.folder.has-mail .folder__ico{animation:nudge .45s ease-in-out 2}
@keyframes nudge{25%{transform:translateY(-2px) rotate(-4deg)}75%{transform:translateY(-1px) rotate(4deg)}}

/* the inbox window that opens on the CRT desktop */
.inbox{position:absolute;left:12px;top:12px;width:150px;z-index:5}
.inbox[hidden]{display:none}
.inbox .win__body{padding:10px}
.folder--item{position:static;display:grid;justify-items:center;gap:3px;width:100%}
.folder--item .folder__label{color:var(--ink);text-shadow:none;font-size:8px}
.folder--item:hover .folder__label{background:var(--violet-mid);color:#fff}

/* ── wallet picker ─────────────────────────────────── */
.wsel{position:fixed;inset:0;z-index:78;display:none;padding:var(--pad);
  overflow-y:auto;overscroll-behavior:contain;place-items:center;place-items:safe center;
  background:rgba(22,8,64,.9);backdrop-filter:blur(10px)}
.wsel.on{display:grid}
/* Glossy card rather than the flat Win98 panel: a dark glass sheet with a
   light sheen across the top, and rows that lift on hover. */
.wsel__win{
  width:min(420px,94vw);border:1px solid rgba(241,233,255,.16);
  background:linear-gradient(168deg,#2A1466 0%,#1B0B47 46%,#150838 100%);
  box-shadow:0 30px 70px rgba(4,0,20,.7),inset 0 1px 0 rgba(255,255,255,.16);
  border-radius:16px;overflow:hidden;position:relative;
}
.wsel__win::before{                      /* the gloss */
  content:"";position:absolute;left:0;right:0;top:0;height:46%;pointer-events:none;
  background:linear-gradient(180deg,rgba(255,255,255,.13),transparent);
}
.wsel__win .win__bar{
  background:linear-gradient(180deg,rgba(255,255,255,.12),rgba(255,255,255,.02));
  border-bottom:1px solid rgba(241,233,255,.12);color:var(--paper);
  padding:11px 12px;position:relative;
}
.wsel__win .win__btns i{
  background:rgba(241,233,255,.1);border:1px solid rgba(241,233,255,.22);
  color:var(--paper);box-shadow:none;border-radius:5px;width:20px;height:18px;
}
.wsel__win .win__body{padding:16px;position:relative}
.wsel__lead{font-size:12px;line-height:1.55;color:var(--paper);opacity:.72}
.wsel__list{display:grid;gap:8px;margin-top:14px}

.wsel__item{
  display:flex;align-items:center;gap:12px;width:100%;cursor:pointer;text-align:left;
  padding:11px 13px;border-radius:12px;color:var(--paper);
  border:1px solid rgba(241,233,255,.14);
  background:linear-gradient(180deg,rgba(255,255,255,.09),rgba(255,255,255,.03));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.16);
  font-family:var(--ui);font-size:14px;
  transition:transform .18s ease,border-color .18s ease,background .18s ease,box-shadow .18s ease;
}
.wsel__item:hover{
  transform:translateY(-1px);border-color:rgba(184,240,42,.55);
  background:linear-gradient(180deg,rgba(184,240,42,.16),rgba(255,255,255,.04));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.24),0 8px 20px rgba(4,0,20,.5);
}
.wsel__item:active{transform:translateY(0)}
.wsel__item[disabled]{opacity:.55;cursor:wait;transform:none}

.wsel__ico{
  flex:0 0 auto;width:32px;height:32px;border-radius:9px;overflow:hidden;
  display:grid;place-items:center;background:rgba(255,255,255,.06);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.1);
}
.wsel__ico svg,.wsel__ico img{width:32px;height:32px;display:block;border-radius:9px}
/* black marks need something to sit on, or they vanish into the dark card */
.wsel__ico:has(.on-plate){background:#F2EFEA;box-shadow:inset 0 0 0 1px rgba(0,0,0,.12)}
.wsel__ico .on-plate{padding:3px;box-sizing:border-box}
.wsel__name{flex:1 1 auto;font-weight:700;letter-spacing:-.01em}
.wsel__chain{
  flex:0 0 auto;padding:3px 7px;border-radius:99px;
  font-family:var(--mono);font-size:9px;letter-spacing:.12em;font-weight:700;
  background:rgba(184,240,42,.16);color:var(--acid);border:1px solid rgba(184,240,42,.3);
}
.wsel__go{flex:0 0 auto;opacity:.5;font-family:var(--mono)}
.wsel__none{margin-top:14px;font-size:12px;line-height:1.6;color:var(--paper);opacity:.75}

/* ── scroll viewer ─────────────────────────────────── */
.scrollv{
  position:fixed;inset:0;z-index:75;display:none;place-items:center;padding:var(--pad);
  background:rgba(22,8,64,.9);backdrop-filter:blur(10px);
}
.scrollv.on{display:grid}
.scrollv__win{width:min(560px,92vw);max-height:92vh;display:flex;flex-direction:column}
.scrollv__stage{
  position:relative;flex:1 1 auto;overflow:hidden;
  margin:8px;background:transparent;min-height:220px;
}
/* the alpha video plays over the viewer backdrop, no card behind it */
.scrollv__vid{
  width:100%;height:auto;display:block;
  filter:drop-shadow(0 14px 26px rgba(0,0,0,.55));
}
/* The still is placed on the exact rectangle the parchment occupies in the
   video's final frame, measured off its alpha channel, so the handoff lands
   without a jump. */
.scrollv__sheet{
  position:absolute;left:17.78%;top:3.73%;width:64.31%;height:91.69%;
  overflow:hidden;opacity:0;pointer-events:none;
}
.scrollv__sheet img{width:100%;height:auto;display:block}
/* once handed off, the still takes over and the panel scrolls */
.scrollv.done .scrollv__stage{overflow-y:auto}
.scrollv.done .scrollv__vid{display:none}
.scrollv.done .scrollv__sheet{
  position:static;width:100%;height:auto;opacity:1;pointer-events:auto;
}

/* small screens: drop the artwork, show the terminal panel plainly */
/* ── phone layout ───────────────────────────────────────
   The CRT is kept as artwork so the section still reads the same; only the
   form moves out from under the glass, since ~180px of screen cannot hold a
   usable 42-character input. */
.stage--flat{perspective:none;height:auto;cursor:auto}
.stage--flat .crt{position:relative;width:100%;filter:none;transform:none!important}
.stage--flat .crt__img{display:block;width:100%;height:auto}

/* The glass shows the wallpaper only: no window, no desktop icons.
   Position and transform are left alone on purpose — crt.js maps this onto
   the glass with the same homography it uses on desktop. Overriding either
   with a plain rectangle cannot line up with a perspective quad. */
.stage--flat .desktop{padding:0;display:block;background-size:cover}
.stage--flat .win--term{display:none}      /* the real one now lives below */
.stage--flat .folder,
.stage--flat .inbox{display:none}
.stage--flat .glass{display:block}
.stage--flat .sticker{display:block}       /* still anchored to the artwork */

/* the form, lifted out and given the full width */
.term-mobile{margin-top:clamp(18px,4vw,28px)}
.term-mobile .win--term{display:block;width:100%;max-width:none}
/* .screen shrinks type to suit the tiny CRT face; off the CRT it must reset */
.term-mobile .win__body{padding:clamp(18px,4vw,26px)}
.term-mobile .win__bar{font-size:11px;padding:5px 6px 5px 10px}
.term-mobile .fld__label{font-size:10px;letter-spacing:.24em}
.term-mobile .sunken--in{padding:12px 14px;margin-top:10px}
.term-mobile .sunken--in input{font-size:14px}
.term-mobile .fld__hint{font-size:10px;margin-top:10px}
.term-mobile .fld__row{gap:10px;margin-top:20px}
.term-mobile .btn{padding:14px 20px;font-size:11px;letter-spacing:.16em;flex:1 1 auto}

.scrolls-mobile{display:block;width:100%;margin-top:12px;padding:14px 20px}

/* ═══ TERMINAL ════════════════════════════════════════ */
.win--term{max-width:880px}
.fld__label{font-family:var(--mono);font-size:10px;letter-spacing:.24em}
.fld__caret{font-family:var(--mono);color:var(--violet-mid);font-weight:700}
.sunken--in input{
  flex:1 1 200px;min-width:0;background:none;border:0;outline:none;color:var(--ink);
  font-family:var(--mono);font-size:clamp(12px,1.5vw,16px);
}
.sunken--in input::placeholder{color:rgba(20,6,52,.28)}
.fld__hint{margin-top:10px;font-family:var(--mono);font-size:10px;letter-spacing:.12em;min-height:14px;opacity:.72}
.fld__hint.err{color:#A3001B;opacity:1;font-weight:700}
.fld__row{display:flex;flex-wrap:wrap;gap:10px;margin-top:20px}

.btn{
  font-family:var(--mono);font-size:11px;letter-spacing:.16em;cursor:pointer;font-weight:700;
  padding:13px 22px;color:var(--ink);background:var(--putty);border:1px solid var(--ink);
  box-shadow:inset 1.5px 1.5px 0 var(--putty-hi),inset -1.5px -1.5px 0 var(--putty-sh);
  transition:background .2s;
}
.btn:hover{background:#DED6F5}
.btn:active{box-shadow:inset -1.5px -1.5px 0 var(--putty-hi),inset 1.5px 1.5px 0 var(--putty-sh);transform:translate(1px,1px)}
.btn--go{background:var(--acid);box-shadow:inset 1.5px 1.5px 0 rgba(255,255,255,.75),inset -1.5px -1.5px 0 var(--acid-dp)}
.btn--go:hover{background:#C9FF44}
.btn[disabled]{opacity:.55;cursor:not-allowed}

/* ═══ GRID ════════════════════════════════════════════ */
.grid{list-style:none;padding:0;display:grid;gap:1px;background:rgba(241,233,255,.2);border:1px solid rgba(241,233,255,.2);grid-template-columns:repeat(auto-fit,minmax(255px,1fr))}
.grid li{background:var(--violet);padding:clamp(22px,3vw,34px)}
.grid__n{font-family:var(--mono);font-size:10px;letter-spacing:.24em;color:var(--acid)}
.grid h3{margin-top:14px;font-size:clamp(17px,2vw,23px);letter-spacing:-.015em;font-weight:600}
.grid p{margin-top:12px;font-size:14px;line-height:1.6;opacity:.78}
.grid p + p{margin-top:10px}   /* second paragraph in a card */

/* ═══ ACCORDION ═══════════════════════════════════════ */
.acc{max-width:880px;border-top:1px solid rgba(241,233,255,.25)}
.acc__item{border-bottom:1px solid rgba(241,233,255,.25)}
.acc__q{
  width:100%;display:flex;align-items:center;justify-content:space-between;gap:20px;
  background:none;border:0;cursor:pointer;text-align:left;
  padding:clamp(18px,2.8vw,28px) 0;font-size:clamp(15px,2vw,22px);letter-spacing:-.01em;transition:color .25s;
}
.acc__q:hover{color:var(--acid)}
.acc__q i{position:relative;width:14px;height:14px;flex:0 0 auto}
.acc__q i::before,.acc__q i::after{content:"";position:absolute;left:0;top:6px;width:14px;height:2px;background:currentColor;transition:transform .35s cubic-bezier(.2,.8,.2,1)}
.acc__q i::after{transform:rotate(90deg)}
.acc__item.open .acc__q i::after{transform:rotate(0)}
.acc__item.open .acc__q{color:var(--acid)}
.acc__a{overflow:hidden;height:0}
.acc__a p{padding-bottom:clamp(18px,2.8vw,28px);max-width:62ch;line-height:1.65;font-size:15px;opacity:.78}
/* multi-paragraph answers: only the last one carries the closing padding */
.acc__a p:not(:last-child){padding-bottom:0}
.acc__a p + p{margin-top:.85em}

/* ═══ RESULT DIALOG ═══════════════════════════════════ */
.result{
  position:fixed;inset:0;z-index:70;display:none;padding:var(--pad);
  background:rgba(22,8,64,.88);backdrop-filter:blur(10px);
  /* On a short phone the granted panel is taller than the viewport. Without a
     scroll the claim code and the button below it are simply unreachable.
     'safe' centring is the other half: plain centring overflows equally in
     both directions, which puts the top of the panel above the scroll origin
     where it can never be scrolled back to. */
  overflow-y:auto;overscroll-behavior:contain;
  place-items:center;place-items:safe center;
}
.result.on{display:grid}
.win--dlg{width:min(900px,94vw);text-align:center}
/* dark panel inside — the chrome gradient needs a dark ground to read */
.win--dlg .win__body{
  margin:8px;padding:clamp(26px,4vw,44px) clamp(18px,3vw,32px);
  color:var(--paper);
  position:relative;overflow:hidden;
  background:#140634;
  border:1px solid var(--putty-sh);
  box-shadow:inset 2px 2px 0 rgba(0,0,0,.5),inset -1px -1px 0 rgba(255,255,255,.15);
}
/* The liquid neon lives on its own layer so it can be moved with transform,
   which the compositor handles on the GPU. Animating background-position
   instead would repaint the whole panel every frame. The layer is inset well
   past the edges so the drift and rotation never expose a corner. */
.win--dlg .win__body::before{
  content:"";position:absolute;inset:-28%;z-index:0;pointer-events:none;
  background:
    linear-gradient(rgba(20,6,52,.58),rgba(20,6,52,.74)),
    image-set(url("../img/liquid.webp") type("image/webp"),
              url("../img/liquid.jpg") type("image/jpeg"));
  background-size:cover;background-position:center;
  will-change:transform;
  animation:liquid 42s ease-in-out infinite alternate;
}
/* content has to sit above that layer */
.win--dlg .win__body > *{position:relative;z-index:1}

@keyframes liquid{
  0%   {transform:translate3d(-3%,-2%,0) scale(1.16) rotate(0deg)}
  35%  {transform:translate3d(2%,-3%,0)  scale(1.24) rotate(1.6deg)}
  70%  {transform:translate3d(3%,2%,0)   scale(1.20) rotate(-1.2deg)}
  100% {transform:translate3d(-2%,3%,0)  scale(1.26) rotate(2deg)}
}
@media (prefers-reduced-motion:reduce){
  .win--dlg .win__body::before{animation:none}
}
/* Granted splits into pack/pass + copy; denied stays a single centred column. */
.reveal{display:none;position:relative;min-height:330px}
/* Column, not a centred grid with the hint absolutely pinned to the bottom:
   that left a 2px gap the hint could ride up through the moment it wrapped
   to a second line, printing the text across the pack art. */
.result--yes .reveal{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
}
.result--yes .win__body{
  display:grid;grid-template-columns:minmax(0,300px) 1fr;
  gap:clamp(20px,3.4vw,40px);align-items:center;text-align:left;
}
.result--yes .result__msg{font-size:clamp(19px,3.3vw,42px)}

/* ── holographic foil pack ─────────────────────────────
   Built from layers rather than one flat gradient: saturated iridescence,
   hard crinkle creases, pillow shading, ridged crimp bands, corner gussets
   and sealed side seams — the anatomy of a real mylar sachet. */
.pack{
  position:relative;width:min(72%,196px);aspect-ratio:760/1172;
  cursor:grab;touch-action:pan-y;outline:none;
  filter:drop-shadow(9px 13px 16px rgba(8,0,30,.6));
}
.pack:active{cursor:grabbing}
.pack:focus-visible{box-shadow:0 0 0 3px var(--acid)}

/* Both halves are the full artwork at identical size; the clip paths applied
   in pack.js split them along one shared jagged tear line, so the lid can
   pull away and still line up perfectly before it does. */
.pack__body,.pack__lid,.pack__inner{position:absolute;inset:0}
.pack__body,.pack__lid{
  background:url("../img/pack.png") center/100% 100% no-repeat;
  background-image:image-set(url("../img/pack.webp") type("image/webp"),
                             url("../img/pack.png") type("image/png"));
  background-size:100% 100%;background-repeat:no-repeat;
}
.pack__body{z-index:2}
.pack__lid{z-index:3;will-change:transform}
/* the sealed interior, seen through the wedge as the strip peels back */
.pack__inner{
  z-index:1;
  background:linear-gradient(180deg,#05011A 0%,#10063A 55%,#1E0A52 100%);
  /* also masked to the artwork so this solid fill can never show past the
     pack's edges, or contribute a square to the parent's drop-shadow */
  -webkit-mask:url("../img/pack.webp") center/100% 100% no-repeat;
          mask:url("../img/pack.webp") center/100% 100% no-repeat;
}
.pack__glow{
  position:absolute;left:6%;right:6%;top:8%;height:16%;
  background:radial-gradient(65% 100% at 50% 100%,rgba(184,240,42,.95),transparent 72%);
  filter:blur(7px);opacity:0;
}
/* A light sweep travelling over the foil so it reads as holographic.
   Masked to the pack artwork: unmasked it is a full-bleed rectangle, and the
   parent's drop-shadow traces the alpha of its whole subtree — so the shadow
   came out square instead of following the pack. */
.pack__sheen{
  position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(104deg,
    transparent 32%,rgba(255,255,255,.5) 45%,rgba(255,190,255,.35) 50%,
    rgba(180,255,255,.45) 55%,transparent 68%);
  background-size:260% 100%;
  -webkit-mask:url("../img/pack.webp") center/100% 100% no-repeat;
          mask:url("../img/pack.webp") center/100% 100% no-repeat;
  mix-blend-mode:overlay;
  animation:sheen 5.5s linear infinite;
}
@keyframes sheen{from{background-position:160% 0}to{background-position:-60% 0}}
.pack__hint{
  position:static;text-align:center;white-space:nowrap;flex:none;
  font-family:var(--mono);font-size:9px;letter-spacing:.22em;color:var(--acid);
}

/* the card itself — hidden until the pack is torn */
.result__pass{
  position:absolute;inset:0;margin:0;display:grid;place-items:center;
  visibility:hidden;z-index:3;
}
.result__pass img{
  width:100%;border:2px solid var(--ink);
  box-shadow:0 0 0 2px var(--acid),10px 10px 0 rgba(12,3,36,.55),0 0 50px rgba(184,240,42,.35);
}
@media (max-width:780px){
  .result--yes .win__body{grid-template-columns:1fr;text-align:center}
  /* width:100% is required, not cosmetic. Without a definite width .reveal
     shrink-to-fits around .pack, whose width is a % of .reveal — a circular
     reference that resolves to 0 and makes the foil pack vanish. */
  .reveal{width:100%;max-width:290px;margin:0 auto}
}
/* ── Ordinals claim block (legacy holders only) ────── */
/* Ordinals holders get the full granted layout (pack + message); this block
   is simply added underneath it. */
.claim{display:none;margin-top:18px;padding:14px 16px;
  border:1px solid rgba(184,240,42,.45);background:rgba(184,240,42,.07)}
.result--legacy .claim{display:block}
.claim__label{display:block;font-family:var(--mono);font-size:9px;letter-spacing:.26em;color:var(--acid)}
.claim__code{display:block;margin-top:6px;font-family:var(--mono);
  font-size:clamp(17px,2.4vw,24px);letter-spacing:.14em;color:#fff;font-weight:700}
.claim__how{margin-top:10px;font-size:12px;line-height:1.55;opacity:.85}
.claim__how a{color:var(--acid);border-bottom:1px solid rgba(184,240,42,.5)}

.result__glyph{font-size:clamp(40px,8vw,76px);line-height:1;margin-bottom:18px}
.result__msg{font-size:clamp(21px,4.4vw,56px)}
/* set here, not inline, so GSAP can clearProps the animated spans wholesale */
.result__msg span{display:inline-block}
.result__addr{margin-top:20px;font-family:var(--mono);font-size:10px;letter-spacing:.12em;word-break:break-all;opacity:.62}
#againBtn{margin-top:26px}
.result--yes .result__glyph{color:var(--acid);text-shadow:0 0 30px rgba(184,240,42,.85)}
.result--no  .result__glyph{color:var(--red);text-shadow:0 0 26px rgba(255,59,87,.65)}
.result--no .result__msg{
  background:linear-gradient(177deg,#fff 0%,#ffd9df 14%,#ff8296 30%,#7E0014 50%,#ff6b83 62%,#fff 80%,#ffb3bf 100%);
  -webkit-background-clip:text;background-clip:text;
  background-size:100% 200%;
  filter:drop-shadow(0 2px 0 rgba(12,3,36,.6)) drop-shadow(0 0 26px rgba(255,59,87,.4));
}

/* ═══ FOOTER ══════════════════════════════════════════ */
.foot{padding:clamp(50px,8vh,90px) var(--pad) 30px;overflow:hidden}
/* logo art, not text: sized to sit comfortably rather than span the footer */
.foot__shine{position:relative;display:block;width:clamp(190px,26vw,360px);margin:0 auto}
.foot__mark{
  display:block;width:100%;height:auto;
  filter:drop-shadow(0 10px 26px rgba(12,3,36,.6));
}
/* glare sweep, masked to the artwork's alpha so it follows the logo's shape
   instead of sweeping a rectangle across the footer */
.foot__shine::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(104deg,
    transparent 40%, rgba(255,255,255,.55) 47%, rgba(255,255,255,.9) 50%,
    rgba(255,255,255,.55) 53%, transparent 60%);
  background-size:260% 100%;
  -webkit-mask:url("../img/krew.webp") center/100% 100% no-repeat;
          mask:url("../img/krew.webp") center/100% 100% no-repeat;
  mix-blend-mode:screen;
  animation:sheen 5s linear infinite;
}
.foot__row{display:flex;justify-content:space-between;flex-wrap:wrap;gap:14px;margin-top:30px;font-family:var(--mono);font-size:10px;letter-spacing:.18em;opacity:.72}
.foot__row nav{display:flex;gap:20px}
.foot__row nav a{display:inline-flex;align-items:center;gap:6px}
/* real brand marks, so they keep their own colour rather than currentColor */
.ico{width:13px;height:13px;flex:0 0 auto;opacity:.9;transition:opacity .25s}
.foot__row nav a:hover .ico{opacity:1}
.foot__row a:hover{color:var(--acid)}

/* Four destinations in the bar is more than the section numbers can sit
   beside. Below ~900px the numbers pushed the CONNECT / CHECK WALLET button
   past the right edge of a fixed bar, where it was clipped and unclickable.
   The numbers go first: they are anchors to sections further down this same
   page, which scrolling reaches anyway, whereas the tabs are other pages. */
@media (max-width:900px){
  .nav__links a:not(.nav__store):not(.nav__tab):not(.chip){display:none}
}

@media (max-width:680px){
  .nav__links a{display:none}
  /* the section numbers go, but the tabs are destinations — keep them */
  .nav__links a.nav__store,
  .nav__links a.nav__tab{display:inline-block;padding:6px 9px;font-size:10px}
  .fld__row .btn{flex:1 1 auto}
  .hero__foot{align-items:flex-start;flex-direction:column}
  .hero__scroll{text-align:left}
}
@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition-duration:.01ms!important}
}

/* ═══ LOCK SCREEN (mint.html) ══════════════════════════
   The mint page ships as a locked shell. This is the only thing a visitor
   without the key ever sees. */
.lock{
  position:fixed;inset:0;z-index:80;display:grid;padding:var(--pad);
  overflow-y:auto;overscroll-behavior:contain;
  place-items:center;place-items:safe center;
  background:rgba(22,8,64,.9);backdrop-filter:blur(10px);
}
.lock__win{width:min(460px,94vw);text-align:center}
.lock__glyph{font-size:34px;line-height:1;color:var(--acid);
  text-shadow:0 0 26px rgba(184,240,42,.7);margin:0 0 10px}
.lock__title{font-size:clamp(20px,4vw,30px);margin:0 0 6px}
.lock__lead{font-size:12px;line-height:1.6;color:var(--paper);opacity:.72;margin:0 0 18px}
.lock .fld__label{text-align:left;display:block}
.lock .fld__row{margin-top:14px;justify-content:center}

/* a wrong key shakes the panel rather than only changing the text */
@keyframes lockShake{
  0%,100%{transform:translateX(0)}
  15%{transform:translateX(-9px)} 30%{transform:translateX(8px)}
  45%{transform:translateX(-6px)} 60%{transform:translateX(5px)}
  75%{transform:translateX(-3px)}
}
.lock.is-shake .lock__win{animation:lockShake .45s ease}
@media (prefers-reduced-motion:reduce){ .lock.is-shake .lock__win{animation:none} }

/* ═══ MINT ═════════════════════════════════════════════ */
.mint__head{text-align:center}
.mint__head p{max-width:60ch;margin-inline:auto;opacity:.8}
.mint{max-width:640px;margin-inline:auto}

.mint__supply{margin-bottom:18px}
.mint__bar{
  height:10px;border:1px solid var(--putty-sh);background:rgba(8,2,28,.6);
  box-shadow:inset 2px 2px 0 rgba(0,0,0,.5);overflow:hidden;
}
.mint__fill{
  display:block;height:100%;width:0;
  background:linear-gradient(90deg,var(--violet-lt),var(--acid));
  transition:width .6s cubic-bezier(.2,.9,.25,1);
}
.mint__count{
  font-family:var(--mono);font-size:10px;letter-spacing:.2em;
  color:var(--acid-hi);margin:8px 0 0;text-align:center;
}

.win--mint{width:100%}
.mint__row{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:9px 0;border-bottom:1px dashed rgba(207,196,238,.25);
}
.mint__label{font-family:var(--mono);font-size:9.5px;letter-spacing:.22em;opacity:.66}
.mint__val{font-family:var(--mono);font-size:11px;letter-spacing:.1em;color:var(--paper)}
.mint__val--ok{color:var(--acid)}
.mint__val--no{color:#FF6B83}
.mint__val--price{font-size:15px;color:var(--acid)}
.mint__row--total{border-bottom:none}

.mint__qty{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  flex-wrap:wrap;padding:12px 0;border-bottom:1px dashed rgba(207,196,238,.25);
}
.mint__qty[hidden],.mint__row[hidden]{display:none}
.qty{display:flex;align-items:center;gap:2px}
.qty__btn{
  width:32px;height:30px;cursor:pointer;font-family:var(--mono);font-size:15px;
  color:var(--ink);background:var(--putty);border:1px solid var(--putty-sh);
  box-shadow:inset 1.5px 1.5px 0 #fff,inset -1.5px -1.5px 0 rgba(107,92,168,.7);
}
.qty__btn:active{box-shadow:inset -1.5px -1.5px 0 #fff,inset 1.5px 1.5px 0 rgba(107,92,168,.7)}
.qty__btn:disabled{opacity:.4;cursor:not-allowed}
.qty__n{
  min-width:44px;text-align:center;font-family:var(--mono);font-size:15px;
  color:var(--acid);
}
.mint__max{font-family:var(--mono);font-size:9px;letter-spacing:.18em;opacity:.55}

.mint__note{max-width:640px;margin-inline:auto}

/* ═══ MINT REVEAL ══════════════════════════════════════
   The set sits in the page above the supply bar. While the wallet and the
   chain work it plays its own Y2K LOADING loop; once the mint confirms the
   reveal plays on the tube. Not an overlay, so the console stays readable. */
.mintfx{display:none;margin:0 0 20px}
.mintfx.on{display:block}
.mintfx[hidden]{display:none}

.tvset{position:relative;width:min(520px,100%);margin-inline:auto}
.tvset__set{display:block;width:100%;height:auto}

/* The glass, measured off the artwork at its native 1000x1000. Everything
   inside rides with it, so the reveal reads as being on the set. */
/* The glass, read off the artwork by sweeping for where the blue tube meets
   the grey cabinet: x 105 to 895, y 110 to 635 of the 1000px frame. */
.tvset__screen{
  position:absolute;left:10.5%;top:11%;width:79%;height:52.5%;
  overflow:hidden;
  /* the tube is not flat, so the corners fall away */
  /* The tube is barrel shaped, not a rounded rectangle: it measures 48%
     wide at the very top against 76% across the middle. A generous radius
     tracks that, so the corners do not sit out over the bezel. */
  border-radius:13% / 19%;
}
/* Only once the reveal is running. Filling it earlier would cover the set's
   own LOADING screen, which is the waiting state. This also stops the loop
   showing through the rounded corners. */
.mintfx.is-playing .tvset__screen{background:#000}

.mintfx__vid{
  width:100%;height:100%;display:block;
  /* Fill the tube. The reveal is 16:9 and the glass is nearer 7:5, so this
     trims about a tenth off each side. Checked against the key beats: the
     ticket wordmark and the portal both survive the crop, and a filled screen
     reads far better than letterbox bars on a set this size. */
  object-fit:cover;background:#000;
  opacity:0;transition:opacity .3s ease;
}
.mintfx.is-playing .mintfx__vid{opacity:1}

/* ── status under the set ──────────────────────────── */
.mintfx__wait{text-align:center;margin-top:12px}
.mintfx__wait[hidden]{display:none}
.mintfx__note{
  font-family:var(--mono);font-size:11px;letter-spacing:.26em;color:var(--acid);
  margin:0 0 5px;
}
.mintfx__sub{
  font-family:var(--mono);font-size:9px;letter-spacing:.22em;
  color:var(--paper);opacity:.55;margin:0;text-transform:uppercase;
}
.mintfx[data-step="fail"] .mintfx__note{color:#FF6B83}

/* ── skip ──────────────────────────────────────────── */
.mintfx__skip{
  position:absolute;right:8px;bottom:8px;z-index:2;cursor:pointer;
  font-family:var(--mono);font-size:8.5px;letter-spacing:.18em;
  padding:6px 10px;color:var(--paper);
  background:rgba(8,2,28,.65);border:1px solid rgba(241,233,255,.32);
  backdrop-filter:blur(6px);
}
.mintfx__skip:hover{color:var(--acid);border-color:var(--acid)}
.mintfx__skip[hidden]{display:none}


/* a disabled action must not look pressable */
.btn:disabled{opacity:.4;cursor:not-allowed;filter:saturate(.35)}
.btn:disabled:active{box-shadow:inset 1.5px 1.5px 0 #fff,inset -1.5px -1.5px 0 rgba(107,92,168,.7)}

/* dark panel for the mint console, matching the result dialog rather than the
   light Win98 plastic used by the terminal form */
.win--mint .win__body{
  margin:8px;padding:clamp(16px,3vw,24px);
  color:var(--paper);
  background:
    linear-gradient(rgba(20,6,52,.74),rgba(20,6,52,.88)),
    image-set(url("../img/liquid.webp") type("image/webp"),
              url("../img/liquid.jpg") type("image/jpeg"));
  background-size:cover;background-position:center;
  border:1px solid var(--putty-sh);
  box-shadow:inset 2px 2px 0 rgba(0,0,0,.5),inset -1px -1px 0 rgba(255,255,255,.15);
}
.win--mint .fld__hint{color:var(--paper);opacity:.7}
