/* mai.anxuos.com · 首抓加载动画 B「机台光环」（设计 2026-10-19 §9.4；ring.js 驱动，骨架在 index.html 的 #ld）。
   固定深色，配色照 L2（site/maimai/maimai.css）；字体栈 --num、--sc 用 maimai.css 在 html 上定义的那份，这里不重定义。
   变量只定义在 .ld 上，不碰 :root；类名不用 maimai.css 已有的 .btn、.glow、.wall、.below（改成 .ld-*）。
   机台所有尺寸都按 --W（机台外框边长）的比例算；动的只有 transform、opacity，和光环那一个属性 stroke-dashoffset。
   body 上的状态类由 ring.js 切：ld-on（加载层在）、queued、waiting、failed、live、prep（B50 页在下面预备）、expand（圆展开）、ld-out（展开收尾，覆盖格淡出）、rm（减弱动效）、snap（第一帧不放过渡）。 */
.ld{
  --bg:#0c0c10;--ink:#f2f0ea;--hi:#fff;--dim:#d8d6e0;--dim2:#c4c2cf;--dim3:#a3a1b1;
  --card:#111117;--line:rgba(255,255,255,.08);
  --gold:#f6e4b6;--gold-hi:#fffae8;--floor:#ffd27a;
  --tier-grad:linear-gradient(100deg,#e2ce96,#fffae8,#d6e6f4,#f6e4b6,#ceb880);
  /* 机台：桌面最大 640，按视口高留出上下文字的位置，手机按宽度 */
  --W:max(240px,min(640px,calc(100vh - 250px),calc(100vw - 32px)));
  --sw:max(4px,calc(var(--W) * .011));          /* 光环粗细 */
  --rh:calc(var(--W) * .415);                   /* 光环半径（中线） */
  --ro:calc(var(--rh) + var(--sw) / 2);         /* 光环外沿半径 */
  --kd:calc(var(--W) * .036);                   /* 按键直径 */
  --S:calc(var(--W) * .19);                     /* 叠放的最上面一张封面 */
  --ease:cubic-bezier(.2,.7,.2,1);
  position:fixed;inset:0;z-index:10;display:flex;flex-direction:column;overflow:hidden auto;
  color:var(--ink);font-family:var(--sc,'PingFang SC','Noto Sans SC',system-ui,sans-serif);font-size:14px;line-height:1.5;color-scheme:dark
}
.ld[hidden]{display:none!important}
.ld *,.ld *::before,.ld *::after{box-sizing:border-box}
/* 加载层在的时候锁住页面滚动；B50 页开始在下面预备（.prep）就放开，让滚动条（Windows、Linux 桌面的经典滚动条）在量格子之前就出现，
   展开时量到的格子位置和加载层藏起后的最终版面一致（mai.css 在 html 上另有 scrollbar-gutter:stable，支持它的浏览器根本不会变宽窄） */
body.ld-on:not(.prep){overflow:hidden}
/* 加载层在的时候，下面的 B50 页（#mm-app）只用透明度藏（P47：boot 前已经去掉 hidden，墙要量宽度）；墙等展开时那 50 格盖上来再露 */
body.ld-on #mm-app{opacity:0;pointer-events:none}
body.ld-on.prep #mm-app{opacity:.001}
body.ld-on.expand #mm-app{opacity:1;transition:opacity .45s .1s}
body.ld-on #mm-walls{opacity:0}
/* 展开时真实的墙在覆盖格下面先淡入（0.4–0.7s），格子里的定数、评级、角标、铭牌和没有封面的格子都跟着平滑出现；
   覆盖格在收尾前 200ms（ring.js 加 .ld-out）淡出，交叉过渡到真实格子，到 EXPAND_MS（780ms）藏起加载层时墙已经完全不透明 */
body.ld-on.expand #mm-walls{opacity:1;transition:opacity .3s ease .4s}
/* 重新开始：第一帧不放过渡 */
body.snap .ld *,body.snap .ld *::before,body.snap .ld *::after{transition:none!important}
.ld .num{font-family:var(--num,'Barlow Condensed',sans-serif);font-variant-numeric:tabular-nums}
.ld .plat{background-image:var(--tier-grad);-webkit-background-clip:text;background-clip:text;color:transparent}

/* ================= 加载层 ================= */
.ld-bg{position:absolute;inset:0;background:radial-gradient(ellipse 80% 70% at 50% 46%,#111118 0%,var(--bg) 70%);transition:opacity .6s}
.ld-top{position:relative;z-index:1;flex:none;height:64px;padding:0 24px;display:flex;align-items:center;gap:12px;white-space:nowrap;transition:opacity .25s}
.ld-top b{font-size:18px;font-weight:700;letter-spacing:.02em}
.ld-top span{font-size:12px;color:var(--dim2)}
.ld-main{position:relative;flex:1;min-height:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;padding:0 16px 76px}
.ld-rm{display:none}

.ld .stage{position:relative;flex:none;width:var(--W);height:var(--W)}
/* 平均色光晕：最上面那张封面的平均色，两层交叉淡入淡出 */
.ld-glow{position:absolute;left:-40%;top:-40%;width:180%;height:180%;border-radius:50%;opacity:0;pointer-events:none;transition:opacity 1.6s ease}
.ld-glow.on{opacity:1}

/* ---- 机台 ---- */
.ld .cab{position:absolute;inset:0;transform-origin:50% 50%;transition:transform .7s cubic-bezier(.25,.55,.2,1),opacity .45s .12s}
.ld .bezel{position:absolute;inset:1.5%;border-radius:50%;
  background:radial-gradient(circle,#14141b 0 80%,#101016 92%,#0d0d12 100%);
  box-shadow:0 0 0 1px rgba(255,255,255,.07),0 30px 80px rgba(0,0,0,.55),inset 0 1px 0 rgba(255,255,255,.05)}
.ld .screen{position:absolute;inset:10%;border-radius:50%;
  background:radial-gradient(circle at 50% 42%,#181820 0%,#0e0e13 58%,#08080b 100%);
  box-shadow:0 0 0 1px rgba(255,255,255,.08),inset 0 0 0 1px rgba(0,0,0,.6),inset 0 0 calc(var(--W) * .08) rgba(0,0,0,.7)}
/* 封面轨道：整圈很慢地匀速转（96 秒一圈），每张封面反向转同样的角度，始终正着；边长 --os 由 ring.js 按 orbitSize 写（手机上至少 40px） */
.ld .orbit{position:absolute;inset:0;transition:opacity .9s}
.ld .oc{position:absolute;left:0;top:0;width:var(--os,calc(var(--W) * .082));height:var(--os,calc(var(--W) * .082));border-radius:3px;background:#1a1a22 center/cover no-repeat;opacity:.5;
  box-shadow:0 2px 10px rgba(0,0,0,.5);will-change:transform}

/* ---- 进度光环：一个 SVG 圆（r 46、pathLength 1），stroke-dasharray 1，ring.js 每帧只改 strokeDashoffset = 1 − 进度；
   旋转 −90° 让起点在 12 点钟、顺时针走。底下一圈暗轨道、起点圆头、走在最前面的光点 ---- */
.ld .halo{position:absolute;inset:0;transition:opacity .9s}
.ld .track{position:absolute;left:calc(50% - var(--ro));top:calc(50% - var(--ro));width:calc(var(--ro) * 2);height:calc(var(--ro) * 2);border-radius:50%;
  border:var(--sw) solid rgba(255,255,255,.07)}
.ld .halo-svg{position:absolute;left:calc(50% - var(--rh) * 50 / 46);top:calc(50% - var(--rh) * 50 / 46);width:calc(var(--rh) * 100 / 46);height:calc(var(--rh) * 100 / 46);
  overflow:visible;transform:rotate(-90deg);filter:drop-shadow(0 0 calc(var(--sw) * 1.1) rgba(246,228,182,.55))}
.ld .arc{fill:none;stroke:var(--gold);stroke-width:1.25;stroke-linecap:butt;stroke-dasharray:1;stroke-dashoffset:1}
.ld .track::after,.ld .head-rot::after{content:"";position:absolute;border-radius:50%;opacity:0;transition:opacity .5s}
.ld .track::after{left:calc(50% - var(--sw) / 2);top:calc(var(--sw) * -1);width:var(--sw);height:var(--sw);background:var(--gold);
  box-shadow:0 0 calc(var(--sw) * 1.6) calc(var(--sw) * .1) rgba(246,228,182,.55)}
.ld .head-rot{position:absolute;inset:0;transform-origin:50% 50%;will-change:transform}
.ld .head-rot::after{left:50%;top:calc(50% - var(--rh));width:calc(var(--sw) * 1.7);height:calc(var(--sw) * 1.7);margin:calc(var(--sw) * -.85) 0 0 calc(var(--sw) * -.85);background:var(--gold-hi);
  box-shadow:0 0 calc(var(--sw) * 1.4) calc(var(--sw) * .4) rgba(255,250,232,.85),0 0 calc(var(--sw) * 4.5) calc(var(--sw) * 1.2) rgba(246,228,182,.4)}
body.live .ld .track::after,body.live .ld .head-rot::after{opacity:1}

/* ---- 8 个按键：光环走过就亮 ---- */
.ld .keys{position:absolute;inset:0;transition:opacity .9s}
.ld .key{position:absolute;left:50%;top:50%;width:var(--kd);height:var(--kd);margin:calc(var(--kd) / -2) 0 0 calc(var(--kd) / -2);border-radius:50%;
  transform:rotate(var(--a)) translateY(calc(var(--W) * -.468));
  background:radial-gradient(circle at 50% 35%,#24242d,#141419);box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.14),0 2px 6px rgba(0,0,0,.6)}
.ld .key::after{content:"";position:absolute;inset:0;border-radius:50%;opacity:0;transition:opacity .8s ease;
  background:radial-gradient(circle at 50% 40%,#fffae8 0 28%,#f6e4b6 62%,#cdb886 100%);box-shadow:0 0 calc(var(--kd) * .55) calc(var(--kd) * .08) rgba(246,228,182,.6)}
.ld .key.on::after{opacity:1}

/* ---- 他的封面：飞进来的、叠着的（最上面一张最大，后面的往上露边、变小、变淡） ---- */
.ld .cards{position:absolute;inset:0;z-index:3;pointer-events:none}
.ld .card{position:absolute;left:50%;top:50%;width:var(--S);height:var(--S);margin:calc(var(--S) / -2) 0 0 calc(var(--S) / -2);border-radius:5px;
  background:#1a1a22 center/cover no-repeat;opacity:0;will-change:transform,opacity;
  transition:transform .65s var(--ease),opacity .65s ease}
.ld .card.fly{transition:none;z-index:30!important}

/* ---- 圆心：摞（下面是随数量变厚的 .depth）+ 计数 + 百分比 + 阶段文字 ---- */
.ld .core{position:absolute;left:50%;top:50%;z-index:4;width:calc(var(--W) * .5);transform:translate(-50%,-50%);display:flex;flex-direction:column;align-items:center;transition:opacity .25s}
.ld .slot{position:relative;width:var(--S);height:var(--S);margin-top:calc(var(--S) * .22);flex:none;border-radius:5px;display:flex;align-items:center;justify-content:center;
  font-size:max(10px,calc(var(--W) * .018));color:var(--dim3);letter-spacing:.06em}
.ld .slot::before{content:"";position:absolute;inset:0;border-radius:inherit;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.025);transition:opacity .5s}
.ld .slot::after{content:"你的封面";position:relative;transition:opacity .5s}
.ld .slot.has::before,.ld .slot.has::after{opacity:0}
/* 摞的厚度：一叠卡边，ring.js 只改 transform: scaleY(stackScale(…)) */
.ld .depth{position:absolute;left:5%;right:5%;top:calc(100% - 2px);height:calc(var(--S) * .12);border-radius:0 0 4px 4px;transform-origin:50% 0;transform:scaleY(.35);
  background:repeating-linear-gradient(180deg,rgba(255,255,255,.2) 0 1px,rgba(20,20,27,.9) 1px 3px);box-shadow:0 4px 10px rgba(0,0,0,.45);opacity:0;transition:transform .5s var(--ease),opacity .5s}
.ld .slot.has .depth{opacity:1}
.ld .count{margin:calc(var(--S) * .14) 0 0;font-size:max(11px,calc(var(--W) * .021));font-weight:600;letter-spacing:.04em;color:var(--dim2);white-space:nowrap}
.ld .count[hidden]{display:block!important;opacity:0}
.ld .readout{position:relative;display:flex;flex-direction:column;align-items:center;margin-top:calc(var(--W) * .02)}
.ld .pct{display:flex;align-items:baseline;gap:2px;height:calc(var(--W) * .088);font-weight:800;line-height:1;transition:opacity .4s;
  filter:drop-shadow(0 0 calc(var(--W) * .03) rgba(226,206,150,.32))}
.ld .pct span{font-size:calc(var(--W) * .105);line-height:.84;letter-spacing:-.01em}
.ld .pct small{font-size:calc(var(--W) * .042);font-weight:700;color:var(--gold);opacity:.85}
.ld .phase{margin:calc(var(--W) * .016) 0 0;max-width:100%;font-size:max(12px,calc(var(--W) * .022));font-weight:500;color:var(--dim);white-space:nowrap;text-align:center;transition:opacity .4s}
.ld .core-fail{position:absolute;left:50%;top:0;width:max-content;max-width:calc(var(--W) * .6);transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;gap:calc(var(--W) * .012);opacity:0;transition:opacity .5s .2s;pointer-events:none}
.ld .core-fail b{font-size:max(15px,calc(var(--W) * .032));font-weight:900;text-align:center}
.ld .fx{width:calc(var(--W) * .068);height:calc(var(--W) * .068);display:flex;align-items:center;justify-content:center;border-radius:50%;font:800 calc(var(--W) * .046)/1 var(--num,'Barlow Condensed',sans-serif);font-style:normal;
  color:#17130a;background:var(--floor);box-shadow:0 0 calc(var(--W) * .04) rgba(255,210,122,.35)}
.ld .bar{display:none}

/* ---- 机台下面：剩余时间 + 六个阶段；失败时换成说明和按钮（同一格叠放，交叉淡入淡出） ---- */
.ld-below{position:relative;z-index:1;width:min(100%,720px);display:grid;transition:opacity .25s}
.ld-below>*{grid-area:1/1}
.ld .info{display:flex;flex-direction:column;align-items:center;gap:10px;transition:opacity .4s}
.ld .eta{margin:0;min-height:1.5em;font-size:14px;color:var(--ink);font-variant-numeric:tabular-nums}
.ld .steps{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;justify-content:center;gap:6px 18px}
.ld .st{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--dim3);white-space:nowrap}
.ld .st::before,.ld .st::after{content:"";width:8px;height:8px;flex:none;border-radius:50%}
.ld .st::before{box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.22)}
.ld .st::after{order:-1;margin-right:-15px;background:var(--gold);box-shadow:0 0 8px rgba(246,228,182,.6);opacity:0;transition:opacity .4s}
.ld .st em{font-style:normal;font-family:var(--num,'Barlow Condensed',sans-serif);font-size:13px;font-weight:600;color:var(--dim2)}
.ld .st.now{color:var(--hi)}
.ld .st.now::before{box-shadow:inset 0 0 0 1.5px var(--gold)}
.ld .st.ok{color:var(--dim2)}
.ld .st.ok::after{opacity:1}
/* 失败说明叠在阶段行的位置上，出现时整列不跳 */
.ld .failbox{display:flex;flex-direction:column;align-items:center;gap:14px;opacity:0;visibility:hidden;transition:opacity .5s .25s,visibility 0s .75s;text-align:center}
.ld .failbox p{margin:0;max-width:40em;white-space:pre-line;text-wrap:balance;font-size:13.5px;line-height:1.65;color:var(--dim)}
.ld-btn{height:42px;padding:0 22px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:9px;
  background:var(--ink);color:var(--bg);font:700 14px var(--sc,'PingFang SC','Noto Sans SC',system-ui,sans-serif);cursor:pointer;white-space:nowrap}
.ld-btn:hover{background:#fff}
.ld-btn:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.ld-btn:disabled{opacity:.45;cursor:not-allowed}
.ld-btn[hidden]{display:none}
.ld .note{position:relative;margin:2px 0 0;max-width:36em;text-wrap:balance;font-size:12px;line-height:1.6;color:var(--dim3);text-align:center;transition:opacity .25s}

/* ---- 排队：光环低亮度缓慢呼吸（只动 opacity，不闪），圆心写「前面还有 N 人」 ---- */
@keyframes breathe{0%,100%{opacity:.4}50%{opacity:.85}}
body.queued .halo{animation:breathe 4.8s ease-in-out infinite}
body.queued .ld .pct{opacity:.35}

/* ---- 等待（维护、退避）：光环停在当前位置，整体变暗；轨道由 ring.js 用 WAAPI 暂停 ---- */
body.waiting .ld .halo{opacity:.45}
body.waiting .ld .keys{opacity:.5}
body.waiting .ld .orbit{opacity:.35}
body.waiting .ld .pct{opacity:.45}

/* ---- 失败：转动缓缓停住，光环和按键变暗，中间换成说明和按钮 ---- */
body.failed .ld .halo{opacity:.3}
body.failed .ld .keys{opacity:.45}
body.failed .ld .orbit{opacity:.5}
body.failed .ld .head-rot::after{opacity:0}
body.failed .ld .pct,body.failed .ld .phase{opacity:0}
body.failed .ld .core-fail{opacity:1}
body.failed .ld .info{opacity:0}
body.failed .ld .failbox{opacity:1;visibility:visible;transition:opacity .5s .25s,visibility 0s}
body.failed .ld .note{opacity:0}

/* ---- 完成：机台放大淡出（圆展开），叠在最上面的封面飞到 B50 页里它的格子，50 格从圆心往外亮起 ---- */
body.expand .ld .cab{transform:scale(1.6);opacity:0}
body.expand .ld .core,body.expand .ld-below,body.expand .ld .note,body.expand .ld-top{opacity:0}
body.prep .ld-bg{opacity:.995}
body.expand .ld-bg,body.expand .ld-glow{opacity:0;transition:opacity .5s .05s}
body.expand .ld{pointer-events:none}

/* ================= 50 格封面墙：减弱动效时是静态墙；展开时（.ov）盖在真实 B50 格子上 ================= */
.ld-wall{display:none;position:relative;width:min(100%,1080px);flex-direction:column;gap:10px}
.ld-grid{display:grid;grid-template-columns:repeat(9,minmax(0,1fr));gap:6px}
.ld-grid::before{content:"B15 新曲";grid-column:1/-1;font:700 13px/1.4 var(--num,'Barlow Condensed',sans-serif);letter-spacing:.06em;color:var(--dim2)}
.ld-grid+.ld-grid::before{content:"B35 旧曲";margin-top:8px}
.ld-wall .t{position:relative;display:block;aspect-ratio:1/1;border-radius:3px;background:#1a1a22 center/cover no-repeat}
/* 静态墙：原有的共享封面压暗；他的封面下载好了就在格子里亮起来（只有透明度变化） */
.ld-wall .t::before{content:"";position:absolute;inset:0;border-radius:inherit;background:rgba(12,12,16,.84)}
.ld-wall .t::after{content:"";position:absolute;inset:0;border-radius:inherit;background:var(--u) center/cover no-repeat;opacity:0;transition:opacity .6s}
.ld-wall .t.got::after{opacity:1}
/* 展开：每格是 100px 的方块，ring.js 按 tileRect 写 transform（平移 + 缩放）；--d 是按离圆心远近排的延迟 */
.ld-wall.ov{display:block;position:fixed;inset:0;z-index:2;width:auto;pointer-events:none}
.ld-wall.ov .ld-grid{display:block}
.ld-wall.ov .ld-grid::before,.ld-wall.ov .t::before,.ld-wall.ov .t::after{display:none}
.ld-wall.ov .t{position:absolute;left:0;top:0;width:100px;height:100px;aspect-ratio:auto;transform-origin:0 0;opacity:0;
  transition:opacity .36s ease var(--d,0ms)}
.ld-wall.ov .t.first{transition-duration:.18s}
body.expand .ld-wall.ov .t.on{opacity:1}
body.expand.ld-out .ld-wall.ov .t.on{opacity:0;transition:opacity .2s ease}

/* ================= 减弱动效：不显示机台，进度卡片（百分比、阶段、进度条、阶段列表）+ 静态封面墙 ================= */
body.rm .ld .stage{display:none}
body.rm .ld-main{justify-content:flex-start;padding:4px 16px 48px}
body.rm .ld-rm{display:flex;flex-direction:column;gap:12px;width:min(100%,1080px);padding:22px 22px 20px;border-radius:16px;
  background:radial-gradient(ellipse 300px 200px at 20% 0%,rgba(246,228,182,.1),rgba(246,228,182,0)),var(--card);border:1px solid rgba(246,228,182,.16)}
body.rm .ld-wall{display:flex}
body.rm .ld .core{position:static;transform:none;width:auto;align-items:stretch}
body.rm .ld .slot{display:none}
body.rm .ld .count{margin:0;order:2;font-size:13px}
body.rm .ld .readout{align-items:flex-start;margin:0}
body.rm .ld .pct{height:64px;margin-left:-2px}
body.rm .ld .pct span{font-size:80px;line-height:64px}
body.rm .ld .pct small{font-size:26px}
body.rm .ld .phase{font-size:14px;margin-top:10px;white-space:normal;text-align:left}
body.rm .ld .core-fail{left:0;transform:none;flex-direction:row;align-items:center;gap:12px;height:64px;max-width:none}
body.rm .ld .core-fail b{font-size:22px;text-align:left}
body.rm .ld .fx{width:36px;height:36px;font-size:24px}
body.rm .ld .bar{display:block;position:relative;order:3;width:100%;height:6px;margin-top:14px;border-radius:3px;background:rgba(255,255,255,.1);overflow:hidden}
body.rm .ld .bar i{position:absolute;inset:0;border-radius:3px;background:linear-gradient(90deg,#ceb880,#f6e4b6 50%,#fffae8);transform-origin:0 50%;transform:scaleX(0)}
body.rm.failed .ld .bar i{opacity:.35}
body.rm .ld-below{width:auto}
body.rm .ld .info{align-items:flex-start}
body.rm .ld .eta{font-size:13px;color:var(--dim)}
body.rm .ld .steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));justify-content:start;gap:7px 12px;padding-top:12px;border-top:1px solid var(--line);width:100%}
body.rm .ld .failbox{align-items:flex-start;text-align:left}
body.rm .ld .failbox p{text-wrap:wrap}
body.rm .ld .note{margin:0;text-align:left;text-wrap:wrap}
body.rm .ld .note br{display:none}
body.rm.failed .ld .note{display:none}
body.rm .ld *,body.rm .ld *::before,body.rm .ld *::after{transition:none!important;animation:none!important}
@media (prefers-reduced-motion: reduce){
  body.queued .halo{animation:none}
  .ld *,.ld *::before,.ld *::after{animation:none!important;transition:none!important}
}

/* ================= 窄屏 ================= */
@media (max-width:600px){
  .ld-top{height:52px;padding:0 16px}
  .ld-top b{font-size:16px}
  .ld-main{padding:0 16px 96px;gap:14px}
  .ld .steps{display:grid;grid-template-columns:repeat(3,auto);justify-content:center;gap:8px 16px}
  .ld .st{font-size:11.5px}
  .ld .eta{font-size:13px}
  .ld .note{font-size:11.5px;padding:0 4px}
  .ld-grid{gap:4px}
  body.rm .ld .steps{grid-template-columns:repeat(2,minmax(0,1fr))}
}
/* 手机：机台尽量占满宽度（两边各留 16），轨道封面至少 40px（ring.js orbitSize），圆心文字换行、不截短 */
@media (max-width: 480px){
  .ld{--W:calc(100vw - 32px)}
  .ld .stage{width:calc(100vw - 32px);height:calc(100vw - 32px)}
  .ld .core{width:calc(var(--W) * .46)}
  .ld .phase{white-space:normal;font-size:12.5px;line-height:1.4}
  .ld .count{font-size:11px}
}
@media (max-height:700px) and (min-width:601px){
  .ld .note{display:none}
}
