/* Media: tiles, the home previews, the full-page wall, the game filter and the viewer.
   Shared by the home page, /renders and /gallery. Tiles always reserve their final shape (no layout shift) and fade
   in over a blurred 32 px placeholder, so nothing ever snaps from low to high resolution. */

/* ── tile ── */
.m{position:relative;display:block;overflow:hidden;background:#0b0809;aspect-ratio:var(--ar, 16/9);cursor:pointer;isolation:isolate;
  -webkit-tap-highlight-color:transparent;outline-offset:-2px}
.m .lq{position:absolute;inset:-6%;background:center / cover no-repeat;filter:blur(16px) saturate(1.1);transform:scale(1.04)}
.m picture,.m img,.m video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.js .m img{opacity:0;transition:opacity .6s ease, transform 1.2s cubic-bezier(.2,.7,.2,1)}
.js .m img.ld{opacity:1}
.m video{opacity:0;transition:opacity .6s ease}
.m video.on{opacity:1}
.m::after{content:"";position:absolute;inset:0;pointer-events:none;background:linear-gradient(0deg, rgba(0,0,0,.28), transparent 38%);opacity:0;transition:opacity .4s}
@media (hover:hover){ .m:hover img{transform:scale(1.02)} .m:hover::after{opacity:1} }
.m:focus-visible{outline:2px solid var(--signal)}

