/* ==========================================================================
   sanctum-gate.css — v2 (fixed)
   Fixes applied vs the original inline <style> injected by sanctum-gate.js:
   1. Seal is centered on its own axis (no flex-column drift from text length)
   2. letter-spacing on .sx-grant/.sx-sub now has matching text-indent
   3. 100dvh/100dvw instead of inset:0 (mobile Safari URL-bar fix)
   4. --sx-vp-x/--sx-vp-y calibrate the dolly + light burst to corridor.jpg's
      actual vanishing point so they stay converged as the plate scales
   5. 26 DOM twinkle divs removed — replaced by a single <canvas class="sx-fx">
   6. Real prefers-reduced-motion alternative (arms final state, no 1ms hack)
   7. Bidirectional shackle: opens on entry, snaps shut on exit
   ========================================================================== */

:root {
  --sx-midnight: #05030c;
  --sx-violet: #7c3aed;
  --sx-violet-soft: #a78bfa;
  --sx-gold: #f5d060;
  --sx-gold-deep: #d4a017;
  --sx-ink: #f1e4b8;

  --sx-ease-enter: cubic-bezier(.16, 1, .3, 1);
  --sx-ease-exit: cubic-bezier(.4, 0, 1, 1);
  --sx-mechanical: cubic-bezier(.9, .02, .6, 1.32);
  --sx-torque: cubic-bezier(.34, 1.56, .64, 1);
  --sx-latch: cubic-bezier(.7, -0.4, .3, 1.4);

  /* FIX 3: calibrate to corridor.jpg's real vanishing point.
     Measure once against your actual image; default assumes the
     horizon sits slightly above center, which is typical for a
     corridor/hallway photograph shot at eye level. */
  --sx-vp-x: 50%;
  --sx-vp-y: 47.5%;

  /* Independent centering axis for the seal (FIX 1) */
  --sx-center-x: 50vw;
  --sx-center-y: 50dvh;
  --sx-optical-y: -6px; /* shackle mass sits high; nudge up slightly */

  --sx-mark-size: clamp(104px, 13.5vmin, 208px);
}

#sxi, #sxi * , #sxi *::before, #sxi *::after { box-sizing: border-box; }

/* FIX 4: dvh/dvw instead of inset:0 */
#sxi {
  position: fixed;
  inset: 0;
  width: 100dvw;
  height: 100dvh;
  z-index: 2147483647;
  background: var(--sx-midnight);
  overflow: hidden;
  opacity: 1;
  transition: opacity 560ms ease;
  isolation: isolate;
}
@supports not (height: 100dvh) {
  #sxi { height: 100vh; width: 100vw; }
}
#sxi.sx-out { opacity: 0; pointer-events: none; }

/* Plate anchored to the calibrated vanishing point, not raw 50/50 */
#sxi .sx-plate {
  position: absolute;
  inset: -8%;
  background: var(--sx-img) center/cover no-repeat;
  background-position: var(--sx-vp-x) var(--sx-vp-y);
  transform-origin: var(--sx-vp-x) var(--sx-vp-y);
  transform: scale(1.03);
  image-rendering: high-quality;
  filter: saturate(1.22) contrast(1.16) brightness(1.1);
  will-change: transform;
}
#sxi.dir-enter .sx-plate { animation: sxDollyIn var(--sx-dolly-ms) var(--sx-ease-enter) forwards; }
#sxi.dir-exit  .sx-plate { animation: sxDollyOut var(--sx-dolly-ms) var(--sx-ease-exit)  forwards; }

#sxi .sx-bloom {
  position: absolute; inset: 0;
  background: radial-gradient(32% 25% at var(--sx-vp-x) var(--sx-vp-y),
              rgba(186,134,255,.6), rgba(139,92,246,.2) 46%, transparent 72%);
  mix-blend-mode: screen;
  animation: sxBloom 1200ms ease-in-out infinite;
}

/* FIX 5: single canvas replaces 26 DOM divs */
#sxi .sx-fx {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  mix-blend-mode: screen;
}

#sxi .sx-fog {
  position: absolute; inset: 0;
  background: radial-gradient(30% 24% at var(--sx-vp-x) var(--sx-vp-y),
              rgba(255,255,255,.22), transparent 68%);
  filter: blur(26px);
  mix-blend-mode: screen;
  animation: sxFog var(--sx-dolly-ms) ease-in forwards;
}

#sxi .sx-vig {
  position: absolute; inset: 0;
  box-shadow: inset 0 0 260px 90px rgba(5,3,12,.94);
  background: radial-gradient(48% 40% at var(--sx-vp-x) calc(var(--sx-vp-y) + 2%),
              rgba(201,162,39,.10), transparent 70%);
}

