/* ============ evolution.css · 守护灵进化全屏动效 ============
   一次性播放的全屏动画。**参数化**：任何生肖 × 任意形态组合共用这一套骨架，
   只换主题色（青绿/金色）、文案与三档形态显示尺寸 —— 所以 12 只守护灵无需各自出资产。

   ── 为什么要给每个形态设不同显示尺寸（v167）────────────────────────
   素材的**构图体量顺序和形态顺序是反的**：幼体图是「占满画布的巨蛋」（主体高占画布
   0.756、填充率 0.325），成长体是「站立全身小老鼠」（0.745 / 0.315），完全体是
   「斗篷 + 星盘」（0.853 / 0.373）。数据实测见 .tmp/measure-subject.cjs。
   结果：旧版三档都用同一个 320px 容器 ⇒ 幼体视觉上**比成长体还大**，玩家读成
   「进化 = 退化」。现在按形态给基线尺寸 --evo-fit-*，强制呈现尺寸单调递增：
     幼体 .84（≈269px） → 成长体 1.00（320px） → 完全体 1.14（≈365px）
   加上动效里「收缩成光点 → 从光点长大」的过程，形成明确的「变大」方向感。

   ── 节奏设计（v168 全面放慢）──────────────────────────────────────
   多巴胺 = **长的预期 + 极短的爆发 + 长的回报**。v167 三段全都太短（蓄力收缩 0.4s、
   光点无停顿、长大 0.56s、爆完 1s 就结束）⇒ 玩家还没反应过来就播完了，像被快进。
   v168 把总时长 3.0s → 6.5s，重点是给「两个关键动作」留够时间，并在爆发前插一记静默。

   ── v169 修两个把「关键动作」吞掉的 bug + 力度加码 ──────────────────
   🔴 BUG-1「收缩成光点看不见」：evoFromLife 只在 0%/5%/20%/100% 写了 opacity，
   于是不透明度从 20%(0.76s) 起就一路线性掉到 3.78s 的 0 ⇒ 等 2.87s 收缩**开始**时
   图上只剩 0.30 不透明度、3.4s 只剩 0.08。玩家看到的是「淡出」，不是「缩小」。
   修法：收缩全程 opacity 保持 1，只在最后 3%（3.66~3.78s）归零。实测不透明度
   从 0.28 → 1.00（见 .tmp/diag-evo.cjs 的探针输出）。

   🔴 BUG-2「reduced-motion 下整段动效消失」：原来的 @media (prefers-reduced-motion)
   把 animation-duration 压到 .01ms，**但延迟被保留** —— .evo-from（延迟 0）瞬间跳到
   终帧 = opacity 0 + scale .22，.evo-to（延迟 3.82s）压根没开始 = 基础态 opacity 0。
   结果一张图都不显示，只有标题和光晕；JS 又按 EVO_TOTAL_REDUCED=1300 提前收场。
   修法：**删掉那个 @media 块**，改由 JS 解析「力度」（auto/full/soft），soft 也保留
   完整的收缩→长大叙事，只是去掉过曝/放射光/碎片/抖动这些强刺激层。

   ── v169 力度加码（用户要「震撼、怦然心动」）──────────────────────
     ・新形态早期成长段加 **RGB 色差偏移**（红/青双色 drop-shadow 错位）+ saturate 由
       0.25 爬到 1（由白显色），让「长大」这件事有材质感
     ・爆开瞬间加 **碎片飞散** .evo-shard（细长碎片高速外飞，与圆点星星区分）
     ・落位加 **地面冲击波** .evo-shock（扁平椭圆在地面扩散）
     ・镜头冲击改**双段**：爆开硬冲击 + 落位软冲击（同一个 evoPunch 的两簇关键帧）
     ・全屏过曝从 .62s 压到 .36s —— 原来 3.87~4.2s 整屏 55~92% 白，正好盖住新形态
       从 scale .04→.3 的早期成长

   总时长 6.5s（与 js/ui/evolution-fx.js 的 EVO_TOTAL 成对，改一个必须改另一个）：
     0.00s          遮罩淡入（.30s）
     0.19 ~ 0.76s   ① 旧形态由小升起就位（0.6s）
     0.76 ~ 2.15s   ② 悬浮呼吸 ×2 —— 「凝视现状」的铺垫（1.4s）
     2.20 ~ 2.87s   ③ 蓄力预兆：光晕收紧 + 形态下沉 + 亮度爬升（0.7s）
                    能量光点从四周向心汇聚（JS 在 2.28s 撒粒子）
     2.87 ~ 3.78s   ④ **收缩成光点**（0.92s）★全程 opacity 1 —— 看得见形体在变小
     3.46 ~ 3.66s   ⑤ **光点定格**：核心光球静止 0.20s（张力峰值，音效刻意留白）
     3.78 ~ 3.96s   ⑥ 闪白爆发 0.18s + 全屏过曝 0.36s ★过曝大幅缩短
     3.80s          ⑦ 碎片飞散（JS 撒）+ 镜头**硬**冲击
     3.82 ~ 5.02s   ⑧ **从光点长大**（1.2s）：色差偏移 → 由白显色 → 过冲 1.22 → 落位
     4.62s          ⑨ 落位：地面冲击波 + 镜头**软**冲击（四音重音）
     4.74s          ⑩ 星星炸开
     4.90 ~ 5.70s   ⑪ 高光横扫新形态
     4.92 ~ 结束    ⑫ **欣赏期**（1.5s）：旋转光环 + 上升光点 + 形态呼吸 + 标题脉动
     6.50s          自动结束（也可点击任意处跳过）

   层级：300（高于 auth 遮罩 80，低于 toast 10000） */

