/* Museum-walk gallery (chapter 05) — pairs with gallery.html.
   Geometry: one 100vh pinned "room" inside a tall [data-scrub] scene. The two walls are FLAT
   strips rotated in a shared perspective — the left wall is hinged at the viewport's left
   edge and recedes toward the vanishing point, the right wall mirrors it. Scroll does not
   move a camera through 3D (camera-passing-a-plane blows up at the perspective plane and
   breaks hit-testing); instead each wall's inner track translates along its own plane, which
   reads identically — paintings stream out of the depth, swell past your shoulder, and exit
   behind you. The scroll position IS the timeline (no transitions on scrubbed transforms,
   per the motion.js invariant: transform/opacity only, one custom property per frame).

   Variables: --walk-frame (frame width) and --walk-gap are design tokens below;
   --walk-travel (px, how far each track streams) is measured by gallery.html's component
   from the track's real scrollWidth, and --scrub-progress is written by js/motion.js. */

.walk-scene { position: relative; }

.walk-pin {
  /* `clip`, not `hidden`: a hidden-overflow box whose content overflows is still a legal
     target for the browser's scroll-into-view on keyboard focus, which would scroll the
     pin's clipped box through a channel the --scrub-progress transform knows nothing
     about and desync the corridor. `clip` forbids all programmatic scrolling. */
  position: sticky; top: 0; height: 100vh; overflow: clip;
  /* The room: skylight above, floor shadow below — all screen-space, no 3D planes needed. */
  background:
    radial-gradient(ellipse 120% 60% at 50% -12%, rgba(247, 241, 227, .95), transparent 62%),
    linear-gradient(to bottom, #EAE0CC 0%, #E6DBC5 52%, #D5C8AC 88%, #C9BB9E 100%);
}

.walk-room {
  position: absolute; inset: 0;
  perspective: 1250px; perspective-origin: 50% 44%;
  transform-style: preserve-3d;
  /* Hit-testing in a preserve-3d context is depth-sorted: this container's own full-viewport
     box sits on the z=0 plane, NEARER the camera than every receded frame, so it would swallow
     every click even though it paints nothing. Opt the room (and the planes on the way down)
     out of pointer events entirely and opt the frames themselves back in. */
  pointer-events: none;
}
.walk-frame { pointer-events: auto; }

.walk-wall {
  /* The wall's geometric tunables, single-sourced: the width budget, mask and blur
     overlay below and the hinge/rotation rules further down all derive from these, so
     retuning the corridor cannot desync them (the file's other tunables
     --walk-frame/--walk-gap set the precedent). --walk-fade is the golden section
     (1/φ ≈ 61.8%, owner request): paintings are fully present for the first 61.8% of
     the wall's run and spend the remaining ~38% dissolving into the haze. */
  --walk-hinge: 36px;
  --walk-angle: 62deg;
  --walk-budget: 0.95;
  --walk-fade: 61.8%;
  position: absolute; top: 0; height: 100%;
  display: flex; align-items: center;
  /* Depth budget (透视原理 invariant): each wall strip runs from its hinge TOWARD the
     corridor's centerline but must stop short of it — an unclipped track is long enough
     that its far frames project past the vanishing point into the other wall's half and
     the two walls visibly interpenetrate mid-screen (the "V型" bug). In wall-plane units
     the centerline sits at (50vw + hinge) / cos θ from the hinge; the strip keeps
     --walk-budget of that and `overflow: clip` cuts the rest in the wall's OWN plane.
     The clip is the hard no-crossing guarantee, never the visible ending: the mask
     below fades each wall to fully transparent BEFORE its clip edge, so distant
     paintings simply become too far away to see instead of being sliced. Frames stream
     in through that dissolved end as the track translates. (clip also flattens this
     subtree, which is fine: every descendant is coplanar with the wall.) */
  width: calc((50vw + var(--walk-hinge)) / cos(var(--walk-angle)) * var(--walk-budget));
  overflow: clip;
}
/* Atmospheric dissolve, in the wall's own plane (masks apply in local space, THEN the 3D
   transform projects them, so it tracks wall-depth exactly): the mask holds full presence to
   the golden section of the run, then fades to nothing well before the clip edge — the
   boundary itself can never be seen.
   No backdrop-filter/blur layer here on purpose (removed 2026-07-13): a blurred ::after
   inside this rotateY + preserve-3d + perspective subtree is exactly the combination behind
   several open Gecko rendering bugs (e.g. Firefox bug 1952612, "backdrop-filter not working
   with transform-style:preserve-3d", and 1808232 for the backface-visibility variant) — it
   rendered fine in Chrome but corrupted the whole corridor's geometry in Firefox. The mask
   fade alone still reads as depth; it just loses the extra soft-focus polish. */
.walk-wall-left {
  -webkit-mask-image: linear-gradient(to right, #000 var(--walk-fade), transparent 94%);
          mask-image: linear-gradient(to right, #000 var(--walk-fade), transparent 94%);
}
.walk-wall-right {
  -webkit-mask-image: linear-gradient(to left, #000 var(--walk-fade), transparent 94%);
          mask-image: linear-gradient(to left, #000 var(--walk-fade), transparent 94%);
}
/* Hinges sit just outside the viewport so the nearest frame bleeds off-screen as you pass it
   (you never see a wall's raw near edge). Angles: steep enough to converge well inside the
   viewport, shallow enough that plaques stay legible three frames deep.
   Sign convention (CSS rotateY): positive θ maps local +X to z' = −sin θ·x — i.e. content to
   the RIGHT of the origin recedes. Left wall content extends right of its hinge → positive θ;
   right wall content extends left of its hinge → negative θ. (Getting these backwards folds
   both walls across the camera plane and the corridor renders empty.)
   The right wall is a flex-end container so its oversized track's END edge stays pinned to
   the hinge — in plain block flow the track would overflow rightward past the viewport. */
.walk-wall-left  { left: calc(-1 * var(--walk-hinge));  transform-origin: left center;  transform: rotateY(var(--walk-angle)); }
.walk-wall-right { right: calc(-1 * var(--walk-hinge)); transform-origin: right center; transform: rotateY(calc(-1 * var(--walk-angle))); justify-content: flex-end; }

.walk-track {
  --walk-frame: clamp(300px, 28vw, 400px);
  --walk-gap: clamp(48px, 5vw, 72px);
  display: flex; align-items: center; gap: var(--walk-gap);
  width: max-content; flex: none;
  /* Lead spacer: the first painting starts a stride ahead instead of already at your shoulder. */
  padding-left: calc(var(--walk-frame) * .6);
  transform: translateX(calc(var(--scrub-progress, 0) * var(--walk-travel, 0px) * -1));
  will-change: transform;
}
/* Right wall mirrors everything: row-reverse puts item №1 at the near (hinge) end, the
   half-step lead staggers its frames between the left wall's, and the stream direction flips. */
.walk-wall-right .walk-track {
  flex-direction: row-reverse;
  padding-left: 0;
  padding-right: calc(var(--walk-frame) * .6 + (var(--walk-frame) + var(--walk-gap)) / 2);
  transform: translateX(calc(var(--scrub-progress, 0) * var(--walk-travel, 0px)));
}

/* ---------- one hung painting: frame, matte, plaque ---------- */
.walk-frame {
  display: block; width: var(--walk-frame); flex: none;
  text-decoration: none; color: inherit;
  /* No backface-visibility: hidden (removed 2026-07-13): frames never rotate past 90° from
     the camera at this corridor's --walk-angle, so it bought nothing, and it's the other half
     of the Firefox 1808232 pairing (3D transform + backface-visibility:hidden breaks
     backdrop-filter) — dropping it removes one more part of a rendering-hazard combination. */
}
.walk-art {
  display: block; background: #F7F1E3; padding: 11px;
  border: 8px solid #38291C; border-radius:4px;
  box-shadow: 0 30px 52px -22px rgba(34, 29, 23, .6), inset 0 0 0 1px rgba(255, 255, 255, .28);
}
.walk-art img { display: block; width: 100%; height: clamp(210px, 20vw, 285px); object-fit: cover; }
.walk-plaque {
  display: block; margin: 14px auto 0; width: fit-content; max-width: 94%;
  text-align: center; background: #F1E8D4;
  border: 1px solid rgba(34, 29, 23, .2); border-radius:8px;
  padding: 7px 13px; box-shadow: 0 3px 9px rgba(34, 29, 23, .16);
}
.walk-plaque b {
  display: block; font-weight: 600; font-size: 13px; color: #221D17;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 34ch;
}
.walk-plaque i {
  display: block; font-style: normal; font-family: var(--ff-mono); font-size: 9.5px;
  color: rgba(34, 29, 23, .62); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 38ch;
}
/* Hover/focus: the red conservation ring — the same accent every clickable specimen uses. */
.walk-frame:hover .walk-art, .walk-frame:focus-visible .walk-art {
  box-shadow: 0 34px 60px -20px rgba(34, 29, 23, .72), 0 0 0 3px rgba(200, 69, 59, .6);
}
.walk-frame:focus-visible { outline: none; }

/* ---------- screen-space depth fog ----------
   Far content always converges into the same screen region (around the perspective origin),
   so a fixed radial veil there reads as atmospheric depth for every frame at once — no
   per-item math, no extra per-frame style writes. */
.walk-fog {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 30% 42% at 50% 44%,
    rgba(232, 222, 200, .95) 0%, rgba(232, 222, 200, .55) 55%, transparent 100%);
}

/* ---------- HUD: hint + dose-gauge progress ---------- */
.walk-hud {
  position: absolute; left: 0; right: 0; bottom: 20px;
  display: flex; flex-direction: column; gap: 10px; align-items: center;
  pointer-events: none;
}
.walk-hint {
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: rgba(34, 29, 23, .66); background: rgba(247, 241, 227, .78);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  padding: 7px 14px; border-radius:12px; corner-shape: squircle;
  border: 1px solid rgba(34, 29, 23, .1);
}
.walk-progress {
  width: min(420px, 60vw); height: 2px; border-radius:2px;
  background: rgba(34, 29, 23, .14); overflow: hidden;
}
.walk-progress i {
  display: block; height: 100%; transform-origin: 0 50%;
  transform: scaleX(var(--scrub-progress, 0));
  background: linear-gradient(90deg, var(--color-good, #5E7A4E), var(--color-warn, #D7A33C) 55%, var(--color-accent, #C8453B));
}

/* ---------- fallback: plain grid (narrow viewports, reduced motion) ----------
   Uses home.css's .gallery-grid/.gallery-card family — same cards the old home gallery used.
   The corridor's lazy-loaded imgs never intersect while display:none, so the hidden variant
   costs no bandwidth. */
.walk-fallback { display: none; max-width: 1240px; margin: 0 auto; padding: 8px clamp(18px, 5vw, 64px) var(--section-gap); }
/* This grid is flat/static — no scrub scene, and no off-screen IntersectionObserver like
   index.html's to pause floats — so home.css's infinite galleryFloat bob (lives on .gallery-card
   itself, not the img — see home.css's float-paused comment) and the slot's --scrub-progress
   drift would otherwise run forever, unpaused, on up to 32 cards. Both are switched off here. */
.walk-fallback .gallery-card { animation: none; }
.walk-fallback .gallery-card-slot { transform: none; }
@media (max-width: 860px), (prefers-reduced-motion: reduce) {
  .walk-scene { height: auto !important; }
  .walk-pin { position: static; height: auto; overflow: visible; background: none; }
  .walk-room, .walk-fog, .walk-hud { display: none; }
  .walk-fallback { display: block; }
}
/* Engines without `overflow: clip` (WebKit before Safari 16 — iOS/iPadOS ≤15 and the
   final Safari on macOS Catalina) would drop the walls' clip declaration and let the
   tracks paint straight across the centerline again — the exact crossing the depth
   budget exists to prevent. `overflow: hidden` is NOT a safe fallback: the frames are
   real <a>s, and a hidden box is a scroll container the browser will scroll on keyboard
   focus (see the .walk-pin note above). Those engines take the same graceful exit as
   narrow viewports: the flat grid. */
@supports not (overflow: clip) {
  .walk-scene { height: auto !important; }
  .walk-pin { position: static; height: auto; overflow: visible; background: none; }
  .walk-room, .walk-fog, .walk-hud { display: none; }
  .walk-fallback { display: block; }
}
