/* =====================================================================
   모션 토큰 + 공용 키프레임 — kiosk-page-motion 계약 (motion.js 와 세트)
     등장: 알파 0 → 1, y +10~20px 랜덤, expo-out, 1.4~1.6s 랜덤, 스태거 0.2s
     퇴장: 0.3s ease, 진행 반대(위)로 36px + 페이드
   타이밍·이징의 단일 소스. JS 에 ms 하드코딩 금지 (폴백 타임아웃만 예외).
   ?fx=off → body.fx-off 로 연출 전부 끔 (QA)
   ===================================================================== */

:root {
  --app-scale: 1;

  --dur-fast:  240ms;   /* 인터랙션 피드백 */
  --dur-exit:  300ms;   /* 화면 퇴장 */
  --dur-med:   420ms;   /* 오버레이 페이드 */
  --dur-slow:  640ms;   /* 화면 셸 진입 */

  --ease-expo:  cubic-bezier(.16, 1, .3, 1);       /* 등장 계약 expo-out */
  --ease-back:  cubic-bezier(.34, 1.4, .5, 1);     /* 살짝 튀는 팝 (정답 표시) */
  --ease-soft:  cubic-bezier(.22, .61, .36, 1);
  --ease-inout: cubic-bezier(.65, 0, .35, 1);
  --ease-exit:  ease;
}

/* ── 등장 (motion.js animateIn 이 --delay/--dur/--dy 를 요소마다 넣는다) ──
   ⚠ 여기에 opacity:0 을 두지 않는다 — 같은 요소에 다른 animation(예: .timer.is-hit 흔들림)이
      걸리면 objIn 이 통째로 밀려 요소가 영영 투명해진다(2026-09-18 실측: 감점 순간 타이머 카드 증발).
      진입 전 투명은 keyframes 의 from + fill-mode both(backwards)가 맡는다. */
.anim-in {
  animation: objIn var(--dur, 1.5s) var(--ease-expo) both;
  animation-delay: var(--delay, 0s);
  will-change: transform, opacity;
}
@keyframes objIn {
  from { opacity: 0; transform: translateY(var(--dy, 16px)); }
  to   { opacity: 1; transform: none; }
}

/* ── 퇴장 (motion.js fadeOutThen) ── */
.is-leaving {
  opacity: 0 !important;
  transform: translateY(-36px);
  transition: opacity var(--dur-exit) var(--ease-exit), transform var(--dur-exit) var(--ease-exit);
  pointer-events: none;
}

/* ── 유도 루프 (대기 유도에만, transform/opacity 만) ── */
.pulse { animation: promptPulse 2.4s var(--ease-inout) infinite; }
@keyframes promptPulse { 0%, 100% { opacity: .62; } 50% { opacity: 1; } }

.tap-ring { position: relative; }
.tap-ring::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  border: 4px solid currentColor;
  animation: tapRing 2.4s var(--ease-expo) infinite;
}
@keyframes tapRing {
  0%   { transform: scale(.9); opacity: .8; }
  70%  { transform: scale(1.18, 1.5); opacity: 0; }
  100% { transform: scale(1.18, 1.5); opacity: 0; }
}

.float-y { animation: floatY 5s var(--ease-inout) infinite; }
@keyframes floatY { 0%, 100% { transform: translateY(0) rotate(-4deg); } 50% { transform: translateY(-16px) rotate(-2deg); } }

/* ── QA: 연출 끔 ── */
body.fx-off .anim-in { animation: none; opacity: 1; }
body.fx-off .pulse, body.fx-off .float-y, body.fx-off .tap-ring::after { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .anim-in { animation-duration: 1ms; animation-delay: 0s; }
  .pulse, .float-y, .tap-ring::after { animation: none; }
}
