/* ==========================================================================
   JM66CLOUD 登录页开场动效（遮罩式，总长 3.26s）
   --------------------------------------------------------------------------
   配合 templates/login.html 顶部的 #jm66Intro 结构与 jm66/js/jm66-intro.js 使用。
   原理：在真实登录页之上叠一层遮罩播动效，播完淡出露出同一页面 → 无跳转、不可能闪白。
   收尾帧与真实左面板像素级重合（蓝白分界 x=791/1440 = 54.93%，实测 0px 偏差）。

   ⚠️ 改这个文件前必读：
   1) 所有 animation-delay 都写成 calc(基准 - var(--fz))，--fz 默认 0ms。
      这样访问 ?freeze=1500 时可用 JS 把动画定格在第 1.5 秒截图评审。
   2) opacity:0 必须加在"被动画的元素自身"，加到父容器上会把子动画关进透明父级里。
   3) introHardOut 是"JS 没加载"时的兜底，不要删。
   ========================================================================== */
/* ================= 开场动效（新增部分） ================= */
:root { --fz: 0ms; }                /* freeze 偏移，?freeze=1500 时由 JS 设为 -1500ms 语义 */
/* ⚠️ 兜底（生产环境必须有）：遮罩正常由 JS 在 3.32s 移除。
   万一 jm66-intro.js 没加载（路径错/被拦），纯 CSS 也必须在 3.34s 后让遮罩
   不可见 + 不再拦截点击，否则用户永远点不到登录框 = 整站登不进去。 */