#sxi .sx-scrim {
  position: absolute;
  left: var(--sx-vp-x); top: var(--sx-vp-y);
  width: min(76vmin, 720px); height: min(60vmin, 560px);
  transform: translate3d(-50%, -50%, 0);
  background: radial-gradient(58% 58% at 50% 50%,
              rgba(5,3,12,.88), rgba(5,3,12,.5) 56%, transparent 82%);
  filter: blur(12px);
  pointer-events: none;
}

/* --- FIX 1: seal on its own absolutely-centered axis, no flex column --- */
#sxi .sx-stage {
  position: fixed;
  inset: auto;
  left: calc(var(--sx-center-x));
  top: calc(var(--sx-center-y) + var(--sx-optical-y));
  transform: translate3d(-50%, -50%, 0);
  width: min(92vw, 760px);
  display: block;         /* not flex — kills the gap-based drift */
  text-align: center;
  contain: layout paint;
}

#sxi .sx-mark {
  position: relative;
  margin: 0 auto;
  width: var(--sx-mark-size);
  height: var(--sx-mark-size);
  opacity: 0;
  transform: scale(.5) rotate(0deg);
  filter: blur(14px) drop-shadow(0 0 30px rgba(201,162,39,.8));
  animation: sxUnlock var(--sx-sigil-grant-ms) var(--sx-mechanical) var(--sx-hall-ms) forwards;
}
#sxi .sx-mark svg { width: 100%; height: 100%; display: block; overflow: visible; }
#sxi .sx-mark .sx-ring {
  transform-origin: 50% 50%;
  animation: sxSpinCCW var(--sx-sigil-grant-ms) cubic-bezier(.3,.7,.2,1) var(--sx-hall-ms) forwards;
}
#sxi.dir-exit .sx-mark .sx-ring { animation-name: sxSpinCW; }

/* Shackle + body are separate elements so the lock can physically open/close */
#sxi .sx-shackle {
  transform-origin: 62px 50px;
  transition: none;
}
#sxi.dir-enter .sx-shackle { animation: sxShackleOpen 320ms var(--sx-latch) calc(var(--sx-hall-ms) + var(--sx-sigil-ms)) forwards; }
#sxi.dir-exit  .sx-shackle { animation: sxShackleClose 420ms var(--sx-torque) calc(var(--sx-hall-ms) + var(--sx-sigil-ms) - 200ms) forwards; }

/* --- FIX 2: text-indent matches letter-spacing so tracking centers correctly --- */
#sxi .sx-grant {
  margin: 20px auto 0;
  opacity: 0;
  font: 400 13px/1 ui-sans-serif, system-ui;
  letter-spacing: .58em;
  text-indent: .58em;        /* <-- the fix */
  text-transform: uppercase;
  text-align: center;
  color: var(--sx-ink);
  text-shadow: 0 0 18px rgba(201,162,39,.9);
  animation: sxGrant 700ms ease-out calc(var(--sx-hall-ms) + var(--sx-sigil-ms)) forwards;
}
#sxi.dir-exit .sx-grant { color: var(--sx-violet-soft); text-shadow: 0 0 18px rgba(124,58,237,.75); }

#sxi .sx-flash {
  position: absolute; inset: 0;
  background: radial-gradient(20% 18% at var(--sx-vp-x) var(--sx-vp-y),
              rgba(255,244,214,.95), rgba(201,162,39,.25) 42%, transparent 74%);
  opacity: 0;
  animation: sxFlash 620ms ease-out calc(var(--sx-hall-ms) + var(--sx-sigil-ms) - 260ms) forwards;
}
#sxi.dir-exit .sx-flash {
  background: radial-gradient(20% 18% at var(--sx-vp-x) var(--sx-vp-y),
              rgba(186,134,255,.85), rgba(124,58,237,.28) 42%, transparent 74%);
}

/* Skip affordance — WCAG 2.2.2 */
#sxi .sx-skip {
  position: absolute; right: 20px; bottom: 20px;
  z-index: 4;
  padding: 8px 14px;
  font: 400 10px/1 ui-monospace, "JetBrains Mono", monospace;
  letter-spacing: .16em; text-transform: uppercase;
  color: #A09BB8; background: rgba(10,8,20,.6);
  border: 1px solid rgba(167,139,250,.24); border-radius: 8px;
  cursor: pointer; opacity: 0;
  animation: sxSkipIn 240ms ease 700ms forwards;
}
#sxi .sx-skip:hover, #sxi .sx-skip:focus-visible { color: var(--sx-gold); border-color: var(--sx-gold-deep); }
#sxi .sx-skip:focus-visible { outline: 2px solid var(--sx-gold); outline-offset: 3px; }

