/* =========================================================
   «Пензенская открытка» — движение
   Хром: 100/150/200/300 мс, вход ease-out, выход ease-in (быстрее).
   Церемонии (штамп, монеты, уровень, район) — исключения слоя наград, см. DESIGN.md.
   Анимируются только transform и opacity.
   Как пользоваться: элементу ставится data-state="enter" при показе и data-state="exit"
   перед скрытием; по animationend движок ставит hidden. Esc обрабатывается сразу,
   не дожидаясь конца анимации выхода.
   ========================================================= */

@keyframes pz-spin { to { transform: rotate(360deg); } }

/* ---------- Базовые входы/выходы ---------- */
@keyframes pz-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pz-fade-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes pz-rise-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes pz-rise-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(8px); } }
@keyframes pz-sheet-in { from { transform: translateY(100%); } to { transform: none; } }
@keyframes pz-sheet-out { from { transform: none; } to { transform: translateY(100%); } }
@keyframes pz-pop-in { from { opacity: 0; transform: scale(0.98); } to { opacity: 1; transform: none; } }
@keyframes pz-pop-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(0.98); } }
@keyframes pz-drop-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
@keyframes pz-drop-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-8px); } }

/* затемнение экрана */
.pz-screen[data-state="enter"], .pz-ceremony[data-state="enter"] { animation: pz-fade-in var(--pz-d-200) var(--pz-ease-out) both; }
.pz-screen[data-state="exit"], .pz-ceremony[data-state="exit"] { animation: pz-fade-out var(--pz-d-150) var(--pz-ease-in) both; }
/* панель внутри экрана */
.pz-screen[data-state="enter"] .pz-panel { animation: pz-pop-in var(--pz-d-200) var(--pz-ease-out) both; }
.pz-screen[data-state="exit"] .pz-panel { animation: pz-pop-out var(--pz-d-150) var(--pz-ease-in) both; }

/* карточка места и диалог: снизу */
.pz-place[data-state="enter"] { animation: pz-rise-in var(--pz-d-200) var(--pz-ease-out) both; }
.pz-place[data-state="exit"] { animation: pz-rise-out var(--pz-d-150) var(--pz-ease-in) both; }
/* у диалога на десктопе transform = translateX(-50%), поэтому свои кадры */
@keyframes pz-dialog-in { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }
@keyframes pz-dialog-out { from { opacity: 1; transform: translate(-50%, 0); } to { opacity: 0; transform: translate(-50%, 8px); } }
.pz-dialog[data-state="enter"] { animation: pz-dialog-in var(--pz-d-200) var(--pz-ease-out) both; }
.pz-dialog[data-state="exit"] { animation: pz-dialog-out var(--pz-d-150) var(--pz-ease-in) both; }

/* тосты: сверху */
.pz-toast[data-state="enter"] { animation: pz-drop-in var(--pz-d-200) var(--pz-ease-out) both; }
.pz-toast[data-state="exit"] { animation: pz-drop-out var(--pz-d-150) var(--pz-ease-in) both; }

/* подсказка взаимодействия */
.pz-prompt[data-state="enter"] { animation: pz-fade-in var(--pz-d-150) var(--pz-ease-out) both; }
.pz-prompt[data-state="exit"] { animation: pz-fade-out var(--pz-d-100) var(--pz-ease-in) both; }

/* ступенчатое появление строк списка: ≤30 мс на строку, не больше 200 мс суммарно */
.pz-stagger > * { animation: pz-rise-in var(--pz-d-200) var(--pz-ease-out) both; animation-delay: calc(min(var(--i, 0), 6) * 30ms); }

/* полоса XP: ширину не анимируем — только scaleX вложенного слоя */
.pz-progress > span { transition: transform var(--pz-d-300) var(--pz-ease-out); }

/* ---------- Узкая ширина: листы выезжают снизу целиком ---------- */
@media (max-width: 767.98px) {
  .pz-place[data-state="enter"], .pz-dialog[data-state="enter"] { animation: pz-sheet-in var(--pz-d-300) var(--pz-ease-out) both; }
  .pz-place[data-state="exit"], .pz-dialog[data-state="exit"] { animation: pz-sheet-out var(--pz-d-200) var(--pz-ease-in) both; }
  .pz-screen[data-state="enter"] .pz-panel { animation: pz-sheet-in var(--pz-d-300) var(--pz-ease-out) both; }
  .pz-screen[data-state="exit"] .pz-panel { animation: pz-sheet-out var(--pz-d-200) var(--pz-ease-in) both; }
}

/* =========================================================
   Церемонии
   ========================================================= */

