/* =============================================================
 * 搏格体测系统 · 双板块改造 · 视觉规范 (report-dual.css)
 * -------------------------------------------------------------
 * 加载顺序（必须在本文件之前）：
 *   parent.css → report.css → report-extra.css → **report-dual.css**
 * 本文件只做「加法」：全部类名 rp-dual- / rp-cmp- / rp-intake- / rp-mgr- 前缀，
 * 不重定义任何 --c-*、不改写任何既有 rp-* 类。既有 246 个 rp- 类一律不动。
 *
 * =============================================================
 * 【0. 本文件的设计决策（改之前先读这段）】
 * -------------------------------------------------------------
 * D1. 两个板块「同一家但不分裂」——
 *     区分**只靠版式，不靠色相**。两个板块共用同一套令牌、同一张卡、
 *     同一种图标尺寸、同一种角色行。差异表达在三个可读维度上：
 *       ① 板块标识色：园所 = --rp-primary-l（亮青，明亮/开阔/集体）
 *                      机构 = --rp-primary  （主青，稳重/聚焦/个体）
 *          ——同一个深青色相的两个明度档，绝不引入第二个色相。
 *       ② 构图：园所侧 = N 个角色**等权并列** + 一排「学生点阵」；
 *                机构侧 = **一主一次**（教练录入口是橙色主 CTA，家长是 ghost）。
 *          「等权并列」本身就表达批量，「一主一次」本身就表达一对一。
 *       ③ 项目条：园所 8 项 · 无体态；机构 9 项 · 含体态（体态用橙色 chip，
 *          因为体态评估是机构链路**独有**的关键增量，值得点一下眉）。
 *
 * D2. 两步 vs 一步 —— **选一步**。
 *     理由：① 家长在园所现场扫码，多一次点击就多一次流失；
 *           ② 机构侧「教练录入」当前完全缺失，同层可见才补得回来；
 *           ③ 板块内角色数差异大（园所 3 / 机构 2），两步会逼出第三种空状态。
 *     代价（明确承认）：首页信息量上升 → 用「板块卡外壳 + 卡内分组」压住，
 *     每张板块卡的第一屏只露标题 + 一句定位 + 一行角色，滚动才见项目明细。
 *
 * D3. 变化方向配色 —— **不引入第二套「红=差」**。
 *     映射：up=--rp-excellent（优秀绿，与"优秀"评级同向）
 *          down=--rp-weak（待加强红，与"待加强"评级同向）
 *          flat=--rp-text-3（中性灰）
 *     三重冗余编码：**箭头形状**（▲ / ▼ / —）+ 数值前缀（+ / − / ±）+ 颜色。
 *     → 色盲、黑白打印、暗色三种退化场景下都仍可读。
 *
 * D4. 「持平」阈值：**|delta| < 1 分** 视为 flat（渲染成「±0」灰横杠）。
 *     ⚠️ 唯一定义在 server.js 的 `FLAT_THRESHOLD = 1`（第 319 行）。
 *        CSS **不做二次判定**，只按后端给的 direction 上色 ——
 *        前端重算阈值必然与后端口径打架（|delta|=0.7 按 0.5 判 flat、
 *        按 1 才判 up，两种口径必有一个错），且会让「显示的数」与「方向」矛盾。
 *     ⚠️ 阈值作用在**四舍五入后的 delta** 上，所以不会出现「显示 1.0 却标 flat」。
 *     ⚠️ 后端另给 `higherIsBetter`：待加强率/人数是**越低越好**，
 *        前端必须靠它决定染色，否则会把「待加强率涨了 5 个点」画成绿色进步。
 *
 * D5. 机构链路的体态评估**只在本文件出现**；园所链路任何视图都不出现
 *     「体态/体姿」字样，两个板块的数据不打通、不互相暗示可继承。
 *
 * 【避免什么 · 降低返工】
 *   ✗ 不给两个板块各配一个主色（会变成两个产品的观感）
 *   ✗ 不用 emoji 当唯一信息载体（打印会掉色、读屏会念出表情名）
 *   ✗ 不让 delta 只靠颜色表达（色盲 + 黑白打印必挂）
 *   ✗ 不在机构侧出现「班级/园所/批量」字样，反之亦然
 *   ✗ 不写死 #fff —— 暗色一律走 --rp-on-*
 * ============================================================= */


/* =============================================================
 * 1. 局部令牌层（--rpd-*）
 * -------------------------------------------------------------
 * 纪律：本层只做「薄别名」，指向 report.css 的 --rp-*。
 * 关键机制：这些别名定义在 **.rp-app 作用域内**，而 report.css 的暗色主题
 * 正是覆盖 `.rp-app` 上的 --rp-*。CSS 自定义属性是「惰性替换」——
 * --rpd-d-up 在使用它的那���元素上，按该元素的 --rp-excellent 求值，
 * 因此暗色切换时**这些别名自动跟随**，不需要再写一份暗色覆盖。
 * （这是本文件不出现任何暗色重复定义的原因。）
 *
 * =============================================================
 * ⚠️⚠️ 令牌命名的硬规则（fe-admin 发现过一处悬空引用后立的）
 * -------------------------------------------------------------
 * 本文件新增的令牌**一律以 `--rpd-` 开头**。
 * 引用分两类，两类都不能写错：
 *
 *   ① 引用 report.css / parent.css 的既有令牌 → `--rp-*` 或 `--c-*`
 *      例：var(--rp-primary) var(--rp-fill-primary)
 *      ⚠️ 只引用**确实存在**的那些。改report.css 前先确认目标存在。
 *
 *   ② 引用本文件新增的令牌 → **必须写全 `--rpd-` 前缀**
 *      例：--rpd-posture-ink / --rpd-line-flat / --rpd-axis-ink
 *
 *   ✗ 绝对不要写「--rp-」+ 本文件的概念名（如 --rp-posture-ink、
 *     --rp-line-flat、--rp-axis-ink）—— 这些名字看起来像是既有令牌，
 *     实际任何文件都没定义，var() 会静默失败 → color/background 整条声明
 *     解析失败 → 回退到继承色 → 串色，而且**不报任何错**。
 *
 *   教训：2026-10 我在 5 处引用了 --rp-posture-ink（拼写与 --rpd-posture-ink
 *   只差一个 d），fe-admin 在后台侧发现串色才报过来。
 *   → 交付前应做「引用集 / 定义集」双向 diff，见 §11 自检脚本。
 * ============================================================= */
.rp-app{
  /* —— 板块标识色（两个板块都取自深青色相）—— */
  --rpd-kind:      var(--rp-primary-l, #1B7A85);   /* 园所体测：亮青，集体 */
  --rpd-org:       var(--rp-primary,   #155E63);   /* 机构体测：主青，个体 */
  --rpd-kind-tint: var(--rp-fill-primary);
  --rpd-org-tint:  var(--rp-fill-primary);

  /* —— 变化方向三态（唯一新增的一个 tint，其余全复用既有令牌）——
     report.css 只有 fill-weak，没有 fill-excellent。这里补这一条，
     并且在 §6 里给了暗色对应值。它是"变化徽标"唯一的着色位。

     ⚠️ 徽标是「tint 底 + 语义色前景」，**不是**「实色底 + 白字」。
        这是沿用 report.css .rp-dim__weakrate 的既有写法，好处是
        前景色 = --rp-excellent / --rp-weak 本身，暗色下这两个值会自动
        提亮成 #4CC38A / #E8655A，于是同一行 CSS 在亮暗两种主题都达标。
        若改成实色底，就必须引入 --rp-on-* 深墨，且 tint 那层信息量就丢了。 */
  --rpd-fill-up:   var(--fill-excellent, rgba(46,125,91,.10));
  --rpd-line-up:   var(--rp-excellent);
  --rpd-line-down: var(--rp-weak);
  --rpd-line-flat: var(--rp-text-3);

  /* —— 机构链路独有的体态区—— */
  --rpd-posture:   var(--rp-accent);
  --rpd-posture-tint: var(--rp-fill-accent);
  --rpd-posture-ink:  var(--rp-accent-ink);

  /* —— 时间轴—— */
  --rpd-axis:      var(--rp-border-strong);
  --rpd-axis-ink:  var(--rp-text-3);

  /* —— 录入页进度环尺寸 —— */
  --rpd-gauge:      64px;
}


/* =============================================================
 * 2. 三层「历次测评对比」区块  ·  共用设计语言
 * -------------------------------------------------------------
 * 【一套组件，三种形态】
 *   共用外壳  .rp-cmp            （卡片、标题行、日期轴、切换器）
 *   共用原子  .rp-cmp__delta     （▲ +3.2 / ▼ −1.8 / — ±0）三态
 *   共用图元  .rp-cmp__pt        （日期轴上的一个测评点）
 *   ────────────────────────────────────────────────────────────
 *   个体 .rp-cmp--personal ：日期轴 + 综合分柱列 + 8 项变化行（列表）
 *   班级 .rp-cmp--class    ：日期轴 + 3 个 KPI 变化 + 评级分布**纵向堆叠**
 *                           （每次测评一行条，纵向 = 时间往下走）
 *   园所 .rp-cmp--garden   ：**班级 × 变化量 的发散条形榜**（中轴 = 0）
 *                           —— 园长唯一的问题："哪个班进步最大 / 退步最多"
 *
 * 【为什么园所层要换图形】
 *   个体/班级的问题是"我（或我的班）变好还是变差"→ 单序列纵向对比；
 *   园所的问题是"哪个班变了"→ 多序列横向排序对比。
 *   换的是**图形（布局）**，不是组件：delta 徽标、日期轴点、色值完全共用。
 *   这样三层读起来是"同一个人在同一个系统里看三件事"。
 * ============================================================= */

/* ---------- 2.1 外壳 ---------- */
.rp-cmp{margin-bottom:14px}
.rp-cmp:last-child{margin-bottom:0}

/* 【打印折叠摘要行】屏显态必须隐藏 —— 只有打印才出现。
   ⚠️ 这一条**不能漏**：漏了会让家长在手机上看到一行重复摘要
   （屏显的完整对比区已经说了同样的事，再来一行是噪音）。
   反向的 .rp-printcmp{display:block!important} 在 §8 @media print 里。

   内容/文案由 fe-report 在屏显态算好后填进来（他负责计算那行摘要文本，
   本文件只管「屏显隐藏 / 打印显示」这一件事）。
   折叠的动因与实测数据见 §8 打印折叠区块的注释。 */
.rp-printcmp{display:none}
/* 摘要行的容器微调：屏显虽不渲染，但 fe-report 可能在屏显态
   复用它做无障碍读出（aria-live）。保持它是一个语义化的容器即可。 */

/* 期次 / 基准标注（.rp-printcmp 内的子元素）——
   ⚠️ 屏显态必须一并隐藏：父级 .rp-printcmp 已是 display:none，
   但若将来有人为了「屏显也显示期次」而给父级改 display，
      这几个子元素会单独漏出来。显式写一遍是保险。
   它们的完整样式在 §8 @media print 里（那里才有黑白排版）。 */
.rp-printcmp__term,
.rp-printcmp__dot,
.rp-printcmp__meta{display:none}

.rp-cmp__hd{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin-bottom:12px;
}
.rp-cmp__ttl{
  display:flex;align-items:center;gap:8px;min-width:0;
  font-size:14.5px;font-weight:700;color:var(--rp-primary);
}
.rp-cmp__ttl::before{
  content:'';width:4px;height:15px;border-radius:3px;flex-shrink:0;
  background:var(--rpd-kind);
}
/* 机构链路的对比区块标题竖条换成主青，与板块标识一致 */
.rp-cmp--org .rp-cmp__ttl::before{background:var(--rpd-org)}
/* .rp-cmp__n（样本量提示）在 §2.7b 定义 —— 因为它和"层级语义"是一组规则，
   放在标题行这里会离上下文太远。 */
/* ══ 基准标注（UX 裁定的硬要求，不是可选项）══════════════════
   已核实 report.js 现状：report.js:1209 单项箭头用 ms[len-2]（对比上次），
   而 report.js:1223 的简析用 ms[0]（对比首次）—— 同一区块两个基准混在一屏，
   3 次记录时家长会看到箭头 +2、简析 +8，且无任何标注说明基准不同。

   → .rp-cmp__base 是解药：基准必须**写在标题行里**，与数字同屏。
   UX 定：三层统一默认「上次」，个体报告额外保留「对比首次」显式选项。
   无论当前选哪个，标题必须写明基准与那一次的日期。 */
.rp-cmp__base{
  display:inline-flex;align-items:center;gap:5px;
  font-size:11px;font-weight:600;line-height:1.5;
  color:var(--rp-text-2);
  padding:2px 8px;border-radius:20px;
  background:var(--rp-surface-2);
  border:1px solid var(--rp-border);
  white-space:nowrap;
}
.rp-cmp__base::before{
  content:'';width:4px;height:4px;border-radius:50%;
  background:var(--rpd-kind);flex-shrink:0;
}
.rp-cmp--org .rp-cmp__base::before{background:var(--rpd-org)}
.rp-cmp__base b{
  font-family:var(--rp-font-num);font-weight:800;color:var(--rp-text);
  font-variant-numeric:tabular-nums;
}
/* 「对比首次」是汇报口径（非默认），压低视觉权重但保持可点 */
.rp-cmp__base--alt{
  background:none;color:var(--rp-text-3);
  border-style:dashed;
}
.rp-cmp__scope{
  font-size:11.5px;color:var(--rp-text-3);line-height:1.55;
  margin-left:auto;text-align:right;
}
.rp-cmp__scope b{color:var(--rp-text-2);font-weight:700}

/* 「这次看哪次 vs 哪次」切换器：视觉刻意做轻（ghost 描边），
   它是**工具**不是行动 —— 橙色留给板块内的关键 CTA（见 §3.4）。 */
.rp-cmp__switch{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:13px}
.rp-cmp__switch .rp-btn{min-height:38px;padding:6px 13px;font-size:12.5px;font-weight:700}
@media(hover:none),(max-width:768px){ .rp-cmp__switch .rp-btn{min-height:44px} }
.rp-cmp__switch .rp-btn[aria-pressed="true"]{
  background:var(--rp-fill-primary);color:var(--rp-primary);
  border-color:var(--rp-primary-l);
}

/* ---------- 2.2 【共用原子】变化徽标 ----------
   三重编码：箭头形状 + 数值符号 + 颜色。任何一层单独失效都可读。

   ⚠️ 阈值 **1 分**（不是 0.5）由 server.js:319 `FLAT_THRESHOLD = 1` 唯一定义。
      方向判定完全在后端（compareDelta），CSS 不做任何二次阈值判断，
      只按返回的 direction 上色。原因见文件头 D4。

   ⚠️ 染色还要看 `higherIsBetter`：
      进步 = up→绿、down→红 只在"越高越好"的指标上成立。
      待加强率 / 待加强人数是**越低越好**（后端会标
      higherIsBetter:false），涨了 5 个点是**退步**，必须画红。
      → 渲染时把 direction 与 higherIsBetter 一起交给 class，
        不要直接把 up 映射成绿色。 */

/* ══ 2.2a 【本次未测 · 独立空态】═══════════════════════════════
   ⚠️⚠️ 这是本文件最要紧的一条安全规则（UX 提出，我核实后认同）：
   缺测项如果被画成灰色 0 分，家长会读成「孩子这项是零分」。
   0 分是**一个真实的测量结果**，未测是**没有结果**，绝不能同形。

   实现方式：未测一律渲染为破折号 + 「未测」二字，
   绝不出现在 .rp-cmp__delta 的三态里 —— delta 也需要未测态。
   （已核实：引擎对缺失项产出 score:null → report.js:1191 渲染「本次未测」）*/
.rp-na{
  display:inline-flex;align-items:center;gap:5px;
  font-size:12px;font-weight:700;color:var(--rp-text-3);
  white-space:nowrap;
}
.rp-na::before{
  /* 破折号而非数字 0 —— 形状上就与所有分数区分开 */
  content:'';width:12px;height:0;border-top:2px solid currentColor;
  flex-shrink:0;opacity:.75;
}
/* 未测项的分项行：整行压低对比度，但**保留项目名**
   （家长要知道"这项没测"，而不是"这项不存在"） */
.rp-dim--na,.rp-cmp__row--na{opacity:.72}
.rp-dim--na .rp-dim__name,.rp-cmp__row--na .rp-cmp__nmname{color:var(--rp-text-2)}
/* 未测项的评级位：未测处放「未测」chip 占位，保持行高一致，
   避免"这行少了点什么"的视觉不安 */
.rp-na--chip{
  padding:2px 8px;border-radius:6px;
  background:var(--rp-fill-muted);color:var(--rp-text-3);
  border:1px dashed var(--rp-border-strong);
  font-size:11px;
}

.rp-cmp__delta{
  display:inline-flex;align-items:center;gap:4px;
  min-height:24px;padding:2px 9px;border-radius:20px;
  font-family:var(--rp-font-num);font-size:13px;font-weight:800;
  font-variant-numeric:tabular-nums;line-height:1.4;
  white-space:nowrap;flex-shrink:0;
}
.rp-cmp__delta::before{
  font-size:9px;line-height:1;margin-top:1px;
  /* 形状是主编码，字形用内联元素注入，这里只给尺寸与基线 */
}
.rp-cmp__delta--up{
  background:var(--rpd-fill-up);color:var(--rpd-line-up);
  box-shadow:inset 0 0 0 1px var(--rp-border);      /* 回退：老浏览器无 color-mix */
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--rpd-line-up) 32%,transparent);
}
.rp-cmp__delta--up::before{content:'▲'}
.rp-cmp__delta--down{
  background:var(--rp-fill-weak);color:var(--rpd-line-down);
  box-shadow:inset 0 0 0 1px var(--rp-border);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--rpd-line-down) 32%,transparent);
}
.rp-cmp__delta--down::before{content:'▼'}
.rp-cmp__delta--flat{
  background:var(--rp-fill-muted);color:var(--rpd-line-flat);
  box-shadow:inset 0 0 0 1px var(--rp-border);
}
.rp-cmp__delta--flat::before{content:'—'}