/* ── home previews: a bento that fades out into the call to action ── */
.preview{position:relative;margin-top:28px}
.preview .grid{-webkit-mask-image:linear-gradient(180deg, #000 calc(100% - var(--fade, 200px)), rgba(0,0,0,.18) calc(100% - 46px), transparent);
  mask-image:linear-gradient(180deg, #000 calc(100% - var(--fade, 200px)), rgba(0,0,0,.18) calc(100% - 46px), transparent)}
.preview .grid .m{aspect-ratio:auto;height:100%}
.rb{display:grid;grid-template-columns:repeat(4, minmax(0, 1fr));grid-auto-rows:clamp(110px, 13vw, 180px);gap:6px}
.rb .m:nth-child(1){grid-column:span 2;grid-row:span 3}
.rb .m:nth-child(2){grid-column:span 2;grid-row:span 2}
.rb .m:nth-child(3){grid-column:span 2;grid-row:span 1}
.rb .m:nth-child(4),.rb .m:nth-child(5){grid-column:span 2;grid-row:span 2}
.gb{display:grid;grid-template-columns:repeat(12, minmax(0, 1fr));grid-auto-rows:clamp(52px, 6.4vw, 92px);gap:6px}
.gb .m:nth-child(15n+1){grid-column:span 8;grid-row:span 5}
.gb .m:nth-child(15n+2){grid-column:span 4;grid-row:span 3}
.gb .m:nth-child(15n+3){grid-column:span 4;grid-row:span 2}
.gb .m:nth-child(15n+4),.gb .m:nth-child(15n+5),.gb .m:nth-child(15n+6),
.gb .m:nth-child(15n+10),.gb .m:nth-child(15n+11),.gb .m:nth-child(15n+12){grid-column:span 4;grid-row:span 3}
.gb .m:nth-child(15n+7){grid-column:span 6;grid-row:span 4}
.gb .m:nth-child(15n+8),.gb .m:nth-child(15n+9){grid-column:span 3;grid-row:span 4}
.gb .m:nth-child(15n+13){grid-column:span 5;grid-row:span 4}
.gb .m:nth-child(15n+14){grid-column:span 4;grid-row:span 4}
.gb .m:nth-child(15n+15){grid-column:span 3;grid-row:span 4}
@media (max-width:760px){
  .rb{grid-template-columns:1fr 1fr;grid-auto-rows:26vw;grid-auto-flow:dense}
  .rb .m:nth-child(n){grid-column:span 1;grid-row:span 2} .rb .m:nth-child(1){grid-column:span 2;grid-row:span 4}
  .rb .m:nth-child(3){grid-column:span 2;grid-row:span 2} .rb .m:nth-child(5){grid-column:span 2;grid-row:span 3}
  .gb{grid-template-columns:repeat(2, minmax(0, 1fr));grid-auto-rows:24vw;grid-auto-flow:dense}
  .gb .m:nth-child(n){grid-column:span 1;grid-row:span 2} .gb .m:nth-child(5n+1){grid-column:span 2;grid-row:span 3} .gb .m.tall{grid-row:span 4}
  .preview{--fade:150px}
}
.more{position:relative;z-index:2;display:flex;justify-content:center;margin-top:-30px}
.cta-btn{display:inline-flex;align-items:center;gap:14px;min-height:52px;padding:0 22px 0 26px;border-radius:999px;border:1px solid rgba(255,255,255,.14);
  background:rgba(12,9,10,.72);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);color:var(--bone);font-size:var(--t-s);font-weight:500;letter-spacing:.005em;
  transition:border-color .3s, background-color .3s}
.cta-btn .n{font-family:var(--f-mono);font-size:var(--t-xs);color:var(--ash);letter-spacing:.04em}
.cta-btn svg{width:18px;height:18px;transition:transform .45s cubic-bezier(.2,.7,.2,1)}
.cta-btn:hover{border-color:var(--signal);background:rgba(28,10,13,.8)}
.cta-btn:hover svg{transform:translateX(4px)}

/* ── full pages: the same organic bento as the home previews, edge to edge, repeating every 15 tiles
   (positions come from media.js; without it every tile takes a plain 4 x 3 slot) ── */
.wall{--g:4px;display:grid;grid-template-columns:repeat(12, minmax(0, 1fr));grid-auto-rows:clamp(52px, 6.6vw, 112px);grid-auto-flow:dense;gap:var(--g);padding:var(--g)}
.wall .m{aspect-ratio:auto;height:100%;grid-column:span 4;grid-row:span 3}
.wall .m[hidden]{display:none}
.wall .m[data-p="1"]{grid-column:span 8;grid-row:span 5}
.wall .m[data-p="2"]{grid-column:span 4;grid-row:span 3}
.wall .m[data-p="3"]{grid-column:span 4;grid-row:span 2}
.wall .m[data-p="7"]{grid-column:span 6;grid-row:span 4}
.wall .m[data-p="8"],.wall .m[data-p="9"]{grid-column:span 3;grid-row:span 4}
.wall .m[data-p="13"]{grid-column:span 5;grid-row:span 4}
.wall .m[data-p="14"]{grid-column:span 4;grid-row:span 4}
.wall .m[data-p="15"]{grid-column:span 3;grid-row:span 4}
@media (max-width:760px){
  .wall{--g:3px;padding:0;grid-template-columns:repeat(2, minmax(0, 1fr));grid-auto-rows:24vw}
  .wall .m,.wall .m[data-p]{grid-column:span 1;grid-row:span 2}
  .wall .m[data-q="1"]{grid-column:span 2;grid-row:span 3}
  .wall .m.tall{grid-row:span 4}
}

/* game filter: quiet text tabs, one at a time; a thin red line slides under the active one */
.tabs{position:relative;display:flex;gap:clamp(18px, 3vw, 32px);margin-top:clamp(14px, 2.4vw, 22px);max-width:100%;overflow-x:auto;scrollbar-width:none;
  padding-bottom:10px;-webkit-overflow-scrolling:touch}
.tabs::-webkit-scrollbar{display:none}
.tabs button{flex:0 0 auto;border:0;background:none;padding:6px 0;color:var(--ash);font:500 var(--t-s) var(--f-sans);letter-spacing:.005em;cursor:pointer;
  white-space:nowrap;transition:color .3s;-webkit-tap-highlight-color:transparent}
.tabs button:hover{color:var(--bone)}
.tabs button[aria-selected=true]{color:var(--bone)}
.tabs button:focus-visible{outline:2px solid var(--signal);outline-offset:4px;border-radius:3px}
.tabs-line{position:absolute;left:0;bottom:4px;height:1.5px;width:0;background:var(--signal);border-radius:1px;
  transition:transform .55s cubic-bezier(.25,.8,.25,1), width .55s cubic-bezier(.25,.8,.25,1)}
html:not(.js) .tabs-line{display:none}
@media (prefers-reduced-motion:reduce){ .tabs-line{transition:none} }

/* ── viewer ──
   The image fills the screen with thin borders (none on phones); the caption sits quietly at the bottom. The outer
   thirds of the screen are back / forward (a thin arrow cursor), the middle closes. */
html{scrollbar-gutter:stable}
.lb-on .m img{transform:none !important;transition:none} .lb-on .m::after{opacity:0 !important}   /* no hover zoom or shade while a piece is viewed or landing */                 /* the page width never changes when overlays come and go */
.m.away img,.m.away video,.m.away .lq{opacity:0 !important;transition:none}
.m.back img,.m.back video,.m.back .lq{transition:none !important}   /* coming back from the viewer: appear at once, not with the first-load fade */   /* opacity, not visibility: a hidden paused video can lose its decoded frames and re-buffer */
.lb{position:fixed;inset:0;z-index:80;visibility:hidden;overscroll-behavior:contain;contain:strict}
.lb.open{visibility:visible}
.lb.closing,.lb.closing *{pointer-events:none}      /* while it glides away, the page underneath already takes clicks */
.lb-bg{position:absolute;inset:0;background:#050304;opacity:0;transition:opacity .42s cubic-bezier(.2,.7,.2,1);will-change:opacity}
.lb.bg-on .lb-bg{opacity:1}
.lb-stage{position:absolute;inset:0;touch-action:none;user-select:none;-webkit-user-select:none;cursor:default}
.lb-stage[data-z=c]{cursor:zoom-out}
.lb-stage[data-z=l],.lb-stage[data-z=r]{cursor:pointer}
.lb-slide{position:absolute;left:0;top:0;transform-origin:0 0;will-change:transform;overflow:hidden;background:#0b0809;backface-visibility:hidden}
.lb-in{position:absolute;left:0;top:0;transform-origin:0 0;will-change:transform}
.lb-in > *{inset:-1px !important;width:calc(100% + 2px) !important;height:calc(100% + 2px) !important}   /* 1px overdraw on every side, clipped by the frame */
.lb-in img,.lb-in video,.lb-in canvas{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.lb-in .hi,.lb-in video{opacity:0;transition:opacity .35s ease}
.lb-in .hi.on,.lb-in video.on{opacity:1}
.lb-in video.master{transition:opacity .18s linear}
.lb-in video.master.on{opacity:.998}   /* not quite opaque: the travelling video under it is then never 'hidden', which Chrome throttles */
.lb-ui{position:absolute;inset:0;pointer-events:none;transition:opacity .35s}
.lb.idle .lb-ui{opacity:0}
.lb.closing .lb-ui{opacity:0;transition:opacity .12s}
.lb-cap{position:absolute;left:0;top:0;margin:0;will-change:transform;display:flex;gap:12px;align-items:baseline;font-size:var(--t-s);color:var(--bone);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:transform .45s cubic-bezier(.25,.8,.25,1)}
.lb-cap.in{text-shadow:0 1px 10px rgba(0,0,0,.7)}
.lb-cap .what:empty{display:none}
.lb-cap .when{font-family:var(--f-mono);font-size:var(--t-xs);letter-spacing:.06em;color:var(--ash)}
.lb-cap.in .when{color:rgba(236,230,227,.75)}
.lb-g{position:absolute;left:0;top:0;width:28px;height:28px;color:var(--bone);opacity:.32;transition:opacity .3s, transform .45s cubic-bezier(.25,.8,.25,1)}
.lb-g svg{width:28px;height:28px;display:block}
.lb-stage[data-z=l] ~ .lb-ui .lb-g.l,.lb-stage[data-z=r] ~ .lb-ui .lb-g.r{opacity:.95;transform-origin:center}
.lb.solo .lb-g{display:none}
.lb-x{position:absolute;pointer-events:auto;top:max(3px, env(safe-area-inset-top, 0px));right:max(6px, env(safe-area-inset-right, 0px));width:40px;height:40px;
  display:grid;place-items:center;border:0;border-radius:50%;background:rgba(10,8,9,.35);color:var(--bone);cursor:pointer;padding:0;transition:background-color .25s}
.lb-x svg{width:20px;height:20px}
.lb-x:hover{background:rgba(40,32,34,.6)}
.lb-x:focus-visible,.lb-sr:focus-visible{outline:2px solid var(--signal);outline-offset:2px}
.lb-sr{position:absolute;top:50%;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);border:0;padding:0;background:none;color:var(--bone)}
.lb-sr:focus-visible{width:44px;height:44px;clip-path:none;margin-top:-22px;pointer-events:auto;border-radius:50%;background:rgba(10,8,9,.5);display:grid;place-items:center}
.lb-sr svg{width:20px;height:20px} .lb-sr.pv{left:16px} .lb-sr.nx{right:16px}
@media (prefers-reduced-motion:reduce){ .lb-ui,.lb-in .hi,.lb-in video,.lb-cap{transition:none} }

/* loading: a small ring at the end of the caption line, only when the full quality takes a moment (data-ld: pend,
   wait, fin = just finished, ok) */
.lb-st{position:absolute;inset:0;pointer-events:none}
.lb.closing .lb-st{opacity:0;transition:opacity .12s}
.lb-ring{position:absolute;left:0;top:0;width:14px;height:14px;fill:none;stroke-width:1.2;opacity:0;transition:opacity .4s}
.lb-ring circle{stroke:rgba(236,230,227,.14)}
.lb-ring .arc{stroke:rgba(236,230,227,.75);stroke-dasharray:22 100;stroke-linecap:round;transform-origin:8px 8px;transition:stroke-dasharray .35s ease}
.lb[data-ld=wait] .lb-ring{opacity:1}
.lb[data-ld=wait] .lb-ring .arc{animation:lb-spin .9s linear infinite}
@keyframes lb-spin{to{transform:rotate(360deg)}}
.lb[data-ld=fin] .lb-ring{opacity:0;transition:opacity .5s ease .4s}
.lb[data-ld=fin] .lb-ring .arc{stroke-dasharray:100 100}
@media (prefers-reduced-motion: reduce){.lb-ring .arc{animation:none !important}}
