/* ==================================================================
   motion.css —— 全端动效层（v1.32）
   前台 / 后台 / 代理端 / 激活页共用，跟在各端自己的 css 之后引入。

   三条硬规矩：
     1. 所有规则都挂在 html.mo-on 下。JS 没跑（或被关掉）时这份文件等于空气，
        不会出现「内容藏起来了但没动画」的白屏。这也是它敢默认 opacity:0 的原因。
     2. 只动 transform / opacity / filter。不动 width/height/top/left，
        保证浏览器全程走合成层，不触发布局重排 —— 这是「炫但不能卡」的底线。
     3. 双击开关：系统 prefers-reduced-motion，或本地 localStorage.kx_motion=off
        （设置页「减少动效」写这个键）。任一条命中，html.mo-on 根本不会加上。

   与 fx.js 的分工：fx.js 管「点击瞬间」的粒子烟花（每次点击新建节点），
   本文件管「状态之间」的过渡 + 鼠标划过的流星（常驻元素，CSS 过渡 + IO 触发）。
   两套互不依赖，任何一套挂掉另一套照常。
   ================================================================== */

/* ---------------------------------------------------------------
   0. 变量与关键帧
   --------------------------------------------------------------- */
:root {
  --mo-fast: .16s;
  --mo-base: .3s;
  --mo-slow: .58s;
  --mo-ease: cubic-bezier(.22, .61, .36, 1);
  --mo-spring: cubic-bezier(.34, 1.4, .64, 1);

  /* 卡片流星（v1.46）：亮核 / 尾巴 / 头部白点，三色是页面级流星的三档配色 */
  --mo-meteor-core: rgba(129, 140, 248, .50);
  --mo-meteor-tail: rgba(99, 102, 241, .26);
  --mo-meteor-head: rgba(255, 255, 255, .92);
  --mo-met-1: rgba(129, 140, 248, .95);
  --mo-met-2: rgba(217, 70, 239, .88);
  --mo-met-3: rgba(56, 189, 248, .90);
  /* 页面级流星的默认值：JS 会逐颗覆盖，这里给默认，
     免得「var() 没定义就回落」在深色下露出浅色（见 test-dark-sse 第二节） */
  --mo-met-len: 120px;
  --mo-met-ang: 0deg;
  --mo-met-c: var(--mo-met-1);
  --mo-tail: .7;

  /* 卡片聚光的余晖（v1.32 起就有，流星沿用它的色调，别删） */
  --mo-spot: rgba(99, 102, 241, .085);
  --mo-spot-2: rgba(217, 70, 239, .055);
  --mo-glow: rgba(99, 102, 241, .30);
  --mo-ring: rgba(99, 102, 241, .18);
}

[data-theme="dark"] {
  /* 深色下改成发光而不是阴影，否则暗底上看不见 */
  --mo-spot: rgba(139, 92, 246, .16);
  --mo-spot-2: rgba(56, 189, 248, .08);
  --mo-glow: rgba(139, 92, 246, .45);
  --mo-ring: rgba(139, 92, 246, .30);

  /* 流星在暗底要更透亮，否则整条尾巴糊成一团灰 */
  --mo-meteor-core: rgba(196, 181, 253, .62);
  --mo-meteor-tail: rgba(139, 92, 246, .34);
  --mo-meteor-head: rgba(255, 255, 255, 1);
  --mo-met-1: rgba(165, 180, 252, 1);
  --mo-met-2: rgba(232, 121, 249, .95);
  --mo-met-3: rgba(103, 232, 249, .95);
}

@keyframes moFadeUp { from { opacity: 0; transform: translate3d(0, 22px, 0); } to { opacity: 1; transform: none; } }
@keyframes moFadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes moSlideL { from { opacity: 0; transform: translate3d(-26px, 0, 0); } to { opacity: 1; transform: none; } }
@keyframes moSlideR { from { opacity: 0; transform: translate3d(26px, 0, 0); } to { opacity: 1; transform: none; } }
@keyframes moZoom   { from { opacity: 0; transform: scale(.945); } to { opacity: 1; transform: none; } }
@keyframes moPop    { 0% { opacity: 0; transform: scale(.82); } 60% { opacity: 1; transform: scale(1.035); } 100% { opacity: 1; transform: none; } }
@keyframes moViewIn { from { opacity: 0; transform: translate3d(0, 9px, 0); } to { opacity: 1; transform: none; } }
@keyframes moBreathe {
  0%, 100% { box-shadow: 0 10px 24px var(--mo-glow), 0 0 0 0 var(--mo-ring); }
  50%      { box-shadow: 0 14px 32px var(--mo-glow), 0 0 0 7px rgba(99, 102, 241, 0); }
}
@keyframes moShimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
@keyframes moSheenFast { 0% { left: -60%; } 55%, 100% { left: 130%; } }
@keyframes moSpin { to { transform: rotate(360deg); } }
@keyframes moPulseRing {
  0%   { transform: scale(.9); opacity: .75; }
  70%  { transform: scale(2.1); opacity: 0; }
  100% { transform: scale(2.1); opacity: 0; }
}
@keyframes moTick { 0% { transform: translateY(0); } 100% { transform: translateY(0); } }