/* —— 结算幕布（v166「先动效 → 再结算」）——
   有进化时答完题先铺这块幕布，再叠全屏进化动效；等动效**开始淡出**的瞬间，
   结算卡片才在幕布的位置渲染（js/level/settlement.js 的 paint / onLeave 回调）。
   遮罩透明度归零与卡片入场重叠 ⇒ 揭幕感，而不是「先出成绩单再被动画盖住」。
   底色刻意与 .evo-overlay 完全一致，避免切换瞬间闪色。层级 60 = 关卡覆盖层同级。 */
.settle-curtain {
  position: fixed; inset: 0; z-index: 60;
  background: radial-gradient(circle at 50% 46%, rgba(26, 14, 48, .90) 0%, rgba(6, 3, 16, .97) 66%);
  opacity: 0; animation: settleCurtainIn .22s ease forwards;
}
@keyframes settleCurtainIn { to { opacity: 1; } }

.evo-overlay {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center;
  font-family: inherit;
  /* 遮罩压得够暗 + 轻微虚化：结算页是浅色卡片，遮罩太透会「花」掉、抢动效焦点 */
  background: radial-gradient(circle at 50% 46%, rgba(26, 14, 48, .90) 0%, rgba(6, 3, 16, .97) 66%);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  opacity: 0; transition: opacity .3s ease;
  overflow: hidden; cursor: pointer; user-select: none;
  -webkit-tap-highlight-color: transparent;
  /* 形态显示尺寸基线（由 JS 按 from/to 覆盖；这里给安全默认值） */
  --evo-fit-from: 1; --evo-fit-to: 1;
}
.evo-overlay.show { opacity: 1; }
.evo-overlay.leaving { opacity: 0; }

/* 主题：幼体→成长体 = 青绿（与成长值条同色）；成长体→完全体 = 金色（与满值同色） */
.evo-overlay.theme-growth {
  --evo-c1: #5eead4; --evo-c2: #14b8a6;
  --evo-glow: rgba(45, 212, 191, .92); --evo-soft: rgba(94, 234, 212, .35);
}
.evo-overlay.theme-complete {
  --evo-c1: #ffd866; --evo-c2: #fbbf24;
  --evo-glow: rgba(251, 191, 36, .95); --evo-soft: rgba(255, 216, 102, .42);
}