/* ── 「越低越好」指标（higherIsBetter:false）──────────────────────
   ⚠️ 已核实 server.js:330-331：compareDelta 返回 higherIsBetter 标注
      「待加强率 / 待加强人数」这类**越低越好**的指标。
      若只看 direction 就上色，「待加强率从 12% 涨到 17%」会画成绿色 ▲——
      把班级最该被看见的坏消息报成好消息。

   ── 渲染契约（已与 report.js:501 cmpSemantic 对齐）──
      fe-report 已把 direction 归一化成**语义** good/bad，再映射到
      --up(绿) / --down(红)。所以**本文件不需要 --up2/--down2**——
      那对后缀是我在核实前写的，与 cmpSemantic 的归一化方案重复。
      两套并存会造成样式分裂（同一语义两种类名），故已删除。

      保持不变的契约：**--up 恒绿、--down 恒红**；
      语义归一化由调用方负责，本文件只管上色。

   ── 残留问题：箭头绑在语义类上，可能与数值符号矛盾 ──
      见下方 --worse / --better。 */

/* ── 箭头与数值方向的口径消歧（fe-report 在 report.js:519-524 提出）──
   箭头绑在**语义类**（--up→▲ / --down→▼），而 delta 符号绑**数值方向**（+ 为正）。
   于是「越低越好」的指标上升 30 个点时会渲染成「▼ +30.0」——
   颜色对（红=退步），**箭头与数字互相矛盾**，读者会读成"下降了 30 个点"。

   两层解法（并存）：
     ① JS 层（cmpDeltaHtml）：反向指标输出**文字方向**「上升 30.0 个点」，
        用文字消歧 —— 主力手段，长文本位用它。
     ② CSS 层（本段兜底）：让箭头跟数值同向，用于**紧凑位 / 只读态**
        （那里放不下长文字）。

   用法：反向指标在 --up/--down 之外追加 --worse（数值上升=更差）
        或 --better（数值下降=更好），箭头即随数值方向。 */
.rp-cmp__delta--worse::before{content:'▲'}
.rp-cmp__delta--better::before{content:'▼'}
/* 只读态同样需要（表格单元 / KPI 角上放不下长文字方向） */
.rp-cmp__delta--bare.rp-cmp__delta--worse::before,
.rp-cmp__delta--bare.rp-cmp__delta--better::before{
  font-size:9px;line-height:1;margin-top:1px;
}
/* 打印：箭头形状保留（黑白下 ▲▼ 仍是唯一的方向线索，不能省） */
@media print{
  .rp-cmp__delta--worse::before{content:'▲'!important}
  .rp-cmp__delta--better::before{content:'▼'!important}
}
/* 无可比对象（首次测评 / 上次缺项）：虚线框 + 文字，绝不显示 ↑0 假信息。
   ⚠️ 「上次缺项」比「首次」更需要注意：上次没测这一项，
   不能渲染成 ↑0/±0（那是"没变"的断言），必须显式说"无可比"。 */
.rp-cmp__delta--none{
  background:none;color:var(--rp-text-3);
  box-shadow:inset 0 0 0 1px var(--rp-border-strong);
  font-family:var(--rp-font);font-size:11px;font-weight:600;
  padding:2px 8px;
}
.rp-cmp__delta--none::before{content:'·'}
/* 只读态（出现在 KPI 角上 / 表格单元里）：无底色，只有箭头+数字 */
.rp-cmp__delta--bare{background:none;box-shadow:none;padding:0;min-height:0}
.rp-cmp__delta--bare.rp-cmp__delta--up{color:var(--rpd-line-up)}
.rp-cmp__delta--bare.rp-cmp__delta--down{color:var(--rpd-line-down)}
.rp-cmp__delta--bare.rp-cmp__delta--flat{color:var(--rp-text-3)}

/* ---------- 2.3 【共用图元】测评日期轴 ----------
   时间轴永远横排、从左(最早)到右(本次)。竖直的"基准线"标出本次。
   三个层级用的是同一个 .rp-cmp__pt，只是下面的容器不同。 */
.rp-cmp__axis{
  display:flex;align-items:flex-end;gap:0;
  overflow-x:auto;-webkit-overflow-scrolling:touch;
  padding:2px 0 0;margin-bottom:4px;
}
.rp-cmp__axis::-webkit-scrollbar{display:none}
.rp-cmp__axis{scrollbar-width:none}

.rp-cmp__col{
  flex:1 0 auto;min-width:54px;
  display:flex;flex-direction:column;align-items:center;gap:0;
}
.rp-cmp__colval{
  font-family:var(--rp-font-num);font-size:13px;font-weight:800;
  line-height:1.1;font-variant-numeric:tabular-nums;color:var(--rp-text);
}
.rp-cmp__colval small{
  display:block;font-family:var(--rp-font);font-size:10px;
  font-weight:600;color:var(--rp-text-3);margin-top:2px;
}
/* 柱体：以 0~100 分映射高度（score * 0.62px + 兜底 4px），
   60 分合格线用虚线段标出 —— 与 .rp-dim__base 同一语义。 */
.rp-cmp__bar{
  position:relative;width:100%;height:74px;margin-top:7px;
  display:flex;align-items:flex-end;justify-content:center;
}
.rp-cmp__bar::before{                 /* 柱区底纹 */
  content:'';position:absolute;left:0;right:0;bottom:0;height:60%;
  background:var(--rp-surface-2);border-radius:6px 6px 0 0;
}
.rp-cmp__bar::after{                  /* 60 分合格线 */
  content:'';position:absolute;left:6px;right:6px;bottom:60%;
  border-top:1.5px dashed var(--rp-weak);opacity:.6;
}
.rp-cmp__fill{
  position:relative;z-index:1;
  width:26px;border-radius:6px 6px 0 0;
  background:var(--rp-primary-l);
}
.rp-cmp__col--now .rp-cmp__fill{background:var(--rp-primary)}
.rp-cmp__col--now .rp-cmp__bar::after{opacity:.85;border-top-style:solid}
.rp-cmp__col--none .rp-cmp__fill{background:var(--rp-fill-muted);min-height:4px}

.rp-cmp__pt{
  display:flex;flex-direction:column;align-items:center;gap:5px;
  margin-top:8px;flex-shrink:0;
}
.rp-cmp__ptdot{
  width:9px;height:9px;border-radius:50%;
  background:var(--rp-surface);border:2px solid var(--rpd-axis);
  transition:.2s;
}
.rp-cmp__pt--now .rp-cmp__ptdot{
  width:12px;height:12px;border-width:3px;
  border-color:var(--rp-primary);background:var(--rp-surface);
}
.rp-cmp__pt--dot-up .rp-cmp__ptdot{border-color:var(--rpd-line-up)}
.rp-cmp__pt--dot-down .rp-cmp__ptdot{border-color:var(--rpd-line-down)}
.rp-cmp__ptdt{
  font-family:var(--rp-font-num);font-size:10.5px;font-weight:700;
  color:var(--rpd-axis-ink);white-space:nowrap;font-variant-numeric:tabular-nums;
}
.rp-cmp__pt--now .rp-cmp__ptdt{color:var(--rp-primary);font-weight:800}
.rp-cmp__ptline{
  height:2px;min-width:8px;margin:0 2px;
  background:var(--rpd-axis);align-self:center;flex:1 1 auto;
}
/* 连接线与圆点同处一条横排（.rp-cmp__axisline）时才显示；
   柱列形态（.rp-cmp__axis）里不出现，避免和柱体叠在一起。 */
.rp-cmp__axis .rp-cmp__ptline{display:none}
.rp-cmp__axisline{
  display:flex;align-items:center;gap:0;
  border-top:2px solid var(--rpd-axis);
  margin-top:8px;padding-top:0;
}

/* ---------- 2.4 层级 A · 个体报告 ---------- */
.rp-cmp--personal .rp-cmp__bar{height:86px}

/* 8 项变化行：项名 / 上次→本次 / delta。
   复用 .rp-dims 的分隔线节奏，让它和报告正文的分项列表读起来是同一张表。 */
.rp-cmp__rows{
  display:flex;flex-direction:column;
  border-top:1px solid var(--rp-line);
}
.rp-cmp__row{
  display:grid;
  grid-template-columns:1fr auto;
  grid-template-areas:"nm dl" "pair pair";
  gap:6px 10px;align-items:center;
  padding:11px 0;border-bottom:1px solid var(--rp-line);
}
.rp-cmp__row:last-child{border-bottom:0}
.rp-cmp__nm{
  grid-area:nm;min-width:0;
  display:flex;align-items:baseline;gap:7px;
}
.rp-cmp__nmname{font-size:13.5px;font-weight:700;color:var(--rp-text);white-space:nowrap}
.rp-cmp__nmcat{font-size:10.5px;color:var(--rp-text-3);font-weight:600}
.rp-cmp__dl{grid-area:dl;justify-self:end;display:flex;align-items:center;gap:8px}

/* 「上次 72 → 本次 78」双值 + 中间箭头。
   两个分数本身用评级色（和 .rp-dim__score 同一语义），
   变化量用 delta 徽标 —— 一行内两种颜色互不干扰，因为它们表达的不是一件事。 */
.rp-cmp__pair{
  grid-area:pair;
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  font-family:var(--rp-font-num);font-size:12.5px;
  font-variant-numeric:tabular-nums;
}
.rp-cmp__from{color:var(--rp-text-3)}
.rp-cmp__arrow{
  font-size:11px;color:var(--rp-text-3);font-family:var(--rp-font);
  letter-spacing:-.5px;
}
.rp-cmp__to{font-weight:800;color:var(--rp-primary)}
.rp-cmp__to--excellent{color:var(--rp-excellent)}
.rp-cmp__to--good{color:var(--rp-good)}
.rp-cmp__to--pass{color:var(--rp-pass)}
.rp-cmp__to--weak{color:var(--rp-weak)}
.rp-cmp__to--untested{color:var(--rp-text-3);font-weight:700}
.rp-cmp__gap{
  font-family:var(--rp-font);font-size:11px;font-weight:600;
  color:var(--rp-text-3);margin-left:2px;
}
@media(min-width:640px){
  .rp-cmp__row{
    grid-template-columns:112px 1fr auto;
    grid-template-areas:"nm pair dl";
    gap:14px;padding:9px 0;
  }
}

/* 综合分变化摘要条：比 8 项行更重（它是头号信息） */
.rp-cmp__hero{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  padding:13px 14px;margin-bottom:13px;
  background:var(--rp-surface-2);
  border:1px solid var(--rp-border);
  border-radius:var(--rp-radius-sm);
}
.rp-cmp__heronum{
  font-family:var(--rp-font-num);font-size:30px;font-weight:800;
  line-height:1;color:var(--rp-primary);
  font-variant-numeric:tabular-nums;
}
.rp-cmp__heronum small{
  font-family:var(--rp-font);font-size:11.5px;font-weight:600;
  color:var(--rp-text-3);margin-left:3px;
}
.rp-cmp__heroinfo{flex:1;min-width:150px}
.rp-cmp__herolab{font-size:12px;color:var(--rp-text-2);font-weight:600}
.rp-cmp__herolab b{color:var(--rp-primary);font-weight:800;font-family:var(--rp-font-num)}

/* ---------- 2.5 层级 B · 班级报告 ---------- */
/* 3 个 KPI 的变化：复用 .rp-kpi 的视觉语言，左侧语义条改由 delta 决定 */
.rp-cmp__kpis{
  display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin-bottom:14px;
}
@media(max-width:400px){ .rp-cmp__kpis{grid-template-columns:1fr} }
.rp-cmp__kpi{
  position:relative;overflow:hidden;
  padding:12px 12px 11px;
  background:var(--rp-surface);border:1px solid var(--rp-border);
  border-radius:var(--rp-radius);box-shadow:var(--rp-shadow-sm);
}
.rp-cmp__kpi::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--rpd-axis-ink)}
.rp-cmp__kpi--up::before{background:var(--rp-excellent)}
.rp-cmp__kpi--down::before{background:var(--rp-weak)}
.rp-cmp__kpi--flat::before{background:var(--rp-text-3)}
.rp-cmp__kpilab{font-size:11.5px;color:var(--rp-text-2);font-weight:600;line-height:1.4}
.rp-cmp__kpival{
  font-family:var(--rp-font-num);font-size:23px;font-weight:800;line-height:1.1;
  color:var(--rp-primary);margin-top:4px;font-variant-numeric:tabular-nums;
}
.rp-cmp__kpival small{font-size:12px;font-weight:700;color:var(--rp-text-2);margin-left:1px}
.rp-cmp__kpi--up .rp-cmp__kpival{color:var(--rp-excellent)}
.rp-cmp__kpi--down .rp-cmp__kpival{color:var(--rp-weak)}
.rp-cmp__kpifoot{margin-top:7px;display:flex;align-items:center;gap:6px;flex-wrap:wrap}

/* 评级分布的纵向堆叠：每一次测评一行，行内是那条 .rp-dist__bar。
   纵向 = 时间向下。同一段分布条重复 2~3 行时，人眼能直接比出比例变化，
   这是横向并列做不到的（横向会诱导"每行独立阅读"）。 */
.rp-cmp__stack{
  display:flex;flex-direction:column;gap:12px;
}
.rp-cmp__stackrow{
  display:grid;
  grid-template-columns:auto 1fr;
  grid-template-areas:"lab bar dl";
  gap:5px 12px;align-items:center;
  padding-bottom:11px;border-bottom:1px solid var(--rp-line);
}
.rp-cmp__stackrow:last-child{border-bottom:0;padding-bottom:0}
.rp-cmp__stacklab{
  grid-area:lab;
  font-family:var(--rp-font-num);font-size:11.5px;font-weight:800;
  color:var(--rp-text-2);white-space:nowrap;
  font-variant-numeric:tabular-nums;
}
.rp-cmp__stacklab small{
  display:block;font-family:var(--rp-font);font-size:10px;
  font-weight:600;color:var(--rp-text-3);margin-top:2px;
}
.rp-cmp__stackrow--now .rp-cmp__stacklab{color:var(--rp-primary)}
.rp-cmp__stackrow--now .rp-cmp__stacklab::after{
  content:'本次';display:inline-block;margin-left:5px;
  font-size:9.5px;font-weight:800;padding:1px 5px;border-radius:4px;
  background:var(--rp-primary);color:var(--rp-on-primary);vertical-align:1px;
}
.rp-cmp__stackbar{grid-area:bar;min-width:0}
.rp-cmp__stackdl{grid-area:dl;justify-self:end}
@media(max-width:520px){
  .rp-cmp__stackrow{
    grid-template-columns:1fr auto;
    grid-template-areas:"lab dl" "bar bar";
    gap:7px 10px;
  }
}

/* ---------- 2.6 层级 C · 园所报告（发散条形榜） ----------
   园长的原话是"哪个班进步最大 / 退步最多"。
   所以主视觉不是"各班的绝对分"，而是**各班的变化量排序**：
   中轴 = 0，右 = 进步（绿），左 = 退步（红）。
   一眼就能看出榜尾（左端最长）和榜首（右端最长）。 */
