/* ============================================================
   animations.css — the motion system
   1) whole-slide transitions (enter/exit)   .tin-* / .tout-*
   2) element reveals (staggered)            .reveal + [data-rv]
   3) ambient / looping motion               .amb-*
   4) SVG drawing + motion-path
   ============================================================ */

/* ---------------------------------------------------------------
   1) SLIDE TRANSITIONS — cinematic enter/exit, run concurrently
   --------------------------------------------------------------- */
.slide.is-anim { will-change: transform, opacity, filter, clip-path; }

/* enters */
.tin-fade    { animation: tinFade    .85s var(--ease-out) both; }
.tin-rise    { animation: tinRise    .9s  var(--ease-out) both; }
.tin-right   { animation: tinRight   .85s var(--ease-out) both; }
.tin-left    { animation: tinLeft    .85s var(--ease-out) both; }
.tin-zoom    { animation: tinZoom    .95s var(--ease-spring) both; }
.tin-punch   { animation: tinPunch   .8s  var(--ease-spring) both; }
.tin-blur    { animation: tinBlur    .95s var(--ease-out) both; }
.tin-wipe    { animation: tinWipe    .95s var(--ease-in-out) both; }
.tin-iris    { animation: tinIris    1s   var(--ease-out) both; }
.tin-swipe   { animation: tinSwipe   .95s var(--ease-in-out) both; }
.tin-flip    { animation: tinFlip    1s   var(--ease-out) both; transform-origin: center; }
.tin-cover   { animation: tinCover   .8s  var(--ease-out) both; }