/* —— 光晕底盘（6.5s 全程，随各阶段收放）—— */
.evo-halo {
  position: absolute; width: 560px; height: 560px; border-radius: 50%;
  background: radial-gradient(circle, var(--evo-soft) 0%, transparent 62%);
  opacity: 0; animation: evoHalo 6.5s ease-in-out forwards;
}
@keyframes evoHalo {
  0%   { opacity: 0;   transform: scale(.5); }    /* 0.00s */
  11%  { opacity: .65; transform: scale(.82); }   /* 0.72s 随旧形态一起浮现 */
  21%  { opacity: .88; transform: scale(1.18); }  /* 1.37s 呼吸期最亮 */
  33%  { opacity: .5;  transform: scale(.92); }   /* 2.15s 蓄力：光晕收紧 */
  48%  { opacity: .7;  transform: scale(.6); }    /* 3.12s 随收缩一起坍缩 */
  55%  { opacity: 1;   transform: scale(.42); }   /* 3.58s 光点（光被吸进核里） */
  60%  { opacity: 1;   transform: scale(1.55); }  /* 3.90s 爆开 */
  72%  { opacity: .5;  transform: scale(1.3); }   /* 4.68s */
  100% { opacity: .45; transform: scale(1.18); }  /* 欣赏期余晖 */
}

/* —— 放射光线：爆开瞬间转出的「光芒万丈」，是「眼前一亮」的主力 ——
   拉长到 2.3s 并加了 66% 档 ⇒ 不是「闪一下就没」，而是持续转出的华丽感 */