@keyframes introHardOut { to { visibility: hidden; pointer-events: none; } }
#jm66Intro {
    position: fixed; inset: 0; z-index: 9999; overflow: hidden;
    background: transparent; cursor: pointer;
    animation: introHardOut 0s linear calc(3340ms - var(--fz)) forwards;
}
#jm66Intro * { pointer-events: none; }
/* 蓝色面板：宽度从满屏收成左 55%，渐变几何与真实左面板一致 → 收尾帧完全重合 */
.intro-blue {
    position: absolute; left: 0; top: 0; height: 100%; width: 100%;
    background: linear-gradient(160deg, #1e3a8a 0%, #2563eb 55%, #3b82f6 100%);
    animation: blueSettle 500ms cubic-bezier(.65,.02,.25,1) calc(2350ms - var(--fz)) both;
}
@keyframes blueSettle { from { width: 100%; } to { width: 55%; } }
/* 收尾用的两个柔光圆：坐标 = 真实左面板 ::before / ::after */
.intro-circle { position: absolute; border-radius: 50%; opacity: 0; }
.intro-circle.c1 { right: -120px; top: -120px; width: 420px; height: 420px; background: rgba(255,255,255,.08);
    animation: fadeIn 700ms ease-out calc(1900ms - var(--fz)) both; }
.intro-circle.c2 { left: -80px; bottom: -160px; width: 380px; height: 380px; background: rgba(255,255,255,.06);
    animation: fadeIn 700ms ease-out calc(2050ms - var(--fz)) both; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
/* 点阵网格 */
.intro-grid {
    position: absolute; inset: 0; opacity: 0;
    background-image: radial-gradient(rgba(255,255,255,.5) 1px, transparent 1px);
    background-size: 36px 36px;
    -webkit-mask-image: radial-gradient(ellipse 78% 78% at 50% 50%, #000 35%, rgba(0,0,0,.35) 70%, transparent 100%);
    mask-image: radial-gradient(ellipse 78% 78% at 50% 50%, #000 35%, rgba(0,0,0,.35) 70%, transparent 100%);
    animation: gridLife 3400ms ease-out calc(150ms - var(--fz)) both;
}
@keyframes gridLife {
    0%   { opacity: 0; transform: translate3d(0,14px,0) scale(1.03); }
    22%  { opacity: .17; }
    62%  { opacity: .15; transform: translate3d(0,0,0) scale(1); }
    100% { opacity: 0; transform: translate3d(0,-8px,0) scale(1); }
}
/* 汇聚光线 */
.intro-stream { position: absolute; left: 50%; top: 50%; height: 1px; width: 40vw; transform-origin: 0 0;
    background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.55), rgba(255,255,255,0));
    opacity: 0; }
.intro-stream.s1 { animation: streamIn 1100ms ease-out calc(900ms - var(--fz)) both; transform: rotate(28deg) translate3d(-30vw,0,0); }
.intro-stream.s2 { animation: streamIn 1100ms ease-out calc(1000ms - var(--fz)) both; transform: rotate(152deg) translate3d(-30vw,0,0); }
.intro-stream.s3 { animation: streamIn 1100ms ease-out calc(1100ms - var(--fz)) both; transform: rotate(-24deg) translate3d(-30vw,0,0); }
.intro-stream.s4 { animation: streamIn 1100ms ease-out calc(1200ms - var(--fz)) both; transform: rotate(204deg) translate3d(-30vw,0,0); }
@keyframes streamIn {
    0%   { opacity: 0; width: 6vw; }
    35%  { opacity: .85; }
    100% { opacity: 0; width: 34vw; }
}
/* ============ 科技感增强层（整层在揭幕前统一隐去，避免与真实面板不一致） ============ */
.intro-tech { position: absolute; inset: 0; animation: techOut 560ms ease-in calc(2160ms - var(--fz)) both; }
@keyframes techOut { from { opacity: 1; } to { opacity: 0; } }
/* 中心辉光：像仪表盘那样呼吸一次 */
.intro-vignette {
    position: absolute; inset: 0;
    background: radial-gradient(ellipse 44% 44% at 50% 50%, rgba(255,255,255,.11), rgba(255,255,255,0) 62%);
    animation: vig 2500ms ease-out calc(260ms - var(--fz)) both;
}
@keyframes vig { 0% { opacity: 0; transform: scale(.84); } 42% { opacity: .95; } 100% { opacity: 0; transform: scale(1.16); } }
/* 一次全屏扫描线 */
.intro-scan {
    position: absolute; left: 0; right: 0; top: 0; height: 150px;
    background: linear-gradient(180deg, rgba(191,219,254,0), rgba(191,219,254,.14) 62%, rgba(255,255,255,.40) 88%, rgba(255,255,255,0));
    animation: scanSweep 1650ms cubic-bezier(.35,.05,.25,1) calc(540ms - var(--fz)) both;
}
@keyframes scanSweep {
    0%   { opacity: 0; transform: translate3d(0,-150px,0); }
    14%  { opacity: 1; }
    100% { opacity: 0; transform: translate3d(0,100vh,0); }
}
/* HUD 四角直角框 */
.intro-hud i { position: absolute; width: 30px; height: 30px; border: 2px solid rgba(191,219,254,.5); opacity: 0; }
.intro-hud i:nth-child(1) { top: 30px; left: 30px; border-right: 0; border-bottom: 0; animation: hudA 520ms cubic-bezier(.2,.8,.25,1) calc(420ms - var(--fz)) both; }
.intro-hud i:nth-child(2) { top: 30px; right: 30px; border-left: 0; border-bottom: 0; animation: hudB 520ms cubic-bezier(.2,.8,.25,1) calc(500ms - var(--fz)) both; }
.intro-hud i:nth-child(3) { bottom: 30px; left: 30px; border-right: 0; border-top: 0; animation: hudC 520ms cubic-bezier(.2,.8,.25,1) calc(580ms - var(--fz)) both; }
.intro-hud i:nth-child(4) { bottom: 30px; right: 30px; border-left: 0; border-top: 0; animation: hudD 520ms cubic-bezier(.2,.8,.25,1) calc(660ms - var(--fz)) both; }
@keyframes hudA { from { opacity: 0; transform: translate3d(-16px,-16px,0); } to { opacity: .85; transform: none; } }
@keyframes hudB { from { opacity: 0; transform: translate3d(16px,-16px,0); }  to { opacity: .85; transform: none; } }
@keyframes hudC { from { opacity: 0; transform: translate3d(-16px,16px,0); }  to { opacity: .85; transform: none; } }
@keyframes hudD { from { opacity: 0; transform: translate3d(16px,16px,0); }   to { opacity: .85; transform: none; } }
/* 上升光点（JS 生成，位置/时延随机） */
.intro-particles i {
    position: absolute; bottom: -12px; width: 3px; height: 3px; border-radius: 50%;
    background: rgba(219,234,254,.9); box-shadow: 0 0 7px rgba(191,219,254,.75); opacity: 0;
    animation: drift 2500ms linear calc(var(--d, 200ms) - var(--fz)) both;
}
@keyframes drift {
    0%   { opacity: 0; transform: translate3d(0,0,0) scale(.6); }
    14%  { opacity: .9; transform: translate3d(0,-30px,0) scale(1); }
    70%  { opacity: .55; }
    100% { opacity: 0; transform: translate3d(var(--x, 12px), calc(-1 * var(--y, 480px)), 0) scale(.7); }
}
/* 中央核心 */
.intro-core {
    position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
    animation: coreOut 320ms ease-in calc(2400ms - var(--fz)) both;
}
@keyframes coreOut { from { opacity: 1; transform: translateY(0) scale(1); } to { opacity: 0; transform: translateY(-14px) scale(.97); } }
.intro-mark { position: relative; width: 96px; height: 96px; display: flex; align-items: center; justify-content: center;
    animation: markIn 760ms cubic-bezier(.2,.8,.25,1) calc(140ms - var(--fz)) both; }
@keyframes markIn { 0% { opacity: 0; transform: scale(.78); } 60% { opacity: 1; } 100% { opacity: 1; transform: scale(1); } }
/* 从 logo 扩散的脉冲环 */
.intro-pulse { position: absolute; width: 96px; height: 96px; border-radius: 50%; border: 1px solid rgba(219,234,254,.8); opacity: 0;
    animation: pulseOut 1700ms cubic-bezier(.2,.7,.3,1) calc(700ms - var(--fz)) both; }
.intro-pulse.p2 { animation-delay: calc(1240ms - var(--fz)); }
@keyframes pulseOut { 0% { opacity: 0; transform: scale(.72); } 16% { opacity: .8; } 100% { opacity: 0; transform: scale(2.15); } }
/* 两层反向旋转的虚线环 */
.intro-ring2 { position: absolute; width: 158px; height: 158px; opacity: 0;
    animation: spinCW 4600ms linear calc(220ms - var(--fz)) both, ringIn 620ms ease-out calc(220ms - var(--fz)) both; }
.intro-ring3 { position: absolute; width: 184px; height: 184px; opacity: 0;
    animation: spinCCW 6200ms linear calc(320ms - var(--fz)) both, ringIn 620ms ease-out calc(320ms - var(--fz)) both; }
.intro-ring2 .d1 { fill: none; stroke: rgba(191,219,254,.6); stroke-width: 1.6; stroke-dasharray: 7 11; }
.intro-ring3 .d2 { fill: none; stroke: rgba(147,197,253,.42); stroke-width: 1.2; stroke-dasharray: 2 16; }
@keyframes spinCW  { from { transform: rotate(0deg); }   to { transform: rotate(360deg); } }
@keyframes spinCCW { from { transform: rotate(360deg); } to { transform: rotate(0deg); } }
@keyframes ringIn  { from { opacity: 0; } to { opacity: .95; } }
.intro-mark img { width: 64px; height: 64px; border-radius: 16px; background: #fff; padding: 7px; box-sizing: content-box;
    box-shadow: 0 12px 34px rgba(2,16,45,.20), 0 2px 8px rgba(2,16,45,.14); position: relative; z-index: 2; }
.intro-mark .sweep { position: absolute; width: 78px; height: 78px; border-radius: 18px; overflow: hidden; z-index: 3; }
.intro-mark .sweep i { position: absolute; top: -40%; left: -70%; width: 40%; height: 180%;
    background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.85), rgba(255,255,255,0));
    transform: rotate(18deg); animation: sweepMove 900ms ease-in-out calc(780ms - var(--fz)) both; }