/* ---------------------------------------------------------------
   1. 首屏编排
      注意：首页 hero / feature / step / price-card 的入场由 site.js 的
      initReveal() + style.css 的 .rv 类负责（有 1.6 秒兜底与 stagger），
      这里**不再重复接管**，否则 animation 会盖掉 .rv 的 opacity:0，
      两套揭示互相打断，反而变成「一下全出来」。
      本段只给没有 .rv 覆盖的容器（后台 / 代理 / 工作台）用。
   --------------------------------------------------------------- */
html.mo-on .mo-enter > * {
  animation: moFadeUp var(--mo-slow) var(--mo-ease) both;
}
html.mo-on .mo-enter > *:nth-child(1) { animation-delay: .04s; }
html.mo-on .mo-enter > *:nth-child(2) { animation-delay: .10s; }
html.mo-on .mo-enter > *:nth-child(3) { animation-delay: .16s; }
html.mo-on .mo-enter > *:nth-child(4) { animation-delay: .22s; }
html.mo-on .mo-enter > *:nth-child(5) { animation-delay: .28s; }
html.mo-on .mo-enter > *:nth-child(6) { animation-delay: .34s; }
html.mo-on .mo-enter > *:nth-child(n+7) { animation-delay: .38s; }

/* ---------------------------------------------------------------
   2. 滚动揭示（[data-mo] 由 JS 自动打，进入视口后加 .mo-in）
      用 transition 不用 animation：stagger 只要改 --mo-d，
      而且元素被提前揭示/打断时能平滑接上，不会闪一下再跳。
   --------------------------------------------------------------- */
html.mo-on [data-mo] {
  opacity: 0;
  transition:
    opacity .52s var(--mo-ease),
    transform .6s var(--mo-ease);
  transition-delay: var(--mo-d, 0ms);
  /* v1.47.1：这里原来有 will-change: opacity, transform。
     它会给页面上每一个卡片都单独提升一个合成层，模板库几十张卡一起提升会把显存吃光，
     低端 GPU / 移动端会整片掉层刷黑（正是「内容整体消失」的观感）。
     opacity/transform 过渡本身不需要 will-change 才能跑。 */
}
html.mo-on [data-mo="up"]    { transform: translate3d(0, 24px, 0); }
html.mo-on [data-mo="left"]  { transform: translate3d(-26px, 0, 0); }
html.mo-on [data-mo="right"] { transform: translate3d(26px, 0, 0); }
html.mo-on [data-mo="zoom"]  { transform: scale(.955); }
html.mo-on [data-mo].mo-in   { opacity: 1; transform: none; }

/* 揭示完就撤掉 will-change，几百个卡片常驻 will-change 会吃显存 */
html.mo-on [data-mo].mo-done { will-change: auto; }

/* ---------------------------------------------------------------
   3. 按钮：弹性位移 + 按压回弹 + 主按钮扫光加速 + 大按钮呼吸光
      原来 .btn 只有 .3s 的 transform，按下是「沉一下」；
      这里换成回弹曲线，抬起来会过冲一点，手感更像实体键。
   --------------------------------------------------------------- */
html.mo-on .btn,
html.mo-on .adm-nav button,
html.mo-on .ag-nav button {
  transition:
    transform var(--mo-fast) var(--mo-spring),
    box-shadow var(--mo-base) var(--mo-ease),
    background-color .22s var(--mo-ease),
    border-color .22s var(--mo-ease),
    color .18s var(--mo-ease);
}

html.mo-on .btn:hover { transform: translateY(-2px); }
html.mo-on .btn:active { transform: translateY(0) scale(.965); transition-duration: .07s; }
html.mo-on .btn.sm:hover { transform: translateY(-1.5px); }
html.mo-on .btn[disabled]:hover { transform: none; }

/* 主按钮：默认 4.6s 一次慢扫光（原有），悬停时加速到 1.4s，像被「唤醒」 */
html.mo-on .btn.primary:hover::after { animation-duration: 1.4s; }
html.mo-on .btn.primary:hover { box-shadow: 0 14px 30px var(--mo-glow); }