.evo-rays {
  position: absolute; width: 1500px; height: 1500px; border-radius: 50%;
  background: repeating-conic-gradient(from 0deg,
    var(--evo-c1) 0deg 1.6deg, transparent 1.6deg 11deg);
  -webkit-mask-image: radial-gradient(circle, transparent 8%, #000 26%, transparent 56%);
  mask-image: radial-gradient(circle, transparent 8%, #000 26%, transparent 56%);
  opacity: 0; mix-blend-mode: screen; pointer-events: none;
  animation: evoRays 2.3s 3.80s ease-out forwards;
}
@keyframes evoRays {
  0%   { opacity: 0;   transform: scale(.16) rotate(-24deg); }
  13%  { opacity: .95; transform: scale(.66) rotate(-7deg); }
  38%  { opacity: .55; transform: scale(1.08) rotate(8deg); }
  66%  { opacity: .3;  transform: scale(1.42) rotate(22deg); }
  100% { opacity: 0;   transform: scale(1.85) rotate(38deg); }
}

/* —— 全屏过曝：闪白那一刻整屏刷白，冲击力的来源 ——
   v169 从 .62s 压到 .36s：原来 3.87~4.2s 整屏 55~92% 白，把新形态最早的成长段
   （scale .04 → .3）整段盖住了。现在 3.96s 就退干净，让「长大」全程可见。 */
.evo-whiteout {
  position: absolute; inset: 0; background: #fff; opacity: 0;
  pointer-events: none; animation: evoWhiteout .36s 3.80s ease-out forwards;
}
@keyframes evoWhiteout {
  0%   { opacity: 0; }
  16%  { opacity: .95; }
  40%  { opacity: .34; }
  100% { opacity: 0; }
}

/* —— 舞台：旧/新两张图叠放；镜头冲击（双段：爆开硬 + 落位软）——
   v169：一个动画里放两簇关键帧。3.80s 起第 0~36%（≈4.1s）是爆开硬冲击，
   70% 后（≈4.6s）第二簇是落位软冲击，整段到 4.96s 收回。 */
.evo-stage {
  position: relative; width: 320px; height: 320px;
  display: flex; align-items: center; justify-content: center;
  animation: evoPunch 1.16s 3.80s cubic-bezier(.3, 1.1, .3, 1);
}
@keyframes evoPunch {
  0%   { transform: scale(1)     translate(0, 0); }
  5%   { transform: scale(1.13)  translate(-9px, 6px); }
  11%  { transform: scale(1.03)  translate(8px, -4px); }
  17%  { transform: scale(1.07)  translate(-6px, 2px); }
  23%  { transform: scale(1.005) translate(4px, 0); }
  29%  { transform: scale(1.02)  translate(-2px, 0); }
  36%  { transform: scale(1)     translate(0, 0); }     /* ≈4.22s 硬冲击收 */
  68%  { transform: scale(1)     translate(0, 0); }     /* ≈4.59s 静 */
  74%  { transform: scale(1.05)  translate(0, 7px); }   /* ≈4.66s 落位软冲击 */
  80%  { transform: scale(.985)  translate(0, -1px); }
  100% { transform: scale(1)     translate(0, 0); }     /* 4.96s */
}
.evo-img {
  position: absolute; object-fit: contain;
  will-change: transform, opacity, filter;
}

/* 旧形态：浮现 → 呼吸 ×2 → 下沉蓄力 → **收缩成光点**（0.92s）
   🔴 v169 修 BUG-1：opacity 全程保持 1，只在最后 3% 归零。
   旧版只在 0/5/20/100% 写 opacity ⇒ 不透明度从 0.76s 起线性掉到 0，等到 2.87s
   收缩**开始**时只剩 0.30、3.4s 只剩 0.08 —— 玩家看到的是「淡出」而不是「缩小」。
   注：CSS 的 filter 在 transform **之前**应用，所以 drop-shadow 的 blur 会跟着 scale
   一起缩小 —— 末段的光点亮度只靠 filter 撑不起来，真正的「光点」由 .evo-core 这颗
   尺寸不受 scale 影响的亮球承担，两者在 3.46s 处交接。 */
.evo-from {
  width: calc(var(--evo-fit-from) * 100%);
  height: calc(var(--evo-fit-from) * 100%);
  animation: evoFromLife 3.78s ease-out forwards;
  filter: drop-shadow(0 0 26px var(--evo-soft));
}
@keyframes evoFromLife {
  /* ① 浮现：由小升起 */
  0%   { opacity: 0; transform: scale(.62) translateY(30px); filter: brightness(.7) blur(1px) drop-shadow(0 0 20px var(--evo-soft)); }
  5%   { opacity: 1; transform: scale(.92) translateY(8px); filter: brightness(.9) blur(.4px) drop-shadow(0 0 22px var(--evo-soft)); }
  20%  { opacity: 1; transform: scale(1)   translateY(0);    filter: brightness(1) blur(0) drop-shadow(0 0 26px var(--evo-soft)); }
  /* ② 呼吸 ×2（0.76 ~ 2.15s）：幅度递减，像深呼吸 —— 给玩家时间「看清现在的样子」 */
  28%  { opacity: 1; transform: scale(1.026) translateY(-8px); }
  36%  { opacity: 1; transform: scale(1)     translateY(0); }
  43%  { opacity: 1; transform: scale(1.02)  translateY(-6px); }
  50%  { opacity: 1; transform: scale(1)     translateY(0); }
  57%  { opacity: 1; transform: scale(1)     translateY(0); }
  /* ③ 蓄力预兆（2.20 ~ 2.87s）：下沉 + 亮度爬升 + 光晕收紧 —— 全程 opacity 1 */
  63%  { opacity: 1; transform: scale(.99) translateY(6px);  filter: brightness(1.6) blur(0)    drop-shadow(0 0 40px var(--evo-glow)); }
  70%  { opacity: 1; transform: scale(.96) translateY(9px);  filter: brightness(2.3) blur(.2px) drop-shadow(0 0 62px var(--evo-glow)); }
  /* ④ 收缩成光点（2.87 ~ 3.78s）：★opacity 保持 1 ⇒ 肉眼看得见形体在缩小
     269px → 237px → 165px → 118px → 81px → 塌进核心光球 */
  76%  { opacity: 1; transform: scale(.88) translateY(5px);  filter: brightness(3)   blur(.4px) drop-shadow(0 0 80px var(--evo-glow)); }
  84%  { opacity: 1; transform: scale(.62) rotate(-2deg);    filter: brightness(3.8) blur(.8px) drop-shadow(0 0 96px var(--evo-glow)); }
  92%  { opacity: 1; transform: scale(.44) rotate(2deg);     filter: brightness(4.8) blur(1.3px) drop-shadow(0 0 110px var(--evo-glow)); }
  97%  { opacity: 1; transform: scale(.3)  rotate(-1deg);    filter: brightness(5.6) blur(1.9px) drop-shadow(0 0 124px var(--evo-glow)); }
  100% { opacity: 0; transform: scale(.22) rotate(-1deg);    filter: brightness(6)   blur(2.4px) drop-shadow(0 0 130px var(--evo-glow)); }
}

/* 核心光球：旧形态坍缩进去的「光点」本体。
   它尺寸固定（88px、不受 transform scale 影响），所以能真正亮起来。
   3.46s 成型 → 3.66s **静止定格**（张力峰值，此刻音效刻意留白）→ 3.78s 炸开。 */
.evo-core {
  position: absolute; width: 88px; height: 88px; border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, var(--evo-c1) 42%, transparent 70%);
  opacity: 0; pointer-events: none;
  animation: evoCore 1.4s 2.42s ease-in forwards;
}
@keyframes evoCore {
  0%   { opacity: 0;   transform: scale(.06); }   /* 2.42s 蓄力期开始聚光 */
  22%  { opacity: .55; transform: scale(.28); }   /* 2.73s */
  45%  { opacity: .9;  transform: scale(.6); }    /* 3.05s */
  64%  { opacity: 1;   transform: scale(.92); }   /* 3.32s */
  74%  { opacity: 1;   transform: scale(1); }     /* 3.46s ★成型 */
  87%  { opacity: 1;   transform: scale(1.06); }  /* 3.64s ★定格（几乎不动） */
  91%  { opacity: 1;   transform: scale(1.2); }   /* 3.69s 蓄势微胀 */
  96%  { opacity: 1;   transform: scale(3.4); }   /* 3.76s ★炸开 */
  100% { opacity: 0;   transform: scale(14); }    /* 3.82s */
}

/* 闪白（爆发只有 0.18s —— 爆发必须极短，快感才靠「预期落差」出来） */
.evo-flash {
  position: absolute; width: 190%; height: 190%; border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, var(--evo-c1) 30%, transparent 62%);
  opacity: 0; animation: evoFlash .64s 3.78s ease-out forwards;
}
@keyframes evoFlash {
  0%   { opacity: 0;   transform: scale(.24); }
  16%  { opacity: 1;   transform: scale(.86); }
  44%  { opacity: .9;  transform: scale(1.4); }
  100% { opacity: 0;   transform: scale(2.9); }
}