@keyframes sweepMove { from { left: -70%; opacity: 0; } 30% { opacity: .9; } to { left: 130%; opacity: 0; } }
.intro-ring { position: absolute; width: 96px; height: 96px; transform: rotate(-90deg); }
.intro-ring circle { fill: none; stroke: rgba(255,255,255,.85); stroke-width: 2; stroke-linecap: round;
    stroke-dasharray: 327; stroke-dashoffset: 327;
    animation: ringDraw 1150ms ease-in-out calc(260ms - var(--fz)) both; }
@keyframes ringDraw { 0% { stroke-dashoffset: 327; opacity: .2; } 55% { opacity: .95; } 100% { stroke-dashoffset: 0; opacity: .35; } }
.intro-ring circle.glow { stroke: rgba(147,197,253,.45); stroke-width: 6; filter: blur(3px);
    animation: ringDraw 1150ms ease-in-out calc(260ms - var(--fz)) both; }
.intro-word { margin-top: 26px; text-align: center; }
.intro-word h1 {
    margin: 0; font-size: 40px; font-weight: 700; letter-spacing: 6px; color: #fff;
    clip-path: inset(0 100% 0 0);
    animation: wordReveal 900ms cubic-bezier(.3,.7,.2,1) calc(620ms - var(--fz)) both,
               wordSpace 900ms cubic-bezier(.3,.7,.2,1) calc(620ms - var(--fz)) both;
}
@keyframes wordReveal { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 -2% 0 0); } }
@keyframes wordSpace { from { letter-spacing: 14px; } to { letter-spacing: 6px; } }
.intro-word .sub { margin-top: 8px; font-size: 16px; letter-spacing: 8px; color: rgba(255,255,255,.92);
    animation: riseIn 700ms ease-out calc(1020ms - var(--fz)) both; }