/* 超大主按钮（hero 的「免费生成」）：轻微呼吸，把视线钉在这 */
html.mo-on .btn.primary.lg { animation: moBreathe 3.8s var(--mo-ease) infinite; }
html.mo-on .btn.primary.lg:hover { animation-play-state: paused; }

/* 幽灵按钮：悬停时边框染上品牌色，配一层很淡的外发光 */
html.mo-on .btn.ghost:hover {
  border-color: var(--mo-ring);
  box-shadow: 0 8px 20px -8px var(--mo-glow);
}

/* ---------------------------------------------------------------
   4. 流星掠过：鼠标位置写进 --mx/--my，亮核跟着走、光尾斜拖在后面
      只在 .mo-spot 上生效（JS 白名单加的），不是所有卡片都铺。

      为什么要两层：::before 是「余晖 + 亮核」（圆形，跟鼠标），
      ::after 是「尾巴」（细长光带，右端钉在鼠标点，绕右端转 -26°）。
      一个圆核 + 一条有方向的尾巴 = 流星；纯 radial-gradient 做不出方向性，
      这就是上一版「手电筒光圈」和现在「流星」的区别。
   --------------------------------------------------------------- */
/* 光层压在内容下面，靠 isolation + z-index:-1 实现：
   这样不用给卡片的子元素改 position，绝对定位的下拉菜单 / 角标不会被带歪。
   （第一版试过 z-index:0 然后给 > * 抬层，会破坏卡片内的 absolute 布局，已弃用） */
html.mo-on .mo-spot { position: relative; isolation: isolate; }

html.mo-on .mo-spot::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  z-index: -1;
  transition: opacity var(--mo-base) var(--mo-ease);
  /* v1.49：从三层大渐变收到两层。
     这张背景是**整卡面积**、跟着鼠标每帧改中心点的 —— 层数直接等于每帧要重画的面积倍数。
     320px 那层最贵、alpha 最低（.055），肉眼几乎看不出来，删掉后观感几乎无差；
     两个色调合并进同一条渐变的中段色标，颜色层次仍然在。 */
  background:
    /* 亮核：小、集中，正好在鼠标下方 */
    radial-gradient(88px circle at var(--mx, 50%) var(--my, 0%), var(--mo-meteor-core), transparent 70%),
    /* 余晖：一层渐变里同时带紫与蓝，替代原来的两层 */
    radial-gradient(230px circle at var(--mx, 50%) var(--my, 0%),
      var(--mo-spot), var(--mo-spot-2) 46%, transparent 70%);
}

/* 尾巴：168px 的光带，右端就是流星头（钉在鼠标点），绕右端转 -26° 指向左上。
   --mo-tail 由 JS 按划动速度写（.62 静止 → 1 飞快），只做 scaleX，不碰布局。

   v1.49 关键改动：定位从 left/top 换成 translate。
   left/top 每改一次都要**重新布局**这个伪元素（改一次鼠标 = 一次 layout + 一次 paint），
   后台几十张卡的时候就是「鼠标一动，页面顿一下」；换成 transform 只有合成，不动布局。
   头部仍然钉在 (--mx, --my)：translate 把右端推到位，再绕右端（origin 100% 50%）转与缩放。 */
html.mo-on .mo-spot::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 168px;
  height: 2px;
  border-radius: 2px;
  pointer-events: none;
  z-index: -1;
  opacity: 0;
  transform-origin: 100% 50%;
  transform:
    translate(calc(var(--mx, 50%) - 168px), calc(var(--my, 0%) - 1px))
    rotate(-26deg)
    scaleX(var(--mo-tail, .7));
  background: linear-gradient(90deg,
    transparent 0%,
    var(--mo-meteor-tail) 56%,
    var(--mo-meteor-core) 94%,
    var(--mo-meteor-head) 100%);
  transition: opacity var(--mo-base) var(--mo-ease);
}
html.mo-on .mo-spot:hover::before,
html.mo-on .mo-spot:hover::after { opacity: 1; }

/* 浅色（白底）下把整块光影收小一档。
   88px 亮核 + 230px 余晖 + 168px 尾带是为深色底调的：白底上同样的面积会糊成
   一大片灰紫，看着像「鼠标拖了一块脏东西」。这里只缩浅色，深色保持原尺寸
   （暗底靠面积才撑得住）。比例 ≈ .6：52 / 132 / 100。 */