/* 光爆环（v169 加到三圈制造层次：内圈快而细、中圈、外圈慢而粗） */
.evo-burst {
  position: absolute; width: 340px; height: 340px; border-radius: 50%;
  border: 5px solid var(--evo-c1); opacity: 0;
  box-shadow: 0 0 40px var(--evo-glow), inset 0 0 40px var(--evo-soft);
}
.evo-burst.b1 { animation: evoBurst .95s 3.88s cubic-bezier(.16, .9, .3, 1) forwards; }
.evo-burst.b2 { animation: evoBurst 1.15s 4.05s cubic-bezier(.16, .9, .3, 1) forwards; border-width: 2px; }
.evo-burst.b3 { animation: evoBurst 1.35s 4.22s cubic-bezier(.16, .9, .3, 1) forwards; border-width: 1.5px; opacity: .8; }
@keyframes evoBurst {
  0%   { opacity: 1;   transform: scale(.12); }
  60%  { opacity: .45; }
  100% { opacity: 0;   transform: scale(3.2); }
}

/* —— 地面冲击波（v169 新增）：落位瞬间在地面扩散的扁平椭圆 ——
   圆环（.evo-burst）是「炸开」，椭圆是「踩下去」。两者叠加才有重量感。 */
.evo-shock {
  position: absolute; left: 50%; top: calc(50% + 116px);
  width: 300px; height: 88px; margin-left: -150px; border-radius: 50%;
  border: 4px solid var(--evo-c1); opacity: 0; pointer-events: none;
  box-shadow: 0 0 34px var(--evo-glow), inset 0 0 26px var(--evo-soft);
  animation: evoShock .8s 4.62s cubic-bezier(.16, .9, .3, 1) forwards;
}
@keyframes evoShock {
  0%   { opacity: 0;    transform: scale(.18, .45); }
  12%  { opacity: .95;  transform: scale(.42, .6); }
  100% { opacity: 0;    transform: scale(2.7, 1.1); }
}

