/* cinema.css: the cinema layer for Blocks Against Boredom (contract in cinema.js).

   The same rules as the club site's design/cinema.css, in Blocks' tokens:
   - Everything that MOVES is gated on html[data-motion="cinematic"], which cinema.js sets from
     <head> before the body paints. Under html[data-motion="calm"] content is simply there.
   - Nothing hides content without that gate, so no-JS and calm never lose a word.
   - Load it AFTER styles.css / show.css. */

:root {
  --ease-cine: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-cine-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --dur-enter: 900ms;
  --dur-scene: 650ms;
  --reveal-step: 80ms;
  --reveal-distance: 28px;
}

/* ── Calm ──────────────────────────────────────────────────────────────────────────────────────
   Stillness by choice or by the device. Durations go to ~0 rather than `none` so code waiting on
   animationend / transitionend still hears it. The media query covers a page whose script never
   ran (no data-motion at all); with the script, the member's choice decides, so a member whose OS
   asks for reduced motion can still opt in to the show. */
html[data-motion='calm'] {
  scroll-behavior: auto;
}
html[data-motion='calm'] *,
html[data-motion='calm'] *::before,
html[data-motion='calm'] *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  animation-delay: 0ms !important;
  transition-duration: 0.01ms !important;
  transition-delay: 0ms !important;
  scroll-behavior: auto !important;
}
@media (prefers-reduced-motion: reduce) {
  html:not([data-motion]) *,
  html:not([data-motion]) *::before,
  html:not([data-motion]) *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── Entrances: data-reveal="up|fade|blur|scale|left|right|wipe" ─────────────────────────────── */
html[data-motion='cinematic']
  :is([data-reveal='up'], [data-reveal='fade'], [data-reveal='blur'], [data-reveal='scale'],
    [data-reveal='left'], [data-reveal='right'], [data-reveal='wipe']) {
  transition:
    opacity var(--dur-enter) var(--ease-cine),
    transform var(--dur-enter) var(--ease-cine),
    filter var(--dur-enter) var(--ease-cine),
    clip-path calc(var(--dur-enter) * 1.2) var(--ease-cine-in-out);
  transition-delay: calc(var(--reveal-i, 0) * var(--reveal-step));
}
html[data-motion='cinematic']
  :is([data-reveal='up'], [data-reveal='fade'], [data-reveal='blur'], [data-reveal='scale'],
    [data-reveal='left'], [data-reveal='right']):not([data-revealed]) {
  opacity: 0;
}
html[data-motion='cinematic'] [data-reveal='up']:not([data-revealed]) {
  transform: translate3d(0, var(--reveal-distance), 0);
}
html[data-motion='cinematic'] [data-reveal='blur']:not([data-revealed]) {
  filter: blur(14px);
  transform: scale(1.03);
}
html[data-motion='cinematic'] [data-reveal='scale']:not([data-revealed]) {
  transform: scale(0.94);
}
html[data-motion='cinematic'] [data-reveal='left']:not([data-revealed]) {
  transform: translate3d(calc(var(--reveal-distance) * -1.5), 0, 0);
}
html[data-motion='cinematic'] [data-reveal='right']:not([data-revealed]) {
  transform: translate3d(calc(var(--reveal-distance) * 1.5), 0, 0);
}
html[data-motion='cinematic'] [data-reveal='wipe']:not([data-revealed]) {
  clip-path: inset(0 100% 0 0);
}
html[data-motion='cinematic'] [data-reveal='wipe'][data-revealed] {
  clip-path: inset(0 0 0 0);
}

/* ── Split titles: BAB_CINEMA.split(el) ─────────────────────────────────────────────────────── */
.cine-split__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.cine-split__u,
.cine-split__word {
  display: inline-block;
}
.cine-split__word {
  white-space: nowrap;
}
html[data-motion='cinematic'] .cine-split[data-split-play='mount'] .cine-split__u,
html[data-motion='cinematic'] .cine-split[data-split-play='reveal'][data-revealed] .cine-split__u {
  animation: cine-rise 1.15s var(--ease-cine) both;
  animation-delay: calc(var(--split-delay, 0ms) + var(--i, 0) * var(--split-step, 70ms));
}
html[data-motion='cinematic'] .cine-split[data-split-play='reveal']:not([data-revealed]) .cine-split__u {
  opacity: 0;
}
@keyframes cine-rise {
  from {
    opacity: 0;
    transform: perspective(600px) translate3d(0, 0.6em, 0) rotateX(-40deg);
    filter: blur(10px);
  }
  to {
    opacity: 1;
    transform: none;
    filter: none;
  }
}

/* Count-ups (BAB_CINEMA.countUp): steady width while the digits roll. No `position`: a positioned
   child drops out of a `background-clip: text` parent's painted text. */
.cine-count {
  font-variant-numeric: tabular-nums;
}

/* ── Pointer light: data-spotlight + .cine-spot (fill, ::after) or .cine-spot-edge (border,
   ::before). Check the element's own pseudo-elements first; when it already uses one, put the
   class on a wrapper instead. ───────────────────────────────────────────────────────────────── */
.cine-spot,
.cine-spot-edge {
  position: relative;
  isolation: isolate;
}
.cine-spot::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(520px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in srgb, var(--spot-color, var(--cyan)) 16%, transparent), transparent 45%);
  transition: opacity var(--dur-scene) var(--ease-cine);
}
.cine-spot-edge::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(300px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in srgb, var(--spot-color, var(--cyan)) 85%, transparent), transparent 60%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  transition: opacity var(--dur-scene) var(--ease-cine);
}
html[data-motion='cinematic'] .cine-spot[data-pointer-in]::after,
html[data-motion='cinematic'] .cine-spot-edge[data-pointer-in]::before {
  opacity: 1;
}

