/* =============================================================================
   chamber-hero.css — the Aldervaatch round table hero
   Red Warden Studios · v1
   Loaded AFTER styles.css. Supersedes the old .chamber-bg / .symbol-hotspot
   hero entirely; those rules are left in styles.css but no longer reachable.

   ── THE COVER STAGE ─────────────────────────────────────────────────────────
   .chamber-stage holds a FIXED aspect ratio and is sized to cover the viewport.
   Because its internal geometry never changes, an emblem percentage is exact on
   every screen and the viewport simply crops the edges.

   A full-viewport `background-size:cover` cannot do this — the crop origin moves
   with the aspect ratio, so percentage hotspots drift. That is why the old
   hand-tuned percentages only looked right on the monitor they were tuned on.
   ========================================================================== */

.chamber-hero{
  position:relative;
  width:100%;
  height:100vh;
  height:100svh;                 /* svh: iOS browser chrome must not shift the table */
  overflow:hidden;
  display:grid;
  place-items:center;
  /* styles.css still sets justify-content:flex-start on .chamber-hero from the old
     flex layout. That property is NOT overridden by place-items, and under grid it
     would shove the stage to the left edge. place-content covers both axes. */
  place-content:center;
  background:var(--rws-void,#050506);
  isolation:isolate;
}

.chamber-stage{
  position:relative;
  aspect-ratio:16/9;
  width:100vw;
  width:max(100vw, calc(100svh * 16 / 9));   /* always covers; never letterboxes */
  transform:translateZ(0);
}
/* Full-bleed layers only. Do NOT use `.chamber-stage > *` — it also catches
   .chamber-title and .chamber-go and stretches them to the whole stage. */
.chamber-stage > .chamber-plate,
.chamber-stage > .chamber-glow-l,
.chamber-stage > .chamber-core-l,
.chamber-stage > .chamber-edge-l,
.chamber-stage > .chamber-canvas,
.chamber-stage > .chamber-vignette,
.chamber-stage > .chamber-seats{position:absolute;inset:0;width:100%;height:100%;}

/* ── Plate ────────────────────────────────────────────────────────────────
   The video is an OVERLAY on the still plate, never a replacement: the image
   is the poster, the fallback, and what shows if the codec is unavailable. */
.chamber-plate{object-fit:cover;display:block;}

/* ⚠️ THE STILL PLATE IS A <picture>, AND THAT IS A PERFORMANCE FIX, NOT A TIDY-UP.
   Until 2026-08-08 it was TWO <img> elements — landscape and portrait — toggled
   with display:none. **display:none does not stop a browser downloading an
   image.** Every phone pulled the 687 KB landscape plate, threw it away, and
   then pulled the 246 KB portrait one. Mobile LCP was 11.1s.
   The file already knew this: the note on the <video> tags explains that exact
   behaviour, which is why the loops carry data-src instead of a source. The
   images were simply never given the same treatment.
   A <picture> makes the browser evaluate `media` BEFORE it fetches, so exactly
   one plate is ever requested. The <source> media query MUST stay identical to
   the portrait breakpoint below (max-aspect-ratio:1/1) — if they drift, the
   layout swaps to the portrait stage while the landscape plate is still loaded.
   The wrapper keeps the .chamber-plate class because the full-bleed rule above
   is a DIRECT-CHILD selector; a bare <picture> would drop out of it. */
picture.chamber-plate{display:block;}
picture.chamber-plate > img{width:100%;height:100%;object-fit:cover;display:block;}
video.chamber-plate--portrait{display:none;}

/* The loops carry NO poster attribute (see the note in index.html — those were
   pulling BOTH plates on every phone). A <video> with no poster frame and no
   decoded data is transparent in Chrome, Safari and Firefox, which is what lets
   the <picture> beneath show through. This makes that explicit rather than
   relying on a default, so a future UA that paints an opaque box cannot flash
   black over the hero. */
video.chamber-plate{background:transparent;}

/* ── The one-shot ruby pour ───────────────────────────────────────────────
   Fires once on arrival, then hands the stage to the emblems. It does NOT
   loop: a repeating pour keeps re-firing the "something is happening" signal,
   so the eye never settles on the thing that is actually clickable. */
@property --r{ syntax:'<length>'; inherits:true; initial-value:0px; }

/* ⚠ .chamber-clip MUST be sized explicitly. Its only child is absolutely
   positioned, so left static it computes to height 0 — and `mask-size:100% 100%`
   then resolves against a zero-height box, which masks the entire pour away.
   That is exactly what happened on 2026-08-02: the ruby never appeared and the
   warm glow on screen was the video's own bronze inlay, not the CSS layer. */
.chamber-clip{
  position:absolute;inset:0;width:100%;height:100%;
  -webkit-mask-image:url('../assets/roundtable/inlay-mask-alpha.png');
          mask-image:url('../assets/roundtable/inlay-mask-alpha.png');
  -webkit-mask-size:100% 100%;         mask-size:100% 100%;
  -webkit-mask-position:center;        mask-position:center;
  -webkit-mask-repeat:no-repeat;       mask-repeat:no-repeat;
}
.chamber-wave,
.chamber-wave2{position:absolute;inset:0;width:100%;height:100%;}

/* Animate an explicit RADIUS, never mask-size. mask-position places a BOX, so
   growing the box slides the gradient's centre (~480px downward when this was
   first built) and the geometry stops being solvable. */
.chamber-wave{
  -webkit-mask-image:radial-gradient(circle var(--r) at var(--hx) var(--hy),
    #000 0%,#000 62%,rgba(0,0,0,.35) 84%,transparent 100%);
          mask-image:radial-gradient(circle var(--r) at var(--hx) var(--hy),
    #000 0%,#000 62%,rgba(0,0,0,.35) 84%,transparent 100%);
  background:#E4231C;
}
.chamber-wave2{
  -webkit-mask-image:radial-gradient(circle var(--r) at var(--hx) var(--hy),
    transparent 0%,transparent 52%,#000 72%,#000 86%,transparent 100%);
          mask-image:radial-gradient(circle var(--r) at var(--hx) var(--hy),
    transparent 0%,transparent 52%,#000 72%,#000 86%,transparent 100%);
  background:#FFDCAC;
}
/* Blur belongs on a PARENT of the masked element, so the glow spills off the
   metal instead of being clipped to it. */
.chamber-glow-l{filter:blur(5px);mix-blend-mode:screen;opacity:.5;}
.chamber-core-l{mix-blend-mode:screen;opacity:.88;}
.chamber-edge-l{filter:blur(2px);mix-blend-mode:screen;opacity:.95;}

.chamber-stage{--t:8.5s;--hx:49.8%;--hy:36.5%;}
.is-pouring .chamber-wave,
.is-pouring .chamber-wave2{animation:rwsSpread var(--t) cubic-bezier(.30,.05,.22,1) forwards;}
.is-pouring .chamber-edge-l{animation:rwsFade  .9s ease-in  calc(var(--t)*.82) forwards;}
.is-pouring .chamber-core-l{animation:rwsCool  .9s ease-out calc(var(--t)*.90) forwards;}
.is-pouring .chamber-glow-l{animation:rwsHand 1.6s ease-out calc(var(--t)*.95) forwards;}
@keyframes rwsSpread{from{--r:0px;} to{--r:var(--maxr,2600px);}}
@keyframes rwsFade{to{opacity:0;}}
/* Settled brightness. These two are the ONLY thing holding the inlay lit once the
   pour is over — and they stack on top of the video's own bronze pulse, so they
   read brighter on the live plate than they did against a still. Dialled 0.20 → 0.10
   (Andrew, 2026-08-02: "the brass is almost too bright at the end"). Settled is not
   dead: the video keeps breathing underneath. */
@keyframes rwsCool{to{opacity:.10;}}
@keyframes rwsHand{to{opacity:.10;}}

/* Settled state for reduced-motion: emblems present, no pour. */
.is-settled .chamber-glow-l,
.is-settled .chamber-core-l{opacity:.10;}
.is-settled .chamber-edge-l{opacity:0;}
.is-settled .chamber-seat{opacity:1;}

/* ── Embers + vignette ───────────────────────────────────────────────────── */
.chamber-canvas{pointer-events:none;z-index:2;}
.chamber-vignette{
  pointer-events:none;z-index:3;
  background:radial-gradient(ellipse at 50% 45%,transparent 34%,rgba(5,5,6,.58) 100%);
}

/* ── Seats ────────────────────────────────────────────────────────────────
   --x/--y/--w/--tilt/--s/--d are all written by chamber-hero.js from the
   MEASURED geometry. Do not hardcode them here. */
.chamber-seats{perspective:1500px;pointer-events:none;z-index:6;}
.chamber-seat{
  position:absolute;left:var(--x);top:var(--y);
  width:var(--w);aspect-ratio:1/1;
  transform:translate(-50%,-50%) rotateX(var(--tilt));
  transform-style:preserve-3d;
  display:block;text-decoration:none;
  pointer-events:auto;opacity:0;
  transition:transform .45s cubic-bezier(.22,.9,.3,1), filter .45s ease;
}
.chamber-seat-art{
  display:flex;align-items:center;justify-content:center;
  width:100%;height:100%;
  transform:scale(var(--s,1));
  filter:drop-shadow(0 6px 10px rgba(0,0,0,.75));
}
.chamber-seat-art img{
  max-width:100%;max-height:100%;width:auto;height:auto;display:block;
  -webkit-user-drag:none;user-select:none;
}

/* The pour is what lights the emblems: each wakes as the wave reaches its
   collar, so by the time the ruby settles all five are present and the inlay
   has handed the stage over. --d is that per-seat arrival fraction. */
.is-pouring .chamber-seat{animation:rwsWake .7s ease-out calc(var(--t) * var(--d,0)) forwards;}
@keyframes rwsWake{
  from{opacity:0;transform:translate(-50%,-46%) rotateX(var(--tilt)) scale(.86);}
  to  {opacity:1;transform:translate(-50%,-50%) rotateX(var(--tilt)) scale(1);}
}
/* ⚠ The wake MUST be torn down once it has run.
   `animation-fill-mode:forwards` holds the element at the end keyframe, and
   animation-filled values sit ABOVE normal author declarations in the cascade —
   so while the animation is still attached, the :hover transform below simply
   cannot apply and the emblem will not lift. chamber-hero.js adds .is-awake on
   animationend; this rule drops the animation so the normal cascade resumes. */
.chamber-seat.is-awake{animation:none;opacity:1;}

/* Raised: hover on pointer devices, first tap on touch. */
@media (hover:hover) and (pointer:fine){
  .chamber-seat:hover,
  .chamber-seat:focus-visible{
    transform:translate(-50%,-64%) rotateX(0deg) scale(1.3);
    filter:drop-shadow(0 28px 26px rgba(0,0,0,.7))
           drop-shadow(0 0 20px rgba(224,35,28,.8));
    outline:none;z-index:9;
  }
  .chamber-seat:hover  .chamber-seat-label,
  .chamber-seat:focus-visible .chamber-seat-label{opacity:1;}
}
.chamber-seat.is-raised,
.chamber-seat:focus-visible{
  transform:translate(-50%,-64%) rotateX(0deg) scale(1.3);
  filter:drop-shadow(0 28px 26px rgba(0,0,0,.7))
         drop-shadow(0 0 20px rgba(224,35,28,.8));
  outline:none;z-index:9;
}
.chamber-seat.is-raised .chamber-seat-label{opacity:1;}

.chamber-seat-label{
  position:absolute;left:50%;bottom:100%;
  transform:translate(-50%,-14px);
  white-space:nowrap;pointer-events:none;
  font-family:var(--font-heading,'Cinzel',serif);
  font-size:clamp(.62rem,.85vw,.95rem);
  letter-spacing:.18em;text-transform:uppercase;
  color:var(--rws-white,#F5F5F5);
  padding:.4em .8em;
  border:1px solid rgba(245,245,245,.26);
  background:rgba(5,5,6,.74);
  opacity:0;transition:opacity .3s ease;
}

/* ── Touch confirm pill (mode B) ─────────────────────────────────────────── */
.chamber-go{
  position:absolute;left:50%;bottom:calc(env(safe-area-inset-bottom) + 5.5rem);
  transform:translateX(-50%) translateY(14px);
  z-index:12;display:inline-flex;align-items:center;gap:.6em;
  padding:.85em 1.5em;
  border:1px solid var(--rws-crimson,#C0392B);
  background:rgba(12,7,8,.92);
  font-family:var(--font-heading,'Cinzel',serif);
  font-size:clamp(.75rem,3.3vw,.95rem);
  letter-spacing:.14em;text-transform:uppercase;
  color:var(--rws-white,#F5F5F5);text-decoration:none;
  opacity:0;pointer-events:none;
  transition:opacity .3s ease, transform .3s ease;
}
.chamber-go.is-on{opacity:1;pointer-events:auto;transform:translateX(-50%) translateY(0);}
@media (hover:hover) and (pointer:fine){ .chamber-go{display:none;} }

/* ── Title, hint, scroll cue ─────────────────────────────────────────────── */
/* Anchored from its own centre rather than left:0/right:0. styles.css leaves this
   as a flex column with align-items:flex-start and constrains its width, so a
   stretched box centred nothing — the title sat hard against the stage's left edge.
   left:50% + translateX(-50%) centres on the stage regardless, and the stage is
   itself centred in the viewport, so this lands centre-screen at any size. */
.chamber-title{
  position:absolute;left:50%;top:clamp(5rem,11vh,9rem);
  transform:translateX(-50%);
  width:min(92vw,1100px);
  z-index:8;pointer-events:none;
  display:flex;flex-direction:column;align-items:center;
  text-align:center;
  /* styles.css adds padding-top:calc(var(--nav-h) + clamp(...)) to clear the fixed
     nav under the old flow layout. Absolutely positioned now, so that padding would
     stack on top of `top` and drop the title ~72px too far. The clamp above already
     clears the 72px nav on its own. */
  padding-top:0;
  padding-inline:1.2rem;
}
.chamber-eyebrow{
  font-family:var(--font-heading,'Cinzel',serif);
  font-size:clamp(1rem,2.2vw,1.6rem);
  letter-spacing:.3em;text-transform:uppercase;
  color:var(--rws-white,#F5F5F5);margin:0 0 .6rem;
  /* The chamber is lit; the line sat on stone with nothing behind it. */
  text-shadow:0 2px 14px rgba(0,0,0,.65), 0 1px 3px rgba(0,0,0,.5);
}

/* ── THE GREETING ─────────────────────────────────────────────────────────
   Andrew, 2026-08-07: "It just sticks out like a sore thumb. What if this text
   appeared for a few seconds and then faded away. Acting as an actual greeting
   instead of a label."

   Exactly right — as permanent furniture it competed with the round table it
   was introducing. Now it arrives, says its piece and gets out of the way.

   Timing: in over 1.1s, hold 3.6s, out over 1.5s. 6.2s total.
   `forwards` holds the final frame so it cannot flash back.

   Safe to fade to nothing: .chamber-title is position:absolute with
   pointer-events:none, so it occupies no layout and blocks no clicks either
   way — removing it cannot shift the plate or disturb the hotspot geometry
   that chamber-hero.js measures.

   NOTE ON REDUCED MOTION: the existing @media (prefers-reduced-motion:reduce)
   block below kills animation on everything inside .chamber-stage, so for those
   users the line simply stays put. That is deliberate and it is the correct
   behaviour — content should not vanish on its own for someone who asked the
   interface to hold still. Do not "fix" it with a delayed display:none. */
@keyframes rws-chamber-greet{
  0%   {opacity:0;}
  18%  {opacity:1;}
  76%  {opacity:1;}
  100% {opacity:0;}
}
.chamber-title{
  animation:rws-chamber-greet 6.2s var(--ease-out,cubic-bezier(0.16,1,0.3,1)) forwards;
}
.chamber-hint{
  font-size:clamp(.72rem,1.1vw,.9rem);
  letter-spacing:.08em;color:rgba(245,245,245,.55);margin:0;
}

/* ── The visitor's seat, when the visitor is a member (K8) ────────────────
   The emblem art is the same file either way — there is no second "lit"
   render of the visitor shield, and there does not need to be. A warm lift
   plus the chamber's own crimson is enough to say "this seat is taken, and
   it is yours." Art-swapping it to a genuinely filled shield is a separate
   asset job; this is not a placeholder for one, it stands on its own.

   Applied by js/chamber-hero.js from RWSession, never from a stored flag. */
.chamber-seat.is-member .chamber-seat-art img{
  filter:brightness(1.18) saturate(1.12)
         drop-shadow(0 0 10px rgba(192,57,43,.55));
}
.chamber-seat.is-member .chamber-seat-label{
  color:var(--rws-white,#F5F5F5);
}

/* ── Portrait ─────────────────────────────────────────────────────────────
   Swaps FOUR things together — plate, mask, seat set and wave origin. The
   seat set and origin are handled in JS off the same media query. */
@media (max-aspect-ratio:1/1){
  .chamber-stage{
    aspect-ratio:9/16;
    width:max(100vw, calc(100svh * 9 / 16));
  }
  /* Only the VIDEO toggles here now. The still plate is a <picture> and swaps
     itself off the same media query — see the note beside it above. Adding an
     img rule back would do nothing except mislead the next reader. */
  video.chamber-plate--landscape{display:none;}
  video.chamber-plate--portrait{display:block;}
  .chamber-clip{
    -webkit-mask-image:url('../assets/roundtable/inlay-portrait-alpha.png');
            mask-image:url('../assets/roundtable/inlay-portrait-alpha.png');
  }
  .chamber-title{top:clamp(4.5rem,9vh,7rem);}
}

@media (prefers-reduced-motion:reduce){
  .chamber-stage *{animation:none !important;}
  .chamber-seat{opacity:1;transition:none;}
}
