/* motion.css — 全站滚动动效（约定见 motion-readme.md v2.0）
   ═══════════════════════════════════════════════════════════════════════════
   改动前必读的三条安全约束（v2.0 核心，违反任意一条都会破坏现有实现）
   ───────────────────────────────────────────────────────────────────────────
   1) 初始隐藏态一律挂在 `.m-ready` 之下，由 js/motion.js 在拆分完成后加上。
      **绝不在静态 CSS 里写 opacity: 0 / visibility: hidden** —— 否则 JS 未加载 /
      被阻止 / 抛错时，内容会永久空白（含 SEO 与读屏器）。
      JS 失败 → 无 .m-ready → 内容直接可见 = 零风险降级。
      （与本项目既有的 .pmd-anim 模式一致）

   2) 位移一律用 CSS 独立变换属性 `translate` / `scale`，**绝不用 `transform`**。
      本项目全站已有大量元素用 transform 做定位：translateX(-50%) 水平居中、
      translateY(-50%) 垂直居中、scaleX(-1) 图标镜像、轮播 track 的 translateX(Npx)…
      若用 transform 做入场，终态的 `transform: none` 会把这些定位一次性抹掉 → 元素跑位。
      `translate` / `scale` 与 `transform` 是彼此独立的属性、叠加生效，互不干扰。
      ⚠ 配套约定：元素自身若要额外变换，请一律用 `transform`（两者分工不重叠）。

   3) prefers-reduced-motion 下 js 直接不加 .m-ready（全程静态、零动效）；
      本文件另留一条 !important 兜底，应对「页面加载后用户中途切换系统设置」。
      注意 base.css 的全局规则只禁用了 transition/animation，**不会复位 opacity**，
      所以兜底必须显式写出来。
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  --m-ease: cubic-bezier(0.075, 0.82, 0.165, 1); /* easeOutCubic 系 */
  --m-dur: 0.7s;
  --m-dur-title: 0.5s;
  --m-dur-title-fade: 0.4s;
  --m-word-step: 60ms;
  --m-stagger-step: 100ms;
}

/* ── 滚动淡入（[data-m-anim]，AOS 风格） ────────────────────────────────── */

.m-ready [data-m-anim] {
  opacity: 0;
  transition:
    opacity var(--m-dur) ease,
    translate var(--m-dur) var(--m-ease),
    scale var(--m-dur) var(--m-ease);
  transition-delay: var(--m-delay, 0ms);
}

.m-ready [data-m-anim="fade-up-20"] {
  translate: 0 1.25rem; /* 20px */
}

.m-ready [data-m-anim="fade-up-50"] {
  translate: 0 3.125rem; /* 50px */
}

.m-ready [data-m-anim="fade-scale-80"] {
  scale: 0.8;
}

.m-ready [data-m-anim].in-view {
  opacity: 1;
  translate: none;
  scale: none;
}

/* ── 词级标题揭示（.m-anim-title） ──────────────────────────────────────── */

/* 拆分前整块隐藏，避免「原始标题 → 被拆成词」的中间态闪一下。
   由 js 在拆分完成后加 .is-ready 释放；reduced-motion / 无 JS 时 .m-ready 不出现，本规则不生效。 */
.m-ready .m-anim-title {
  visibility: hidden;
}

.m-ready .m-anim-title.is-ready {
  visibility: visible;
}

/* 每个 .m-line 恒为**一行** —— 由 js 在原始纯文本结构下用 Range 量出行归属后切分。
   块高必须等于一行高，遮罩才生效；否则窄屏折行后第一行的词上浮会盖到第二行（糊字）。
   切分对几何零影响：块高 = 行盒高，N 个单行块的高度和与一个 N 行块相同。

   `white-space: nowrap` 是必须的：切分后每个词都是元素，文字整形按元素边界分段，
   内容会比原始宽 1 个 LayoutUnit。块本身已经是「原始的一行」，若允许再折行，这
   1/64px 就会把最后一个词挤到下一行 —— 行数 +1、标题变高（实测 about 120 → 180）。
   溢出量仅 1/64px，远小于 `overflow-clip-margin: 0.14em`，所以不会被裁到。 */
.m-anim-title .m-line {
  display: block;
  white-space: nowrap;
  /* 防 descender（g/y/p）与斜体下伸部被裁。
     ⚠ 不用 v1.0 的 `padding-bottom: .12em + margin-bottom: -.12em` —— 在块模型下
     最后一行的 padding 不会被抵消（其 margin 会折叠出父盒），标题盒会凭空高出
     0.12em（48px 字号 ≈ 5.8px），直接推动其后所有内容。
     `overflow-clip-margin` 只扩大裁切范围、**对布局零影响**，是正确工具。
     不支持该属性的浏览器退化为按 padding box 裁切，仅可能轻微裁到 descender，不会破坏布局。 */
  overflow: hidden;              /* 回退 */
  overflow: clip;                /* 支持时改用 clip（可与 overflow-clip-margin 配合） */
  overflow-clip-margin: 0.14em;
}

.m-anim-title .m-word {
  display: inline-block;
  translate: 0 110%;
  opacity: 0;
  transition:
    translate var(--m-dur-title) var(--m-ease),
    opacity var(--m-dur-title-fade) ease;
  transition-delay: calc(min(var(--wi, 0), 8) * var(--m-word-step));
}

.m-anim-title.in-view .m-word {
  translate: none;
  opacity: 1;
}

/* ── 降级兜底（约束 3） ─────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .m-ready [data-m-anim],
  .m-anim-title .m-word {
    opacity: 1 !important;
    translate: none !important;
    scale: none !important;
  }

  .m-ready .m-anim-title {
    visibility: visible !important;
  }
}
