/* 落地页动效层（7 站共用，品牌无关）
 *
 * 目标：把散在各处的手写时长收成一套**用途命名**的动效令牌，并补上几个真正缺的件。
 *
 * 判据（取自 beUI 官网 Motion Guide + 仓库 AGENTS.md 的 Motion conventions，
 * 2026-09-25 取证，https://beui.dev/docs/motion-patterns ｜ MIT）：
 *   ① 频次：一天点 100 次的不编排 —— 按压只做 120ms 即时反馈，不做回弹；
 *   ② 目的：说不出为什么动就删掉 —— 下面每一条都挂在"解释空间 / 确认输入 / 表达状态 / 软化变化"上；
 *   ③ 物理：入场 ease-out（立刻响应再安静落定）、屏上移动 ease-in-out；
 *      **界面动效默认 < 300ms**，更长的只留给解释性演示；
 *   ④ 回落：无障碍是一种动效状态 —— 命中 reduce 时**保留颜色与明暗反馈，只去掉位移/缩放/模糊**。
 *   另：只动 transform / opacity（入场期加 blur），blur ≤ 10px，不动任何布局属性。
 *
 * ⚠️ 本文件不得出现 Blade 插值、不得写死品牌色 —— 一律走 var()（与 landing.css 同契约）。
 *
 * ── 门控（三层，缺一不可，顺序就是优先级） ────────────────────────────────────
 *   1. `html.js`            ← 脚本可用的唯一证据。**所有"先藏起来再出现"的规则都必须挂在它下面**，
 *                             否则 landing-motion.js 一旦 404，hero 会永远空着（比不加动效更糟）。
 *   2. `html[data-motion=on]` ← 本模块的开关，由脚本自己打开。演示页用它做"改前/改后"对比。
 *   3. `prefers-reduced-motion` ← 本文件**整体**裹在 no-preference 里：命中 reduce 时本层完全不生效，
 *                             "reduce 下保留什么"交给 landing.css 那段 reduce 块与文件末尾两条 focus/颜色规则。
 */

