/* ============================================================================
   PsyShift — Motion layer
   ----------------------------------------------------------------------------
   Loaded last. Nothing here changes what a page shows or how it lays out: it
   only animates what is already there. Every state that hides something waits
   for `html.fx`, which effects.js sets once it runs, so a page without
   JavaScript looks exactly as it did. Reduced motion — the system's setting or
   the account's (`[data-motion="reduced"]`) — turns all of it off: effects.js
   never sets `html.fx`, and the page transitions stand down below.
   Transforms and opacity only, so nothing here can move the layout.
   ========================================================================== */

/* ── Page transitions (View Transitions API, cross-document) ─────────────
   A soft cross-fade between pages, and a festival card's artwork growing into
   the festival page's hero. Browsers without it just navigate.             */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation: fx-page-out 220ms var(--ease) both; }
::view-transition-new(root) { animation: fx-page-in 360ms var(--ease-out) both; }
@keyframes fx-page-out { to { opacity: 0; transform: translateY(-6px); } }
@keyframes fx-page-in  { from { opacity: 0; transform: translateY(10px); } }

/* The festival's artwork: named on the card that was clicked (effects.js),
   and always on the festival page's hero. */
.fhero > .poster { view-transition-name: festival-art; }
::view-transition-group(festival-art) { animation-duration: 520ms; animation-timing-function: var(--ease-out); }
::view-transition-old(festival-art),
::view-transition-new(festival-art) { height: 100%; object-fit: cover; }

/* The chrome stays put while the page changes under it. */
.sidebar { view-transition-name: fx-sidebar; }
.topbar { view-transition-name: fx-topbar; }
.bottomnav { view-transition-name: fx-bottomnav; }
::view-transition-group(fx-sidebar),
::view-transition-group(fx-topbar),
::view-transition-group(fx-bottomnav) { animation: none; }

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}
:root[data-motion="reduced"]::view-transition-group(*),
:root[data-motion="reduced"]::view-transition-old(*),
:root[data-motion="reduced"]::view-transition-new(*) { animation: none !important; }

/* ── Reveal on scroll ─────────────────────────────────────────────────────
   Only for what starts below the fold (effects.js decides): what is on
   screen at load keeps the page's own entrance.                            */
html.fx .fx-reveal { opacity: 0; }
/* translate/scale, not transform: a card's tilt owns its transform. */
html.fx .fx-reveal.is-inview { opacity: 1; animation: fx-in 720ms var(--ease-out) var(--fx-delay, 0ms) both; }
@keyframes fx-in {
  from { opacity: 0; translate: 0 26px; scale: .98; }
  to   { opacity: 1; translate: none; scale: none; }
}

/* ── Counting numbers ─────────────────────────────────────────────────── */
fx-count { display: inline-block; font-variant-numeric: tabular-nums; }

/* ── Cards in relief (pointer devices) ────────────────────────────────────
   A tilt toward the pointer, a light that follows it, and the artwork
   drifting the other way. --rx/--ry/--mx/--my are written by effects.js.   */
@media (hover: hover) and (pointer: fine) {
  html.fx .fcard,
  html.fx .acard {
    transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(var(--lift, 0px));
    transition: transform 450ms var(--ease-out), box-shadow var(--dur-3) var(--ease), border-color var(--dur-3) var(--ease);
  }
  html.fx .fcard.is-tilting,
  html.fx .acard.is-tilting { --lift: -5px; transition: transform 120ms linear, box-shadow var(--dur-3) var(--ease), border-color var(--dur-3) var(--ease); }
  html.fx .fcard::after,
  html.fx .acard::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
    border-radius: inherit;
    pointer-events: none;
    background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%), rgba(155,132,255,.16), rgba(46,211,183,.05) 40%, transparent 65%);
    opacity: 0;
    transition: opacity var(--dur-3) var(--ease);
  }
  html.fx .fcard.is-tilting::after,
  html.fx .acard.is-tilting::after { opacity: 1; }
  html.fx .fcard.is-tilting .fcard__art .poster { translate: var(--px, 0px) var(--py, 0px); }
}

/* ── "I'm attending": the burst ───────────────────────────────────────── */
.fx-burst {
  position: fixed;
  z-index: 200;
  width: 0; height: 0;
  pointer-events: none;
}
.fx-burst__ring {
  position: absolute;
  left: -24px; top: -24px;
  width: 48px; height: 48px;
  border-radius: 50%;
  border: 2px solid var(--c-accent-bright);
  box-shadow: 0 0 18px rgba(124,92,255,.55);
  animation: fx-ring 620ms var(--ease-out) both;
}
@keyframes fx-ring { from { transform: scale(.3); opacity: 1; } to { transform: scale(2.4); opacity: 0; } }
.fx-burst__bit {
  position: absolute;
  left: -4px; top: -4px;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--fx-c, var(--c-accent-bright));
  animation: fx-bit var(--fx-t, 760ms) cubic-bezier(.15,.7,.3,1) both;
}
.fx-burst__bit--heart {
  width: 12px; height: 12px;
  left: -6px; top: -6px;
  background: none;
  color: var(--fx-c, var(--c-hot));
}
.fx-burst__bit--heart svg { display: block; width: 100%; height: 100%; fill: currentColor; }
@keyframes fx-bit {
  0%   { transform: translate(0, 0) scale(.4) rotate(0deg); opacity: 1; }
  70%  { opacity: 1; }
  100% { transform: translate(var(--fx-x), var(--fx-y)) scale(var(--fx-s, 1)) rotate(var(--fx-r, 0deg)); opacity: 0; }
}