html:not([data-theme="dark"]).mo-on .mo-spot::before {
  background:
    radial-gradient(52px circle at var(--mx, 50%) var(--my, 0%),
      var(--mo-meteor-core), transparent 72%),
    radial-gradient(132px circle at var(--mx, 50%) var(--my, 0%),
      var(--mo-spot), var(--mo-spot-2) 46%, transparent 70%);
}
html:not([data-theme="dark"]).mo-on .mo-spot::after {
  width: 100px;
  transform:
    translate(calc(var(--mx, 50%) - 100px), calc(var(--my, 0%) - 1px))
    rotate(-26deg)
    scaleX(var(--mo-tail, .7));
}

/* 页面级流星：鼠标划得快时从指针飞过的尾焰（JS 建节点，0.8s 自己散掉） */
.mo-meteor-layer {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9996;
  overflow: hidden;
  /* v1.49：明确告诉浏览器这一层自成一体 —— 里面的流星怎么动都不会连累页面其它部分重绘 */
  contain: layout style paint;
}
.mo-meteor {
  position: absolute;
  width: var(--mo-met-len, 120px);
  height: 2px;
  margin-left: calc(var(--mo-met-len, 120px) * -1);
  margin-top: -1px;
  border-radius: 2px;
  pointer-events: none;
  transform-origin: 100% 50%;
  background: linear-gradient(90deg, transparent 0%, var(--mo-met-c, var(--mo-met-1)) 82%, var(--mo-meteor-head) 100%);
  animation: moMeteor .78s cubic-bezier(.18, .7, .3, 1) both;
}
/* 流星头：一个 3px 的白点 + 一圈同色光晕，尾巴才不会「没有头」 */
.mo-meteor::after {
  content: "";
  position: absolute;
  right: -1px;
  top: 50%;
  width: 3px;
  height: 3px;
  margin-top: -1.5px;
  border-radius: 50%;
  background: var(--mo-meteor-head);
  box-shadow: 0 0 7px 2px var(--mo-met-c, var(--mo-met-1));
}

/* 浅色同上：页面级流星按 .6 缩（最长 160 → 96px），头部的 7px 光晕收到 4px，
   白底上才不会出现一条「拖不散的雾带」。深色不动。 */
html:not([data-theme="dark"]) .mo-meteor {
  width: calc(var(--mo-met-len, 120px) * .6);
  margin-left: calc(var(--mo-met-len, 120px) * -.6);
}
html:not([data-theme="dark"]) .mo-meteor::after {
  box-shadow: 0 0 4px 1px var(--mo-met-c, var(--mo-met-1));
}
@keyframes moMeteor {
  0%   { opacity: 0; transform: rotate(var(--mo-met-ang, 0deg)) scaleX(.35); }
  14%  { opacity: .95; }
  70%  { opacity: .66; }
  100% { opacity: 0; transform: rotate(var(--mo-met-ang, 0deg)) translateX(28px) scaleX(1); }
}

/* ---------------------------------------------------------------
   5. 导航：下划线滑入 + 吸顶阴影 + 顶部滚动进度条
   --------------------------------------------------------------- */
html.mo-on .nav-links a { position: relative; transition: color .2s var(--mo-ease); }
html.mo-on .nav-links a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -7px;
  height: 2px;
  border-radius: 2px;
  background: var(--grad);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .3s var(--mo-ease);
}
html.mo-on .nav-links a:hover::after { transform: scaleX(1); }

html.mo-on .nav { transition: box-shadow var(--mo-base) var(--mo-ease), background-color var(--mo-base); }
html.mo-on .nav.mo-stuck { box-shadow: 0 6px 26px rgba(23, 29, 64, .09); }
[data-theme="dark"] html.mo-on .nav.mo-stuck { box-shadow: 0 6px 26px rgba(0, 0, 0, .55); }

#moProg {
  position: fixed;
  top: 0; left: 0;
  width: 100%;
  height: 2px;
  z-index: 9997;
  pointer-events: none;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: var(--grad);
  box-shadow: 0 0 10px var(--mo-glow);
  opacity: 0;
  transition: opacity .25s var(--mo-ease);
}
#moProg.on { opacity: 1; }

/* ---------------------------------------------------------------
   6. 后台 / 代理端：视图切换 + 侧栏导航光条
       display:none → 显示 会让 animation 重新播放，纯 CSS 就能拿到过渡。
   --------------------------------------------------------------- */
html.mo-on .adm-view:not(.hidden),
html.mo-on .ag-view:not(.hidden) {
  animation: moViewIn .32s var(--mo-ease) both;
}

