/* ================================================================
   PALETTE
   ================================================================ */
:root{
  --ground: #08080a;
  --smoke:  #121215;
  --bone:   #e4e2dd;
  --dim:    #70706f;
  --hot:    #ffffff;
}

*{ margin:0; padding:0; box-sizing:border-box; }

html{ background:var(--ground); }

body{
  background:
    radial-gradient(130vw 90vh at 50% -20%, rgba(18,18,21,.5) 0%, transparent 60%),
    url("../../images/texture.png") repeat,
    var(--ground);
  background-size: auto, 500px, auto;
  color:var(--bone);
  font-family:'IBM Plex Mono', monospace;
  overflow-x:hidden;
}

::selection{ background:var(--hot); color:var(--ground); }

/* ---- photocopy grain ---- */
.grain{
  position:fixed; inset:-100px;
  pointer-events:none;
  z-index:50;
  opacity:.09;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 1.1s steps(4) infinite;
}
@keyframes grain{
  0%{ transform:translate(0,0); }
  25%{ transform:translate(-40px,30px); }
  50%{ transform:translate(30px,-50px); }
  75%{ transform:translate(-30px,-20px); }
  100%{ transform:translate(0,0); }
}

/* ---- corner marks ---- */
.mark{
  position:fixed; z-index:40;
  font-size:11px; letter-spacing:.18em;
  color:var(--dim); text-transform:lowercase;
}
.mark.tl{ top:18px; left:22px; }
.mark.tr{ top:18px; right:22px; text-align:right; }

/* ---- opening screen ---- */
.intro{
  height:100vh;
  display:flex; flex-direction:column;
  align-items:center; justify-content:center;
}

/* ---- the title ----
   A stacked tower of three "systems" storeys on ALL screens.
   Each storey carries its own glitch ghosts on an offset clock.
   Desktop size is set here; mobile size is set in the media
   query at the bottom of this file. */
.intro h1{
  font-family:'VT323', monospace;
  font-size:16vw;
  letter-spacing:.02em;
  line-height:.82;
  font-weight:400;
  color:var(--bone);
  text-transform:uppercase;
  white-space:nowrap;
  text-align:center;
  position:relative;
  opacity:0;
  animation:
    emerge 2s ease .3s forwards,
    flicker 7s steps(1) 2.6s infinite;
}
.intro h1 span{
  position:relative;
  display:block;
}
.intro h1 span::before,
.intro h1 span::after{
  content:attr(data-text);
  position:absolute; inset:0;
  color:var(--bone);
  opacity:0;
  pointer-events:none;
}
.intro h1 span::before{ animation:ghostL 7s steps(1) 2.6s infinite; }
.intro h1 span::after{  animation:ghostR 7s steps(1) 2.6s infinite; }
/* each storey glitches on its own offset clock */
.intro h1 span:nth-child(2)::before,
.intro h1 span:nth-child(2)::after{ animation-delay:4.1s; }
.intro h1 span:nth-child(3)::before,
.intro h1 span:nth-child(3)::after{ animation-delay:5.7s; }

@keyframes emerge{
  from{ opacity:0; filter:blur(12px); }
  to{ opacity:1; filter:blur(0); }
}
@keyframes flicker{
  0%, 100% { opacity:1; }
  11%   { opacity:.55; }
  11.6% { opacity:1; }
  12.1% { opacity:.8; }
  12.5% { opacity:1; }
  37%   { opacity:.7; }
  37.4% { opacity:1; }
  61%   { opacity:.45; }
  61.5% { opacity:.9; }
  62.3% { opacity:1; }
  83%   { opacity:.85; }
  83.5% { opacity:1; }
}
@keyframes ghostL{
  0%, 100% { opacity:0; transform:none; }
  11%   { opacity:.35; transform:translateX(-4px); }
  12.5% { opacity:0;   transform:none; }
  61%   { opacity:.4;  transform:translateX(-6px) skewX(-2deg); }
  62.3% { opacity:0;   transform:none; }
}
@keyframes ghostR{
  0%, 100% { opacity:0; transform:none; }
  11.6% { opacity:.3;  transform:translateX(4px); }
  12.5% { opacity:0;   transform:none; }
  37%   { opacity:.35; transform:translateX(5px); }
  37.4% { opacity:0;   transform:none; }
  61.5% { opacity:.3;  transform:translateX(6px); }
  62.3% { opacity:0;   transform:none; }
}