/* ── Depth: data-tilt (owns `transform`; lift with the separate `translate` so they compose) ──── */
html[data-motion='cinematic'] [data-tilt] {
  transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transform-style: preserve-3d;
  transition: transform 700ms var(--ease-cine);
}
html[data-motion='cinematic'] [data-tilt][data-pointer-in] {
  transition-duration: 140ms;
}
.cine-glare,
.cine-holo {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-scene) var(--ease-cine);
}
.cine-glare {
  background: radial-gradient(circle at var(--gx, 50%) var(--gy, 50%),
    color-mix(in srgb, var(--ink, #fff) 26%, transparent), transparent 55%);
  mix-blend-mode: soft-light;
}
.cine-holo {
  background:
    repeating-linear-gradient(115deg, #ff6ec4 0%, #ffd36e 8%, #7dff9b 16%, #6ee7ff 24%, #a78bfa 32%, #ff6ec4 40%),
    radial-gradient(circle at var(--gx, 50%) var(--gy, 50%), #ffffff 0%, transparent 60%);
  background-size: 300% 300%, 100% 100%;
  background-position: var(--gx, 50%) var(--gy, 50%), center;
  background-blend-mode: overlay;
  mix-blend-mode: color-dodge;
  filter: saturate(1.2) brightness(0.9);
}
html[data-motion='cinematic'] [data-pointer-in] > .cine-glare {
  opacity: 1;
}
html[data-motion='cinematic'] [data-pointer-in] > .cine-holo {
  opacity: calc(0.18 + var(--gd, 0) * 0.32);
}

/* ── Magnetic: data-magnetic pulls toward the pointer (`translate`, composes with transform) ──── */
html[data-motion='cinematic'] [data-magnetic] {
  translate: var(--tx, 0px) var(--ty, 0px);
  transition: translate 420ms var(--ease-cine);
}
html[data-motion='cinematic'] [data-magnetic][data-pointer-in] {
  transition-duration: 90ms;
}

/* ── The night sky (<html data-cine-sky>) ────────────────────────────────────────────────────────
   Behind the stage lights and lasers (z -1) and above the page background. It fades in on its
   first frame; until then, and wherever the shader is refused, the page's own gradient stands. */
.cine-sky {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -2;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.8s var(--ease-cine);
}
html.has-shader-sky .cine-sky {
  opacity: 1;
}
/* During a cut the sky is lifted out of the page's snapshots and not drawn: the page's own
   gradient stands in for it until the cut ends. A named group paints ABOVE the root snapshot, so a
   drawn sky hid the whole stage for the length of every cut; and left in the root snapshot, a WebGL
   canvas can capture blank (white under a software rasteriser). */
html[data-vt] .cine-sky {
  view-transition-name: cine-sky;
}
::view-transition-group(cine-sky) {
  animation: none;
}
::view-transition-old(cine-sky),
::view-transition-new(cine-sky) {
  display: none;
}

/* ── Film grain (<html data-cine-grain>) ─────────────────────────────────────────────────────── */
.cine-grain {
  position: fixed;
  inset: -50%;
  z-index: 29; /* under the letterbox bars (z 30), over the stage */
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}
html[data-motion='calm'] .cine-grain {
  display: none;
}
@media (hover: hover) and (pointer: fine) {
  html[data-motion='cinematic'] .cine-grain {
    animation: cine-grain 0.9s steps(6) infinite;
  }
}
@keyframes cine-grain {
  0% { transform: translate3d(0, 0, 0); }
  20% { transform: translate3d(-4%, 3%, 0); }
  40% { transform: translate3d(3%, -5%, 0); }
  60% { transform: translate3d(-6%, -2%, 0); }
  80% { transform: translate3d(5%, 4%, 0); }
  100% { transform: translate3d(-2%, 6%, 0); }
}

/* ── Cuts: BAB_CINEMA.cut(update, origin) ────────────────────────────────────────────────────────
   The old screen dims and recedes; the new one opens as an iris from the pressed control
   (--vt-x / --vt-y). Persistent chrome holds still by carrying its own view-transition-name, and
   ONLY under html[data-vt] (set for the life of one cut): a standing name stops any glass inside
   the element from blurring the page behind it. */
::view-transition-old(root) {
  animation: cine-vt-out 460ms var(--ease-cine-in-out) both;
}
::view-transition-new(root) {
  animation: cine-vt-in 720ms var(--ease-cine) both;
}
@keyframes cine-vt-out {
  to {
    opacity: 0;
    transform: scale(0.985);
    filter: blur(6px) brightness(0.6);
  }
}
@keyframes cine-vt-in {
  from { clip-path: circle(0% at var(--vt-x, 50%) var(--vt-y, 50%)); }
  to { clip-path: circle(150% at var(--vt-x, 50%) var(--vt-y, 50%)); }
}

/* ── Small helpers ────────────────────────────────────────────────────────────────────────────── */
/* A sheen that crosses once when the element is revealed (logos, banners, title plates). */
.cine-sheen {
  position: relative;
  overflow: hidden;
}
.cine-sheen::after {
  content: '';
  position: absolute;
  inset: -20% auto -20% -60%;
  width: 45%;
  pointer-events: none;
  background: linear-gradient(100deg, transparent, color-mix(in srgb, var(--ink, #fff) 22%, transparent), transparent);
  transform: skewX(-18deg) translateX(-120%);
  opacity: 0;
}
html[data-motion='cinematic'] .cine-sheen[data-revealed]::after,
html[data-motion='cinematic'] [data-revealed] .cine-sheen::after,
html[data-motion='cinematic'] .cine-sheen[data-sheen='mount']::after {
  animation: cine-sheen 1.6s var(--ease-cine-in-out) 0.4s both;
}
@keyframes cine-sheen {
  0% { opacity: 0; transform: skewX(-18deg) translateX(-120%); }
  20% { opacity: 1; }
  100% { opacity: 0; transform: skewX(-18deg) translateX(420%); }
}

/* A headline that glows like a lit sign (--neon picks the colour). */
.cine-neon {
  text-shadow:
    0 0 18px color-mix(in srgb, var(--neon, var(--pink)) 55%, transparent),
    0 0 42px color-mix(in srgb, var(--neon, var(--pink)) 30%, transparent);
}