/* ── Buttons: magnetism and a click ripple ────────────────────────────── */
html.fx .btn { overflow: hidden; }
@media (hover: hover) and (pointer: fine) {
  html.fx .btn--primary.btn--lg,
  html.fx .topbar__cta,
  html.fx .hero__cta .btn {
    translate: var(--fx-mx, 0px) var(--fx-my, 0px);
    transition: translate 260ms var(--ease-out), background var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease), color var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
  }
}
.fx-ripple {
  position: absolute;
  width: 12px; height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: 50%;
  background: rgba(255,255,255,.35);
  pointer-events: none;
  animation: fx-ripple 600ms var(--ease-out) both;
}
@keyframes fx-ripple { to { transform: scale(var(--fx-rs, 24)); opacity: 0; } }

/* ── Top bar: denser once the page scrolls ────────────────────────────── */
html.fx .topbar { transition: background var(--dur-3) var(--ease), box-shadow var(--dur-3) var(--ease), border-color var(--dur-3) var(--ease); }
html.fx .topbar.is-scrolled {
  background: linear-gradient(180deg, rgba(10,12,19,.97), rgba(10,12,19,.9));
  border-bottom-color: var(--c-line-strong);
  box-shadow: 0 10px 30px -12px rgba(0,0,0,.65);
}

/* ── Sidebar: a pill that glides to the item under the pointer ─────────── */
@media (min-width: 1024px) {
  html.fx .nav { position: relative; }
  html.fx .nav__item { z-index: 1; }
  html.fx .nav__item:hover { background: transparent; }
  .fx-navpill {
    position: absolute;
    left: var(--s-2); right: var(--s-2);
    top: 0;
    height: var(--fx-h, 44px);
    z-index: 0;
    border-radius: var(--r-md);
    background: rgba(255,255,255,.05);
    border: 1px solid rgba(155,132,255,.14);
    transform: translateY(var(--fx-y, 0px));
    opacity: 0;
    pointer-events: none;
    transition: transform 320ms var(--ease-out), height 320ms var(--ease-out), opacity var(--dur-2) var(--ease);
  }
  .fx-navpill.is-on { opacity: 1; }
}

/* ── Home hero: pointer parallax, a sweep of light, the title rising ───── */
html.fx .aurora__field--violet  { translate: calc(var(--fx-px, 0) * -38px) calc(var(--fx-py, 0) * -26px); }
html.fx .aurora__field--teal    { translate: calc(var(--fx-px, 0) * 30px)  calc(var(--fx-py, 0) * 22px); }
html.fx .aurora__field--magenta { translate: calc(var(--fx-px, 0) * -20px) calc(var(--fx-py, 0) * 30px); }
html.fx .aurora__field { transition: translate 1.2s var(--ease-out); }

html.fx .hero::before {
  translate: calc(var(--fx-px, 0) * 26px) calc(-50% + var(--fx-py, 0) * 20px);
  transition: translate 900ms var(--ease-out);
}
html.fx .hero__inner { translate: calc(var(--fx-px, 0) * -6px) calc(var(--fx-py, 0) * -4px); transition: translate 900ms var(--ease-out); }

html.fx .hero h1 em {
  background-image:
    linear-gradient(100deg, transparent 38%, rgba(255,255,255,.7) 50%, transparent 62%),
    linear-gradient(100deg, var(--c-accent-bright) 10%, var(--c-second) 90%);
  background-size: 260% 100%, 100% 100%;
  background-repeat: no-repeat;
  animation: fx-shine 7s var(--ease-in-out) 1.4s infinite;
}
@keyframes fx-shine {
  0%, 62% { background-position: 130% 0, 0 0; }
  100%    { background-position: -130% 0, 0 0; }
}

html.fx .fx-line { display: block; animation: fx-rise 900ms var(--ease-out) both; animation-delay: var(--fx-delay, 0ms); }
@keyframes fx-rise {
  from { opacity: 0; transform: translateY(.45em); clip-path: inset(0 0 100% 0); }
  to   { opacity: 1; transform: none; clip-path: inset(0 0 -20% 0); }
}

/* ── Festival page: the hero's artwork scrolls slower than the page ────── */
html.fx .fhero > .poster { translate: 0 var(--fx-scroll, 0px); scale: 1.08; }

/* ── Sign-in pages: the posters drift with the pointer ─────────────────── */
html.fx .authside__posters { translate: calc(var(--fx-px, 0) * -14px) calc(var(--fx-py, 0) * -10px); transition: translate 900ms var(--ease-out); }
html.fx .authside__poster { animation: reveal 800ms var(--ease-out) both; }
html.fx .authside__poster:nth-child(2) { animation-delay: 90ms; }
html.fx .authside__poster:nth-child(3) { animation-delay: 180ms; }
html.fx .authside__poster:nth-child(4) { animation-delay: 270ms; }
html.fx .authside__poster:nth-child(5) { animation-delay: 360ms; }
html.fx .authside__poster:nth-child(6) { animation-delay: 450ms; }