/* ---- the collage field ---- */
.field{ position:relative; width:100%; }

.piece{
  position:absolute;
  cursor:pointer;
  will-change:transform;
  opacity:1;
  transition:opacity 3.4s ease;
}
.piece.moving{
  opacity:0 !important;
  pointer-events:none;
}

.piece img{
  display:block; width:100%; height:auto;
  filter:brightness(.82);
  box-shadow:0 26px 70px rgba(0,0,0,.7);
  animation:hum var(--humDur, 6s) ease-in-out var(--humDelay, 0s) infinite alternate;
}
@keyframes hum{
  from{ opacity:.45; }
  to{   opacity:1; }
}

.piece:hover img, .piece:focus-visible img{
  animation:humFast 1.1s ease-in-out infinite alternate;
  filter:brightness(1);
  box-shadow:0 0 0 1px var(--hot), 0 30px 80px rgba(0,0,0,.8);
}
/* a quick shallow flutter — the piece is awake, not frozen */
@keyframes humFast{
  from{ opacity:.8; }
  to{   opacity:1; }
}
/* linger (added by script after ~half a second of hovering):
   the flutter quickens further, like current rising in the line */
.piece.linger img{ animation-duration:.55s; }
.piece:hover{ z-index:30 !important; }
.piece:focus-visible{ outline:1px solid var(--hot); outline-offset:6px; z-index:30 !important; }

.piece figcaption{
  position:absolute; left:2px; top:calc(100% + 10px);
  font-size:10px; letter-spacing:.22em;
  color:var(--dim); text-transform:lowercase;
  opacity:0; transition:opacity .45s ease;
  white-space:nowrap;
}
.piece:hover figcaption, .piece:focus-visible figcaption{ opacity:1; }
.piece figcaption b{ color:var(--hot); font-weight:400; margin-right:.8em; }


/* ---- edge static: a fizz of noise around each piece's edges,
   strengthening as the cursor approaches (set as --staticAmt by
   the script; stays 0 on touch screens and for reduced motion) ---- */
.piece::after{
  content:'';
  position:absolute; inset:-3px;
  pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode:screen;
  opacity:var(--staticAmt, 0);
  -webkit-mask-image:radial-gradient(ellipse 62% 62% at 50% 50%, transparent 38%, black 82%);
  mask-image:radial-gradient(ellipse 62% 62% at 50% 50%, transparent 38%, black 82%);
  animation:staticshift .7s steps(3) infinite;
  transition:opacity .2s linear;
}
@keyframes staticshift{
  0%{ background-position:0 0; }
  33%{ background-position:-70px 45px; }
  66%{ background-position:55px -60px; }
  100%{ background-position:0 0; }
}

/* ---- end mark ---- */
.fin{
  height:60vh;
  display:flex; align-items:center; justify-content:center;
  flex-direction:column; gap:18px;
  font-size:11px; letter-spacing:.34em;
  color:var(--dim); text-transform:lowercase;
}

/* ---- lightbox ---- */
.box{
  position:fixed; inset:0; z-index:60;
  background:rgba(5,5,6,.97);
  display:none;
  align-items:center; justify-content:center;
  flex-direction:column;
}
.box.open{ display:flex; }
.box img{
  max-width:92vw; max-height:82vh;
  box-shadow:0 40px 120px rgba(0,0,0,.85);
}
.box .cap{
  margin-top:22px; font-size:11px; letter-spacing:.25em;
  color:var(--dim); text-transform:lowercase;
}
.box .cap b{ color:var(--hot); font-weight:400; margin-right:1em; }
.box .close{
  position:absolute; top:16px; right:22px;
  background:none; border:none; color:var(--dim);
  font-family:'IBM Plex Mono',monospace; font-size:12px;
  letter-spacing:.2em; cursor:pointer; padding:8px;
}
.box .close:hover{ color:var(--hot); }
.nav{
  position:absolute; top:0; bottom:0; width:34%;
  background:none; border:none; cursor:pointer;
}
.nav.prev{ left:0; } .nav.next{ right:0; }


