:root{
  --bg:#f4f5f7; --card:#fff; --line:#e3e5e9; --line2:#cbd0d8;
  --tx:#14181f; --tx2:#5b6472; --tx3:#8a94a3;
  --ac:#c2410c; --ac-bg:#fff5f0;
  --ok:#15803d; --ok-bg:#f0fdf4;
  --wn:#b45309; --wn-bg:#fffbeb;
  --bd:#b91c1c; --bd-bg:#fef2f2;
  --r:12px;
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0}
body{
  background:var(--bg);color:var(--tx);
  font:400 15px/1.6 -apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",system-ui,sans-serif;
  padding-bottom:env(safe-area-inset-bottom);
}

.hd{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:calc(12px + env(safe-area-inset-top)) 16px 12px;
  background:var(--card);border-bottom:1px solid var(--line);
  position:sticky;top:0;z-index:20;
}
.hd-l strong{display:block;font-size:17px;font-weight:600;letter-spacing:.2px}
.hd-l .sub{display:block;font-size:12px;color:var(--tx3);margin-top:1px}
.badge{
  flex:none;font-size:12px;padding:4px 9px;border-radius:999px;
  background:var(--ac-bg);color:var(--ac);border:1px solid #f6d9cd;font-weight:500;
}
/* 常驻版本号：让「手机跑的是哪一版」随时可见，不用再靠猜 */
.ver{font-weight:600;color:var(--ac);font-variant-numeric:tabular-nums}
/* 旧版本提示条：只在本机代码落后于服务器时出现 */
.upd{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin:14px 14px 0;padding:12px 14px;border-radius:var(--r);
  background:var(--wn-bg);border:1px solid #fcd9a4;
  font-size:13px;line-height:1.5;color:var(--wn);
}
.upd .btn{margin-left:auto;flex:none;white-space:nowrap}
.upd .btn + .btn{margin-left:8px}

