/* ==========================================================================
   motion.css — QikSwap 高级交互层（桌面网页版 + 移动网页版）
   --------------------------------------------------------------------------
   设计原则（改之前先读）：
   1. 只动 transform / opacity / box-shadow，不动 width/height/top/left，
      避免触发布局重排（中低端安卓机掉帧的第一来源）。
   2. 只碰「静态壳层」——页头、导航、弹窗、按钮。**不碰由轮询重渲染的列表**：
      shared-test-sync 会周期性套用状态投影，列表节点被重建时动画会重播，
      表现就是"页面一直在闪"。所以商品卡/订单/消息这些一律不加挂载动画。
   3. 时长分层：触摸 90ms / 浮层 220ms / 手机抽屉 260ms。超过 380ms 会显得卡。
   4. 所有效果必须能在系统"减弱动态效果"下退化成"直接到位"，见文件末尾。
   5. 本文件是**增量覆盖**，加载顺序在所有主题/页面样式之后，不修改既有文件。
   ========================================================================== */

:root {
  --qs-tap: 90ms;
  --qs-enter: 220ms;
  --qs-sheet: 260ms;
  --qs-ease-enter: cubic-bezier(.22, 1, .36, 1);
  --qs-ease-exit: cubic-bezier(.4, 0, 1, 1);
}

/* --------------------------------------------------------------------------
   1. 触摸反馈基线
   移动端默认的 300ms 灰块高亮比"没有反馈"更廉价，统一关掉，改用缩放反馈。
   -------------------------------------------------------------------------- */
button,
a,
[role="button"],
label.check,
.game-item,
.store-product-grid article {
  -webkit-tap-highlight-color: transparent;
}

button:not(:disabled) {
  transition: transform var(--qs-tap) var(--qs-ease-enter);
}

/* 大面积卡片按钮（整卡可点）缩放会让内容在边框里"缩一下"，很怪，单独处理 */
button:not(:disabled):not(.listing-main):active {
  transform: scale(.97);
}

.listing:active {
  transform: translateY(-1px) scale(.997);
}

/* --------------------------------------------------------------------------
   2. 键盘可达性：焦点环
   鼠标点击不出现，Tab 导航必现。这是"高级"里最容易被忽略、也最便宜的一项。
   -------------------------------------------------------------------------- */
:where(a, button, [tabindex], summary):focus-visible {
  outline: 2px solid var(--blue, #2357e8);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   3. 桌面导航：hover 下划线由左展开
   （第 3 项原本是"页头玻璃"，实测后**没有上线**，原因见文末"实测记录"）
   -------------------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) {
  .desktop-nav a:not(.active)::after,
  .desktop-nav button:not(.active)::after {
    position: absolute;
    right: 0;
    bottom: -1px;
    left: 0;
    height: 2px;
    content: "";
    background: currentColor;
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 200ms var(--qs-ease-enter);
  }

  .desktop-nav a:not(.active):hover::after,
  .desktop-nav button:not(.active):hover::after {
    transform: scaleX(1);
  }

  /* 桌面端按钮不做缩放（鼠标没有"按压"的物理感），改用极轻的位移 */
  button:not(:disabled):not(.listing-main):active {
    transform: translateY(1px);
  }
}

/* --------------------------------------------------------------------------
   5. 浮层：遮罩淡入 + 对话框上浮（桌面）/ 抽屉上滑（手机）
   .modal-backdrop 用 display:none ↔ flex 切换，动画只挂在 .show 上，
   每次打开重新触发；关闭走原生隐藏，不给"关不掉"留机会。
   -------------------------------------------------------------------------- */
@keyframes qs-backdrop-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes qs-dialog-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

@keyframes qs-sheet-in {
  from { opacity: 0; transform: translateY(34px); }
  to { opacity: 1; transform: none; }
}

@keyframes qs-rise-in {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}

.modal-backdrop.show {
  animation: qs-backdrop-in 180ms var(--qs-ease-enter) backwards;
}

.modal-backdrop.show > .modal {
  animation: qs-dialog-in var(--qs-enter) var(--qs-ease-enter) backwards;
}

/* --------------------------------------------------------------------------
   6. 首屏主文案上浮
   只给 .hero-copy：hero-media 多半是 LCP 元素，给它做淡入会拖慢 LCP。
   .hero-copy 是静态标记，不会被轮询重渲染，重播风险为零。
   -------------------------------------------------------------------------- */
.hero-copy {
  /* fill=backwards：动画结束后不保留填充，元素不会长期停在合成层上，
     否则文字从次像素渲染退化成灰度抗锯齿（看起来"糊一点"）。 */
  animation: qs-rise-in 420ms var(--qs-ease-enter) backwards;
}

/* --------------------------------------------------------------------------
   7. 手机端：抽屉式弹窗 + 底部导航按压
   注意：**故意不给 .mobile-nav 加 backdrop-filter**。
   实测（A/B 像素差分）：给这条通栏固定底栏加玻璃会让整页文字重采样，
   移动端变化像素 9.7%，且滚动时每帧都要重新模糊背后的内容——
   中低端安卓上这是"用视觉换帧率"。底栏保持实色。
   -------------------------------------------------------------------------- */
@media (max-width: 620px) {
  .modal-backdrop.show > .modal {
    animation-name: qs-sheet-in;
    animation-duration: var(--qs-sheet);
  }

  .mobile-nav a:active,
  .mobile-nav button:active {
    transform: scale(.94);
  }
}

/* --------------------------------------------------------------------------
   8. 系统开启"减弱动态效果"：全部退化为直接到位
   ui-polish.css 已有全局 duration:.01ms 的兜底，但那条不清 animation-delay，
   也不清 animation-fill-mode，会留下"延迟期间不可见 / 结束后停在首帧"的坑，
   所以这里把本文件的效果整体关掉。
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .modal-backdrop.show,
  .modal-backdrop.show > .modal,
  .hero-copy {
    animation: none !important;
  }

  button:not(:disabled),
  .listing,
  .mobile-nav a,
  .mobile-nav button,
  .desktop-nav a:not(.active)::after,
  .desktop-nav button:not(.active)::after {
    transition: none !important;
    transform: none !important;
  }
}

/* ==========================================================================
   实测记录（2026-11-15，别删，避免下次又试一遍）
   --------------------------------------------------------------------------
   方法：本地起静态服务，1440×1000 / 390×844 各截图，与"不加载 motion.css"
   的基准做逐像素差分，并用"同一配置连拍两次"验证渲染确定性。

   1) 首屏文案上浮（.hero-copy）      静止态差异 0 px
   2) 按钮/卡片按压 + 去 tap 高亮      静止态差异 0 px
   3) 桌面导航 hover 下划线            静止态差异 0 px
   4) 页头玻璃（alpha .82 + saturate） 未上线
      → 会让整页文字重新栅格化（次像素抗锯齿退化为灰度），且同一配置连拍
        两次差异达 11%，说明合成层在抖动。收益（一点点通透）不值这个代价。
   5) 底部导航玻璃                    未上线
      → 通栏固定 + backdrop-filter，移动端静止态差异 9.74%，且滚动时每帧
        重新模糊背后内容，中低端安卓是拿帧率换观感。
   6) 列表挂载入场动画                未上线
      → shared-test-sync 会周期性套用状态投影并重建列表节点，动画会反复重播，
        表现为"页面一直在闪"。商品卡/订单/消息一律不加挂载动画。

   结论：本文件只做"交互瞬间"的反馈，静止态与改造前逐像素一致（0 px）。
   要改任何视觉效果，先按上面方法重跑一遍差分。
   ========================================================================== */
