/**
 * oz-motion.css — the shared motion + polish layer for OCCUPY ZONE.
 *
 * WHY THIS EXISTS
 * Every page had its own ad-hoc transitions, so the product felt like several
 * sites stitched together. This is one vocabulary, included with one line, so
 * the website, the kiosk, the big screen and the player app all move the same.
 *
 * THE VOCABULARY COMES FROM THE ARENA, NOT FROM A TEMPLATE
 *   · reveal    — a short, low-travel rise. Content arrives; it does not float.
 *   · lock      — numerals settle like a reticle acquiring a target.
 *   · pulse     — anything genuinely live breathes. Nothing else does.
 *   · scan      — a single sweep across a loading surface (radio sweep).
 *   · press     — physical, immediate feedback. This is a venue tool; staff
 *                 need to know the tap registered.
 *
 * RULES
 *   · Motion is opt-in per element (a class), never a blanket * transition.
 *   · Only transform and opacity animate — they do not trigger layout.
 *   · prefers-reduced-motion disables all of it. Non-negotiable.
 */

/* ---------- tokens ---------- */
:root{
  --oz-fast:.16s;
  --oz-base:.34s;
  --oz-slow:.6s;
  --oz-ease:cubic-bezier(.22,.68,.24,1);      /* decisive, slight settle */
  --oz-ease-out:cubic-bezier(.16,1,.3,1);     /* long tail, for reveals   */
}

/* ---------- reveal on scroll ----------
   12px of travel, not 40. Content should look like it arrived, not flew in. */
.oz-rise{
  opacity:0;
  transform:translate3d(0,12px,0);
  transition:opacity var(--oz-base) var(--oz-ease-out),
             transform var(--oz-base) var(--oz-ease-out);
  will-change:opacity,transform;
}
.oz-rise.oz-in{opacity:1;transform:none}

/* stagger children so a grid resolves left-to-right instead of all at once */
.oz-stagger>*{
  opacity:0;
  transform:translate3d(0,10px,0);
  transition:opacity var(--oz-base) var(--oz-ease-out),
             transform var(--oz-base) var(--oz-ease-out);
}
.oz-stagger.oz-in>*{opacity:1;transform:none}
.oz-stagger.oz-in>*:nth-child(1){transition-delay:.00s}
.oz-stagger.oz-in>*:nth-child(2){transition-delay:.05s}
.oz-stagger.oz-in>*:nth-child(3){transition-delay:.10s}
.oz-stagger.oz-in>*:nth-child(4){transition-delay:.15s}
.oz-stagger.oz-in>*:nth-child(5){transition-delay:.20s}
.oz-stagger.oz-in>*:nth-child(6){transition-delay:.25s}
.oz-stagger.oz-in>*:nth-child(n+7){transition-delay:.30s}

/* ---------- lock-on ----------
   A number that just changed gets one crisp beat. Used by countUp(). */
@keyframes ozLock{
  0%{transform:scale(1.11);filter:brightness(1.5)}
  60%{transform:scale(.985)}
  100%{transform:scale(1);filter:brightness(1)}
}
.oz-lock{animation:ozLock .3s var(--oz-ease) both}

/* ---------- live pulse ----------
   Reserved for things that are genuinely live. Never decorative. */
@keyframes ozPulse{
  0%,100%{opacity:1;box-shadow:0 0 0 0 currentColor}
  55%{opacity:.62;box-shadow:0 0 0 7px transparent}
}
.oz-live{animation:ozPulse 1.5s ease-in-out infinite}

/* ---------- scan (loading) ----------
   A radio sweep across the surface while real data is on its way. Replaces
   the blank panels that used to sit there with no explanation. */
.oz-skel{
  position:relative;overflow:hidden;
  background:rgba(255,255,255,.05);
  border-radius:10px;min-height:14px;
}
.oz-skel::after{
  content:'';position:absolute;inset:0;transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,rgba(52,224,240,.16),transparent);
  animation:ozScan 1.15s ease-in-out infinite;
}
@keyframes ozScan{100%{transform:translateX(100%)}}
.oz-skel.t{height:13px;margin:7px 0;border-radius:6px}
.oz-skel.t.w60{width:60%}.oz-skel.t.w40{width:40%}.oz-skel.t.w80{width:80%}

/* ---------- press feedback ---------- */
.oz-press{transition:transform var(--oz-fast) var(--oz-ease),
                     filter var(--oz-fast) var(--oz-ease)}
.oz-press:active{transform:scale(.972)}
.oz-press:hover{filter:brightness(1.07)}

/* lift for cards that are actually clickable */
.oz-lift{transition:transform var(--oz-base) var(--oz-ease),
                    border-color var(--oz-base) var(--oz-ease),
                    box-shadow var(--oz-base) var(--oz-ease)}
.oz-lift:hover{transform:translateY(-3px)}

/* ---------- value flash ----------
   A score that went up glows green for a beat; one that dropped, red. */
@keyframes ozUp{0%{color:var(--green,#3BE0A0)}100%{color:inherit}}
@keyframes ozDown{0%{color:var(--red,#FF5A76)}100%{color:inherit}}
.oz-up{animation:ozUp .9s var(--oz-ease) both}
.oz-down{animation:ozDown .9s var(--oz-ease) both}

/* ---------- page entrance ----------
   One quiet settle on load so a page never snaps into place. */
@keyframes ozEnter{from{opacity:0;transform:translate3d(0,6px,0)}to{opacity:1;transform:none}}
.oz-enter{animation:ozEnter var(--oz-base) var(--oz-ease-out) both}

/* ---------- focus, always visible ---------- */
.oz-press:focus-visible,.oz-lift:focus-visible{
  outline:2px solid var(--cyan,#34E0F0);outline-offset:3px;
}

/* ---------- the floor: motion is a preference, not a requirement ---------- */
@media (prefers-reduced-motion:reduce){
  .oz-rise,.oz-stagger>*{opacity:1!important;transform:none!important;transition:none!important}
  .oz-lock,.oz-live,.oz-up,.oz-down,.oz-enter{animation:none!important}
  .oz-skel::after{animation:none!important}
  .oz-press,.oz-lift{transition:none!important}
  .oz-press:active,.oz-lift:hover{transform:none!important}
}
