/* ============================================================
   弹窗过渡统一层
   站内弹窗大多是 display:none ↔ display:flex 切换。display 不是
   可过渡属性，所以哪怕外层套了淡入动画，面板本体也是「瞬间到位」，
   关闭时更是直接消失——看起来就是硬闪。

   这里的做法：
    · 遮罩层：统一淡入，并给出 backdrop-filter 的渐变
    · 面板本体：统一「轻微上移 + 缩放」进场，曲线和站内其他动效一致
    · 用 animation 而不是 transition：display:none 的元素读不到
      transition 起始值（浏览器不会为「从无到有」的元素跑过渡），
      而 animation 在元素变为可见的那一帧就会开始播。

   覆盖层文件：index.html 删掉这行 <link> 即可完全回退。
   ============================================================ */

/* 统一的动效参数，改这里就能整站生效 */
:root{
  --mo-dur:.26s;
  --mo-dur-fast:.2s;
  --mo-ease:cubic-bezier(.16,1,.3,1);   /* 快出慢收，收尾不过冲 */
}

@keyframes moFade{ from{opacity:0} to{opacity:1} }
@keyframes moPanel{
  from{opacity:0;transform:translateY(12px) scale(.975)}
  to  {opacity:1;transform:none}
}
/* 贴边/悬浮类窗口（聊天、私信）不适合缩放，只做位移 */
@keyframes moRise{
  from{opacity:0;transform:translateY(16px)}
  to  {opacity:1;transform:none}
}
/* 从按钮下方展开的下拉 */
@keyframes moDrop{
  from{opacity:0;transform:translateY(-8px) scale(.97)}
  to  {opacity:1;transform:none}
}

/* ── 遮罩：统一淡入 ───────────────────────────────────── */
.game-modal.active,
.player-center-modal.active,
.challenge-modal.active,
.user-profile-overlay.show,
.tz-manage-modal.open,
.cd-modal.show,
.reset-modal.show,
.pure-overlay.active,
#nc-mask.open{
  animation:moFade var(--mo-dur-fast) ease both;
}

/* ── 面板本体：上移 + 缩放 ────────────────────────────── */
.game-modal.active > *:not(script),
.player-center-modal.active > *:not(script),
.challenge-modal.active > *:not(script),
.user-profile-overlay.show > *:not(script),
.tz-manage-modal.open .tz-manage-panel,
.cd-modal.show > *:not(script),
.reset-modal.show > *:not(script),
.sakura-confirm-overlay > *:not(script),
.chat-paste-overlay > *:not(script),
#nc-win{
  animation:moPanel var(--mo-dur) var(--mo-ease) both;
}

/* ── 悬浮窗：只上移，不缩放 ───────────────────────────── */
.im-win.open:not(.mo-out){
  animation:moRise var(--mo-dur) var(--mo-ease) both;
}

/* ── 下拉 / 小面板：从上方展开 ────────────────────────── */
.bell-panel.show,
.chat-emoji-panel.show,
.note-modal.open,
.calc-modal.open,
.cal-modal.open{
  animation:moDrop var(--mo-dur-fast) var(--mo-ease) both;
}

/* ── 关闭动画 ──────────────────────────────────────────
   JS 在移除 open/show 之前先加 .mo-out，等动画跑完再真正隐藏。
   由 modal-anim.js 自动接管，各模块自身代码不用改。 */
@keyframes moFadeOut{ from{opacity:1} to{opacity:0} }
@keyframes moPanelOut{
  from{opacity:1;transform:none}
  to  {opacity:0;transform:translateY(8px) scale(.985)}
}
.mo-out{
  animation:moFadeOut var(--mo-dur-fast) ease both !important;
  pointer-events:none !important;   /* 退场途中别再接收点击 */
}
/* 遮罩类弹窗：遮罩淡出的同时，里面的面板一起下沉。
   聊天室 / 私信不在此列——它们的背景（那层紫蓝渐变）画在窗口本体上，
   如果只让子元素淡出，就会剩一块纯背景色的空壳闪一下才消失。
   它们整体走 .mo-out 的淡出即可，内部不要再单独动。 */
.mo-out:not(.im-win) > *:not(script){
  animation:moPanelOut var(--mo-dur-fast) ease both !important;
}

/* ── 弹窗内部：内容异步到达时高度别跳 ──────────────────
   通知中心先渲染「加载中…」再填真实内容，窗口会先小后大。
   给个最小高度顶住，再让高度本身可过渡。 */
#nc-body{ min-height:min(380px, 52dvh); transition:none; }
#nc-win{ transition:height var(--mo-dur) var(--mo-ease); }

@media (prefers-reduced-motion:reduce){
  .game-modal.active, .player-center-modal.active, .challenge-modal.active,
  .user-profile-overlay.show, .tz-manage-modal.open, .cd-modal.show,
  .reset-modal.show, .pure-overlay.active, #nc-mask.open,
  .game-modal.active > *, .player-center-modal.active > *,
  .challenge-modal.active > *, .user-profile-overlay.show > *,
  .tz-manage-modal.open .tz-manage-panel, .cd-modal.show > *,
  .reset-modal.show > *, .sakura-confirm-overlay > *,
  .chat-paste-overlay > *, #nc-win,
  .im-win.open,
  .bell-panel.show, .chat-emoji-panel.show,
  .note-modal.open, .calc-modal.open, .cal-modal.open,
  .mo-out, .mo-out > *{
    animation:none !important;
  }
}