.rp-cmp__rank{display:flex;flex-direction:column;gap:2px}
.rp-cmp__rankrow{
  display:grid;
  grid-template-columns:76px 1fr 92px;
  grid-template-areas:"nm bar dl";
  gap:11px;align-items:center;
  padding:9px 0;border-bottom:1px solid var(--rp-line);
}
.rp-cmp__rankrow:last-child{border-bottom:0}
.rp-cmp__ranknm{
  grid-area:nm;min-width:0;
  font-size:12.5px;font-weight:700;color:var(--rp-text);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.rp-cmp__ranknm small{
  display:block;font-size:10.5px;font-weight:600;
  color:var(--rp-text-3);margin-top:2px;
  font-family:var(--rp-font-num);
}
.rp-cmp__rankbar{
  grid-area:bar;position:relative;height:22px;
  background:var(--rp-surface-2);border-radius:6px;
}
/* 0 轴：整条榜的左右分界，视觉上就是"及第线" */
.rp-cmp__rankbar::before{
  content:'';position:absolute;left:50%;top:-2px;bottom:-2px;width:2px;
  background:var(--rpd-axis);transform:translateX(-1px);border-radius:2px;
}
.rp-cmp__rankfill{
  position:absolute;top:3px;bottom:3px;border-radius:4px;
  /* width / left 由 JS 按变化量与最大绝对值计算 */
}
.rp-cmp__rankfill--up{background:var(--rp-excellent)}
.rp-cmp__rankfill--down{background:var(--rp-weak)}
.rp-cmp__rankfill--flat{background:var(--rp-text-3);opacity:.5}
.rp-cmp__rankdl{grid-area:dl;display:flex;align-items:center;gap:7px;justify-self:end}
.rp-cmp__rankdl b{
  font-family:var(--rp-font-num);font-size:12.5px;font-weight:700;
  color:var(--rp-text-2);font-variant-numeric:tabular-nums;white-space:nowrap;
}
@media(max-width:400px){
  .rp-cmp__rankrow{grid-template-columns:62px 1fr 76px;gap:8px}
}

/* 全园均分随测评的变化：一根横向的迷你时间轴（与班级层同源，只是横排） */
.rp-cmp__spark{
  display:flex;align-items:flex-end;gap:3px;height:34px;
  padding:0 2px;margin-top:10px;
}
.rp-cmp__sparkbar{
  flex:1;border-radius:4px 4px 0 0;background:var(--rpd-kind);
  min-height:4px;
}
.rp-cmp__sparkbar--now{background:var(--rp-primary)}
.rp-cmp__sparkax{
  display:flex;gap:3px;padding:0 2px;margin-top:5px;
}
.rp-cmp__sparkax span{
  flex:1;text-align:center;
  font-family:var(--rp-font-num);font-size:9.5px;font-weight:700;
  color:var(--rp-text-3);white-space:nowrap;font-variant-numeric:tabular-nums;
}
.rp-cmp__sparkax span.is-now{color:var(--rp-primary);font-weight:800}

/* ---------- 2.7 【默认首屏】成长记录 · 第 1 次引导卡 ----------
   ⚠️ 这不是边角状态，而是**当前生产库的默认首屏**。
      已核实 kg.sqlite：127 名学生，每人恰好 1 次测量，
      无一条 ≥2 次；testDate 只有 2026-09-02 / 09-03 两天。
      也就是说对比功能上线后，所有人看到的第一屏都是这张卡。
      —— 因此它必须像"一个有意义的开始"，不能像"数据缺失"。

   ★ 三条硬纪律（改之前先读）：
     1. 绝不画成空白 / 灰掉 / 「暂无数据」—— 那是报错语气，
        家长看到会以为系统坏了。
     2. 绝不用「暂无对比」这类词。对比不是"还没有的数据"，
        是"还没发生的事"。
     3. 这张卡与成长对比区块**同一个标题前缀**（成长记录 ·），
        用户第二次来时标题不变、只是内容长出曲线 —— 位置感稳定。*/
.rp-cmp__seed{
  position:relative;overflow:hidden;
  padding:16px 15px;
  background:var(--rp-surface-2);
  border:1px solid var(--rp-border);
  border-radius:var(--rp-radius);
}
/* 背景是一段极淡的"未来曲线"剪影：暗示"后面会长出来"，
   但透明度压到 .06，不与文案争视线 */
.rp-cmp__seed::after{
  content:'';position:absolute;right:-8px;bottom:-6px;
  width:132px;height:62px;pointer-events:none;
  background:
    linear-gradient(to top right,transparent 49%,var(--rpd-kind) 49.5%,var(--rpd-kind) 50.5%,transparent 51%) 0 100%/26px 100% no-repeat,
    linear-gradient(to top right,transparent 49%,var(--rpd-kind) 49.5%,var(--rpd-kind) 50.5%,transparent 51%) 26px 100%/26px 100% no-repeat;
  opacity:.06;
}
.rp-cmp__seedttl{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  font-size:14.5px;font-weight:700;color:var(--rp-primary);
  margin-bottom:8px;
}
.rp-cmp__seedttl::before{
  content:'';width:4px;height:15px;border-radius:3px;background:var(--rpd-kind);flex-shrink:0;
}
.rp-cmp--org .rp-cmp__seedttl::before{background:var(--rpd-org)}
/* 「第 1 次」是这个卡的英雄数字 —— 用记分牌字型，让"第一次"有分量 */
.rp-cmp__seedn{
  display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;margin-bottom:7px;
}
.rp-cmp__seedn b{
  font-family:var(--rp-font-num);font-size:34px;font-weight:800;line-height:1;
  color:var(--rpd-kind);font-variant-numeric:tabular-nums;
}
.rp-cmp--org .rp-cmp__seedn b{color:var(--rpd-org)}
.rp-cmp__seedn span{font-size:13px;color:var(--rp-text-2);font-weight:600}
.rp-cmp__seedd{
  font-size:12.5px;line-height:1.7;color:var(--rp-text-2);
  max-width:30em;position:relative;
}
.rp-cmp__seedd b{color:var(--rp-text);font-weight:700}
/* 次要说明：解释「自动」这件事，家长最常问"要不要另外操作" */
.rp-cmp__seedhint{
  display:flex;align-items:flex-start;gap:7px;
  margin-top:10px;padding-top:9px;
  border-top:1px dashed var(--rp-border-strong);
  font-size:11.5px;line-height:1.6;color:var(--rp-text-3);
  position:relative;
}
.rp-cmp__seedhint::before{
  content:'';width:5px;height:5px;border-radius:50%;
  background:var(--rp-excellent);flex-shrink:0;margin-top:6px;
}
/* 已测日期 —— 让家长看到"这一次的记录确实在" */
.rp-cmp__seeddate{
  display:inline-flex;align-items:center;gap:5px;
  margin-top:10px;
  font-family:var(--rp-font-num);font-size:11.5px;font-weight:700;
  color:var(--rp-text-2);
  background:var(--rp-surface);border:1px solid var(--rp-border);
  padding:3px 9px;border-radius:20px;
}
.rp-cmp__seeddate::before{
  content:'';width:5px;height:5px;border-radius:50%;background:var(--rp-excellent);
}

/* ---------- 2.7b 【层级语义】样本量提示与层级化 seed 卡 ----------
   ⚠️ UX 提出、我认同且认为比任何视觉处理都有效的一条：
   「第 1 次」这个说法**只在个体层是准确的**。

     个体：这个孩子测了 1 次          ✅ 准确
     班级：这个班测了 1 期            ⚠️ 家长会误读成"我的孩子只测了 1 次"
     园所：全园测了 1 期              ❌ 不准确 —— 全园 127 个孩子各自都测了，
                                          不存在"全园第 1 次"这个概念

   而且班级/园所的"≥2 次才渲染"条件本身也危险：
   全园 127 人里**只要有 1 个孩子**测过 2 次，对比就有数据了 ——
   这时园长看到的不是"全园对比"，而是**基于极少数人的样本**，
   极易被当成"全园整体变化"来决策。

   → 因此本节提供两样东西：
     ① .rp-cmp__n —— 样本量必须与对比区块同屏（班级/园所**强制**）
     ② .rp-cmp__seed--agg —— 层级化措辞，机构/集体层不用"第 1 次" */

/* ① 样本量提示：与 .rp-cmp__n 同级，班级/园所必填
   低占比时（<20%）用 --warn 变体，见下方 §10 判定规则 */
.rp-cmp__n{
  font-family:var(--rp-font-num);font-size:11.5px;font-weight:800;
  padding:2px 8px;border-radius:6px;
  background:var(--rp-fill-muted);color:var(--rp-text-2);
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
/* 样本量偏低的告警态 —— 仍可渲染，但必须显得"这不是结论" */
.rp-cmp__n--warn{
  background:var(--rp-fill-accent);color:var(--rp-accent-ink);
  font-weight:700;
}

/* ② 样本占比不足时的降级提示（UX 建议 ≥20% 才生成全园对比）
   ⚠️ 低覆盖率有两种成因，**视觉必须能分开**：
     · .rp-cmp__thin      漏测多（未测 >0）→ 橙色，可行动：先补测
     · .rp-cmp__thin--wait 无人补测（未测 =0）→ 中性灰，不可行动：只能等下学期
   两者若长一样，家长和老师会得出相反结论却看到同一句话。
   橙色是"现在有件事可做"，灰色是"只能等" —— 这是唯一的区别理由。 */
.rp-cmp__thin{
  display:flex;align-items:flex-start;gap:9px;
  padding:11px 13px;margin-bottom:13px;
  font-size:12.5px;line-height:1.7;color:var(--rp-accent-ink);
  background:var(--rp-fill-accent);
  border:1px solid var(--rp-accent);
  border-radius:var(--rp-radius-sm);
}
.rp-cmp__thin b{font-family:var(--rp-font-num);font-weight:800}
/* 无人补测：中性灰 + 虚线。它不紧急，不该占橙色 */
.rp-cmp__thin--wait{
  color:var(--rp-text-2);
  background:var(--rp-surface-2);
  border-style:dashed;border-color:var(--rp-border-strong);
}
.rp-cmp__thin--wait b{color:var(--rp-text)}

/* ③ 层级化措辞：机构侧 / 集体层的 seed 卡不用「第 1 次」
   —— 「第 1 次」是个体专属概念，班级/园所层用它会误导。 */
.rp-cmp__seed--agg .rp-cmp__seedttl::after{
  content:'尚无跨期数据';
  font-size:11px;font-weight:600;color:var(--rp-text-2);
  background:var(--rp-surface);border:1px solid var(--rp-border);
  padding:1px 7px;border-radius:5px;
}

/* ---------- 2.8 「看哪次 vs 看哪次」切换条与兜底提示 ---------- */
/* 基准标注是硬要求（UX 裁定）：标题必须写明"跟谁比"，
   否则家长读到箭头 +2、简析说 +8 却不��道基准不同，会以为数据矛盾。
   → .rp-cmp__scope 是必填项，不是可选装饰。 */
.rp-cmp__none{
  display:flex;align-items:flex-start;gap:9px;
  font-size:12px;color:var(--rp-text-3);line-height:1.65;
  padding:10px 12px;background:var(--rp-surface-2);
  border:1px dashed var(--rp-border-strong);border-radius:var(--rp-radius-sm);
}
.rp-cmp__none b{color:var(--rp-text-2);font-weight:700}

/* 对比结论一句话（复用 .rp-note 的左竖条语言）
   ↑条 = 行动建议，弱条 = 数据提醒。橙只出现在"需要做什么"上。 */
.rp-cmp__verdict{
  margin-top:12px;padding:11px 14px;
  font-size:12.5px;line-height:1.7;color:var(--rp-text-2);
  background:var(--rp-surface-2);
  border-left:3px solid var(--rpd-kind);
  border-radius:0 8px 8px 0;
}
.rp-cmp__verdict b{font-weight:800;color:var(--rp-primary)}
.rp-cmp__verdict--act{border-left-color:var(--rp-accent);background:var(--rp-fill-accent);color:var(--rpd-posture-ink)}
.rp-cmp__verdict--act b{color:var(--rp-accent-d)}
.rp-cmp--org .rp-cmp__verdict{border-left-color:var(--rpd-org)}


/* =============================================================
 * 3. 双板块入口页
 * -------------------------------------------------------------
 * 层级：.rp-dual（板块容器）> .rp-sector（板块卡）> 内部
 * ============================================================= */

/* ---------- 3.1 板块容器 ---------- */
.rp-dual{display:grid;gap:12px;margin-bottom:6px}
@media(min-width:760px){ .rp-dual{grid-template-columns:1fr 1fr;gap:16px} }
/* 超宽屏（平板横/桌面）：两块并列但不无限拉伸，止于 1100px 容器 */
@media(min-width:1280px){ .rp-dual{max-width:1100px} }

/* ---------- 3.2 板块卡外壳 ---------- */
.rp-sector{
  position:relative;overflow:hidden;
  display:flex;flex-direction:column;
  background:var(--rp-surface);
  border:1px solid var(--rp-border);
  border-radius:var(--rp-radius);
  box-shadow:var(--rp-shadow-sm);
  /* 顶部 3px 板块色 —— 两个板块唯一的"品牌色"表达位，
     比整块染色克制得多，且两个色相相同，一眼还是一家。 */
  border-top:3px solid var(--rpd-kind);
}
.rp-sector--org{border-top-color:var(--rpd-org)}

/* ---------- 3.3 板块卡头：图标 + 标题 + 一句定位 ---------- */
.rp-sector__hd{
  display:grid;
  grid-template-columns:52px 1fr;
  grid-template-areas:"ico hd" "sp sp" "meta meta";
  gap:12px;align-items:center;
  padding:15px 15px 0;
}
.rp-sector__ico{
  grid-area:ico;
  width:52px;height:52px;border-radius:16px;flex-shrink:0;
  background:var(--rpd-kind-tint);
  display:flex;align-items:center;justify-content:center;font-size:25px;
}
/* 机构侧图标底用描边而非填充 —— "一个个来"比"一大片"更轻 */
.rp-sector--org .rp-sector__ico{
  background:none;border:1.5px solid var(--rpd-org);
}
.rp-sector__hdb{grid-area:hd;min-width:0}
.rp-sector__ttl{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  font-size:17.5px;font-weight:800;color:var(--rp-text);line-height:1.3;
}
.rp-sector__sub{
  font-size:12.5px;color:var(--rp-text-2);margin-top:5px;line-height:1.6;
}
/* 板块规模标签：「批量 / 一对一」—— 这是 D1 里最直给的差异表达 */
.rp-sector__scale{
  display:inline-flex;align-items:center;gap:5px;
  font-size:10.5px;font-weight:800;padding:2px 8px;border-radius:6px;
  background:var(--rp-surface-2);color:var(--rp-text-2);
  border:1px solid var(--rp-border);
}
.rp-sector--kind .rp-sector__scale{color:var(--rpd-kind);background:var(--rpd-kind-tint);border-color:transparent}
.rp-sector--org  .rp-sector__scale{color:var(--rpd-org);background:var(--rpd-org-tint);border-color:transparent}

/* 「学生点阵」：园所侧画一排 12 个小方块（= 一批孩子），
   机构侧只画 1 个（= 一个学员）。纯 CSS，无 JS，无图片。
   这是"批量感 / 一对一感"最省事又最不含糊的一笔。

   ⚠️ 措辞纪律：园所侧只能说"整班"（集体测），机构侧只能说"一个学员"。
   两边都禁止出现"班级"一词 —— 机构侧一旦说"班级"，
   用户会与园所侧的班级对��，以为数据可互通（实际两链路不打通）。 */
.rp-sector__dots{display:flex;align-items:center;gap:4px;margin-top:9px;flex-wrap:nowrap}
.rp-sector__dots i{
  width:9px;height:9px;border-radius:3px;
  background:var(--rpd-kind);opacity:.75;flex-shrink:0;
}
.rp-sector__dots--one i{width:13px;height:13px;border-radius:5px;opacity:1}
/* ⚠️ fe-admin 报告的缺陷（已在源文件修）：::after 生成的说明文字是
   **可收缩的 flex item**，容器一窄就逐字压成竖排。
   flex-shrink:0 是必须的 —— 这段文字要保持一行不折。
   （曾考虑把文案移到 <span> 由 JS 渲染，但纯 CSS 更省事且不依赖 JS。） */
.rp-sector__dots::after{
  flex-shrink:0;white-space:nowrap;align-self:center;
}
.rp-sector__dots--one::after{
  content:'一次测一个学员';font-size:10.5px;font-weight:700;
  color:var(--rp-text-3);margin-left:3px;
}
.rp-sector__dots--many::after{
  content:'一次测整班';font-size:10.5px;font-weight:700;
  color:var(--rp-text-3);margin-left:3px;
}
/* 极窄屏（<330px）：宁可让点阵自身换行，也不要压文字 */
@media(max-width:330px){
  .rp-sector__dots{flex-wrap:wrap}
  .rp-sector__dots::after{flex-basis:100%;margin-left:0;padding-top:2px}
}

/* ---------- 3.4 板块卡内的「测什么项目」 ----------
   园所：8 项标准项目，无体态。
   机构：8 项标准项目 + 体姿体态评估（唯一差异项，橙色 chip）。
   橙色在这里出现是允许的：它标记的是"这条链路独有的增量能力"，
   属于「关键差异」而非「行动按钮」，与 .rp-btn--accent 的行动语义分开。 */
.rp-sector__items{
  padding:13px 15px 0;
}
.rp-sector__itemslab{
  font-size:11px;font-weight:700;color:var(--rp-text-3);
  letter-spacing:.3px;margin-bottom:7px;
  display:flex;align-items:center;gap:6px;
}
.rp-sector__itemslab::after{content:'';flex:1;height:1px;background:var(--rp-border)}
.rp-sector__chips{display:flex;flex-wrap:wrap;gap:5px}
.rp-chip{
  display:inline-flex;align-items:center;gap:4px;
  font-size:11px;font-weight:600;line-height:1.5;
  padding:3px 8px;border-radius:6px;
  background:var(--rp-surface-2);color:var(--rp-text-2);
  border:1px solid var(--rp-border);
  white-space:nowrap;
}
/* 独有增量项：体姿体态评估 */
.rp-chip--ext{
  background:var(--rpd-posture-tint);color:var(--rpd-posture-ink);
  border-color:transparent;font-weight:800;
}
.rp-chip--ext::before{content:'＋';font-weight:800;font-size:10px}
.rp-chip--muted{color:var(--rp-text-3);background:none}

/* ---------- 3.5 板块卡内的角色入口 ---------- */
.rp-sector__acts{
  padding:13px 15px 15px;margin-top:auto;
  display:flex;flex-direction:column;gap:8px;
}
.rp-sector__actsrow{display:flex;flex-direction:column;gap:8px}
@media(min-width:440px){
  .rp-sector__actsrow--eq{ /* 园所侧：三个角色等权并列 */
    display:grid;grid-template-columns:repeat(3,1fr);gap:8px;
  }
}

/* 角色行（板块卡内，比 .rp-role 更紧凑：
   板块卡已经有图标 + 标题了，角色行不该再抢一次大图标）

   ⚠️ 两个板块在这里**刻意不对称**（UX Q1 裁定）：
   · 园所侧：老师 / 园长并列两张卡，一步选完。
     理由：运营者在两种身份间切换成本极低，选错只是多一次点击、无损害，
     不值得为它单开一屏。
   · 机构侧：**不做「我是教练」这一步**。机构侧的主行动是"录一个新学员"，
     它的自然首页就是学员列表 + 主 CTA。硬塞一张身份卡是纯粹的中间层。

   → 所以 .rp-sector--org 里的 .rp-sector__acts 装的是**动作**，
     不是身份；.rp-sector--kind 装的是**身份**。
     两边都用 .rp-sector__act，但语义不同，所以文案不要互抄。*/
.rp-sector__act{
  display:grid;
  grid-template-columns:34px 1fr 22px;
  gap:10px;align-items:center;
  width:100%;text-align:left;
  min-height:var(--rp-tap);padding:9px 11px;
  font-family:inherit;cursor:pointer;
  background:var(--rp-surface);color:var(--rp-text);
  border:1px solid var(--rp-border);border-radius:var(--rp-radius-sm);
  transition:box-shadow .18s,border-color .18s,background .18s;
}
.rp-sector__act:hover{box-shadow:var(--rp-shadow-sm);border-color:var(--rpd-kind)}
.rp-sector--org .rp-sector__act:hover{border-color:var(--rpd-org)}
.rp-sector__act:active{transform:scale(.985)}
.rp-sector__act:focus-visible{
  outline:none;border-color:var(--rp-primary);
  box-shadow:0 0 0 3px var(--rp-ring-primary);
}
.rp-sector__actico{
  width:34px;height:34px;border-radius:11px;
  background:var(--rp-surface-2);
  display:flex;align-items:center;justify-content:center;font-size:16px;
}
.rp-sector__actb{min-width:0}
.rp-sector__actt{
  font-size:13.5px;font-weight:700;color:var(--rp-text);
  display:flex;align-items:center;gap:6px;flex-wrap:wrap;
}
.rp-sector__actd{
  font-size:11px;color:var(--rp-text-3);margin-top:2px;line-height:1.5;
}
/* 角色行里的新功能角标（机构侧「体态评估」等） */
.rp-sector__actnew{
  font-size:9.5px;font-weight:800;padding:1px 5px;border-radius:4px;
  background:var(--rpd-posture);color:var(--rp-on-accent);
  letter-spacing:.2px;
}
.rp-sector__actgo{
  justify-self:end;color:var(--rp-text-3);font-size:16px;
  width:22px;text-align:center;transition:.18s;
}
.rp-sector__actgo::after{content:'›'}
.rp-sector__act:hover .rp-sector__actgo{color:var(--rp-primary)}

/* 板块内的主行动（机构侧「开始录入」= 橙色；园所侧不需要）。
   橙色全站只有两处：这一处 + 打印 CTA。都是"不可逆的关键行动"。 */
.rp-sector__act--primary{
  background:var(--rp-accent);color:var(--rp-on-accent);
  border-color:transparent;
  box-shadow:var(--rp-shadow-accent);
}
.rp-sector__act--primary .rp-sector__actico{
  /* 描边式图标底：不引入任何写死色，橙底上用前景墨描边，
     暗色下 --rp-on-accent 自动变深墨，图标底也随之变深 —— 自动跟随。 */
  background:none;border:1px solid currentColor;color:var(--rp-on-accent);
}
.rp-sector__act--primary .rp-sector__actt{color:var(--rp-on-accent)}
.rp-sector__act--primary .rp-sector__actd{color:var(--rp-on-accent);opacity:.9}
.rp-sector__act--primary .rp-sector__actgo{color:var(--rp-on-accent);opacity:.85}
.rp-sector__act--primary:hover{background:var(--rp-accent);filter:brightness(1.05);border-color:transparent}

/* 板块卡脚注：一句话说明"这条链路的报告存在哪 / 谁能看到" */
.rp-sector__foot{
  padding:10px 15px;
  font-size:11px;line-height:1.65;color:var(--rp-text-3);
  background:var(--rp-surface-2);
  border-top:1px solid var(--rp-border);
}
.rp-sector__foot b{color:var(--rp-text-2);font-weight:700}

/* 两个板块之间的"同一家"锚点：底部一行并排的品牌说明 */
.rp-dual__anchor{
  margin-top:14px;padding:12px 14px;
  display:flex;align-items:flex-start;gap:10px;
  background:var(--rp-surface-2);
  border:1px solid var(--rp-border);border-radius:var(--rp-radius);
  font-size:11.5px;color:var(--rp-text-2);line-height:1.7;
}
.rp-dual__anchor b{color:var(--rp-primary);font-weight:800}
.rp-dual__anchorico{
  width:26px;height:26px;border-radius:9px;flex-shrink:0;
  background:var(--rp-fill-primary);color:var(--rp-primary);
  display:flex;align-items:center;justify-content:center;font-size:13px;
}


/* =============================================================
 * 4. 机构体测 · 教练「边测边录」录入界面
 * -------------------------------------------------------------
 * 与园所侧的本质差异：园所是「一次把一整班灌进表格」，
 * 机构是「测一项录一项」。所以：
 *   · 输入区必须**永远在拇指区**，且一次只要求一个数字
 *   · 项目清单要显示"进行到第几项"，教练一眼知道还剩几项
 *   · 触摸目标 ≥56px（教练单手、可能手上有粉/器材，比家长端更宽松）
 *   · 体姿体态评估独立成组，独立完成度（它是机构链路的差异项）
 * ============================================================= */

/* ---------- 4.1 录入外壳 ---------- */
.rp-intake{padding-bottom:0}
.rp-intake__head{
  display:flex;align-items:center;gap:13px;flex-wrap:wrap;
  padding:15px 16px;margin-bottom:13px;
  background:var(--rp-surface);border:1px solid var(--rp-border);
  border-left:3px solid var(--rpd-org);
  border-radius:var(--rp-radius);box-shadow:var(--rp-shadow-sm);
}
.rp-intake__av{
  width:46px;height:46px;border-radius:15px;flex-shrink:0;
  background:var(--rp-fill-primary);color:var(--rp-primary);
  display:flex;align-items:center;justify-content:center;
  font-size:19px;font-weight:800;font-family:var(--rp-font-num);
}
.rp-intake__hb{flex:1;min-width:140px}
.rp-intake__nm{
  font-size:17px;font-weight:800;color:var(--rp-text);
  display:flex;align-items:center;gap:7px;flex-wrap:wrap;
}
.rp-intake__meta{font-size:11.5px;color:var(--rp-text-3);margin-top:4px;line-height:1.55}

/* 完成度环：SVG 由 JS 画 stroke-dasharray，这里只给容器与轨道 */
.rp-intake__gauge{
  position:relative;width:var(--rpd-gauge);height:var(--rpd-gauge);
  flex-shrink:0;
}
.rp-intake__gauge svg{width:100%;height:100%;display:block;transform:rotate(-90deg)}
.rp-intake__gauge circle{fill:none;stroke-width:6;stroke-linecap:round}
.rp-intake__gauge .trk{stroke:var(--rp-border)}
.rp-intake__gauge .val{stroke:var(--rpd-org);transition:stroke-dashoffset .5s ease}
.rp-intake__gauge span{
  position:absolute;inset:0;
  display:flex;align-items:center;justify-content:center;
  font-family:var(--rp-font-num);font-size:15px;font-weight:800;
  color:var(--rp-primary);font-variant-numeric:tabular-nums;
}

/* ---------- 4.2 项目组（标准项目 / 体姿体态评估） ---------- */
.rp-intake__group{margin-bottom:14px}
.rp-intake__gt{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin-bottom:11px;
}
.rp-intake__gtname{
  display:flex;align-items:center;gap:8px;
  font-size:15.5px;font-weight:800;color:var(--rp-primary);
}
.rp-intake__gtname::before{
  content:'';width:4px;height:16px;border-radius:3px;background:var(--rpd-org);
}
.rp-intake__gtname small{
  font-family:var(--rp-font);font-size:11px;font-weight:700;
  color:var(--rp-text-3);letter-spacing:.2px;
}
.rp-intake__gtcount{
  margin-left:auto;font-size:11.5px;font-weight:700;
  color:var(--rp-text-3);white-space:nowrap;
}
.rp-intake__gtcount b{
  font-family:var(--rp-font-num);color:var(--rpd-org);font-weight:800;
}

/* ---------- 4.3 录入项行 ----------
   状态三态：done（已录）/ now（正在测）/ todo（未测）
   "now" 用左侧 3px 主色条 + 极浅底 + 序号实心 —— 教练永远知道"当前该录哪个" */
.rp-intake__items{
  background:var(--rp-surface);border:1px solid var(--rp-border);
  border-radius:var(--rp-radius);overflow:hidden;
  box-shadow:var(--rp-shadow-sm);
}
.rp-intake__item{
  position:relative;
  display:grid;
  grid-template-columns:30px 1fr;
  grid-template-areas:"ord nm" "ord inp";
  gap:2px 12px;align-items:center;
  padding:10px 13px 11px;
  border-bottom:1px solid var(--rp-line);
  transition:background .18s;
}
.rp-intake__item:last-child{border-bottom:0}
.rp-intake__item--now{background:var(--rp-fill-primary)}
.rp-intake__item--now::before{
  content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--rpd-org);
}
.rp-intake__ord{
  grid-area:ord;justify-self:center;align-self:center;
  width:26px;height:26px;border-radius:9px;
  display:flex;align-items:center;justify-content:center;
  font-family:var(--rp-font-num);font-size:12px;font-weight:800;
  background:var(--rp-surface-2);color:var(--rp-text-3);
  border:1px solid var(--rp-border);
}
.rp-intake__item--done .rp-intake__ord{
  background:var(--rp-excellent);color:var(--rp-on-excellent);border-color:transparent;
}
.rp-intake__item--done .rp-intake__ord::before{content:'✓';font-size:13px}
.rp-intake__item--done .rp-intake__ord b{display:none}
/* 已明确标记「本次不测」：用**中性灰 + 斜杠**而不是第二个绿勾。
   理由（UX 裁定）：绿勾 = "有数据且已录"，斜杠 = "这次没有测"。
   两者若都长成勾，教练和报告端都分不清「已完成」与「本次不测」——
   而这两种在报告端的后果完全不同。 */
.rp-intake__item--na .rp-intake__ord{
  background:var(--rp-surface-2);color:var(--rp-text-3);
  border:1.5px dashed var(--rp-border-strong);
}
.rp-intake__item--na .rp-intake__ord::before{content:'—';font-size:14px;font-weight:700}
.rp-intake__item--na .rp-intake__ord b{display:none}
.rp-intake__item--now .rp-intake__ord{
  background:var(--rp-primary);color:var(--rp-on-primary);border-color:transparent;
  box-shadow:0 0 0 4px var(--rp-ring-primary);
}
.rp-intake__nm{
  grid-area:nm;min-width:0;
  display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;
}
.rp-intake__nmname{font-size:14.5px;font-weight:700;color:var(--rp-text)}
.rp-intake__item--todo .rp-intake__nmname{color:var(--rp-text-2)}
.rp-intake__item--na .rp-intake__nmname{color:var(--rp-text-2)}
/* 「本次不测」已记录的标记 —— 录完后必须留痕，
   让教练能区分「还没录」与「已标记为不测」（UX 硬要求） */
.rp-intake__natag{
  display:inline-flex;align-items:center;gap:5px;
  font-size:11px;font-weight:700;color:var(--rp-text-3);
  padding:2px 8px;border-radius:6px;
  background:var(--rp-fill-muted);
  border:1px dashed var(--rp-border-strong);
}
.rp-intake__natag::before{
  content:'';width:10px;height:0;border-top:2px solid currentColor;flex-shrink:0;
}
/* 「取消不测」—— 给教练后悔药。
   ⚠️ 它**必须是可回退的**（UX 问的就是这点）：
   `__natag`（中性灰）是"已发生的事实"，撤销是"改变这个事实的行动"，
   两者语义不同类 —— 所以撤销给主青色 + 下划线，
   不能也做成中性灰，否则教练找不到从哪改回来。
   视觉权重仍低于主 CTA：它是纠错动作，不是流程推进。 */
.rp-intake__naundo{
  font-family:inherit;font-size:11.5px;font-weight:700;
  color:var(--rp-primary);background:none;border:0;
  padding:4px 6px;min-height:32px;
  text-decoration:underline;text-underline-offset:2px;
  text-decoration-thickness:1px;
  -webkit-appearance:none;appearance:none;
}
.rp-intake__naundo:hover{color:var(--rp-primary-l);background:var(--rp-fill-primary)}
.rp-intake__naundo:focus-visible{outline:none;box-shadow:0 0 0 3px var(--rp-ring-primary)}
@media(hover:none),(max-width:768px){ .rp-intake__naundo{min-height:44px;padding:4px 10px} }
.rp-intake__nmhint{
  font-size:11px;color:var(--rp-text-3);line-height:1.5;
}
.rp-intake__nmhint b{color:var(--rp-text-2);font-weight:700}

/* 大号数字输入：56px 高 —— 教练站着、单手、可能戴手套/拿器材。
   font-size 22px：既够大看清，又不会让 iOS 输入框横向溢出。 */
.rp-intake__inp{
  grid-area:inp;
  display:flex;align-items:center;gap:9px;margin-top:5px;
}
.rp-intake__num{
  flex:1;min-width:0;min-height:56px;
  padding:8px 13px;
  font-family:var(--rp-font-num);font-size:22px;font-weight:800;
  font-variant-numeric:tabular-nums;text-align:center;
  font-family:var(--rp-font-num);
  color:var(--rp-text);
  background:var(--rp-surface);border:1.5px solid var(--rp-border);
  border-radius:var(--rp-radius-sm);
  -webkit-appearance:none;appearance:none;
  transition:border-color .15s,box-shadow .15s;
}
.rp-intake__num:focus{
  outline:none;border-color:var(--rp-primary);
  box-shadow:0 0 0 3px var(--rp-ring-primary);
}
.rp-intake__num[readonly]{
  background:var(--rp-surface-2);color:var(--rp-text-3);
  border-style:dashed;
}
.rp-intake__unit{
  font-size:12px;font-weight:700;color:var(--rp-text-3);
  white-space:nowrap;flex-shrink:0;
}
.rp-intake__grade{
  flex-shrink:0;width:64px;display:flex;justify-content:flex-end;
}
/* 「本次不测」按钮（原名「跳过」，UX 裁定改名）
   ── 为什么改名是关键，不是措辞洁癖 ──
   已核实 server.js:47validate()：空值直接 continue，
   引擎对缺失项产出 score:null。也就是说「跳过」和「未测」
   在数据层是**同一件事** —— 那个「未测」会立刻写进报告。

   原名「跳过」暗示"我等下回来填"，教练点完以为自己没填完、
   系统会提醒；实际上数据已经记为未测了。UX 裁定改名为
   **「本次不测」**：这是一个**已记录的结论**，让后果在动作
   发生的那一刻就可见。视觉上相应地给它一个"确认中"的样式，
   按下后整行切换成 .rp-intake__item--na 的留痕状态。 */
.rp-intake__skip{
  flex-shrink:0;min-height:56px;min-width:52px;padding:0 10px;
  font-family:inherit;font-size:12px;font-weight:700;
  color:var(--rp-text-3);background:var(--rp-surface-2);
  border:1px solid var(--rp-border);border-radius:var(--rp-radius-sm);
  -webkit-appearance:none;appearance:none;
  transition:.15s;
}
/* hover 不再变红 —— 它不是"错误/危险"动作，是一个中性记录动作。
   用橙（与机构侧主行动同色相但这里只做文字色）会暗示"要点它"，
   用红会暗示"点错后果严重"。中性灰 + 虚线是准确的态度。 */
.rp-intake__skip:hover{
  color:var(--rp-text-2);border-color:var(--rp-border-strong);
  background:var(--rp-surface);
}
.rp-intake__skip:focus-visible{outline:none;box-shadow:0 0 0 3px var(--rp-ring-primary)}
/* 按下态 = 明确显示"这一项会被记为未测"，不是"已选中" */
.rp-intake__skip[aria-pressed="true"]{
  background:var(--rp-fill-muted);color:var(--rp-text-2);
  border:1.5px dashed var(--rp-border-strong);
}
@media(max-width:400px){
  .rp-intake__inp{flex-wrap:wrap}
  .rp-intake__num{flex:1 0 100%;order:1}
  .rp-intake__grade{order:2;width:auto}
  .rp-intake__skip{order:3}
}

/* ---------- 4.4 体姿体态评估（机构链路独有） ----------
   视觉上刻意与标准项目组区分：虚线描边 + 橙色 + 体姿照槽位。
   理由：如果它长得跟标准项目一样，家长/教练会以为"体态也是打个分"，
   实际上体态是**看照片说问题**，两者的操作与产出完全不同。 */
.rp-intake__posture{
  padding:14px 15px;
  background:var(--rp-surface);
  border:1.5px dashed var(--rp-accent);
  border-radius:var(--rp-radius);
}
.rp-intake__posturehd{
  display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:4px;
}
.rp-intake__posturettl{
  display:flex;align-items:center;gap:8px;
  font-size:15.5px;font-weight:800;color:var(--rpd-posture-ink);
}
.rp-intake__posturettl::before{
  content:'';width:4px;height:16px;border-radius:3px;background:var(--rp-accent);
}
.rp-intake__posturesub{
  font-size:11.5px;color:var(--rp-text-2);line-height:1.65;
  margin:0 0 12px;padding-bottom:11px;
  border-bottom:1px solid var(--rp-border);
}
/* 体姿照槽位：3 个机位（正面/侧面/背面） */
.rp-intake__shots{
  display:grid;grid-template-columns:repeat(3,1fr);gap:9px;
}
@media(max-width:420px){ .rp-intake__shots{grid-template-columns:repeat(3,1fr);gap:7px} }
.rp-intake__shot{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:6px;min-height:104px;padding:9px 6px;
  background:var(--rp-surface-2);
  border:1.5px dashed var(--rp-border-strong);border-radius:12px;
  color:var(--rp-text-3);font-size:11px;font-weight:700;text-align:center;
  cursor:pointer;font-family:inherit;
  transition:border-color .18s,background .18s;
}
.rp-intake__shot:hover{border-color:var(--rp-accent);background:var(--rpd-posture-tint)}
.rp-intake__shot:focus-visible{outline:none;box-shadow:0 0 0 3px var(--rp-ring-accent)}
.rp-intake__shotico{font-size:22px;line-height:1}
.rp-intake__shot--ok{
  border-style:solid;border-color:var(--rp-accent);
  background:var(--rpd-posture-tint);color:var(--rpd-posture-ink);
  padding:0;overflow:hidden;position:relative;
}
.rp-intake__shot--ok img{width:100%;height:104px;object-fit:cover;display:block}
/* 体态结论选择：3~4 个常见结论，用 pill 而非下拉（教练现场单手） */
.rp-intake__concl{
  display:flex;flex-wrap:wrap;gap:7px;margin-top:12px;
  padding-top:12px;border-top:1px solid var(--rp-border);
}
.rp-intake__conclab{
  width:100%;font-size:11px;font-weight:700;color:var(--rp-text-3);
  letter-spacing:.3px;margin-bottom:1px;
}
.rp-intake__pill{
  min-height:40px;padding:8px 14px;
  display:inline-flex;align-items:center;gap:6px;
  font-family:inherit;font-size:12.5px;font-weight:700;
  color:var(--rp-text-2);background:var(--rp-surface-2);
  border:1px solid var(--rp-border);border-radius:20px;
  transition:.15s;cursor:pointer;-webkit-appearance:none;appearance:none;
}
@media(hover:none),(max-width:768px){ .rp-intake__pill{min-height:44px} }
.rp-intake__pill:hover{border-color:var(--rp-accent);color:var(--rpd-posture-ink)}
.rp-intake__pill:focus-visible{outline:none;box-shadow:0 0 0 3px var(--rp-ring-accent)}
.rp-intake__pill[aria-pressed="true"]{
  background:var(--rp-accent);color:var(--rp-on-accent);border-color:transparent;
}

/* ---------- 4.5 录入页吸底行动条 ----------
   与 .rp-query__actions 同一手法：教练录完最后一项，必须能立刻生成报告，
   不能让他滚到页面顶部找按钮。 */
.rp-intake__bar{
  position:sticky;bottom:0;z-index:30;
  margin:16px -14px -56px;
  padding:12px 14px calc(12px + env(safe-area-inset-bottom,0px));
  display:flex;align-items:center;gap:11px;flex-wrap:wrap;
  background:var(--rp-surface);border-top:1px solid var(--rp-border);
  box-shadow:0 -6px 18px rgba(18,28,38,.08);
}
.rp-intake__barinfo{
  flex:1;min-width:140px;
  font-size:11.5px;color:var(--rp-text-3);line-height:1.55;
}
.rp-intake__barinfo b{
  font-family:var(--rp-font-num);font-size:13px;font-weight:800;color:var(--rp-primary);
}
.rp-intake__barinfo.is-warn{color:var(--rp-accent-d)}
/* ⚠️ 橙色纪律的具体落点（UX 提出，我认同并加严）：
   机构侧「录入学员 / 开始录入」已经是橙色主 CTA。
   如果录入学员的页面**同一屏内**还有打印 CTA，两块橙色会撞车，
   用户分不清哪个是主行动。所以：

   .rp-intake__bar 里的「生成报告」用**主青实心**，不用橙。
   理由：它在这一屏的作用是"完成本次录入"（推进当前流程），
   而橙色在整个机构链路里恒定代表"新建/开始一次录入"这件事。
   同色 = 同类语义，不能因为都在按钮里就混用。 */
.rp-intake__cta{
  flex-shrink:0;min-height:50px;padding:0 20px;
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  font-family:inherit;font-size:14px;font-weight:700;
  background:var(--rp-primary);color:var(--rp-on-primary);
  border:1px solid transparent;border-radius:var(--rp-radius-sm);
  -webkit-appearance:none;appearance:none;
  transition:filter .15s;
}
.rp-intake__cta:hover{filter:brightness(1.06)}
.rp-intake__cta:focus-visible{outline:none;box-shadow:0 0 0 3px var(--rp-ring-primary)}
.rp-intake__cta[disabled]{
  background:var(--rp-surface-2);color:var(--rp-text-3);
  border-color:var(--rp-border);filter:none;cursor:not-allowed;
}
/* 「存草稿」：比 CTA 弱一档，用 ghost。教练中途被叫走是常态 */
.rp-intake__cta--ghost{
  min-height:44px;padding:0 15px;font-size:13px;
  background:var(--rp-surface);color:var(--rp-text-2);
  border-color:var(--rp-border);
}
.rp-intake__cta--ghost:hover{background:var(--rp-surface-2);color:var(--rp-text)}
@media(min-width:768px){
  .rp-intake__bar{
    position:static;margin:18px 0 0;padding:14px 0 0;
    border-top:1px dashed var(--rp-border-strong);box-shadow:none;background:none;
  }
}

/* 保存草稿提示：录入中途离开不丢数据（教练会被家长叫走） */
.rp-intake__autosave{
  display:flex;align-items:center;gap:6px;
  font-size:11px;color:var(--rp-text-3);
}
.rp-intake__autosave::before{
  content:'';width:6px;height:6px;border-radius:50%;
  background:var(--rp-excellent);flex-shrink:0;
}
.rp-intake__autosave.is-idle::before{background:var(--rp-untested)}


/* =============================================================
 * 5. 机构体测 · 报告管理列表
 * -------------------------------------------------------------
 * 教练/老板的高频动线：打开 → 看"谁还没出报告" → 点进去打印。
 * 所以行的信息密度按"**能不能立刻判断要不要动手**"来排：
 *   姓名 + 最近测评日期 + 综合分 + 报告状态 + 体态评估状态。
   状态用 chip 而非颜色块：三个状态并存，颜色越多越读不出来。
 * ============================================================= */
.rp-mgr__bar{
  display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  margin-bottom:12px;
}
.rp-mgr__bar .rp-seg{flex:0 1 auto}
.rp-mgr__count{
  font-size:11.5px;color:var(--rp-text-3);font-weight:600;white-space:nowrap;
}
.rp-mgr__count b{
  font-family:var(--rp-font-num);color:var(--rpd-org);font-weight:800;font-size:13px;
}
.rp-mgr__srch{flex:1;min-width:170px}

.rp-mgr__list{display:flex;flex-direction:column;gap:8px}
.rp-mgr__row{
  position:relative;
  display:grid;
  /* 手机：姓名+元信息一列，右侧分数；两个状态 chip 在左下 */
  grid-template-columns:auto 1fr auto;
  grid-template-areas:
    "av name score"
    "av meta score"
    "st  st   st";
  gap:3px 11px;align-items:center;
  width:100%;text-align:left;padding:12px 13px;
  font-family:inherit;cursor:pointer;
  background:var(--rp-surface);color:var(--rp-text);
  border:1px solid var(--rp-border);border-radius:var(--rp-radius-sm);
  transition:box-shadow .18s,border-color .18s;
}
.rp-mgr__row:hover{box-shadow:var(--rp-shadow);border-color:var(--rpd-org)}
.rp-mgr__row:active{transform:scale(.99)}
.rp-mgr__row:focus-visible{
  outline:none;border-color:var(--rp-primary);box-shadow:0 0 0 3px var(--rp-ring-primary);
}
.rp-mgr__av{
  grid-area:av;
  width:40px;height:40px;border-radius:13px;flex-shrink:0;
  background:var(--rp-surface-2);color:var(--rp-text-2);
  display:flex;align-items:center;justify-content:center;
  font-size:16px;font-weight:800;font-family:var(--rp-font-num);
}
.rp-mgr__row--tone .rp-mgr__av{background:var(--rpd-posture-tint);color:var(--rpd-posture-ink)}
.rp-mgr__nm{
  grid-area:name;min-width:0;
  font-size:15px;font-weight:800;color:var(--rp-text);
  display:flex;align-items:center;gap:6px;flex-wrap:wrap;
}
.rp-mgr__gender{
  font-size:10.5px;font-weight:700;padding:2px 7px;border-radius:6px;
  background:var(--rp-surface-2);color:var(--rp-text-2);
}
.rp-mgr__meta{
  grid-area:meta;min-width:0;
  font-size:11.5px;color:var(--rp-text-3);line-height:1.5;
  display:flex;flex-wrap:wrap;gap:2px 9px;
}
.rp-mgr__meta b{
  font-family:var(--rp-font-num);color:var(--rp-text-2);font-weight:700;
  font-variant-numeric:tabular-nums;
}
.rp-mgr__score{
  grid-area:score;justify-self:end;text-align:right;line-height:1.05;
  font-family:var(--rp-font-num);font-variant-numeric:tabular-nums;
}
.rp-mgr__score b{display:block;font-size:22px;font-weight:800;color:var(--rp-primary)}
.rp-mgr__score small{
  display:block;font-size:10px;color:var(--rp-text-3);
  font-family:var(--rp-font);font-weight:600;margin-top:2px;
}
.rp-mgr__row--untested .rp-mgr__score b{color:var(--rp-untested)}
/* 状态 chip 区 */
.rp-mgr__st{
  grid-area:st;
  display:flex;align-items:center;gap:6px;flex-wrap:wrap;
  padding-top:8px;margin-top:5px;
  border-top:1px solid var(--rp-line);
}
.rp-mgr__gost{margin-left:auto;color:var(--rp-text-3);font-size:15px}
.rp-mgr__gost::after{content:'›'}
.rp-mgr__row:hover .rp-mgr__gost{color:var(--rp-primary)}

@media(min-width:720px){
  .rp-mgr__row{
    grid-template-columns:40px 1.3fr .8fr .6fr .9fr auto 16px;
    grid-template-areas:"av name meta score score st go";
    gap:0 13px;padding:11px 15px;
  }
  .rp-mgr__st{
    padding-top:0;margin-top:0;border-top:0;justify-self:end;
  }
  .rp-mgr__gost{grid-area:go;margin-left:0}
}

/* 状态 chip：形状 + 文字 + 颜色三重编码
   （形状是给打印和色盲留的冗余，不是装饰） */
.rp-mgr__chip{
  display:inline-flex;align-items:center;gap:4px;
  min-height:22px;padding:2px 8px;border-radius:6px;
  font-size:11px;font-weight:700;line-height:1.5;white-space:nowrap;
  background:var(--rp-surface-2);color:var(--rp-text-2);
  border:1px solid var(--rp-border);
}
.rp-mgr__chip::before{
  font-size:9px;line-height:1;flex-shrink:0;
}
/* 报告已生成（可打印）→ 复用"良好"青 */
.rp-mgr__chip--ready{
  background:var(--rp-fill-primary);color:var(--rp-primary);border-color:transparent;
}
.rp-mgr__chip--ready::before{content:'●'}
/* 报告未生成 → 中性灰虚线（不是红：没出报告不等于有问题） */
.rp-mgr__chip--none{
  background:none;color:var(--rp-text-3);border-style:dashed;
}
.rp-mgr__chip--none::before{content:'○'}
/* 报告有草稿/未完成 */
.rp-mgr__chip--draft{
  background:var(--rp-fill-accent);color:var(--rp-accent-ink);border-color:transparent;
}
.rp-mgr__chip--draft::before{content:'◐'}
/* 体态评估：已完成 */
.rp-mgr__chip--tone{
  background:var(--rpd-posture-tint);color:var(--rpd-posture-ink);border-color:transparent;
}
.rp-mgr__chip--tone::before{content:'▣'}
/* 体态评估：未做 */
.rp-mgr__chip--notone{
  background:none;color:var(--rp-text-3);border-style:dashed;
}
.rp-mgr__chip--notone::before{content:'▢'}
.rp-mgr__chip--new{
  background:var(--rp-accent);color:var(--rp-on-accent);border-color:transparent;
}
.rp-mgr__chip--new::before{content:'NEW';font-size:8.5px;letter-spacing:.3px}

/* 报告管理分组小标题（如"本月已测 12 人"）
   ⚠️ 已按 UX 裁定移除（Q7）。原预留类 .rp-mgr__grp 删除。
   理由不只是 YAGNI：园所链路有「班级」概念，机构侧再来一个
   分组/班级会让用户以为是同一件事 —— 直接违反本文件 §D5 的
   「两链路字样隔离」硬纪律。真实需求出现时再开一轮抽象。 */


/* =============================================================
 * 6. 暗色主题
 * -------------------------------------------------------------
 * 只补 §1 里那两个**新增** token 的暗色值（fill-excellent）。
 * 其余全部自动跟随 —— 因为它们是 report.css --rp-* 的别名，
 * 而 report.css 的暗色覆盖就写在 `.rp-app` 上（见 report.css §6）。
 *
 * ⚠️ 这里**必须**与 report.css §6 一样写两遍：
 *    系统偏好 + 显式 data-theme（后者优先级更高）。
 * ============================================================= */
/* 深色主题已全局移除（2026-10-18）。原先这里是配合 report.css §6 的
   --rpd-fill-up 暗色覆盖（进步榜填充色），主题去掉后不再需要。 */

/* 暗色下两个板块的标识色要拉开：园所 = 亮青 #3FD3D8、机构 = 青 #2BC4C9
   （--rpd-kind 取 --rp-primary-l、--rpd-org 取 --rp-primary，
   暗色下这两个值本身就不同，天然有区分度，无需覆盖。）
   但图标底色在暗色下 fill-primary 已提亮，两个板块图标会看起来一样。
   → 机构侧改用「描边」方案（§3.3 已写），不依赖底色，天然规避。 */


/* =============================================================
 * 7. 响应式
 * ============================================================= */
@media (max-width:768px){
  /* 录入吸底条与 .rp-shell 的 12px 边距对齐（report.css §7 把 shell 改成 12px）*/
  .rp-intake__bar{margin:16px -12px -56px;padding:12px 12px calc(12px + env(safe-area-inset-bottom,0px))}

  /* 板块卡在手机上占满，靠留白与分隔线分组，不做双列 */
  .rp-sector__hd{grid-template-columns:46px 1fr;gap:10px;padding:14px 14px 0}
  .rp-sector__ico{width:46px;height:46px;font-size:22px;border-radius:14px}
  .rp-sector__ttl{font-size:16.5px}
  .rp-sector__items,.rp-sector__acts{padding-left:14px;padding-right:14px}

  /* 触摸目标统一抬到 44px（机构侧录入页原为 56px，是有意的，不在此降）*/
  .rp-sector__act{min-height:var(--rp-tap)}
  .rp-mgr__row{padding:12px}
}
@media (max-width:360px){
  .rp-sector__hd{grid-template-columns:40px 1fr;gap:9px}
  .rp-sector__ico{width:40px;height:40px;font-size:19px;border-radius:12px}
  .rp-sector__ttl{font-size:15.5px}
  .rp-intake__nmname{font-size:13.5px}
  .rp-cmp__heronum{font-size:26px}
  .rp-cmp__rankrow{grid-template-columns:56px 1fr 68px;gap:8px}
}
@media (min-width:1280px){
  /* 桌面：对比区块限制行宽，8 项变化表不要拉成一条 2000px 的横线 */
  .rp-cmp{max-width:820px}
  .rp-cmp--garden{max-width:1000px}
}


/* =============================================================
 * 8. 打印（A4 纵向 · 灰阶单调 · 延续 report.css §8 的纪律）
 * -------------------------------------------------------------
 * 本文件所有新增块在打印时的三条硬线：
 *  ① 零新色 —— 全部落回黑/白/灰。变化方向靠**箭头形状 + 边框样式**冗余：
 *     进步 = 实心▲ + 白底黑字；退步 = 实心▼ + 灰底黑字 + 上下点线框；
 *     持平 = 短横 — + 虚线框。
 *  ② 发散条形榜在纸面上必须能读出"中轴=0"，故中轴加粗成实线，
 *     且左右两侧加不同的边框样式（右侧实线 / 左侧虚线）。
 *  ③ 分页不撕裂：对比区块 break-inside:avoid；
 *     区间若 >6 行（一次半学期 6 次以上）时由 JS 加 .rp-cmp--long，
 *     打印时改为双列 8 项，8 行永远挤在一页内。
 * ============================================================= */
@media print{
  /* ══════════════════════════════════════════════════════════
   * 【打印折叠】成绩单必须保持单页
   * ══════════════════════════════════════════════════════════
   * fe-report 实测（单期班级，2061px vs A4 可用 2031px）：
   *   KPI 179px → 对比空态 153px → 排名空态 63px → itemStats 285px → …
   * 略超约 30px 就把成绩单挤到第 2 页 —— 而这张纸是老师打印给家长、
   * 家长要签字的，**多一页等于成绩单作废**。

   * 决策：对比区块在打印时**折叠**，而不是直接删掉。
   *   · 删掉 = 家长拿到一份看不出变化的成绩单，签字的人不知道孩子进步没；
   *   · 展开 = 破坏单页。
   *   → 折叠成一行摘要（fe-report 渲染 .rp-printcmp 的内容），
   *     页数不增，家长仍能看到"综合分 78→85（+7）"。

   * ⚠️ 类名核对（我方与 fe-report 双侧已对齐）：
   *   · 空态类是 **.rp-cmp__none**，不是 .rp-cmp__empty
   *     （team-lead 的指令里写的是 empty，实际双方代码都用 none —— 以实际为准）
   *   · .rp-cmp__thin / --wait 样本不足降级（§2.7b）
   *   · .rp-printcmp 折叠摘要行，**内容与文案由 fe-report 渲染**
   */
  .rp-cmp__none,
  .rp-cmp__thin,
  .rp-cmp__thin--wait{display:none!important}

  /* 整个对比区不进打印正文（空态本来也在 .rp-cmp 内，
     上面三条是冗余保险 —— 将来若有人把空态提到 .rp-cmp 外仍能隐藏） */
  .rp-cmp{display:none!important}

  /* ⚠️⚠️ 结构性约束：.rp-printcmp 必须是 .rp-cmp 的**兄弟节点**，不能是它的子节点！
     CSS 无法让子元素覆盖祖先的 display:none —— 父级 hidden ⇒ 整棵子树不渲染，
     子元素的 display:block 不会生效，**折叠会静默失效**（打印时整块消失，
     连摘要行一起没了，正好是最糟的结果：成绩单既没有对比、也没有摘要）。

     正确结构（fe-report 渲染时务必遵守）：
         <div class="rp-cmp">…完整对比区…</div>      ← 打印隐藏
         <div class="rp-printcmp">综合分 78→85（+7）…</div>   ← 打印显示
     两者是兄弟，不是父子。 */
  .rp-printcmp{
    display:block!important;
    break-inside:avoid;page-break-inside:avoid;
    /* 折叠摘要行的纸面样式（内容文案由 fe-report 渲染，这里只管排版）。
       单行、灰底、细边框 —— 它是成绩单的脚注，不是标题。 */
    padding:3pt 6pt!important;margin:0 0 6pt!important;
    background:#F2F2F2!important;
    border:.5pt solid #999!important;border-radius:2pt!important;
    font-size:8.5pt;line-height:1.5;color:#000!important;
    break-after:avoid;page-break-after:avoid;
  }
  /* 摘要行内若复用了 .rp-cmp__delta / .rp-cmp__base / .rp-cmp__n，
     它们会继承本节后面的打印规则（黑白化+边框冗余）—— 无需重复声明。
     唯一要防的是 delta 的底色在浅灰上发灰，故强制白底+黑框。 */
  .rp-printcmp .rp-cmp__delta{
    background:#fff!important;border:.75pt solid #000!important;color:#000!important;
  }

  /* ── 期次 / 基准标注（打印件必须显式印出）─────────────────────
     为什么必须印：报告支持 ?t=N 切换期次，期次切换器**屏显可见、打印隐藏**。
     老师切到第 2 期看了一会儿再打印，纸面若不标期次 —— 就是一张
     "看不出是哪一期"的成绩单，纸面与屏幕不一致，属 bug。

     ⚠️ 内容必须放在 .rp-printcmp 里，**不能放 .rp-cmp__base**：
     已核实 report.js:600-615 的 DOM 结构 —— base 是 .rp-cmp__hd 的子元素、
     .rp-cmp__hd 又在 .rp-cmp 内；而本节的 .rp-cmp{display:none!important}
     会把整棵子树连坐掉。放base 里 ⇒ 纸面既没有对比也没有基准标注，
     比不做折叠更糟（家长签字时无从判断这张纸说的是哪一期）。

     用法（fe-report）：在 .rp-printcmp 的文本里带上期次与基准，
     不需要新类名 —— 本段只保证「摘要行里的期次/基准文字」排版协调。*/
  .rp-printcmp .rp-printcmp__term{
    font-size:8pt;font-weight:700;color:#000;
    white-space:nowrap;margin-right:6pt;
  }
  /* 分隔用的中点：不用竖线（黑白下竖线容易被读成表格边界） */
  .rp-printcmp .rp-printcmp__term b{font-weight:800}
  .rp-printcmp .rp-printcmp__dot{
    color:#666;margin:0 4pt;font-weight:400;
  }
  /* 期次与基准整体作为一个不可拆的整体：分页时不要被切开 */
  .rp-printcmp .rp-printcmp__meta{
    display:inline-block;white-space:nowrap;
    break-inside:avoid;page-break-inside:avoid;
  }

  /* —— 隐藏交互件 —— */
  .rp-cmp__switch,
  .rp-dual__anchor,
  .rp-intake__bar,
  .rp-intake__skip,
  .rp-intake__shot:not(.rp-intake__shot--ok),
  .rp-sector__actgo,
  .rp-mgr__srch,
  .rp-mgr__gost,
  .rp-intake__autosave{display:none!important}

  /* —— 入口页：板块卡转成两份"档案页"，各占一页的两栏 —— */
  .rp-dual{display:block!important}
  .rp-sector{
    border:1pt solid #B9B9B9!important;border-radius:0!important;
    box-shadow:none!important;break-inside:avoid;page-break-inside:avoid;
    margin-bottom:8pt;
  }
  /* 顶部 3px 板块色：黑白会变灰块 → 改为文字标签，靠内容区分板块 */
  .rp-sector{border-top:1.5pt solid #000!important}
  .rp-sector__ico{
    background:#fff!important;border:.75pt solid #000;
    width:26pt;height:26pt;font-size:13pt;border-radius:0;
  }
  .rp-sector__ttl{font-size:12pt;color:#000}
  .rp-sector__sub{font-size:8.5pt;color:#333}
  .rp-sector__scale{
    background:#fff!important;border:.75pt solid #000!important;color:#000!important;
    font-size:7.5pt;padding:0 4pt;
  }
  .rp-sector__dots{display:none}          /* 点阵打印无意义，纯装饰 */
  .rp-sector__itemslab{font-size:7.5pt;color:#555}
  .rp-chip{
    background:#fff!important;border:.5pt solid #999!important;color:#333!important;
    font-size:7.5pt;padding:0 4pt;border-radius:2pt;
  }
  /* 独有增量项（体态）打印必须能看出来 → 虚线框 */
  .rp-chip--ext{border:.75pt dashed #000!important;color:#000!important;font-weight:800}
  .rp-chip--ext::before{content:'+ '}
  .rp-sector__actsrow{display:block!important}
  .rp-sector__act{
    background:#fff!important;border:.5pt solid #999!important;
    box-shadow:none!important;border-radius:0!important;
    min-height:0;padding:3pt 4pt!important;margin-bottom:3pt;
    break-inside:avoid;
  }
  .rp-sector__act--primary{
    border:1pt solid #000!important;background:#fff!important;color:#000!important;
  }
  .rp-sector__act--primary .rp-sector__actt,
  .rp-sector__act--primary .rp-sector__actd,
  .rp-sector__act--primary .rp-sector__actico{color:#000!important}
  .rp-sector__actico{
    background:#fff!important;border:.5pt solid #999;border-radius:0;
    width:16pt;height:16pt;font-size:9pt;
  }
  .rp-sector__actt{font-size:9.5pt;color:#000}
  .rp-sector__actd{font-size:8pt;color:#555}
  .rp-sector__actnew{
    background:#fff!important;color:#000!important;
    border:.5pt solid #000;font-size:7pt;
  }
  .rp-sector__foot{
    background:#fff!important;border-top:.5pt solid #999;
    font-size:7.5pt;color:#555;padding:4pt 5pt!important;
  }

  /* —— 对比区块：卡片化 + 不撕裂 —— */
  .rp-cmp{
    border:1pt solid #B9B9B9!important;border-radius:0!important;
    box-shadow:none!important;padding:8pt 9pt!important;margin:0 0 8pt!important;
    break-inside:avoid;page-break-inside:avoid;max-width:none!important;
  }
  .rp-cmp__ttl{font-size:11.5pt;color:#000}
  .rp-cmp__ttl::before{background:#000!important;height:13pt}
  .rp-cmp__n{
    background:#fff!important;border:.75pt solid #000;
    color:#000!important;font-size:8pt;border-radius:2pt;
  }
  .rp-cmp__scope{font-size:8pt;color:#555}
  .rp-cmp__scope b{color:#000}

  /* 综合分变化摘要条 */
  .rp-cmp__hero{
    background:#fff!important;border:.75pt solid #999;
    border-radius:0!important;padding:5pt 6pt!important;margin-bottom:6pt;
  }
  .rp-cmp__heronum{font-size:17pt!important;color:#000!important}
  .rp-cmp__heronum small{color:#555;font-size:8pt}
  .rp-cmp__herolab{font-size:8.5pt;color:#333}
  .rp-cmp__herolab b{color:#000!important}

  /* 柱列：灰阶 + 边框冗余。60 分线变实线黑（虚线在纸上看不见）*/
  .rp-cmp__axis{overflow:visible!important}
  .rp-cmp__bar{height:38pt}
  .rp-cmp__bar::before{
    background:#fff!important;border:.5pt solid #CCC;border-radius:0;
  }
  .rp-cmp__bar::after{border-top:.75pt solid #000!important;opacity:1!important}
  .rp-cmp__fill{background:#8C8C8C!important;border-radius:0!important;width:14pt}
  .rp-cmp__col--now .rp-cmp__fill{background:#000!important}
  .rp-cmp__colval{font-size:9.5pt;color:#000}
  .rp-cmp__colval small{color:#555;font-size:7pt}
  .rp-cmp__axisline{border-top:.75pt solid #000;margin-top:4pt}
  .rp-cmp__ptdot{
    background:#fff!important;border:.75pt solid #000;border-radius:0!important;
    width:6pt;height:6pt;
  }
  .rp-cmp__pt--now .rp-cmp__ptdot{
    background:#000!important;border:.75pt solid #000;width:8pt;height:8pt;
  }
  .rp-cmp__ptdt{font-size:7.5pt;color:#555}
  .rp-cmp__pt--now .rp-cmp__ptdt{color:#000}
  .rp-cmp__ptline{background:#000;height:.75pt;min-width:4pt}

  /* 基准标注：打印时**必须保留**。它是"这组数字跟谁比"的唯一说明，
     丢了它打印件就变成一堆没有基准的分数。 */
  .rp-cmp__base{
    background:#fff!important;border:.5pt solid #999!important;color:#000!important;
    font-size:7.5pt;padding:0 4pt;border-radius:2pt;
  }
  .rp-cmp__base::before{background:#000!important}
  .rp-cmp__base b{color:#000!important}
  .rp-cmp__base--alt{border-style:dashed!important;color:#555!important}

  /* 样本量：打印时同样必须保留 ——
     老师打印出来给家长看，家长有权知道"这个平均分基于几个人"。 */
  .rp-cmp__n{
    background:#fff!important;border:.5pt solid #999!important;
    color:#000!important;font-size:7.5pt;border-radius:2pt;
  }
  .rp-cmp__n--warn{
    border:.75pt solid #000!important;font-weight:800;
    -webkit-print-color-adjust:exact;print-color-adjust:exact;
  }
  /* 样本不足的降级提示：打印时用**框型区分两种成因**，不能灰掉 ——
     它是在解释"为什么没有全园对比"，需要家长读得出来。
     漏测多：实线框（可行动）；无人补测：虚线框（只能等）。 */
  .rp-cmp__thin{
    background:#fff!important;border:.75pt solid #000!important;
    color:#000!important;font-size:8.5pt;padding:5pt 6pt!important;
    break-inside:avoid;
  }
  .rp-cmp__thin b{color:#000!important;font-weight:800}
  .rp-cmp__thin--wait{
    background:#fff!important;border:.75pt dashed #666!important;
    color:#333!important;
  }
  .rp-cmp__thin--wait b{color:#000!important}

  /* 集体层 seed 卡：措辞不同但同样保留 */
  .rp-cmp__seed--agg .rp-cmp__seedttl::after{
    background:#fff!important;border:.5pt dashed #000!important;
    color:#000!important;font-size:7.5pt;
  }

  /* 「成长记录 · 第 1 次」引导卡 —— **打印时必须原样保留**。
     它是家长拿到的那张纸上的"下次再来测一次"的理由，
     灰掉等于把最有价值的一句话删掉。 */
  .rp-cmp__seed{
    background:#fff!important;border:.75pt solid #999!important;
    border-radius:0!important;padding:8pt 9pt!important;
    break-inside:avoid;page-break-inside:avoid;
  }
  .rp-cmp__seed::after{display:none}   /* 背景剪影是屏幕装饰，纸上无意义 */
  .rp-cmp__seedttl{font-size:11.5pt;color:#000}
  .rp-cmp__seedttl::before{background:#000!important;height:13pt}
  .rp-cmp__seedn b{font-size:22pt!important;color:#000!important}
  .rp-cmp__seedn span{font-size:9pt;color:#333}
  .rp-cmp__seedd{font-size:9pt;color:#000!important;line-height:1.65}
  .rp-cmp__seedd b{color:#000!important;font-weight:800}
  .rp-cmp__seedhint{
    border-top:.5pt solid #999!important;font-size:8pt;color:#555;
    padding-top:5pt;margin-top:5pt;
  }
  .rp-cmp__seedhint::before{background:#000!important}
  .rp-cmp__seeddate{
    background:#fff!important;border:.5pt solid #999!important;
    color:#000!important;font-size:8pt;padding:1pt 5pt;border-radius:2pt;
  }
  .rp-cmp__seeddate::before{background:#000!important}

  /* 「本次未测」打印规格 —— 打印件上"未测"与"0 分"必须依然可区分。
     破折号 + 虚线框是两个数字永远拿不到的编码。 */
  .rp-na{
    background:#fff!important;color:#000!important;
    font-size:8.5pt;font-weight:700;
  }
  .rp-na::before{border-top:1.5pt solid #000!important;width:10pt;opacity:1}
  .rp-na--chip{
    background:#fff!important;border:.75pt dashed #666!important;
    color:#000!important;font-size:7.5pt;border-radius:2pt;padding:0 4pt;
  }
  .rp-dim--na,.rp-cmp__row--na{opacity:1}   /* 打印不做整体压暗 */
  .rp-dim--na .rp-dim__name,.rp-cmp__row--na .rp-cmp__nmname{color:#000!important}

  /* 录入页：「本次不测」的留痕状态
     序号位用实线框 + 破折号（区别于已录的实心方块），填的是手写位 */
  .rp-intake__item--na .rp-intake__ord{
    background:#fff!important;border:.75pt dashed #000!important;
    color:#000!important;border-radius:0;
  }
  .rp-intake__item--na .rp-intake__ord::before{content:'—';color:#000!important}
  .rp-intake__natag{
    background:#fff!important;border:.75pt dashed #666!important;
    color:#000!important;font-size:7.5pt;padding:0 4pt;border-radius:2pt;
  }
  .rp-intake__natag::before{border-top:1.5pt solid #000!important}
  .rp-intake__naundo{display:none!important}
  /* 但"已标记本次不测"这个事实必须随报告打印（靠 --na 序号位 + __natag）*/
  /* 录入吸底条里的 CTA：打印转成普通描边按钮，不与橙色 CTA 抢视觉 */
  .rp-intake__cta{
    background:#fff!important;border:.75pt solid #000!important;
    color:#000!important;font-size:8.5pt;min-height:0;padding:2pt 6pt;
  }
  .rp-intake__cta--ghost{border-color:#999!important;color:#555!important}

  /* ★ 变化徽标打印规格（三个层级共用同一套）——
     进步：白底 + 实线框 + 实心▲
     退步：浅灰底 + 上下点线框 + 实心▼
     持平：白底 + 虚线框 + 短横
     这样即使机器把 ▲▼ 印糊了，框型仍可区分。 */
  .rp-cmp__delta{
    background:#fff!important;color:#000!important;
    box-shadow:none!important;border:.75pt solid #000!important;
    border-radius:2pt!important;font-size:9pt;padding:0 4pt;min-height:0;
    font-weight:800;
  }
  .rp-cmp__delta::before{
    color:#000!important;font-size:7.5pt;
    -webkit-print-color-adjust:exact;print-color-adjust:exact;
  }
  .rp-cmp__delta--up{border-style:solid!important}
  .rp-cmp__delta--down{
    background:#EDEDED!important;border-style:dotted!important;border-width:1pt!important;
  }
  .rp-cmp__delta--flat{border-style:dashed!important;color:#555!important}
  .rp-cmp__delta--none{
    border:.5pt dashed #999!important;color:#666!important;font-weight:600;
  }
  .rp-cmp__delta--bare{
    background:none!important;border:0!important;padding:0;
    box-shadow:none!important;
  }
  .rp-cmp__delta--bare.rp-cmp__delta--flat{color:#666!important}

  /* 8 项变化行：两列排布（一次半学期 6 次测评 × 8 项很长） */
  .rp-cmp__rows{
    display:grid!important;grid-template-columns:repeat(2,1fr)!important;
    gap:0 10pt;border-top:0;
  }
  .rp-cmp__row{
    grid-template-columns:52pt 1fr auto!important;
    grid-template-areas:"nm pair dl"!important;
    gap:6pt!important;padding:3.5pt 0!important;
    border-bottom:.5pt solid #DDD!important;break-inside:avoid;
  }
  .rp-cmp__nmname{font-size:8.5pt;color:#000;white-space:normal}
  .rp-cmp__nmcat{font-size:7pt;color:#666}
  .rp-cmp__pair{font-size:8.5pt;gap:4pt}
  .rp-cmp__from{color:#666}
  .rp-cmp__arrow{color:#666;font-size:8pt}
  .rp-cmp__to{color:#000!important;font-weight:800}
  .rp-cmp__gap{font-size:7.5pt;color:#666}
  .rp-cmp__dl{gap:5pt}

  /* 班级层 KPI */
  .rp-cmp__kpis{grid-template-columns:repeat(3,1fr)!important;gap:6pt!important;margin-bottom:6pt}
  .rp-cmp__kpi{
    border:.75pt solid #999!important;border-radius:0!important;box-shadow:none!important;
    padding:5pt 6pt!important;break-inside:avoid;
  }
  .rp-cmp__kpi::before{display:none}     /* 左侧色条打印会变灰 → 去掉，靠 delta */
  .rp-cmp__kpilab{font-size:8pt;color:#333}
  .rp-cmp__kpival{font-size:13pt!important;color:#000!important}
  .rp-cmp__kpival small{font-size:8pt;color:#333}
  .rp-cmp__kpifoot{margin-top:4pt}

  /* 班级层：分布条纵向堆叠 */
  .rp-cmp__stack{gap:5pt}
  .rp-cmp__stackrow{
    grid-template-columns:44pt 1fr 40pt!important;
    grid-template-areas:"lab bar dl"!important;
    gap:5pt!important;padding-bottom:4pt;
    break-inside:avoid;
  }
  .rp-cmp__stacklab{font-size:8pt;color:#000}
  .rp-cmp__stacklab small{font-size:7pt;color:#666}
  .rp-cmp__stackrow--now .rp-cmp__stacklab{color:#000}
  .rp-cmp__stackrow--now .rp-cmp__stacklab::after{
    background:#fff!important;color:#000!important;
    border:.5pt solid #000;font-size:6.5pt;padding:0 3pt;vertical-align:0;
  }
  /* 分布条复用 report.css 的灰阶规格（.rp-dist__seg 已在 report.css 里
     做过实线/虚线/点线三重冗余，这里不再重复覆盖，只调高度）*/
  .rp-cmp__stackbar .rp-dist__bar{height:8pt}
  .rp-cmp__stackbar .rp-dist__legend{display:none}

  /* 园所层：发散条形榜 —— 中轴必须实线，否则读不出"0 在哪" */
  .rp-cmp__rankrow{
    grid-template-columns:46pt 1fr 44pt!important;
    gap:6pt!important;padding:4pt 0!important;break-inside:avoid;
  }
  .rp-cmp__ranknm{font-size:8.5pt;color:#000}
  .rp-cmp__ranknm small{font-size:7pt;color:#666}
  .rp-cmp__rankbar{
    height:11pt;background:#fff!important;
    border:.5pt solid #999;border-radius:0;
  }
  .rp-cmp__rankbar::before{
    background:#000!important;width:1pt;left:50%;opacity:1;
    border-radius:0;
  }
  .rp-cmp__rankfill{top:1.5pt;bottom:1.5pt;border-radius:0}
  .rp-cmp__rankfill--up{
    background:#8C8C8C!important;
    border:.75pt solid #000;border-left:0;
  }
  .rp-cmp__rankfill--down{
    background:#CFCFCF!important;
    border:.75pt dashed #000;border-right:0;
  }
  .rp-cmp__rankfill--flat{background:#fff!important;border:.5pt dotted #999;opacity:1}
  .rp-cmp__rankdl b{font-size:8.5pt;color:#000!important}

  /* 全园均分迷你柱 */
  .rp-cmp__spark{height:16pt;margin-top:5pt;gap:2pt}
  .rp-cmp__sparkbar{
    background:#8C8C8C!important;border-radius:0;
    border:.5pt solid #666;
  }
  .rp-cmp__sparkbar--now{background:#000!important}
  .rp-cmp__sparkax{margin-top:2pt}
  .rp-cmp__sparkax span{font-size:6.5pt;color:#666}
  .rp-cmp__sparkax span.is-now{color:#000;font-weight:800}

  /* 结论条 */
  .rp-cmp__verdict{
    background:#fff!important;border:.5pt solid #999;
    border-left:2pt solid #000!important;border-radius:0!important;
    padding:5pt 6pt!important;font-size:8.5pt;color:#000!important;margin-top:6pt;
    break-inside:avoid;
  }
  .rp-cmp__verdict--act{border-left:2pt dashed #000!important;color:#000!important}
  .rp-cmp__verdict b{color:#000!important}
  .rp-cmp__none{
    background:#fff!important;border:.75pt dashed #999!important;
    font-size:8pt;color:#555;padding:4pt 5pt!important;
  }

  /* —— 录入页打印：这是一张"录入工作单"，不是报告 —— */
  .rp-intake__head{
    border:.75pt solid #B9B9B9!important;border-left:2pt solid #000!important;
    border-radius:0!important;box-shadow:none!important;padding:5pt 6pt!important;
  }
  .rp-intake__av{
    background:#fff!important;border:.75pt solid #000;color:#000!important;
    width:22pt;height:22pt;font-size:10pt;border-radius:0;
  }
  .rp-intake__nm{font-size:12pt;color:#000}
  .rp-intake__meta{font-size:8pt;color:#555}
  .rp-intake__gauge{width:26pt!important;height:26pt!important}
  .rp-intake__gauge circle{stroke-width:4}
  .rp-intake__gauge .trk{stroke:#CCC}
  .rp-intake__gauge .val{stroke:#000}
  .rp-intake__gauge span{font-size:9pt;color:#000}
  .rp-intake__gtname{font-size:11pt;color:#000}
  .rp-intake__gtname::before{background:#000;height:12pt}
  .rp-intake__gtname small{color:#666;font-size:8pt}
  .rp-intake__gtcount{font-size:8.5pt;color:#555}
  .rp-intake__gtcount b{color:#000!important}
  .rp-intake__items{border:.75pt solid #999!important;border-radius:0!important;box-shadow:none!important}
  .rp-intake__item{
    grid-template-columns:16pt 1fr!important;
    grid-template-areas:"ord nm" "ord inp"!important;
    padding:4pt 5pt!important;border-bottom:.5pt solid #DDD;
    break-inside:avoid;
  }
  .rp-intake__ord{
    width:14pt;height:14pt;border-radius:0;font-size:8pt;
    border:.5pt solid #999;background:#fff!important;color:#000!important;
  }
  .rp-intake__item--done .rp-intake__ord{background:#fff!important;border:.75pt solid #000}
  .rp-intake__item--now{background:#FAFAFA!important}
  .rp-intake__item--now::before{display:none}
  .rp-intake__nmname{font-size:9.5pt;color:#000}
  .rp-intake__nmhint{font-size:7.5pt;color:#666}
  .rp-intake__inp{margin-top:2pt;gap:5pt}
  /* 输入框打印成"横线填写位"（打印出来就是要手填/签字的）*/
  .rp-intake__num{
    min-height:0!important;height:16pt!important;
    background:#fff!important;border:0!important;
    border-bottom:.75pt solid #666!important;border-radius:0!important;
    font-size:10pt;color:#000!important;text-align:left;
    box-shadow:none!important;
  }
  .rp-intake__num:empty::after{content:''}
  .rp-intake__unit{font-size:7.5pt;color:#555}
  .rp-intake__grade{
    width:auto;min-width:26pt;justify-content:flex-start;
  }
  .rp-intake__grade .rp-badge{
    background:#fff!important;border:.75pt solid #000!important;color:#000!important;
    border-radius:2pt!important;font-size:7.5pt;padding:0 4pt;
  }
  .rp-intake__posture{
    border:.75pt dashed #000!important;border-radius:0!important;
    padding:6pt 7pt!important;break-inside:avoid;margin-bottom:8pt;
  }
  .rp-intake__posturettl{font-size:11pt;color:#000}
  .rp-intake__posturettl::before{background:#000;height:12pt}
  .rp-intake__posturesub{font-size:8pt;color:#333;border-bottom:.5pt solid #999}
  .rp-intake__shots{grid-template-columns:repeat(3,1fr)!important;gap:6pt}
  /* 未拍的槽位打印成空框（教练/家长现场手写标注）*/
  .rp-intake__shot{
    min-height:52pt!important;border:.75pt dashed #999!important;
    background:#fff!important;color:#999;font-size:7.5pt;border-radius:0;
  }
  .rp-intake__shotico{display:none}
  .rp-intake__shot--ok{border-style:solid!important;border-color:#000!important;background:#fff!important}
  .rp-intake__shot--ok img{height:52pt;filter:grayscale(1) contrast(1.05)}
  .rp-intake__concl{gap:5pt;margin-top:7pt;padding-top:7pt;border-top:.5pt solid #999}
  .rp-intake__conclab{font-size:8pt;color:#555}
  .rp-intake__pill{
    min-height:0!important;padding:2pt 5pt!important;
    background:#fff!important;border:.75pt solid #666!important;
    color:#333!important;font-size:7.5pt;border-radius:2pt;
  }
  .rp-intake__pill[aria-pressed="true"]{
    background:#fff!important;border:1pt solid #000!important;
    color:#000!important;font-weight:800;
  }

  /* —— 报告管理列表：转真表格排布 —— */
  .rp-mgr__bar{display:none}
  .rp-mgr__list{display:block}
  .rp-mgr__row{
    display:grid!important;
    grid-template-columns:18pt 1fr .8fr .5fr .9fr 18pt!important;
    grid-template-areas:"av name score score st go"!important;
    gap:0 6pt!important;padding:3.5pt 0!important;
    border:0!important;border-bottom:.5pt solid #DDD!important;
    border-radius:0!important;background:#fff!important;box-shadow:none!important;
    break-inside:avoid;page-break-inside:avoid;
  }
  .rp-mgr__row:nth-child(even){background:#FAFAFA!important}
  .rp-mgr__av{
    width:14pt;height:14pt;border-radius:0;font-size:8pt;
    background:#fff!important;border:.75pt solid #999;color:#000!important;
  }
  .rp-mgr__nm{font-size:9.5pt;color:#000}
  .rp-mgr__gender{background:#fff!important;border:.5pt solid #999;color:#333!important;font-size:7pt}
  .rp-mgr__meta{font-size:8pt;color:#555}
  .rp-mgr__meta b{color:#000!important}
  .rp-mgr__score{text-align:right}
  .rp-mgr__score b{font-size:11pt!important;color:#000!important;display:inline}
  .rp-mgr__score small{font-size:7pt;color:#666;display:inline;margin-left:2pt}
  .rp-mgr__st{
    grid-area:st;justify-self:end;
    padding:0;margin:0;border:0;gap:4pt;
  }
  /* 状态 chip 打印：靠边框样式与形状区分，不靠底色 */
  .rp-mgr__chip{
    background:#fff!important;border:.75pt solid #000!important;
    color:#000!important;font-size:7.5pt;padding:0 4pt;border-radius:2pt;min-height:0;
  }
  .rp-mgr__chip--none{border-style:dashed!important;border-color:#999!important;color:#666!important}
  .rp-mgr__chip--draft{border-style:dotted!important;border-width:1pt!important}
  .rp-mgr__chip--notone{border-style:dashed!important;border-color:#999!important;color:#666!important}
  .rp-mgr__chip--tone{border:.75pt solid #000!important;font-weight:800}
  .rp-mgr__chip--new{border-width:1pt!important;font-weight:800}
  /* .rp-mgr__grp 已按 Q7 移除（会违反两链路字样隔离纪律），无打印规则 */

  /* 打印时强制亮色（暗色主题也不能出深底黑字）*/
  .rp-cmp,.rp-sector,.rp-intake__items,.rp-intake__head,.rp-intake__posture{
    --rpd-fill-up:#fff; --rpd-line-up:#000; --rpd-line-down:#000;
    --rpd-posture-tint:#fff; --rpd-posture-ink:#000; --rpd-posture:#000;
    --rpd-kind:#000; --rpd-org:#000; --rpd-axis:#000; --rpd-axis-ink:#555;
  }
}


/* =============================================================
 * 9. 动效与偏好设置
 * ============================================================= */
@media (prefers-reduced-motion:reduce){
  .rp-cmp__fill,.rp-intake__gauge .val{transition:none!important}
  .rp-sector__act:active,.rp-mgr__row:active{transform:none!important}
}

/* 高对比度偏好：把变化徽标的内阴影换成实线边框（Windows 高对比模式）*/
@media (prefers-contrast:more){
  .rp-cmp__delta{
    box-shadow:none!important;
    border:1.5px solid currentColor;
  }
  .rp-sector{border-width:2px;border-top-width:4px}
  .rp-mgr__chip{border-width:1.5px}
}


/* =============================================================
 * 10. 给前端的落地说明（CSS 注释形式）
 * -------------------------------------------------------------
 * 【类名 → 区块映射】全部新增类（不带前缀的是复用 report.css 的既有类）
 *
 *  §3 双板块入口
 *    .rp-dual / .rp-dual__anchor / .rp-dual__anchorico
 *    .rp-sector / .rp-sector--kind / .rp-sector--org
 *    .rp-sector__hd / __ico / __hdb / __ttl / __sub / __scale
 *    .rp-sector__dots / --one / --many
 *    .rp-sector__items / __itemslab / __chips
 *    .rp-chip / --ext / --muted
 *    .rp-sector__acts / __actsrow / --eq
 *    .rp-sector__act / --primary / __actico / __actb / __actt / __actd
 *    / __actnew / __actgo / __foot
 *
 *  §2 三层对比（外壳 + 原子共用）
 *    .rp-cmp / --personal / --class / --garden / --org / --long
 *    .rp-cmp__hd / __ttl / __n / --warn / __scope / __switch / __none
 *    .rp-cmp__base / --alt          （基准标注 · 强制）
 *    .rp-cmp__thin / --wait         （样本不足降级 · 分母=studentCount）
 *    .rp-cmp__seed / --agg          （「第 1 次」引导卡 · 默认首屏）
 *    / __seedttl / __seedn / __seedd / __seedhint / __seeddate
 *    .rp-cmp__delta / --up / --down / --flat / --none / --bare
 *       / --worse / --better  ←「越低越好」指标的箭头口径消歧（见 §2.2）
 *    .rp-cmp__axis / __axisline / __col / --now / --none
 *    .rp-cmp__colval / __bar / __fill / __pt / --now / --dot-up / --dot-down
 *    / __ptdot / __ptdt / __ptline
 *  个体层
 *    .rp-cmp__hero / __heronum / __heroinfo / __herolab
 *    .rp-cmp__rows / __row / __nm / __nmname / __nmcat / __dl
 *    .rp-cmp__pair / __from / __arrow / __to / --{grade} / __gap
 *  班级层
 *    .rp-cmp__kpis / __kpi / --up / --down / --flat / __kpilab / __kpival
 *    / __kpifoot
 *    .rp-cmp__stack / __stackrow / --now / __stacklab / __stackbar / __stackdl
 *  园所层
 *    .rp-cmp__rank / __rankrow / __ranknm / __rankbar / __rankfill
 *    / --up / --down / --flat / __rankdl
 *    .rp-cmp__spark / __sparkbar / --now / __sparkax / .is-now
 *    .rp-cmp__verdict / --act
 *
 *  §4 机构录入
 *    .rp-intake / __head / __av / __hb / __nm / __meta
 *    / __gauge / __autosave / --idle
 *    .rp-intake__group / __gt / __gtname / __gtcount / __items
 *    .rp-intake__item / --now / --done / --todo / __ord / __nm / __nmname
 *    / __nmhint / __inp / __num / __unit / __grade / __skip
 *    .rp-intake__item--na / __natag / __naundo
 *    .rp-intake__posture / __posturehd / __posturettl / __posturesub
 *    / __shots / __shot / --ok / __shotico
 *    / __concl / __conclab / __pill
 *    .rp-intake__bar / __barinfo / --warn
 *    .rp-intake__cta / --ghost
 *
 *  §5 报告管理
 *    .rp-mgr__bar / __srch / __count / __list / __row / --tone
 *    / --untested / __av / __nm / __gender / __meta / __score / __st / __gost
 *    .rp-mgr__chip / --ready / --none / --draft / --tone / --notone / --new
 *    （.rp-mgr__grp 已按 UX Q7 移除 —— 会破坏两链路字样隔离）
 *
 *  §6 未测空态（跨层级，最高优先级规则）
 *    .rp-na / .rp-na--chip
 *    .rp-dim--na / .rp-cmp__row--na
 *
 *  【JS 需要做的事】
 *  ① ★ 只有 1 次测评时渲染**引导卡**而非空壳：
 *     .rp-cmp__seed（+ __seedttl/__seedn/__seedd/__seedhint/__seeddate）。
 *     ⚠️ 已核实 kg.sqlite：127 名学生每人恰好 1 次测量、无一条 ≥2，
 *        testDate 只有 2026-09-02/09-03 —— **引导卡就是上线后的默认首屏**，
 *        不是边角状态。现有 parent.js:194 / report.js:1198 都是
 *        `if (ms.length < 2) return ''`，等于什么都不画，必须改。
 *     文案（UX 指定，不要改写）：标题「成长记录 · 第 1 次」/
 *     正文「这是孩子的第 1 次体测。再测一次，就能在这里自动看到孩子的进步曲线。」/
 *     次要「对比会自动生成，不需要另外操作」。
 *     禁止画成空白 / 灰掉 / 「暂无数据」—— 那是报错语气。
 *
 *     ⚠️ 文案铁律：**家长可见文案里不得出现「他/她/TA」等人称代词。**
 *     （原规格写的「他的进步曲线」是 UX 的笔误，我照抄了 —— 特此更正。）
 *     理由有三，都不是文字洁癖：
 *       ① .rp-cmp--org 说明这张卡**园所/班级层级也用**，那边的主体
 *          是"这个班/全园"，"他"没有指代对象；
 *       ② 这批孩子男女都有，"他"指向不明，家长会以为在讲另一个孩子；
 *       ③ report.js 的水印/标题会带具体姓名（stu.alias），
 *          但**班级/园所层没有单一主体**，代词在这里逻辑上就不成立。
 *     统一写法：重复「孩子」，或改主语（"再测一次，就能看到进步曲线"）。
 *  ② ★★★ 班级/园所级对比：样本量 + 分母 + 阈值（三条都是硬要求）
 *     （UX 提出；我认为这比任何视觉处理都有效，所以写成硬规则。）
 *
 *     ── 为什么这条比视觉重要 ──
 *     「第 1 次」只在个体层准确：
 *       个体：这个孩子测了 1 次        ✅
 *       班级：这个班测了 1 期          ⚠️ 家长会误读成"我的孩子只测了 1 次"
 *       园所：全园测了 1 期            ❌ 127 个孩子各自都测了，没有"全园第 1 次"
 *     更危险的是触发条件：全园 127 人里**只要有 1 个孩子**测过 2 次，
 *     园所级对比就有数据了 —— 园长看到的不是"全园对比"，
 *     而是**基于极少数人的样本**，却极易被当成"全园整体变化"去决策。
 *
 *     ── ⚠️⚠️ 分母必须是 studentCount（在册），不是 measuredCount（已测）──
 *     （UX 核验时发现的分母漏洞，已采纳。这个错会系统性高估覆盖率。）
 *
 *       覆盖率回答的是"我对**这个班的整体**判断有多可信"，
 *       分母就必须是"这个班有多少人"，而不是"有多少人碰巧测了"。
 *       漏测的孩子本身就是"我们不知道他们进步如何"的一部分，
 *       把他们从分母里剔除 = 假装他们不存在。
 *
 *       【以下是假设反例，不是当前数据】
 *       ⚠️ 已核实 kg.sqlite：当前 6 个班**全部满员**（苗二 13/13、果二 30/30、
 *          果一 27/27、苗一 22/22、果三 26/26、芽班 9/9，未测均为 0）。
 *          下面这个场景**今天并不存在**，写它是��说明机制，不是描述现状。
 *
 *       假设反例（芽班 9 人在册，其中 6 人漏测，而这 3 个已测的恰好都有 2 次记录）：
 *         用已测做分母 → 3/3 = 100% ✅「样本充足，放心下结论」← 错得离谱
 *         用在册做分母 → 3/9 =  33% ⚠️ 加 warn
 *
 *       ── 这是「潜伏的冲突」，不是「现在的矛盾」──
 *       必须说清楚，否则会被误读成"现状已经有问题"：
 *         · 现在：全满员，两条规则**尚未**冲突；
 *         · 一旦有班级漏测 ≥3 人，冲突立刻显形。
 *
 *       显形后会怎样 —— 同一屏里两个结论打架，且**方向相反**：
 *         report.js 的 .rp-tr--warn 规则「未测 ≥3 人 → 标红警示」
 *             vs 覆盖率若用已测做分母 → 「样本充足，放心下结论」
 *         最该被怀疑的班，报告最告诉老师"放心"。**这是反向加权。**
 *
 *       → 正因为现在看不出来，**分母必须现在定对**：
 *         晚改就失去了暴露这个问题的数据 —— 等漏测真的发生时，
 *         系统已经在用错误的分母输出误导性结论了。
 *         这一点也是 A/B/C 跨学期口径决策的**时间压力来源**：
 *         不是"早改早好"，而是"晚改就没有数据能发现它了"。
 *
 *       （report.js:1791 `WARN_UNTESTED = 3` / :1849 标红说明均已核实存在。
 *        ⚠️ 留痕：本节反例最早被写成"用真实库的例子"，实际是构造的场景。
 *        已核实真实库全满员，故标注为假设反例 —— 后人不要误读为观测数据。）
 *
 *     ── 两个量必须分开实现，别合并成一个 ──
 *       cmpRows      = 两次都测过的孩子  → **算均值变化**（只能用它）
 *       studentCount = 全班在册人数      → **算覆盖率、判断能不能下结论**
 *       若把两者混成一个数，会出现"用已测子集算覆盖率"这类错误。
 *
 *     ── 阈值：园所 20% / 班级 30%，班级样本 <5 人一律不渲染 ──
 *       园所 20%：园长要的是"全园趋势"，样本必须够大。
 *       班级 30%：班级人少，最小的班只有 9 人 —— 20% 才 2 个孩子。
 *                 **2 个孩子的均值变化不叫趋势，是噪音**，
 *                 而且会诱导老师过度解读个别孩子的波动。
 *       两者都可用 .rp-cmp__n--warn 标记（园所 20~40% / 班级 30~50%）。
 *
 *     ── ⚠️ 两条班级规则会叠加，实现时必须按顺序判，不能含糊 ──
 *       「样本 ≥5 人」和「覆盖率 ≥30%」在两个条件上同时成立时，
 *       谁先判谁后判会得到不同结果 —— 已按 UX 建议固定为**优先级顺序**：
 *
 *         第1 步：cmpRows.length < 5        → 不渲染（绝对数门槛，硬的）
 *         第2 步：cmpSamplePct < 30%        → 不渲染（相对比例门槛）
 *         第3 步：以上都过 → 渲染对比
 *
 *       两条叠加的真实后果（已实算，**这不是 bug，是刻意的取舍**）：
 *         在册 9 人（芽班）→ 30% 只需 3 人，但 ≥5 人门槛更严 → 实际需 5 人 = 55.6%
 *         在册13 人（苗二）→ 30% 只需 4 人，但 ≥5 人门槛更严 → 实际需 5 人 = 38.5%
 *         在册30 人（果二）→ 30% 需 9 人，≥5 人已过           → 实际需 9 人 = 30.0%
 *       也就是说**小班会比大班更难生成对比**。这是有意的：
 *       小班上两个人的均值不叫趋势，宁可不给。
 *       但**不要因此把 30% 降到 20% 来"让小班能用"** ——
 *       那正是我们想避免的：2 个孩子的均值变化给老师看是噪音。
 *
 *       若将来认为小班也不该被卡，正确的放宽方式是**降低绝对数门槛**
 *       （如 ≥3 人），而不是降低覆盖率 —— 因为覆盖率低才是真正的风险信号。
 *
 *     ── 实现要求 ──
 *     · 判定顺序（照上面三步写，不要合并成一个 if）：
 *         班级：cmpRows.length < 5 → 不渲染
 *               cmpSamplePct < 30% → 不渲染
 *         园所：cmpSamplePct < 20% → 不渲染（无绝对数门槛）
 *     · 通过判定后渲染 .rp-cmp 时，**必须**同时给 .rp-cmp__n 带上
 *       「全班 30 人 · 6 人有 2 次记录（20%）」。
 *       ⚠️ 数字要让用户看出分母是谁，所以**必须写出在册人数**，
 *          不能只给一个百分比。
 *     · 未通过判定 → 不渲染对比，改渲染 .rp-cmp__thin 一行，
 *       **宁可不给，也不能给一个会被当成全班/全园结论的东西。**
 *     · ⚠️ 低覆盖率有**两种完全不同的成因**，必须分开写文案，
 *       否则家长和老师会得出相反结论却看到同一句话：
 *         · 漏测多（未测人数 >0）→「全班 30 人，仅 6 人有 2 次记录
 *           （另 8 人未测）」→ 指向"先把漏测的补上"，不是"下学期才有"
 *         · 无人补测（未测 0 人）→「全班 30 人，仅 6 人有 2 次记录
 *           （其余仅 1 次记录）」→ 才是"下学期才会有对比"
 *     · 机构侧 / 集体层的 seed 卡用 .rp-cmp__seed--agg，
 *       措辞不用「第 1 次」，改「尚无跨期数据」。
 *  ③ ★ 基准必须标注：.rp-cmp__base 写明当前跟谁比，文案「对比：上次（2026-03-05）」。
 *     UX 裁定这是硬要求，因为已核实 report.js 现状自相矛盾：
 *       report.js:1209  单项箭头用 ms[len-2] → 对比「上次」
 *       report.js:1223  自动简析用 ms[0]    → 对比「首次」
 *     同一区块两个基准混在一屏，3 次记录时家长会看到箭头 +2、简析 +8。
 *     → 实现时统一用同一个基准渲染全部内容，不要两处各算一次。
 *  ④ ★ 「本次未测」必须独立表达，**任何情况下都不能渲染成数字 0**。
 *     用 .rp-na（破折号）或 .rp-na--chip（虚线 chip），
 *     行上再加 .rp-cmp__row--na / .rp-dim--na。
 *     已核实：引擎对缺失项产出 score:null → report.js:1191 渲染「本次未测」。
 *     delta 侧同样需要未测态 → 用 .rp-cmp__delta--none（不是 ±0）。
 *     ⚠️ 家长可见文案（.rp-cmp__verdict 的文案由 JS 拼）同样禁止「他/她」。
 *  ④ .rp-cmp__switch 的按钮用 aria-pressed 标记当前选择对；
 *     **必须进 URL**（UX Q3 裁定）：参数 `t`=测评期次、`cmp`=对比基准，
 *     用 replace 模式 go({t:..., cmp:...}, true) —— 否则每次切换塞一条历史，
 *     浏览器返回要按十几次。
 *     理由不只是体验：打印件是要给家长签字的，对比视图不在 URL →
 *     老师刷新一下再打印，纸面和屏幕不一致，是真 bug。
 *  ⑤ 默认基准 `cmp=prev`（对比上次，可行动）；
 *     个体报告额外保留 `cmp=base`（对比首次，可汇报），用
 *     .rp-cmp__base--alt 压低权重但保持可点。
 *     三层统一默认「上次」形成统一心智，不做"个体=首次/班级=上次"的两套口径。
 *     ⚠️ 若只有 1 次测评（只有基准 = 首次），**不要渲染基准切换器**——
 *        没有"上次"可选，给一个只有一项的分段控件是纯噪音。
 *        直接渲染 .rp-cmp__seed 即可。
 *  ⑥ .rp-cmp__bar 的柱高由 JS 算：height = score*0.62px（上限 74px，
 *     .rp-cmp--personal 是 86px → 系数 0.74）；score 为 null 时给 4px
 *     并在列上加 .rp-cmp__col--none。
 *  ⑦ .rp-cmp__rankbar 的 .rp-cmp__fill 的 left/width 由 JS 算：
 *     maxAbs = max(|delta|) 兜底 1；up → left:50%; width:(d/maxAbs*50)%；
 *     down → right:50%; width:(|d|/maxAbs*50)%。flat → 居中 3px 灰条。
 *     ⚠️ 这要求 API 给每班下发 delta+direction，不只是 avgComposite。
 *  ⑧ .rp-intake__gauge 的 SVG circle 由 JS 生成，r=26、
 *     circumference≈163.4，stroke-dasharray=163.4，
 *     stroke-dashoffset = 163.4*(1-完成率)。
 *  ⑨ 录入项状态由 JS 维护（UX Q6 裁定）：
 *     第一个未完成项加 .rp-intake__item--now；已录加 --done；
 *     点「本次不测」后该项加 --na 并在行内显示 .rp-intake__natag 留痕，
 *     同时提供 .rp-intake__naundo 让教练撤销。
 *     ⚠️「还没录」与「已标记不测」在界面上绝不能长得一样 ——
 *        二者在报告端后果完全不同（前者是草稿，后者会写进报告）。
 *     按钮文案是「本次不测」不是「跳过」（已核实 server.js:47 空值
 *     直接 continue，跳过即等于记为未测，原名会误导教练以为会再提醒）。
 *  ⑩ 机构链路的任何视图都**不得**出现"班级/园所/批量/待加强率"字样；
 *     园所链路的任何视图都不得出现"体态/体姿/学员/教练"字样。
 *     两个板块的数据不打通，视觉上也不做继承暗示。
 *     两侧结构**刻意不对称**（UX Q1）：园所侧装身份（老师/园长并列），
 *     机构侧装动作（学员列表 + 主 CTA，不做「我是教练」中间层）。
 *
 *  【禁止事项】
 *  ✗ 不要把「本次未测」渲染成 0、0 分、或与「实测 0 分」同形的任何表达
 *  ✗ ★ 家长可见文案里不要出现「他 / 她 / TA」等人称代词。
 *    主体写「孩子」，或改主语。班级/园所层没有单一主体，代词逻辑上不成立。
 *  ✗ ★ 班级/园所渲染 .rp-cmp 时不要省略 .rp-cmp__n 样本量。
 *    全园 127 人里只要有 1 人测过 2 次就"有数据"了 ——
 *    不标样本量的对比会被当成全园整体结论，这是决策级误导。
 *    ⚠️ 分母是 studentCount（在册），**不是** measuredCount（已测）。
 *    用已测做分母会系统性高估覆盖率，且漏测班高估最严重。
 *  ✗ ★ 不要把 cmpRows（算均值的可比子集）与 studentCount（算覆盖率的分母）
 *    混用同一个数 —— 它们是两个量。
 *  ✗ 班级级判定顺序：先 cmpRows.length < 5，再 cmpSamplePct < 30%。
 *    两条会叠加（芽班 9 人实际需 5 人 = 55.6%），必须按顺序判——
 *    写成一个 if 会让"谁先谁后"变成实现者的自由裁量。
 *  ✗ 不要为了让小班能用而把 30% 降到 20% —— 那等于把 2 个孩子的
 *    均值变化当趋势给老师。要放宽就放宽绝对数门槛（≥3 人），
 *    因为覆盖率低才是真正的风险信号。
 *  ✗ 低覆盖率的两种成因不要共用一句话：
 *    漏测多 → 橙色 .rp-cmp__thin（先补测）；
 *    无人补测 → 灰色 .rp-cmp__thin--wait（只能等下学期）。
 *  ✗ 集体层（班级/园所）不要用「第 1 次」这个措辞 —— 用 .rp-cmp__seed--agg。
 *    「第 1 次」只在个体层成立。
 *  ✗ 不要只画箭头不算箭头形状之外的第二重编码
 *  ✗ 不要给 .rp-cmp__delta 写死前景色（必须走 --rpd-line-up / --rpd-line-down）
 *  ✗ 不要把 .rp-cmp__delta--up 的绿色用在非变化语义的地方
 *     （.rp-badge--excellent / .rp-chip--ext 之外的绿都是误用）
 *  ✗ ★ 渲染 delta 时必须读 `higherIsBetter`，**不能只看 direction 就上色**。
 *     已核实 server.js:330-331：待加强率/待加强人数是越低越好，
 *     direction=up 意味着"待加强率涨了"，必须画**红**。
 *     直接把 up 画成绿色 = 把班级最该被看见的坏消息报成了好消息。
 *     ✅ 已对齐：report.js:501`cmpSemantic()` 把 direction 归一化成语义
 *     good/bad 再映射到 --up/--down，所以调用方传进来的类名已是语义化的。
 *     CSS 侧 --up 恒绿、--down 恒红，不再提供反转后缀。
 *  ✗ 不要在两个板块卡上用不同的圆角 / 阴影 / 图标尺寸 —— 那会让它像两个产品
 *  ✗ 不要把 .rp-chip--ext 的橙色用于园所侧（体态只属机构链路）
 *  ✗ 橙色在机构侧恒定代表"新建/开始一次录入"。录入页吸底条的
 *     「生成报告」已改用 .rp-intake__cta（主青实心），
 *     不要把它改回橙色 —— 同一屏两块橙色会让用户分不清主行动。
 *  ✗ 不要新增 .rp-mgr__grp 或任何"机构侧分组"概念（UX Q7 裁定，
 *     会破坏两链路字样隔离；真实需求出现时另开一轮）
 *
 *  【⚠️ 交付纪律 · CSS 令牌必须双向审计（team-lead 裁定）】
 *  ---------------------------------------------------------------
 *  **改完 CSS 必跑：python check_css_tokens.py**（项目根目录，非零退出码可挂 CI）
 *
 *  为什么这是硬纪律 —— `var()` 拼错后的失败模式极其恶劣：
 *    · 不报错
 *    · 花括号配平检查也通过
 *    · 截图中只是「颜色淡了一点」
 *    → 静态 review 与肉眼都抓不到。
 *
 *  本项目真实中过 3 次，全是「--rpd-」少写一个 d：
 *    --rp-posture-ink（5 处）/ --rp-line-flat（1 处）/ --rp-axis-ink（2 处）
 *  它们看起来像 report.css 的既有令牌，实际任何文件都没定义。
 *  注意：**其中两处直到工程侧在浏览器里发现串色才被报出来**——
 *  说明只审自己写的文件也不够，必须做跨文件的「引用集 vs 定义集」双向diff。
 *
 *  脚本三项检查（均已做注入式反向验证，确认真能抓到）：
 *    1. 悬空引用（带 fallback 的 var 不算）
 *    2. 注释块语法（提前闭合 / 不闭合会让代码泄漏进样式表）
 *    3. 入口页可达性（静态 <link> 疑点 + 扫 JS 里的运行时注入线索）
 *  期望输出：`PASS：三项检查全过`
 * ============================================================= */
 *  【✅ 跨学期身份口径 —— 已按 A 方案落地（原「待拍板」注记已释放）】
 *  ------------------------------------------------------------------
 *  口径：**一个班跨学期复用同一 classId**，期次不靠日期硬分期，
 *  而是按**复测证据**识别。三处落地：
 *
 *  ① server.js:1208 建班时term 改为「选填」，不再强制带学期后缀。
 *  ② fe-admin 新建班级文案已明示：「测下一期时，请选择同一个班继续录入，
 *     不要新建班级 —— 只有同一个班里的同一名学员，才能看出跨期的进步与退步。」
 *     这是数据正确性的**前端第一道防线**：靠文案阻止运营人员制造无法对比的班。
 *  ③ server.js:307-317 期次识别规则：**同一 testDate 的日期桶，只有与其他
 *     日期桶存在「同一学员被测两次」的证据时才独立成期**，否则并入相邻期次。
 *     期次 = 复测关系的连通分量。
 *
 *  ⚠️ ③ 这条规则来自真实数据，不是过度设计（server.js:299-306 已记录）：
 *     库里 127 名学员/127 条测量，每人有且仅有 1 条；testDate 只有
 *     2026-09-02(120 人) 与 2026-09-03(7 人)，而**这 7 人与同班 09-02 的
 *     学生集合交集为 0** → 09-03 是同轮错峰补测，不是复测。
 *     若按 testDate 硬分期，这 3 个班会被判成两期，然后拿两批
 *     **完全不同的孩子**算出「平均分涨了 2 分」—— 一个看起来完全正常、
 *     实则彻底无意义的假结论。
 *
 *  → 对本文件的影响：三层都是"≥2 期才渲染"的条件渲染，
 *    全库当前只有 1 期，因此上线首屏走 .rp-cmp__seed 引导卡
 *    （不是空壳、不是报错态）。有了第二期后自动长出对比区。
 *  → 期次数 < 2 时后端**不返回 history 字段**（而非返回空对象），
 *    前端 `if (rep.history)` 即可隐藏整个对比区块。


/* =============================================================
 * 11. 交付前自检（脚本已随仓库交付，见项目根目录）
 * -------------------------------------------------------------
 * var() 引用了不存在的令牌时**不会报错**，只会让那条声明静默失效、
 * 回退到继承色 → 串色。这种 bug 肉眼很难发现，必须靠脚本兜。
 * 本文件历史上就中过 3 次（--rp-posture-ink / --rp-line-flat /
 * --rp-axis-ink，均是「--rpd-」少写一个 d；均由 fe-admin 在后台侧
 * 发现串色后报出）。
 *
 *   脚本：check_css_tokens.py（项目根目录，与本文件同仓）
 *   用法：python check_css_tokens.py
 *   期望输出：PASS：三项检查全过
 *
 * 为什么不把脚本源码内嵌在CSS 注释里 ——
 *   ⚠️ 本节第一个版本是内嵌的，结果脚本里的正则字面量
 *      （用来剥注释的那个「斜杠星 … 星斜杠」序列）**提前闭合了包裹它的注释**，
 *      导致 Python 代码泄漏进 CSS 主体。
 *      而这个问题是脚本自己的第2 项检查报出来的（狗哨咬到主人）。
 *   → 所以改为**引用仓库里的脚本文件**，不再内嵌源码。
 *     代价是要多一个文件，收益是彻底消除注释转义这个雷。
 * ============================================================= */

/* =============================================================
 * 【§11 自检脚本覆盖的三项检查】
 *1. 悬空引用：var(--x) 引用了全站未定义的 --x（带 fallback 的不算）
 *  2. 注释块语法：提前闭合 / 最终不闭合（会污染样式表）
 *  3. 入口页可达性：report-dual.css 产出的类，在它被用到的页面里能否加载到
 *     ⚠️ 第3 项刻意不做"纯静态 grep"。fe-admin曾用静态 grep 判断
 *        "report.html 没 link report-dual.css → 三层对比完全无样式"，
 *        准备当高优先级问题上报—— **结论是误报**：report-api.js 的
 *        ensureCmpStyle() 在运行时注入了 <link>，浏览器实测 4 个样式表全在。
 *        所以脚本改为「静态疑点 + 扫描 JS 里的运行时注入证据」的组合，
 *        只报"待人工确认"而不报假高危。
 * ============================================================= */