/* Штамп «шлёп» (450 мс): штемпель падает сверху, оттиск проявляется, бумага чуть вздрагивает */
@keyframes pz-stamp-slap {
  0%   { opacity: 0; transform: rotate(var(--tilt, -8deg)) scale(1.5); }
  55%  { opacity: 1; transform: rotate(var(--tilt, -8deg)) scale(1); }
  100% { opacity: 1; transform: rotate(var(--tilt, -8deg)) scale(1); }
}
@keyframes pz-ink-in { 0%, 50% { opacity: 0; } 100% { opacity: 1; } }
@keyframes pz-paper-thud { 0%, 50% { transform: none; } 62% { transform: translateY(2px); } 100% { transform: none; } }
.pz-stamp.is-new { animation: pz-stamp-slap var(--pz-d-stamp) var(--pz-ease-stamp) both; }
.pz-stamp.is-new > * { animation: pz-ink-in var(--pz-d-stamp) linear both; }
.pz-slot.is-new { animation: pz-paper-thud var(--pz-d-stamp) linear both; }
/* надпись «Новый штамп» рядом (смысл не только движением) */
.pz-slot__new { position: absolute; top: var(--pz-s2); left: var(--pz-s2); font-size: var(--pz-text-meta); font-weight: var(--pz-w-semibold); color: var(--pz-stamp-2); }

/* Монетки (600 мс): каждая монета — .pz-coin-fly с переменными --dx --dy (путь до счётчика) и --i */
@keyframes pz-coin-arc {
  0%   { opacity: 0; transform: translate(0, 0) scale(0.6); }
  15%  { opacity: 1; transform: translate(calc(var(--dx) * 0.1), calc(var(--dy) * 0.1 - 24px)) scale(1); }
  100% { opacity: 1; transform: translate(var(--dx), var(--dy)) scale(0.7); }
}
.pz-coin-fly { animation: pz-coin-arc var(--pz-d-coins) var(--pz-ease-inout) both; animation-delay: calc(var(--i, 0) * 40ms); }
/* счётчик монет «тикает»: короткая смена прозрачности, без масштаба */
@keyframes pz-tick { 0% { opacity: 0.4; } 100% { opacity: 1; } }
.pz-coins.is-tick { animation: pz-tick var(--pz-d-150) var(--pz-ease-out); }

/* Новый уровень (600 мс): лента разворачивается, номер проявляется */
@keyframes pz-ribbon-unroll { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes pz-num-in { 0%, 40% { opacity: 0; transform: translateY(8px); } 100% { opacity: 1; transform: none; } }
.pz-levelup[data-state="enter"] { animation: pz-pop-in var(--pz-d-200) var(--pz-ease-out) both; }
.pz-levelup[data-state="enter"] .pz-levelup__ribbon { animation: pz-ribbon-unroll var(--pz-d-level) var(--pz-ease-out) both; transform-origin: left center; }
.pz-levelup[data-state="enter"] .pz-levelup__num { animation: pz-num-in var(--pz-d-level) var(--pz-ease-out) both; }
.pz-levelup[data-state="enter"] .pz-levelup__perks > li { animation: pz-rise-in var(--pz-d-200) var(--pz-ease-out) both; animation-delay: calc(400ms + var(--i, 0) * 30ms); }

/* Открытие района (700 мс): калька-маска уходит, граница прорисовывается */
@keyframes pz-veil-off { from { opacity: 1; } to { opacity: 0; } }
@keyframes pz-border-draw { from { stroke-dashoffset: var(--len, 2000); } to { stroke-dashoffset: 0; } }
.pz-district-veil.is-opening { animation: pz-veil-off var(--pz-d-district) var(--pz-ease-out) both; }
.pz-district-edge.is-opening { stroke-dasharray: var(--len, 2000); animation: pz-border-draw var(--pz-d-district) var(--pz-ease-out) both; }

/* Пин новой цели на карте: однократное появление, не бесконечная пульсация */
@keyframes pz-pin-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
.pz-map-pin.is-new { animation: pz-pin-in var(--pz-d-300) var(--pz-ease-out) both; transform-box: fill-box; transform-origin: 50% 100%; }

/* Скелет загрузки: мягкое мерцание прозрачностью (функциональный цикл) */
@keyframes pz-skel-breathe { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } }
.pz-skel { animation: pz-skel-breathe 1.6s ease-in-out infinite; }

/* =========================================================
   prefers-reduced-motion: только прозрачность ≤150 мс или мгновенно
   ========================================================= */