@media (prefers-reduced-motion: no-preference) {

  :root {
    /* ── 动效令牌：按**用途**命名，不按数值命名（beUI 的 lib/ease.ts 同一路数） ── */
    --m-press: 120ms;                                  /* 按压反馈：100–160ms，即时 */
    --m-fast: 180ms;                                   /* tooltip / 小状态切换：125–200ms */
    --m-base: 240ms;                                   /* 下拉 / 内容替换：150–250ms */
    --m-enter: 300ms;                                  /* 入场：界面动效的上限 */
    --m-ease-enter: cubic-bezier(.16, 1, .3, 1);       /* 入场：立刻响应、安静落定 */
    --m-ease-move: cubic-bezier(.77, 0, .175, 1);      /* 屏上物体：自然加减速 */
  }

  /* ── ① 入场：`.reveal` 的时长与位移**已在 landing.css 本体改掉**（700ms/26px → 300ms/12px）──
     这里刻意**不再重写** `.reveal`，原因有两条，都很硬：
       ① 特异性：本模块的闸门 `html.js[data-motion="on"]` 让选择器变成 (0,2,2)，
          必然压过 `html.js .reveal.in` (0,2,1) —— 一写就把"已揭示"态压回去，
          结果**滚动揭示整条失效**（本模块第一版就踩了这个坑，实测出来的）。
       ② 无 JS 兜底：`.reveal` 的隐藏态本来就写在 landing.css 里，若把"改多快"放在本模块，
          脚本一旦 404，用户会继续吃到 0.7s 的旧时长 —— 改动就"看不见"。
     所以：动的定义留在 landing.css（单一所有者），本模块只负责**新加的件**。 */

  /* 首屏四件套不等滚动，直接错峰入场。
     为什么：hero 在首屏，IntersectionObserver 永远不给它"进入视口"的机会，
     不特判的话首屏反而是全页唯一没有入场编排的一段（而它是最该有的）。
     m-in 由 landing-motion.js 在第一帧之后挂上；无 JS / reduce / 脚本失败时这些规则不生效。 */
  html.js[data-motion="on"] .hero .eyebrow,
  html.js[data-motion="on"] .hero h1,
  html.js[data-motion="on"] .hero .sub,
  html.js[data-motion="on"] .hero .cta,
  html.js[data-motion="on"] .hero .hero-chips {
    opacity: 0;
    transform: translateY(10px);
    transition: opacity var(--m-enter) var(--m-ease-enter), transform var(--m-enter) var(--m-ease-enter);
  }
  html.js[data-motion="on"].m-in .hero .eyebrow,
  html.js[data-motion="on"].m-in .hero h1,
  html.js[data-motion="on"].m-in .hero .sub,
  html.js[data-motion="on"].m-in .hero .cta,
  html.js[data-motion="on"].m-in .hero .hero-chips {
    opacity: 1;
    transform: none;
  }
  /* 递进只加在"已入场"那一支上（60ms 一档，沿用 landing.css 的节奏） */
  html.js[data-motion="on"].m-in .hero h1 { transition-delay: 60ms; }
  html.js[data-motion="on"].m-in .hero .sub { transition-delay: 120ms; }
  html.js[data-motion="on"].m-in .hero .cta { transition-delay: 180ms; }
  html.js[data-motion="on"].m-in .hero .hero-chips { transition-delay: 240ms; }

  /* ── ② 错峰编排：同一排孩子 60ms 递进（沿用 landing.css 既有的 60ms，不发明第二套节奏） ── */
  html.js[data-motion="on"] .scenes .scene:nth-child(2),
  html.js[data-motion="on"] .stats .grid .stat:nth-child(2),
  html.js[data-motion="on"] .plans .plan:nth-child(2) { transition-delay: 60ms; }
  html.js[data-motion="on"] .scenes .scene:nth-child(3),
  html.js[data-motion="on"] .stats .grid .stat:nth-child(3),
  html.js[data-motion="on"] .plans .plan:nth-child(3) { transition-delay: 120ms; }
  html.js[data-motion="on"] .stats .grid .stat:nth-child(4),
  html.js[data-motion="on"] .plans .plan:nth-child(4) { transition-delay: 180ms; }

  /* ── ③ 数字滚动（beUI `Number Animation` 的最小内核） ──
     为什么动：stats 这四个数字是"我们有多大"的证据，滚一次让视线停在它上面。
     纪律：**只跑一次**、只有"一次性出现的读数"才用；实时变化的数字绝不滚动
     （读数是可信度，不是节目 —— 与 OPTIMIZE.md §6.24 同一条）。
     做法：JS 逐帧改 textContent；.num 用等宽数字，所以宽度不抖。
     reduce / 无 JS / 脚本失败 → 本段不生效，数字保持 HTML 里写的最终值。 */
  html.js[data-motion="on"] .stat .num[data-count-to] { font-variant-numeric: tabular-nums; }

  /* ── ④ 折叠面板：展开时"软化变化"（beUI `Accordion` 的克制版，不弹跳） ──
     为什么动：<details> 原生是瞬间跳开，页面高度骤然变化。
     做什么：只给内容淡入 + 4px 抬升，**不做高度动画**（高度动画动布局，违反"只动 transform/opacity"）。
     ⚠️ `[open]` 这一支是**兜底的正确性**，不是可选项：首次展开时浏览器刚把内容从 display:none 变成
        渲染，过渡不一定发生；只靠 JS 挂的 .m-in 一旦没跑到，内容就会永远停在 opacity:0（比不动效更糟）。
        所以：`[open]` 保证"展开就一定看得见"，`.m-in` 只负责"能过渡时过渡一下"。 */
  html.js[data-motion="on"] .faq details > p,
  html.js[data-motion="on"] .tech details > .steps,
  html.js[data-motion="on"] .tech details > .code {
    opacity: 0;
    transform: translateY(4px);
    transition: opacity var(--m-base) var(--m-ease-enter), transform var(--m-base) var(--m-ease-enter);
  }
  html.js[data-motion="on"] .faq details[open] > p,
  html.js[data-motion="on"] .tech details[open] > .steps,
  html.js[data-motion="on"] .tech details[open] > .code,
  html.js[data-motion="on"] .faq details > p.m-in,
  html.js[data-motion="on"] .tech details > .steps.m-in,
  html.js[data-motion="on"] .tech details > .code.m-in {
    opacity: 1;
    transform: none;
  }

  /* ── ⑤ 按压反馈：150ms 的 scale(.97) 收成规范里"立刻响应"那一档 ──
     为什么改：beUI 口径是按压 100–160ms 且按下要立刻有回应；.15s 已是上限，收到 120ms 后更"按得动"。
     ⚠️ 这里**替掉** landing.css:83 那行的 transition（本文件在它之后加载）；hover 抬升挪进 ⑦ 的指针门。 */
  html.js[data-motion="on"] .btn {
    transition: transform var(--m-press) var(--m-ease-enter), box-shadow var(--m-fast) var(--m-ease-enter);
  }
  html.js[data-motion="on"] .nav-cta {
    transition: box-shadow var(--m-fast) var(--m-ease-enter), transform var(--m-press) var(--m-ease-enter);
  }
  html.js[data-motion="on"] .nav-cta:active { transform: scale(.97); }
  html.js[data-motion="on"] .btn { -webkit-tap-highlight-color: transparent; }

  /* ── ⑥ .fn-btn：修掉 `transition: all`，只动真正会变的属性 ──
     为什么：`transition: all` 会把将来任何新增属性也一起动起来（不可预测、且可能意外动布局）；
     beUI 的 brand.md 把它明文列在 Don't 里，我们自己也一直在守"可测"这条。
     另补 beUI 的"状态切换"：激活态做一次极轻的确认，不是弹跳。 */
  html.js[data-motion="on"] .fn-btn {
    transition:
      color var(--m-fast) var(--m-ease-enter),
      border-color var(--m-fast) var(--m-ease-enter),
      background-color var(--m-fast) var(--m-ease-enter),
      box-shadow var(--m-fast) var(--m-ease-enter),
      transform var(--m-press) var(--m-ease-enter);
  }
  html.js[data-motion="on"] .fn-btn:active { transform: scale(.98); }

  /* ── ⑦ hover 只在**真指针设备**上挂（beUI `useHoverCapable` 的纯 CSS 版） ──
     为什么：触摸屏点一下会留下"幽灵 hover"直到点别处 —— 卡片一直悬在半空、扫光一直亮着。
     `(hover: hover) and (pointer: fine)` 是最能表达"有真指针"的判据。
     ⚠️ 这里必须重复选择器：landing.css 里 `.scene:hover` 的**特异性高于**
        `html.js[data-motion="on"] .scene` 之类，不重复就压不住。这是本文件唯一一处冗余，故意的。 */
  @media (hover: hover) and (pointer: fine) {
    html.js[data-motion="on"] .scene:hover { transform: translateY(-6px); border-color: rgba(var(--rgb-1), .4); }
    html.js[data-motion="on"] .plan:hover { transform: translateY(-5px); }
    html.js[data-motion="on"] .scene:hover::before { opacity: 1; }
    html.js[data-motion="on"] .scene::after,
    html.js[data-motion="on"] .plan::after {
      transition: opacity var(--m-base) var(--m-ease-enter), background-position 600ms var(--m-ease-enter);
    }
    html.js[data-motion="on"] .scene:hover::after,
    html.js[data-motion="on"] .plan:hover::after { opacity: 1; background-position: -20% 0; }
    html.js[data-motion="on"] nav a:hover { color: var(--text); }
    html.js[data-motion="on"] .fn-btn:hover { border-color: rgba(var(--rgb-1), .5); color: var(--text); }
    html.js[data-motion="on"] .btn-fire:hover { transform: translateY(-2px); }
  }
}