/* 新形态：**从光点长大**（3.82 ~ 5.02s，整整 1.2s）
   三个要点：
   ① 亮度跟着尺寸一起降（brightness 6 → 1），看得出「在成型」而不是「啪一下换图」
   ② **RGB 色差偏移**（v169 新增）：早期用红/青双色 drop-shadow 错位 + saturate .25，
      像镜头色散，视觉上「炸出来的东西还在晃」
   ③ 过冲 1.22 再回弹落位，最后停在自己的形态基线尺寸 --evo-fit-to 上 */
.evo-to {
  width: calc(var(--evo-fit-to) * 100%);
  height: calc(var(--evo-fit-to) * 100%);
  opacity: 0; animation: evoGrow 1.2s 3.82s cubic-bezier(.2, 1.3, .36, 1) forwards;
}
@keyframes evoGrow {
  0%   { opacity: 0;   transform: scale(.05) rotate(-18deg);
         filter: brightness(6) blur(2.8px) saturate(.25) drop-shadow(5px 0 rgba(255, 70, 70, .9)) drop-shadow(-5px 0 rgba(70, 215, 255, .9)); }
  7%   { opacity: .9;  transform: scale(.12) rotate(-15deg);
         filter: brightness(5) blur(2.2px) saturate(.35) drop-shadow(4px 0 rgba(255, 70, 70, .85)) drop-shadow(-4px 0 rgba(70, 215, 255, .85)); }
  18%  { opacity: 1;   transform: scale(.3)  rotate(-11deg);
         filter: brightness(4) blur(1.4px) saturate(.6) drop-shadow(3px 0 rgba(255, 70, 70, .7)) drop-shadow(-3px 0 rgba(70, 215, 255, .7)); }
  34%  { transform: scale(.56) rotate(-6deg);
         filter: brightness(2.8) blur(.7px) saturate(.85) drop-shadow(1.5px 0 rgba(255, 70, 70, .45)) drop-shadow(-1.5px 0 rgba(70, 215, 255, .45)); }
  52%  { transform: scale(.84) rotate(-2deg);
         filter: brightness(2) blur(.25px) saturate(1) drop-shadow(0 0 48px var(--evo-glow)); }
  68%  { transform: scale(1.22) rotate(3deg);
         filter: brightness(1.4) blur(0) saturate(1) drop-shadow(0 0 46px var(--evo-glow)); }
  80%  { transform: scale(.93) rotate(-1.5deg); }
  90%  { transform: scale(1.05) rotate(.5deg); }
  100% { opacity: 1;   transform: scale(1) rotate(0);
         filter: brightness(1) blur(0) saturate(1) drop-shadow(0 0 30px var(--evo-soft)); }
}

/* 高光扫过新形态：一道白光横掠，金属质感 + 提神 */
.evo-shine {
  position: absolute;
  width: calc(var(--evo-fit-to) * 100%);
  height: calc(var(--evo-fit-to) * 100%);
  background: linear-gradient(112deg, transparent 36%, rgba(255, 255, 255, .95) 50%, transparent 64%);
  background-size: 250% 100%; background-position: 150% 0;
  opacity: 0; mix-blend-mode: screen; pointer-events: none;
  animation: evoShine .8s 4.90s ease-out forwards;
}
@keyframes evoShine {
  0%   { opacity: 0; background-position: 150% 0; }
  22%  { opacity: 1; }
  100% { opacity: 0; background-position: -50% 0; }
}

/* —— 旋转光环（v168 新增）：欣赏期的持续视觉支撑 ——
   没有它，新形态弹出后就「静止」了，1.5s 的欣赏期会显得空。
   结构是「外层负责淡入 + 内层负责旋转」—— 两个动画若都写在同一元素上会因为
   同时改 transform 而互相覆盖（后声明的赢），所以拆成 .evo-ring > i。 */
