/* ============================================
   货代小工具 — ⑤ 动效层 (Motion)
   纯 CSS，零新依赖。全部动效 ≤280ms、位移 ≤8px。
   动效只改 transform / opacity，不触发布局重排。
   ============================================ */

/* ---------- 关键帧 ---------- */
@keyframes fade-up {
  from { opacity: 0; transform: translate3d(0, 6px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes scale-in {
  from { opacity: 0; transform: scale(.92); }
  to   { opacity: 1; transform: scale(1); }
}

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

@keyframes shimmer {
  100% { transform: translateX(100%); }
}

@keyframes pulse-soft {
  0%, 100% { opacity: 1; }
  50%      { opacity: .55; }
}

@keyframes spin-dot {
  0%, 80%, 100% { opacity: .25; transform: scale(.7); }
  40%           { opacity: 1;   transform: scale(1); }
}

/* ---------- 入场动画 ---------- */
/* 由 common.js 的 initMotion() 添加 .is-entering 触发。
   这里用后代选择器而非直接子选择器：询价页的 .page-header 在 <form> 内、
   记录页的在 .records-page 内，直接子选择器会漏掉。 */
.is-entering .page-header {
  animation: fade-up var(--duration-slow) var(--ease-out) both;
}

.is-entering .dashboard-hero {
  animation: fade-up var(--duration-slow) var(--ease-out) both;
}

.is-entering .dashboard-section-title {
  animation: fade-up var(--duration-slow) var(--ease-out) 40ms both;
}

/* 宫格 / 列表逐项入场，每项延后 30ms，上限 8 项 */
.stagger > * {
  animation: fade-up var(--duration-slow) var(--ease-out) both;
}

.stagger > *:nth-child(1) { animation-delay: 0ms; }
.stagger > *:nth-child(2) { animation-delay: 30ms; }
.stagger > *:nth-child(3) { animation-delay: 60ms; }
.stagger > *:nth-child(4) { animation-delay: 90ms; }
.stagger > *:nth-child(5) { animation-delay: 120ms; }
.stagger > *:nth-child(6) { animation-delay: 150ms; }
.stagger > *:nth-child(7) { animation-delay: 180ms; }
.stagger > *:nth-child(n+8) { animation-delay: 210ms; }

/* 工作台左右两栏分别入场 */
.workbench > .workbench-rail {
  animation: fade-up var(--duration-slow) var(--ease-out) both;
}

.workbench > .workbench-main {
  animation: fade-up var(--duration-slow) var(--ease-out) 60ms both;
}

/* ---------- 弹窗内容入场 ---------- */
.modal.fade .modal-dialog {
  transition: transform var(--duration-slow) var(--ease-out),
              opacity var(--duration-base) var(--ease-out);
}

.modal.show .modal-dialog {
  transform: none;
}

/* 弹窗内容淡入，配合 Modal 的缩放 */
.modal.fade .modal-content > .modal-body {
  animation: fade-up var(--duration-base) var(--ease-out) both;
}

/* ---------- 状态徽章：发送中呼吸脉冲 ---------- */
.status-badge.status-sending {
  animation: pulse-soft 1.6s var(--ease-in-out) infinite;
}

.status-badge.status-sending::before {
  animation: pulse-soft 1.6s var(--ease-in-out) infinite;
}

/* ---------- 面板悬停微抬升 ---------- */
.workbench-rail > .card:hover,
.workbench-main > .card:hover {
  transform: translateY(-2px);
}

/* ---------- 表格行进入动画 ---------- */
/* 预留（阶段二用）：当前没有模板/JS 引用 .row-enter。
   阶段二改造数据表时，给 records.js 渲染出的 <tr> 加这个类即可获得逐行入场。 */
.row-enter {
  animation: fade-up var(--duration-base) var(--ease-out) both;
}

/* ---------- 加载点动画（三点跳动，用于异步提示） ---------- */
/* 预留（阶段二用）：给「加载中…」文案旁挂一个
   <span class="loading-dots"><span></span><span></span><span></span></span>。 */
.loading-dots {
  display: inline-flex;
  gap: 3px;
  vertical-align: middle;
  margin-right: .3rem;
}

.loading-dots > span {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background-color: currentColor;
  animation: spin-dot 1.2s var(--ease-in-out) infinite;
}

.loading-dots > span:nth-child(2) { animation-delay: .16s; }
.loading-dots > span:nth-child(3) { animation-delay: .32s; }

/* ---------- 滚动揭示（IntersectionObserver 挂载 .is-visible） ---------- */
.reveal {
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition: opacity var(--duration-slow) var(--ease-out),
              transform var(--duration-slow) var(--ease-out);
}

.reveal.is-visible {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* ============================================
   减弱动效总闸（无障碍，不可省略）
   系统开启「减弱动态效果」时，所有动效停止，
   页面功能完全不受影响。
   ============================================ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: .01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  /* 入场元素必须落回可见终态，不能停在 opacity:0。
     选择器与上面施加动画的规则一一对应。 */
  .is-entering .page-header,
  .is-entering .dashboard-hero,
  .is-entering .dashboard-section-title,
  .workbench > .workbench-rail,
  .workbench > .workbench-main,
  .stagger > *,
  .row-enter,
  .reveal {
    opacity: 1 !important;
    transform: none !important;
  }

  .skeleton::after {
    display: none;
  }

  .btn:active {
    transform: none;
  }
}