html.mo-on .adm-nav button,
html.mo-on .ag-nav button {
  position: relative;
}
html.mo-on .adm-nav button::before,
html.mo-on .ag-nav button::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 3px; height: 0;
  border-radius: 0 3px 3px 0;
  background: var(--grad);
  transform: translateY(-50%);
  transition: height .24s var(--mo-ease);
}
html.mo-on .adm-nav button:hover::before,
html.mo-on .ag-nav button:hover::before { height: 42%; }
html.mo-on .adm-nav button.on::before,
html.mo-on .ag-nav button.on::before { height: 62%; }

/* ---------------------------------------------------------------
   7. 通用小件：骨架 shimmer / 圆点脉冲 / 数字防抖 / 旋转
   --------------------------------------------------------------- */
html.mo-on .mo-skel {
  position: relative;
  overflow: hidden;
  background: var(--chip);
  border-radius: 8px;
}
html.mo-on .mo-skel::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 18%, rgba(255, 255, 255, .52) 50%, transparent 82%);
  transform: translateX(-100%);
  animation: moShimmer 1.35s var(--mo-ease) infinite;
}
[data-theme="dark"] html.mo-on .mo-skel::after {
  background: linear-gradient(100deg, transparent 18%, rgba(255, 255, 255, .09) 50%, transparent 82%);
}

/* 头部小徽标：一圈缓慢扩散的光环，别用在超过 3 个元素上 */
html.mo-on .mo-ring { position: relative; }
html.mo-on .mo-ring::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: inherit;
  border: 1.5px solid var(--mo-glow);
  animation: moPulseRing 2.4s var(--mo-ease) infinite;
  pointer-events: none;
}

/* 数字滚动时用等宽数字，避免「位数变化把后面的字挤跑」 */
html.mo-on .mo-num { font-variant-numeric: tabular-nums; }

html.mo-on .mo-spin { animation: moSpin .9s linear infinite; }

/* 点击后需要「等一下」的按钮：加 .mo-busy，右上一个转圈 */
html.mo-on .mo-busy { position: relative; pointer-events: none; }
html.mo-on .mo-busy::before {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 14px; height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .35);
  border-top-color: currentColor;
  animation: moSpin .7s linear infinite;
}
html.mo-on .btn.ghost.mo-busy::before { border-color: var(--line-2); border-top-color: var(--brand); }

/* ---------------------------------------------------------------
   8. 关掉一切
      两道闸：系统级 prefers-reduced-motion、本地 kx_motion=off
      （后者由 JS 直接不加 html.mo-on，这里只管前者与运行中切换）。
   --------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html.mo-on [data-mo],
  html.mo-on .mo-enter > *,
  html.mo-on .adm-view:not(.hidden),
  html.mo-on .ag-view:not(.hidden),
  html.mo-on .btn.primary.lg,
  html.mo-on .mo-ring::after,
  html.mo-on .mo-spin,
  html.mo-on .mo-skel::after {
    animation: none !important;
    transition: none !important;
  }
  html.mo-on [data-mo] { opacity: 1 !important; transform: none !important; }
  html.mo-on .mo-spot::before { display: none; }
  html.mo-on .mo-spot::after { display: none; }
  .mo-meteor-layer { display: none; }
  #moProg { display: none; }
  html.mo-on .btn:hover,
  html.mo-on .btn:active { transform: none; }
  html.mo-on .nav-links a::after { transition: none; }
}

/* 低端设备（内存小 / 核心少）只保留按钮反馈，去掉大范围动效 */
@media (max-width: 720px) {
  html.mo-on .mo-spot::before { display: none; }        /* 触屏没有 hover，纯浪费 */
  html.mo-on .mo-spot::after { display: none; }         /* 流星尾巴同理 */
  .mo-meteor-layer { display: none; }
  html.mo-on .btn.primary.lg { animation: none; }        /* 手机上呼吸光容易显得卡 */
}

/* v1.52：触屏设备上取消「悬停上浮」。
   手指点完按钮后，:hover 会一直粘着（直到点别处），那个 translateY(-2px)
   就让按钮保持上移 2px 不回落 —— 屏幕上看着就是「点一下，按钮自己往上跳了一下」。
   触屏本来没有真正的悬停语义，这条只留 :active 的按压回弹。 */
@media (hover: none) {
  html.mo-on .btn:hover,
  html.mo-on .btn.sm:hover,
  html.mo-on .btn.ghost:hover,
  html.mo-on .adm-nav button:hover,
  html.mo-on .ag-nav button:hover { transform: none; }
  html.mo-on .btn.primary:hover { box-shadow: none; }
  html.mo-on .btn.primary:hover::after { animation-duration: 4.6s; }
}