.intro-word .tag { margin-top: 10px; font-size: 11.5px; letter-spacing: 3.2px; color: rgba(219,234,254,.72);
    animation: riseIn 700ms ease-out calc(1180ms - var(--fz)) both; }
@keyframes riseIn { from { opacity: 0; transform: translate3d(0,10px,0); } to { opacity: 1; transform: none; } }
/* 启动进度线（故意不放百分比，避免"假进度"观感；线头带光点） */
.intro-bar { margin-top: 30px; width: 208px; height: 2px; border-radius: 2px; background: rgba(255,255,255,.16); overflow: visible; }
.intro-bar i { display: block; height: 100%; width: 0; position: relative; border-radius: 2px;
    background: linear-gradient(90deg, rgba(191,219,254,.95), #ffffff);
    box-shadow: 0 0 10px rgba(255,255,255,.75);
    animation: barFill 1250ms cubic-bezier(.5,.05,.3,1) calc(1120ms - var(--fz)) both; }
.intro-bar i::after { content: ""; position: absolute; right: -3px; top: -3px; width: 8px; height: 8px; border-radius: 50%;
    background: #ffffff; box-shadow: 0 0 14px 3px rgba(255,255,255,.9); }
@keyframes barFill { from { width: 0; } to { width: 100%; } }
/* 打字机启动日志 + 光标 */
.intro-boot { margin-top: 14px; display: flex; align-items: center; justify-content: center;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 10.5px; letter-spacing: 2.6px; color: rgba(191,219,254,.66); height: 14px;
    animation: bootLife 1600ms ease-out calc(1150ms - var(--fz)) both; }
.intro-boot span { display: inline-block; overflow: hidden; white-space: nowrap; width: 0;
    animation: bootType 1150ms steps(26, end) calc(1240ms - var(--fz)) both; }
.intro-boot .cur { display: inline-block; width: 7px; height: 11px; margin-left: 4px; background: rgba(191,219,254,.85);
    animation: blink 620ms steps(1, end) calc(1240ms - var(--fz)) infinite; }
@keyframes bootType { from { width: 0; } to { width: 26ch; } }
@keyframes blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } }
@keyframes bootLife { 0% { opacity: 0; } 26% { opacity: .95; } 82% { opacity: .95; } 100% { opacity: 0; } }

/* ================= 四周 HUD 内容（治"只有中间一坨、四周空"）=================
   全部挂在 .intro-tech 里 → 2.16s 统一淡出，仍不影响与真实页的无缝交接
   ⚠️ 所有 animation-delay 都必须写成 calc(基准 - var(--fz))，否则定格截图会失真 */
