/* =====================================================================
   Oxymph 模拟器 · 动效层
   原则（第 43 轮重做）：**动效分三类，各有各的语言，不用同一套弹簧到处弹。**
     1 手势转场（push/pop/sheet/tab）—— 有方向有位移，曲线 --e-gesture，不过冲
     2 内容出现（入场、图表生长、数字滚动）—— 快起慢收 --e-spring，不过冲，位移 ≤8pt
     3 值变化（切周期/筛选/实时数字）—— 几乎不动：≤4pt + 淡入；实时数字完全不动
   禁止：数据相关元素用弹簧/过冲（数据是精确的，弹一下像坏了）；
        同一元素同时播两个改同一属性的动画；手势转场中内容再各自位移。
   全部尊重 prefers-reduced-motion。
   ===================================================================== */
:root{
  --e-out:cubic-bezier(.2,.8,.2,1);
  /* 手势：iOS 系统转场曲线。推进去就停，不回弹 —— 手指推出来的，不是弹出来的 */
  --e-gesture:cubic-bezier(.32,.72,0,1);
  /* 出现：快起慢收。**没有过冲**（旧值 .34,1.42 会冲过头再抖回去，看着像触电） */
  --e-spring:cubic-bezier(.2,.9,.3,1);
  --e-io:cubic-bezier(.4,0,.2,1);
}

/* ---------- 1. 按压反馈 ----------
   按下要快（.09s），松手慢一点（.26s）给一点弹回来的感觉。
   旧版用 CSS animation 做果冻回弹，和 :active 的 transform 抢同一属性：
   松手瞬间 animation 被摘掉 → 元素从半路瞬跳回原位，就是那一下「抽」。 */
.ex,.lrow,.mc,.stat,.metric,.group,.gr,.chip,.wd,.tile-i,
.press,.gbtn,.gtxt,.cta,.tab,.seg button,
.alert .bts button,.asheet .op,.asheet .cancel,.menu button,.side .it,.side .flag{
  transition:transform .26s var(--e-spring),filter .16s,opacity .16s,background .2s,color .2s,box-shadow .2s}
.ex:active,.lrow:active,.mc:active,.stat:active,.metric:active,
.chip:active,.tile-i:active,.gr:active,.wd:active,.side .it:active,.side .flag:active{
  transform:scale(.975);filter:brightness(.96);transition-duration:.09s;transition-timing-function:ease-out}
.press:active,.gbtn:active,.gtxt:active,.cta:active,.tab:active,.seg button:active,
.menu button:active,.alert .bts button:active,.asheet .op:active,.asheet .cancel:active{
  transform:scale(.94);transition-duration:.09s;transition-timing-function:ease-out}
.cta:active{transform:scale(.972)}
/* 桌面端悬停微抬 */
@media (hover:hover){
  .ex:hover,.lrow:hover,.mc:hover,.stat:hover,.metric:hover{transform:translateY(-2px);box-shadow:0 8px 22px rgba(20,40,70,.09)}
  .ex:hover:active,.lrow:hover:active,.mc:hover:active{transform:scale(.975)}
}

/* ---------- 2. push / pop 转场（旧页 ghost 视差）
   手势转场：用 --e-gesture（推进去就停）。转场进行中内容不再各自位移（见 motion.js stagger） ---------- */
.scr.in-r{animation:inR .38s var(--e-gesture);z-index:2}
.scr.in-l{animation:inL .34s var(--e-gesture);z-index:2}
.scr.out-l{animation:outL .38s var(--e-gesture) forwards;z-index:1;pointer-events:none}
.scr.out-r{animation:outR .34s var(--e-gesture) forwards;z-index:3;pointer-events:none}
@keyframes inR{from{transform:translateX(100%)}to{transform:none}}
@keyframes inL{from{transform:translateX(-30%);opacity:.35}to{transform:none;opacity:1}}
@keyframes outL{from{transform:none;filter:brightness(1)}to{transform:translateX(-30%);filter:brightness(.88)}}
@keyframes outR{from{transform:none;opacity:1}to{transform:translateX(100%);opacity:.9}}

/* 3. 内容依次浮现：由 motion.js 用 WAAPI 驱动（见 fadeUp），
      不放 CSS 里——避免动画不执行时内容被 fill:both 卡在透明状态 */

/* ---------- 4. 图表生长 ----------
   数据点不再「弹」出来：旧版 popIn 从 scale(.2) 用过冲弹簧弹到 1，
   十几个点一起弹 = 触电。改成跟着线一起淡入，最多从 .94 长到 1。 */
