:root{
/* durations */
--dur-in:.55s; /* @kind other */ /* slide-in .45–.7s */
--dur-out:.45s; /* @kind other */
--dur-press:.15s; /* @kind other */
--stagger:.07s; /* @kind other */ /* same-kind elements: .06–.09s steps, from the edge */
--exit-wait:.5s; /* @kind other */ /* screen transitions: exit first, enter ~.5s later */
/* mechanical inertia — NOT ease-out */
--ease-clank:cubic-bezier(.4,1,.5,1); /* @kind other */
--ease-lever:cubic-bezier(.6,-.3,.3,1.4); /* @kind other */
}
/* ===== always-running (no screen may be fully still) ===== */
@keyframes spin{to{transform:rotate(360deg);}}
@keyframes spinR{to{transform:rotate(-360deg);}}
@keyframes wob{0%,100%{transform:rotate(-24deg);}45%{transform:rotate(31deg);}55%{transform:rotate(27deg);}65%{transform:rotate(30deg);}}
@keyframes blink{0%,55%{opacity:1;}60%,100%{opacity:.15;}}
@keyframes lampPulse{0%,100%{box-shadow:0 0 6px 2px rgba(227,52,47,.9),inset 0 0 3px rgba(255,255,255,.6);}50%{box-shadow:0 0 2px 0 rgba(227,52,47,.35),inset 0 0 2px rgba(255,255,255,.25);}}
@keyframes marq{0%,100%{opacity:1;text-shadow:0 0 14px rgba(84,255,138,.85),0 0 3px rgba(84,255,138,.9);}50%{opacity:.82;text-shadow:0 0 6px rgba(84,255,138,.5);}}
@keyframes steam{0%{transform:translateY(0) scale(.7);opacity:0;}25%{opacity:.35;}100%{transform:translateY(-46px) scale(1.5);opacity:0;}}
@keyframes fireFlick{0%,100%{opacity:1;scale:1;}50%{opacity:.7;scale:.94;}}
/* ===== entrances — fully off-screen start, overshoot at 70%, settle 85% =====
   Set --dx/--dy per element: the MINIMUM distance that puts element+strut off-screen.
   STACKING (支柱の描画順): animation/rotate on a wrapper creates a stacking context —
   neighboring struts pierce card bodies. Strutted card rows: explicit reverse z-index
   on wrappers (struts grow up → upper rows higher z; down → lower rows higher z);
   entry fill-mode `backwards`, never `both` (both keeps the context forever);
   rotate/shake on the card body, not the wrapper; no z-index:-1 on struts. */
@keyframes inL{0%{translate:calc(-1*var(--dx,2000px)) 0;}70%{translate:16px 0;}85%{translate:-6px 0;}100%{translate:0 0;}}
@keyframes inR{0%{translate:var(--dx,2000px) 0;}70%{translate:-16px 0;}85%{translate:6px 0;}100%{translate:0 0;}}
@keyframes inU{0%{translate:0 var(--dy,1200px);}70%{translate:0 -14px;}85%{translate:0 6px;}100%{translate:0 0;}}
@keyframes inD{0%{translate:0 calc(-1*var(--dy,1200px));}55%{translate:0 16px;}75%{translate:0 -8px;}90%{translate:0 3px;}100%{translate:0 0;}}
@keyframes inNav{0%{translate:0 800px;}70%{translate:0 -10px;}100%{translate:0 0;}}
/* depth-only exceptions: viewport keyvisual scale in/out, modal shade */
@keyframes inP{0%{scale:.9;opacity:0;}60%{scale:1.03;opacity:1;}100%{scale:1;opacity:1;}}
@keyframes outP{0%{scale:1;opacity:1;}100%{scale:.92;opacity:0;}}
@keyframes shadeIn{from{opacity:0;}to{opacity:1;}}
/* ===== exits — reverse of entrance, small recoil first ===== */
@keyframes outL{0%{translate:0 0;}18%{translate:18px 0;}100%{translate:calc(-1*var(--dx,2000px)) 0;}}
@keyframes outR{0%{translate:0 0;}18%{translate:-18px 0;}100%{translate:var(--dx,2000px) 0;}}
@keyframes outU{0%{translate:0 0;}18%{translate:0 -16px;}100%{translate:0 var(--dy,1200px);}}
@keyframes outD{0%{translate:0 0;}18%{translate:0 16px;}100%{translate:0 calc(-1*var(--dy,1200px));}}
/* ===== value changes ===== */
@keyframes flipIn{0%{transform:rotateX(90deg);opacity:0;}60%{transform:rotateX(-18deg);}100%{transform:rotateX(0);opacity:1;}}
@keyframes modalDrop{0%{transform:translateY(-1100px);}70%{transform:translateY(14px);}85%{transform:translateY(-6px);}100%{transform:translateY(0);}}