@media (prefers-reduced-motion: reduce) {
  .pz-screen[data-state], .pz-ceremony[data-state], .pz-place[data-state], .pz-dialog[data-state],
  .pz-toast[data-state], .pz-prompt[data-state], .pz-levelup[data-state] {
    animation-name: pz-fade-in !important; animation-duration: var(--pz-d-150) !important; animation-timing-function: linear !important;
    transition: none !important;
  }
  .pz-screen[data-state="exit"], .pz-ceremony[data-state="exit"], .pz-place[data-state="exit"], .pz-dialog[data-state="exit"],
  .pz-toast[data-state="exit"], .pz-prompt[data-state="exit"] { animation-name: pz-fade-out !important; animation-duration: var(--pz-d-100) !important; }
  .pz-screen[data-state] .pz-panel,
  .pz-levelup[data-state] .pz-levelup__ribbon,
  .pz-levelup[data-state] .pz-levelup__num,
  .pz-levelup[data-state] .pz-levelup__perks > li,
  .pz-stagger > *,
  .pz-slot.is-new,
  .pz-stamp.is-new > * { animation: none !important; }
  .pz-stamp.is-new { animation: pz-fade-in var(--pz-d-150) linear both !important; }
  .pz-coin-fly { display: none !important; }          /* монеты не летят: счёт меняется сразу, «+50» показывает тост */
  .pz-coins.is-tick { animation: none !important; }
  .pz-district-veil.is-opening { animation: pz-veil-off var(--pz-d-150) linear both !important; }
  .pz-district-edge.is-opening { animation: none !important; stroke-dasharray: none; }
  .pz-map-pin.is-new { animation: pz-fade-in var(--pz-d-150) linear both !important; }
  .pz-skel { animation: none !important; }
  .pz-btn[aria-busy="true"]::before { animation-duration: 2.4s; } /* функциональный индикатор: медленнее, но остаётся */
  .pz-progress > span, .pz-switch::after, .pz-tip, .pz-btn, .pz-icon-btn { transition: none !important; }
  .pz-carousel__track { scroll-behavior: auto; }
}

/* Ручной режим «Меньше движения» из настроек: класс .pz-reduce-motion на <html> — те же правила */
.pz-reduce-motion .pz-screen[data-state],
.pz-reduce-motion .pz-ceremony[data-state],
.pz-reduce-motion .pz-place[data-state],
.pz-reduce-motion .pz-dialog[data-state],
.pz-reduce-motion .pz-toast[data-state],
.pz-reduce-motion .pz-prompt[data-state],
.pz-reduce-motion .pz-levelup[data-state] {
    animation-name: pz-fade-in !important; animation-duration: var(--pz-d-150) !important; animation-timing-function: linear !important;
    transition: none !important;
  }
.pz-reduce-motion .pz-screen[data-state="exit"],
.pz-reduce-motion .pz-ceremony[data-state="exit"],
.pz-reduce-motion .pz-place[data-state="exit"],
.pz-reduce-motion .pz-dialog[data-state="exit"],
.pz-reduce-motion .pz-toast[data-state="exit"],
.pz-reduce-motion .pz-prompt[data-state="exit"] { animation-name: pz-fade-out !important; animation-duration: var(--pz-d-100) !important; }
.pz-reduce-motion .pz-screen[data-state] .pz-panel,
.pz-reduce-motion .pz-levelup[data-state] .pz-levelup__ribbon,
.pz-reduce-motion .pz-levelup[data-state] .pz-levelup__num,
.pz-reduce-motion .pz-levelup[data-state] .pz-levelup__perks > li,
.pz-reduce-motion .pz-stagger > *,
.pz-reduce-motion .pz-slot.is-new,
.pz-reduce-motion .pz-stamp.is-new > * { animation: none !important; }
.pz-reduce-motion .pz-stamp.is-new { animation: pz-fade-in var(--pz-d-150) linear both !important; }
.pz-reduce-motion .pz-coin-fly { display: none !important; }
.pz-reduce-motion «+50» показывает тост */
  .pz-coins.is-tick { animation: none !important; }
.pz-reduce-motion .pz-district-veil.is-opening { animation: pz-veil-off var(--pz-d-150) linear both !important; }
.pz-reduce-motion .pz-district-edge.is-opening { animation: none !important; stroke-dasharray: none; }
.pz-reduce-motion .pz-map-pin.is-new { animation: pz-fade-in var(--pz-d-150) linear both !important; }
.pz-reduce-motion .pz-skel { animation: none !important; }
.pz-reduce-motion .pz-btn[aria-busy="true"]::before { animation-duration: 2.4s; }
.pz-reduce-motion но остаётся */
  .pz-progress > span,
.pz-reduce-motion .pz-switch::after,
.pz-reduce-motion .pz-tip,
.pz-reduce-motion .pz-btn,
.pz-reduce-motion .pz-icon-btn { transition: none !important; }
.pz-reduce-motion .pz-carousel__track { scroll-behavior: auto; }

/* ландшафт телефона: диалог — панель справа без translateX(-50%) */
@media (orientation: landscape) and (max-height: 500px) {
  .pz-dialog[data-state="enter"] { animation: pz-fade-in var(--pz-d-200) var(--pz-ease-out) both; }
  .pz-dialog[data-state="exit"] { animation: pz-fade-out var(--pz-d-150) var(--pz-ease-in) both; }
}