/* ── reduce 下的"保留意义"：这几条**刻意放在媒体查询外**，因为命中 reduce 时它们也必须生效 ──
   beUI：`Keep meaning. Remove travel.` —— 颜色/明暗反馈留着，否则用户不知道点到了；
   焦点环留着，否则键盘用户丢了位置（这条比动效重要得多）。
   ⚠️ 焦点环这里**必须带 `html.js[data-motion="on"]` 前缀提高特异性**：
      只写 `.faq summary:focus-visible`（0,2,0）压不过组件自身的 `summary { color: … }` 一类规则，
      实测出来 outline 会落到文本色（几乎看不见）。带上前缀后是 (0,3,2)，稳定生效。 */
html.js[data-motion="on"] .btn-ghost:hover,
html.js[data-motion="on"] .btn-ghost:focus-visible { border-color: var(--fire-1); color: var(--fire-3); }

html.js[data-motion="on"] .fn-btn:focus-visible,
html.js[data-motion="on"] .faq summary:focus-visible,
html.js[data-motion="on"] .tech summary:focus-visible,
html.js[data-motion="on"] .nav-cta:focus-visible,
html.js[data-motion="on"] .btn:focus-visible,
html.js[data-motion="on"] nav a:focus-visible {
  outline: 2px solid var(--fire-1);
  outline-offset: 2px;
  border-radius: 6px;
}