/* 全屏十字轴线：把中心与四边连起来 */
.intro-axis { position: absolute; left: 0; right: 0; top: 50%; height: 1px;
    background: linear-gradient(90deg, rgba(191,219,254,0) 0%, rgba(191,219,254,.30) 22%, rgba(255,255,255,.6) 50%, rgba(191,219,254,.30) 78%, rgba(191,219,254,0) 100%);
    animation: axisX 900ms cubic-bezier(.2,.8,.25,1) calc(420ms - var(--fz)) both; }
.intro-axis.v { left: 50%; right: auto; top: 0; bottom: 0; width: 1px; height: auto;
    background: linear-gradient(180deg, rgba(191,219,254,0) 0%, rgba(191,219,254,.26) 24%, rgba(255,255,255,.5) 50%, rgba(191,219,254,.26) 76%, rgba(191,219,254,0) 100%);
    animation: axisY 900ms cubic-bezier(.2,.8,.25,1) calc(480ms - var(--fz)) both; }
@keyframes axisX { from { opacity: 0; transform: scaleX(.18); } to { opacity: .55; transform: scaleX(1); } }
@keyframes axisY { from { opacity: 0; transform: scaleY(.18); } to { opacity: .45; transform: scaleY(1); } }
/* 上下边缘刻度尺 */
.intro-ruler { position: absolute; left: 0; right: 0; height: 20px;
    background-image: repeating-linear-gradient(90deg, rgba(191,219,254,.42) 0 1px, transparent 1px 40px),
                      repeating-linear-gradient(90deg, rgba(191,219,254,.20) 0 1px, transparent 1px 8px);
    background-size: 100% 13px, 100% 6px; background-repeat: no-repeat; }
.intro-ruler.t { top: 0; animation: ruleIn 700ms ease-out calc(300ms - var(--fz)) both; }
.intro-ruler.b { bottom: 0; transform: scaleY(-1); animation: ruleIn 700ms ease-out calc(360ms - var(--fz)) both; }
@keyframes ruleIn { from { opacity: 0; } to { opacity: .6; } }
/* 四角状态块（左下留给启动日志） */
.intro-quad { position: absolute; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; opacity: 0; }
.intro-quad .k { display: block; font-size: 9.5px; letter-spacing: 2.8px; color: rgba(147,197,253,.6); }
.intro-quad .v { display: block; margin-top: 4px; font-size: 12px; letter-spacing: 1.6px; color: rgba(226,240,255,.92); }
.intro-quad .v::before { content: ""; display: inline-block; width: 5px; height: 5px; margin-right: 8px; border-radius: 1px;
    background: rgba(147,197,253,.9); vertical-align: 1px; }
.intro-quad.q1 { top: 74px; left: 74px; animation: qIn 600ms cubic-bezier(.2,.8,.25,1) calc(640ms - var(--fz)) both; }
.intro-quad.q2 { top: 74px; right: 74px; text-align: right; animation: qIn 600ms cubic-bezier(.2,.8,.25,1) calc(740ms - var(--fz)) both; }
.intro-quad.q3 { bottom: 74px; right: 74px; text-align: right; animation: qIn 600ms cubic-bezier(.2,.8,.25,1) calc(840ms - var(--fz)) both; }
@keyframes qIn { from { opacity: 0; transform: translate3d(0,8px,0); } to { opacity: 1; transform: none; } }
/* 左下：启动日志逐行推入 */
.intro-log { position: absolute; left: 74px; bottom: 66px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 10px; letter-spacing: 1.9px; line-height: 2; color: rgba(191,219,254,.72); }
.intro-log div { opacity: 0; white-space: nowrap; animation: logIn 460ms ease-out calc(var(--t) - var(--fz)) both; }
.intro-log div b { font-weight: 400; color: rgba(226,240,255,.96); }
@keyframes logIn { from { opacity: 0; transform: translate3d(-10px,0,0); } to { opacity: 1; transform: none; } }
/* 左侧：运行状态列 */
.intro-node { position: absolute; left: 74px; top: 50%; transform: translateY(-50%); opacity: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 9.5px; letter-spacing: 2.2px;
    color: rgba(191,219,254,.62); animation: nodeIn 700ms ease-out calc(1020ms - var(--fz)) both; }
