/* ══ THE ZINE-OPEN TRANSITION, DRESSED. ══════════════════════════════════════════════════════════
   ONE stylesheet, linked by BOTH surfaces that can play this transition:
     · the app chrome (src/app/layout.tsx <head>)        — the cork wall's shelf, /clubs/<slug>
     · the reading table (demos/book-reader/reader.html) — the zine grid at /show-and-tell
   It used to live inside src/app/globals.css, which the reader cannot load: /show-and-tell is a
   route handler serving a static file, not a page under the app layout. Pasting a copy into the
   reader would have made a second edition of a 100-line camera rig, and two copies of one animation
   is exactly how the orb hub ended up with three (see scripts/build-island.mjs for that story).

   Behaviour lives in src/app/clubs/[slug]/zineOpenTransition.ts and is bundled to /zine-open.js for
   the vanilla surfaces (npm run build:zine-open, guarded by src/reader/zine-open-stale.test.ts).

   Everything here is scoped under `.ztx` — an overlay that exists only during the ~2.4s beat — and
   every colour it uses is its own `--ztx-*` token, no app token and no reader token, precisely so
   this file can be dropped onto any ground without inheriting one. Do not add a rule that reaches
   outside `.ztx`.

   The scrim copies the live ground's background at runtime (JS) so it is a pixel match — the wall's
   clutter "disappears" behind identical cork while the tapped zine flies to centre; on the reading
   table the same trick hides the pile behind the table's own paper. ══════════════════════════════ */
/* pointer-events:auto — the overlay owns input for the ~2.4s beat. It's aria-hidden and decorative,
   but a tap falling through to the wall underneath could start a SECOND navigation that then collides
   with this transition's own pending one (you'd land somewhere, then get yanked to the reader). */
.ztx { position: fixed; inset: 0; z-index: 99999; pointer-events: auto; }
.ztx-cork { position: absolute; inset: 0; z-index: 2; }
/* THE FLYING ZINE. `.ztx > .ztx-zine`, not `.ztx-zine.zbook-art`: the clone is whatever the caller
   tapped, and it now arrives wearing two different costumes — the wall's `.zbook-art` cover and the
   reading table's `.gcard`. Both bring a resting transform, a margin and a z-index of their own, and
   the overlay has to outrank all of them. The descendant form is (0,2,0), same as the old compound,
   and it is true by construction: the clone is appended directly to the .ztx overlay root. */
.ztx > .ztx-zine { position: fixed; margin: 0; transform-origin: center center; will-change: transform;
  display: block; z-index: 5; border-radius: 3px; box-shadow: 6px 8px 0 rgba(26, 14, 4, 0.5); }
/* the table's cards paint their torn edge and their own hard shadow through a filter on the <img>;
   inside the overlay the card carries the shadow (above), so the doubled one comes off. */
.ztx > .ztx-zine.gcard img { filter: none; }
@media (prefers-reduced-motion: reduce) { .ztx { display: none !important; } }

/* ── Cube-ROOM beat for the zine-open transition (wall side). Additive; exists ONLY during the
   transition, entirely inside the .ztx overlay (never touches the resting cork wall or the reader).
   Flat cartoon skeuo per DESIGN.md: flat fills + hard-offset ink shadows + hard-edged repeating
   textures — no soft blur, no soft gradients. Ported from whimsy/doom-transition-v3.html; its
   frame-relative absolute-px constants are re-expressed against --S/--P/--dz-rest, which JS sizes
   from the real full-screen viewport so the room fills the screen. See zineOpenTransition.ts. ── */
@property --ztx-pitch { syntax: "<angle>";  inherits: true; initial-value: 0deg; }
@property --ztx-dz    { syntax: "<length>"; inherits: true; initial-value: 0px; }

/* --ztx-beat = the length of ONE camera gesture (dolly / pitch / dive). JS sets it from ZTX_CAM_MS in
   zineOpenTransition.ts so the CSS camera and the JS tweens that ride along with it stay in lockstep —
   retune the tempo there, not here. The literal is only the no-JS fallback. */