.chb,.cht,.chh{transform-box:fill-box;transform-origin:bottom;animation:growY .55s var(--e-out) both}
/* pathLength=1：按每条线自身长度归一化（以前写死 1600，心率这类尖峰多的长线超出部分永远画不出来） */
.chl{stroke-dasharray:1;stroke-dashoffset:1;animation:draw .9s var(--e-out) .06s both}
.chs{stroke-dasharray:1;stroke-dashoffset:1;animation:draw .6s var(--e-out) both}
.cha{animation:fadeIn .7s ease .22s both}
.chd{transform-box:fill-box;transform-origin:center;animation:popIn .34s var(--e-out) .3s both}
.chtp{transform-box:fill-box;transform-origin:center;animation:popIn .34s var(--e-out) .08s both}
.chbp{animation:fadeIn .5s ease both}
.chi{animation:popIn .3s var(--e-out) both}
/* 非首次渲染（切动作 / 切组 / 切语言）：不播生长，但必须落在「画完」的状态。
   以前只关 animation，.chl 停在 stroke-dashoffset:1600 → 线整条消失（第 24 轮 bug） */
.nm,.nm *{animation:none!important}
.chl.nm,.chs.nm,.nm .chl,.nm .chs{stroke-dashoffset:0!important}
.cha.nm,.chbp.nm,.nm .cha,.nm .chbp{opacity:1!important}
@keyframes growY{from{transform:scaleY(.04)}to{transform:scaleY(1)}}
@keyframes draw{to{stroke-dashoffset:0}}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes popIn{from{transform:scale(.94);opacity:0}to{transform:scale(1);opacity:1}}

/* ---------- 5. 大标题折叠（滚动时大标题 → 导航标题） ---------- */
.lt{transform-origin:20px 62%;will-change:transform,opacity}
.tbbg{position:absolute;left:0;right:0;top:0;height:118px;z-index:44;pointer-events:none;opacity:0;
  background:rgba(240,250,255,.66);backdrop-filter:blur(14px) saturate(160%);-webkit-backdrop-filter:blur(14px) saturate(160%);
  -webkit-mask-image:linear-gradient(#000 70%,transparent);mask-image:linear-gradient(#000 70%,transparent)}
.in-sheet .tbbg{height:78px}
/* 普通导航页也有滚动边缘（iOS 26 scroll edge）：内容滚到玻璃按钮/标题下时不再直接叠字 */
.tbbg.sm{height:146px}
.in-sheet .tbbg.sm{height:96px}
.ttl.lt-ttl{opacity:0;transform:translateX(-50%) translateY(8px)}
.tb.ltb{pointer-events:none}

/* ---------- 6. Tab bar 选中 ----------
   透镜滑过去就够（motion.js tabPop 负责位移）。图标再弹一下是噪音 —— 删掉 icoPop。 */
@keyframes tabPop{0%{transform:scale(.84)}55%{transform:scale(1.05)}100%{transform:scale(1)}}

/* ---------- 7. Toast 弹入（手势感：从上方飞入，用 --e-gesture） ---------- */
.toast{transform:translate(-50%,-34px) scale(.9);
  transition:transform .38s var(--e-gesture),opacity .24s ease}
.toast.on{opacity:1;transform:translate(-50%,0) scale(1)}

/* ---------- 9. 实时感：心跳 / 呼吸 / 实时数字 ---------- */
.beat{animation:beat 1s var(--e-io) infinite}
@keyframes beat{0%,100%{transform:scale(1)}12%{transform:scale(1.14)}26%{transform:scale(1)}38%{transform:scale(1.07)}52%{transform:scale(1)}}
.breathe{animation:breathe 2.8s ease-in-out infinite}
@keyframes breathe{0%,100%{box-shadow:0 0 0 0 rgba(30,144,255,0)}50%{box-shadow:0 0 0 9px rgba(30,144,255,.11)}}
/* 实时数字不再「跳一下」：训练页每秒都在变，每秒从下弹一次 = 一直抽。
   只做极轻的淡入，且只在手表换视图时用（那是视图切换，不是每秒 tick）。 */
.flash{animation:flash .3s var(--e-out)}
@keyframes flash{0%{opacity:.45}100%{opacity:1}}

/* 实时环平滑（迷你播放条 / 手表） */
.miniplayer .mr svg circle,#wscreen circle[stroke-dasharray]{transition:stroke-dasharray .45s linear,stroke .3s}

/* ---------- 10. 浮层细节 ---------- */
.half .grab{transition:background .2s}
.half:hover .grab{background:rgba(0,0,0,.26)}
.ov .half{animation:sheetIn .42s var(--e-gesture)}

/* ---------- 11. 无障碍：尊重系统「减弱动态效果」 ---------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;animation-delay:0s!important;transition-duration:.01ms!important}
}