.intro-node div { padding: 10px 0; border-top: 1px solid rgba(191,219,254,.15); }
.intro-node div:first-child { border-top: 0; }
.intro-node i { display: inline-block; width: 5px; height: 5px; margin-right: 9px; border-radius: 50%;
    background: rgba(147,197,253,.85); vertical-align: 1px; animation: blink 1300ms steps(1,end) infinite; }
@keyframes nodeIn { from { opacity: 0; transform: translate3d(-12px,-50%,0); } to { opacity: 1; transform: translateY(-50%); } }
/* 右侧：雷达扫描 */
.intro-radar { position: absolute; right: 78px; top: 30%; transform: translateY(-50%); width: 168px; height: 168px; border-radius: 50%;
    border: 1px solid rgba(191,219,254,.22); opacity: 0; animation: radarIn 800ms ease-out calc(700ms - var(--fz)) both; }
.intro-radar::before, .intro-radar::after { content: ""; position: absolute; border-radius: 50%; border: 1px solid rgba(191,219,254,.15); }
.intro-radar::before { inset: 34px; }
.intro-radar::after { inset: 62px; }
.intro-radar .beam { position: absolute; inset: 0; border-radius: 50%; overflow: hidden;
    background: conic-gradient(from 0deg, rgba(147,197,253,.34) 0deg, rgba(147,197,253,.10) 36deg, rgba(147,197,253,0) 72deg, rgba(147,197,253,0) 360deg);
    animation: radarSpin 2500ms linear calc(760ms - var(--fz)) infinite; }
@keyframes radarSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes radarIn { from { opacity: 0; transform: scale(.9); } to { opacity: 1; transform: none; } }
/* 右下：频谱柱（抽象图形，不写任何状态文字，避免看起来像真实指标） */
.intro-spectrum { position: absolute; right: 88px; top: 58%; display: flex; align-items: flex-end; gap: 6px; height: 130px;
    opacity: 0; animation: specIn 800ms ease-out calc(880ms - var(--fz)) both; }
.intro-spectrum i { display: block; width: 5px; border-radius: 1px; transform-origin: bottom;
    background: linear-gradient(180deg, rgba(219,234,254,.85), rgba(147,197,253,.22));
    animation: specPulse 1800ms ease-in-out infinite alternate; }