/* Sound control — never autoplays without arming */
#sxi .sx-sound {
  position: absolute; left: 20px; bottom: 20px;
  z-index: 4;
  padding: 8px 14px;
  font: 400 10px/1 ui-monospace, "JetBrains Mono", monospace;
  letter-spacing: .14em; text-transform: uppercase;
  color: #A09BB8; background: rgba(10,8,20,.6);
  border: 1px solid rgba(167,139,250,.24); border-radius: 999px;
  cursor: pointer; opacity: .82;
}
#sxi .sx-sound:hover, #sxi .sx-sound:focus-visible { color: var(--sx-gold); border-color: var(--sx-gold-deep); }

/* ---------------- Keyframes ---------------- */
@keyframes sxDollyIn  { 0% { transform: scale(1.03); } 100% { transform: scale(1.34); } }
@keyframes sxDollyOut { 0% { transform: scale(1.34); } 100% { transform: scale(1.03); } }
@keyframes sxBloom { 0%,100% { opacity: .5; } 50% { opacity: 1; } }
@keyframes sxFog {
  0%   { opacity: .25; transform: translateY(8%) scale(1); }
  70%  { opacity: .9;  transform: translateY(-2%) scale(1.5); }
  100% { opacity: .35; transform: translateY(-6%) scale(1.9); }
}
@keyframes sxUnlock {
  0%   { opacity: 0; transform: scale(.5) rotate(0deg);   filter: blur(16px) drop-shadow(0 0 10px rgba(201,162,39,.4)); }
  45%  { opacity: 1; transform: scale(1.08) rotate(540deg); filter: blur(2px) drop-shadow(0 0 34px rgba(201,162,39,.95)); }
  72%  { transform: scale(1) rotate(430deg); filter: blur(0) drop-shadow(0 0 26px rgba(201,162,39,.9)); }
  100% { opacity: 1; transform: scale(1) rotate(450deg); filter: blur(0) drop-shadow(0 0 22px rgba(139,92,246,.7)); }
}
@keyframes sxSpinCCW { 0% { transform: rotate(0deg); } 45% { transform: rotate(-360deg); } 100% { transform: rotate(-450deg); } }
@keyframes sxSpinCW  { 0% { transform: rotate(0deg); } 45% { transform: rotate(360deg); }  100% { transform: rotate(450deg); } }
@keyframes sxGrant { 0% { opacity: 0; letter-spacing: .3em; } 100% { opacity: 1; letter-spacing: .58em; } }
@keyframes sxFlash { 0% { opacity: 0; } 35% { opacity: 1; } 100% { opacity: 0; } }
@keyframes sxSkipIn { to { opacity: .82; } }

@keyframes sxShackleOpen {
  0%   { transform: translate3d(0,0,0)     rotate(0deg);   stroke: var(--sx-violet-soft); }
  60%  { transform: translate3d(0,-11px,0) rotate(-31deg); stroke: var(--sx-gold); }
  100% { transform: translate3d(5px,-13px,0) rotate(25deg); stroke: var(--sx-gold); }
}
@keyframes sxShackleClose {
  0%   { transform: translate3d(5px,-13px,0) rotate(25deg); stroke: var(--sx-gold); }
  30%  { transform: translate3d(0,-11px,0)   rotate(-7deg); stroke: var(--sx-gold); }
  65%  { transform: translate3d(0,3px,0)     rotate(0deg);  stroke: var(--sx-violet-soft); }
  100% { transform: translate3d(0,0,0)       rotate(0deg);  stroke: var(--sx-violet-soft); }
}

@media (max-width: 480px) {
  :root { --sx-mark-size: clamp(88px, 30vw, 148px); }
  #sxi .sx-grant { font-size: 11px; letter-spacing: .38em; text-indent: .38em; }
}

/* FIX 6: a designed reduced-motion alternative, not a 1ms hack.
   Arms the resolved state directly and cross-fades instead of animating. */
@media (prefers-reduced-motion: reduce) {
  #sxi .sx-plate, #sxi .sx-bloom, #sxi .sx-fog, #sxi .sx-mark,
  #sxi .sx-mark .sx-ring, #sxi .sx-shackle, #sxi .sx-grant, #sxi .sx-flash {
    animation: none !important;
  }
  #sxi .sx-plate { transform: scale(var(--sx-reduced-scale, 1.15)); }
  #sxi .sx-mark  { opacity: 1; transform: scale(1) rotate(450deg); filter: none; }
  #sxi .sx-shackle {
    transform: var(--sx-reduced-shackle, translate3d(5px,-13px,0) rotate(25deg));
  }
  #sxi .sx-grant { opacity: 1; }
  #sxi .sx-fx { display: none; }
  #sxi { transition: opacity 200ms linear; }
}