.evo-ring {
  position: absolute; width: 470px; height: 470px;
  opacity: 0; pointer-events: none;
  animation: evoRingIn .8s 4.92s ease-out forwards;
}
.evo-ring i {
  display: block; width: 100%; height: 100%; border-radius: 50%;
  background: repeating-conic-gradient(from 0deg,
    var(--evo-c1) 0deg 1.2deg, transparent 1.2deg 9deg);
  -webkit-mask-image: radial-gradient(circle, transparent 62%, #000 68%, #000 72%, transparent 78%);
  mask-image: radial-gradient(circle, transparent 62%, #000 68%, #000 72%, transparent 78%);
  mix-blend-mode: screen;
  animation: evoRingSpin 16s linear infinite;
}
@keyframes evoRingIn { from { opacity: 0; transform: scale(.5); } to { opacity: .6; transform: scale(1); } }
@keyframes evoRingSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* —— 标题组 —— */
.evo-title {
  position: absolute; left: 0; right: 0; bottom: 12%;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  opacity: 0; animation: evoTitleIn .68s 4.98s cubic-bezier(.2, 1.4, .4, 1) forwards;
  pointer-events: none;
}
/* 标题背后的一团光，让文字「浮」在光上（v169 加厚） */
.evo-title::before {
  content: ''; position: absolute; top: 50%; left: 50%;
  width: 460px; height: 190px; margin: -95px 0 0 -230px; border-radius: 50%;
  background: radial-gradient(ellipse, var(--evo-soft) 0%, transparent 68%);
  opacity: .9; z-index: -1;
}
@keyframes evoTitleIn {
  0%   { opacity: 0; transform: translateY(26px) scale(.86); }
  62%  { opacity: 1; transform: translateY(-4px) scale(1.04); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
.evo-badge {
  font-size: 46px; line-height: 1;
  filter: drop-shadow(0 0 18px var(--evo-glow));
  animation: evoBadge 1.1s 5.2s ease-in-out infinite alternate;
}
@keyframes evoBadge {
  from { transform: scale(1) rotate(0); }
  to   { transform: scale(1.2) rotate(7deg); }
}
.evo-word {
  font-size: 46px; font-weight: 900; letter-spacing: 5px;
  background: linear-gradient(180deg, #fff 8%, var(--evo-c1) 55%, var(--evo-c2) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 34px var(--evo-glow)) drop-shadow(0 4px 12px rgba(0, 0, 0, .55));
}
.evo-name {
  font-size: 17px; font-weight: 800; color: #fdf6ff;
  text-shadow: 0 2px 10px rgba(0, 0, 0, .65);
}
.evo-name .evo-arrow { color: var(--evo-c1); margin: 0 7px; font-weight: 900; }
.evo-sub {
  font-size: 13px; font-weight: 700; color: var(--evo-c1);
  letter-spacing: 1px; text-shadow: 0 2px 10px rgba(0, 0, 0, .6);
}

/* —— 粒子 ——
   .evo-orb    蓄力期向内聚拢（JS 在 2.28s 撒）
   .evo-shard  爆开瞬间碎片飞散（JS 在 3.80s 撒）—— 细长碎片，与圆点星星区分
   .evo-spark  落位后向外炸开（JS 在 4.74s 撒）
   .evo-mote   欣赏期缓慢上浮（JS 在 4.98s 撒）—— 让「静止的欣赏」一直有微动 */
.evo-orb {
  position: absolute; left: 50%; top: 50%; width: 7px; height: 7px; border-radius: 50%;
  background: var(--evo-c1); box-shadow: 0 0 10px var(--evo-glow);
  pointer-events: none; opacity: 0; animation: evoOrb 1.1s ease-in forwards;
}
@keyframes evoOrb {
  0%   { opacity: 0; transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(.35); }
  14%  { opacity: 1; }
  75%  { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.5); }
}
.evo-shard {
  position: absolute; left: 50%; top: 50%; width: 3px; height: 17px; border-radius: 2px;
  background: linear-gradient(180deg, #fff 0%, var(--evo-c1) 70%, transparent 100%);
  box-shadow: 0 0 12px var(--evo-glow);
  pointer-events: none; opacity: 0;
  animation: evoShard .66s cubic-bezier(.1, .85, .25, 1) forwards;
}
@keyframes evoShard {
  0%   { opacity: 0;  transform: translate(-50%, -50%) rotate(var(--rot)) scale(.2); }
  8%   { opacity: 1;  transform: translate(calc(-50% + var(--dx) * .3), calc(-50% + var(--dy) * .3)) rotate(var(--rot)) scale(1.2); }
  100% { opacity: 0;  transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) rotate(var(--rot)) scale(.45); }
}
.evo-spark {
  position: absolute; left: 50%; top: 50%; width: 10px; height: 10px; border-radius: 50%;
  background: var(--evo-c1); box-shadow: 0 0 12px var(--evo-glow);
  pointer-events: none; opacity: 0; animation: evoSpark 1.4s ease-out forwards;
}
@keyframes evoSpark {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(.25); }
  10%  { opacity: 1; transform: translate(-50%, -50%) scale(1.15); }
  100% { opacity: 0; transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(.08); }
}
.evo-mote {
  position: absolute; left: 50%; top: 50%; width: 6px; height: 6px; border-radius: 50%;
  background: var(--evo-c1); box-shadow: 0 0 14px var(--evo-glow);
  pointer-events: none; opacity: 0; animation: evoMote 2.4s ease-out forwards;
}
@keyframes evoMote {
  0%   { opacity: 0;   transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(.5); }
  22%  { opacity: .95; }
  70%  { opacity: .65; }
  100% { opacity: 0;   transform: translate(calc(-50% + var(--dx) * 1.3), calc(-50% + var(--dy) - 120px)) scale(.3); }
}

/* —— 跳过提示 —— */
.evo-skip {
  position: absolute; right: 22px; bottom: 20px;
  font-size: 12px; font-weight: 700; letter-spacing: 1px;
  color: rgba(255, 255, 255, .48);
  opacity: 0; animation: evoTitleIn .4s 1.4s ease-out forwards;
}

/* ══════════════════════════════════════════════════════════════════
   「温和」力度（.int-soft）：给开了「减少动态效果」偏好、或主动选温和的玩家。
   🔴 v169 关键取舍 —— 温和 ≠ 什么也看不见。
   旧版的无障碍分支把 animation-duration 压到 .01ms **但延迟保留**，于是
   .evo-from（延迟 0）瞬间跳到终帧 = 透明、.evo-to（延迟 3.82s）压根没开始 = 也透明
   ⇒ 整段动效一张图都不显示。那个 @media 块已**删除**。
   现在温和模式只做「减法」：保留完整的 6.5s 叙事（升起 → 呼吸 → **收缩成光点** →
   从光点长大 → 落位 → 欣赏），只去掉强刺激层（全屏过曝 / 放射光线 / 碎片 / 地面
   冲击波），并把镜头冲击换成小幅度版本。动效总时长不变 ⇒ JS 不需要缩短等待。
   ══════════════════════════════════════════════════════════════════ */
.evo-overlay.int-soft .evo-whiteout,
.evo-overlay.int-soft .evo-rays,
.evo-overlay.int-soft .evo-shard,
.evo-overlay.int-soft .evo-shock { display: none; }
.evo-overlay.int-soft .evo-stage { animation-name: evoPunchSoft; }
.evo-overlay.int-soft .evo-to   { animation-name: evoGrowSoft; }
@keyframes evoPunchSoft {
  0%   { transform: scale(1); }
  8%   { transform: scale(1.035); }
  22%  { transform: scale(.995); }
  70%  { transform: scale(1); }
  78%  { transform: scale(1.015); }
  100% { transform: scale(1); }
}
/* 温和版去掉色差偏移（红/青错位对光敏感人群不友好），保留由白显色与过冲 */
@keyframes evoGrowSoft {
  0%   { opacity: 0;   transform: scale(.06); filter: brightness(5) blur(2.4px) saturate(.3); }
  8%   { opacity: .9;  transform: scale(.14); filter: brightness(4.2) blur(1.9px) saturate(.5); }
  20%  { opacity: 1;   transform: scale(.32); filter: brightness(3.4) blur(1.2px) saturate(.7); }
  36%  { transform: scale(.58); filter: brightness(2.5) blur(.6px) saturate(.9); }
  54%  { transform: scale(.85); filter: brightness(1.9) blur(.2px) saturate(1); }
  68%  { transform: scale(1.18); filter: brightness(1.4) blur(0) saturate(1); }
  82%  { transform: scale(.95); }
  100% { opacity: 1; transform: scale(1); filter: brightness(1) blur(0) saturate(1) drop-shadow(0 0 30px var(--evo-soft)); }
}