@keyframes specIn { from { opacity: 0; } to { opacity: .9; } }
@keyframes specPulse { from { transform: scaleY(.22); } to { transform: scaleY(1); } }
/* 散布准星 */
.intro-cross { position: absolute; width: 11px; height: 11px; animation: crossIn 800ms ease-out calc(1200ms - var(--fz)) both; }
.intro-cross::before, .intro-cross::after { content: ""; position: absolute; background: rgba(191,219,254,.5); }
.intro-cross::before { left: 50%; top: 0; width: 1px; height: 100%; margin-left: -.5px; }
.intro-cross::after { top: 50%; left: 0; height: 1px; width: 100%; margin-top: -.5px; }
@keyframes crossIn { from { opacity: 0; } to { opacity: .5; } }
.intro-cross.c1 { left: 22%; top: 21%; } .intro-cross.c2 { left: 78%; top: 17%; }
.intro-cross.c3 { left: 15%; top: 74%; } .intro-cross.c4 { left: 85%; top: 68%; }
.intro-cross.c5 { left: 40%; top: 12%; } .intro-cross.c6 { left: 60%; top: 86%; }
/* 上下横贯信号波形（填掉上下两条空白横带） */
.intro-wave { position: absolute; height: 44px; opacity: 0; animation: waveIn 900ms ease-out calc(560ms - var(--fz)) both; }
.intro-wave svg { width: 100%; height: 100%; display: block; overflow: visible; }
.intro-wave .wl { fill: none; stroke: rgba(191,219,254,.5); stroke-width: 1.2; }
.intro-wave .wf { fill: url(#wg); }
.intro-wave.t { top: 118px; left: 12%; right: 12%; }
.intro-wave.b { bottom: 122px; left: 35%; right: 9%; transform: scaleY(-1); }
@keyframes waveIn { from { opacity: 0; } to { opacity: .8; } }
/* 遮罩淡出（必须先等蓝色面板收位完成，否则收尾帧与真实页对不齐） */
/* ⚠️ 兜底必须挂在这条规则上：.dissolve 比 #jm66Intro 更具体，会整条覆盖基础规则里的 animation */
#jm66Intro.dissolve { animation: introOut 400ms ease-in calc(2860ms - var(--fz)) both,
                                   introHardOut 0s linear calc(3340ms - var(--fz)) forwards; }
@keyframes introOut { from { opacity: 1; } to { opacity: 0; } }
/* 真实登录页内容入场（延迟到遮罩即将揭开）
   ⚠️ 关键：opacity:0 只能加在"被动画的那个元素"身上。上一版把 0 加在父级 <ul> 上、
   动画加在 <li> 上 → li 动画照跑却被关在透明父级里，不点一下永远看不见（已修） */
.jm66-login-left > *:not(.jm66-features), .jm66-login-right > * { opacity: 0; }
.jm66-features li { opacity: 0; }
.entrance .jm66-brand       { animation: riseIn 520ms cubic-bezier(.2,.8,.25,1) calc(2800ms - var(--fz)) both; }
.entrance .jm66-login-left h2   { animation: riseIn 520ms cubic-bezier(.2,.8,.25,1) calc(2870ms - var(--fz)) both; }
.entrance .jm66-login-left .desc { animation: riseIn 520ms cubic-bezier(.2,.8,.25,1) calc(2930ms - var(--fz)) both; }
/* 四条卖点：一条接一条（间隔 150ms，自右侧滑入）—— 拉开间隔才看得出"逐条"的节奏 */
.entrance .jm66-features li:nth-child(1) { animation: featureIn 520ms cubic-bezier(.2,.8,.25,1) calc(3010ms - var(--fz)) both; }
.entrance .jm66-features li:nth-child(2) { animation: featureIn 520ms cubic-bezier(.2,.8,.25,1) calc(3160ms - var(--fz)) both; }
.entrance .jm66-features li:nth-child(3) { animation: featureIn 520ms cubic-bezier(.2,.8,.25,1) calc(3310ms - var(--fz)) both; }
.entrance .jm66-features li:nth-child(4) { animation: featureIn 520ms cubic-bezier(.2,.8,.25,1) calc(3460ms - var(--fz)) both; }
.entrance .jm66-login-card   { animation: cardIn 560ms cubic-bezier(.2,.8,.25,1) calc(2880ms - var(--fz)) both; }
.entrance .jm66-login-footer { animation: fadeIn 600ms ease-out calc(3200ms - var(--fz)) both; }
@keyframes featureIn { from { opacity: 0; transform: translate3d(30px,6px,0); } to { opacity: 1; transform: none; } }
@keyframes cardIn { from { opacity: 0; transform: translate3d(0,16px,0); } to { opacity: 1; transform: none; } }
/* 冻结（截图评审用） */
.frozen #jm66Intro, .frozen #jm66Intro *, .frozen .jm66-login-wrap, .frozen .jm66-login-wrap *,
.frozen .jm66-login-footer { animation-play-state: paused !important; }
/* 减少动效偏好：直接不播 */
@media (prefers-reduced-motion: reduce) {
    #jm66Intro { display: none !important; }
    .jm66-login-left > *, .jm66-login-right > *, .entrance .jm66-login-footer { opacity: 1 !important; animation: none !important; }
}
/* 手机端：左面板本就隐藏 → 蓝色整屏淡出，不做左右分栏交接 */
@media screen and (max-width: 960px) {
    .intro-blue { animation-name: blueFadeOut; }
    .intro-circle, .intro-grid, .intro-stream,
    .intro-axis, .intro-ruler, .intro-quad, .intro-log, .intro-node, .intro-radar, .intro-cross { display: none; }
    @keyframes blueFadeOut { from { opacity: 1; } to { opacity: 0; } }
}