/* ── 数据采集清单表 ── */
table.cap{width:100%;border-collapse:collapse;font-size:13px;margin-bottom:6px}
table.cap th{
  text-align:left;font-weight:600;color:var(--muted,#6b7280);
  padding:6px 8px;border-bottom:1px solid var(--line,#e5e7eb);white-space:nowrap;
}
table.cap td{padding:7px 8px;border-bottom:1px solid var(--line-soft,#f3f4f6);vertical-align:top;line-height:1.5}
table.cap tr:last-child td{border-bottom:none}
table.cap .c-k{color:var(--text,#111827);font-weight:500;white-space:nowrap}
table.cap .c-v{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}
table.cap .c-s{color:var(--muted,#6b7280);font-size:12.5px}
table.cap tr.ok .c-v{color:#15803d}
table.cap tr.warn .c-v{color:#b45309}
table.cap tr.bad .c-v{color:#b91c1c}
/* ⚠️ 窄屏必须转成卡片式 —— 与下面的 .pl-table 一样的处理。
   实测（360px 视口）：这张表被 .c-k/.c-v 的 white-space:nowrap 撑到 531px，
   整页横向溢出 186px，手机上得左右拖。老师主要用手机看，这一条不能省。 */
@media(max-width:560px){
  table.cap thead{display:none}
  table.cap tr{display:block;padding:8px 0;border-bottom:1px solid var(--line)}
  table.cap td{display:inline;border-bottom:none;padding:0;white-space:normal}
  table.cap .c-k{display:block;white-space:normal;margin-bottom:1px}
  table.cap .c-v{margin-right:8px}
  table.cap tr:last-child{border-bottom:none}
}

/* ── 摄像头录制面板 ── */
.cam-open{width:100%;margin-top:10px;justify-content:center}
.camwrap{position:fixed;inset:0;z-index:100;background:#000;display:flex;flex-direction:column}
.camwrap[hidden]{display:none}
#camView{flex:1;min-height:0;width:100%;object-fit:contain;background:#000}
.cam-hd{
  position:absolute;top:0;left:0;right:0;display:flex;align-items:flex-start;gap:10px;
  padding:calc(10px + env(safe-area-inset-top)) 14px 14px;color:#fff;font-size:12.5px;
  background:linear-gradient(rgba(0,0,0,.62),transparent);
}
.cam-stat{flex:1;line-height:1.5;font-variant-numeric:tabular-nums}
.cam-stat b{color:#7dd3fc;font-weight:600}
.cam-stat em{font-style:normal;color:#fca5a5}
.cam-x{flex:none;background:rgba(255,255,255,.16);border:0;color:#fff;font-size:13px;padding:7px 12px;border-radius:8px}
.cam-guide{
  position:absolute;left:0;right:0;bottom:104px;text-align:center;
  color:#fde68a;font-size:13px;line-height:1.5;padding:0 22px;text-shadow:0 1px 6px #000;
}
.cam-ft{
  display:flex;align-items:center;gap:14px;
  padding:16px 18px calc(20px + env(safe-area-inset-bottom));background:#000;
}
.cam-fps{display:flex;gap:6px;flex:1}
.cam-fps button{
  background:rgba(255,255,255,.12);border:0;color:#cbd5e1;font-size:12px;
  padding:8px 11px;border-radius:8px;font-variant-numeric:tabular-nums;
}
.cam-fps button.on{background:#e11d48;color:#fff}
.cam-fps button:disabled{opacity:.35}
.cam-rec{flex:none;width:66px;height:66px;border-radius:50%;border:4px solid #fff;background:#e11d48}
.cam-rec.on{background:#fff;box-shadow:inset 0 0 0 7px #e11d48}
.cam-time{flex:1;text-align:right;color:#94a3b8;font-size:12.5px;font-variant-numeric:tabular-nums}

main{padding:14px 12px 24px;display:flex;flex-direction:column;gap:14px;max-width:720px;margin:0 auto}

.card{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:15px 15px 16px;
}
.card h2{
  margin:0 0 13px;font-size:15px;font-weight:600;display:flex;align-items:center;gap:8px;
}
.card h2 i{
  font-style:normal;width:20px;height:20px;flex:none;border-radius:6px;
  background:var(--ac-bg);color:var(--ac);font-size:12px;font-weight:600;
  display:flex;align-items:center;justify-content:center;
}

/* 导入 */
.drop{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
  border:1.5px dashed var(--line2);border-radius:var(--r);
  padding:26px 16px;background:#fafbfc;cursor:pointer;text-align:center;
}
.drop:active{background:#f1f3f6}
.drop input{display:none}
.drop-t{font-size:15px;font-weight:500;color:var(--ac)}
.drop-s{font-size:12px;color:var(--tx3)}
.meta{
  margin-top:10px;font-size:12px;color:var(--tx2);background:#f7f8fa;
  border-radius:8px;padding:8px 10px;word-break:break-all;
}

.grid3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:14px}
/* 两列网格：用于「速度档 + 模型档」这种成对但不需要第三列的场合 */
.grid2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:14px}
.fld{display:flex;flex-direction:column;gap:5px}
.fld span{font-size:12px;color:var(--tx2)}
.fld input,.fld select{
  width:100%;padding:10px 10px;font-size:15px;color:var(--tx);
  border:1px solid var(--line2);border-radius:9px;background:#fff;
  font-family:inherit;min-height:44px;
}
.fld input:focus,.fld select:focus{outline:2px solid #f6d9cd;outline-offset:-1px;border-color:var(--ac)}

.hint{font-size:12px;color:var(--tx3);margin:11px 0 0;line-height:1.55}
.muted{color:var(--tx3)}

.row{display:flex;align-items:center;gap:12px;margin-top:14px}
.row-end{justify-content:flex-end;margin-top:0}
.btn{
  font-family:inherit;font-size:15px;font-weight:500;color:var(--tx);
  background:#fff;border:1px solid var(--line2);border-radius:10px;
  padding:0 16px;min-height:44px;cursor:pointer;
}
.btn.primary{background:var(--ac);border-color:var(--ac);color:#fff;flex:1}
.btn.primary:disabled{opacity:.4}
.btn.sm{min-height:36px;font-size:13px;padding:0 12px;border-radius:8px}
.btn:active{transform:translateY(1px)}
.prog-t{font-size:13px;color:var(--tx2)}
.bar{height:5px;background:#eceef2;border-radius:999px;overflow:hidden;margin-top:11px}
.bar i{display:block;height:100%;width:0;background:var(--ac);transition:width .18s}
.err{
  margin-top:11px;font-size:13px;line-height:1.6;color:var(--bd);
  background:var(--bd-bg);border:1px solid #f6cfcf;border-radius:9px;padding:10px 12px;
}

/* 播放器 */
.player{position:relative;border-radius:10px;overflow:hidden;background:#0d1117;aspect-ratio:16/10}
.player video{width:100%;height:100%;display:block;object-fit:contain}
.player canvas{position:absolute;left:0;top:0;pointer-events:none}
.phases{position:absolute;left:0;right:0;bottom:0;height:5px;display:flex}
.phases i{height:100%;display:block}
.ctrl{display:flex;align-items:center;gap:9px;margin-top:11px;flex-wrap:wrap}
.tcode{font-size:12px;color:var(--tx3);margin-left:auto;font-variant-numeric:tabular-nums}
/* 球状态带：球仍在手中 → 出手瞬间 → 球已出手。
   出手角、出手点高度、超越器械三项都以「出手那一瞬」为刻度原点，
   不把这条带画出来，老师就看不出某个数值是在哪一帧量出来的。 */
.ballstate{display:flex;height:9px;border-radius:5px;overflow:hidden;margin:13px 0 0;background:rgba(128,128,128,.16)}
.ballstate i{display:block;height:100%}
/* 球检测命中带：绿色 = 这一帧真的检到了球。
   覆盖率只是个数字，看不出断在哪里；画出来才知道是「开头没检到」还是「出手后就丢了」。 */
.ballhits{display:flex;height:5px;margin-top:3px;border-radius:3px;overflow:hidden;background:rgba(128,128,128,.12)}
.ballhits i{display:block;height:100%;background:#10b981}
input[type=range]{width:100%;margin:12px 0 6px;accent-color:var(--ac)}
.phaseLeg{display:flex;flex-wrap:wrap;gap:10px 14px;font-size:11.5px;color:var(--tx2)}
.phaseLeg span{display:flex;align-items:center;gap:5px}
.phaseLeg b{width:9px;height:9px;border-radius:2px;display:block}

/* KPI */
.kpis{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.kpi{background:#f7f8fa;border-radius:10px;padding:11px 12px;border:1px solid transparent}
.kpi.ok{background:var(--ok-bg);border-color:#d6f0df}
.kpi.warn{background:var(--wn-bg);border-color:#f7e3bd}
.kpi.bad{background:var(--bd-bg);border-color:#f6cfcf}
.k-l{display:block;font-size:12px;color:var(--tx2)}
.k-v{display:block;font-size:21px;font-weight:600;letter-spacing:-.3px;margin:3px 0 1px;font-variant-numeric:tabular-nums}
.k-s{display:block;font-size:11.5px;color:var(--tx3);line-height:1.45}
/* 就地标记：被判「识别无效 / 待核对 / 已修正」时贴在指标名后面。
   刻意不用红色大块 —— 它说的不是"这个学生差"，是"这个数别用"。 */
.k-bad,.k-flag{display:inline-block;margin-left:6px;font-size:10.5px;font-weight:500;
  padding:1px 6px;border-radius:5px;vertical-align:1px}
.k-bad{background:var(--bd-bg);color:var(--bd);border:1px solid #f6cfcf}
.k-flag{background:var(--wn-bg);color:var(--wn);border:1px solid #f7e3bd}
.k-void{color:var(--tx3)}

/* 识别有效性校验表 */
.pl-sum{font-size:13px;line-height:1.6;border-radius:9px;padding:10px 12px;margin-bottom:8px}
.pl-sum.good{background:var(--ok-bg);color:#1d6b3a}
.pl-sum.bad{background:var(--bd-bg);color:var(--bd)}
.pl-note{font-size:11.5px;color:var(--tx3);line-height:1.55;margin-bottom:11px}
.pl-table{width:100%;border-collapse:collapse;font-size:12px}
.pl-table th{text-align:left;font-weight:500;color:var(--tx3);font-size:11px;
  padding:6px 8px;border-bottom:1px solid var(--line);white-space:nowrap}
.pl-table td{padding:7px 8px;border-bottom:1px solid var(--line);vertical-align:top;line-height:1.5}
.pl-table tr:last-child td{border-bottom:none}
.pl-k{font-weight:500;white-space:nowrap}
.pl-v{font-variant-numeric:tabular-nums;white-space:nowrap}
.pl-r{font-variant-numeric:tabular-nums;color:var(--tx3);white-space:nowrap}
.pl-b{color:var(--tx3);font-size:11.5px}
.pl-tag{display:inline-block;font-size:10.5px;padding:1px 6px;border-radius:5px;white-space:nowrap}
.pl-tag.bad{background:var(--bd-bg);color:var(--bd);border:1px solid #f6cfcf}
.pl-tag.warn{background:var(--wn-bg);color:var(--wn);border:1px solid #f7e3bd}
.pl-tag.ok{background:var(--ok-bg);color:#1d6b3a;border:1px solid #d6f0df}
.pl-tag.mute{background:#f1f3f6;color:var(--tx3);border:1px solid var(--line)}
.pl-table tr.bad .pl-k,.pl-table tr.bad .pl-v{color:var(--bd)}
@media(max-width:560px){
  .pl-table thead{display:none}
  .pl-table td{display:block;border-bottom:none;padding:2px 0}
  .pl-table tr{display:block;padding:9px 0;border-bottom:1px solid var(--line)}
  .pl-r:before{content:'生理范围 ';color:var(--tx3)}
}

/* 诊断 */
.summary{font-size:13.5px;line-height:1.7;background:#f7f8fa;border-radius:10px;padding:12px 13px;margin-bottom:13px}
.summary p{margin:0 0 8px}
.summary p:last-child{margin:0}
.summary strong{font-weight:600;color:var(--ac)}

.finding{border:1px solid var(--line);border-left:3px solid var(--wn);border-radius:9px;padding:12px 13px;margin-bottom:10px}
.finding.bad{border-left-color:var(--bd)}
.finding h3{margin:0 0 6px;font-size:14px;font-weight:600;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.finding h3 em{font-style:normal;font-size:11.5px;font-weight:500;color:var(--tx3);background:#f1f3f6;padding:2px 7px;border-radius:6px}
.finding .nums{font-size:12.5px;color:var(--tx2);margin-bottom:8px;font-variant-numeric:tabular-nums}
.finding .msg{font-size:13.5px;margin-bottom:9px}
.finding .fa{font-size:13px;color:var(--tx2);margin:0 0 7px}
.finding .fa b{color:var(--tx);font-weight:500}
.finding ul{margin:0;padding-left:19px;font-size:13px;line-height:1.7}
.finding ul li{margin-bottom:3px}
.src{font-size:11.5px;color:var(--tx3);margin-top:9px;padding-top:8px;border-top:1px dashed var(--line);line-height:1.55}

/* ── 课堂运动处方 ──
   版面规矩（老师明确要求）：常驻说明一律不收 —— 所以「怎么做/练多少/怎么算练对」
   用固定标签 + 行内排版，靠标签本身分辨，不靠引言和小字解释。
   次要内容（单元计划、安全、依据）收进 details，是要用时才展开的东西。 */
.rx-head{background:#f7f9fc;border:1px solid var(--line);border-left:3px solid var(--ac);border-radius:9px;padding:11px 13px;margin-bottom:12px;font-size:13.5px;line-height:1.65}
.rx-head b{font-weight:600;color:var(--ac)}
.rx-chain{background:#fff8f2;border:1px solid #f4d9c4;border-radius:9px;padding:11px 13px;margin-bottom:13px}
.rx-chain h4{margin:0 0 7px;font-size:13.5px;font-weight:600;color:#9a3412}
.rx-chain .lead{font-size:12.5px;color:var(--tx2);margin:0 0 7px}
.rx-chain ol{margin:0;padding-left:20px;font-size:12.5px;line-height:1.75;color:var(--tx2)}
/* ══ 老师肉眼勾选（处方第二入口）══
   放在处方上方。算法判不了的那批易错（持球手型、腕指拨球、双脚离地、踩线、
   助跑、脱手、肩柔韧）只能由老师判 —— 勾了照样出处方。
   用 details 收起：默认不展开，不占版面；勾过之后自动展开（renderManual 里加 open）。 */
.manual{margin:0 0 14px;border:1px solid var(--line);border-radius:9px;background:var(--card)}
.manual>summary{cursor:pointer;padding:10px 12px;font-size:13px;font-weight:600;color:var(--tx)}
.manual[open]>summary{border-bottom:1px solid var(--line)}
.manual .hint{margin:10px 12px 4px}
.m-list{display:grid;gap:4px;padding:4px 12px 12px}
.m-item{display:flex;align-items:baseline;gap:8px;font-size:12.5px;
  padding:6px 8px;border-radius:7px;cursor:pointer}
.m-item:hover{background:#f7f8fa}
.m-item.on{background:var(--ac-bg)}
.m-item input{margin:0;flex:none}
.m-item .m-t{font-weight:500;color:var(--tx)}
/* 出处右对齐、小一号 —— 它是"让你敢信"的凭据，不是主信息 */
.m-item .m-f{font-size:11px;color:var(--tx3);margin-left:auto;text-align:right}
/* ⚠️ 窄屏：出处移到第二行。否则长出处（如「课标配套教材表 4-3-2；南京中考规则」）
   会把标题挤成一行两三个字，跟处方行踩过的是同一个坑。 */
@media(max-width:560px){
  .m-item{flex-wrap:wrap}
  .m-item .m-f{margin-left:0;text-align:left;flex-basis:100%;padding-left:22px}
}
.rx-block{border:1px solid var(--line);border-left:3px solid var(--ac);border-radius:9px;padding:12px 13px;margin-bottom:12px}
.rx-block.aux{border-left-color:#94a3b8}
.rx-block h4{margin:0 0 6px;font-size:14px;font-weight:600;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.rx-block h4 em{font-style:normal;font-size:11.5px;font-weight:500;padding:2px 7px;border-radius:6px;background:#eef4ff;color:var(--ac)}
.rx-block.aux h4 em{background:#f1f3f6;color:var(--tx3)}
.rx-block .ev{font-size:12.5px;color:var(--tx2);margin-bottom:7px;font-variant-numeric:tabular-nums}
.rx-block .why{font-size:13px;line-height:1.7;color:var(--tx2);margin:0 0 9px}
.rx-item{border-top:1px dashed var(--line);padding:10px 0 3px}
.rx-item:first-of-type{border-top:none;padding-top:2px}
.rx-item .nm{font-size:13.5px;font-weight:600;margin-bottom:6px}
/* ⚠️ 类名必须是 rx-ln，不能图省事叫 row。
   styles.css:145 的 `.row{display:flex;align-items:center;gap:12px}` 是给表单行/按钮行用的，
   处方卡若复用 row，那一行的 display 就被改成 flex 且没被这里覆盖 —— 后果：
   整行被拆成若干 flex 项横排，`<u>怎么做</u>` 被 flex-shrink 压成竖排单字，
   正文也被 gap 切成几栏。宽屏文字短看不出来，窄屏（老师用手机看）直接崩。
   因此这里除了改类名，还**显式声明 display:block** 兜底：即便将来又有人加
   一条通用 `.row{...}`，rx-ln 也不会被误伤。 */
.rx-item .rx-ln{display:block;font-size:12.5px;line-height:1.7;margin:0 0 3px}
.rx-item .rx-ln u{text-decoration:none;color:var(--tx3);font-weight:500;margin-right:4px}
.rx-item .rx-ln.k u{color:#0e7490}
/* ⚠️ 原先这里写的是 white-space:nowrap —— 宽屏没问题，窄屏会把容器撑破：
   实测 360px 视口下「训练学 / 解剖学 / 权威机构」这类标签宽 143px，
   行内放不下就顶出右边界，处方区 scrollWidth 311 > 289。改为允许换行。 */
.rx-item .rx-ln em{font-style:normal;font-size:11px;padding:1px 6px;border-radius:5px;background:#f1f3f6;color:var(--tx3);margin-left:6px;white-space:normal;display:inline-block;max-width:100%;vertical-align:bottom}
.rx-lesson{font-size:13px;line-height:1.7}
.rx-lesson .p{border-left:2px solid var(--line);padding-left:11px;margin-bottom:9px}
.rx-lesson .p b{font-weight:600}
.rx-lesson ul{margin:3px 0 0;padding-left:18px;font-size:12.5px;color:var(--tx2)}
.rx-gate{font-size:12.5px;line-height:1.75;font-variant-numeric:tabular-nums}
.rx-gate .g{border-bottom:1px dashed var(--line);padding:5px 0}
.rx-gate .g:last-child{border-bottom:none}
/* rx-note：处方里的补充说明（置信度提示、复测怎么做）。
   ⚠️ 这两处从 v049 起就写了 <p class="rx-note">，但 styles.css 里始终没有这条 ——
   等于"写了类名、以为有个样式，其实从未生效"，与「算了不说=没算」同源。
   规矩：**用了类名就必须有样式**，否则要么删掉类名、要么把样式补上（这里补上）。
   左侧一道细线是为了和正文分开 —— 它们是"备注"，不该被读成结论。 */
.rx-note{font-size:12.5px;line-height:1.65;color:var(--tx2);
  margin:0 0 8px;padding-left:9px;border-left:2px solid var(--line)}
.rx-hold{font-size:12.5px;line-height:1.7;color:var(--tx2)}

/* ── 物理杠杆：这一项改善了射程能多多少（一行，说明"为什么先练它"）── */
.rx-block .lever{font-size:12px;line-height:1.6;margin:0 0 9px;padding:6px 9px;background:var(--ac-bg);border-radius:7px;color:var(--tx2)}
.rx-block .lever u{text-decoration:none;color:var(--ac);font-weight:600;margin-right:5px}
.rx-block .lever b{font-weight:600;color:var(--ac)}

/* ── 成因分流：同一个毛病，是"不会做"还是"条件不够"，练法不同 ── */
.rx-cause{margin-top:6px}
.rx-cause>.ch{display:flex;align-items:baseline;gap:7px;font-size:11.5px;color:var(--tx3);margin:10px 0 0;padding-bottom:4px;border-bottom:1px solid var(--line)}
.rx-cause>.ch b{font-size:12.5px;font-weight:600;color:var(--tx)}
.rx-cause>.ch span{flex:1;min-width:0}
.rx-cause>.ch em{font-style:normal;white-space:nowrap;color:var(--tx3)}
.rx-cause .rx-item:first-of-type{border-top:none;padding-top:6px}

/* ── 成因总览（这次练习里各成因各占几项）── */
.rx-causes{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:11.5px;color:var(--tx3);margin:0 0 12px}
.rx-causes .c{padding:2px 9px;border-radius:999px;background:var(--card);border:1px solid var(--line);color:var(--tx2)}
.rx-causes .c b{font-weight:600;color:var(--ac);margin-left:3px}
details.rx-more{margin-top:13px;border-top:1px dashed var(--line);padding-top:10px}
details.rx-more summary{font-size:12.5px;color:var(--ac);cursor:pointer;font-weight:500}
details.rx-more .inner{font-size:12.5px;line-height:1.7;color:var(--tx2);margin-top:9px}
details.rx-more h5{margin:12px 0 5px;font-size:12.5px;font-weight:600;color:var(--tx)}
details.rx-more h5:first-child{margin-top:0}
details.rx-more ul{margin:4px 0 0;padding-left:18px}

/* ── 结果页折叠区（2026-10-11 精简）──
   两类折叠共用一套外观：
     · .rx-fold     —— 结果页第 ④ 卡的四个「想细看」区（有效性/采集/合规/依据）
                       和处方卡里的辅助块
     · 处方卡那个「老师肉眼补充」也用 .rx-fold
   为什么统一：老师看到的第一眼要能认出"这是个能点开的抽屉"，
   三套样式各长各的，他反而不知道该点哪个。
   ⚠️ 这是**折叠**不是**删除** —— 老师觉得某个数不对劲时，原样都在。
      本项目纪律：「缺就标缺，不编造、不兜底」，折叠只是把"过程证据"
      从主结论前面挪到了后面，一条都没少。 */
details.rx-fold{
  margin:0 0 9px;border:1px solid var(--line);border-radius:10px;
  padding:11px 13px;background:#fafbfc;
}
details.rx-fold:last-child{margin-bottom:0}
details.rx-fold>summary{
  font-size:13px;color:var(--ac);cursor:pointer;font-weight:500;
  list-style:none;
}
details.rx-fold>summary::-webkit-details-marker{display:none}
details.rx-fold>summary::before{content:"▸ "}
details.rx-fold[open]>summary::before{content:"▾ "}
details.rx-fold .inner{margin-top:10px}
/* 辅助块折起来之后不要再套一层虚线框（会跟外层 details 的框重复） */
details.aux-fold .inner>.rx-block{border-top:0;padding-top:4px;margin-top:0}

/* ══════════════════════════════════════════════════════════════════
   ★★ 2026-10-11「说明开关」—— 结果页默认只给结论，解释按需展开
   ──────────────────────────────────────────────────────────────────
   老师的原话（附手机长截图 786×15948，约 12 屏）：
     「一节课就那么 45 分钟，分析引擎就要 20 秒，然后还有这么多文字，
       妈的看完都快下课了。我的要求很简单就是言简意赅，
       不需要的解释说明，全部去掉。学生只需要结论就行。」
   老师选定：「设一个开关，就是说明开关，默认关闭，点击后打开显示」。

   ── 为什么用 CSS 类开关，而不是每个渲染函数写两套分支 ──
   ① 渲染函数只负责「产出内容」，不操心「现在开没开」——
      否则每个函数都要接收一个 showWhy 参数，改一处漏一处。
   ② 切开关只是换 body 上的一个类名，**不重新渲染** ⇒ 瞬间完成、不卡顿。
   ③ 说明文字**始终在 HTML 里** ⇒ 自检可以断言「它一定在」，
      从根本上杜绝「收着收着就丢了」（本项目纪律：折叠≠删除）。
   ④ 打印/导出时只要给 body 加回这个类，说明全都在。

   ⚠️ 铁律：`class="why"` 只能加在**解释性文字**上。
      判定结论（「偏低」「到位」「识别无效」）**不许**加 ——
      那些是学生要看的结论，收起来就没意义了。

   ⚠️⚠️ 优先级陷阱（实现时必须知道）：
      现有规则里有 `.rx-item .rx-ln{display:block}`（specificity 0,2,0），
      而单写 `.why{display:none}` 只有 (0,1,0) —— **优先级更低，收起根本不生效**，
      且因为不报错，肉眼看不出问题（本项目最怕这种静默失效）。
      所以下面用 `.why` + 一个同样带两级的兜底选择器，把该收的都收到。
      实测方式：真浏览器里量 `.rx-item .rx-ln.why` 是否真的为 0 高。 */
.why{display:none}
body.show-why .why{display:block}
/* 处方里的说明行（器材/口令/出处/没器材时）—— 这两条专门压过 .rx-item .rx-ln */
.rx-item .rx-ln.why{display:none}
body.show-why .rx-item .rx-ln.why{display:block}
/* 指标卡里的口径行同理：.k-s 自己是 block，里面的 .why 要压过它 */
.kpi .k-s.why{display:none}
body.show-why .kpi .k-s.why{display:block}
/* 告警详情用的是 <span class="why">（main.js 里逐条 createElement 建的）。
   span 默认 inline，展开时改成 block —— 详情本来就该另起一行，
   而且 inline 元素上的 border-left 撑不起高度，会画成一小段。 */
.chk span.why{display:none}
body.show-why .chk span.why{display:block}
/* 归因诊断里的两处说明（2026-10-11 新收进来的）：
     · .finding .nums .why —— f.detail 细分数值，原来是直接跟在「实测/理想」后面的 <br> 行；
       它是 <span>，默认 inline，展开时要另起一行才读得顺。
     · .finding .src.why   —— f.why 判定依据全文，本来就是 block（.src 没写 display），
       这里**显式再写一遍**，理由见上面那条优先级教训：
       凡是"靠默认值恰好生效"的显示规则，换个类名就会静默失效。 */
.finding .nums .why{display:none}
body.show-why .finding .nums .why{display:block}
.finding .src.why{display:none}
body.show-why .finding .src.why{display:block}
/* 处方块的「杠杆」行（2026-10-11 新收进来的）：
   `.rx-block .lever` 是 (0,2,0) —— 和 .rx-item .rx-ln 同一个陷阱，
   `.why{display:none}` 压不过它。这里显式再写一遍（哪怕它当前没声明 display，
   也不许靠默认值恰好生效 —— 本项目最怕的就是"改了别处，这里静默失效"）。 */
.rx-block .lever.why{display:none}
body.show-why .rx-block .lever.why{display:block}

/* 开关本体：跟「换一个视频」同一排，低调但看得见 */
.why-toggle{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  margin:0 0 12px;padding:10px 13px;
  border:1px solid var(--line);border-radius:10px;background:var(--card);
  cursor:pointer;user-select:none;-webkit-user-select:none;
}
.why-toggle .wt-l{display:flex;flex-direction:column;gap:2px;min-width:0}
.why-toggle .wt-t{font-size:13px;font-weight:500;color:var(--tx)}
.why-toggle .wt-s{font-size:11.5px;color:var(--tx3);line-height:1.5}
.why-toggle .wt-sw{
  flex:0 0 auto;width:42px;height:24px;border-radius:999px;
  background:#dfe3ea;position:relative;transition:background .16s;
}
.why-toggle .wt-sw::after{
  content:"";position:absolute;top:2px;left:2px;width:20px;height:20px;
  border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.22);
  transition:transform .16s;
}
.why-toggle[aria-pressed="true"]{border-color:var(--ac);background:#fff7f2}
.why-toggle[aria-pressed="true"] .wt-sw{background:var(--ac)}
.why-toggle[aria-pressed="true"] .wt-sw::after{transform:translateX(18px)}
/* 说明展开后，被它"撑起来"的那段文字要有个视觉归属，不然分不清哪句是解释。
   ⚠️ 只列**代码里真实存在**的选择器（.k-s .why 是指标卡里的口径、
      .rx-basis 是处方块的判定依据、.chk .why 是告警的详细原因）——
      写不存在的类名会让人以为还有别的机制，排查时被带偏。 */
body.show-why .k-s .why,
body.show-why .rx-basis,
body.show-why .chk .why,
body.show-why .rx-ln.why{
  border-left:2px solid #e6e9ef;padding-left:9px;margin-top:6px;
  color:var(--tx3);font-size:11.5px;line-height:1.62;
}
/* 处方里被收起的行（器材/口令/出处/没器材时）是 flex 行，展开时按行显示 */
body.show-why .rx-ln.why{display:block}

/* 得分 */
.sbrow{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.sbrow .big{font-size:30px;font-weight:600;letter-spacing:-.5px;font-variant-numeric:tabular-nums}
.sbrow .unit{font-size:13px;color:var(--tx3)}
.prog2{height:9px;background:#eceef2;border-radius:999px;overflow:hidden;margin:12px 0 8px;position:relative}
.prog2 i{display:block;height:100%;background:linear-gradient(90deg,#fb923c,#c2410c)}
.scoreL{font-size:12.5px;color:var(--tx2);line-height:1.6}

.checks{display:flex;flex-direction:column;gap:9px}
.chk{font-size:13px;line-height:1.6;border-radius:9px;padding:10px 12px;border:1px solid var(--line);background:#fafbfc;color:var(--tx2)}
.chk.ok{background:var(--ok-bg);border-color:#d6f0df;color:#14532d}
.chk.no{background:var(--bd-bg);border-color:#f6cfcf;color:#7f1d1d}

.ft{padding:0 16px calc(22px + env(safe-area-inset-bottom));text-align:center}
.ft p{font-size:11.5px;color:var(--tx3);margin:0}

@media (max-width:400px){
  .grid3{grid-template-columns:1fr 1fr}
  .grid3 .fld:last-child{grid-column:1/-1}
  .kpis{grid-template-columns:1fr}
}

/* 数据依据面板 */
#sources details{border:1px solid var(--line);border-radius:10px;padding:11px 13px;margin-bottom:10px;background:#fafbfc}
#sources details:last-child{margin-bottom:0}
#sources summary{font-size:13.5px;font-weight:500;cursor:pointer;list-style:none}
#sources summary::-webkit-details-marker{display:none}
#sources summary::before{content:"▸ ";color:var(--tx3)}
#sources details[open] summary::before{content:"▾ "}
.src-ul{margin:9px 0 0;padding-left:17px;font-size:12.5px;line-height:1.65}
.src-ul li{margin-bottom:7px}
.src-doc{color:var(--tx2);font-size:12px}
.src-ok{color:var(--ok);font-size:12px}
.src-warn{color:var(--wn);font-size:12px}
.src-bad{color:var(--bd);font-size:12px}

/* 离线就绪状态条 */
.offline{display:flex;align-items:center;gap:9px;margin-top:12px;padding:10px 12px;
  border-radius:9px;border:1px solid var(--line);background:#fafbfc;font-size:12.5px;color:var(--tx2)}
.offline.ok{background:var(--ok-bg);border-color:#d6f0df;color:#14532d}
.offline.warn{background:var(--wn-bg);border-color:#f7e3bd;color:#78350f}
.off-dot{width:9px;height:9px;border-radius:50%;background:#cbd0d8;flex:none}
.offline.ok .off-dot{background:var(--ok)}

/* 离线就绪后自动收起 —— 状态是"好消息"，提示几秒即可，
   长期占位反而让老师误以为"更新没生效"。
   鼠标移上去会重新展开，需要确认时随时能看。 */
.offline.collapse{
  max-height:0;padding-top:0;padding-bottom:0;margin-top:0;opacity:0;
  overflow:hidden;transition:max-height .45s ease,opacity .45s ease,padding .45s ease,margin .45s ease;
}
.offline.collapse:hover{
  max-height:80px;padding-top:10px;padding-bottom:10px;margin-top:12px;opacity:1;
}
.offline.warn .off-dot{background:var(--wn)}
.off-t{flex:1;line-height:1.5}

/* 拍摄要求卡 */
.shoot{border:1px solid var(--line);border-radius:10px;padding:11px 13px;margin-bottom:12px;background:#fafbfc}
.shoot summary{font-size:13.5px;font-weight:500;cursor:pointer;list-style:none}
.shoot summary::-webkit-details-marker{display:none}
.shoot summary::before{content:"▸ ";color:var(--tx3)}
.shoot[open] summary::before{content:"▾ "}
.shoot ul{margin:9px 0 0;padding-left:18px;font-size:12.5px;line-height:1.7;color:var(--tx2)}
.shoot li{margin-bottom:5px}
.shoot b{color:var(--tx)}

/* ── 输入体检：拍摄改进建议 ── */
.percept-warn{margin:6px 0 0;padding-left:18px;font-size:12.5px;line-height:1.75;color:var(--tx2)}
.percept-warn li{margin-bottom:6px}
.percept-warn li::marker{color:var(--wn)}