.ztx { --ztx-plaster:#b9beb3; --ztx-plaster-hi:#ece6da; --ztx-desk:#f2e6cd; --ztx-ink:#414d57;
  --ztx-oats:#fef6e4; --ztx-sky:#bfe3f2; --ztx-ease:cubic-bezier(.5,.02,.24,1); --ztx-beat:.78s; }
.ztx[data-tod="dawn"]  { --ztx-sky:#f6b6a0; }
.ztx[data-tod="dusk"]  { --ztx-sky:#e58b6a; }
.ztx[data-tod="night"] { --ztx-sky:#26333d; }

/* camera housing — owns perspective (= --P) + a vanishing point that rises as we pitch down */
.ztx-vp { position:absolute; inset:0; overflow:hidden; z-index:1;
  perspective:var(--P,800px); perspective-origin:54% 49%;
  transition:perspective-origin var(--ztx-beat,.78s) var(--ztx-ease); }
.ztx.s-down .ztx-vp { perspective-origin:54% 32%; }

/* the ROOM — eye-pivot camera (transform-origin Z = --P) + a DOLLY (translateZ = --dz) */
.ztx-room { position:absolute; top:50%; left:50%; width:var(--S,600px); height:var(--S,600px);
  transform-style:preserve-3d; transform-origin:50% 50% var(--P,800px);
  --ztx-dz:var(--dz-rest,600px); --ztx-pitch:0deg;
  transform:translate(-50%,-50%) translateZ(var(--ztx-dz)) rotateX(var(--ztx-pitch));
  transition:--ztx-dz var(--ztx-beat,.78s) var(--ztx-ease), --ztx-pitch var(--ztx-beat,.78s) var(--ztx-ease), opacity .4s var(--ztx-ease); }
.ztx.s-reveal .ztx-room { --ztx-dz:0px; }        /* dolly OUT → reveal the cube */
.ztx.s-down   .ztx-room { --ztx-pitch:-60deg; }   /* pitch DOWN to the desk (negative = look down; keeps the window/walls in frame on a wide viewport) */
/* hold the room opaque until the desk (viewport bg) has settled underneath, then dissolve the floor */
.ztx.s-read   .ztx-room { opacity:0;
  transition:opacity calc(var(--ztx-beat,.78s) * .72) calc(var(--ztx-beat,.78s) * .45); }

.ztx-face { position:absolute; width:var(--S,600px); height:var(--S,600px); left:0; top:0; }
.ztx-face.front { transform:translateZ(calc(var(--S)/-2)); } /* cork — background copied in JS */
.ztx-face.left  { transform:rotateY(90deg)  translateZ(calc(var(--S)/-2)); background:var(--ztx-plaster);
  background-image:repeating-radial-gradient(circle at 3px 4px,rgba(70,78,70,.12) 0 1px,transparent 1px 11px);
  background-size:11px 11px; box-shadow:inset 0 0 0 2px rgba(70,78,70,.12); }
.ztx-face.right { transform:rotateY(-90deg) translateZ(calc(var(--S)/-2)); overflow:visible; background:var(--ztx-plaster);
  background-image:repeating-radial-gradient(circle at 3px 4px,rgba(70,78,70,.12) 0 1px,transparent 1px 11px);
  background-size:11px 11px; box-shadow:inset 0 0 0 2px rgba(70,78,70,.12); }
.ztx-face.ceil  { transform:rotateX(-90deg) translateZ(calc(var(--S)/-2)); background:var(--ztx-plaster-hi); }
.ztx-face.floor { width:calc(var(--S)*1.7); height:calc(var(--S)*3.4); left:50%; top:50%;
  transform:translate(-50%,-50%) translateY(calc(var(--S)*0.5)) rotateX(90deg); background:var(--ztx-desk);
  background-image:repeating-linear-gradient(0deg,rgba(120,83,39,.13) 0 3px,transparent 3px 24px); }

/* window on the right wall — flat cartoon, hard edges, time-of-day sky */
.ztx-win { position:absolute; left:calc(var(--S)*0.282); top:calc(var(--S)*0.306);
  width:calc(var(--S)*0.441); height:calc(var(--S)*0.388);
  border:max(4px,calc(var(--S)*0.017)) solid var(--ztx-ink); border-radius:3px; background:var(--ztx-sky);
  overflow:hidden; box-shadow:calc(var(--S)*0.012) calc(var(--S)*0.015) 0 rgba(26,14,4,.45); }
.ztx-win .g    { position:absolute; left:0; right:0; bottom:0; height:calc(var(--S)*0.1); background:#1cab5b;
  border-top:max(2px,calc(var(--S)*0.009)) solid var(--ztx-ink); }
.ztx-win .sun  { position:absolute; right:calc(var(--S)*0.053); top:calc(var(--S)*0.041);
  width:calc(var(--S)*0.1); height:calc(var(--S)*0.1); border-radius:50%; background:#ecaf21;
  border:max(2px,calc(var(--S)*0.009)) solid var(--ztx-ink); }
.ztx-win .moon { position:absolute; right:calc(var(--S)*0.053); top:calc(var(--S)*0.041);
  width:calc(var(--S)*0.088); height:calc(var(--S)*0.088); border-radius:50%; background:var(--ztx-oats);
  border:max(2px,calc(var(--S)*0.009)) solid var(--ztx-ink); box-shadow:inset calc(var(--S)*-0.023) 0 0 #2b3550; display:none; }
.ztx-win .mv   { position:absolute; left:50%; top:0; bottom:0; width:max(2px,calc(var(--S)*0.012)); background:var(--ztx-ink); transform:translateX(-50%); }
.ztx-win .mh   { position:absolute; left:0; right:0; top:50%; height:max(2px,calc(var(--S)*0.012)); background:var(--ztx-ink); transform:translateY(-50%); }
.ztx[data-tod="night"] .ztx-win .sun  { display:none; }
.ztx[data-tod="night"] .ztx-win .moon { display:block; }

/* the window's LIGHT cast on the desk — FOUR flat pane-rectangles skewed into a shaft (no glow) */
.ztx-floorlight { position:absolute; right:var(--fl-right,7%); bottom:var(--fl-bot,30%);
  width:calc(var(--S)*0.606); height:calc(var(--S)*0.535); pointer-events:none;
  display:grid; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:13% 15%;
  transform-origin:100% 0%; transform:skewX(var(--fl-skx,-26deg)) skewY(var(--fl-sky,-6deg)); }
.ztx-floorlight i { background:var(--fl-fill,rgba(236,175,33,.34)); border-radius:2px; }
.ztx[data-tod="dawn"]  .ztx-floorlight { --fl-fill:rgba(236,175,33,.28); --fl-skx:-46deg; --fl-bot:34%; }
.ztx[data-tod="dusk"]  .ztx-floorlight { --fl-fill:rgba(232,145,46,.34); --fl-skx:-48deg; --fl-bot:34%; }
.ztx[data-tod="night"] .ztx-floorlight { --fl-fill:rgba(70,130,190,.24); --fl-skx:12deg;  --fl-right:20%; }

/* Doom-style floor-pinned billboard sprite — feet on the ground, partially cancels camera pitch */
.ztx-sprite-anchor { position:absolute; left:50%; top:50%; transform-style:preserve-3d;
  transform:translate3d(calc(var(--S)*0.282),calc(var(--S)*0.5),calc(var(--S)*0.082)); }
.ztx-sprite-img { width:calc(var(--S)*0.212); height:calc(var(--S)*0.312); transform-origin:50% 100%;
  transform:translate(-50%,-100%) rotateX(calc(-1 * var(--ztx-pitch) * 0.5));
  filter:url(#ztxRough1); animation:ztxBoil .42s steps(1,end) infinite; }
@keyframes ztxBoil { 0%,33%{ filter:url(#ztxRough1); } 34%,66%{ filter:url(#ztxRough2); } 67%,100%{ filter:url(#ztxRough3); } }
@media (prefers-reduced-motion:reduce){ .ztx-sprite-img{ animation:none; filter:url(#ztxRough1); } }

/* HUD spread — the flat book that "opens" under the flown cover; scales in lockstep with the cover */
.ztx-hud-spread { position:fixed; z-index:4; display:flex; opacity:0; will-change:transform,opacity;
  box-shadow:6px 8px 0 rgba(80,54,20,.4); }
.ztx-leaf { flex:1 1 50%; background:#fffdf6; border:2.5px solid var(--ztx-ink,#414d57); box-sizing:border-box; }
.ztx-leaf.l { border-right:1px solid var(--ztx-ink,#414d57); border-radius:3px 0 0 3px;
  transform-origin:right center; transform:scaleX(.05); box-shadow:inset -7px 0 0 rgba(65,77,87,.1); }
.ztx-leaf.r { border-radius:0 3px 3px 0; }