/* ---- sound toggle (bottom-left corner) ---- */
button.mark{
  font-family:'IBM Plex Mono', monospace;
  font-size:11px; letter-spacing:.18em;
  color:var(--dim); text-transform:lowercase;
  background:none; border:none; padding:0;
  cursor:pointer;
}
button.mark:hover{ color:var(--hot); }
.mark.bl{ bottom:16px; left:22px; top:auto; }
.mark.bl.playing::before{
  content:'\25CF  ';
  color:var(--hot);
  animation:soundpulse 4s ease-in-out infinite;
}
@keyframes soundpulse{
  0%, 100% { opacity:.25; }
  50%      { opacity:.8; }
}

/* ---- navigation links ---- */
.mark a, .fin a{
  color:var(--dim); text-decoration:none;
  border-bottom:1px solid transparent;
  transition:color .3s ease, border-color .3s ease;
}
.mark a:hover, .fin a:hover{ color:var(--hot); border-bottom-color:var(--hot); }

/* ---- grid page: an infinite draggable sheet ---- */
body.canvasbody{
  position:fixed; inset:0; width:100%;
  overflow:hidden;
  overscroll-behavior:none;
}
.gridcanvas{
  position:fixed; inset:0;
  overflow:hidden;
  touch-action:none;          /* we handle all dragging ourselves */
  cursor:grab;
}
.gridcanvas.dragging{ cursor:grabbing; }
.supergrid{
  position:absolute; left:0; top:0;
  will-change:transform;
}
.gridblock{ position:absolute; }

/* the one-time invitation */
.hint{
  position:fixed; left:50%;
  bottom:calc(18px + env(safe-area-inset-bottom));
  transform:translateX(-50%);
  z-index:40;
  font-size:11px; letter-spacing:.3em;
  color:var(--dim); text-transform:lowercase;
  transition:opacity 1.2s ease;
  pointer-events:none;
}
.hint.gone{ opacity:0; }
.grid{ display:grid; grid-template-columns:repeat(4, 1fr); gap:26px; }
@media (max-width:1100px){ .grid{ grid-template-columns:repeat(3, 1fr); } }

.tile{ cursor:pointer; }
.tile img{
  display:block; width:100%;
  aspect-ratio:1/1; object-fit:cover;   /* uniform squares; change to 3/4 for portrait tiles */
  filter:brightness(.82);
  transition:filter .3s ease, box-shadow .3s ease;
}
.tile:hover img, .tile:focus-visible img{
  filter:brightness(1);
  box-shadow:0 0 0 1px var(--hot);
}
.tile figcaption{
  margin-top:8px; font-size:10px; letter-spacing:.22em;
  color:var(--dim); text-transform:lowercase;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.tile img{
  -webkit-user-drag:none;
  user-select:none;
  -webkit-user-select:none;
}
.tile figcaption b{ color:var(--hot); font-weight:400; margin-right:.8em; }

@media (prefers-reduced-motion: reduce){
  .grain{ animation:none; }
  .intro h1{ animation:emerge 0s forwards; opacity:1; }
  .intro h1 span::before, .intro h1 span::after{ animation:none; opacity:0; }
  .piece{ transform:none !important; transition:none; }
  .piece img{ animation:none; opacity:1; }
  .piece::after{ animation:none; opacity:0 !important; }
}

/* ================================================================
   MOBILE — last in the file so it always wins on small screens
   ================================================================ */
@media (max-width:640px){
  /* sound toggle on phones: bottom-right, lifted clear of browser
     toolbars (safe-area) so it can't collide with anything */
  .mark.bl{
    left:auto; right:22px; top:auto;
    bottom:calc(14px + env(safe-area-inset-bottom));
  }

  /* the title tower, sized for phones */
  .intro h1{
    font-size:23vw;
    line-height:.82;
    letter-spacing:.03em;
  }

  /* captions can't be hovered on a phone — show them faintly, always */
  .piece figcaption{ opacity:.55; font-size:9px; }

  /* lighter shadows: cheaper to render, and phone screens crush
     dark detail anyway */
  .piece img{ box-shadow:0 14px 36px rgba(0,0,0,.6); }

  /* grid page: two columns on phones */
  .grid{ grid-template-columns:repeat(2, 1fr); gap:14px; }
}