@keyframes tinFade  { from { opacity:0; transform:scale(1.03); } to { opacity:1; transform:none; } }
@keyframes tinRise  { from { opacity:0; transform:translateY(7%) scale(.985); } to { opacity:1; transform:none; } }
@keyframes tinRight { from { opacity:.2; transform:translateX(100%); } to { opacity:1; transform:none; } }
@keyframes tinLeft  { from { opacity:.2; transform:translateX(-100%); } to { opacity:1; transform:none; } }
@keyframes tinZoom  { from { opacity:0; transform:scale(1.18); filter:blur(6px); } to { opacity:1; transform:none; filter:none; } }
@keyframes tinPunch { 0%{opacity:0; transform:scale(.82);} 60%{opacity:1; transform:scale(1.02);} 100%{transform:none;} }
@keyframes tinBlur  { from { opacity:0; filter:blur(26px) saturate(1.6); transform:scale(1.05);} to { opacity:1; filter:none; transform:none; } }
@keyframes tinWipe  { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes tinIris  { from { clip-path: circle(0% at 50% 54%); opacity:.4;} to { clip-path: circle(150% at 50% 54%); opacity:1;} }
@keyframes tinSwipe { from { clip-path: polygon(0 0,0 0,-30% 100%,-30% 100%); } to { clip-path: polygon(0 0,130% 0,100% 100%,0 100%); } }
@keyframes tinFlip  { from { opacity:0; transform:perspective(1600px) rotateY(24deg) scale(.94); } to { opacity:1; transform:none; } }
@keyframes tinCover { from { opacity:.3; transform:translateY(100%);} to { opacity:1; transform:none; } }

/* exits */
.tout-fade  { animation: toutFade  .7s  var(--ease-in-out) both; }
.tout-sink  { animation: toutSink  .7s  var(--ease-in-out) both; }
.tout-left  { animation: toutLeft  .75s var(--ease-in-out) both; }
.tout-right { animation: toutRight .75s var(--ease-in-out) both; }
.tout-zoom  { animation: toutZoom  .7s  var(--ease-in-out) both; }
.tout-blur  { animation: toutBlur  .7s  var(--ease-in-out) both; }
.tout-wipe  { animation: toutWipe  .75s var(--ease-in-out) both; }
.tout-scale { animation: toutScale .7s  var(--ease-in-out) both; }

@keyframes toutFade  { to { opacity:0; transform:scale(.985);} }
@keyframes toutSink  { to { opacity:0; transform:translateY(-6%) scale(.98);} }
@keyframes toutLeft  { to { opacity:0; transform:translateX(-16%) scale(.96);} }
@keyframes toutRight { to { opacity:0; transform:translateX(16%) scale(.96);} }
@keyframes toutZoom  { to { opacity:0; transform:scale(1.16); filter:blur(8px);} }
@keyframes toutBlur  { to { opacity:0; filter:blur(22px); transform:scale(1.02);} }
@keyframes toutWipe  { to { clip-path: inset(0 0 0 100%);} }
@keyframes toutScale { to { opacity:0; transform:scale(.8);} }

/* ---------------------------------------------------------------
   2) ELEMENT REVEALS — staggered, choreographed like motion graphics
   --------------------------------------------------------------- */
.slide.is-live .reveal {
  opacity: 0;
  animation-duration: .8s;
  animation-timing-function: var(--ease-out);
  animation-fill-mode: both;
  animation-delay: calc(var(--i, 0) * 85ms + var(--rvbase, 240ms));
}
.slide.is-live .reveal[data-rv="up"]    { animation-name: rvUp; }
.slide.is-live .reveal[data-rv="down"]  { animation-name: rvDown; }
.slide.is-live .reveal[data-rv="left"]  { animation-name: rvLeft; }
.slide.is-live .reveal[data-rv="right"] { animation-name: rvRight; }
.slide.is-live .reveal[data-rv="zoom"]  { animation-name: rvZoom; }
.slide.is-live .reveal[data-rv="pop"]   { animation-name: rvPop; animation-timing-function: var(--ease-spring); }
.slide.is-live .reveal[data-rv="blur"]  { animation-name: rvBlur; }
.slide.is-live .reveal[data-rv="rot"]   { animation-name: rvRot; animation-timing-function: var(--ease-spring); }
.slide.is-live .reveal[data-rv="mask"]  { animation-name: rvMask; }
.slide.is-live .reveal[data-rv="flip"]  { animation-name: rvFlip; }
/* default */
.slide.is-live .reveal:not([data-rv]) { animation-name: rvUp; }

@keyframes rvUp   { from { opacity:0; transform:translateY(26px);} to { opacity:1; transform:none;} }
@keyframes rvDown { from { opacity:0; transform:translateY(-24px);} to { opacity:1; transform:none;} }
@keyframes rvLeft { from { opacity:0; transform:translateX(-34px);} to { opacity:1; transform:none;} }
@keyframes rvRight{ from { opacity:0; transform:translateX(34px);} to { opacity:1; transform:none;} }
@keyframes rvZoom { from { opacity:0; transform:scale(.8);} to { opacity:1; transform:none;} }
@keyframes rvPop  { 0%{opacity:0; transform:scale(.5) translateY(10px);} 65%{opacity:1; transform:scale(1.06);} 100%{opacity:1; transform:none;} }
@keyframes rvBlur { from { opacity:0; filter:blur(14px); transform:scale(1.04);} to { opacity:1; filter:none; transform:none;} }
@keyframes rvRot  { from { opacity:0; transform:rotate(-8deg) translateY(22px) scale(.94);} to { opacity:1; transform:none;} }
@keyframes rvMask { from { opacity:1; clip-path: inset(0 100% 0 0);} to { opacity:1; clip-path: inset(0 0 0 0);} }
@keyframes rvFlip { from { opacity:0; transform:perspective(900px) rotateX(-70deg); transform-origin:center bottom;} to { opacity:1; transform:none;} }

/* ---------------------------------------------------------------
   3) AMBIENT LOOPS — the continuous "video" life of a slide
   --------------------------------------------------------------- */
.amb-float    { animation: ambFloat   7s  var(--ease-in-out) infinite; }
.amb-float-2  { animation: ambFloat2  9s  var(--ease-in-out) infinite; }
.amb-float-3  { animation: ambFloat3  11s var(--ease-in-out) infinite; }
.amb-drift    { animation: ambDrift   16s var(--ease-in-out) infinite; }
.amb-spin     { animation: spin       26s linear infinite; transform-origin:center; }
.amb-spin-rev { animation: spinRev    32s linear infinite; transform-origin:center; }
.amb-spin-fast{ animation: spin       11s linear infinite; transform-origin:center; }
.amb-pulse    { animation: ambPulse   4.5s var(--ease-in-out) infinite; }
.amb-breathe  { animation: ambBreathe 7s  var(--ease-in-out) infinite; }
.amb-sway     { animation: ambSway    8s  var(--ease-in-out) infinite; transform-origin:center bottom; }
.amb-orbit    { animation: ambOrbit   18s linear infinite; }
.amb-twinkle  { animation: ambTwinkle 3.2s var(--ease-in-out) infinite; }
.amb-shimmer  { background-size: 220% 100%; animation: ambShimmer 6s linear infinite; }
.amb-bob      { animation: ambBob     3.4s var(--ease-in-out) infinite; }
.amb-wave     { animation: ambWave    9s  var(--ease-in-out) infinite; }
.amb-gradient { background-size: 260% 260%; animation: ambGradient 14s var(--ease-in-out) infinite; }
.amb-conic    { animation: spin       24s linear infinite; }

@keyframes spin      { to { transform: rotate(360deg);} }
@keyframes spinRev   { to { transform: rotate(-360deg);} }
@keyframes ambFloat  { 0%,100%{transform:translateY(0);} 50%{transform:translateY(-16px);} }
@keyframes ambFloat2 { 0%,100%{transform:translate(0,0);} 50%{transform:translate(12px,-18px);} }
@keyframes ambFloat3 { 0%,100%{transform:translate(0,0);} 50%{transform:translate(-14px,-12px);} }
@keyframes ambDrift  { 0%,100%{transform:translate(0,0) scale(1);} 33%{transform:translate(22px,-16px) scale(1.05);} 66%{transform:translate(-18px,14px) scale(.97);} }
@keyframes ambPulse  { 0%,100%{transform:scale(1); opacity:.85;} 50%{transform:scale(1.09); opacity:1;} }
@keyframes ambBreathe{ 0%,100%{transform:scale(1); opacity:.6;} 50%{transform:scale(1.14); opacity:.95;} }
@keyframes ambSway   { 0%,100%{transform:rotate(-3deg);} 50%{transform:rotate(3deg);} }
@keyframes ambOrbit  { from{transform:rotate(0) translateX(var(--orb,60px)) rotate(0);} to{transform:rotate(360deg) translateX(var(--orb,60px)) rotate(-360deg);} }
@keyframes ambTwinkle{ 0%,100%{opacity:.25; transform:scale(.8);} 50%{opacity:1; transform:scale(1.15);} }
@keyframes ambShimmer{ to { background-position: 220% 0;} }
@keyframes ambBob    { 0%,100%{transform:translateY(0) rotate(0);} 50%{transform:translateY(-8px) rotate(2deg);} }
@keyframes ambWave   { 0%,100%{transform:translateX(0);} 50%{transform:translateX(-40px);} }
@keyframes ambGradient { 0%{background-position:0% 50%;} 50%{background-position:100% 50%;} 100%{background-position:0% 50%;} }

/* type-on caret */
.type-caret::after { content:"▋"; margin-left:2px; color: var(--a2); animation: caret 1s steps(1) infinite; }
@keyframes caret { 50% { opacity: 0; } }

/* progress ring fill (base/inline stroke-dashoffset is the target value) */
@keyframes ringFill { from { stroke-dashoffset: var(--circ); } }

/* ---------------------------------------------------------------
   4) SVG drawing + motion path
   --------------------------------------------------------------- */
.slide.is-live .draw {
  stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: dashDraw 1.6s var(--ease-out) forwards;
  animation-delay: calc(var(--i,0) * 120ms + 350ms);
}
@keyframes dashDraw { to { stroke-dashoffset: 0; } }

.slide.is-live .dot-run { offset-path: var(--path); animation: dotRun 4s linear infinite; }
@keyframes dotRun { to { offset-distance: 100%; } }

.slide.is-live .grow-line { transform-origin:left; animation: growX 1.1s var(--ease-out) both; animation-delay: calc(var(--i,0)*120ms + 450ms); }
.slide.is-live .grow-up   { transform-origin:bottom; animation: growY 1s var(--ease-out) both; animation-delay: calc(var(--i,0)*110ms + 500ms); }
@keyframes growX { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes growY { from { transform: scaleY(0); } to { transform: scaleY(1); } }

/* gradient text helper */
.grad-text {
  background: linear-gradient(115deg, var(--a1), var(--a2) 55%, var(--a3));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.grad-text.amb-gradient { background-size: 260% 260%; }

/* static slides (gallery thumbnails): freeze all motion at final state */
.slide.static [class*="amb-"] { animation: none !important; }
.slide.static .type-caret::after { animation: none; }
.slide.static .draw { stroke-dashoffset: 0 !important; animation: none !important; }
.slide.static .grow-line, .slide.static .grow-up { transform: none !important; animation: none !important; }

@media (prefers-reduced-motion: reduce) {
  .slide.is-live .reveal { opacity: 1 !important; }
  .amb-float,.amb-float-2,.amb-float-3,.amb-drift,.amb-spin,.amb-spin-rev,.amb-spin-fast,
  .amb-pulse,.amb-breathe,.amb-sway,.amb-orbit,.amb-twinkle,.amb-shimmer,.amb-bob,.amb-wave,
  .amb-gradient,.amb-conic { animation: none !important; }
  .slide.is-live .draw { stroke-dashoffset: 0 !important; animation: none !important; }
}
