/* ═══════════════════════════════════════════════════════════════
   v41.16 全站交互动效层（安全版）

   ⚠️ v41.15 的教训：不能用全局选择器（button/input/select）+ will-change，
      会创建合成层、盖掉页面原有样式，把画布布局搞崩。

   本版原则：
     1. 只对【明确的按钮类】生效，绝不用裸 button/input/select 选择器
     2. 不用 will-change（会创建合成层，破坏 transform 定位的画布）
     3. 不碰 position / overflow / z-index / display —— 布局相关一律不动
     4. 画布节点区（.canvas-host / .canvas-pan 内）整体排除，不受任何影响
   ═══════════════════════════════════════════════════════════════ */

/* ── 需要动效的按钮类（白名单，逐个点名，绝不用裸 button）────── */
.btn-primary, .btn-secondary, .nav-cta,
.msg-btn, .rc-btn, .acct-btn,
.sbp-genbtn, .sbp-minibtn, .sb-tbtn,
.cl-btn, .cv-lightbox-action, .lightbox-action,
.mlib-fbtn, .conv-batch-btn, .tb-btn,
.ui-btn {
  transition: transform .15s cubic-bezier(.2,.9,.3,1),
              filter .18s ease,
              box-shadow .2s ease;
}

/* 悬停：微提亮（不位移，避免影响任何布局） */
.btn-primary:not(:disabled):hover, .btn-secondary:not(:disabled):hover,
.nav-cta:hover, .msg-btn:not(:disabled):hover, .rc-btn:not(:disabled):hover,
.acct-btn:hover, .sbp-genbtn:not(:disabled):hover, .sbp-minibtn:hover,
.sb-tbtn:not(:disabled):hover, .cl-btn:not(:disabled):hover,
.cv-lightbox-action:hover, .lightbox-action:hover,
.mlib-fbtn:hover, .conv-batch-btn:hover, .tb-btn:not(:disabled):hover,
.ui-btn:not(:disabled):hover {
  filter: brightness(1.08);
}

/* 按下：回弹压缩 —— 这就是"手感"的来源 */
.btn-primary:not(:disabled):active, .btn-secondary:not(:disabled):active,
.nav-cta:active, .msg-btn:not(:disabled):active, .rc-btn:not(:disabled):active,
.acct-btn:active, .sbp-genbtn:not(:disabled):active, .sbp-minibtn:active,
.sb-tbtn:not(:disabled):active, .cl-btn:not(:disabled):active,
.cv-lightbox-action:active, .lightbox-action:active,
.mlib-fbtn:active, .conv-batch-btn:active, .tb-btn:not(:disabled):active,
.ui-btn:not(:disabled):active {
  transform: scale(.955);
  transition-duration: .07s;
}

/* ── 涟漪（js 只给白名单按钮注入）───────────────────────── */
.ui-ripple {
  position: absolute;
  border-radius: 50%;
  transform: scale(0);
  background: currentColor;
  opacity: .25;
  pointer-events: none;
  animation: uiRipple .55s cubic-bezier(.2,.7,.3,1) forwards;
}
@keyframes uiRipple { to { transform: scale(2.6); opacity: 0; } }

/* ── 按钮 loading / 成功 / 失败 ────────────────────────── */
.ui-loading { position: relative; color: transparent !important; pointer-events: none; }
.ui-loading > * { opacity: 0; }
.ui-loading::after {
  content: ''; position: absolute; inset: 0; margin: auto;
  width: 15px; height: 15px;
  border: 2px solid #fff; border-top-color: transparent;
  border-radius: 50%; opacity: .9;
  animation: uiSpin .6s linear infinite;
}
@keyframes uiSpin { to { transform: rotate(360deg); } }
.ui-ok  { animation: uiPopOk .5s ease; }
.ui-err { animation: uiShake .42s cubic-bezier(.36,.07,.19,.97); }
@keyframes uiPopOk {
  0%{transform:scale(1)} 35%{transform:scale(1.06)} 100%{transform:scale(1)}
}
@keyframes uiShake {
  10%,90%{transform:translateX(-2px)} 20%,80%{transform:translateX(3px)}
  30%,50%,70%{transform:translateX(-4px)} 40%,60%{transform:translateX(4px)}
}

/* ── Toast（独立层，不干扰任何页面元素）──────────────────── */
#ui-toast-wrap {
  position: fixed; top: 20px; left: 50%;
  transform: translateX(-50%);
  z-index: 999999;
  display: flex; flex-direction: column; gap: 10px; align-items: center;
  pointer-events: none;
}
.ui-toast {
  display: flex; align-items: center; gap: 10px;
  min-width: 200px; max-width: 90vw;
  padding: 12px 18px; border-radius: 12px;
  background: rgba(20,24,33,.94);
  border: 1px solid rgba(255,255,255,.10);
  backdrop-filter: blur(14px);
  color: #e8eaf0; font-size: 14px; font-weight: 500;
  box-shadow: 0 10px 40px rgba(0,0,0,.45);
  pointer-events: auto;
  animation: uiToastIn .34s cubic-bezier(.2,.9,.25,1.1) forwards;
  position: relative; overflow: hidden;
}
.ui-toast.out { animation: uiToastOut .26s ease forwards; }
.ui-toast-icon { font-size: 17px; line-height: 1; flex-shrink: 0; }
.ui-toast.ok   { border-color: rgba(34,197,94,.45); }
.ui-toast.err  { border-color: rgba(239,68,68,.45); }
.ui-toast.warn { border-color: rgba(245,158,11,.45); }
.ui-toast-bar {
  position: absolute; left: 0; bottom: 0; height: 2px;
  background: currentColor; opacity: .5;
  animation: uiToastBar linear forwards;
}
.ui-toast.ok .ui-toast-bar{color:#22c55e}
.ui-toast.err .ui-toast-bar{color:#ef4444}
.ui-toast.warn .ui-toast-bar{color:#f59e0b}
.ui-toast.info .ui-toast-bar{color:#60a5fa}
@keyframes uiToastIn { from{opacity:0;transform:translateY(-16px) scale(.94)} to{opacity:1;transform:none} }
@keyframes uiToastOut { to{opacity:0;transform:translateY(-10px) scale(.96)} }
@keyframes uiToastBar { from{width:100%} to{width:0} }

/* ── 弹窗进出场（js 主动加类，不自动侦测）──────────────── */
.ui-modal-in { animation: uiModalIn .3s cubic-bezier(.2,.9,.25,1.05) forwards; }
@keyframes uiModalIn { from{opacity:0;transform:translateY(14px) scale(.965)} to{opacity:1;transform:none} }

/* ── 可选：手动加类才生效的效果 ────────────────────────── */
.ui-fade-in { animation: uiFadeUp .34s cubic-bezier(.2,.9,.3,1) both; }
.ui-fade-out { animation: uiFadeOut .26s ease forwards; }
@keyframes uiFadeUp { from{opacity:0;transform:translateY(10px)} to{opacity:1;transform:none} }
@keyframes uiFadeOut { to{opacity:0;transform:scale(.94)} }
.ui-count-pop { animation: uiCountPop .5s cubic-bezier(.2,.9,.3,1); }
@keyframes uiCountPop { 0%{transform:scale(1)} 40%{transform:scale(1.16)} 100%{transform:scale(1)} }

/* ── 画布保护：画布节点区内一律不加任何动效 ──────────────── */
.canvas-host *, .canvas-pan *, .canvas-svg * {
  animation: none !important;
}
.canvas-host .ui-ripple, .canvas-pan .ui-ripple { display: none !important; }

/* ── 无障碍 ───────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}
