/* ==========================================================================
   现代 OJ 设计系统
   1) 设计变量（深浅两套）2) 基础排版 3) 布局骨架 4) 组件 5) 题库 6) 题页工作台
   7) 编辑器 8) 判题控制台 9) 响应式
   ========================================================================== */

/* ---------- 1) 设计变量 ---------- */
:root {
  --bg: #f6f7f9;
  --surface: #ffffff;
  --surface-2: #fafafb;
  --surface-3: #f1f3f5;
  --border: #e6e8eb;
  --border-strong: #d3d7dd;
  /* 列表行的发丝分隔线（题库/错题本/收藏夹 .prow）。亮色沿用 --border；
     暗色的 --border(#333b46) 压在深底上太亮，每行像被亮线包边的独立卡条（2026-09-29 实测
     「分离卡片条」观感主因），故暗色把行线往 surface 方向收回 45%。 */
  --row-line: var(--border);
  --text: #16181d;
  --text-2: #5b6270;
  /* --text-3 是「提示/次要文字」用色，白卡片上实测 3.17:1（低于 WCAG AA 4.5:1）。
     #6b7280 在该色与各底色（白卡片 4.83 / 页面底 4.51 / surface-2 4.63）都过关，
     视觉上仍是同一档灰；--text-2 更深的层级关系不变。 */
  --text-3: #6b7280;
  --brand: #2f6df6;
  --brand-hover: #245bdb;
  --brand-soft: #eaf1ff;
  --ac: #12a150;
  --ac-soft: #e8f8ef;
  --info: #0e8aa8;      --info-soft: #e2f4f8;
  --warn: #d98200;
  --warn-soft: #fff5e6;
  --kt: #7a58f2;        --kt-soft: #f1ecff;   /* 知识点标签紫（NOI 大纲树，2026-09-30） */
  --danger: #e5484d;
  --danger-soft: #fdecec;
  --mono: "Sarasa Mono SC", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* 正文不放等宽（2026-10-15 用户「读起来生硬」）：等宽黑体只适合代码，
     长文阅读回人文黑体栈（苹方/雅黑/思源），轻松清晰零加载成本。 */
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB",
          "Microsoft YaHei", "Noto Sans SC", sans-serif;
  /* 阅读内容区字体（2026-10-16 用户钦定「字体还是保留默认字体吧」）：文楷实验回退，
     题面/文章/解析与全站 UI 同用默认黑体栈；代码仍用 --mono 等宽。
     （fonts.css 里的 LXGW @font-face 保留但无人引用=零下载，随时可回切。） */
  --font-read: var(--sans);
  --r-sm: 6px; --r: 10px; --r-lg: 14px;
  /* 字号（设置里可调，JS 改写这两个变量） */
  --code-fs: 13px; --fs-statement: 15px;
  --sh-1: 0 1px 2px rgba(16, 24, 40, .04), 0 1px 3px rgba(16, 24, 40, .06);
  --sh-2: 0 8px 24px rgba(16, 24, 40, .10);
  --nav-h: 56px;
  /* 语法高亮 */
  --syn-kw: #c026d3; --syn-str: #0f7b3f; --syn-num: #b45309; --syn-fn: #2563eb;
  --syn-type: #0891b2; --syn-com: #98a1ad;
}
/* 暗色：跟随系统，除非用户显式选了亮色 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0d0f12; --surface: #15181d; --surface-2: #1a1e24; --surface-3: #21262e;
    --border: #333b46; --border-strong: #454f5e;
    --row-line: color-mix(in srgb, var(--border) 45%, var(--surface));
    --text: #e9ecf1; --text-2: #9aa3b2; --text-3: #858d9b;
    --brand: #5b8cff; --brand-hover: #7ba3ff; --brand-soft: #17233c;
    --ac: #35c07a; --ac-soft: #11281d;
    --info: #56d4dd; --info-soft: rgba(86, 212, 221, .12);
    --warn: #f0b429; --warn-soft: #2b2210;
  --kt: #b9a3ff; --kt-soft: rgba(150, 120, 255, .14);
    --kt: #b9a3ff; --kt-soft: rgba(150, 120, 255, .14);
    --danger: #f2555a; --danger-soft: #2c1a1b;
    --sh-1: 0 1px 2px rgba(0, 0, 0, .4); --sh-2: 0 10px 30px rgba(0, 0, 0, .45);
    --syn-kw: #e879f9; --syn-str: #7ee787; --syn-num: #f0b429; --syn-fn: #79c0ff;
    --syn-type: #56d4dd; --syn-com: #6f7784;
  }
}
/* 用户手动选暗色（覆盖系统亮色） */
:root[data-theme="dark"] {
  --bg: #0d0f12; --surface: #15181d; --surface-2: #1a1e24; --surface-3: #21262e;
  /* 深色描边原 #262b33：压在行底上只有 1.22–1.25:1，表格的横线细到几乎看不见，
     在「重置密码」那种带边框输入框的列里，看上去就像横线断成两截（用户报障）。
     改 #333b46（1.53–1.57:1）后线是连续的、清楚的，又不抢内容。 */
  --border: #333b46; --border-strong: #454f5e;
  --row-line: color-mix(in srgb, var(--border) 45%, var(--surface));
  /* 深色下 --text-3 原为 #6f7784：在 surface-3 上只有 3.36:1。改 #858d9b 后
     最差表面 4.55:1、常规卡片 5.32:1，仍明显比 --text-2(#9aa3b2) 弱，层级不变。 */
  --text: #e9ecf1; --text-2: #9aa3b2; --text-3: #858d9b;
  --brand: #5b8cff; --brand-hover: #7ba3ff; --brand-soft: #17233c;
  --ac: #35c07a; --ac-soft: #11281d;
  --info: #56d4dd; --info-soft: rgba(86, 212, 221, .12);
  --warn: #f0b429; --warn-soft: #2b2210;
  --kt: #b9a3ff; --kt-soft: rgba(150, 120, 255, .14);
  --danger: #f2555a; --danger-soft: #2c1a1b;
  --sh-1: 0 1px 2px rgba(0, 0, 0, .4); --sh-2: 0 10px 30px rgba(0, 0, 0, .45);
  --syn-kw: #e879f9; --syn-str: #7ee787; --syn-num: #f0b429; --syn-fn: #79c0ff;
  --syn-type: #56d4dd; --syn-com: #6f7784;
}
.theme-btn { background: none; border: 0; cursor: pointer; color: var(--text-2); padding: 6px; border-radius: var(--r-sm); display: grid; place-items: center; }

/* ---------- 46) 导航栏隐藏（2026-09-29 用户要求「腾出可视区域」） ----------
   顶栏右侧一枚收起钮；隐藏后右上角浮一枚恢复钮。--nav-h 归零让所有应用式页面
   （题库 .pl-app / 作业比赛 .ct-app / 私信 .pm-app）自动吃满腾出的 56px。 */
html.nav-hidden { --nav-h: 0px; }
html.nav-hidden .topbar { display: none; }
/* 居中把手（2026-09-29 用户钦定「细小横条放中间，点击上折/下展」）：
   展开态贴在顶栏正下方中间（top: var(--nav-h)），收起态 --nav-h 归零自动跳到屏幕顶缘中央；
   外钮 64×16 透明扩热区，内条 64×6 胶囊，hover 亮品牌色。 */
.nav-handle { position: fixed; top: var(--nav-h); left: 50%; transform: translateX(-50%); z-index: 90;
  width: 64px; height: 16px; padding: 5px 0; border: 0; background: none; cursor: pointer;
  display: grid; place-items: center; }
.nav-handle i { display: block; width: 64px; height: 6px; border-radius: 99px;
  background: var(--surface-3); border: 1px solid var(--border-strong); transition: background .13s, border-color .13s; }
.nav-handle:hover i { background: var(--brand-soft); border-color: var(--brand); }
.theme-btn:hover { background: var(--surface-3); color: var(--text); }

/* ---------- 2) 基础排版 ---------- */
* { box-sizing: border-box; }
/* 我们自己给 .console/.run-panel/.pane-body 写了 display，会盖掉 hidden 属性自带的 display:none，
   于是 JS 用 el.hidden 开关根本关不掉（踩过：自测面板一直挂在页面上、按钮点了像没反应） */
[hidden] { display: none !important; }

/* 滚动条：告诉浏览器用哪套配色（缺 color-scheme 时暗色主题下浏览器会画亮色滚动条 + 上下箭头，
   就是"下拉条跟主题不配"的根因），再补一层细滚动条样式 */
html { color-scheme: light; }
html[data-theme="dark"] { color-scheme: dark; }
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) { color-scheme: dark; }
}
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--border-strong); background-clip: content-box;
  border: 2px solid transparent; border-radius: 99px;
}
::-webkit-scrollbar-thumb:hover { background: var(--text-3); background-clip: content-box; }
::-webkit-scrollbar-corner { background: transparent; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 14px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
}
a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: none; color: var(--brand-hover); }
h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -.01em; }
h1 { font-size: 22px; }
h2 { font-size: 16px; }
h3 { font-size: 14px; }
p { margin: 0 0 10px; }
::selection { background: var(--brand-soft); }
:focus-visible { outline: 2px solid color-mix(in srgb, var(--brand) 45%, transparent); outline-offset: 2px; }
.muted { color: var(--text-3); }
.small { font-size: 12px; }
/* 图标尺寸护栏：SVG 不给宽高会按默认尺寸撑开（踩过） */
svg { flex: none; }
.brand, .nav-link, .user-btn { white-space: nowrap; }
.mono { font-family: var(--mono); }
.row { display: flex; align-items: center; gap: 8px; }
.spacer { flex: 1; }

/* ---------- 3) 布局骨架 ---------- */
.shell { min-height: 100vh; display: flex; flex-direction: column; }
.topbar {
  position: sticky; top: 0; z-index: 40; height: var(--nav-h);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--border);
}
/* 全宽流式：不用 max-width 居中（带鱼屏上会出现"中间一条"，左不贴左右不贴右） */
.topbar-inner { width: 100%; height: 100%; padding: 0 20px; display: flex; align-items: center; gap: 22px; }
.brand { display: flex; align-items: center; gap: 9px; color: var(--text); font-weight: 650; font-size: 15px; }
.brand-mark {
  width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center;
  background: linear-gradient(135deg, var(--brand), color-mix(in srgb, var(--brand) 60%, #7c3aed));
  color: #fff; font-size: 14px; font-weight: 700;
}
.nav { display: flex; gap: 2px; }
.nav-link { color: var(--text-2); padding: 7px 12px; border-radius: var(--r-sm); font-size: 14px; }
.nav-link:hover { background: var(--surface-3); color: var(--text); }
.nav-link.active { color: var(--text); font-weight: 600; background: var(--surface-3); }
.nav-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
/* 顶栏时钟（hh:mm:ss 24 小时制）：等宽数字防走秒跳动，色阶同导航词 */
.topbar-clock {
  font-family: var(--mono);
  font-size: 13.5px; font-variant-numeric: tabular-nums; letter-spacing: .5px;
  color: var(--text-2); white-space: nowrap; user-select: none; padding: 0 2px;
}
/* ≤760px 顶栏导航已收进底部 tabbar，右侧只剩图标排不下时钟（手机状态栏本就有时间） */
@media (max-width: 760px) { .topbar-clock { display: none; } }

/* 用户菜单 */
.user { position: relative; }
.user-btn { display: flex; align-items: center; gap: 8px; background: none; border: 0; cursor: pointer; padding: 4px 6px; border-radius: var(--r-sm); color: var(--text); }
.user-btn:hover { background: var(--surface-3); }
.avatar { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 600; color: #fff; background: linear-gradient(135deg, #6366f1, #0ea5e9); }
.user-menu {
  position: absolute; right: 0; top: calc(100% + 6px); min-width: 180px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r); box-shadow: var(--sh-2); padding: 6px; display: none;
}
.user-menu.open { display: block; }
.user-menu a, .user-menu button { display: flex; width: 100%; align-items: center; gap: 8px; padding: 8px 10px; border: 0; background: none; color: var(--text-2); font: inherit; text-align: left; border-radius: var(--r-sm); cursor: pointer; }
.user-menu a:hover, .user-menu button:hover { background: var(--surface-3); color: var(--text); }
.user-menu .sep { height: 1px; background: var(--border); margin: 5px 4px; }

.page { flex: 1; width: 100%; padding: 22px 20px 64px; }
.footer { border-top: 1px solid var(--border); color: var(--text-3); font-size: 12px; }
.footer-inner { width: 100%; padding: 16px 20px; display: flex; gap: 8px; flex-wrap: wrap; }
/* 工作台页：整屏高度、页面本身不滚动（题面与编辑器各自内部滚） */
.shell-full { height: 100vh; overflow: hidden; }

/* 页面标题区 */
.page-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 16px; flex-wrap: wrap; }
.page-title { display: flex; align-items: baseline; gap: 10px; }
.page-title .count { color: var(--text-3); font-size: 13px; font-weight: 400; }

/* 统计条 */
.stats { display: flex; gap: 10px; flex-wrap: wrap; }
.stat {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  padding: 8px 14px; min-width: 108px; box-shadow: var(--sh-1);
}
.stat .k { color: var(--text-3); font-size: 12px; }
.stat .v { font-size: 18px; font-weight: 650; letter-spacing: -.02em; }
.stat .v small { font-size: 12px; font-weight: 400; color: var(--text-3); }

/* 两栏（左分类栏 + 内容） */
.with-rail { display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 20px; align-items: start; }
@media (max-width: 900px) { .with-rail { grid-template-columns: 1fr; } }
.rail { position: sticky; top: calc(var(--nav-h) + 14px); display: flex; flex-direction: column; gap: 14px; }
.rail-group { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); padding: 12px 12px 10px; box-shadow: var(--sh-1); }
.rail-title { font-size: 12px; font-weight: 600; color: var(--text-3); text-transform: uppercase; letter-spacing: .04em; margin-bottom: 8px; }
.rail-list { display: flex; flex-direction: column; gap: 1px; }
.rail-item { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 5px 8px; border-radius: var(--r-sm); color: var(--text-2); font-size: 13px; }
.rail-item:hover { background: var(--surface-3); color: var(--text); }
.rail-item.on { background: var(--brand-soft); color: var(--brand); font-weight: 500; }
.rail-item .n { color: var(--text-3); font-size: 12px; font-variant-numeric: tabular-nums; }
.rail-item.on .n { color: var(--brand); }
.rail-sub { padding-left: 10px; }

/* ---------- 4) 组件 ---------- */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); box-shadow: var(--sh-1); }
.card-pad { padding: 16px 18px; }
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 7px 13px; font: inherit; font-size: 13px;
  color: var(--text); background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); cursor: pointer; transition: background .15s, border-color .15s, transform .06s;
}
/* 按钮被 min-width/width 拉宽时（如 .run-head 的 96px 运行钮、手机端拉满行宽），图标+文字要居中而不是挤左
   （2026-10-03 用户「按钮里面的内容要居中，现在里面靠左很怪」）。 */
.btn:hover { background: var(--surface-3); }
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 550; }
.btn-primary:hover { background: var(--brand-hover); border-color: var(--brand-hover); color: #fff; }
/* <a class="btn btn-primary"> 会命中全局 a:hover 的蓝字规则（蓝底蓝字=按钮"消失"），此处显式压回白字 */
a.btn-primary, a.btn-primary:hover { color: #fff; }
.btn-ghost { border-color: transparent; background: transparent; color: var(--text-2); }
.btn-ghost:hover { background: var(--surface-3); color: var(--text); }
.btn-sm { padding: 5px 10px; font-size: 12px; }
/* 只有一枚图标的方钮（顶栏的「全屏编辑」）：宽度收成正方形，和旁边带字的按钮一样高 */
.btn-icon { padding: 5px; width: 30px; justify-content: center; }
.btn-icon svg { width: 16px; height: 16px; }
/* 全屏态换图标：展开 ↔ 收起（两枚都渲染在按钮里，靠 body.fs-on 切） */
#btn-fs .ic-shrink { display: none; }
body.fs-on #btn-fs .ic-expand { display: none; }
body.fs-on #btn-fs .ic-shrink { display: block; }
.btn:disabled { opacity: .5; cursor: default; }
/* 草稿状态点（题目工作台 + 笔记编辑器共用）：
   「草稿已保存」在右栏这种天然窄容器里会一字一行竖排（用户圈图两次），圆点全端统一：
   绿=已保存 / 蓝=已恢复；悬停展开完整文字。 */
#draft-tip, #note-draft-tip { font-size: 0; line-height: 1; }
#draft-tip:not(:empty)::before, #note-draft-tip:not(:empty)::before {
  content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--ac); vertical-align: middle; transition: transform .12s;
}
#draft-tip[data-kind=info]:not(:empty)::before, #note-draft-tip[data-kind=info]:not(:empty)::before { background: var(--brand); }
#draft-tip:hover, #note-draft-tip:hover { font-size: 12px; }
#draft-tip:hover::before, #note-draft-tip:hover::before { margin-right: 5px; }
/* 判题方式开关：做成「模式徽章」而不是普通按钮——
   关=灰边框中性（标准输入输出是默认态，不该抢眼）；开=品牌色填充（文件判题必须一眼看出来，
   学生此时必须写 freopen，忘写就全 WA）。开着时文件名用等宽字，复制文件名时看得清。 */
/* 判题方式滑块（.fio，2026-09-25 改版：原来是「标准输入输出 ⇄ x.in / .out」一枚 toggle 按钮）。
   外壳一枚胶囊、里面「标准｜文件」两段，选中的那段浮起来；右边两枚文件名按钮与滑块**同高**
   （24px，对齐旁边的 .btn-sm），双击复制名字（走全局 [data-copynum]）。
   作业/比赛里老师定过判题方式时滑块带 data-editable="0"：两段变灰、点不动，但还看得见。 */
.fio { display: inline-flex; align-items: center; gap: 6px; }
.fio-seg { display: inline-flex; align-items: center; gap: 2px; height: 31px; padding: 0 3px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border); }

/* 文件读写提示条（2026-10-01）：文件判题的题，把输入/输出文件名亮在题面最上方。
   2026-10-02 按用户反馈改版：去掉 freopen 说教与品牌蓝底（「好丑」），收敛为安静的信息条——
   文件名用等宽 chip 呈现，一眼可复制。★ 此前一次编辑把这三条规则嵌进了 .fio-seg 未闭合的
   大括号里，整块被 CSS 解析器丢弃（提示条裸文本的根因）——已在顶层重新落位。 */
.fio-names { margin: 0 0 14px; padding: 8px 12px; background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-sm); font-size: 13.5px; color: var(--text-2); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fio-names .fk { color: var(--text-3); }
.fio-names code { font-family: var(--mono); font-size: 12.5px; background: var(--surface-3); border: 1px solid var(--border);
  border-radius: 5px; padding: 1px 8px; color: var(--text); }
.fio-opt { height: 25px; padding: 0 12px; font: inherit; font-size: 12px; line-height: 1;
  white-space: nowrap;   /* 手机窄栏里「标准/文件」被压到竖排折行（2026-10-07 问题记录 #16） */
  color: var(--text-3); background: none; border: 0; border-radius: 999px; cursor: pointer;
  transition: background .15s, color .15s; }
.fio-opt:hover:not(.on) { color: var(--text); }
.fio-opt.on { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
/* 锁定态（作业/比赛里老师定的）：两段都是死的 —— 悬浮**一点变化都不给**（不然看着像能点），
   光标也保持默认；这不是「disabled 变淡」，是「本来就不响应的硬按钮」。 */
.fio-seg[data-editable="0"] .fio-opt,
.fio-seg[data-editable="0"] .fio-opt:hover,
.fio-seg[data-editable="0"] .fio-opt:active { color: var(--text-3); cursor: default; }
.fio-seg[data-editable="0"] .fio-opt.on { background: var(--surface-3); color: var(--text-3); }
.fio-files { display: inline-flex; align-items: center; gap: 6px; }
/* 文件名按钮（.in/.out）：**全站统一灰、无悬浮、无选中高亮**，只认双击复制 ——
   桌面软件那种「刚性」观感（2026-09-25 用户：悬浮不要变色、不要能选中的文本按钮）。 */
.fio-file { display: inline-flex; align-items: center; height: 31px; padding: 0 12px;
  font-family: var(--mono); font-size: 12px; line-height: 1;
  color: var(--text-3); background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 999px; cursor: default; user-select: none; }
/* 顶栏 <> 在编辑器页 = 返回钮：图标转 180°（右尖括号变左尖括号），微妙但能看出来作用变了 */
.theme-btn.is-back svg { transform: rotate(180deg); }
.theme-btn.is-back { color: var(--brand); }
.btn svg { width: 15px; height: 15px; }

.input, select.input {
  padding: 8px 11px; font: inherit; font-size: 13px; color: var(--text); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm); width: 100%;
}
.input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent); }
.search-wrap { position: relative; flex: 1; max-width: 420px; }
/* 放大镜是**真的提交按钮**：Chromium 在「表单里没有 submit 按钮」时不做隐式提交，
   而筛选态下表单里带着 hidden 的 kind/tag —— 结果就是「筛选中按回车搜不动」（2026-09-23 实测）。 */
.search-wrap .search-go { position: absolute; left: 6px; top: 50%; transform: translateY(-50%);
  width: 26px; height: 26px; display: flex; align-items: center; justify-content: center;
  padding: 0; border: 0; border-radius: 6px; background: none; color: var(--text-3); cursor: pointer; }
.search-wrap .search-go:hover { color: var(--brand); background: var(--brand-soft); }
.search-wrap .search-go svg { width: 15px; height: 15px; }
.search-wrap .input { padding-left: 34px; }

.toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.seg { display: inline-flex; background: var(--surface-3); border-radius: var(--r-sm); padding: 2px; gap: 2px; }
.seg a, .seg button { padding: 5px 11px; font-size: 13px; color: var(--text-2); border-radius: 4px; border: 0; background: none; cursor: pointer; font-family: inherit; display: inline-flex; align-items: center; gap: 5px; }
.seg a:hover { color: var(--text); }
.seg a.on { background: var(--surface); color: var(--text); font-weight: 550; box-shadow: var(--sh-1); }
.chip { display: inline-flex; align-items: center; gap: 4px; padding: 2px 9px; border-radius: 999px; background: var(--surface-3); color: var(--text-2); font-size: 12px; border: 1px solid transparent; }
.chip:hover { color: var(--text); border-color: var(--border-strong); }
.chip-on { background: var(--brand-soft); color: var(--brand); border-color: color-mix(in srgb, var(--brand) 35%, transparent); }
.chip-xs { padding: 1px 7px; font-size: 11px; }
/* 测试点数据的下载列（老师专用「入/出」两个小链接） */
.case-dl a { color: var(--brand); text-decoration: none; margin-right: 12px; font-size: 12.5px; white-space: nowrap; }
.case-dl a:last-child { margin-right: 0; }
.case-dl a:hover { text-decoration: underline; }
/* 失败点透出（2026-10-10）：学生的「看数据」按钮 + 输入/期望输出双栏对照 */
.case-view { background: none; border: none; padding: 0; color: var(--brand); font: inherit; font-size: 12.5px; cursor: pointer; white-space: nowrap; }
.case-view:hover { text-decoration: underline; }
.case-view:disabled { opacity: .5; cursor: default; }
.rec-actions { display: inline-flex; gap: 8px; align-items: center; }
.case-data-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 720px) { .case-data-cols { grid-template-columns: 1fr; } }
/* 知识块侧栏树（2026-10-10 可嵌套：老师可拖动排序/就地新增/双击改名） */
.kb-nav-row { display: flex; align-items: center; gap: 2px; border-radius: var(--r-sm); }
.kb-nav-row.t { cursor: grab; }
.kb-nav-row.t.dragging { opacity: .45; }
.kb-nav-row .scope-item { flex: 1; min-width: 0; }
.kb-grip2 { color: var(--muted); font-size: 11px; cursor: grab; padding: 0 2px; user-select: none; letter-spacing: -1px; }
.kb-mini { background: none; border: 1px solid var(--border); border-radius: 6px; color: var(--muted); font-size: 12px; line-height: 1; padding: 2px 6px; cursor: pointer; opacity: 0; transition: opacity .12s; }
.kb-nav-row:hover .kb-mini, .kb-mini:focus { opacity: 1; }
.kb-mini:hover { color: var(--brand); border-color: var(--brand); }
.kb-add-root { width: 100%; margin-top: 8px; background: none; border: 1px dashed var(--border); border-radius: var(--r-sm); color: var(--muted); font-size: 12.5px; padding: 7px 0; cursor: pointer; }
.kb-add-root:hover { color: var(--brand); border-color: var(--brand); }
#kb-root-drop { min-height: 26px; }
.kb-add-name { width: 100%; }
.kb-nav-row.drop-before { box-shadow: inset 0 2px 0 var(--brand); }
.kb-nav-row.drop-after { box-shadow: inset 0 -2px 0 var(--brand); }
.kb-nav-row.drop-in { outline: 2px dashed var(--brand); outline-offset: -2px; background: color-mix(in srgb, var(--brand) 8%, transparent); }
/* 编辑分组弹窗（2026-10-10 重做）：搜索 + 树形层级勾选 + 已选 chips，替代行内 52 个平铺复选框 */
.gm-card { max-width: 520px; }
.gm-tree { border: 1px solid var(--border); border-radius: var(--r-sm); max-height: 46vh; overflow: auto; padding: 6px 0; margin-top: 8px; }
.gm-row { display: flex; align-items: center; gap: 8px; padding: 6px 12px 6px calc(12px + var(--d, 0) * 18px); cursor: pointer; }
.gm-row:hover { background: var(--surface-2); }
.gm-row input { accent-color: var(--brand); }
.gm-row[data-hidden="1"] { display: none; }
.gm-sel { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.gm-sel:empty { display: none; }
.gm-chip { cursor: pointer; }
.stu-acts .btn, .stu-acts summary, .stu-acts .btn-sm { white-space: nowrap; }
/* 知识块右键菜单（2026-10-10 VSCode 式）：新增子块/改名/删除 */
.ctx-menu { position: fixed; z-index: 300; min-width: 150px; background: var(--surface, #1c2128); border: 1px solid var(--border);
  border-radius: var(--r-sm); box-shadow: 0 8px 24px rgba(0,0,0,.4); padding: 4px; }
.ctx-item { display: block; width: 100%; text-align: left; background: none; border: none; color: var(--text, inherit);
  font-size: 12.5px; padding: 7px 12px; border-radius: 6px; cursor: pointer; }
.ctx-item:hover { background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand); }
/* 题面「复制 Markdown」按钮：外观与旁边的标签 chip 一致，但它是可点的按钮 */
.copy-md { cursor: pointer; font-family: inherit; }
.copy-md:hover { color: var(--brand); border-color: color-mix(in srgb, var(--brand) 40%, transparent); }
.chips { display: flex; gap: 6px; flex-wrap: wrap; margin: 10px 0 14px; }
.badge { display: inline-flex; align-items: center; gap: 5px; padding: 2px 9px; border-radius: 999px; font-size: 12px; font-weight: 500; }
.badge-ac { background: var(--ac-soft); color: var(--ac); }
.badge-tried { background: var(--warn-soft); color: var(--warn); }
.badge-todo { background: var(--surface-3); color: var(--text-3); }
.badge-pending { background: var(--brand-soft); color: var(--brand); }
.badge-fail { background: var(--danger-soft); color: var(--danger); }
.badge-muted { background: var(--surface-3); color: var(--text-3); }
.alert { background: var(--danger-soft); color: var(--danger); border-radius: var(--r-sm); padding: 10px 12px; font-size: 13px; margin-bottom: 12px; }
.empty { padding: 40px 20px; text-align: center; color: var(--text-3); }

/* ---------- 5) 题库 ---------- */
/* 行清单走「文件管理器」式连续紧凑条（2026-09-29 用户钦定）：发丝线分隔 + 小内距，
   分隔线用 --row-line（暗色自动收暗）——实测暗色下 --border 太亮，是「行像独立卡片」观感的主因。 */
.plist { overflow: hidden; }
.plhead { font-size: 11.5px; font-weight: 700; letter-spacing: .05em; color: var(--text-3); background: var(--surface-2);
  border-bottom: 1px solid var(--border); padding: 8px 18px; }
/* .plhead 的 8px 内距曾被下面同优先级的 .prow(11px) 按源码顺序盖掉，表头跟着变高；这里提一级优先级定死 */
.plist .prow.plhead { padding: 6px 18px; }
.plhead .plh-st { text-align: center; }
.plhead .plh-no { text-align: right; }
.plhead .plh-rate { text-align: right; }
.plist .prow:not(.plhead):hover { background: var(--surface-2); }
.prow {
  display: grid; grid-template-columns: 34px 74px minmax(0, max-content) minmax(0, 1fr) 118px;
  align-items: center; gap: 12px; padding: 7px 18px; border-bottom: 1px solid var(--row-line);
  color: inherit; transition: background .15s, box-shadow .15s;
}
.prow:last-child { border-bottom: 0; }
.prow { position: relative; }
.prow:hover { background: var(--surface-2); box-shadow: inset 2px 0 0 var(--brand); }
.prow .ttl a { color: inherit; }
/* 标题链接拉伸覆盖整行（整行可点），行内的按钮/标签/徽章抬起来保持可点 */
.prow .ttl a::after { content: ""; position: absolute; inset: 0; }
.prow .tags, .prow .rate, .prow .diff, .prow .btn, .prow .badge, .prow button { position: relative; z-index: 1; }
.prow .no {
  position: relative; z-index: 1;   /* 抬到整行拉伸链接之上：点题号不跳转，方便双击/全选复制 */
  font-family: var(--mono); font-size: 12.5px; color: var(--text-3); text-align: right;
  font-variant-numeric: tabular-nums; cursor: text; user-select: all;
}
/* 原来这里有一条 .prow .ttl:hover { color: var(--brand) } —— 删掉。
   .ttl 是 minmax(0,1fr) 那一整列（很宽），指针只要移进这一列、哪怕离文字还差几百像素，
   题名就白→蓝变一次色；同一行的「悬停」于是有了两套反馈（列内变蓝 / 列外只有底色+左侧蓝条），
   用户报「我就稍微挪动了一些鼠标，颜色就从白色变成蓝色」。
   现在整行统一：底色 + 左侧 2px 蓝条 + 指针变手型，不再有看不见的变色边界。 */
.prow .ttl { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prow .tags { display: flex; gap: 5px; overflow: hidden; }

/* 标签按类型着色（tagClass() 在 layout.mjs）：大类=蓝 / 课名=青 / 自拟题=绿 / 池题=橙 */
.chip.tag-cat { background: var(--brand-soft); color: var(--brand); border-color: transparent; }
.chip.tag-cat:hover { border-color: color-mix(in srgb, var(--brand) 40%, transparent); color: var(--brand); }
.chip.tag-lesson { background: var(--info-soft); color: var(--info); border-color: transparent; }
.chip.tag-lesson:hover { border-color: color-mix(in srgb, var(--info) 40%, transparent); color: var(--info); }
.chip.tag-zt { background: var(--ac-soft); color: var(--ac); border-color: transparent; }
.chip.tag-zt:hover { border-color: color-mix(in srgb, var(--ac) 40%, transparent); color: var(--ac); }
/* 知识点叶子（NOI 大纲树，2026-09-30）：专属紫，与课名青/大类蓝/题源绿区分 */
.chip.tag-know { background: var(--kt-soft); color: var(--kt); border-color: transparent; }
.chip.tag-know:hover { border-color: color-mix(in srgb, var(--kt) 40%, transparent); color: var(--kt); }
.chip.tag-chi { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.chip.tag-chi:hover { border-color: color-mix(in srgb, var(--warn) 40%, transparent); color: var(--warn); }

/* 通过率：56px 圆角小轨 + 分档配色（≥60 绿 / ≥30 琥珀 / 低=灰红）；没人提交过显示 — */
.prow .rate { font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; display: flex; align-items: center; gap: 8px; }
.prow .rate b { font-weight: 600; color: var(--text-2); min-width: 34px; text-align: right; }
.prow .rate .rate-na { min-width: 34px; text-align: right; opacity: .7; }
.ratebar { flex: 1; height: 6px; border-radius: 99px; background: var(--surface-3); overflow: hidden; min-width: 52px; }
.ratebar i { display: block; height: 100%; border-radius: 99px; background: var(--text-3); transition: width .3s; }
.ratebar.rate-hi i { background: var(--ac); }
.ratebar.rate-mid i { background: var(--warn); }
.ratebar.rate-lo i { background: color-mix(in srgb, var(--danger) 55%, var(--text-3)); }

.diff { font-size: 12px; display: inline-flex; align-items: center; gap: 6px; }
.diff::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; opacity: .8; }
.diff-easy { color: var(--ac); } .diff-medium { color: var(--warn); } .diff-hard { color: var(--danger); } .diff-none { color: var(--text-3); }
.mark { width: 18px; height: 18px; border-radius: 50%; display: grid; place-items: center; font-size: 11px; }
.mark-ac { background: var(--ac-soft); color: var(--ac); }
.mark-tried { background: var(--warn-soft); color: var(--warn); }
.mark-todo { border: 1.5px dashed var(--border-strong); }
@media (max-width: 1100px) {
  .prow { grid-template-columns: 30px 60px minmax(0, 1fr) 84px; }
  .prow .tags { display: none; }
}
.pager { display: flex; gap: 4px; justify-content: center; margin: 18px 0 0; }
.pg { min-width: 32px; height: 32px; padding: 0 9px; display: inline-flex; align-items: center; justify-content: center; border-radius: var(--r-sm); color: var(--text-2); font-size: 13px; border: 1px solid transparent; }
.pg:hover { background: var(--surface-3); color: var(--text); }
.pg.on { background: var(--brand); color: #fff; }
.pg.off { opacity: .4; }

/* ---------- 6) 题页工作台 ---------- */
/* 中间那条拖动线（2026-09-24 用户「看起来很粗」）：
   原来 gutter 8px 里用 `inset: 0 3px` 画一条 **2px** 的线，左边还叠着 .ws-left 的
   1px 右边框 —— 两条线之间隔 3px，眼睛把它们并成一条粗带子。
   现在整条分隔线只由 gutter 画：1px 居中，hover 加粗到 3px 变蓝。 */
.ws { display: grid; grid-template-columns: minmax(0, 1fr) 9px minmax(0, 1fr); height: calc(100vh - var(--nav-h)); }
.ws.dragging { cursor: col-resize; user-select: none; }
/* 拖分栏线时指针会扫过右栏 —— 右栏若是 Excalidraw 的 iframe，move 事件全被 iframe 吃掉，
   表现为「往右拖不动」（2026-09-28 用户报；往左拖没事是因为指针还在父文档里）。
   拖动期间把 iframe 的指针事件关掉，父文档收得到 mousemove。 */
.ws.dragging #bd-frame { pointer-events: none; }
.ws-gutter { cursor: col-resize; background: transparent; position: relative; }
.ws-gutter::after { content: ""; position: absolute; top: 0; bottom: 0; left: 50%; width: 1px; margin-left: -.5px;
  background: var(--border); transition: width .15s, margin-left .15s, background .15s; }
.ws-gutter:hover::after, .ws.dragging .ws-gutter::after { width: 3px; margin-left: -1.5px; background: var(--brand); }
.ws-left, .ws-right { min-width: 0; overflow: hidden; display: flex; flex-direction: column; }
/* 右边框交给 .ws-gutter 画：这里再画一条就和它并排成「粗线」了。窄屏下由 1118 行统一清掉 */
.ws-left { border-right: 0; }
/* 标题+徽章块已移进 pane-body 滚动流（2026-10-03 用户：这块常驻占了太多可视区，题目描述太窄；
   滚动时随内容上滚，钉住的只有 tabs 行）。pane-body 自带 20px 内边距，这里只留纵向节奏。 */
.pane-body .problem-head { padding: 0 0 12px; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
.problem-head { padding: 18px 22px 14px; border-bottom: 1px solid var(--border); }
.problem-head h1 { font-size: 20px; display: flex; align-items: center; gap: 10px; }
.problem-meta { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; margin-top: 9px; font-size: 12px; color: var(--text-3); }
.problem-meta > span { display: inline-flex; align-items: center; gap: 5px; }
.problem-meta svg { width: 14px; height: 14px; }
.problem-meta .sep { width: 3px; height: 3px; border-radius: 50%; background: var(--border-strong); }
.tabs { display: flex; gap: 2px; padding: 8px 16px 0; border-bottom: 1px solid var(--border); align-items: center; }
/* 提交记录搜索（2026-10-03 用户钦定「老师可以搜索出某个人的提交记录」；2026-10-03 美化：
   放大镜图标胶囊输入（复用题库 search-wrap 形态）+ 计数同行右置，与列表间距收紧） */
.recs-search { display: flex; align-items: center; gap: 14px; padding: 10px 16px 8px; }
.recs-search .search-wrap { position: relative; width: 240px; }
.recs-search .search-wrap .input { width: 100%; padding-left: 30px; border-radius: 999px; }
.recs-search .search-go { position: absolute; left: 9px; top: 50%; transform: translateY(-50%); color: var(--text-3); pointer-events: none; display: inline-flex; }
.recs-search .search-go svg { width: 14px; height: 14px; }
.recs-search .input:focus + .search-go, .recs-search .search-wrap:focus-within .search-go { color: var(--brand); }
.recs-search > .muted { flex: none; }
/* 收藏/打印/翻题挪进 tab 行右侧（2026-10-03 用户钦定）：标题块随内容滚走后，这组操作跟着钉住的 tabs 走 */
.tabs .ph-nav { margin-left: auto; flex: none; }
/* 页签行垂直居中（2026-10-07 问题记录 #28）：tab 与右侧动作链接统一盒高（8px 上下 + 底边对齐），
   原先 tab 有 padding-bottom 0、ph-nav 组 8px，两边中心差一截，肉眼看是一高一低。 */
.tabs .tab, .tabs .pn-link { display: inline-flex; align-items: center; padding-top: 8px; padding-bottom: 8px; }
.tabs .tab { padding: 8px 12px; margin-bottom: -1px; }
.tabs .pn-link { white-space: nowrap; }
.tab { padding: 8px 12px; font-size: 13px; color: var(--text-2); border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: pointer; background: none; border-left: 0; border-right: 0; border-top: 0; font-family: inherit; }
.tab:hover { color: var(--text); }
.tab.on { color: var(--text); font-weight: 600; border-bottom-color: var(--brand); }
.pane-body { flex: 1; overflow: auto; padding: 20px 22px 60px; }
.statement { max-width: 760px; font-size: var(--fs-statement); line-height: 1.78; color: var(--text); }
/* 工作台左栏里的题面**跟随栏宽**（2026-09-25 用户：「拖动之后题目没跟着变长、右边留一大片空白」）。
   760px 那个限宽是给居中排版留的可读行长用的；在分栏里，宽度是用户自己拖出来的，就该听他的。
   注意只限 .ws-left（作业/比赛的说明、打印页等地方仍然吃 760px）。 */
.ws-left .statement { max-width: none; }
.statement > h2 { font-size: 15px; margin: 26px 0 8px; padding-top: 4px; }
.statement > h2:first-child { margin-top: 0; }
.statement p { margin: 0 0 12px; }
/* 列表缩进随字号缩放（2026-10-01 用户报「1. 2. 序号被裁掉一半」）：padding 写死 22px 时，
   字号调大（设置面板最高 35px）后 outside 标记的占位超出 padding 区，被 pane-body 的
   overflow 裁掉。max() 保证小字号维持原 22px、大字号按 1.7em 自动放宽（嵌套列表逐层叠加也安全）。 */
.statement ul, .statement ol { margin: 0 0 12px; padding-left: max(22px, 1.7em); }
.statement li { margin: 3px 0; }
.statement code { font-family: var(--mono); font-size: .88em; background: var(--surface-3); padding: 1.5px 5px; border-radius: 5px; color: var(--text); }
.statement pre { position: relative; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 12px 14px; overflow: auto; margin: 0 0 14px; }
.statement pre code { background: none; padding: 0; font-size: 13px; }
/* 代码块的行高必须按「代码自己的字号」钉死（2026-09-25 用户报「笔记里代码块莫名有很多空行」）。
   真凶：pre 继承的是正文那套（--fs-statement ≈21px × line-height 1.78 = 37.4px 的行盒），
   而里面的 code 只有 13px —— 行盒高度取参与者的较大者，于是**每行都被撑成将近两倍**，
   看着就跟「每行下面多一个空行」一样（实测 pre 高 699px，按 13px 算只该 440px，倍数 1.59）。
   这里把 pre 自己的字号/行高也按代码钉死，行盒就不再被正文的 strut 撑开。 */
.statement pre { font-size: 13px; line-height: 1.62; }
/* 代码高亮（Prism）主题：颜色全取门户调色板，暗/亮两套自动跟随 ——
   刻意**不用** prism 自带的浅色主题 css（暗色下深绿 #690、深蓝 #07a 几乎看不清）。 */
pre code .token.comment, pre code .token.prolog, pre code .token.doctype, pre code .token.cdata { color: var(--text-2); }
/* 注释不放斜体（2026-10-15 用户「注释看不清」）：中文伪斜体发虚，颜色提到 --text-2 分层即可。 */
pre code .token.punctuation, pre code .token.operator { color: var(--text-2); }
pre code .token.keyword, pre code .token.control, pre code .token.directive { color: var(--brand); }
pre code .token.string, pre code .token.char, pre code .token.attr-value { color: var(--ac); }
pre code .token.number, pre code .token.boolean, pre code .token.constant { color: var(--warn); }
pre code .token.function, pre code .token.macro, pre code .token.preprocessor { color: var(--info); }
pre code .token.class-name, pre code .token.type, pre code .token.builtin { color: var(--info); }
pre code .token.deleted { color: var(--danger); }
pre code .token.inserted { color: var(--ac); }
.statement table { border-collapse: collapse; margin: 4px 0 14px; font-size: 14px; }
.statement th, .statement td { border: 1px solid var(--border); padding: 6px 11px; }
.statement th { background: var(--surface-2); font-weight: 600; }
.statement img { max-width: 100%; border-radius: var(--r-sm); }
.statement .math-block { overflow-x: auto; margin: 10px 0 14px; }
.statement blockquote { margin: 0 0 12px; padding: 2px 14px; border-left: 3px solid var(--border-strong); color: var(--text-2); }
.katex { font-size: 1.02em; }
/* 复制按钮：常显（原来 opacity:0 只在悬停出现，用户看不到 → 以为没有复制功能，踩过） */
.copy-btn { padding: 3px 9px; font-size: 11.5px; color: var(--text-2); background: var(--surface);
  border: 1px solid var(--border); border-radius: 6px; cursor: pointer; transition: all .14s; font-family: inherit; }
.copy-btn:hover { color: var(--brand); border-color: var(--brand); background: var(--brand-soft); }
/* 题面里非样例的代码块：仍悬浮在右上角（那里没有块头可放） */
.statement pre > .copy-btn { position: absolute; top: 6px; right: 6px; }
.statement pre { position: relative; }
/* 说明：早先这里有一条给「样例代码块」用的 .sample 规则；现在 .sample 已经是力扣式示例卡片
   （见文末第 13 节），旧规则会让卡片继承等宽字体 + white-space:pre，故删除。 */
.pane-foot { border-top: 1px solid var(--border); padding: 10px 22px; display: flex; gap: 10px; align-items: center; color: var(--text-3); font-size: 12px; }

/* 右栏编辑器 */
.ed-top { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--border);
  flex-wrap: wrap; row-gap: 6px; }
/* 窄栏不裁按钮（2026-10-07 问题记录 #14）：把左栏拖宽（或窗口本身窄）时顶栏一行装不下，
   而 .ws-right 是 overflow:hidden——排最后的「提交」「重置」直接被裁没。三层降级：
   ① 容器查询按右栏**实际宽度**生效（拖分隔条也响应，媒体查询做不到）：先藏文件名芯片与草稿提示，
   ② 再把「重置」「画板」收成纯图标，③ flex-wrap 永远兜底——任何宽度下主操作都看得见。 */
.ws-right { container: wsright / inline-size; }
@container wsright (max-width: 560px) {
  .ws-right .ed-top .fio-files, .ws-right .ed-top .draft-tip { display: none; }
}
@container wsright (max-width: 470px) {
  .ws-right .ed-top #btn-reset-t, .ws-right .ed-top .bd-open-t { display: none; }
  .ws-right .ed-top { row-gap: 4px; }
}
.ed-top .lang { appearance: none; padding: 6px 26px 6px 10px; font-size: 13px; border-radius: var(--r-sm); border: 1px solid var(--border-strong); background: var(--surface) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238b919d' stroke-width='2.5'><path d='M6 9l6 6 6-6'/></svg>") no-repeat right 8px center; color: var(--text); }
/* 编辑器容器：绝对定位让 CodeMirror 严格填满父容器
   （踩过：CM 内部的 .CodeMirror-scroll 会算成内容高度，导致可视区空一片） */
.ed-body { flex: 1; min-height: 0; overflow: hidden; position: relative; }
.ed-body .CodeMirror { position: absolute; inset: 0; height: auto; }
.CodeMirror { font-family: var(--mono); font-size: var(--code-fs); line-height: 1.6; background: var(--surface); color: var(--text); }
.cm-s-oj.CodeMirror { background: var(--surface); color: var(--text); }
.cm-s-oj .CodeMirror-gutters { background: var(--surface-2); border-right: 1px solid var(--border); }
/* ---------- 行号栏宽度：**算出来的，不是量出来的**（2026-09-26 定稿，替换掉前三轮的"自愈"） ----------
   病根：CodeMirror 5 把行号栏宽度交给**运行时 JS 测量**（造隐藏节点读 offsetWidth），缓存在
   `display.lineNumWidth/lineNumInnerWidth/lineNumChars` 上，而且**只在行号位数变化时**才重量。
   这一个数决定：行号栏内联宽度 → `gutters.offsetWidth` → `sizer.marginLeft`（= 代码的左偏移）；
   同一个数还进 `dims.gutterTotalWidth` → 每一行行号盒的左移量。所以"量错一次"就会同时表现为
   「代码压住行号」「行号压住代码」「越量越宽右漂」——全都是这一个数错了。
   而我们站点恰好把"测量必须成立"的三个前提同时破坏了：**Web 字体迟到**（先按回退字体量）、
   **面板/分栏初始零宽**（量的时候容器是 0）、**字号用户可调**（老师设了 28px，字形变了却永不重量）。
   前三轮我都在"治理被污染出来的数字"（补写内联值、清缓存逼它重量、按几何回扳、加看门狗）——
   3 次以上失败就该换架构：**把测量从系统里删掉**。
   现在宽度 = `位数 × 1ch + 内边距`，由 CSS 算（`ch` 是浏览器按当前真实字体算的，不用我们量）；
   栏宽、每行号码盒宽、每行左移量、代码左偏移**全部由这同一个值推导**，并用 `!important`
   压掉 CM 写死的那些内联值（`vendor` 的 renderGutters / maybeUpdateLineNumberWidth 会写内联 width）。
   JS 只负责把「现在是几位数」写进 `--num-digits`（`String(cm.lineCount()).length`，纯数字、零测量）。
   ⇒ 字体迟到 / 容器零宽 / 字号变化这些**时机问题全部失去意义**：条件一变 CSS 自己重算，
     没有缓存会过期，也就没有东西需要"自愈"。5 个编辑器实例都吃 `.cm-s-oj`，一处生效。 */
.CodeMirror { --line-num-w: calc(var(--num-digits, 3) * 1ch + 22px); }
/* 尾部内边距从 15px 提到 22px（2026-09-26 用户报「代码离行号栏太近」）。
   为什么是 22：行号在栏里是**左对齐**的，所以「行号右缘 → 代码左缘」的间隙 = 尾部内边距 − 左 padding(8px)。
   15px 时只有 7px，两位数行号（10、11…）几乎贴住代码；22px → 14px，一位数两位数都一样宽，只多 7px。
   改这一个数仍然够用：栏宽 / 号码盒宽 / 每行左移量 / 代码左偏移全由它推导，见上面那段注释。
   对过的四种取值（15/19/22/26）本地同源渲染在 workspace/cspj-review-kebiao_2026-09-23/gutter-check.html。 */
/* 三处的 1ch 必须同一个基准：把字号钉成代码字号（行号本身也是这个字号） */
.cm-s-oj .CodeMirror-gutters, .cm-s-oj .CodeMirror-gutter-wrapper { font-size: var(--code-fs, 13px); }
/* ⚠️ 下面这几条**只对"真的带行号"的实例生效**：判据是 CM 有没有渲染出行号栅格
   （`.CodeMirror-linenumbers`）。2026-09-26 用户报「写笔记的地方前面有很多空白」——
   笔记编辑器是 lineNumbers:false（没有栅格、没有号码盒），可 `.CodeMirror-sizer` 的
   margin-left 是**无条件**打断的，于是正文与光标整体右移 34.5px、还和左侧占位文字错位。 */
.cm-s-oj:has(.CodeMirror-linenumbers) .CodeMirror-gutter.CodeMirror-linenumbers { width: var(--line-num-w) !important; }
.cm-s-oj:has(.CodeMirror-linenumbers) .CodeMirror-gutter-wrapper { left: calc(-1 * var(--line-num-w)) !important; }
.cm-s-oj:has(.CodeMirror-linenumbers) .CodeMirror-linenumber.CodeMirror-gutter-elt {
  width: var(--line-num-w) !important; box-sizing: border-box !important; }
.cm-s-oj:has(.CodeMirror-linenumbers) .CodeMirror-sizer { margin-left: var(--line-num-w) !important; }
.cm-s-oj .CodeMirror-linenumber { padding: 0 6px 0 8px; color: var(--text-3); opacity: .75; }
/* 编辑器获得焦点时行号亮一点：让「现在在写代码」有可见反馈 */
.cm-s-oj.CodeMirror-focused .CodeMirror-linenumber { opacity: 1; }
/* 代码区四周留出呼吸空间：CodeMirror 默认贴边，长行滚动条贴着底边很挤 */
.ed-body .CodeMirror { padding: 8px 0 2px; box-sizing: border-box; }
.ed-body .CodeMirror-scroll { padding-bottom: 14px; }
/* 横向滚动条细化（默认 16px 高，手机上会盖住最后一行代码的下沿） */
.ed-body .CodeMirror-scroll::-webkit-scrollbar { height: 8px; }
.ed-body .CodeMirror-scroll::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 99px; }
.ed-body .CodeMirror-scroll::-webkit-scrollbar-track { background: transparent; }
/* 行号字号必须跟代码字号走（--code-fs）：写死 12px 时，用户调大编辑器字号后
   行号行盒(19px)比代码行(32px)矮，行号越往下越往上飘（累积错位，用户抓到） */
.cm-s-oj .CodeMirror-linenumber { color: var(--text-3); font-size: var(--code-fs, 13px); line-height: inherit; }
.cm-s-oj .CodeMirror-cursor { border-left: 2px solid var(--brand); }
.cm-s-oj .CodeMirror-selected, .cm-s-oj.CodeMirror-focused .CodeMirror-selected { background: var(--brand-soft) !important; }
.cm-s-oj .cm-keyword { color: var(--syn-kw); } .cm-s-oj .cm-builtin { color: var(--syn-type); }
.cm-s-oj .cm-string, .cm-s-oj .cm-string-2 { color: var(--syn-str); }
.cm-s-oj .cm-number, .cm-s-oj .cm-atom { color: var(--syn-num); }
.cm-s-oj .cm-comment { color: var(--syn-com); }   /* 中文注释不放斜体（2026-10-15，同 Prism token 口径） */
.cm-s-oj .cm-def, .cm-s-oj .cm-variable-2 { color: var(--syn-fn); }
.cm-s-oj .cm-type, .cm-s-oj .cm-variable-3 { color: var(--syn-type); }
.cm-s-oj .cm-meta, .cm-s-oj .cm-preprocessor { color: var(--syn-kw); }
.cm-s-oj .cm-operator, .cm-s-oj .cm-punctuation { color: var(--text-2); }
.cm-s-oj .CodeMirror-matchingbracket { color: var(--brand) !important; border-bottom: 1px solid var(--brand); }
.cm-s-oj .CodeMirror-activeline-background { background: var(--surface-2); }

/* ---------- 7) 底部停靠区：判题控制台 + 自测面板（两块各自独立开合） ---------- */
.dock { display: flex; flex-direction: column; min-height: 0; flex: 0 1 auto; }
.console { border-top: 1px solid var(--border); background: var(--surface); display: flex; flex-direction: column; min-height: 0; max-height: 40vh; }
.console-head { display: flex; align-items: center; gap: 10px; padding: 9px 14px; border-bottom: 1px solid var(--border); cursor: pointer; flex: none; }
.console-head .v { font-weight: 650; font-size: 14px; }
.v-ac { color: var(--ac); } .v-fail { color: var(--danger); } .v-pending { color: var(--brand); } .v-muted { color: var(--text-3); }
.console-body { overflow: auto; padding: 12px 14px 16px; min-height: 0; }
.cases { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.cases th { text-align: left; color: var(--text-3); font-weight: 500; padding: 4px 10px 6px; }
.cases td { padding: 5px 10px; border-top: 1px solid var(--border); font-variant-numeric: tabular-nums; }
.cases tr:hover td { background: var(--surface-2); }
.msg { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 9px 11px; margin: 8px 0 0; font-family: var(--mono); font-size: 12px; white-space: pre-wrap; max-height: 200px; overflow: auto; }

/* 自测面板：左输入 / 右输出双栏；高度随视口走，两块区域一起长 */
/* 高度要「固定」而不是 max-height：否则切到「测试结果」内容少 → 面板塌下去、编辑器突然变高（用户报的 bug） */
.run-panel { border-top: 1px solid var(--border); background: var(--surface); display: flex; flex-direction: column; min-height: 0; height: clamp(210px, 44vh, 460px); }
.run-head { display: flex; align-items: center; gap: 10px; padding: 11px 14px; border-bottom: 1px solid var(--border); flex: none;
  background: var(--surface-2); }
.run-title { font-weight: 650; font-size: 13px; display: inline-flex; align-items: center; gap: 7px; }
.run-head .btn-primary { min-width: 96px; }
.run-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0; flex: 1; min-height: 0; }
@media (max-width: 900px) { .run-grid { grid-template-columns: 1fr; } }
/* 三区布局（输入 / 输出 / 答案）：输出区是程序真实跑出来的结果，就地显示、不再单开「测试结果」页 */
.run-tri { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); flex: 1; min-height: 0; }
.run-tri .run-col + .run-col { border-left: 1px solid var(--border); }
.run-tri .run-output { flex: 1; min-height: 104px; margin: 0 12px 12px; padding: 10px 12px; overflow: auto;
  font-family: var(--mono); font-size: 12.5px; line-height: 1.65; white-space: pre-wrap;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2); color: var(--text-2); }
/* 手机上三格竖排：每格给固定可用的最小高度（64px 只够看一行，实际跑样例要看 3~5 行） */
@media (max-width: 900px) {
  .run-tri { grid-template-columns: 1fr; }
  .run-tri .run-col + .run-col { border-left: 0; border-top: 1px solid var(--border); }
  .run-tri .run-panel textarea, .run-tri .run-output { min-height: 96px; max-height: 40vh; }
}
/* 三格并排时输出格太窄，一行放不下几个字符：≤720px 就竖排 */
@media (max-width: 720px) { .run-tri { grid-template-columns: 1fr; } .run-tri .run-col + .run-col { border-left: 0; border-top: 1px solid var(--border); } }
.run-col { min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.run-col + .run-col { border-left: 1px solid var(--border); }
.run-label { flex: none; padding: 9px 14px 5px; font-size: 11.5px; letter-spacing: .05em; color: var(--text-3);
  display: flex; align-items: center; gap: 8px; text-transform: uppercase; font-weight: 600; }
.run-label .btn { padding: 2px 7px; font-size: 11px; }
/* 检查器给的不通过理由（自测用题目自己的 checker 判，2026-09-25）：挂在「答案」格文本域下面，
   只在有话说时出现（.hide 收起来），文案可能是兜底模板译出来的中文，也可能是 checker.cpp 自己写的 */
.run-chk { flex: none; margin: 0 12px 10px; padding: 7px 10px; border-radius: var(--r-sm); font-size: 12px;
  line-height: 1.6; overflow-wrap: anywhere;
  background: color-mix(in srgb, var(--danger) 10%, transparent); color: var(--danger);
  border: 1px solid color-mix(in srgb, var(--danger) 26%, transparent); }
.run-chk.hide { display: none; }
.run-status { font-size: 12px; font-weight: 500; letter-spacing: 0; }
.run-status.ok { color: var(--ac); } .run-status.bad { color: var(--danger); } .run-status.wait { color: var(--brand); }
.run-panel textarea,
.run-panel .run-output {
  flex: 1; min-height: 104px; margin: 0 12px 12px; padding: 11px 13px; resize: none; overflow: auto;
  font-family: var(--mono); font-size: 13px; line-height: 1.7;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text); white-space: pre;
}
.run-panel textarea:focus { border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 16%, transparent); }
.run-panel textarea { display: block; width: calc(100% - 24px); }
.run-panel textarea:focus { outline: none; }
/* 三格底色统一（2026-09-24 用户「为什么背景色不一样」）：
   原来「输出」和「只读的输入」用 --bg（更深），可编辑的用 --surface-2 ——
   同一排三格出现两种深浅，同一个「输入」格在题目页（只读）和编辑器（可写）还不一样。
   只读态改由 cursor + 灰字 + 标签上的「样例 · 只读」表达，不再动底色。 */
.run-panel textarea.ro { background: var(--surface-2); color: var(--text-2); cursor: not-allowed; }
.run-panel .run-output { color: var(--text-2); background: var(--surface-2); tab-size: 4; }
.run-panel .run-output.has-out { color: var(--text); }
/* 编译错误态（2026-10-07 问题 #9 美化）：输出格升格为「编译输出」——danger 浅底 + 描边与
   .run-chk 同一词汇（color-mix 令牌自动适配深浅色）；g++ 正文保持 --text（三四十行长文全红
   反而读不了），语义由底色/描边/标签换字（「编译输出」+ .is-ce danger 色）承担。 */
.run-panel .run-output.ce, .run-tri .run-output.ce {
  background: color-mix(in srgb, var(--danger) 7%, var(--surface-2));
  border-color: color-mix(in srgb, var(--danger) 32%, transparent);
  color: var(--text);
}
.run-label .is-ce { color: var(--danger); }
/* 提交详情「提交人」行（2026-10-07 问题 #10）：行内人形图标 + 名字，与 meta 卡其他行同基线 */
.rec-owner { display: inline-flex; align-items: center; gap: 5px; }
.rec-owner svg { opacity: .72; }

.recs { padding: 4px 0; }
.rec-row { display: grid; grid-template-columns: 96px 110px 70px 90px 90px 150px; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--border); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.rec-row:last-child { border-bottom: 0; }

/* ---------- 8) 首页 ---------- */
.hero { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 18px; margin-bottom: 18px; }
@media (max-width: 900px) { .hero { grid-template-columns: 1fr; } }
.hero-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 22px 24px; box-shadow: var(--sh-1); }
.hero-card h2 { font-size: 18px; margin-bottom: 6px; }
.ring { position: relative; width: 132px; height: 132px; }
.ring svg { transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 11; stroke-linecap: round; }
.ring .bg { stroke: var(--surface-3); }
.ring .fg { stroke: var(--brand); transition: stroke-dashoffset .6s cubic-bezier(.4, 0, .2, 1); }
.ring-label { position: absolute; inset: 0; display: grid; place-items: center; text-align: center; }
.ring-label b { font-size: 24px; letter-spacing: -.03em; display: block; }
.ring-label span { font-size: 12px; color: var(--text-3); }
.quick { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px; }
.quick a { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); box-shadow: var(--sh-1); color: var(--text); }
.quick a:hover { border-color: var(--brand); }
.quick .ic { width: 32px; height: 32px; border-radius: 9px; display: grid; place-items: center; background: var(--brand-soft); color: var(--brand); }
.quick .ic svg { width: 17px; height: 17px; }
.quick .tt { font-weight: 550; font-size: 13.5px; }
.quick .dd { font-size: 12px; color: var(--text-3); }

/* ---------- 9) 登录 ---------- */
.login-shell { min-height: calc(100vh - var(--nav-h)); display: grid; place-items: center; padding: 40px 20px; }
.login-card { width: 100%; max-width: 400px; padding: 28px 30px; }
.login-card h1 { font-size: 20px; margin-bottom: 4px; }
.field { margin: 14px 0; }
/* 只作用于字段的直接标签：写成 .field label 会连带命中选择器里的 <label class="pk-item">，
   把它的 grid 布局压成 block（踩过：选择器每行题名/题号/标签全挤成三行） */
.field > label { display: block; font-size: 13px; color: var(--text-2); margin-bottom: 6px; }

/* ---------- 9c) 收藏（题目页星标 + 收藏夹） ---------- */
.btn-fav { border: 0; background: none; cursor: pointer; font-size: 13px; color: var(--text-2); display: inline-flex; align-items: center; gap: 5px; padding: 4px 8px; border-radius: var(--r-sm); transition: all .14s; }
.btn-fav:hover { background: var(--brand-soft); color: var(--brand); }
.btn-fav svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.btn-fav.on { color: var(--warn); }
.btn-fav.on svg { fill: var(--warn); stroke: var(--warn); }

/* ---------- GESP 等级徽章（学生名单列 + 设置弹窗，2026-10-11 用户要求） ----------
   1~8 级八种颜色（绿→青→蓝→靛→紫→品红→橙→红，像段位一样一眼看出级别）；
   徽章与弹窗钮共用 .gesp-badge，颜色全走 --gl 单变量（色底用 color-mix，深浅主题自适配）。 */
.gesp-cell { white-space: nowrap; }
th.gesp-cell { color: var(--text-3); font-weight: 600; }
.gesp-badge { display: inline-flex; align-items: center; justify-content: center; gap: 4px; min-width: 54px;
  padding: 3px 10px; border-radius: 999px; border: 1px solid var(--border); background: none;
  color: var(--text-3); font: inherit; font-size: 12px; font-weight: 600;
  font-variant-numeric: tabular-nums; cursor: pointer; transition: all .14s; }
.gesp-badge.none { border-style: dashed; }
.gesp-badge:not(.none), .gesp-badge[data-lv] { --gl: var(--brand); }
.gesp-badge[data-lv="1"] { --gl: #3fa45b; }
.gesp-badge[data-lv="2"] { --gl: #14a8ad; }
.gesp-badge[data-lv="3"] { --gl: #2f6df6; }
.gesp-badge[data-lv="4"] { --gl: #5e5ce6; }
.gesp-badge[data-lv="5"] { --gl: #8b5cf6; }
.gesp-badge[data-lv="6"] { --gl: #c2419a; }
.gesp-badge[data-lv="7"] { --gl: #e08a1e; }
.gesp-badge[data-lv="8"] { --gl: #e5484d; }
.gesp-badge:not(.none) { color: var(--gl); border-color: color-mix(in srgb, var(--gl) 45%, transparent);
  background: color-mix(in srgb, var(--gl) 14%, transparent); }
.gesp-badge:not(.none):hover { background: color-mix(in srgb, var(--gl) 26%, transparent); }
.gesp-badge.none:hover { border-color: var(--brand); color: var(--brand); }
/* 设置弹窗里的八枚级别钮：4×2 网格、块状加大，当前等级描边高亮 */
.gesp-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 12px; }
.gesp-grid .gesp-badge { min-width: 0; padding: 9px 0; font-size: 13px; border-radius: var(--r-sm); }
.gesp-grid .gesp-badge.on { outline: 2px solid var(--gl); outline-offset: 1px; }
/* 考试分数行（等级+分数双值，2026-10-11） */
.gesp-score-row { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.gesp-score-row label { font-size: 13px; color: var(--text-2); flex: none; }
.gesp-score-row .input { width: 110px; }
.gesp-score-row .input::placeholder { color: var(--text-3); font-size: 12px; }
/* 工具条里的按钮版 pn-link（收藏/数据存疑）：.pn-link 是按 <a> 写的，不重置的话
   <button> 会露出 UA 默认按钮壳（深色底+边框，2026-10-11 用户报「好丑」） */
.tabs button.pn-link { border: 0; background: none; cursor: pointer; font: inherit; color: var(--text-3); display: inline-flex; align-items: center; gap: 4px; }
.btn-weak { padding: 8px; border-radius: var(--r-sm); transition: all .14s; }   /* 8px 上下=与 .tab 同高垂直居中（#28） */
.btn-weak.arm { background: var(--danger-soft); color: var(--danger); font-weight: 600; }   /* 确认上报态（#27 两步确认） */
.btn-weak svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.btn-weak:hover { background: var(--warn-soft); color: var(--warn); }
.favhead { font-size: 12px; color: var(--text-3); }
.favrow { transition: opacity .15s; }
.favrow.removing { opacity: 0; }

/* ---------- 9d) 可见范围（全站共享 / 指定分组多选） ---------- */
/* 单选：自绘 + 选项卡形态（原来只有 accent-color，暗色下原生圆点是灰黑圈，用户嫌丑） */
input[type="radio"] {
  appearance: none; -webkit-appearance: none;
  margin: 0; width: 17px; height: 17px; flex: none;
  border: 1.5px solid var(--border-strong); border-radius: 50%;
  background: var(--surface); cursor: pointer; transition: all .14s;
}
input[type="radio"]:hover { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
/* 选中：蓝底 + 内缩底色环 = 中心蓝点（inset 阴影比 ::after 可靠，input 的伪元素在部分浏览器不生效） */
input[type="radio"]:checked { background: var(--brand); border-color: var(--brand); box-shadow: inset 0 0 0 3.5px var(--surface); }
/* 注意：用 .field > label.radio-line 提高特异性——通用的 `.field > label{display:block}` 会压掉 inline-flex */
.field > label.radio-line { display: inline-flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--text);
  margin: 6px 8px 6px 0; padding: 8px 13px; cursor: pointer; font-weight: 400;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface);
  transition: all .14s; }
.field > label.radio-line:hover { border-color: color-mix(in srgb, var(--brand) 40%, var(--border)); background: var(--surface-2); }
.field > label.radio-line:has(input:checked) { border-color: var(--brand); background: var(--brand-soft); color: var(--brand); font-weight: 550; }

.req { color: var(--fail, #d64545); font-weight: 700; margin-left: 2px; }
.field > label.radio-line input { cursor: pointer; }
/* 分组勾选：树形渲染（父组一行、子分组缩进挂在下面），样式见下方 .vis-groups / .vt-row */
/* 自绘时间选择器（原生 time 弹层样式碰不到；见 timepicker.js）：两列滚选 + 现在/清除/确定 */
.tp { position: relative; display: block; width: 100%; }
.tp .tp-input { padding-right: 34px; }
.tp-btn { position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  width: 26px; height: 26px; display: flex; align-items: center; justify-content: center;
  padding: 0; border: 0; border-radius: 6px; background: none; color: var(--text-3); cursor: pointer; }
.tp-btn:hover { color: var(--brand); background: var(--brand-soft); }
.tp-pop { position: absolute; z-index: 60; left: 0; top: calc(100% + 6px); width: 200px; padding: 8px;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .38); }
.tp-head { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; padding: 0 2px 6px;
  font-size: 11.5px; color: var(--text-3); text-align: center; }
.tp-body { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; height: 190px; }
.tp-col { overflow-y: auto; scrollbar-width: thin; border: 1px solid var(--border); border-radius: var(--r-sm); padding: 3px; background: var(--surface-2); }
.tp-cell { display: block; width: 100%; height: 28px; border: 0; border-radius: 5px; background: none;
  color: var(--text-2); font-family: inherit; font-size: 13px; font-variant-numeric: tabular-nums; cursor: pointer; }
.tp-cell:hover { background: var(--brand-soft); color: var(--brand); }
.tp-cell.on { background: var(--brand); color: #fff; font-weight: 650; }
.tp-foot { display: flex; gap: 6px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); }
.tp-foot .btn { flex: 1; justify-content: center; }

/* 数字输入框：去掉原生上下调节箭头（用户直接键入即可，箭头既难看又易误点） */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }

/* 自绘日期选择器（原生 <input type=date> 弹层样式碰不到，全站接管；见 datepicker.js） */
.dc { position: relative; display: block; width: 100%; }
.dc .dc-input { padding-right: 34px; }
.dc-btn { position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  width: 26px; height: 26px; display: flex; align-items: center; justify-content: center;
  padding: 0; border: 0; border-radius: 6px; background: none; color: var(--text-3); cursor: pointer; }
.dc-btn:hover { color: var(--brand); background: var(--brand-soft); }
.dc-pop { position: absolute; z-index: 60; left: 0; top: calc(100% + 6px); width: 272px; padding: 10px 10px 8px;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .38); }
.dc-head { display: flex; align-items: center; gap: 2px; margin-bottom: 8px; }
.dc-title { flex: 1; text-align: center; font-size: 13.5px; font-weight: 650; letter-spacing: .01em; }
.dc-nav { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 6px; background: none; color: var(--text-2); cursor: pointer; font-size: 14px; line-height: 1; }
.dc-nav:hover { background: var(--brand-soft); color: var(--brand); }
.dc-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 3px; }
.dc-week span { text-align: center; font-size: 11px; color: var(--text-3); padding: 2px 0; }
.dc-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dc-day { height: 30px; border: 0; border-radius: 6px; background: none; color: var(--text);
  font-family: inherit; font-size: 12.5px; font-variant-numeric: tabular-nums; cursor: pointer; transition: background .12s, color .12s; }
.dc-day:hover { background: var(--brand-soft); color: var(--brand); }
.dc-day.out { color: var(--text-3); opacity: .5; }
.dc-day.today { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--brand) 50%, transparent); }
.dc-day.on { background: var(--brand); color: #fff; font-weight: 650; }
.dc-day.on:hover { background: var(--brand-hover); color: #fff; }
.dc-foot { display: flex; gap: 8px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); }
.dc-foot .btn { flex: 1; justify-content: center; }

/* 持续时间：年/月/天/时/分 紧凑一行（5 个带 label 的字段太散） */
.dur-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.dur-item { display: inline-flex; align-items: center; gap: 4px; }
.dur-item .input { width: 76px; text-align: center; padding: 6px 8px; }
.dur-item em { font-style: normal; font-size: 13px; color: var(--text-2); }
.vis-groups {
  margin: 6px 0 0; padding: 9px 11px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2);
  /* 每行一个分组（旧版 flex-wrap 会把父子排成一排，层级看不出来）；层级的缩进与竖线在 .vt-kids */
  display: flex; flex-direction: column; gap: 2px;
}
.vt-row { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text); cursor: pointer;
  padding: 4px 6px; border-radius: var(--r-sm); }
.vt-row:hover { background: var(--surface-3); }
/* 三态：全选 / 半选（.mid，后代没勾齐）/ 未选。`:has()` 是首选，`.on`/`.mid` 由 app.js 同步（旧浏览器兜底） */
.vt-row.on, .vt-row:has(input:checked:not(:indeterminate)) { color: var(--brand); font-weight: 550; }
.vt-row.mid, .vt-row:has(input:indeterminate) { color: var(--text-2); font-weight: 550; }
.vt-row.mid { background: color-mix(in srgb, var(--brand-soft) 55%, transparent); }
.vt-row input:indeterminate { opacity: .85; }
.vt-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vt-tag { flex: none; margin-left: 2px; font-size: 11.5px; font-weight: 400; color: var(--text-3);
  border: 1px solid var(--border-strong); border-radius: 999px; padding: 1px 8px; }
/* 子分组层：左侧一条竖线从父组行引下来，深一层再套一层（与分组管理页 .gs-kids 同一套视觉语言） */
.vt-kids { display: flex; flex-direction: column; gap: 2px;
  margin: 2px 0 2px 11px; padding-left: 13px; border-left: 2px solid var(--border-strong); }

/* ---------- 29) 我的编辑器：与题目工作台同版式（上代码 / 下样例坞），只是没有题面 ---------- */
/* 整页零外边距、与顶栏同色，工作区占满导航条以下；class 全部复用题目工作台那套 */
.me-stack {
  display: flex; flex-direction: column;
  height: calc(100vh - var(--nav-h)); min-height: 420px;
  background: var(--surface);
}
.me-stack .ed-body { flex: 1; min-height: 120px; }
.me-stack .run-panel { flex: none; }
/* 编辑器 ⇄ 画板 切换（2026-10-01 用户钦定）：顶栏 seg 复用私信那套圆角分段钮；画板吃满代码区 */
.ed-top .me-mode-seg { margin-bottom: 0; }
/* ---------- 编辑器页空间最大化（2026-10-04 用户钦定）----------
   ① .ed-top 从流式横条（~57px）改为**右上悬浮胶囊**：语言下拉/编辑器⇄画板/重置/清空全在上面，
      代码区上移一整行；胶囊半透明毛玻璃，代码从它底下穿过去；
   ② .run-head 删除，统计+运行钮改 .me-run-float 悬浮簇钉样例坞右上角，用例区上移一整行；
      折叠态（拖到底）固定 48px——只剩悬浮运行钮一条，单击恢复。 */
.me-stack { position: relative; }
.me-stack .ed-top { position: absolute; top: 10px; right: 14px; z-index: 30;
  max-width: calc(100% - 24px);
  padding: 6px 10px; gap: 8px; border: 1px solid var(--border); border-radius: 999px;
  background: color-mix(in srgb, var(--surface-2) 90%, transparent);
  backdrop-filter: blur(10px); box-shadow: var(--sh-1); }
.me-stack .ed-top .spacer { display: none; }
/* —— 胶囊内控件统一「幽灵」化（2026-10-04 用户「美化这些图标」）——
   原来 dd-btn/pm-seg/两个 btn 各带一层边框，叠进悬浮胶囊里就成了「盒中盒」的杂乱感。
   现在：内部一律去边框、统一 28px 高、小圆角、悬浮才提亮；整枚胶囊只保留一层外边界，
   语言 | 编辑器⇄画板 | 重置·清空 三组之间用发丝分隔线与间距拉开节奏。 */
.me-stack .ed-top { border-radius: 13px; padding: 5px 7px; gap: 4px; }
.me-stack .ed-top .dd-btn { border: 0; background: transparent; min-height: 28px; height: 28px;
  padding: 0 8px; border-radius: 8px; font-size: 12.5px; color: var(--text-2); gap: 6px;
  box-shadow: none; transition: background .13s, color .13s; }
.me-stack .ed-top .dd-btn:hover { background: var(--surface-3); color: var(--text); }
.me-stack .ed-top .dd.open .dd-btn { border: 0; box-shadow: none; background: var(--surface-3); color: var(--text); }
.me-stack .ed-top .dd-btn .dd-caret { width: 14px; height: 14px; color: var(--text-3); }
.me-stack .ed-top .pm-seg { margin: 0; border: 0; border-radius: 9px; background: var(--surface-3);
  padding: 2px; overflow: visible; }
.me-stack .ed-top .pm-seg-btn { padding: 3px 11px; border-radius: 7px; font-size: 12px;
  transition: background .13s, color .13s; }
.me-stack .ed-top .pm-seg-btn + .pm-seg-btn { border-left: 0; }
.me-stack .ed-top .pm-seg-btn:not(.on):hover { color: var(--text); background: color-mix(in srgb, var(--surface) 60%, transparent); }
.me-stack .ed-top .pm-seg-btn.on { background: var(--brand); color: #fff; }
.me-stack .ed-top .btn { border: 0; background: transparent; height: 28px; padding: 0 9px;
  border-radius: 8px; font-size: 12.5px; color: var(--text-2); gap: 5px;
  transition: background .13s, color .13s; }
.me-stack .ed-top .btn:hover { background: var(--surface-3); color: var(--text); }
.me-stack .ed-top .btn svg { width: 14px; height: 14px; }
.me-stack .ed-top .muted.small { font-size: 12px; }
/* 组间发丝分隔线：语言组 | 模式组 | 动作组 */
.me-stack .ed-top #me-mode { margin-left: 3px; }
.me-stack .ed-top #me-reset { margin-left: 3px; position: relative; }
.me-stack .ed-top #me-reset::before { content: ''; position: absolute; left: -3px; top: 7px; bottom: 7px;
  width: 1px; background: var(--border); }
.me-stack .ed-top .dd-menu { z-index: 60; }   /* 语言下拉菜单得盖在胶囊与代码之上 */
.me-run-float { display: flex; align-items: center; justify-content: flex-end; gap: 8px; padding: 8px 12px 0; }
.me-stack .run-panel { position: relative; }
@media (min-width: 901px) {
  .me-run-float { position: absolute; top: 8px; right: 12px; z-index: 8; padding: 0; }
  .me-stack .case-tabs { padding-right: 168px; }              /* Case 标签/＋ 不被悬浮簇压住 */
  .me-stack .run-panel.collapsed { height: 48px; overflow: hidden; }   /* 折叠=只剩悬浮运行钮一条 */
  .me-stack .run-panel.collapsed .me-ce { display: none; }             /* 折叠时不显示编译错误块（展开可见） */
}
.ed-board { flex: 1; min-height: 240px; display: flex; }
.ed-board[hidden] { display: none; }
.ed-board iframe { flex: 1; width: 100%; border: 0; background: var(--surface); }
/* 我的编辑器：编译错误原文（g++ stderr，含行号列号）—— 徽章只说「编译错了」，这块才说「错在哪」 */
.me-ce { flex: none; margin: 10px 14px 0; max-height: 170px; overflow: auto; padding: 9px 12px;
  background: var(--danger-soft); color: var(--danger); border-radius: var(--r-sm);
  font: 12px/1.65 var(--mono, ui-monospace, monospace); white-space: pre-wrap; word-break: break-all; }
/* 样例坞折叠态（拖到底部） */
.run-panel.collapsed { height: auto; }
.run-panel.collapsed .run-body { display: none; }
@media (max-width: 1000px) {
  .me-stack { height: auto; min-height: 0; }
  .me-stack .ed-body { height: 52vh; flex: none; }
}
/* ---------- 9b) 表单校验错误（压掉浏览器原生气泡后的自己画的） ---------- */
.field.has-err { position: relative; }
.input-err, .input.input-err {
  border-color: var(--danger) !important;
  box-shadow: 0 0 0 3px var(--danger-soft);
}
.f-err-tip {
  position: absolute; top: calc(100% + 8px); left: 2px; z-index: 80;
  background: var(--danger); color: #fff;
  padding: 5px 11px; border-radius: 7px; font-size: 12px;
  width: max-content; max-width: 280px;
  box-shadow: var(--sh-2);
  animation: f-err-in .15s ease;
}
.f-err-tip::before {
  content: ""; position: absolute; top: -4px; left: 14px;
  width: 9px; height: 9px; background: var(--danger);
  transform: rotate(45deg); border-radius: 2px;
}
@keyframes f-err-in { from { opacity: 0; transform: translateY(-4px); } }

/* ---------- 10) 题单 / 团队（P2） ---------- */
/* 进度条：题单卡片与分节头共用 */
.bar { display: block; height: 6px; border-radius: 99px; background: var(--surface-3); overflow: hidden; }
.bar > i { display: block; height: 100%; border-radius: 99px; background: var(--brand); transition: width .4s ease; }

.list-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; }
.list-card { display: block; padding: 16px 18px; border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); box-shadow: var(--sh-1); color: var(--text); }
.list-card:hover { border-color: var(--brand); box-shadow: var(--sh-2); transform: translateY(-1px); }
.lc-top { display: flex; align-items: center; gap: 8px; }
.lc-name { font-size: 15.5px; font-weight: 600; letter-spacing: -.01em; }
.lc-done { margin-left: auto; font-size: 11.5px; color: var(--ac); font-weight: 600; }
.lc-desc { margin: 6px 0 10px; font-size: 12.5px; color: var(--text-3); min-height: 34px; line-height: 1.55;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.lc-meta { display: flex; flex-wrap: wrap; gap: 12px; font-size: 12px; color: var(--text-2); }
.lc-meta svg { vertical-align: -3px; }
.lc-prog { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.lc-prog .bar { flex: 1; }
.my-prog { margin-bottom: 16px; }
.mp-top { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 8px; }

/* 题单详情：分节 */
.node { margin-bottom: 14px; overflow: hidden; }
.node-head { display: flex; align-items: center; gap: 12px; padding: 12px 16px; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.node-head h2 { font-size: 14px; font-weight: 600; display: inline-flex; align-items: center; gap: 7px; }
.node-head h2 svg { width: 15px; height: 15px; flex: none; }
.node-head .bar { width: 120px; margin-left: auto; }
.prob-list { padding: 4px 0; }
.prob-row { display: grid; grid-template-columns: 56px minmax(0, 1fr) auto 76px; align-items: center; gap: 10px;
  padding: 8px 16px; border-bottom: 1px solid var(--border); position: relative; }
.prob-row:last-child { border-bottom: 0; }
.prob-row:hover { background: var(--surface-2); }
.prob-row .idx { color: var(--text-3); font-family: var(--mono); font-size: 12px; }
/* 题号那格抬到「整行拉伸链接」之上（与 .prow .no 同一套约定）：
   点题号不跳转，双击只复制题号本身（题目名不带上，JS 见 app.js 的 [data-copynum]）。 */
.prob-row .idx[data-copynum] { position: relative; z-index: 1; cursor: text; user-select: all; }
.prob-row .ttl a::after { content: ""; position: absolute; inset: 0; }
.prob-row .tags { display: flex; gap: 6px; z-index: 1; }
.prob-row .badge { justify-self: end; }

/* 团队 */
.card-head { display: flex; align-items: center; gap: 10px; padding: 13px 16px; border-bottom: 1px solid var(--border); }
.card-head h2 { font-size: 14.5px; display: flex; align-items: center; gap: 8px; }
.table { width: 100%; border-collapse: collapse; font-size: 13px; }
.table th { text-align: left; font-weight: 500; color: var(--text-3); font-size: 12px; padding: 9px 16px; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.table td { padding: 9px 16px; border-bottom: 1px solid var(--border); }
.table tr:last-child td { border-bottom: 0; }
.table tr:hover td { background: var(--surface-2); }
.table .num { font-variant-numeric: tabular-nums; }
.who { display: inline-flex; align-items: center; gap: 8px; }
.avatar-sm { width: 22px; height: 22px; font-size: 11px; }
.group-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
.group-card .gc-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px 8px; }
.group-card .gc-head h3 { font-size: 14px; }
.group-card .chips { padding: 0 14px 14px; }

/* ---------- 11) 作业 / 比赛（P3） ---------- */
.ct-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 14px; }
.ct-card { display: block; padding: 15px 17px; border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); box-shadow: var(--sh-1); color: var(--text); }
.ct-card:hover { border-color: var(--brand); box-shadow: var(--sh-2); transform: translateY(-1px); }
.ct-top { display: flex; align-items: center; gap: 10px; }
.ct-name { font-size: 15.5px; font-weight: 600; letter-spacing: -.01em; }
.ct-top .badge { margin-left: auto; }
.ct-time { margin: 8px 0; font-size: 12.5px; color: var(--text-2); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ct-live { color: var(--warn); font-weight: 600; }
.ct-meta { display: flex; align-items: center; gap: 12px; font-size: 12px; color: var(--text-2); }
.ct-mine { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--border); font-size: 12.5px; color: var(--text-2); }
.ct-when { display: flex; gap: 22px; flex-wrap: wrap; margin-bottom: 14px; font-size: 13px; }
.ct-desc { margin-bottom: 14px; white-space: pre-wrap; color: var(--text-2); font-size: 13px; }
.ct-prob .tags { display: none; }
.board { font-variant-numeric: tabular-nums; }
.board td.ok { color: var(--ac); font-weight: 600; }
.board td.part { color: var(--warn); }
.table tr.me td { background: var(--brand-soft); }
/* 子分组的段落标题行（成绩单/排行榜里按组分段，2026-09-25）：
   整行一条浅底 + 小字，别抢数据行的视线，也别让人误点 */
.table tr.board-grp td { background: var(--surface-2); color: var(--text-3); font-size: 12px;
  font-weight: 600; letter-spacing: .02em; padding-top: 6px; padding-bottom: 6px; }
.avatar-sm { font-size: 11px; }

/* 作业/比赛下的题目页：工作台占满导航栏以下全部高度。
   （2026-10-15 钦定：原题面上方的 ct-banner 横幅整条删除，上下文条压缩进顶栏
   正中间的 .topbar-center——题面/代码区因此多出一整条横幅的高度，flex 自动补位。） */
.ws-wrap { display: flex; flex-direction: column; height: calc(100vh - var(--nav-h)); }
.ws-wrap > .ws { flex: 1; min-height: 0; height: auto; }

/* 顶栏正中间的上下文条（作业/比赛/题单，2026-10-15 二次收敛）：只留「类型·状态徽章 + 返回」。
   场内进度「第 N/M 题」挪到工作台切换行（.ph-nav 里嵌在上一题/下一题中间）；
   跳转下拉按用户钦定删除——切题走上一题/下一题，低频跳题回场次详情页；
   完整标题+截止仍在徽章 hover title 里。定位双档：宽屏(≥1441)绝对定位真居中；
   窄屏 flex 流内居中——绝对居中在左右两栏宽度悬殊时会压到导航词（1200 老师号实测撞 62px），
   流内居中永不重叠。空中间条（无 tid 普通题页）两种模式都不可见。 */
.topbar-inner { position: relative; }
.topbar-center {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  font-size: 13px;
}
.topbar-center .ctx-badge { cursor: help; max-width: 30vw; overflow: hidden; text-overflow: ellipsis; }
.topbar-center .ctx-back { flex: none; padding-block: 3px; }
@media (min-width: 1441px) {
  .topbar-center {
    position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
    flex: none; max-width: 40vw;
  }
}
/* 中间条收窄后降级只剩三档：≤1040 藏时钟 → ≤1000 藏返回（底部 tabbar/导航有入口）→ ≤820 整条不放 */
@media (max-width: 1040px) { .topbar-clock { display: none; } }
@media (max-width: 1000px) { .topbar-center .ctx-back { display: none; } }
@media (max-width: 820px) { .topbar-center { display: none; } }

.dd-item { overflow: hidden; text-overflow: ellipsis; }
/* 上一题/下一题：无上/下一题时置灰不可点 */
.pn-link.off { color: var(--text-3); opacity: .45; pointer-events: none; }
/* 场内进度（第 N/M 题，2026-10-15 从顶栏挪来）：嵌在工作台切换行上一题/下一题中间，
   与切换组成「‹ 第 1/4 题 ›」；hover 说明跳题去场次详情页 */
.ph-nav .ctx-pos { font-family: var(--mono); font-size: 12.5px; font-variant-numeric: tabular-nums;
  color: var(--text-2); white-space: nowrap; padding: 4px 2px; cursor: help; }

/* 老师后台「分组」页：分组卡片 = 成员 chips + 可展开的成员选择器 */
.group-edit { margin-bottom: 12px; }
.group-edit .gc-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px 8px; }
.group-edit .gc-head .spacer { flex: 1; }
.group-edit .gc-head h3 { font-size: 15px; margin: 0; }
/* 手机宽度：一行装不下「标题+人数+层级标注+三枚钮」，允许换行 —— 不换行时 flex 会把
   中文名挤到 min-content（一列一个字，2026-10-11 390px 实测，加了「← 父分组」标注后更挤）。 */
@media (max-width: 720px) {
  .group-edit .gc-head { flex-wrap: wrap; row-gap: 4px; }
}
.ge-chips { padding: 0 16px 12px; }
.ge-picker { padding: 0 16px 12px; border-top: 1px dashed var(--border); margin-top: 4px; padding-top: 10px; }

/* ---------- 分组页：子分组**嵌套**在父组卡里（2026-09-26 用户：「并列很怪、没有层次感」） ----------
   一张卡 = 一个顶层分组；卡内 `.gs-node` 是本组、`.gs-kids` 是它下面那一层（左侧竖线 + 缩进），
   子子分组再套一层 .gs-node… 层数靠 h3 字号与左侧竖线一起区分。 */
.gs-node { display: block; }
.gs-kids { margin: 2px 0 6px 20px; padding-left: 14px; border-left: 2px solid var(--border); }
.gs-kids:empty { display: none; }
.gs-node .gs-node .gc-head { padding: 9px 16px 6px 0; }
.gs-node .gs-node .gc-head h3 { font-size: 14px; }
.gs-node .gs-node .gs-node .gc-head h3 { font-size: 13.5px; }
.gs-node .gs-node .ge-chips { padding: 0 16px 8px 0; }
/* 一级子分组那行：把「本组直属、不在下级分组里」的人单独标出来（他们看得见本组与所有上级的东西） */
.gs-label { padding: 0 16px 6px; font-size: 12.5px; font-weight: 600; color: var(--text-2); }
.gs-label .muted { font-weight: 400; margin-left: 6px; }
.gs-node .gs-node .gs-label { padding-left: 0; }
/* 就地展开的「新建子分组」表单：虚线框、贴着本组的位置 */
.ge-newkid { margin: 6px 0 10px; padding: 12px 14px; border: 1px dashed var(--border-strong);
  border-radius: var(--r); background: var(--surface-2); }
.ge-newkid .nk-head { display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600;
  color: var(--text-2); margin-bottom: 10px; }
.ge-newkid .field { margin-bottom: 10px; }

/* 团队页：按分组筛选的 chip 行 + 成员表的「所在分组」列 */
.filter-chips { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.fchip {
  padding: 4px 12px; border-radius: 999px; font-size: 12.5px; cursor: pointer; font-family: inherit;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-2); transition: all .14s;
}
.fchip:hover { border-color: var(--brand); color: var(--brand); }
.fchip.on { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 600; }
/* 表格里的「所在分组」格：flex 必须套在内层 span 上，**不能设在 td 上** ——
   td 一旦变成 flex 容器就不再是 table-cell，不参与行高拉伸，
   它的下边框会比整行高出十几像素，横线就在这一列断开（用户 2026-09-24 圈出来的）。 */
.gp-cell .gp-wrap { display: inline-flex; align-items: center; gap: 5px; flex-wrap: wrap; }

/* 题单页：J/S 组分区标题 */
.cat-group-title { font-size: 16px; font-weight: 800; margin: 26px 0 10px; letter-spacing: .02em; }
.cat-group-title:first-child { margin-top: 0; }
.cat-sub { font-size: 13px; font-weight: 600; color: var(--brand); margin: 14px 0 8px; }
.cat-sub .muted { font-weight: 400; }

/* ---------- 12) 老师后台（P4） ---------- */
.admin-tabs { margin-bottom: 16px; }
.admin-tabs .tab { text-decoration: none; }
.adm-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 12px; }
.adm-card { display: block; padding: 15px 17px; border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); box-shadow: var(--sh-1); color: var(--text); }
.adm-card:hover { border-color: var(--brand); box-shadow: var(--sh-2); }
/* 概览统计卡：原来 minmax(170px) 在 1040 宽下每行只放 5 张，第 6 张「提交」孤零零换行。
   收到 148px 后 6 张正好一排；卡片也收紧一点（用户要求美化概览）。 */
.adm-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(146px, 1fr)); gap: 12px; }
.adm-stats .adm-card { padding: 14px 16px; }
.adm-stats .adm-k { font-size: 12px; }
.adm-stats .adm-v { font-size: 24px; margin: 4px 0 0; }
.adm-k { font-size: 12.5px; color: var(--text-3); }
.adm-v { font-size: 26px; font-weight: 650; letter-spacing: -.02em; margin: 2px 0 4px; }
.adm-form { max-width: none; }               /* 曾经限 900px：宽屏下右侧一大片空白 */
/* 字段网格：宽屏自动 2~3 列、中屏 2 列、窄屏 1 列；.field.full 占整行（分节编辑器/勾选列表用） */
.adm-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 340px)); gap: 16px 22px; justify-content: start; }
.adm-grid > .field { margin-bottom: 0; min-width: 0; }
.adm-grid > .field.full { grid-column: 1 / -1; }
.adm-form .field { margin-bottom: 14px; }
.form-row { display: flex; gap: 14px; flex-wrap: wrap; }
.form-row .field { flex: 1; min-width: 180px; }
.adm-actions { display: flex; align-items: center; gap: 12px; margin-top: 18px; }
.picker { border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2); padding: 12px; }
.pk-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.pk-bar .input { flex: 1; min-width: 200px; }
.pk-list { max-height: 320px; overflow: auto; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface); }
.pk-item { display: flex; align-items: center; gap: 9px; padding: 7px 11px; border-bottom: 1px solid var(--border); font-size: 13px; cursor: pointer; transition: background .13s; }
.pk-item:last-child { border-bottom: 0; }
.pk-item:hover { background: var(--surface-2); }
/* 复选框全站自绘（appearance:none）：圆角方框灰边，勾选 = 品牌底 + 白勾；
   挂在全局而不是某个容器上——管分组、选题器、以及将来任何地方的新勾选框都自动长这样 */
input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  margin: 0; width: 17px; height: 17px; flex: none;
  border: 1.5px solid var(--border-strong); border-radius: 5px;
  background: var(--surface); cursor: pointer;
  display: grid; place-items: center; transition: all .14s;
  vertical-align: -3px;
}
input[type="checkbox"]:hover { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
input[type="checkbox"]:checked { background: var(--brand); border-color: var(--brand); }
input[type="checkbox"]:checked::after {
  content: ""; width: 10px; height: 10px;
  background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><path d="M2.2 6.6 4.9 9.2 9.9 3.4" fill="none" stroke="white" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>') center/contain no-repeat;
}
input[type="checkbox"]:disabled { opacity: .35; cursor: not-allowed; box-shadow: none; }
.pk-item:has(input:checked) { background: color-mix(in srgb, var(--brand-soft) 55%, transparent); }
.pk-item:has(input:checked):hover { background: var(--brand-soft); }
/* 作业/比赛详情：分节小标题（没有分节的作业不出现） */
/* 作业/比赛里的分节展示（2026-09-25 美化；只此一处用 .ct-sec，题单页那边是「一节一张卡」）：
   原来是整条品牌色底的横带，又宽又吵、跟行抢注意力。现在是一条安静的分节头——
   左侧一根小竖条 + 节名 + 右侧题数，节与节之间用一条细线分开。 */
.ct-sec { display: flex; align-items: center; gap: 8px; padding: 15px 18px 6px; }
.ct-sec::before { content: ""; width: 3px; height: 13px; border-radius: 2px; background: var(--brand); flex: none; }
.ct-sec .sec-t { font-size: 13px; font-weight: 600; color: var(--text-1); }
.ct-sec .sec-n { margin-left: auto; font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.ct-sec:not(:first-child) { border-top: 1px solid var(--border); margin-top: 10px; }
/* 行首字母装进小方块、行高略放大，悬停时左侧亮一条品牌色细线（与题库页 .prow:hover 同一套观感）。
   注意：栅格列宽归下面 `.detail-page .prob-row` 管（那条更靠后、同权重），这里只调间距与内距。 */
.prob-row.ct-prob { gap: 12px; padding: 9px 18px; }
.ct-prob .idx { width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 6px; background: var(--surface-2); border: 1px solid var(--border);
  font-size: 11.5px; font-weight: 600; color: var(--text-2); }
.prob-row.ct-prob:hover { box-shadow: inset 2px 0 0 var(--brand); }
.pk-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pk-manual { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.pk-manual .input { flex: 1; }

/* ---------- 13) 力扣式题目展示（示例卡片 / 难度 pill / 测试用例标签页） ---------- */
.problem-head h1 { font-size: 21px; }
.ph-no { color: var(--text-3); font-weight: 600; }
.ph-chips { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.ph-chips svg { width: 13px; height: 13px; vertical-align: -2px; }
.diff { font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 99px; }
.diff-easy { color: var(--ac); background: var(--ac-soft); }
.diff-medium { color: var(--warn); background: var(--warn-soft); }
.diff-hard, .diff-none { color: var(--text-2); background: var(--surface-3); }

/* 示例卡片：一张卡里「输入 / 输出」并排两个独立代码块（窄屏叠放）；块头是窄条标签行 */
.statement .sample { margin: 14px 0; }
/* 样例卡字号全部跟题面字号等比缩放（2026-10-14 用户：题面字号一大，样例还是小字，
   比例失调）——默认 15px 时 0.8/0.87 恰好还原旧的 12/13，调大调小全程同呼吸。
   「样例 N」内嵌大标题已废除（2026-10-14 用户统一：多样例=页签按钮，单样例=无标题直铺） */
/* 样例页签（2026-10-14 用户：多样例时「样例 N」不当大字标题，改成小按钮切换）——
   按钮字号固定 12.5px，刻意不随题面字号缩放（用户原话「不需要把字体变大」）；
   文字不可拖选（user-select:none，2026-10-14 用户）；选中态=浅品牌底+品牌字
   （2026-10-14 用户：蓝底白字大色块与主题不搭，改成站内图标章/选中芯片同款静音强调） */
.sample-tabs { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.sample-tab { padding: 4px 13px; font-size: 12.5px; font-weight: 600; font-family: inherit;
  color: var(--text-2); background: var(--surface-3); border: 1px solid var(--border);
  border-radius: 999px; cursor: pointer; user-select: none; -webkit-user-select: none;
  transition: color .14s, border-color .14s, background .14s; }
.sample-tab:hover { color: var(--brand); border-color: var(--brand); }
.sample-tab.on { color: var(--brand); background: var(--brand-soft);
  border-color: color-mix(in srgb, var(--brand) 45%, transparent); }
.sample-pane > p:last-child { margin-bottom: 0; }
.sample-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; }
.sample-io { border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2); overflow: hidden; }
.sample-io-h .copy-btn { position: static; }
.sample-io-h { display: flex; align-items: center; justify-content: space-between;
  padding: 5px 12px; font-size: calc(var(--fs-statement, 15px) * 0.8); font-weight: 550; color: var(--text-3);
  background: color-mix(in srgb, var(--text) 4%, transparent); border-bottom: 1px solid var(--border); }
.sample-code { margin: 0; padding: 9px 12px 11px; font-family: var(--mono); font-size: calc(var(--fs-statement, 15px) * 0.87); line-height: 1.7;
  white-space: pre; overflow-x: auto; background: none; }
/* .statement pre 自带的边框/圆角会漏进来（块内多出一条线）；
   它是「类+元素」两级优先级，必须用 .statement .sample-code（0,2,0）才压得住 */
.statement .sample-code { border: 0; border-radius: 0; }
.sl-k { color: var(--text-3); flex: none; }
/* 大样例附件下载钮（题面「见附件中的 xxx」的示例框，2026-10-11 用户要求）：
   与代码框同框同高观感；未收录=禁用态说明（文件就位后服务端自动点亮成下载钮） */
.sample-att { display: flex; align-items: center; gap: 8px; padding: 12px;
  color: var(--brand); text-decoration: none; transition: background .14s; }
.sample-att svg { flex: none; }
.sample-att .mono { font-family: var(--mono); font-size: 12.5px; word-break: break-all; }
.sample-att i { font-style: normal; font-size: 12px; color: var(--text-3);
  border: 1px solid var(--border); border-radius: 999px; padding: 1px 8px; flex: none; }
.sample-att:hover { background: color-mix(in srgb, var(--brand) 8%, transparent); }
.sample-att:hover i { border-color: var(--brand); color: var(--brand); }
.sample-att.miss { color: var(--text-3); cursor: default; }
.sample-att.miss:hover { background: none; }

/* 测试用例 / 测试结果 两个标签 + Case 标签页 */
.run-tabs { display: flex; gap: 4px; }
.rtab { background: none; border: 0; color: var(--text-2); font-size: 13px; padding: 6px 10px; border-radius: var(--r-sm); cursor: pointer; }
.rtab:hover { background: var(--surface-2); }
.rtab.on { color: var(--text); background: var(--surface-3); font-weight: 600; }
.run-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.case-tabs { display: flex; align-items: center; gap: 6px; padding: 8px 14px 0; flex-wrap: wrap; flex: none; }
.ctab { background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; padding: 6px 14px;
  font-size: 12.5px; color: var(--text-2); cursor: pointer; transition: border-color .13s, color .13s, background .13s; }
.ctab:hover { color: var(--text); border-color: var(--border-strong); }
.ctab.on { border-color: var(--brand); color: var(--brand); background: var(--brand-soft); font-weight: 600; }
.ctab-add { padding: 6px 12px; border-radius: 999px; }
/* （用例结果改用标签底色表示，.ct-dot 已不用） */
.run-results { flex: 1; min-height: 0; padding: 12px 14px; overflow: auto; }
.res-sum { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; font-size: 13px; }
.res-row { border: 1px solid var(--border); border-radius: var(--r-sm); margin-bottom: 10px; overflow: hidden; }
.res-row.cur { border-color: var(--brand); }
.res-head { display: flex; align-items: center; gap: 10px; padding: 8px 12px; background: var(--surface-2); border-bottom: 1px solid var(--border); font-size: 13px; }
.res-cols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.res-cols > div { padding: 10px 12px; min-width: 0; border-right: 1px solid var(--border); }
.res-cols > div:last-child { border-right: 0; }
.res-cols pre { margin: 4px 0 0; font-family: var(--mono); font-size: 12px; white-space: pre-wrap; word-break: break-word; color: var(--text); }
@media (max-width: 900px) {
  .res-cols { grid-template-columns: 1fr; }
  .res-cols > div { border-right: 0; border-bottom: 1px solid var(--border); }
}

/* ---------- 14) 测试区：拖拽调高 / 运行中态 / 折叠（2026-09-22 用户指定） ---------- */
/* .badge-mute 在多个页面用到但一直没样式（只有 -muted），补上 */
.badge-mute { background: var(--surface-3); color: var(--text-3); }

/* 面板顶部那条拖动线：上拖变高，拖到底部折叠，折叠后再上拖展开 */
.run-resize { flex: none; height: 7px; margin-top: -4px; cursor: row-resize; position: relative; }
.run-resize::after {
  content: ""; position: absolute; left: 50%; top: 2px; transform: translateX(-50%);
  width: 46px; height: 3px; border-radius: 99px; background: var(--border-strong); transition: background .15s, width .15s;
}
.run-resize:hover::after { background: var(--brand); width: 70px; }
body.resizing-v { cursor: row-resize; user-select: none; }
.run-panel.collapsed { height: auto; }
.run-panel.collapsed .run-body { display: none; }

/* 用例标签上的三种点：灰=跑着、绿=通过、红=不通过 */
@keyframes ctpulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

/* 结果区：运行中的占位 */
.res-wait { display: flex; align-items: center; gap: 8px; padding: 16px 12px; color: var(--text-2); font-size: 13px; }
.res-wait::before {
  content: ""; width: 13px; height: 13px; border-radius: 50%;
  border: 2px solid var(--border-strong); border-top-color: var(--brand); animation: ctspin .8s linear infinite;
}
@keyframes ctspin { to { transform: rotate(360deg); } }

/* ---------- 15) 题面小标题图标 + 自绘下拉 ---------- */
.statement h2.h-ic, .statement h3.h-ic { display: flex; align-items: center; gap: 8px; }
.h-ic-glyph { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px;
  border-radius: 7px; background: var(--brand-soft); color: var(--brand); flex: none; }
.statement h3.h-ic { font-size: 14px; margin: 18px 0 6px; }

/* 题面分块卡（2026-10-14 用户「一块一块的展示」）：题目描述/输入格式/输出格式/样例/数据范围各一张卡，
   标题栏 + 正文两段式；库里数据不动，纯 lib/md.mjs blockifyStatement 展示层改造。 */
.statement .stmt-sec { background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-lg); margin: 0 0 14px; overflow: hidden; }
.statement > .stmt-sec:first-child { margin-top: 0; }
.statement .stmt-sec:last-child { margin-bottom: 0; }
.statement .stmt-sec-h { padding: 9px 16px 8px; border-bottom: 1px solid var(--border); background: var(--surface-3); }
.statement .stmt-sec-h h2 { margin: 0; font-size: 14.5px; font-weight: 600; padding: 0; }
.statement .stmt-sec-b { padding: 13px 16px 14px; }
.statement .stmt-sec-b > :first-child { margin-top: 0; }
.statement .stmt-sec-b > :last-child { margin-bottom: 0; }
.statement .stmt-sec-b > h2 { font-size: 15px; margin: 22px 0 8px; }   /* 块内罕见的二级标题 */

/* 自绘下拉：原生 <select> 的弹层由浏览器画，没法配色（用户嫌丑），这里换成按钮 + 浮层 */
.dd { position: relative; flex: none; }
/* 全站统一：自绘下拉的尺寸规格（新地方要用下拉请复用 .dd / .dd-btn / .dd-menu / .dd-item） */
.dd-btn { display: inline-flex; align-items: center; justify-content: space-between; gap: 10px;
  min-height: 36px; padding: 7px 12px; font-size: 13.5px; cursor: pointer;
  border: 1px solid var(--border-strong); border-radius: 8px; background: var(--surface); color: var(--text);
  transition: border-color .15s, box-shadow .15s; }
.dd-btn:hover { border-color: var(--brand); background: var(--surface-2); }
.dd-btn .dd-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-btn .dd-caret { color: var(--text-2); flex: none; transition: transform .15s; width: 16px; height: 16px; }
.dd.open .dd-btn { border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 16%, transparent); }
.dd.open .dd-caret { transform: rotate(180deg); }
.dd-menu { position: absolute; z-index: 40; top: calc(100% + 6px); left: 0; min-width: 100%;
  background: var(--surface); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--sh-2);
  padding: 6px; display: none; max-height: 340px; overflow: auto; }
.dd.open .dd-menu { display: block; }
.dd-item { display: block; width: 100%; text-align: left; padding: 9px 12px; font-size: 13.5px; border: 0; background: none;
  color: var(--text); border-radius: 7px; cursor: pointer; white-space: nowrap; }
.dd-item:hover { background: var(--surface-2); }
.dd-item.on { background: var(--brand-soft); color: var(--brand); font-weight: 600; }

/* ---------- 16) 提交详情页 ---------- */
.rec-meta { display: flex; gap: 26px; flex-wrap: wrap; font-size: 13px; margin-bottom: 14px; }
.rec-meta .sl-k { color: var(--text-3); margin-right: 6px; }
.rec-blk-t { font-size: 13px; font-weight: 600; margin-bottom: 8px; }
.rec-code { padding: 0 0 4px; }
.cases-table td, .cases-table th { padding: 8px 16px; }
/* 题目页「我的提交」行整行可点 */
a.rec-row { text-decoration: none; color: inherit; }
a.rec-row:hover { background: var(--surface-2); }

/* ---------- 17) 细节对齐 / 用例底色 / 主题图标 / 像桌面应用的选区控制（2026-09-22 用户指定） ---------- */
/* 标签页里的图标与文字要垂直居中（原先 svg 跟文字基线不对齐，看着是歪的） */
.tab { display: inline-flex; align-items: center; gap: 6px; }
.tab svg { flex: none; }

/* 主题按钮：浅色时显示月亮（点它切到暗色），暗色时显示太阳——不用半黑半白那个看不懂的图标 */
.theme-btn .ic-sun, .theme-btn .ic-moon { display: inline-flex; align-items: center; }
.theme-btn .ic-sun { display: none; }
html[data-theme="dark"] .theme-btn .ic-sun { display: inline-flex; }
html[data-theme="dark"] .theme-btn .ic-moon { display: none; }
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) .theme-btn .ic-sun { display: inline-flex; }
  html:not([data-theme="light"]) .theme-btn .ic-moon { display: none; }
}

/* 用例标签用「底色」表示结果，不用小圆点 */
.ctab.ac { background: var(--ac-soft); border-color: color-mix(in srgb, var(--ac) 34%, transparent); color: var(--ac); }
.ctab.fail { background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 34%, transparent); color: var(--danger); }
.ctab.wait { background: var(--brand-soft); border-color: color-mix(in srgb, var(--brand) 30%, transparent); color: var(--brand);
  animation: ctpulse 1.2s ease-in-out infinite; }
.ctab.on { font-weight: 600; box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand) 40%, transparent); }

/* 像桌面软件那样：默认不许拖选，只有「该能复制的」区域例外——题面（含代码块与样例）、
   编辑器、输入框、测试结果的输出、编译/评测信息、提交详情里的代码 */
body { user-select: none; -webkit-user-select: none; }
.statement, .CodeMirror, textarea, input,
.res-cols, .res-wait, .msg, .rec-code, .rec-meta,
.cases td, .cases-table td {
  user-select: text; -webkit-user-select: text;
}
img, svg { -webkit-user-drag: none; }

/* ---------- 18) 题目头与样例细节（2026-09-22 用户指定） ---------- */
/* align-items:center 必须显式给：默认 stretch 会把纯文本子项（如 .ctx-pos「第 N/M 题」）
   拉到整行高、文字贴顶——旁边带内边距的链接居中、它独浮上去（2026-10-15 实测翻车） */
.ph-nav { display: inline-flex; align-items: center; gap: 8px; flex: none; }

/* 提交结果（并入测试面板的第三个标签） */
.sub-head { display: flex; align-items: center; gap: 10px; padding: 0 0 10px; font-size: 13px; flex-wrap: wrap; }
.sub-head .v { font-size: 15px; font-weight: 650; }
.run-results .cases { font-size: 12.5px; }
.run-results .cases td { padding: 6px 10px; }

/* 提交记录行：徽标即入口，去掉「查看代码」那列；整行内容垂直居中 */
.recs .rec-row, .rec-row { align-items: center; }
.recs a.rec-row .badge { cursor: pointer; transition: filter .15s; }
.recs a.rec-row:hover .badge { filter: brightness(1.06); }

/* 样例块：复制按钮浮在角上；标题行右侧放上一题/下一题 */
/* 复制按钮由 JS 放进 .sample-io-h（块头右侧），不需要额外定位 */
.ph-title-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; }
/* 标题优先占满整行并允许换行：窄栏时不再被右侧导航压成一字一行（踩过） */
/* 标题与操作同排省高度：给标题留 min-width（≈8 个字），放不下时整排导航换行——
   既不会把标题压成一字一行（踩过），也不会浪费一整行空间 */
.ph-title-row h1 {
  /* 不 grow：标题只占内容宽度，右侧操作才能与它同排；长标题自动收缩到 8em 后省略号 */
  flex: 0 1 auto; min-width: 8em; max-width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ph-title-row .ph-nav { flex: 0 0 auto; margin-left: auto; }
@media (max-width: 760px) { .ph-title-row { flex-wrap: wrap; } }

/* ---------- 19) 设置弹窗（字号 / 默认代码模板） ---------- */
.modal { position: fixed; inset: 0; z-index: 90; background: rgba(0,0,0,.45);
  display: grid; place-items: center; padding: 20px; }
.modal-card { width: 100%; max-width: 620px; max-height: 86vh; overflow: auto;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--sh-2); padding: 18px 20px 20px; }
.modal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.modal-head b { font-size: 16px; }
.set-sec { margin-bottom: 18px; }
.set-sec:last-child { margin-bottom: 4px; }
.set-title { font-size: 13px; font-weight: 600; margin-bottom: 10px; display: flex; align-items: baseline; gap: 8px; }
.set-row { display: flex; align-items: center; gap: 12px; margin: 10px 0; }
.set-row label { flex: none; width: 150px; font-size: 13px; color: var(--text-2); display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.set-row output { font-family: var(--mono); color: var(--brand); font-weight: 700; min-width: 52px; text-align: right; font-size: 14px; }
.set-font-row input[type="range"] { flex: 1; height: 6px; accent-color: var(--brand); cursor: pointer; }
.set-font-row { flex-wrap: nowrap; }

/* 设置弹窗（2026-09-24 美化）：滑杆两端标出范围、下面给一行跟着字号缩放的预览 */
.set-card { max-width: 520px; }
.set-font-row { display: flex; align-items: center; gap: 10px; margin: 4px 0 0; }
.set-font-row .set-fk { flex: none; width: 34px; font-size: 12.5px; color: var(--text-2); }
.set-font-row output { min-width: 56px; margin-left: auto; }
.set-tpl-tabs { display: flex; gap: 6px; margin-bottom: 8px; }
/* 代码模板框：**不自动换行**（2026-09-24 用户要求）——长行走横向滚动，代码该是几行就几行。
   `white-space: pre` 与标签上的 wrap="off" 双保险（有的引擎只认其中之一）。 */
.tpl-editor { width: 100%; box-sizing: border-box; font-family: var(--mono); font-size: var(--code-fs); line-height: 1.6;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text); resize: none; height: 220px;
  white-space: pre; overflow-x: auto; overflow-y: auto; }
.tpl-editor:focus { outline: none; border-color: var(--text-3); }
.set-actions { display: flex; align-items: center; gap: 12px; margin-top: 10px; }

/* ---------- 20) 应用内对话框与提示条（替代原生 confirm/alert） ---------- */
.dlg-card { max-width: 380px; padding: 20px 22px 18px; }
.dlg-title { font-size: 15.5px; font-weight: 650; margin-bottom: 8px; }
.dlg-msg { font-size: 13.5px; line-height: 1.7; color: var(--text-2); }
.dlg-msg .muted { color: var(--text-3); }
.dlg-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.btn-danger { background: var(--danger); color: #fff; }
.btn-danger:hover { background: color-mix(in srgb, var(--danger) 88%, #000); color: #fff; }

.toast { position: fixed; z-index: 120; left: 50%; bottom: 34px; transform: translate(-50%, 12px);
  background: var(--surface); color: var(--text); border: 1px solid var(--border); border-radius: var(--r);
  box-shadow: var(--sh-2); padding: 10px 16px; font-size: 13px; opacity: 0; transition: opacity .25s, transform .25s; }
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast-bad, .toast-fail { border-color: color-mix(in srgb, var(--danger) 40%, transparent); color: var(--danger); }

/* 用例标签上的删除 ×（只有自建用例有）；输入/预期输出的小复制按钮 */
.ct-x { display: inline-block; margin-left: 6px; margin-right: -3px; padding: 0 3px; border-radius: 4px;
  color: inherit; opacity: .55; font-size: 13px; line-height: 1; }
.ct-x:hover { opacity: 1; background: color-mix(in srgb, var(--danger) 18%, transparent); color: var(--danger); }
.copy-mini { background: none; border: 0; color: var(--text-3); font-size: 11.5px; cursor: pointer; padding: 1px 5px; border-radius: 4px; }
.copy-mini:hover { color: var(--brand); background: var(--surface-3); }
.run-label { cursor: default; }

/* ---------- 21) 题库页细节（悬浮搜索 / 分类栏内滚 / 行状态与导航） ---------- */
/* 搜索框悬浮：滚动题目时它钉在顶栏下方，题目列表从它底下穿过去 */
.toolbar {
  position: sticky; top: calc(var(--nav-h) + 14px); z-index: 30;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  box-shadow: var(--sh-1);
  padding: 12px 14px; margin-bottom: 12px;
  display: flex; align-items: center;
  /* min-height 由页面脚本按左侧第一个卡片实测写入，保证两栏顶行等高 */
}
.toolbar .search-wrap { max-width: none; }
/* 分类栏：固定在视口内、超出一屏就栏内滚动（不再把页面无限拉长） */
.rail { max-height: calc(100vh - var(--nav-h) - 40px); overflow-y: auto; overscroll-behavior: contain; padding-right: 2px; }
/* 上一题/下一题：纯文字导航，不再有悬停灰块（点击跳页后悬停态不一致，用户反馈过） */
.pn-link { color: var(--text-3); font-size: 13px; padding: 4px 6px; border-radius: 6px; flex: none; }
.pn-link:hover { color: var(--brand); }
/* 题目笔记：讨论流（列表）+ 发帖式编辑器（2026-09-24 二次改版，用户「笔记要像发讨论帖」） */
.note-bar { display: flex; align-items: center; gap: 8px; padding: 10px 2px; flex-wrap: wrap; }

/* 「写下你的笔记…」：一条假输入框，点开即写 —— 发帖入口就该长这样（原来是右上角一个按钮） */
.note-new { display: flex; align-items: center; gap: 10px; width: 100%; margin-bottom: 14px; padding: 11px 13px;
  font: inherit; font-size: 14px; text-align: left; color: var(--text-3); cursor: text;
  border: 1px solid var(--border); border-radius: var(--r); background: var(--surface);
  transition: border-color .15s, background .15s; }
.note-new:hover { border-color: color-mix(in srgb, var(--brand) 45%, var(--border)); background: var(--surface-2); }
.note-new:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.note-new-ph { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.note-count { font-size: 12.5px; color: var(--text-3); margin: 2px 2px 8px; }
/* 笔记列表的「按作者筛」那一行（2026-09-26）：左边自绘下拉（全部 / 我的 / 某个学生），右边「N / M 篇」。
   只有出现两位以上作者时才显示（一位作者时筛选没意义，直接给篇数那行）。 */
.note-sort { display: flex; align-items: center; gap: 8px; margin: 2px 2px 10px; }
.note-count-inline { font-size: 12.5px; color: var(--text-3); }

/* 讨论卡片 */
.note-card { position: relative; border: 1px solid var(--border); border-radius: var(--r); padding: 12px 14px;
  margin-bottom: 10px; background: var(--surface); cursor: pointer;
  transition: border-color .15s, background .15s, box-shadow .15s; }
.note-card:hover { border-color: color-mix(in srgb, var(--brand) 45%, var(--border)); background: var(--surface-2);
  box-shadow: var(--sh-1); }
.note-card:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.note-card.mine { border-left: 3px solid var(--brand); }
/* 右侧小箭头只在悬停时亮：暗示「整卡可点开」（键盘用户有 focus-visible 描边兜底） */
.note-card::after { content: ""; position: absolute; right: 15px; top: 50%; width: 7px; height: 7px;
  border-right: 1.6px solid var(--text-3); border-bottom: 1.6px solid var(--text-3);
  transform: translateY(-50%) rotate(-45deg); opacity: 0; transition: opacity .15s; }
.note-card:hover::after { opacity: .75; }

/* 「谁在说」：卡片头 / 编辑器头 / 单篇视图共用一套（原来只挂在 .note-head 下，
   单篇视图那处的 who-txt 是裸的，姓名和副标题挤成一行） */
.who-txt { display: flex; flex-direction: column; line-height: 1.35; min-width: 0; }
.who-name { font-weight: 600; display: inline-flex; align-items: center; gap: 6px; }
.who-sub { font-size: 12px; color: var(--text-3); }
.note-head { display: flex; align-items: center; gap: 9px; font-size: 13.5px; }
.note-me { font-style: normal; font-size: 11px; font-weight: 500; color: var(--brand);
  background: var(--brand-soft); border-radius: 999px; padding: 1px 7px; }
.note-acts { display: inline-flex; gap: 6px; flex: none; position: relative; z-index: 1; }
.note-excerpt { margin-top: 8px; padding-right: 18px; font-size: 13px; color: var(--text-2); line-height: 1.7;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow-wrap: anywhere; }
/* 笔记主题：列表卡片上的标题（卡片只显示主题，不再显示正文摘要——2026-09-25 用户要求） */
.note-title { margin-top: 7px; padding-right: 18px; font-size: 14px; font-weight: 600; color: var(--text-1);
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow-wrap: anywhere; }
/* 编辑器顶部的主题输入：单独一行放在写作区之上（不塞进 grid，免得撑坏 note-ed-body 的高度） */
.note-ed-title { padding: 9px 12px 0; }
.note-ed-title input { width: 100%; box-sizing: border-box; padding: 7px 10px; font: inherit; font-size: 14px;
  font-weight: 600; color: var(--text-1); background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 8px; }
.note-ed-title input::placeholder { font-weight: 400; color: var(--text-3); }
.note-ed-title input:focus { outline: none; border-color: var(--brand); }
.note-view-title { margin: 0 0 10px; font-size: 17px; font-weight: 600; color: var(--text-1); }
.note-view-who { display: inline-flex; align-items: center; gap: 9px; min-width: 0; }
/* 单篇视图：正文也装进一张卡（原来直接摊在页面上，跟列表卡片不是一套观感） */
.note-article { max-width: none; padding: 14px 16px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r); }

/* 编辑器：一整张卡（头 / 写作区 / 底栏），不再是两个各自带边框的盒子 */
.note-ed { border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); overflow: hidden; }
.note-ed-head { display: flex; align-items: center; gap: 9px; padding: 10px 12px; flex-wrap: wrap;
  font-size: 13.5px; background: var(--surface-2); border-bottom: 1px solid var(--border); }
.note-ed-head .spacer, .note-foot .spacer { flex: 1; }
/* 写作区：**永远单栏**（2026-09-24 用户钦定「预览不应该是边写边预览」——原来宽屏会左右分栏，
   长笔记的预览把下面的工具栏顶穿）。现在只有「写」和「预览」两种状态，用头部的分段钮切。
   两个关键点，少一个就又会被内容顶穿：
     ① `grid-template-rows: minmax(0, 1fr)` —— 行高锁死到容器高度；
     ② 面板 `min-height: 0` —— grid 项默认 `min-height:auto`，会被内容撑开、把行顶大，
        于是 `.note-prev` 的 `overflow:auto` 永远不触发（用户截图里预览盖住工具栏就是这个）。 */
.note-ed-body { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr);
  height: clamp(280px, calc(100vh - 380px), 620px); }
/* 桌面（≥761px）且正在编辑：整张卡**占满左侧工作区**（宽 + 高），高度恒定不长个儿 ——
   内容多了在写作区里自己滚，底部工具栏钉在卡底不随滚动消失（2026-09-25 用户要求）。
   移动端不进这套：`.ws` 在窄屏是 auto 高度，flex 撑高会塌，那边继续吃下面的固定高度。 */
@media (min-width: 761px) {
  .pane-body.notes-fill.editing { display: flex; flex-direction: column; overflow: hidden; padding: 14px 16px 16px; }
  .pane-body.notes-fill.editing > .note-ed { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .pane-body.notes-fill.editing > .note-ed > .note-ed-head,
  .pane-body.notes-fill.editing > .note-ed > .note-ed-title,
  .pane-body.notes-fill.editing > .note-ed > .note-foot { flex: none; }   /* 头/题/底栏不许被压扁 */
  .pane-body.notes-fill.editing .note-ed-body { flex: 1 1 auto; min-height: 0; height: auto; }
}
.note-src { position: relative; min-width: 0; min-height: 0; }
.note-src .CodeMirror { height: 100%; padding: 10px 2px 10px 8px; box-sizing: border-box;
  font-family: var(--mono); font-size: 13px; line-height: 1.75; background: none; }
.note-src .CodeMirror-scroll { padding-bottom: 10px; }
/* 空的时候给一句占位：CM5 要额外装 placeholder 插件，这儿用一层浮层，零依赖。
   `top: 14px` = .CodeMirror 上内边距 10 + .CodeMirror-lines 的 4；
   `left: 16px` = 左内边距 8 + 行内 4 = 12，**再往右让 4px**（光标宽 2px 停在 x=29，
   与占位文字齐平会「穿模」——2026-09-25 用户截图报的就是这个）。改这里要连着量光标位置。 */
.note-ph { position: absolute; top: 14px; left: 16px; right: 14px; color: var(--text-3); font-size: 13px;
  line-height: 1.75; pointer-events: none; }
.note-src.has-text .note-ph { display: none; }
.note-prev { display: none; min-width: 0; min-height: 0; overflow: auto; padding: 12px 16px; background: var(--surface-2); }
.note-prev .statement { max-width: none; overflow-wrap: anywhere; }
.note-prev .empty { padding: 0; }
/* 「预览」状态：换格子显示（写的那格藏起来，CodeMirror 不必销毁，切回来 refresh 一下即可） */
.note-ed-body.show-prev .note-src { display: none; }
.note-ed-body.show-prev .note-prev { display: block; }
.note-foot { display: flex; align-items: center; gap: 8px; padding: 8px 10px; flex-wrap: wrap;
  background: var(--surface-2); border-top: 1px solid var(--border); }
/* 分段切换（写 | 预览）：与「判题方式」同一套观感 —— 两个状态都摆出来，点哪格切哪格 */
.note-seg { display: inline-flex; flex: none; border: 1px solid var(--border); border-radius: 999px;
  overflow: hidden; background: var(--surface); }
.note-seg-btn { border: 0; background: none; padding: 5px 15px; font: inherit; font-size: 12.5px;
  line-height: 1.3; color: var(--text-3); cursor: pointer; white-space: nowrap;
  transition: background .13s, color .13s; }
.note-seg-btn + .note-seg-btn { border-left: 1px solid var(--border); }
.note-seg-btn:hover { color: var(--text); }
.note-seg-btn.on { background: var(--brand); color: #fff; font-weight: 600; }
/* 工具条：按钮多了（2026-09-25 加到 14 枚）必须允许换行 —— 窄栏/手机上排成两行，
   不然整条会顶出底栏、横向溢出（.note-foot 的 flex-wrap 管的是「项之间」，管不到这条内部）。
   `max-width: 100%` 是换行的前提：`flex: none` 让这条按 max-content 撑开（实测手机 511px > 卡 334px），
   不给宽度上限的话内部 flex-wrap 永远不会触发，右边的公式/图片钮直接被裁掉点不到（2026-09-25 实测）。 */
.note-tools { display: inline-flex; align-items: center; gap: 1px; padding: 2px; flex: none; flex-wrap: wrap;
  max-width: 100%; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface); }
.note-tool { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px;
  border: 0; border-radius: 6px; background: none; color: var(--text-2); cursor: pointer; padding: 0; }
.note-tool:hover { background: var(--surface-3); color: var(--text); }
.note-tool:focus-visible { outline: 2px solid var(--brand); outline-offset: -1px; }
.note-tool svg { width: 16px; height: 16px; }
.note-tools-sep { width: 1px; height: 16px; background: var(--border); margin: 0 3px; }
/* 公开：勾选框保持全站样式不动，外壳包成一枚胶囊（勾上=品牌边+品牌字） */
.note-pub { display: inline-flex; align-items: center; gap: 6px; padding: 3px 11px 3px 8px;
  font-size: 13px; color: var(--text-2); cursor: pointer; white-space: nowrap;
  border: 1px solid var(--border); border-radius: 999px; background: var(--surface);
  transition: border-color .14s, color .14s; }
.note-pub:hover { border-color: var(--border-strong); }
.note-pub:has(input:checked) { border-color: var(--brand); color: var(--brand); font-weight: 600; }
/* 笔记/预览里的宽表格：横向可滚，别让窄栏把它剪掉 */
.md-scroll-x { max-width: 100%; overflow-x: auto; }
.note-md img { max-width: 100%; border-radius: var(--r-sm); border: 1px solid var(--border); }

/* 题解页 */
.sol-wrap { padding: 4px 0 10px; }
.sol-wrap .CodeMirror { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm); }
/* 多解法阶梯（真题题解：部分分档 → 满分档），一块一档 */
.sol-part { margin-bottom: 18px; }
.sol-part:last-child { margin-bottom: 4px; }
.sol-part-h { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; font-size: 13.5px; color: var(--text-2); }
.sol-part-h b { font-size: 14px; font-weight: 650; color: var(--text); }
.sol-badge { flex: none; padding: 2px 9px; border-radius: 999px; font-size: 12px; font-weight: 650;
  background: var(--surface-3); color: var(--text-2); border: 1px solid var(--border); }
/* 部分分档用青、满分档用绿：一眼看出这档能拿多少（深色主题跟着变量走） */
.sol-badge:not(.full):not(.ref) { background: var(--info-soft); border-color: color-mix(in srgb, var(--info) 35%, transparent); color: var(--info); }
.sol-badge.full { background: var(--ac-soft); border-color: color-mix(in srgb, var(--ac) 35%, transparent); color: var(--ac); }
.sol-sub { color: var(--text-3); }
/* 没做过就不画圈：空占位压缩掉 */
.mark:empty { display: none; }

/* 提交记录：徽标是按钮样式就该在列内居中（grid 默认拉伸会把胶囊拉宽、文字贴左，很难看） */
.recs .rec-row, a.rec-row { justify-items: center; }
.recs .rec-row .badge, a.rec-row .badge { justify-self: center; min-width: 86px; justify-content: center; }
.recs .rec-row .ttl, a.rec-row .ttl { justify-self: start; text-align: left; }

/* 提交结果头部：徽标 + chip 之间的间距 */
.sub-head .badge { font-size: 13px; padding: 3px 12px; }
.sub-head .chip { color: var(--text-2); }

/* ---------- 22) 老师视角：操作条 / 成绩单可点 / 学生账号 ---------- */
.head-right { display: inline-flex; align-items: center; gap: 8px; flex: none; }
.page-head { flex-wrap: wrap; }
/* 成绩单里的分数可点进代码 */
.score-link { color: inherit; border-bottom: 1px dashed color-mix(in srgb, currentColor 45%, transparent); }
.score-link:hover { color: var(--brand); border-bottom-color: var(--brand); }
/* 学生账号页：表格里的重置密码表单 */
.pw-form { display: flex; align-items: center; gap: 6px; }
.input-xs { width: 110px; padding: 5px 8px; font-size: 12.5px; }
/* 列表卡片等高：标题不同长也不参差 */
.list-grid, .ct-grid { align-items: stretch; }
.list-card, .ct-card { display: flex; flex-direction: column; height: 100%; }
.list-card .lc-desc, .ct-card .ct-meta { margin-top: auto; }
/* 题单/作业/比赛卡片里的进度条贴底 */
.list-card .lc-prog { margin-top: 10px; }

/* 提交记录行：标题列不再无限吞宽（1440 窗口下数值列被推得太散） */
.rec-row { max-width: 1180px; }
/* 老师视角的提交表：姓名列淡一点 */
.rec-row .muted.small { white-space: nowrap; }

/* 「提交记录」宽行（2026-09-27）：谁 / 状态 / 来源 / 分数 / 时间。
   题目页左栏只有 ~660px，八列放不下 —— 语言·耗时·内存让位（它们都在记录详情页里）。
   2026-10-11 #31：列宽改 **fr 比例**——固定 px 列在窄栏合计超出被 min-width:0 压缩的行盒时，
   时间列会溢出压到行外的「发到笔记」钮上（截图实测）；fr 按比例缩放永不溢出。
   加 min-width:0 防网格内容撑破，行内 gap 已由 .rec-row 的 10px 提供。 */
.rec-row-wide { grid-template-columns: 84fr 96fr 56fr 54fr 132fr; max-width: 100%; min-width: 0; }
.rec-row-wide > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.rec-row-wide .rec-who { color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rec-row-wide .rec-src { justify-self: start; font-size: 11.5px; line-height: 17px; color: var(--text-3);
  border: 1px solid var(--border-strong); border-radius: 999px; padding: 0 7px; white-space: nowrap; }
@media (max-width: 760px) {
  /* 手机上让「谁」占剩余宽度，来源/分数/时间收紧；徽标去掉 86px 的最小宽度（那是桌面口径） */
  .rec-row-wide { grid-template-columns: minmax(0, 1fr) 80px 46px 40px 58px; gap: 5px; font-size: 12px; }
  .rec-row-wide .badge { min-width: 0; padding: 2px 6px; font-size: 11px; }
  .rec-row-wide .rec-src { padding: 0 5px; font-size: 11px; }
}

/* ---------- 23) 错题本 ---------- */
.mkrow { grid-template-columns: 74px minmax(0, 1fr) 220px 110px 70px 90px 130px; }
.mkhead { grid-template-columns: 74px minmax(0, 1fr) 220px 110px 70px 90px 130px; font-size: 12px; color: var(--text-3); background: var(--surface-2); }
.mkhead .ttl, .mkhead .no { color: var(--text-3); }
.mklist .mkrow { align-items: center; }
.mkrow > span, .mkrow > a { min-width: 0; }

/* ---------- 24) 手机适配（窄屏 390px 实测有横向溢出，2026-09-22 修） ---------- */
@media (max-width: 760px) {
  /* 顶栏：导航横向滚动，不再把页面撑宽 */
  .topbar-inner { gap: 10px; padding: 0 12px; }
  .nav { overflow-x: auto; flex-wrap: nowrap; scrollbar-width: none; }
  .nav::-webkit-scrollbar { display: none; }
  .nav-link { white-space: nowrap; }

  /* 题库页：侧栏改成横滑条，别占满手机首屏 */
  .rail { position: static; max-height: none; flex-direction: row; overflow-x: auto; gap: 10px; padding-bottom: 6px; }
  .rail-group { flex: none; min-width: 190px; }
  .toolbar { position: static; min-height: 0 !important; padding: 10px 12px; }
  .prow { grid-template-columns: 26px 52px minmax(0, 1fr); gap: 8px; padding: 10px 12px; }
  /* 手机屏放不下：标签与通过率先藏。
     表头用的是 plh-* 类（.plhead .plh-tags/.plh-rate），只藏 .tags/.rate 会漏掉表头 —— 漏掉时
     表头还剩 6 格而数据行只剩 4 列，多出来的「通过率/难度」会掉到第二行，看着像表格错位（实测踩到）。 */
  .prow .tags, .prow .rate,
  .plhead .plh-tags, .plhead .plh-rate { display: none; }
  .mkrow, .mkhead { grid-template-columns: 46px minmax(0, 1fr) 84px; }
  .mkrow > *:nth-child(n+3), .mkhead > *:nth-child(n+3) { display: none; }

  /* 卡片类网格变单列 */
  .list-grid, .ct-grid, .adm-grid, .group-grid, .sample-grid { grid-template-columns: 1fr; }

  /* 提交记录（手机）：只留 状态 / 题目或分数 / 提交时间 —— 时间那一格只显示「时:分:秒」，
     日期由 .rec-date 藏掉（精确到秒在手机上也要看得见）。 */
  .rec-row { grid-template-columns: 92px 52px minmax(0, 1fr) !important; max-width: none; }
  /* 「我的提交」页那行第 2 格是**题目名**（不是分数），得让它占宽的那一列 */
  .rec-row.rec-subs { grid-template-columns: 92px minmax(0, 1fr) 78px !important; }
  .rec-row .rec-hide-sm { display: none; }
  .rec-row .rec-date { display: none; }

  /* 题目工作台：左右分栏在手机上叠成上下。
     ⚠ 编辑器必须有自己的固定高度：`.ws` 的高度是 auto，`.ed-body { flex:1 }` 在
     「父级高度由内容决定」时算出来是 0 → 整个编辑器只剩一行（2026-09-24 用户「代码都看不见了」）。
     60vh 给右侧，其中代码区独占约 55vh，自测面板保持自己的 clamp 高度。 */
  .ws { grid-template-columns: 1fr; height: auto; }
  /* 全屏编辑：手机上没列可归零（桌面那套是 `setSplit(0)`），直接把题面块整块藏掉；
     题面没了，「题目/代码」跳转条也一起收（留着是死链接观感）。 */
  .ws.fs .ws-left { display: none; }
  body.fs-on #ws-jump { display: none; }
  .ws-gutter { display: none; }
  .ws-left, .ws-right { border-right: 0; }
  .ws-right { border-top: 1px solid var(--border); height: auto; min-height: 0; }
  .ws-right .ed-body { flex: none; height: 55vh; }
  .ws-wrap { height: auto; }
  .statement { max-width: none; }
  .page-head { gap: 10px; }
  .table { font-size: 12.5px; }
  .table th, .table td { padding: 8px 10px; }
  .modal-card { max-height: 92vh; padding: 16px; }
}
@media (max-width: 760px) {
  /* 宽表格在手机里横滑，不要撑破页面（团队/学生名单实测会溢出 8px） */
  .card { overflow-x: auto; }
  .table { min-width: 460px; }
}

/* ---------- 25) 题库页应用式布局：只有列表滚，侧栏与搜索条钉死 ---------- */
/* 之前的 sticky 版本滚到页脚时会被"推走"（sticky 只能在容器内粘），用户看到侧栏/搜索条上滚。
   现在整页不滚（页面高度=视口），列表区自己滚 → 侧栏与搜索条在任何滚动位置都完全不动。 */
/* 中列 4px 是拖宽夹缝：按住左右拖调侧栏宽（--pl-w 由页面 JS 写入并记 localStorage） */
.pl-app { display: grid; grid-template-columns: var(--pl-w, 236px) 4px minmax(0, 1fr); gap: 0;
  height: calc(100vh - var(--nav-h)); padding: 16px 20px 0; box-sizing: border-box; overflow: hidden; }
.pl-app .rail { position: static; max-height: 100%; overflow-y: auto; padding-right: 2px; }
/* 侧栏外壳：两大页签（编程题/客观题）+ 原侧栏。页签切换时整侧内容替换。 */
.pl-side { min-height: 0; display: flex; flex-direction: column; min-width: 0; padding-right: 10px; box-sizing: border-box; }
.pl-side .rail { flex: 1; min-height: 0; }
/* 拖宽夹缝：平时几乎隐形，悬停/按住时亮起品牌色竖线 */
.pl-gutter { position: relative; cursor: col-resize; touch-action: none; }
.pl-gutter::before { content: ''; position: absolute; left: 50%; top: 6px; bottom: 6px; width: 2px;
  transform: translateX(-1px); border-radius: 1px; background: transparent; transition: background .13s; }
.pl-gutter:hover::before, .pl-gutter.dragging::before { background: var(--brand); opacity: .55; }
.pl-gutter.dragging::before { opacity: .9; }
/* 局部换血进行中：主列半透明锁点（换的是 .pl-side/.pl-main，侧栏滚动与展开不受影响） */
.pl-app.pl-loading .pl-main { opacity: .55; pointer-events: none; }
/* 目录树：可展开的分类/考级节点（details>summary），子项缩进 + 竖线轨 */
.rail-tree { display: flex; flex-direction: column; gap: 2px; }
details.rail-branch > summary { list-style: none; }
details.rail-branch > summary::-webkit-details-marker { display: none; }
details.rail-branch > summary.rail-item { cursor: pointer; user-select: none; }
/* summary 里是 caret / 标签 / 计数 三件套，space-between 会把标签挤到中间——标签自己吃掉富余宽度 */
details.rail-branch > summary.rail-item span:not(.n) { flex: 1; min-width: 0; text-align: left;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail-item .caret { flex: none; width: 0; height: 0; border-style: solid; border-width: 4px 0 4px 6px;
  border-color: transparent transparent transparent var(--text-3); transition: transform .14s; }
details[open] > summary .caret { transform: rotate(90deg); }
.rail-kids { margin: 2px 0 4px 14px; padding-left: 9px; border-left: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 1px; }
.rail-kids .rail-item { font-size: 12.5px; padding: 4px 7px; }
.pl-tabs { display: flex; gap: 6px; margin-bottom: 12px; }
.pl-tab { flex: 1; text-align: center; padding: 8px 0; border-radius: var(--r-sm);
  font-size: 13.5px; font-weight: 650; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border-strong); transition: background .13s, color .13s; }
.pl-tab:hover { color: var(--brand); }
.pl-tab.on { background: var(--brand-soft); border-color: var(--brand); color: var(--brand); }
.pl-main { min-width: 0; display: flex; flex-direction: column; min-height: 0; padding-left: 14px; box-sizing: border-box; }
.pl-main .toolbar { position: static; margin: 0 0 12px; padding: 10px 14px; min-height: 0; }
.pl-scroll { flex: 1; min-height: 0; overflow-y: auto; padding-bottom: 18px; }
.pl-scroll .plist { margin-bottom: 12px; }
.pl-scroll .pager { padding: 6px 0 10px; }
/* 当前筛选指示：点它即清除。位置固定在搜索条右侧 —— 用户报过「点了筛选但列表像是没变」，
   把生效中的筛选写在列表头上，比只靠侧栏高亮更不容易看走眼 */
.pl-sel { display: inline-flex; align-items: center; gap: 7px; margin-left: auto;
  padding: 4px 12px; border: 1px solid var(--brand); border-radius: 999px;
  background: var(--brand-soft); color: var(--brand); font-size: 12.5px; font-weight: 600;
  white-space: nowrap; max-width: 100%; overflow: hidden; }
/* 排序切换（2026-09-28）：名字 / 题号 两档，挂搜索条右侧、筛选指示左侧 */
.pl-sort { display: inline-flex; margin-left: auto; }
.pl-sel + .pl-sort, .pl-sort + .pl-sel { margin-left: 0; }
.pl-sort-opt { padding: 5px 11px; font-size: 12.5px; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border); text-decoration: none; }
.pl-sort-opt:first-child { border-radius: var(--r-sm) 0 0 var(--r-sm); }
.pl-sort-opt:last-child { border-radius: 0 var(--r-sm) var(--r-sm) 0; border-left: 0; }
.pl-sort-opt.on { background: var(--brand-soft); border-color: var(--brand); color: var(--brand); font-weight: 650; }

.pl-sel:hover { background: var(--brand); border-color: var(--brand); color: #fff; }
.pl-sel .pl-sel-x { flex: none; opacity: .75; }
.pl-sel:hover .pl-sel-x { opacity: 1; }

@media (max-width: 760px) {
  /* 手机上回到普通流式（页面可滚）；拖宽夹缝没有意义，隐藏 */
  .pl-app { display: block; height: auto; overflow: visible; padding: 12px; }
  .pl-app .rail { position: static; max-height: none; flex-direction: row; overflow-x: auto; }
  .pl-gutter { display: none; }
  .pl-side { padding-right: 0; }
  .pl-main { padding-left: 0; }
  .pl-scroll { overflow: visible; }
}
@media (max-width: 760px) {
  /* bare 外壳（.shell-full）在手机下要解锁高度，否则列表被裁掉 */
  .shell-full { height: auto; overflow: visible; }
}

/* ---------- 28) 手机适配二轮（390px 实测：题库侧栏霸屏 / 工作台标题一字一行） ---------- */
@media (max-width: 760px) {
  /* 工作台头部：标题独占一行正常换行，收藏/打印/翻页放第二行
     （原来 flex 不换行把 h1 压到 min-content，中文一字一行竖排） */
  .ph-title-row { flex-wrap: wrap; row-gap: 4px; }
  .problem-head h1 { flex: 1 1 100%; min-width: 0; font-size: 18px; white-space: normal; }
  .ph-nav { width: 100%; justify-content: flex-start; }
  .problem-head { padding: 14px 14px 10px; }

  /* 题库页：目录树（可折叠）在手机上回到纵向分组——折叠态本身紧凑，横滑列会把树挤成窄条 */
  .pl-app { padding: 10px 12px 0; }
  .pl-app .rail { flex-direction: column; overflow: visible; max-height: none; }
  .pl-app .rail .rail-group { max-height: none; overflow: visible; }
  .pl-main .toolbar { padding: 8px 2px; }
}

/* ---------- 26) 交互扫描后的整改（2026-09-22） ---------- */
/* ① 题目选择器每行用栅格分列：勾选框 / 题名 / 题号 / 标签，别再挤成一团 */
.pk-item { display: grid; grid-template-columns: 18px minmax(0, 1fr) 46px auto; align-items: center; gap: 10px; padding: 8px 12px; }
.pk-item .pk-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pk-item .mono { color: var(--text-3); font-size: 12px; text-align: right; }
.pk-item .chips-mini { display: flex; gap: 4px; }
.pk-item:hover { background: var(--surface-2); }
/* 判题方式（发作业/发比赛时每题一个）：「标准 | 文件」分段开关——两个状态都摆出来，
   点哪格设哪种，不用猜这个钮能不能点（用户反馈：单胶囊「标准」看着像静态标签，找不到入口）。
   行是 <label>，JS 里已拦掉冒泡。只有带开关的行才多一列（:has 精确命中），
   题单/加题目的选择器行不受影响 */
.pk-item:has(.pk-fio-grp) { grid-template-columns: 18px minmax(0, 1fr) 46px auto auto; }
/* 拖动排序的把手（2026-09-26 用户：「题目能不能支持拖动排序？」）：只有**真的带把手**的行才多一列，
   别的行（不存在的题号 / 学生选择器）栅格不动 —— 用 :has 精确命中，别改全局那条 */
.pk-item:has(.pk-grip) { grid-template-columns: 18px 18px minmax(0, 1fr) 46px auto; }
.pk-item:has(.pk-grip):has(.pk-fio-grp) { grid-template-columns: 18px 18px minmax(0, 1fr) 46px auto auto; }
.pk-grip { display: flex; align-items: center; justify-content: center; width: 18px; height: 22px; margin-left: -4px;
  color: var(--text-3); cursor: grab; touch-action: none; user-select: none; border-radius: 4px; }
.pk-grip:hover { color: var(--text); background: var(--surface-3); }
/* 拖动中的行：半透明 + 抬起感；列表加 .dragging 把光标也换成抓手 */
.pk-item.dragging { opacity: .55; background: var(--brand-soft); }
.pk-item.dragging .pk-grip { cursor: grabbing; }
.pk-list.dragging { cursor: grabbing; }
/* 判题方式三档（标准 / 文件 / 无限制，2026-09-26 起）。三枚按钮共享一个胶囊，内边距收到 8px
   才不至于把题目名挤窄（原来是两枚按钮的 10px）。 */
.pk-fio-grp { display: inline-flex; flex: none; border: 1px solid var(--border); border-radius: 999px;
  overflow: hidden; background: var(--surface-1); }
.pk-fio-seg { border: 0; background: none; padding: 4px 8px; font-size: 12px; line-height: 1.3;
  color: var(--text-3); cursor: pointer; transition: background .13s, color .13s; white-space: nowrap; }
.pk-fio-seg + .pk-fio-seg { border-left: 1px solid var(--border); }
.pk-fio-seg:hover { color: var(--text); }
/* 函数题行（2026-10-14）：不发三档开关——函数题=课程教学题专属，没有标准/文件判题方式；
   小签样式与页签按钮同语言（浅品牌底+品牌字），栅格与带开关的行同列数免得挤压 */
.pk-item:has(.pk-fn) { grid-template-columns: 18px minmax(0, 1fr) 46px auto auto; }
.pk-item:has(.pk-grip):has(.pk-fn) { grid-template-columns: 18px 18px minmax(0, 1fr) 46px auto auto; }
.pk-fn { display: inline-flex; flex: none; align-items: center; padding: 4px 10px; font-size: 12px; line-height: 1.3;
  color: var(--brand); background: var(--brand-soft); border: 1px solid color-mix(in srgb, var(--brand) 40%, transparent);
  border-radius: 999px; white-space: nowrap; user-select: none; }
.pk-fio-seg.on { background: var(--brand); color: #fff; font-weight: 600; }
.pk-fio-grp[data-f]:hover { border-color: var(--border-strong); }
/* 复选框的全站样式在前文「表单校验错误」前后的全局 input[type=checkbox] 规则里（accent-color 那套已废） */

/* ② 表单里的自绘下拉：撑满整列、与 .input 同高同观感 */
.dd-block { display: block; }
.dd-block .dd-btn { width: 100%; justify-content: space-between; padding: 8px 11px; font-size: 13px; }
.dd-block .dd-menu { width: 100%; }
.dd-block .dd-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 普通下拉（语言）保持紧凑 */
.dd .dd-btn .dd-label { white-space: nowrap; }

/* ③ 所有复选框/单选框都给手型（原来只有 cursor:default，勾选没提示） */
input[type=checkbox], input[type=radio], label:has(> input[type=checkbox]), label:has(> input[type=radio]) { cursor: pointer; }

/* 分节编辑块：卡片式容器 + 序号条（原来两块连在一起、删除按钮像纯文字） */
.node-edit { border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2);
  padding: 12px 14px 14px; margin-bottom: 12px; }

/* ---------- 加题目页：拖拽上传区 + 两栏布局 ---------- */
/* align-items 用 stretch：右栏（结构表 + yaml）比左栏高得多，让左栏跟着长高、
   拖拽区吃掉多出来的高度 —— 两栏底部对齐，拖拽热区也更大（原来左 385 / 右 751 差一半）。 */
.imp-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; align-items: stretch; }
/* 右栏原来只有 4fr（1040 下约 455px），格式表里的长路径被挤成三四行 —— 改成对半，右栏约 500px，路径一行放得下。 */
.imp-main { min-width: 0; display: flex; flex-direction: column; }
.imp-main .dropzone { flex: 1 1 auto; max-height: 560px; }
.dropzone {
  border: 2px dashed var(--border-strong); border-radius: var(--r); background: var(--surface-2);
  padding: 34px 20px; text-align: center; cursor: pointer; transition: all .16s;
  min-height: 300px; display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.dropzone:hover, .dropzone.drag { border-color: var(--brand); background: var(--brand-soft); }
.dropzone.drag .dz-ic { transform: translateY(-3px) scale(1.08); }
.dropzone.shake { animation: dz-shake .35s; border-color: var(--danger); }
@keyframes dz-shake { 20%, 60% { transform: translateX(-5px); } 40%, 80% { transform: translateX(5px); } }
.dropzone .dz-ic { color: var(--brand); display: inline-grid; place-items: center; transition: transform .16s; }
.dropzone .dz-t { font-size: 14.5px; font-weight: 600; margin: 8px 0 4px; }
.dropzone .dz-link { color: var(--brand); text-decoration: underline; text-underline-offset: 3px; }
.file-chip {
  display: flex; align-items: center; gap: 10px; margin-top: 12px;
  padding: 9px 12px; border: 1px solid var(--oj-line, var(--border)); border-radius: var(--r-sm);
  background: var(--surface); font-size: 13px;
}
.file-chip .fc-name { font-weight: 600; font-family: var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-chip button { margin-left: auto; flex: none; }
.imp-actions { display: flex; align-items: center; gap: 12px; margin-top: 14px; flex-wrap: wrap; }
.imp-result { margin-top: 16px; border: 1px solid var(--border); border-radius: var(--r-sm); padding: 12px 14px; background: var(--surface-2); }
.imp-result .ir-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.imp-result .ir-newest { font-size: 14px; margin: 6px 0; }
.imp-result .msg { max-height: 260px; overflow: auto; }
.imp-side { min-width: 0; }
.imp-side .fmt-block { max-height: 430px; overflow: auto; font-size: 12px; line-height: 1.65; }
@media (max-width: 1000px) { .imp-grid { grid-template-columns: 1fr; } }
/* 分节卡：左侧色条标出「这是第 N 节」，节号做徽章，删除收成低调图标按钮（每节都有大按钮太吵） */
.ne-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.ne-no { font-size: 11.5px; font-weight: 650; color: var(--brand); letter-spacing: .02em;
  background: var(--brand-soft); border: 1px solid color-mix(in srgb, var(--brand) 22%, transparent);
  border-radius: 999px; padding: 1px 9px; }
.ne-del { background: none; border-color: transparent; color: var(--text-3); margin-left: auto; }
.ne-del:hover { background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 35%, transparent); color: var(--danger); }
.node-edit { border-left: 3px solid color-mix(in srgb, var(--brand) 45%, var(--border)); }
.ne-head { margin-bottom: 8px; }
.node-edit .pk-list { max-height: 240px; }
.node-edit .pk-bar .input { flex: 1; }

/* ---------- 27) 老师后台视觉规范（照 Element UI 设计语言，保持零依赖） ---------- */
:root { --ctl-h: 34px; }

/* ① 控件统一规格：高度/圆角/边框/聚焦光晕全站一致（原来日期、下拉、文本框高矮不一） */
.adm-form .input,
.adm-form select.input,
.adm-form .dd-btn {
  height: var(--ctl-h); line-height: 1.4; padding: 0 12px; border-radius: var(--r-sm);
  border: 1px solid var(--border-strong); background: var(--surface); font-size: 13.5px;
  transition: border-color .15s, box-shadow .15s;
}
.adm-form .input:hover, .adm-form .dd-btn:hover { border-color: var(--text-3); }
.adm-form .input:focus, .adm-form .dd-btn:focus-visible {
  border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 14%, transparent); outline: none;
}
.adm-form input[type="date"], .adm-form input[type="time"] { padding-right: 8px; }

/* ② 表单分组标题（Element 的 section 感）：标题 + 一条细分隔线 */
.form-sec { display: flex; align-items: center; gap: 10px; margin: 24px 0 16px;
  font-size: 13px; font-weight: 600; color: var(--text-2); }
.form-sec::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.form-sec:first-child { margin-top: 4px; }

/* ③ 字段间距与标签规格 */
/* 落在 .adm-grid 里的字段，间距交给 grid 的 row-gap 管 —— 这里再给 margin-bottom 会和它叠加：
   实测「上一行输入框底边 → 下一行标签顶边」拉开到 48px（用户报「上下间距太大」）。
   所以 grid 内部的 margin 归零，只留 row-gap；不在 grid 里的字段仍用 14px。 */
.adm-form .field { margin-bottom: 14px; }
/* grid 内部的字段：上下外边距全归零 —— 基础规则 `.field { margin: 14px 0 }` 的**上**边距
   会和 grid 的 row-gap 再叠一层（48 = 14 + 18 + 16），所以这里整体清掉，只留 row-gap。 */
.adm-form .adm-grid > .field { margin: 0; }
.adm-form .field > label { font-size: 13px; font-weight: 500; color: var(--text-2); margin-bottom: 7px; }
.form-row { gap: 16px; }

/* ④ 卡片阴影更接近 Element 的轻浮起（原来是几乎无阴影的平铺） */
.adm-form.card { box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 2px 8px rgba(16, 24, 40, .05); }

/* ⑤ 表格：Element 风格表头 + 行高与悬停 + 首列吸顶感 */
/* 表头吸顶分两种情形，别混用：
   ① 整页滚动时 top:0 会被 56px 高的顶栏盖住（顶栏 z-index 40 > 表头 2）→ 让开一个 --nav-h；
   ② 表在自己的限高滚动容器里（.table-scroll）时要贴容器顶 → 回到 0（见第 29 节）。 */
.table th { background: var(--surface-3); color: var(--text-2); font-weight: 600; font-size: 12.5px; letter-spacing: .01em;
  position: sticky; top: var(--nav-h); z-index: 2; }
.table td { padding: 11px 16px; }
.table tbody tr:nth-child(even) td { background: color-mix(in srgb, var(--surface-2) 45%, transparent); }
.table tr:hover td { background: var(--brand-soft); }
/* 学生/成员行的圆形头像：按 uid 取色，扫一眼能区分人 */
.avatar-sm { width: 24px; height: 24px; font-size: 12px; }
.avatar-c0 { background: linear-gradient(135deg, #2b6df6, #6a5cf5); }
.avatar-c1 { background: linear-gradient(135deg, #0ea5a4, #2b8cd9); }
.avatar-c2 { background: linear-gradient(135deg, #d97706, #e0554f); }
.avatar-c3 { background: linear-gradient(135deg, #7c3aed, #c026d3); }
.avatar-c4 { background: linear-gradient(135deg, #059669, #65a30d); }
/* 后台表单卡：宽屏两栏（主表单 + 侧栏说明） */
.adm-split { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 18px; align-items: start; }
@media (max-width: 1100px) { .adm-split { grid-template-columns: 1fr; } }
/* 说明侧栏：可折叠（默认展开，点标题收起腾地方）；标题行带图标与折叠箭头 */
.adm-aside { font-size: 13px; color: var(--text-2); line-height: 1.75; }
.adm-aside > summary { cursor: pointer; font-size: 13.5px; font-weight: 600; color: var(--text);
  display: flex; align-items: center; gap: 6px; list-style: none; user-select: none; }
.adm-aside > summary::-webkit-details-marker { display: none; }
.adm-aside > summary::after { content: "▾"; margin-left: auto; color: var(--text-3); font-size: 12px; transition: transform .15s; }
.adm-aside[open] > summary::after { transform: rotate(180deg); }
.adm-aside > summary svg { color: var(--brand); }
.adm-aside ul { margin: 10px 0 0; padding-left: 18px; }
.adm-aside li { margin-bottom: 5px; }
.adm-aside b { color: var(--text); }
/* 勾选列表限高滚动：学生多了不把页面撑爆 */
.pk-list { max-height: 340px; overflow: auto; }
.pk-item .pk-title { white-space: nowrap; }

/* ⑥ 自绘下拉的浮层更像 Element 的 select-dropdown */
.dd-menu { padding: 6px; border-radius: var(--r); box-shadow: 0 6px 22px rgba(16, 24, 40, .13); }
.dd-item { border-radius: 6px; padding: 8px 12px; }

/* ⑦ 分节卡片：白底（原来灰底与表单底色糊在一起）、内部列表不再二次描边 */
.node-edit { background: var(--surface); }
.node-edit .pk-list { border-color: var(--border); background: var(--surface-2); }
.node-edit .ne-bar { padding-bottom: 8px; border-bottom: 1px dashed var(--border); }

/* ⑧ 后台 tab：Element tabs 风格（激活态浅底 + 下划线） */
.admin-tabs { border-bottom: 1px solid var(--border); gap: 6px; }
.admin-tabs .tab { border-radius: 6px 6px 0 0; padding: 9px 14px; }
.admin-tabs .tab.on { background: var(--brand-soft); border-bottom-color: var(--brand); }

/* 后台 Tab 图标与文字的间距（加图标后要对齐） */
.admin-tabs .tab svg { vertical-align: -3px; margin-right: 2px; }
.admin-tabs .tab { display: inline-flex; align-items: center; gap: 5px; }
/* 按钮里的图标统一基线 */
.btn svg { vertical-align: -3px; }

/* ---------- 27) 老师后台三页整改（2026-09-24 全页黑盒测试后） ---------- */

/* 学生账号：两张建号卡并排 —— 原来上下各占一屏，学生名单要滚两屏才露头 */
.adm-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); gap: 16px; align-items: start; }
.adm-two > form { min-width: 0; }

/* 学生勾选行：勾选框 / 头像 / 「姓名 + 账号·UID」两行块。
   原来姓名与 UID 各占一头（1fr + auto），卡片一宽中间就空一大段，整片很散。 */
.pk-item.pk-stu { grid-template-columns: 18px 24px minmax(0, 1fr); }
.pk-item.pk-stu .avatar { flex: none; }
.pk-item.pk-stu .who-txt { min-width: 0; }
.pk-item.pk-stu .who-name,
.pk-item.pk-stu .who-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 加题目：示例包按钮成组，题目包结构改表格（汉字双宽，字符画手工对齐永远对不齐） */
.imp-dl { display: flex; gap: 8px; flex-wrap: wrap; }
.fmt-wrap { border: 1px solid var(--border); border-radius: var(--r-sm); overflow-x: auto; }
.fmt-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.fmt-table th { text-align: left; font-weight: 500; color: var(--text-3); font-size: 11.5px;
  padding: 7px 10px; background: var(--surface-2); border-bottom: 1px solid var(--border); }
.fmt-table td { padding: 7px 10px; border-bottom: 1px solid var(--border); vertical-align: top; line-height: 1.65; }
.fmt-table tr:last-child td { border-bottom: 0; }
.fmt-table td:first-child { color: var(--text-2); }
.fmt-table code { font-family: var(--mono); font-size: 11.5px; background: var(--surface-3);
  border-radius: 4px; padding: 1px 4px; overflow-wrap: anywhere; }
/* 加题目右栏窄，格式表原来靠横向滚动才看得全 —— 改成换行，别再出左右拉条 */
.imp-side .fmt-block { max-height: 300px; }
.fmt-table { font-size: 12px; }
.fmt-table th, .fmt-table td { padding: 6px 9px; }

/* ---------- 28) 无障碍与窄屏补齐（2026-09-24，按 ui-ux-pro-max 检查表扫出来的） ---------- */

/* ① 尊重系统的「减少动态效果」。此前全站 24 处 transition + 拖拽区抖动动画都没有
      reduced-motion 分支，技能检查表把这条标 High。 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ② 自测输入框原来是 `outline: none` 且没有任何替代（技能原文反例：
      "Remove focus outline without replacement"）——键盘走到这里看不出焦点在哪。 */
.run-panel textarea:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--brand) 45%, transparent);
  outline-offset: 1px;
  border-color: var(--brand);
}

/* ③ Tab 条窄屏整条横滑，别再让中文标签被挤成竖排（375px 实测「概览」两字上下叠） */
.tabs { overflow-x: auto; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tabs > .tab { flex: none; white-space: nowrap; }

/* ④ 窄屏顶栏：品牌只留图标、用户名只留头像，把宽度让给主导航。
      实测 390/430px 时 .nav 被压成 0–29px —— 题库/题单/作业/比赛四个入口完全点不到，
      要到 560px 才勉强可用。收掉这两处文字后主导航重新可滚可点（顶栏高度不变，
      所以各页基于 --nav-h 的高度计算不受影响）。 */
@media (max-width: 560px) {
  .brand-name { display: none; }
  .user-btn .small { display: none; }
  .topbar-inner { gap: 8px; }
}

/* ④b 页面级横向兜底（2026-10-07 用户报「手机/iPad 页面会往左拉，而不是全屏」）：
   所有宽内容都应落在内部滚动容器里（.table-scroll/.tabs/CodeMirror/成绩单表格），
   页面本身永远不该横向滚——真机上「能往左拉一段」全是页面级溢出。用 clip 不用 hidden：
   clip 不产生滚动容器，position:sticky（日视图节头吸顶、工作台 tabs 行）照常工作；
   老引擎不认识这条就当没写（不会更坏）。 */
html, body { overflow-x: clip; }

/* ④c ≤370 小屏（iPhone SE 一类）顶栏再收一档：320px 实测 .user-btn 被顶出 15px。
   图标钮内边距 6→3、右组间距 8→4、左右留白 12→8，320 全部控件回屏内。 */
@media (max-width: 370px) {
  .topbar-inner { gap: 6px; padding: 0 8px; }
  .nav-right { gap: 4px; }
  .theme-btn { padding: 3px; }
  .user-btn { padding: 4px 2px; gap: 4px; }
}

/* ④d 详情页头右侧操作组窄屏允许换行（390 实测「导出成绩+家长链接+复制链接+关闭分享」
   一行放不下被顶出 4px）：家长链接输入框改可伸缩、按钮组自动分行。 */
@media (max-width: 760px) {
  .head-right { flex-wrap: wrap; max-width: 100%; row-gap: 6px; }
  .share-inline { flex-wrap: wrap; }
  .share-inline .input { flex: 1 1 120px; width: auto; max-width: none; }
}

/* ⑤ 老师后台两栏卡片在窄屏要退成单列；minmax(360px,…) 在 375px 屏上会撑破容器 */
@media (max-width: 620px) {
  .adm-two { grid-template-columns: 1fr; }
  .adm-grid { grid-template-columns: 1fr; }
  .adm-split { grid-template-columns: 1fr; }
  /* 标题条：说明文字掉到第二行，别把 h2 挤成「现有\n分组」两行 */
  .card-head { flex-wrap: wrap; row-gap: 6px; }
  .card-head h2 { flex: 1 1 auto; }
}

/* ---------- 29) 撑得住 100 个学生（2026-09-24 用户提问「学生会不会有 100 个」） ---------- */

/* 长表格（名单 / 成绩单 / 班级进度）限高：不限高时 100 个学生会撑出 6000px 的页面，
   而且外层 `overflow:auto` 没有高度 → 里面的 thead(position:sticky) 没有可粘的滚动容器，
   等于失效（实测滚到 1200px 时表头已在 -581px，早跑出屏幕）。
   限高之后表格自己滚、表头真正钉住，页面高度也回到一屏左右。 */
.table-scroll { max-height: min(62vh, 620px); overflow: auto; }
.table-scroll .table thead th { position: sticky; top: 0; z-index: 2; }

/* 保存条吸底：100 个学生时列表很长，「保存分组」原来会被顶到折叠线以下
   （实测 720px 视口里按钮在 y=767，勾完还要再滚一屏才点得到） */
.adm-actions-sticky {
  position: sticky; bottom: 0; z-index: 5;
  background: var(--surface); border-top: 1px solid var(--border);
  padding: 12px 0 4px; margin-top: 14px;
}

/* 勾选列表：10 人以内贴合内容，人多时才长到限高，别在小班上留一片空盒子 */
.pk-list.pk-grid { max-height: min(52vh, 520px); }

/* 搜索没命中时的提示（技能规则：No Results → 别留空白屏） */
.muted.is-empty { color: var(--danger); }

/* ---------- 30) 详情页 / 管理页：限宽 + 信息密度（2026-09-24 用户「太丑了」） ---------- */

/* 整页限宽并居中。原来所有东西摊在 1860px 上：标题在最左、状态徽标甩到最右
   （题单页实测：题名在 x=103、进度条在 x=1731，中间 1600px 全空）、
   成绩单的数字各自漂在一大片空单元格里、时间条和说明卡都只剩一行字。
   技能规则 Line Length：大屏不要铺满整宽（中文一行 30~40 字最舒服）。
   只在宽度：老师后台各页、详情页都用它，保证后台每个 tab 宽度一致。 */
/* 详情页专属的排版微调（题目行/分节进度条）单独放 .detail-page，别误伤后台概览里的题目行。 */
.narrow-page { max-width: 1040px; margin: 0 auto; }
.narrow-page .page-head { margin-bottom: 14px; }

/* 题目行：状态徽标跟在题名/标签后面，别再被 1fr 列推到上千像素之外。
   只改详情页的 .ct-prob / .li-prob，题单页与后台概览用的 .prob-row 默认布局不动。 */
.detail-page .prob-row { grid-template-columns: 56px minmax(0, auto) auto minmax(0, 1fr); }
/* 作业/比赛详情页的行：首列放的是「字母」（装进 22px 小方块），56px 太宽，收到 26px；
   题单详情页的首列放的是题号（j01265，要 56px），所以这条只认 .ct-prob，别外溢（2026-09-25）。 */
.detail-page .prob-row.ct-prob { grid-template-columns: 26px minmax(0, auto) auto minmax(0, 1fr); }
.detail-page .prob-row > .badge { justify-self: start; }
.detail-page .prob-row .ttl { min-width: 0; }
.detail-page .prob-row .ttl > a { overflow-wrap: anywhere; }
/* 分节头里的进度条原来靠 margin-left:auto 顶到最右（1600px 外），改成贴着数字走 */
.detail-page .node-head .bar { margin-left: 0; width: 160px; }

/* 成绩单：数字居中 + 列间竖线 —— 宽屏下才像一张成绩表，而不是几个数字漂在空里 */
.table.board th.num, .table.board td.num { text-align: center; border-left: 1px solid var(--border); }

/* ---------- 31) 学生名单重做（2026-09-24 用户「要重做」） ---------- */

/* 姓名 + 「账号 · UID」副行：把原来两个只放一个词的列并进一格 */
.who-txt { display: inline-flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.who-name { font-weight: 550; }
.who-sub { font-family: var(--mono); font-size: 11.5px; color: var(--text-3); }

/* 重置密码：原生 <details> 折叠（100 个学生时不塞 100 个常驻输入框，且不依赖 JS）。
   注意别把 summary 在展开时藏起来——那样就没有「收起」的入口了。展开后它留在原位，
   再点一次就收起，同时给个浅底表示「当前是它打开着」。 */
.stu-table .act-cell { width: 300px; }
.pw-reset > summary { list-style: none; display: inline-flex; cursor: pointer; }
.pw-reset > summary::-webkit-details-marker { display: none; }
.pw-reset[open] { display: flex; gap: 6px; align-items: center; flex-wrap: nowrap; }
.pw-reset[open] > summary { background: var(--surface-3); }
.pw-reset .pw-form { display: flex; gap: 6px; align-items: center; }
.pw-reset .input { max-width: 120px; }
/* ⑥ 学生勾选列表在宽屏排成多列卡片：一名学生占一整行 1740px、UID 甩到最右边，
      找一个人要横着扫完整个屏幕（40 人的班尤其难受）。窄屏保持单列不动。
      高度上限统一由上面第 29 节的 .pk-list.pk-grid 规则管，这里不重复设 max-height。 */
@media (min-width: 900px) {
  .pk-list.pk-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 6px; padding: 8px; }
  .pk-list.pk-grid .pk-item.pk-stu {
    border: 1px solid var(--border); border-bottom: 1px solid var(--border);
    border-radius: var(--r-sm); padding: 6px 10px;
  }
  .pk-list.pk-grid .pk-item.pk-stu:last-child { border-bottom: 1px solid var(--border); }
}

/* ---------- 32) 题库列表：标签紧跟标题（2026-09-24 用户「美化题库展示页」） ---------- */
/* 题目列原来是 1fr —— 1830px 窗口下它拿到 852px 去放一个 5 字标题，
   标签被推到 860px 之外，每行中间空出一整片。改成「标题按内容宽、标签列吃剩余」，
   标签紧跟标题，通过率/难度仍右对齐。 */
.prow .ttl { min-width: 0; }
.prow .tags { min-width: 0; }

/* ---------- 33) 列表页「可见范围」切换条 + 卡片收紧（2026-09-24 用户要求） ---------- */
/* 题单/作业/比赛列表顶部的范围切换：全部 / 官方（全站共享）/ 各分组 */
.scope-chip { padding: 4px 12px; border: 1px solid var(--border); border-radius: 999px;
  font-size: 12.5px; color: var(--text-2); background: var(--surface-2); }
.scope-chip:hover { border-color: var(--brand); color: var(--brand); }
.scope-chip.on { background: var(--brand-soft); border-color: var(--brand); color: var(--brand); font-weight: 600; }
/* 工具栏分组：状态 / 类型 / 视图 / 排序 各框成一个小胶囊，chip 多起来也不会糊成一片。
   组内的 chip 改成「挖空」观感（底色=页面色），选中的才亮起来 —— 一眼能看出有哪几组、
   每组选中了什么。（早先用竖线分隔 + 单独一枚「降序」chip 跟在「按名字」后面，
   看着像只控制名字，2026-09-25 用户反馈后改成「箭头长在当前键上」。） */
.ct-grp { display: inline-flex; gap: 5px; padding: 3px 5px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border); }
.ct-grp .scope-chip { background: var(--surface); border-color: transparent; }
.ct-grp .scope-chip.on { background: var(--brand-soft); border-color: var(--brand); }

/* 题单卡：原来给说明文字留死 34px 高（一行字也占两行），而说明又都是同一句模板生成的。
   现在没说明就不占位；有说明时按内容高走。 */
.list-card .lc-desc { min-height: 0; }

/* 卡片标题行：标题长时右侧徽标被挤成竖排（「未开/始」两行）——徽标不换行、不收缩，
   标题最多两行（超出省略），这样同一行的卡片高度也齐。 */
.list-card .lc-top, .ct-card .ct-top { align-items: flex-start; }
.list-card .lc-name, .ct-card .ct-name {
  flex: 1 1 auto; min-width: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; line-height: 1.35;
}
.list-card .lc-top > .chip, .list-card .lc-done,
.ct-card .ct-top > .badge, .ct-card .ct-top > .chip { flex: none; white-space: nowrap; }

/* ---------- 34) 作业/比赛列表：工具条（2026-09-24，用户「多起来很乱很难看」） ---------- */
/* 几十场排成一堵墙看不出结构 → 按月分区（复用 .cat-group-title）+ 搜索 + 类型筛选 */
.ct-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: -6px 0 16px; }
.ct-tools .input { max-width: 260px; }
.ct-tools .spacer { flex: 1; }
/* 课程工具条（2026-10-10 用户钦定）：搜索与「+ 新增题单」成组靠右、同高对齐；搜索框内嵌图标 */
.tb-search { position: relative; display: flex; align-items: center; }
.tb-search .tb-search-ic { position: absolute; left: 9px; width: 14px; height: 14px; color: var(--muted); pointer-events: none; }
.tb-search .input { padding-left: 28px; width: 210px; height: 30px; max-width: none; }
.ct-main .ct-right .btn, .ct-main .ct-right .scope-chip, .ct-main .ct-right .tb-search .input { height: 30px; }
.ct-main .ct-right .btn { display: inline-flex; align-items: center; }
/* 作业/比赛工具条右组（2026-10-10）：搜索 → 类型筛选 → 视图 → 排序指示 → 主按钮，逻辑组用细分隔线 */
.tb-sort { display: inline-flex; align-items: center; gap: 4px; color: var(--muted); font-size: 12.5px; padding: 0 4px; user-select: none; cursor: default; }
.ct-main .ct-right .btn-primary { margin-left: 4px; }
/* 状态筛选与类型筛选之间加一道分隔，别看成一组 */
.ct-tools .ct-sep { width: 1px; height: 18px; background: var(--border); margin: 0 2px; }

/* 类型小标「讲解 / 作业」（2026-09-25 起作业名只留主题，类型改由小标表达；列表/周/月历/详情共用）。
   尺寸**不另写一套**：标记里同时带 `.badge`，几何（padding/font-size/圆角）跟状态徽标完全一致 ——
   2026-09-25 用户报「作业、进行中、未开始 这几个按钮大小不统一」，根因就是这里自己写了 11px/3px 7px。 */
.ct-kind { flex: none; }
.ct-kind.k-talk { color: var(--brand); background: color-mix(in srgb, var(--brand) 14%, transparent); }
.ct-kind.k-hw { color: var(--warn); background: color-mix(in srgb, var(--warn) 16%, transparent); }
/* 月历格子只有 43px 宽，放不下两个字 → 用单字标记（讲/业），完整名字在 title 里 */
.cal-kind { font-style: normal; font-weight: 700; margin-right: 4px; }
.cal-kind.k-talk { color: var(--brand); }
.cal-kind.k-hw { color: var(--warn); }

/* ---------- 35) 作业/比赛的日历视图（2026-09-24 用户选「甲」） ---------- */
/* 每场只占一天（00:00~23:59），所以一格一天最直观：哪几天有课一眼看得出 */
.cal { margin-bottom: 8px; }
.cal-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.cal-head b { font-size: 15px; }
.cal-head .spacer { flex: 1; }
.cal-dow { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; margin-bottom: 6px; }
.cal-dow span { font-size: 11.5px; color: var(--text-3); text-align: center; }
.cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; }
.cal-cell { min-height: 84px; padding: 6px 7px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); display: flex; flex-direction: column; gap: 4px; overflow: hidden; }
.cal-cell.out { background: transparent; border-color: transparent; }
.cal-cell.out .cal-day { color: var(--text-3); opacity: .5; }
/* 周末淡底 + 今天描边（与周视图同一套语汇，两个视图看起来是一家的） */
.cal-cell.wk-end:not(.out) { background: color-mix(in srgb, var(--surface-2) 45%, transparent); }
.cal-cell.today:not(.out) { border-color: color-mix(in srgb, var(--brand) 45%, var(--border));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--brand) 30%, transparent); }
.cal-cell.today .cal-day { color: var(--brand); font-weight: 700; }
.cal-day { font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.cal-item { display: block; padding: 3px 7px; border-radius: 999px; font-size: 11.5px; line-height: 1.45;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background: var(--surface-3); color: var(--text-2); }
.cal-item:hover { color: var(--text); }
.cal-item.live { background: var(--ac-soft); color: var(--ac); font-weight: 600; }
.cal-item.soon { background: var(--brand-soft); color: var(--brand); }
.cal-item.done { background: var(--surface-2); color: var(--text-3); }
/* 一格里超过 3 条时收成一句「还有 N 场」（悬停看名字）：不然一天十几场会把这行撑到半个屏幕高 */
.cal-more { font-size: 10.5px; color: var(--text-3); padding: 1px 2px 0; }
@media (max-width: 900px) {
  .cal-cell { min-height: 68px; }
  .cal-item { font-size: 10.5px; padding: 2px 5px; }
}

/* ---------- 35b) 作业/比赛的**周视图**（2026-09-25 用户要「周视图」→ 三次迭代后的形态） ----------
   形态：**一天一行**（日期在左、当天条目在右横向排开）。为什么不做 7 列月历式：
   用户实测「横着摆有点挤、有点窄，下面还很多空白，信息比较密」—— 7 栏时每栏只有 ~250px、
   行高被最长的那天撑起来，其余栏底下全是空档；改成行之后每条都能用满宽度、行高跟着内容走。
   保留下来的是：周导航（‹ 第 N 周 › 回到本周）、今天整行高亮、类型小标（讲解/作业）、
   卡片底部的本周场次读数；空的那天留一条淡虚线（整周节奏看得出来，又不占地方）。 */
.week { margin-bottom: 8px; }
.wk-no { white-space: nowrap; font-size: 12px; color: var(--text-3); background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 999px; padding: 2px 9px; }
.wk-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--sh-1); overflow: hidden; }
.wk-rows { display: flex; flex-direction: column; }
.wk-row { display: grid; grid-template-columns: 120px minmax(0, 1fr); gap: 12px; align-items: center;
  padding: 10px 14px; border-top: 1px solid var(--border); }
.wk-row:first-child { border-top: 0; }
.wk-row.wk-end { background: color-mix(in srgb, var(--surface-2) 45%, transparent); }
.wk-row.today { background: color-mix(in srgb, var(--brand) 6%, var(--surface));
  box-shadow: inset 3px 0 0 var(--brand); }
/* 日期栏（2026-09-25 用户：「左边这列 今天 和 场次 那两枚按钮很影响视觉」）：
   只留「周五 9/25 今天」——场次计数删掉（右边就摆着那几条，卡片底部还有本周总数），
   「今天」也不再是胶囊块，改成品牌色小字，整行已经用底色+左色条表示今天了。 */
.wk-day { display: flex; align-items: baseline; gap: 6px; min-width: 0; flex-wrap: wrap; row-gap: 2px; }
.wk-day b { font-size: 13px; font-weight: 700; color: var(--text-2); white-space: nowrap; }
.wk-row.today .wk-day b { color: var(--brand); }
.wk-date { font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.wk-today { font-style: normal; font-size: 11px; font-weight: 700; color: var(--brand); }
.wk-items { display: flex; flex-wrap: wrap; gap: 8px; min-width: 0; }
/* 条目是**横向一条**：小标 + 标题 + 「全天 · 3 题」，宽了就自然折到下一行 */
.wk-item { display: inline-flex; align-items: center; gap: 8px; max-width: 100%;
  padding: 7px 11px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); text-decoration: none;
  transition: border-color .12s ease, box-shadow .12s ease; }
.wk-item:hover { border-color: var(--border-strong); box-shadow: var(--sh-1); }
.wk-item.live { border-color: color-mix(in srgb, var(--ac) 40%, var(--border));
  background: color-mix(in srgb, var(--ac-soft) 45%, var(--surface-2)); }
.wk-item.soon { border-color: color-mix(in srgb, var(--brand) 30%, var(--border)); }
.wk-item.done { opacity: .8; }
.wk-t { font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wk-item.live .wk-t { font-weight: 600; }
.wk-meta { font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.wk-kind { font-style: normal; font-weight: 700; font-size: 10.5px; border-radius: 4px; padding: 1px 5px;
  color: var(--brand); background: color-mix(in srgb, var(--brand) 14%, transparent); }
.wk-item.k-hw .wk-kind { color: var(--warn); background: color-mix(in srgb, var(--warn) 15%, transparent); }
.wk-none { flex: 1; align-self: center; border-top: 1px dashed color-mix(in srgb, var(--border) 85%, transparent); }
.wk-foot { display: flex; align-items: center; gap: 8px; padding: 9px 14px;
  border-top: 1px solid var(--border); background: var(--surface-2); font-size: 12px; color: var(--text-3); }
.wk-foot b { color: var(--text); font-size: 13px; }
.wk-foot .spacer { flex: 1; }

@media (max-width: 760px) {
  .wk-row { grid-template-columns: 84px minmax(0, 1fr); gap: 8px; padding: 8px 10px; align-items: start; }
  /* 手机上的日期栏只留两行：`周五 9/25` / `6 场`。
     「今天」那枚小标在手机上藏掉 —— 整行已经有品牌色底 + 左侧色条表示今天，再挂一枚 pill
     只会被挤到第三行（用户截图：「今天跟 6 挤在同一行」）。`.wk-date` 也**不能**再 `width:100%`
     （那会把日期单独顶到一行）。 */
  .wk-day { row-gap: 2px; }
  .wk-today { display: none; }
  .wk-date { width: auto; }
  .wk-item { width: 100%; justify-content: space-between; }
  .wk-item .wk-t { flex: 1; min-width: 0; }
  .wk-kind { flex: none; }
  .wk-meta { flex: none; }
  .wk-foot { padding: 8px 10px; }
}

/* ---------- 36) 作业/比赛详情右上角读数条（2026-09-24 用户「优化右上角」） ---------- */
/* 原来三个独立小卡片并排，在标题右边显空、也占地方；改成一条紧凑读数条，用竖线分隔 */
.ct-stats { gap: 0; }
.ct-stats .stat { background: none; border: 0; box-shadow: none; padding: 0 16px; min-width: 0; }
.ct-stats .stat:first-child { padding-left: 0; }
.ct-stats .stat:last-child { padding-right: 0; }
.ct-stats .stat + .stat { border-left: 1px solid var(--border); }
.ct-stats .k { font-size: 11.5px; margin-bottom: 1px; }
.ct-stats .v { font-size: 19px; line-height: 1.25; }
/* 分隔线被圆角带弯了：基类 .stat 有 border-radius，去掉边框时忘了它 → 竖线沿圆角画成括号形 */
.ct-stats .stat { border-radius: 0; }

/* 筛选结果为零时的提示条：一句话 + 一键恢复（用户抓过「全灭了整页空白，还以为数据没了」） */
.ct-hint { display: flex; align-items: center; gap: 12px; padding: 12px 16px; margin: -6px 0 14px;
  border: 1px dashed var(--border-strong); border-radius: var(--r-sm); color: var(--text-2); font-size: 13px; }
.ct-hint[hidden] { display: none; }
.ct-hint .scope-chip { flex: none; }

/* ---------- 37) 手机端全面扫描（2026-09-24，390×844 逐页实测） ---------- */
/* 这一轮扫描的结论：整站**没有横向溢出**（前两轮的地基还在），坏的是「够不着 / 看不见 / 字竖排」：
   ① 顶栏四个导航字在 390px 里挤不下（横滑 136→214，从词中间截断，还看不出来能滑）；
   ② 后台 tab 条 340→678 横滑，后四个 tab 完全没提示；
   ③ 按钮/徽标被挤窄时文字**竖排**（/editor 的「重置」变两行、/favorites 的「取消收藏」变三行、
      作业详情的「未开始」徽标断成两行）；
   ④ 触控目标偏小（主题钮 29、品牌 26、分页 32、用例标签 24、小复制钮 18、日期选择钮 26、勾选框 17）；
   ⑤ 成绩单/名单表格横滑后，滑走了就不知道在看谁（首列不粘）；
   ⑥ 题库侧栏在手机上占掉首屏 200px，还要在横滑条里再竖滑。 */

/* ① 底部 tab 栏（手机主导航）。桌面不显示；顶栏的四个字在窄屏隐藏，位置让给图标 */
.tabbar { display: none; }
@media (max-width: 760px) {
  .nav { display: none; }
  .tabbar {
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 70;
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: blur(10px);
    border-top: 1px solid var(--border);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .tabbar-item { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    padding: 8px 4px 7px; font-size: 11px; color: var(--text-3); text-decoration: none; min-height: 52px; }
  .tabbar-item.on { color: var(--brand); background: var(--brand-soft); }
  .tabbar-item svg { width: 20px; height: 20px; }
  /* 内容别被底栏盖住（含 iPhone 安全区） */
  body { padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
  .footer { padding-bottom: 8px; }
}

/* ③ 按钮/徽标/chip 一律不换行：宽度不够时它们该整体缩小或换行排布，而不是把字竖起来 */
.btn, .badge, .chip, .scope-chip, .tab, .rail-item, .rec-tab, .pn-link, .ctab, .rtab, .pg, .copy-mini, .copy-btn, .tabbar-item {
  white-space: nowrap;
}

/* ② 后台 tab 条：手机上换行铺开，七项全看得见（横滑时后四项在屏幕外，等于没有） */
@media (max-width: 760px) {
  .tabs { flex-wrap: wrap; overflow: visible; row-gap: 2px; }
  .tab { padding: 9px 12px; }
}

/* ⑥ 题库侧栏：旧的「标题 + 横滑胶囊行」设计已废弃（2026-09-26 目录树取代——横滑会把树压成居中窄条），
   手机端布局由上文第 25/28 节的移动块负责：纵向分组、折叠态天然紧凑 */
@media (max-width: 760px) {
  .pl-app .rail { flex-direction: column; gap: 8px; max-height: none; overflow: visible; }
  .pl-app .rail .rail-group { display: block; max-height: none; overflow: visible; padding: 10px 12px; }
  .pl-app .rail .rail-title { margin: 0 0 8px; }
}

/* ④ 触控目标：手机上一律放到 ≥36px（拇指够得着），别让它们停在 26~32 */
@media (max-width: 760px) {
  .brand-mark { width: 36px; height: 36px; }
  .theme-btn { width: 40px; height: 40px; }
  .theme-btn svg { width: 20px; height: 20px; }
  .user-btn { padding: 6px 8px; min-height: 40px; }
  .user-btn .avatar { width: 30px; height: 30px; }
  /* 搜索框里那个放大镜：基类是 .search-wrap .search-go（两个类），只写 .search-go 会被压住 */
  .search-wrap .search-go { width: 34px; height: 34px; }
  .search-wrap .input { padding-left: 42px; }
  .pg { min-width: 38px; height: 38px; }
  /* 9 个分页钮（‹ 1..7 ›）在 360px 上排不下会顶出 2px 横向溢出 —— 手机上换行 */
  .pager { flex-wrap: wrap; row-gap: 6px; }
  .ctab { padding: 9px 13px; }
  .ctab-add { padding: 9px 14px; }
  .rtab { padding: 10px 13px; }
  .btn-sm { padding: 9px 13px; }
  .copy-mini, .copy-btn { padding: 7px 11px; font-size: 12px; }
  .chip-xs { padding: 3px 9px; font-size: 11.5px; }
  .scope-chip { padding: 9px 15px; }
  .dc-btn, .tp-btn { width: 36px; height: 36px; right: 2px; }
  .pn-link { padding: 9px 10px; }
  /* 表单控件：13px 字 + 8px 内边距在手机上只有 34px，指尖点不准 */
  .input, select.input { padding: 11px 12px; }
  .input-xs { padding: 8px 10px; }
  /* 勾选框/单选框（分组、选题器、公开、作业类型、可见范围）：17px 太小 */
  input[type="checkbox"], input[type="radio"] { width: 20px; height: 20px; }
}

/* ⑤ 宽表格横滑时首列粘住：滑到右边还知道这行是谁 */
@media (max-width: 760px) {
  .table-scroll .table td:first-child { position: sticky; left: 0; z-index: 1; background: var(--surface); }
  .table-scroll .table thead th:first-child { position: sticky; left: 0; top: 0; z-index: 3;
    background: var(--surface-2); box-shadow: 1px 0 0 var(--border); }
  .table-scroll .table td:first-child { box-shadow: 1px 0 0 var(--border); }
}

/* ⑦ 题目工作台（手机）：题面在上、编辑器在下，两屏都长；给个「题目 / 代码」跳转钮，
   点一下滚到编辑器并把光标放进去，省掉手动翻屏。只在窄屏出现。 */
.ws-jump { display: none; }
@media (max-width: 760px) {
  .ws-jump { display: flex; gap: 8px; position: fixed; right: 12px; bottom: calc(64px + env(safe-area-inset-bottom, 0px));
    z-index: 65; }
  .ws-jump button { display: inline-flex; align-items: center; gap: 6px; padding: 10px 14px; border-radius: 999px;
    border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
    box-shadow: var(--sh-2); font-size: 13px; cursor: pointer; }
  .ws-jump button.primary { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 600; }
}

/* ⑧ 编辑器工具条在手机上要点得准：语言下拉与提交钮加高 */
@media (max-width: 760px) {
  /* 工具条手机版：语言选择器独占一行拉满，重置/提交/判题方式一行三个等宽
     （原来是 flex-wrap 随缘折行，按钮东一个西一个，看着乱） */
  .ed-top { flex-wrap: wrap; row-gap: 8px; padding: 10px 12px; }
  .ed-top .dd { flex: 1 1 100%; }
  .ed-top .dd-btn { width: 100%; min-height: 40px; justify-content: space-between; }
  .ed-top .btn, .ed-top .fio { flex: 1 1 0; justify-content: center; }
  .ed-top .btn { min-height: 40px; }
  .ed-top .fio { flex-wrap: wrap; gap: 8px; }
  .ed-top .fio-seg { min-height: 40px; flex: 1 1 auto; justify-content: center; }
  .ed-top .fio-opt { height: 34px; flex: 1 1 0; }
  /* 滑块与文件名按钮**同高**（2026-09-25 用户测试抓到的 6px 差：40 vs 34，两者并排时错位） */
  .ed-top .fio-file { min-height: 40px; display: inline-flex; align-items: center; flex: 1 1 auto; justify-content: center; }
  .ed-top #draft-tip { flex: 1 1 100%; text-align: center; }
  .dd-btn { min-height: 38px; }
  .note-tool { width: 34px; height: 34px; }
  /* 笔记编辑器底栏：手机上一行放不下「工具条 + 取消 + 保存」，让两个按钮平分第二行
     （留着 spacer 的话它们会挤在右端、左边空一截） */
  .note-ed-head { gap: 8px; padding: 10px; }
  .note-foot { gap: 6px; padding: 8px 10px; }
  .note-foot .spacer { display: none; }
  .note-foot .btn { flex: 1 1 0; justify-content: center; min-height: 38px; }
  /* 写作区按视口给高：桌面那套 clamp(100vh-380px) 在手机上把「工具条 + 取消/保存」
     顶到屏幕外去了（实测 844 高要翻一屏才够得着保存） */
  .note-ed-body { height: clamp(220px, 40vh, 380px); }
  /* 卡片上的「编辑 / 删除」是触屏唯一的改/删入口，btn-sm 只有 28px 高，按不准 */
  .note-acts .btn { padding: 7px 13px; font-size: 12.5px; }
  /* 日期/时间浮层原来 z-index 60，会被底部 tab 栏（70）压住 —— 贴近屏幕底部时弹层看不见 */
  .dc-pop, .tp-pop { z-index: 80; }
  /* 自测面板（手机）：竖排三格装不进 44vh（44vh≈371px，内容要 ~500px），
     格子会互相叠。手机上面板改为「内容决定高度、整体限高可滚」，格子各给固定可视高度 */
  .run-panel { height: auto; max-height: 78vh; overflow: auto; }
  /* 面板要**由内容决定高度**：`.run-body`/`.run-tri` 自带的 `flex: 1; min-height: 0` 会把高度压塌
     （实测 390×844：三者共 3 格内容要 275px，被压成 118px ⇒ 溢出 157px 落进面板滚动条里，
     最底下的「分析」正好被挡在可视区外 —— 用户截图报的就是这个）。手机上这层别参与 flex 收缩。 */
  .run-body { flex: none; }
  .run-tri { flex: none; min-height: 0; }
  .run-tri .run-panel textarea, .run-tri .run-output { flex: none; height: 96px; }
  /* 标题条一行放「测试用例 + 运行」，Case 行饱满可点 */
  .run-head { padding: 10px 12px; }
  .run-head .btn-primary { flex: 1 1 0; min-height: 40px; }
  .case-tabs { padding: 10px 12px 0; gap: 7px; }
  .ctab { padding: 8px 15px; font-size: 13px; }
  .ctab-add { padding: 8px 14px; }
  .run-label { padding: 10px 13px 5px; }
  .run-panel textarea, .run-panel .run-output { margin: 0 12px 12px; font-size: var(--code-fs, 13px); }
  .run-panel textarea { width: calc(100% - 24px); }
  /* 复制钮加大 */
  .copy-mini { padding: 6px 11px; }
  /* 题面样例卡（手机）：输入/输出上下排，代码格内边距收紧 */
  .sample { margin: 12px 0; }
  .sample-io-h { padding: 7px 11px; }
  .statement .sample-code { padding: 9px 11px 10px; }
  /* 选题器一行里有 勾选框/题名/题号/标签/判题开关，手机上塞不下会在行内出现横向滚动条；
     标签是锦上添花，窄屏先藏（题号 + 题名 + 判题开关留着） */
  .pk-item .chips-mini { display: none; }
  .pk-item { gap: 8px; padding: 9px 10px; }
}

/* ⑨ 日历视图在手机上：7 列格子每格只有 43px，标题会被截成「前…」「搜…」。
   格子退化成色条（看密度），标题按日期列在下面的 .cal-list 里（看得清）。
   .cal-list 桌面端不显示（桌面格子够宽，直接看格子）。 */
.cal-list { display: none; }
@media (max-width: 760px) {
  /* 色条只是「这天有几场」的密度指示，不是点击目标（6px 高，误触率极高）；
     要点开某一场就点下面清单里的整行 */
  .cal-item { font-size: 0; padding: 0; height: 6px; border-radius: 3px; margin: 2px 0; pointer-events: none; }
  .cal-item.live { background: var(--ac); }
  .cal-item.soon { background: var(--brand); }
  .cal-item.done { background: var(--border-strong); }
  .cal-cell { min-height: 46px; padding: 3px 4px; }
  .cal-day { font-size: 11px; }
  .cal-list { display: block; margin-top: 14px; }
  .cal-row { display: flex; align-items: center; gap: 10px; padding: 11px 12px; border: 1px solid var(--border);
    border-radius: var(--r-sm); margin-bottom: 8px; color: inherit; background: var(--surface); }
  .cal-row .cal-date { flex: none; font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; min-width: 62px; }
  .cal-row .cal-t { min-width: 0; font-size: 13.5px; }
  .cal-row.live { border-color: color-mix(in srgb, var(--ac) 45%, var(--border)); }
  .cal-row.soon { border-left: 3px solid var(--brand); }
}

/* ---------- 联系老师（私信，2026-09-26） ---------- */
/* 顶栏信封上的未读角标：小圆点里塞数字（9+ 封顶），绝对定位到图标右上角 */
.pm-entry { position: relative; }
.pm-badge { position: absolute; top: 1px; right: 0; min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: 99px; background: var(--danger); color: #fff; font-size: 10.5px; font-weight: 700;
  line-height: 15px; text-align: center; font-style: normal; }
.pm-page .page-head { margin-bottom: 12px; }
/* ---------- 私信整屏版式（2026-09-26 用户：「宽度稍微大一点、全框都可以，弄得有那么一点点像微信」）----------
   左边联系人（固定宽、自己滚）+ 右边聊天区（页眉 / 消息滚动区 / 输入区钉底），占满导航条以下的整屏。
   手机上退回上下两段（列表在上、聊天在下，各自限高自己滚）——「历史在里滚、输入框常驻」这条不能破。 */
/* 高度要把 main.page 的上下内边距（22 + 64）一起减掉，否则整页会多出一条滚动条、发送钮掉到屏幕外 */
.pm-app { display: flex; gap: 12px; height: calc(100vh - var(--nav-h) - 86px); min-height: 460px;
  padding: 14px 18px 18px; box-sizing: border-box; }
.pm-app-solo { display: flex; flex-direction: column; padding: 0; height: calc(100vh - var(--nav-h) - 86px); }
.pm-side { flex: none; width: 268px; display: flex; flex-direction: column; min-height: 0;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.pm-side-head { flex: none; display: flex; align-items: baseline; gap: 8px; padding: 11px 13px 9px;
  border-bottom: 1px solid var(--border); }
.pm-side-head b { font-size: 15px; }
.pm-side-head .count { font-size: 12.5px; }
.pm-search { flex: none; padding: 9px 11px; border-bottom: 1px solid var(--border); }
.pm-search .input { width: 100%; box-sizing: border-box; padding: 7px 10px; font-size: 13.5px; }
.pm-conv { flex: 1; min-height: 0; overflow: auto; padding: 6px; }
.pm-conv .empty { padding: 22px 12px; }
.pm-card { display: flex; flex-direction: column; min-height: 0; padding: 0; }
.pm-thread { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; padding: 0; overflow: hidden; }
.pm-thread-head { flex: none; display: flex; align-items: center; gap: 8px; padding: 10px 16px;
  border-bottom: 1px solid var(--border); background: var(--surface); }
.pm-thread-head b { font-size: 14.5px; }
.pm-list { flex: 1; min-height: 0; overflow: auto; padding: 16px 20px 6px; }
.pm-msg { display: flex; align-items: flex-start; gap: 9px; margin-bottom: 14px; }
.pm-msg.mine { flex-direction: row-reverse; }
.pm-bubble { min-width: 0; max-width: 62%; }
.pm-msg .pm-at { font-size: 11.5px; color: var(--text-3); margin-top: 3px; }
.pm-msg.mine .pm-at { text-align: right; }
/* 气泡要「看得出来是个框」（2026-09-26 用户：「消息的背景与主题背景太像了，不太容易区分信息框」）：
   原来用 --surface-2，它在深色主题里与卡片 --surface 只差 **1.06:1** —— 肉眼几乎同色（浅色主题同理）。
   改成三件套：抬一档的底（--surface-3）+ 加重的描边（--border-strong）+ 一层浅阴影，
   深浅两套主题下都能一眼看出边界；自己发的仍靠品牌色区分。 */
.pm-msg .pm-body { border: 1px solid var(--border-strong); border-radius: var(--r); background: var(--surface-3);
  box-shadow: var(--sh-1); padding: 9px 12px; }
.pm-msg .pm-body > :first-child { margin-top: 0; }
.pm-msg .pm-body > :last-child { margin-bottom: 0; }
.pm-msg .pm-at { font-size: 11.5px; color: var(--text-3); margin-top: 3px; }
/* 消息正文的字号（2026-09-26 用户：「普通的字体也太大了吧？在私信这边」）：
   `.pm-body` 带着 `.statement`（借它的 code/pre/table 元素样式），于是**连题面字号一起吃** ——
   而 --fs-statement 是老师按自己看题的习惯调的（他落在 28px），28px 的聊天泡泡非常夸张。
   这里把正文字号与行高固定下来，与输入框（#pm-text 13.5px）、笔记正文同一档；
   标题也收一收（markdown 的 h1 是浏览器默认 2em，在泡泡里就是一行半个屏）。 */
.pm-msg .pm-body { font-size: 13.5px; line-height: 1.7; }
.pm-msg .pm-body h1, .pm-msg .pm-body h2, .pm-msg .pm-body h3, .pm-msg .pm-body h4 { font-size: 14.5px; margin: 2px 0 6px; }
.pm-msg .pm-body p, .pm-msg .pm-body ul, .pm-msg .pm-body ol { margin: 0 0 8px; }
.pm-msg .pm-body blockquote { margin: 4px 0 8px; }
/* 自己发的靠右、染品牌边（讨论区那套观感的轻量版）；气泡宽度由 .pm-bubble 封顶，不再按行拉伸 */
.pm-msg.mine .pm-body { background: var(--brand-soft);
  border-color: color-mix(in srgb, var(--brand) 45%, var(--border-strong)); }

/* ---------- 消息工具条：复制 Markdown / 编辑 / 历史（2026-09-26 用户要求）----------
   常驻可见（手机上没 hover，藏起来就点不到）但压得很轻；悬停/展开时提亮。
   「编辑」只出现在自己发的那侧（服务端还会再判一次「只能改自己的」）。 */
.pm-tools { display: flex; gap: 6px; margin: 0 0 4px; opacity: .55; transition: opacity .13s; }
.pm-msg.mine .pm-tools { justify-content: flex-end; }
.pm-msg:hover .pm-tools { opacity: 1; }
.pm-tool { border: 0; background: none; padding: 0; font: inherit; font-size: 11.5px; color: var(--text-3);
  cursor: pointer; border-bottom: 1px dashed transparent; }
.pm-tool:hover { color: var(--brand); border-bottom-color: currentColor; }
.pm-tool.on { color: var(--brand); font-weight: 600; }
/* 「已编辑」标记跟在时间后面 */
.pm-edited { color: var(--warn); border-bottom: 1px dotted currentColor; }
/* 历史（旧版本）：缩进 + 左竖线 + 更淡，一眼看出是「改之前的」 */
.pm-hist { margin-top: 6px; padding-left: 10px; border-left: 2px solid var(--border); }
.pm-hist-row { margin-bottom: 8px; }
.pm-hist-row:last-child { margin-bottom: 0; }
.pm-hist-at { display: block; font-size: 11px; color: var(--text-3); margin-bottom: 2px; }
.pm-hist .pm-body { background: var(--surface-2); border-style: dashed; opacity: .85; }
/* 就地编辑框 */
.pm-edit-box { min-width: 260px; max-width: 62vw; }
.pm-msg.mine .pm-edit-box { margin-left: auto; }
.pm-edit-ta { width: 100%; box-sizing: border-box; min-height: 84px; max-height: 260px; resize: vertical;
  font: inherit; font-size: 13.5px; line-height: 1.7; padding: 9px 11px; color: var(--text-1);
  background: var(--surface); border: 1px solid var(--brand); border-radius: var(--r-sm); }
.pm-edit-ta:focus { outline: none; }
.pm-edit-bar { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.pm-foot { flex: none; border-top: 1px solid var(--border); padding: 10px 14px 12px; background: var(--surface); }
/* pm-foot 改 flex 列布局后，分段钮会被拉伸成整行宽（2026-09-29 用户报「按钮大小不对」）——收回内容宽 */
.pm-foot .pm-seg { align-self: flex-start; }
.pm-seg { display: inline-flex; border: 1px solid var(--border); border-radius: 999px; overflow: hidden; margin-bottom: 8px; }
.pm-seg-btn { border: 0; background: none; padding: 4px 14px; font: inherit; font-size: 12.5px;
  color: var(--text-3); cursor: pointer; }
.pm-seg-btn + .pm-seg-btn { border-left: 1px solid var(--border); }
.pm-seg-btn.on { background: var(--brand); color: #fff; font-weight: 600; }
#pm-text { width: 100%; box-sizing: border-box; min-height: 96px; max-height: 220px; resize: vertical;
  font: inherit; font-size: 13.5px; line-height: 1.7; padding: 10px 12px; color: var(--text-1);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm); }
#pm-text:focus { outline: none; border-color: var(--brand); }
.pm-prev { min-height: 96px; max-height: 260px; overflow: auto; padding: 10px 12px; border: 1px dashed var(--border);
  border-radius: var(--r-sm); background: var(--surface-2); }
.pm-tip { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-3); min-height: 18px; margin: 4px 0 6px; }
.pm-tip #pm-tip[data-kind="ok"] { color: var(--ac); }
.pm-tip #pm-tip[data-kind="fail"] { color: var(--danger); }
.pm-tip #pm-count.over { color: var(--danger); font-weight: 600; }
.pm-actions { display: flex; align-items: center; gap: 8px; }
/* 联系人一行：头像 + 姓名/摘要 + 未读点（微信那套） */
.pm-row { display: flex; align-items: center; gap: 10px; padding: 9px 10px;
  border-radius: var(--r-sm); text-decoration: none; color: var(--text); }
.pm-row:hover { background: var(--surface-2); }
.pm-row.on { background: var(--brand-soft); }
.pm-row-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.pm-row-name { font-size: 13.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pm-row-sub { font-size: 12px; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pm-dot { flex: none; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 99px; background: var(--danger); color: #fff;
  font-size: 11px; line-height: 18px; text-align: center; }
.pm-pick { padding: 40px 0; }
/* 手机上「列表 → 聊天」两级：聊天页页眉左侧给一个返回键（微信那种），桌面端不显示 */
.pm-back { display: none; align-items: center; color: var(--text-2); }
.pm-back svg { width: 18px; height: 18px; transform: rotate(90deg); }
@media (max-width: 760px) {
  /* 手机：老师侧不选中学生时 = 联系人列表（自己限高），选中了就只留聊天窗口并把高度钉死 ——
     这样输入区一定在首屏里（历史一长把发送钮顶出屏幕是这页踩过的坑：实测 .pm-foot 落在 y=1036、视口才 844）。 */
  .pm-app:not(.pm-app-solo) { display: block; height: auto; padding: 10px; }
  .pm-side { width: auto; }
  .pm-conv { max-height: 58vh; }
  .pm-app:has(.pm-thread[data-to]) { height: calc(100vh - var(--nav-h) - 86px); }
  .pm-app:has(.pm-thread[data-to]) .pm-side { display: none; }
  .pm-app:has(.pm-thread[data-to]) .pm-thread { height: 100%; }
  .pm-back { display: inline-flex; }
  .pm-bubble { max-width: 84%; }
}

/* 注：「内容有更新 · 点此同步」药丸已按用户要求撤掉（2026-09-27：「有更新就点击刷新，那我直接刷新不就行了？
   多此一举，还碍事」）。心跳只在安全页面静默重载，有草稿的页面不动 —— 数据靠各自及时落盘保证不丢。 */

/* ---------- 私信整屏（2026-09-26 用户：「这个私信无论是电脑端还是手机端，都应该占满。四周还有太多间隙，私信有点窄」）----------
   原来两道内边距叠着：`main.page` 的 22/20/64 + `.pm-app` 自己的 14/18/18 ⇒ 左右各约 38px、顶 36px、底下 82px 白边，
   聊天窗被挤在中间一条。现在这一页整屏：顶栏之下直接是「会话列表 + 聊天窗」，底部不留白（页脚这页不渲染，
   否则会被 100vh 裁掉还多出一条滚动条）；贴边的两栏去掉卡片圆角与四边框，只留一条分隔线（微信那种）。 */
.shell-chat { height: 100vh; min-height: 0; overflow: hidden; }
.shell-chat .page { padding: 0; min-height: 0; display: flex; flex-direction: column; }
.page-full .pm-app { flex: 1; height: auto; min-height: 0; padding: 0; gap: 0; }
.page-full .pm-app-solo { flex: 1; height: auto; min-height: 0; }
.page-full .pm-side, .page-full .pm-thread, .page-full .pm-app .card {
  border: 0; border-radius: 0; box-shadow: none; }
.page-full .pm-side { border-right: 1px solid var(--border); }
@media (max-width: 760px) {
  /* 手机上照旧两级（列表 ↔ 聊天），但两级都占满；底栏那 56px 由 body 的 padding-bottom 让出来。
     min-height 必须归零：`.shell` 的 `min-height:100vh` 会压过这里的 height，整页就多出 56px、
     冒出一条滚动条、底栏还压在输入区上（第一次改完实测 scrollHeight 900 > 视口 844）。 */
  .shell-chat { height: calc(100dvh - 56px - env(safe-area-inset-bottom, 0px)); min-height: 0; }
  .page-full .pm-app:not(.pm-app-solo) { display: block; height: 100%; padding: 0; }
  .page-full .pm-side { height: 100%; border-right: 0; }
  .page-full .pm-conv { max-height: none; }
  .page-full .pm-app:not(:has(.pm-thread[data-to])) .pm-thread { display: none; }   /* 没选学生时别占地方 */
  .page-full .pm-app:has(.pm-thread[data-to]) { height: 100%; }
  .page-full .pm-app:has(.pm-thread[data-to]) .pm-thread { height: 100%; }
}

/* ---------- 列表页的立式分组目录（2026-09-27 用户：「要把左边优化成侧边目录栏，不然就是太丑了」）----------
   原来是一张只包住几行的小卡片、下面空一大片 ⇒ 改成占满视口高度的目录栏：sticky 跟着滚、右侧一条分隔线当路轨、
   表头固定、树自己滚；当前项用「左侧品牌竖条 + 浅品牌底」指位置（UX 库：当前项必须强指示），
   子分组缩进 + 竖线画层级。手机上退回列表上方的一块。 */
.list-split { display: grid; grid-template-columns: var(--scope-w, 190px) 16px minmax(0, 1fr); align-items: start; }
.scope-side { position: sticky; top: 12px; align-self: start; height: calc(100vh - var(--nav-h) - 116px);
  min-height: 320px; display: flex; flex-direction: column;
  border-right: 1px solid var(--border); padding-right: 4px; }
.scope-head { flex: none; display: flex; align-items: baseline; gap: 6px; padding: 2px 10px 10px;
  font-size: 12px; font-weight: 600; letter-spacing: .04em; color: var(--text-3);
  border-bottom: 1px solid var(--border); margin-bottom: 8px; }
.scope-head .count { font-size: 11.5px; }
.scope-tree { flex: 1; min-height: 0; overflow: auto; padding-right: 2px; }
.scope-item { position: relative; display: flex; align-items: center; gap: 6px; padding: 7px 8px;
  margin-left: calc(var(--d, 0) * 14px); border-radius: var(--r-sm);
  text-decoration: none; color: var(--text-2); font-size: 13.5px; }
.scope-item:hover { background: var(--surface-2); color: var(--text); }
.scope-item.on { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
.scope-item.on::before { content: ''; position: absolute; left: -6px; top: 5px; bottom: 5px; width: 3px;
  border-radius: 3px; background: var(--brand); }
.scope-item.sub::after { content: ''; position: absolute; left: -8px; top: 0; bottom: 0;
  border-left: 2px solid var(--border-strong); }
@media (max-width: 760px) {
  .list-split { display: block; }
  .scope-side { position: static; height: auto; max-height: 42vh; min-height: 0; margin-bottom: 10px;
    border-right: 0; border-bottom: 1px solid var(--border); padding: 0 0 8px; }
  .scope-gutter { display: none; }
}

/* 拖动竖线（#scope-gutter）的**功能性**样式 —— 2026-09-27 视觉复测补回。
   上一轮改这段 CSS 时「删过头」，把这三条规则一起删了（git: 26e2fdba 里 5 处、a1e4c724 只剩 1 处）。
   后果是**功能失效**而不是样式变丑：容器是 `align-items: start`，竖线没有 `align-self: stretch`
   高度就塌成 0（实测 h=0、cursor:auto）⇒ 鼠标根本抓不到，「拖宽」与「双击还原」都按不出来。
   常驻可见的那条竖线**不恢复**：路轨已改由 `.scope-side` 的 border-right 表达（见文件前半段），
   这里只保留悬停/拖动时的品牌色反馈，静态下不添装饰。 */
.scope-gutter { grid-column: 2; align-self: stretch; cursor: col-resize; position: relative; }
.scope-gutter::after { content: ''; position: absolute; left: 6px; top: 8px; bottom: 8px; width: 4px;
  border-radius: 2px; background: transparent; transition: background .12s; }
.scope-gutter:hover::after, .scope-gutter.dragging::after { background: var(--brand); }

/* ==================== 画板（题目页草稿白板，2026-09-26） ====================
   与测试用例面板同住 .dock：打开时把用例面板收成一栏（保留「运行」一键可用），
   自己占满余下高度。视觉语法沿用门户既有的「分段硬按钮」：静态不花哨，
   `.on` 才是品牌色；悬停只给一层背景反馈（不要按列各变一套）。 */
.board-panel { background: var(--surface);
  display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; height: auto; }
/* 画板模式下右栏整体让给画板：代码编辑器与测试用例面板收起（关掉画板一切复原）。
   用户 2026-09-26：「这么小一块区域，我怎么画？都画板了，还要样例干嘛呢？还要那么多边距干嘛呢？」 */
.ws-right.board-mode .ed-body { display: none; }
.ws-right.board-mode .dock { flex: 1 1 auto; height: auto; }

/* 注：画板**不再吃整屏**（2026-09-28 用户纠正：「我点击画板应该是占满代码区和测试用例区的，
   我点击全屏按钮才全屏的」）—— 画板只占右栏，全屏交给 #btn-fs 那套（.ws.fs + setSplit(0)，
   两者可叠加：画板开着按全屏，右栏吃满整屏、画板跟着全屏）。
   真正让「可画区域」变大的是子应用里把属性面板改成浮动不占位（见 board-app/src/main.jsx
   的 UIOptions.dockedSidebarBreakpoint）。窄屏那个「Excalidraw 在 height:auto 里无限长高」
   由 board-embed.js 的 layoutForBoard() 用内联高钉住（CSS 覆盖不稳，实测过）。 */
.ws-right.board-mode .run-panel { display: none; }

.bd-head { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; row-gap: 5px;
  padding: 7px 9px; border-bottom: 1px solid var(--border); background: var(--surface-2); flex: none; }
.bd-sep { width: 1px; height: 18px; background: var(--border); flex: none; }
.bd-tools, .bd-colors, .bd-widths { display: inline-flex; align-items: center; gap: 3px; }

.bd-tool, .bd-act { display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0; border: 1px solid transparent; border-radius: var(--r-sm);
  background: none; color: var(--text-2); cursor: pointer; transition: background .13s, color .13s; }
.bd-tool:hover, .bd-act:hover:not(:disabled) { background: var(--surface-3); color: var(--text); }
.bd-tool.on, .bd-act.on { background: var(--brand-soft); border-color: color-mix(in srgb, var(--brand) 22%, transparent); color: var(--brand); }
.bd-act:disabled { color: var(--border-strong); cursor: default; }

.bd-color { width: 21px; height: 21px; padding: 0; border-radius: 999px; cursor: pointer;
  background: var(--c); border: 1px solid var(--border-strong); position: relative; }
.bd-color.on::after { content: ''; position: absolute; inset: -4px; border-radius: 999px;
  border: 2px solid var(--brand); }
.bd-w { width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;
  padding: 0; border: 1px solid transparent; border-radius: var(--r-sm); background: none; cursor: pointer;
  color: var(--text-2); transition: background .13s, color .13s; }
.bd-w i { display: block; width: 15px; border-radius: 99px; background: currentColor; }
.bd-w:hover { background: var(--surface-3); color: var(--text); }
.bd-w.on { background: var(--brand-soft); border-color: color-mix(in srgb, var(--brand) 22%, transparent); color: var(--brand); }

.bd-zoom { display: inline-flex; align-items: center; gap: 2px; }
.bd-pct { height: 28px; min-width: 42px; padding: 0 4px; font: inherit; font-size: 12px; line-height: 1;
  color: var(--text-2); background: none; border: 1px solid transparent; border-radius: var(--r-sm); cursor: pointer;
  font-variant-numeric: tabular-nums; transition: background .13s, color .13s; }
.bd-pct:hover { background: var(--surface-3); color: var(--text); }
.bd-save { font-size: 12px; line-height: 1; min-width: 54px; text-align: right; color: var(--text-3); }
.bd-save.ok { color: var(--ac); }
.bd-save.warn { color: var(--warn); }
.bd-save.err { color: var(--danger); }

/* 画布区：纸张浮在略深一档的底上，白纸贴白卡也看得出边界 */
/* 无内边距、无纸框：整块区域都是可画空间（用户 2026-09-26：「边距等内容不需要，全部都是可画空间」） */
.bd-body { position: relative; flex: 1; min-height: 0; display: block;
  padding: 0; background: var(--surface); overflow: hidden; }
.bd-body canvas { display: block; touch-action: none;
  overscroll-behavior: contain; outline-offset: -2px; }
/* 画布是「一直在用」的输入面：鼠标点开时不要顶着蓝圈（那看着像被选中），
   键盘 Tab 进来才给焦点环（无障碍要求的是「键盘可见焦点」，不是「永远高亮」）。 */
.bd-body canvas:focus:not(:focus-visible) { outline: none; }
/* Excalidraw 引擎：面板正文就是一整块 iframe（画布/工具条/缩放都在子应用里，门户只给容器）。
   子应用是独立的文档，样式不共享 —— 这里只管把容器铺满、别留缝、别让页面滚动抢触摸。 */
.bd-body-frame { padding: 0; background: var(--surface); }
.bd-body-frame iframe { display: block; width: 100%; height: 100%; border: 0;
  background: var(--surface); touch-action: none; }
.bd-hint { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  color: var(--text-3); font-size: 13px; pointer-events: none; user-select: none; text-align: center; }
#bd-open.on { background: var(--brand-soft); border-color: color-mix(in srgb, var(--brand) 26%, transparent); color: var(--brand); }

/* 老师表单里的「画板」开关（与判题方式的 .fio-opt 同一套观感） */
.bd-ctl { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.bd-seg { display: inline-flex; align-items: center; gap: 2px; height: 31px; padding: 0 3px;
  border-radius: 999px; background: var(--surface-2); border: 1px solid var(--border); flex: none; }
.bd-seg-opt { height: 25px; padding: 0 14px; font: inherit; font-size: 12px; line-height: 1;
  color: var(--text-3); background: none; border: 0; border-radius: 999px; cursor: pointer;
  transition: background .15s, color .15s; }
.bd-seg-opt:hover:not(.on) { color: var(--text); }
.bd-seg-opt.on { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
.bd-ctl .muted { flex: 1 1 260px; min-width: 200px; }

@media (max-width: 760px) {
  .bd-head { gap: 5px; padding: 8px 9px; }
  .bd-tool, .bd-act { width: 34px; height: 34px; }      /* 手指目标 ≥34px */
  .bd-w { width: 34px; height: 34px; }
  .bd-color { width: 26px; height: 26px; }
  .bd-sep { display: none; }                            /* 换行铺排时竖线只会添乱 */
  .bd-save { min-width: 52px; }
}
@media (prefers-reduced-motion: reduce) {
  .bd-tool, .bd-act, .bd-w, .bd-color, .bd-seg-opt, .bd-pct { transition: none; }
}

/* ============ 账号管理页的三个行内控件（2026-09-27） ============
   学生行的操作列从「只有重置密码」扩成 重置密码 / 编辑分组 / 删除；
   沿用 .pw-reset 那套 <details> 折叠范式（100 个学生时不塞常驻输入框）。 */
.stu-table .act-cell.stu-acts { width: 360px; }
.stu-acts > details, .stu-acts > details[open] { display: inline-flex; vertical-align: top; }
.stu-acts > details + details { margin-left: 6px; }
.gr-edit, .del-account { position: relative; }
.gr-edit > summary, .del-account > summary { list-style: none; display: inline-flex; cursor: pointer; }
.gr-edit > summary::-webkit-details-marker, .del-account > summary::-webkit-details-marker { display: none; }
/* 展开后就地铺开（表格里不能真的浮层，会把行撑坏）：占满整行宽、自己滚 */
.gr-edit[open], .del-account[open] { display: block; margin-top: 8px; }
.gr-edit[open] > summary, .del-account[open] > summary { background: var(--surface-3); }
.gr-box { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 4px 10px;
  max-height: 190px; overflow: auto; padding: 8px 10px; margin-top: 6px;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2); }
.gr-box .chk-line { display: flex; align-items: center; gap: 6px; font-size: 13px; padding: 2px 0; }
.del-form { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-top: 6px; }
.del-form .input { max-width: 170px; }
.ok-banner { display: flex; align-items: center; gap: 8px; color: var(--text); background: var(--ac-soft); }
@media (max-width: 760px) {
  .stu-table .act-cell.stu-acts { width: auto; }
  .gr-box { grid-template-columns: 1fr; }
}

/* ============ 「这条实际可见范围」标记（2026-09-27） ============
   用户报：「这些作业明明是在对应的子分组可看，为啥我点击父分组还能看到呢？…父分组里面罗列子分组，
   会让人误会这个作业是父分组权限的」。可见性规则没错（选一个组会列出它 + 祖先 + 后代布置的内容），
   缺的是**每条自己绑在哪个组**的说明 —— 这三处标记补上它（只有老师看得到，学生不该知道别的班存在）。 */
.ct-scope { background: var(--warn-soft); color: var(--warn); border-color: transparent; white-space: nowrap; }
.wk-scope { display: block; margin-top: 2px; font-size: 11.5px; color: var(--warn);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wk-scope::before { content: '范围 '; color: var(--text-3); }
.cal-scope { margin-left: auto; font-size: 11.5px; color: var(--warn); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-width: 40%; }

/* ============ 测试区拖到顶 = 代码编辑器整体收起（2026-09-28 用户要求） ============
   用户问：「测试区上拉到顶端时能不能把代码块隐藏？」
   旧行为：拖动高度封顶 80vh —— 大屏上 80vh 够不着「编辑器已经没用了」的程度，
   于是编辑器被挤成几行残条（半截代码露在面板边上），既占地方又没法看代码。
   新行为：往上拖过阈值（剩不下 ≈4 行）就把整个 .ed-body 收掉，测试用例独占右栏；
   往下拖回来自动还回来，双击复位（逻辑见 public/app.js 的 initResize / setEditorHidden）。 */
.ws-right.ed-hidden .ed-body, .me-stack.ed-hidden .ed-body { display: none; }
.ws-right.ed-hidden .dock, .me-stack.ed-hidden .dock { flex: 1 1 auto; }
.run-panel.expanded { height: auto; flex: 1 1 auto; }


/* ============ 客观题（选择题）：工作台模式（2026-09-28 用户定稿） ============
   与编程题**同一个工作台**：左栏 = 题目框 + 选项框（可点选）+ 题解/提交记录/笔记页签；
   右栏 = 只有画板（board-mode 常驻，ed-top 的语言/判题方式/提交代码整体藏掉 —— 没有写代码的需求）。
   两框同宽同内边距 ⇒ 选项与题干左对齐；题目/选项各自成框，分隔一目了然（用户圈的红色范围）。 */
/* 顶栏显示但只留类型按钮 + 全屏：语言/判题方式/提交/重置对客观题都失去意义（app.js 启动要绑定
   这些元素，所以只藏不删）；「客观题」按钮 = 类型徽标，告诉学生这题是选择题、没有判题方式。 */
.obj-workbench .ed-top { display: flex; }
.obj-workbench .ed-top .dd,
.obj-workbench .ed-top #draft-tip,
.obj-workbench .ed-top #btn-reset,
.obj-workbench .ed-top #btn-submit,
.obj-workbench .ed-top #bd-open { display: none; }  /* 画板常驻，开关钮多余 */
.obj-workbench .ed-top .fio { display: inline-flex; }
.obj-workbench .obj-type { cursor: default; }
.obj-workbench #bd-close { display: none; }      /* 画板是右栏的常驻内容，不提供「收起」 */
/* 客观题永远没有「写代码/跑用例」这回事：ed-body 与 run-panel 任何视口都不露。
   手机端进页面会收起常开画板、摘掉 board-mode（board-embed.js 2026-10-16），
   没有这两条就会把代码编辑器和运行面板裸露给客观题。 */
.obj-workbench .ed-body, .obj-workbench .run-panel { display: none; }
/* 老师禁了画板的客观题：右栏没有内容可看 → 退回单栏（!important 压过 app.js setSplit 的内联 50/50） */
.obj-workbench.obj-no-board .ws-gutter, .obj-workbench.obj-no-board .ws-right { display: none; }
.obj-workbench.obj-no-board .ws { grid-template-columns: 1fr !important; }
/* 题目框：题干 + 材料块（代码/图片）。题干（首个直接子级）单独垫一层浅色底，让「题干」与
   「材料」在同一个框里也有层次；框标题小字点明这是题面。 */
.obj-statement { margin: 0; padding: 14px 18px 16px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r); }
.obj-statement::before { content: '题面'; display: block; margin: 0 0 8px;
  font-size: 12px; font-weight: 700; letter-spacing: .08em; color: var(--text-3); }
.obj-statement > :first-child { margin-top: 0; }
.obj-statement > :first-child::before { display: none; }   // ::before 会落在首元素前，标签本身只有一处
.obj-statement > :last-child { margin-bottom: 0; }
/* 选项框：标题行（「选项」小标 + 已选状态）→ 选项行 → 操作行；与题目框同宽同内边距 ⇒ 左对齐 */
.obj-card { margin: 12px 0 24px; padding: 12px 18px 14px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r); }
.obj-card::before { content: '选项'; display: block; margin: 0 0 6px;
  font-size: 12px; font-weight: 700; letter-spacing: .08em; color: var(--text-3); }
#obj-opts-slot:empty { display: none; }
.obj-card.has-rows .obj-opts { display: none; }   /* 有选项行时，那排字母按钮退役（判断题没有行，保留） */
.obj-opts { display: flex; gap: 10px; flex-wrap: wrap; padding: 2px 0 0; }
/* 选项按钮：判断题用（正确 / 错误）—— 选择题的入口是下面的选项行 */
.obj-opt { display: inline-flex; align-items: center; gap: 8px; min-width: 62px; padding: 10px 16px;
  font: inherit; font-size: 15px; color: var(--text); background: var(--surface-2);
  border: 1.5px solid var(--border-strong); border-radius: var(--r-sm); cursor: pointer;
  transition: background .13s, border-color .13s, color .13s; }
.obj-opt b { font-weight: 700; }
.obj-opt i { font-style: normal; font-size: 12px; color: var(--text-3); }
.obj-opt:hover { border-color: var(--brand); color: var(--brand); }
.obj-opt.on { background: var(--brand-soft); border-color: var(--brand); color: var(--brand); font-weight: 650; }
/* 「已批改」锁（2026-10-14 用户抓的洞：出分后没点重做还能改选再交）：选项禁点、整体降饱和，
   正确/你的选择两行保持原样醒目；重做按钮可点（exitGraded 解锁） */
.obj-card.graded .obj-opt, .obj-card.graded .obj-li { pointer-events: none; cursor: default; }
.obj-card.graded .obj-opt:not(.on), .obj-card.graded .obj-li:not(.right):not(.wrong) { opacity: .55; }
.obj-card.graded .obj-opt:hover { border-color: var(--border-strong); color: inherit; }
/* 课程「文章」页签（2026-10-14 用户钦定）：教材式 markdown 知识点讲解，沿用题面 .statement 渲染样式 */
.dt-panel .statement { padding: 4px 2px; }
#art-md { background: var(--surface); color: var(--text); border: 1px solid var(--border-strong); border-radius: 8px; line-height: 1.55; }
/* 操作行：与选项区隔一条细线，「已选 X」是主状态（字母按钮退役后它就是选择状态的显示位） */
.obj-actions { display: flex; align-items: center; gap: 10px; margin-top: 12px; padding-top: 12px;
  border-top: 1px solid var(--border); }
.obj-picked { padding: 3px 10px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
  background: var(--surface-2); border: 1px solid var(--border-strong); color: var(--text-3); }
.obj-picked.picked { background: var(--brand-soft); border-color: color-mix(in srgb, var(--brand) 26%, transparent); color: var(--brand); }

/* 题面里的选项列表（- **A.** …）：objective.js 把它升级成**可点选的选项行** ——
   字母徽标 + 内容，与答题卡双向同步（点行 = 选中，键盘 A–D 同样有效）；
   公布答案后判完，行上直接标对错（正确项描绿、选错的描红）。 */
.obj-ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
/* 选项行 = 一枚「选项卡」：浅底 + 圆角，行与行之间留 8px 呼吸（2026-09-28 用户「美化一下选项框」）；
   悬停描边变亮、行微微上浮；选中品牌描边 + 浅品牌底；判完对错整行着色 + 行尾徽章（图标 + 文字）。 */
/* 选项行 = 块级行内排版（2026-10-17 修「公式两侧间距过大」）：
   原实现 display:flex + gap:14px，把行内文字、空格、KaTeX 全部拆成独立 flex item，
   每个空格与公式两侧各吃一次 14px 间隙，公式看起来被"隔离"。
   选项内容是行内富文本（文字/公式/代码/图片），必须走正常行内排版；
   字母徽标与对错徽章改用绝对定位（DOM 不变，objective.js 无需改）。 */
.obj-li { position: relative; display: block; padding: 10px 14px 10px 50px; line-height: 1.75;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm);
  cursor: pointer; transition: border-color .13s, background .13s, transform .13s; }
.obj-li:has(.obj-li-flag) { padding-right: 108px; }
.obj-li:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.obj-li:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.obj-li-key { position: absolute; left: 12px; top: 9px; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  border-radius: 9px; background: var(--surface-2); border: 1px solid var(--border-strong);
  font-weight: 700; font-size: 13.5px; color: var(--text-2); transition: background .13s, color .13s; }
.obj-li.on { border-color: color-mix(in srgb, var(--brand) 45%, transparent); background: var(--brand-soft); }
.obj-li.on .obj-li-key { background: var(--brand); border-color: var(--brand); color: #fff; }
.obj-li.right { border-color: color-mix(in srgb, var(--ac) 45%, transparent); background: var(--ac-soft); }
.obj-li.right .obj-li-key { background: var(--ac); border-color: var(--ac); color: #fff; }
.obj-li.wrong { border-color: color-mix(in srgb, var(--danger) 45%, transparent); background: var(--danger-soft); }
.obj-li.wrong .obj-li-key { background: var(--danger); border-color: var(--danger); color: #fff; }
/* 行尾对错徽章：颜色之外再给「图标 + 文字」（ux 规范：对错不能只靠颜色传达） */
.obj-li-flag { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border-radius: 999px; font-size: 12px; font-weight: 650; white-space: nowrap; }
.obj-li.right .obj-li-flag { background: var(--ac); color: #fff; }
.obj-li.wrong .obj-li-flag { background: var(--danger); color: #fff; }
.obj-li-flag svg { display: block; }
/* 选项行里的 KaTeX / 代码与正文对齐（徽标右侧首行齐平） */
/* 选项正文与题干同字号：选项不是小字注释 */
.obj-li { font-size: 15px; }
/* ===== 客观题题解的教学版式（2026-09-28 用户重设计：「题解的意义是教会学生做这道题」）=====
   答案徽章（先自己想一遍）→ 编号步骤卡：方法 → 推导 → 辨析 → 易错点（琥珀警示）。
   每步一张卡、左侧色条按序号递进；步骤 HTML（表格/KaTeX）来自服务端构建。 */
.obj-ans { display: flex; align-items: center; gap: 12px; padding: 12px 16px; margin: 0 0 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); }
.obj-ans-t { font-size: 12px; font-weight: 700; letter-spacing: .08em; color: var(--text-3); }
.obj-ans-key { display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 34px; padding: 0 8px; border-radius: 10px;
  background: var(--ac); color: #fff; font-size: 17px; font-weight: 800; }
.obj-steps { display: grid; gap: 10px; }
.obj-step { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  padding: 12px 16px 14px; border-left: 3px solid var(--brand); }
.obj-step-h { display: flex; align-items: center; gap: 9px; margin: 0 0 8px;
  font-size: 13px; font-weight: 700; color: var(--text-2); }
.obj-step-h i { flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 7px; background: var(--brand-soft);
  color: var(--brand); font-style: normal; font-size: 12px; font-weight: 800; }
.obj-step-b { font-size: 14.5px; }
.obj-step-b > :first-child { margin-top: 0; }
.obj-step-b > :last-child { margin-bottom: 0; }
/* 推导表格 / 引用块在步骤卡内的观感 */
.obj-step-b table { max-width: 100%; }
.obj-step-b blockquote { margin: 8px 0; }
/* 易错点：琥珀警示（左条 + 标题 + 编号全换色） */
.obj-step.warn { border-left-color: var(--warn); }
.obj-step.warn .obj-step-h { color: var(--warn); }
.obj-step.warn .obj-step-h i { background: var(--warn-soft); color: var(--warn); }
/* 三块式的语义色（2026-09-28 用户定：①什么考点 ②怎么做 ③其他选项为什么错）：
   考点=品牌蓝、怎么做=绿（动手）、其他选项为什么错=红（讲错因） */
.obj-step.kind-point { border-left-color: var(--brand); }
.obj-step.kind-point .obj-step-h i { background: var(--brand-soft); color: var(--brand); }
.obj-step.kind-how { border-left-color: var(--ac); }
.obj-step.kind-how .obj-step-h i { background: var(--ac-soft); color: var(--ac); }
.obj-step.kind-why, .obj-step.why { border-left-color: var(--danger); }
.obj-step.kind-why .obj-step-h i, .obj-step.why .obj-step-h i { background: var(--danger-soft); color: var(--danger); }
/* 「怎么做」卡内的易错点警示盒（琥珀浅底，随内容走而不是独占一张卡） */
.obj-warn-note { margin: 10px 0 0; padding: 9px 12px; border-radius: var(--r-sm);
  background: var(--warn-soft); border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent); }
.obj-warn-note > :first-child { margin-top: 0; }
.obj-warn-note > :last-child { margin-bottom: 0; }
@media (max-width: 760px) {
  .obj-step { padding: 10px 12px 12px; }
}

/* 题干/选项里的插图（GESP 选项甲/乙/丙/丁 这类）：默认限高，点一下放大、再点收回。
   背景：选项图原图常是 500~600px 见方，四个选项堆起来接近 1800px，学生没法同屏对比。 */
.obj-li img {
  max-width: 100%; max-height: 170px; width: auto; height: auto;
  border-radius: var(--r-sm); border: 1px solid var(--border); background: #fff;
  vertical-align: middle; cursor: zoom-in;
}
.obj-li img.zoomed { max-height: none; cursor: zoom-out; }
/* 题干图放宽些（宽扁的示意图压到 170px 会看不清），普通题面插图只加"可点击放大" */
.obj-statement img { max-width: 100%; max-height: 320px; width: auto; height: auto; cursor: zoom-in; }
.obj-statement img.zoomed { max-height: none; cursor: zoom-out; }
/* 选项图必须比题干更小（同权重会被上面的规则盖掉，所以这里提高一级选择器） */
.obj-statement .obj-li img { max-height: 170px; }
.obj-statement .obj-li img.zoomed { max-height: none; }
.statement img { cursor: zoom-in; }
.statement img.zoomed { max-height: none; cursor: zoom-out; }
/* 题单列表的题型徽标（2026-10-13 用户要的类型区分）：选择=紫、编程=青——颜色+文字双编码，不只靠色 */
.type-chip { display: inline-flex; align-items: center; flex: none; margin-right: 8px;
  padding: 1px 7px; border-radius: 999px; font-size: 11px; font-weight: 600; line-height: 18px;
  vertical-align: 1px; user-select: none; }
.type-chip.type-obj { color: #8b5cf6; background: rgba(139, 92, 246, 0.14); }
.type-chip.type-prog { color: #0891b2; background: rgba(8, 145, 178, 0.14); }
html[data-theme='dark'] .type-chip.type-obj { color: #b79bfa; background: rgba(139, 92, 246, 0.22); }
html[data-theme='dark'] .type-chip.type-prog { color: #4cc7d8; background: rgba(8, 145, 178, 0.22); }
/* 外站引用题（type: external）：徽标橙 + 题目页的「去原网站提交」卡片 */
.type-chip.type-ext { color: #d97706; background: rgba(217, 119, 6, 0.16); }
html[data-theme='dark'] .type-chip.type-ext { color: #f0b357; background: rgba(217, 119, 6, 0.24); }
.ext-go-badge { text-decoration: none; }
/* 函数判题（2026-10-13）：徽标靛蓝——实现 Solution 类，答案 return 回来 */
.type-chip.type-fn { color: #4f46e5; background: rgba(79, 70, 229, 0.14); }
html[data-theme='dark'] .type-chip.type-fn { color: #818cf8; background: rgba(79, 70, 229, 0.24); }
.ext-card { margin: 12px 0 24px; padding: 8px 14px; background: var(--surface);
  border: 1px solid var(--border); border-left: 4px solid #d97706; border-radius: var(--r);
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.ext-card .ext-head { font-weight: 700; font-size: 13px; }
.obj-result { margin-top: 14px; padding: 12px 14px; border-radius: var(--r-sm); font-size: 14px;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.obj-result b { font-weight: 700; }
.obj-result.ac { background: var(--ac-soft); color: var(--ac); }
.obj-result.fail { background: var(--danger-soft); color: var(--danger); }
.obj-result.wait { background: var(--brand-soft); color: var(--brand); }
/* 解析块（知识点自拟题的三层解析；pdoc.explanation）——判分后展开，重做/未公布时隐藏 */
.obj-explain { margin-top: 14px; padding: 14px 16px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2); font-size: 14px; line-height: 1.75; }
.obj-explain-head { font-weight: 600; color: var(--text); margin-bottom: 8px; }
.obj-explain-body > :first-child { margin-top: 0; }
.obj-explain-body > :last-child { margin-bottom: 0; }
.obj-explain-body p, .obj-explain-body ul, .obj-explain-body ol { margin: 8px 0; }
.obj-explain-body ul, .obj-explain-body ol { padding-left: 22px; }
.obj-explain-body h4, .obj-explain-body h5 { margin: 14px 0 6px; font-size: 14px; color: var(--text); }
.obj-explain-body code { background: var(--surface-3); padding: 1px 5px; border-radius: 4px; font-size: .92em; }
.obj-explain-body pre { background: var(--surface-3); padding: 10px 12px; border-radius: var(--r-sm); overflow-x: auto; }
.obj-explain-body blockquote { margin: 8px 0; padding: 2px 0 2px 12px; border-left: 3px solid var(--brand-soft); color: var(--text-2); }
.obj-recs { margin-top: 18px; }
@media (max-width: 760px) {
  .obj-wrap .problem-head, .obj-main { padding-left: 14px; padding-right: 14px; }
  .obj-opt { flex: 1 1 0; justify-content: center; min-width: 0; padding: 12px 10px; }
  .obj-li { padding: 9px 10px 9px 44px; line-height: 1.7; }
  .obj-li-key { left: 9px; top: 8px; width: 26px; height: 26px; }
  .obj-li:has(.obj-li-flag) { padding-right: 92px; }
  /* 手机上徽章收成只有图标（文字藏掉）：行宽有限，内容是主角 */
  .obj-li-flag { padding: 3px 7px; }
  .obj-li-flag .obj-li-flag-t { display: none; }
  .obj-li-flag svg { width: 14px; height: 14px; }
}

/* ============ 笔记「复制为图片」的分享卡（2026-09-28 用户要求） ============
   卡片先在**视口外**排版（.nd-stage 钉在 -20000px），再整块序列化成 SVG(foreignObject) → <img>
   → canvas → PNG（见 public/app.js 的 ndNotePng）。宽度写死 880px：出图与窗口宽度无关，
   手机上点出来的图和桌面上是同一张。 */
.nd-stage { position: fixed; left: -20000px; top: 0; width: 880px; pointer-events: none; z-index: -1; }
.nd-card { width: 880px; box-sizing: border-box; padding: 30px 34px 22px; background: var(--surface);
  color: var(--text); font-family: var(--sans); font-size: 15px; line-height: 1.75; }
.nd-head { display: flex; align-items: center; gap: 7px; margin-bottom: 16px; font-size: 13px; color: var(--text-3); }
.nd-head b { color: var(--text-2); font-size: 13.5px; }
.nd-logo { width: 22px; height: 22px; border-radius: 7px; display: inline-grid; place-items: center;
  font-size: 12px; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, var(--brand), color-mix(in srgb, var(--brand) 60%, #7c3aed)); }
.nd-who { display: flex; align-items: center; gap: 9px; margin-bottom: 14px; }
.nd-who .who-name { font-size: 14.5px; font-weight: 650; color: var(--text); }
.nd-who .who-sub { font-size: 12.5px; color: var(--text-3); }
.nd-title { margin: 0 0 12px; font-size: 21px; font-weight: 650; line-height: 1.4; color: var(--text); }
.nd-body { padding-top: 16px; border-top: 1px solid var(--border); }
.nd-body .statement { max-width: none; font-size: 15px; line-height: 1.78; overflow-wrap: anywhere; }
.nd-body .md-scroll-x { overflow: visible; }          /* 图里没有横向滚动条：表格直接铺开 */
.nd-body pre { overflow: visible; white-space: pre-wrap; overflow-wrap: anywhere; }
.nd-body .copy-btn { display: none; }                 /* 图里的「复制」按钮没意义 */
.nd-foot { display: flex; justify-content: space-between; gap: 10px; margin-top: 22px; padding-top: 12px;
  border-top: 1px solid var(--border); font-size: 12px; color: var(--text-3); }

/* 出图后的浮层（http 访问写不了剪贴板，退回「看图 + 下载 / 右键复制」） */
.nd-modal-card { max-width: 780px; }
.nd-tip { font-size: 12.5px; color: var(--text-3); }
.nd-shot { max-height: 56vh; overflow: auto; margin: 10px 0 2px; border: 1px solid var(--border);
  border-radius: var(--r-sm); background: var(--surface-2); }
.nd-shot img { display: block; width: 100%; height: auto; }

/* ---------- 42) 成绩单分享链接 + 问题记录助手（2026-09-29） ---------- */
/* 详情页右上角的「家长链接」框：链接输入框 + 复制 + 关闭分享，横排塞进 head-right */
.share-inline { display: inline-flex; align-items: center; gap: 6px; vertical-align: middle; }
.share-inline .input { width: 300px; max-width: 34vw; font-family: var(--mono); font-size: 12px; }

/* 分享页（家长手机打开，2026-10-01 用户钦定「分享链接一定要兼容手机端」）：
   2026-10-05 视觉重做后全部规则移到文末 47) 节 .share-page 段，这里不再留旧表格覆盖。 */
/* 私信侧栏的「问题记录」隐藏助手行（只有站长渲染） */
.pm-row.pm-helper { border-bottom: 1px solid var(--border); margin-bottom: 4px; }
.pm-row.pm-helper .pm-row-name { display: inline-flex; align-items: center; gap: 6px; }
.pm-msg.issue .issue-st { color: var(--warn); font-weight: 650; }
.pm-msg.issue.issue-done .issue-st { color: var(--ac); }
.pm-msg.issue.issue-done .pm-body { opacity: .62; }   /* 已解决的记录淡一点，未解决的更醒目 */

/* ---------- 43) 文件 OI 赛制（2026-09-29） ---------- */
/* 工作台与客观题同一套「无编辑口」（board-mode 藏 ed-body/run-panel）：ed-top 只留「文件 OI」标签 */
.froi-workbench .ed-top { display: none; }   /* FROI 无可操作项（语言/重置/提交全藏），整条收掉 */
.froi-workbench .ed-body { display: none; }  /* 2026-10-02 用户钦定：文件OI 题目页不留编辑器与提交入口 */
.froi-workbench .board-panel { display: flex; flex: 1; min-height: 0; }
.froi-workbench .board-panel[hidden] { display: none; }
.froi-workbench .board-panel { display: flex; flex: 1; min-height: 0; }
.froi-workbench .board-panel[hidden] { display: none; }
.froi-workbench .fio { display: inline-flex; }
.froi-workbench .ed-top .dd,
.froi-workbench .ed-top #draft-tip,
.froi-workbench .ed-top #btn-reset,
.froi-workbench .ed-top #btn-submit,
.froi-workbench .ed-top #bd-open { display: none; }   /* 画板常驻，开关钮多余 */
.froi-workbench .fio { display: inline-flex; }
.froi-workbench .obj-type { cursor: default; }
.froi-workbench #bd-close { display: none; }
.froi-workbench .run-panel { display: none; }    /* 无编辑器就没有「跑样例」，面板一并收 */
/* 手机端（2026-10-16 用户报「打开题目被自动带到画板」）：画板改为**点开才出现**——
   进页面永远停在题面/编辑器上（board-embed.js 收起常开面板、跳过「上次开着」的记忆口径）。
   这里把客观题/文件OI 在桌面藏掉的「画板」开关钮放开（放在上面那批规则之后才能赢同权重），
   想画点一下、再点一下收起（bd-open 本身就是开合开关）。桌面观感一字不动。 */
@media (max-width: 760px) {
  .obj-workbench .ed-top #bd-open { display: inline-flex; }
  .froi-workbench .ed-top { display: flex; }     /* 桌面整条藏掉；手机只留「画板」钮 */
  .froi-workbench .ed-top #btn-fs { display: none; }
  .froi-workbench .ed-top #bd-open { display: inline-flex; }
}
/* 上传面板（替代编辑器，右栏上半） */
.froi-panel { padding: 14px 16px 16px; border-bottom: 1px solid var(--border); background: var(--surface); overflow: auto; }
/* 观感优化（2026-10-01 用户「有点丑」）：考号卡片化居左、步骤/规则分节留白、按钮等高一排对齐 */
.froi-no-row { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.froi-no { font-family: var(--mono); font-size: 22px; font-weight: 700; letter-spacing: .08em;
  color: var(--brand); background: var(--brand-soft); border: 1px dashed color-mix(in srgb, var(--brand) 45%, transparent);
  border-radius: var(--r-sm); padding: 4px 14px; cursor: text; user-select: all; }
.froi-steps { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 12px 14px; margin-bottom: 12px; }
.froi-steps > .muted small:, .froi-steps .muted.small { display: block; margin-bottom: 8px; }
/* 目录树（2026-10-03 用户「字符树有点丑」）：pre 字符画换成 HTML 树——
   文件夹/文件/代码图标 + 竖向引导线 + 层次配色；行高紧凑，8 题与原字符树等高。 */
.ftree { margin: 0 0 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); font-size: 13px; overflow: auto; }
.ft-row { display: flex; align-items: center; gap: 7px; padding: 2.5px 7px; color: var(--text-2); line-height: 1.5; }
.ft-row svg { width: 15px; height: 15px; flex: none; opacity: .72; }
.ft-kids { margin-left: 10px; padding-left: 10px; border-left: 1px solid var(--border-strong); }
.ft-root { color: var(--text); font-weight: 650; margin-bottom: 2px; }
.ft-root svg { color: var(--brand); opacity: 1; }
.ft-root .mono { font-size: 13.5px; letter-spacing: .03em; }
.ft-dirname { color: var(--text); font-weight: 550; }
.ft-dirname svg { color: var(--brand); opacity: .85; }
.ft-row:not(.ft-root):not(.ft-dirname) svg { color: var(--text-3); }
.froi-rules { margin: 0; padding-left: 18px; line-height: 1.9; }
.froi-up { display: flex; align-items: stretch; gap: 10px; flex-wrap: wrap; margin-top: 2px; }
.froi-up .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 38px; }
.froi-result { margin-top: 10px; }
.froi-no-tag { margin-left: 6px; font-family: var(--mono); }

/* ---------- 45) 作业/比赛列表：题库同款应用式布局（2026-09-29 用户要求） ---------- */
/* 借鉴题库 .pl-app：bare 外壳(100vh 不滚) + 左目录|拖缝|主区；主区工具条钉死、.ct-scroll 自己滚。
   复用 .list-split 类名（拖宽 JS 往它写 --scope-w）与 .scope-side/.scope-gutter 全套。 */
.list-split.ct-app { height: calc(100vh - var(--nav-h)); padding: 14px 20px 0; box-sizing: border-box;
  overflow: hidden; align-items: stretch; }   /* stretch：主区必须拿满高（内滚链的根）；侧栏单独 start 自适应 */

.ct-app .scope-gutter { grid-column: 2; }
.list-split.ct-app.no-side { grid-template-columns: minmax(0, 1fr); }
.ct-main { min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.ct-main .ct-tools { flex: none; margin: 0 0 10px; justify-content: space-between; gap: 10px; }
/* 左右两块（2026-09-29 用户报「换行后排序组掉到第二行左端，与首行错位显乱」）：
   左=计数+搜索固定；右=全部筛选组靠右，换行时仍 justify-end 对齐右缘，不飘到左边 */
.ct-main .ct-left { display: flex; align-items: center; gap: 10px; flex: none; }
.ct-main .ct-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.ct-main .ct-tools .count { font-size: 12.5px; color: var(--text-3); white-space: nowrap; }
.ct-scroll { flex: 1; min-height: 0; overflow-y: auto; padding-bottom: 18px; }
/* 目录卡片化（题库 rail 同款）：白卡 + 标题小字 + 行 hover/on 与右侧计数 */
.ct-app .scope-side { position: static; align-self: start; height: auto; max-height: 100%; min-height: 0;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  box-shadow: var(--sh-1); padding: 12px 12px 10px; border-right: 1px solid var(--border); }
.ct-app .scope-head { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-3); padding: 0 4px 10px; margin-bottom: 8px; }
.ct-app .scope-tree { display: flex; flex-direction: column; gap: 1px; }
.ct-app .scope-item { justify-content: space-between; padding: 5px 8px; font-size: 13px; }
.ct-app .scope-item .n { flex: none; color: var(--text-3); font-size: 12px; font-variant-numeric: tabular-nums; }
.ct-app .scope-item.on .n { color: var(--brand); }
/* 选中态对齐 rail-item.on：底色 + 品牌字，去掉旧版左侧竖条（缩进层级的竖线轨保留） */
.ct-app .scope-item.on::before { display: none; }
.ct-app .scope-sep { height: 1px; background: var(--border); margin: 6px 2px; }
/* 日视图（2026-09-29 用户钦定 v2）：一天一节、节头吸顶、空日子不存在 */
.day-sec { margin-bottom: 22px; }
.day-head { position: sticky; top: -2px; z-index: 5; display: flex; align-items: center; gap: 8px;
  padding: 7px 2px; background: var(--bg); font-size: 13px; }
.day-head .day-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--text-3); }
.day-head.today .day-dot { background: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
.day-head b { font-weight: 650; color: var(--text); }
.day-head.today b { color: var(--brand); }
.day-head .n { margin-left: auto; color: var(--text-3); font-size: 12px; font-variant-numeric: tabular-nums; }
.day-cards { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.day-today-line { display: flex; align-items: center; gap: 12px; margin: 20px 0;
  color: var(--text-3); font-size: 12px; white-space: nowrap; }
.day-today-line::before, .day-today-line::after { content: ''; flex: 1; height: 1px; background: var(--border); }
@media (max-width: 760px) {
  /* 手机回退（题库同款）：解锁流式，主区自己不滚交给整页 */
  .list-split.ct-app { display: block; height: auto; padding: 10px 12px 0; overflow: visible; }
  .ct-scroll { overflow: visible; }
  .ct-main { display: block; }
}


/* ---------- 44) 私信：拖动夹缝 + Markdown 工具栏 + 工具条下移（2026-09-29） ---------- */
/* ① 竖缝：侧栏 ↔ 聊天区（左右拖调宽）；② 横缝：消息区 ↔ 输入区（上下拖调输入区高度） */
.pm-gutter { flex: none; width: 6px; cursor: col-resize; border-radius: 99px; transition: background .13s; }
.pm-gutter:hover, body.is-col-resize .pm-gutter { background: var(--brand); opacity: .55; }
.pm-hgutter { flex: none; height: 6px; margin: 0 14px; cursor: row-resize; border-radius: 99px; transition: background .13s; }
.pm-hgutter:hover, body.is-row-resize .pm-hgutter { background: var(--brand); opacity: .55; }
body.is-col-resize { cursor: col-resize; user-select: none; }
body.is-row-resize { cursor: row-resize; user-select: none; }
/* 输入区被拉高时内部跟着伸缩（写/预览两块都要能涨） */
.pm-thread .pm-foot { display: flex; flex-direction: column; }
/* 固定件不参与压缩（foot 定高时「写/预览」不被压扁，2026-09-29 用户报） */
.pm-foot .pm-seg, .pm-foot .pm-mdtools, .pm-foot .pm-tip, .pm-foot .pm-actions { flex: none; }
/* 「问题记录」面板不参与横缝定高：foot 用自然高度（与私信输入区一致） */
.pm-thread:has(#issue-text) .pm-hgutter { display: none; }
.pm-thread .pm-foot[style*="height"] #pm-text,
.pm-thread .pm-foot[style*="height"] #pm-prev { flex: 1 1 auto; min-height: 0; }
/* ② Markdown 工具标（与笔记同一套按钮，顶层 noteToolBtn 生成） */
.pm-mdtools { display: flex; align-items: center; gap: 2px; flex-wrap: wrap; margin: 0 0 6px; }
.pm-mdtools .note-tool { border: 0; background: none; padding: 4px 5px; cursor: pointer; color: var(--text-3);
  border-radius: var(--r-sm); display: inline-flex; }
.pm-mdtools .note-tool:hover { background: var(--surface-3); color: var(--text); }
.pm-mdtools .note-tool svg { width: 15px; height: 15px; }
.pm-mdtools .note-tools-sep { width: 1px; height: 14px; background: var(--border); margin: 0 4px; }
/* ③ 消息工具条（复制/编辑/历史）挪到气泡下方：顺着阅读方向，不用回滚 */
.pm-tools { margin: 3px 0 0; }
/* 「问题记录」助手的输入框：与私信 #pm-text 同款（裸 textarea 没样式时是一条细带，2026-09-29 用户报） */
#issue-text { width: 100%; box-sizing: border-box; min-height: 96px; max-height: 260px; resize: vertical;
  font: inherit; font-size: 13.5px; line-height: 1.7; padding: 10px 12px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm); }
#issue-text:focus { outline: none; border-color: var(--brand); }
/* 横缝把输入区拉高后，两个输入框都要跟着撑满（height 交给 flex，别被 textarea 自身高度顶住） */
.pm-thread .pm-foot[style*="height"] #pm-text,
.pm-thread .pm-foot[style*="height"] #pm-prev { flex: 1 1 auto; min-height: 0; height: auto; }
@media (max-width: 760px) {
  .pm-gutter, .pm-hgutter { display: none; }   /* 手机竖排布局，两条缝都没有意义 */
}

/* 文件 OI 不合规报告（2026-10-03 用户钦定「美化+说明到底是什么不规范」）：
   标题行（徽章+后果）→ 逐条问题列表 → 「本次实际收到」诊断区，三段式，不再是一长串红字。 */

/* ---------- 47) 成绩单分享页视觉重做（2026-10-05 用户「有点丑」+ 钦点 Element UI 风格） ----------
   结构（pages/contests.mjs shareBoardPage）：渐变报告头（品牌蓝→紫，与站内渐变同族）+
   Element 式卡片表格（名次奖牌圈 / 姓名头像 / 得分胶囊：AC 绿·部分分橙·零分灰·未交 –）+
   「题目对照」栅格图例。全部走 --var，深浅色自适应；手机端学生列钉死左缘（沿用旧口径）。 */
.share-page { max-width: 1160px !important; }   /* 20 题的大榜 1040px 太挤，放宽一档 */
.share-page { --rk-gold-c:#b45309; --rk-gold-bg:rgba(217,130,0,.14);
  --rk-sil-c:#5b6270; --rk-sil-bg:rgba(91,98,112,.13);
  --rk-brz-c:#95542a; --rk-brz-bg:rgba(149,84,42,.14); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .share-page { --rk-gold-c:#f0b429; --rk-sil-c:#9aa3b2; --rk-brz-c:#d99a6c; }
}
:root[data-theme="dark"] .share-page { --rk-gold-c:#f0b429; --rk-sil-c:#9aa3b2; --rk-brz-c:#d99a6c; }

/* 报告头：上=渐变横幅（类型/状态/标题），下=白底元信息条（开始/截止/题数/人数） */
.share-page .sh-hero { background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--sh-1); overflow: hidden; }
.share-page .sh-band { padding: 18px 22px 16px; color: #fff;
  background: linear-gradient(135deg, var(--brand), color-mix(in srgb, var(--brand) 55%, #7c3aed)); }
.share-page .sh-band-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 9px; }
.share-page .sh-kind { font-size: 12px; font-weight: 550; padding: 2px 10px; border-radius: 999px;
  background: rgba(255,255,255,.18); border: 1px solid rgba(255,255,255,.38); }
.share-page .sh-phase { display: inline-flex; align-items: center; gap: 6px; font-size: 12px;
  padding: 2.5px 10px; border-radius: 999px; background: rgba(255,255,255,.16); border: 1px solid rgba(255,255,255,.32); }
.share-page .sh-phase i { width: 6px; height: 6px; border-radius: 99px; background: currentColor; }
.share-page .sh-phase.sh-live i { background: #86ffb9; box-shadow: 0 0 0 3px rgba(134,255,185,.25); }
.share-page .sh-doc { margin-left: auto; font-size: 12px; opacity: .85; }
.share-page .sh-title { margin: 0; font-size: 21px; font-weight: 700; line-height: 1.35; color: #fff; overflow-wrap: anywhere; }
.share-page .sh-meta { display: flex; flex-wrap: wrap; gap: 8px 28px; padding: 13px 22px; }
.share-page .sh-meta-item { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; }
.share-page .sh-meta-item svg { color: var(--brand); opacity: .8; flex: none; }
.share-page .sh-ml { color: var(--text-3); font-size: 12.5px; }
.share-page .sh-mv { font-weight: 600; font-variant-numeric: tabular-nums; }

/* Element 式卡片（排行榜 / 题目对照 / 空态共用外壳） */
.share-page .sh-card { margin-top: 16px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--sh-1); overflow: hidden; }
.share-page .sh-hd { display: flex; align-items: center; gap: 9px; padding: 12px 16px; border-bottom: 1px solid var(--border); }
.share-page .sh-hd h2 { margin: 0; font-size: 15px; font-weight: 650; }
.share-page .sh-hd-ic { display: grid; place-items: center; width: 26px; height: 26px; border-radius: 8px;
  background: var(--brand-soft); color: var(--brand); flex: none; }
.share-page .sh-count { margin-left: auto; font-size: 12px; color: var(--text-2);
  background: var(--surface-3); border-radius: 999px; padding: 2.5px 10px; white-space: nowrap; }

/* 榜单表：表头灰底 + 行 hover（Element 口味，不斑马纹——分组行会打乱奇偶） */
.share-page .sh-board { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 560px; }
.share-page .sh-board thead th { position: sticky; top: 0; z-index: 2; background: var(--surface-2);
  color: var(--text-3); font-size: 12px; font-weight: 600; letter-spacing: .02em;
  padding: 10px 12px; border-bottom: 1px solid var(--border); white-space: nowrap; }
.share-page .sh-board td { padding: 9px 12px; border-bottom: 1px solid var(--border); }
.share-page .sh-board tbody tr:last-child td { border-bottom: 0; }
.share-page .sh-board tbody tr:not(.sh-grp):hover td { background: var(--surface-2); }
.share-page .sh-board .num { text-align: center; font-variant-numeric: tabular-nums; }
/* 列类名必须是 col-rk，不能叫 rk —— 圆牌 span 用的就是 .rk（display:inline-grid），
   类名撞车会把 td 的表格盒也打塌成 20px 内联网格，行分隔线画穿圆牌（2026-10-06 实测事故） */
.share-page .sh-board th.col-rk { width: 52px; }
/* 「分组」列（2026-10-14 用户钦定）：组名可能很长，限宽省略号，悬停看全名（title 由模板给） */
.share-page .sh-board th.grp { white-space: nowrap; }
.share-page .sh-board td.grp { max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text-2); font-size: 12px; }
.share-page .rk { display: inline-grid; place-items: center; min-width: 22px; height: 22px; padding: 0 4px;
  border-radius: 999px; font-size: 12px; font-weight: 600; color: var(--text-3); }
.share-page .rk-1 { background: var(--rk-gold-bg); color: var(--rk-gold-c); }
.share-page .rk-2 { background: var(--rk-sil-bg); color: var(--rk-sil-c); }
.share-page .rk-3 { background: var(--rk-brz-bg); color: var(--rk-brz-c); }
.share-page td.st { white-space: nowrap; }
.share-page .sh-who { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.share-page .sh-ava { display: grid; place-items: center; width: 24px; height: 24px; border-radius: 999px;
  background: var(--brand-soft); color: var(--brand); font-size: 12px; font-weight: 650; flex: none; }
.share-page .sh-name { font-weight: 550; }
.share-page .sc { display: inline-grid; place-items: center; min-width: 26px; height: 20px; padding: 0 7px;
  border-radius: 999px; font-size: 12.5px; font-weight: 650; }
.share-page .sc-ac { background: var(--ac-soft); color: var(--ac); }
.share-page .sc-part { background: var(--warn-soft); color: var(--warn); }
.share-page td.sh-none { color: var(--text-3); opacity: .55; }
.share-page td.sh-zero { color: var(--text-3); }
.share-page td.tt b { font-size: 13.5px; }
.share-page td.sv { color: var(--text-2); font-weight: 600; }
.share-page tr.sh-grp td { background: var(--surface-2); color: var(--text-3); font-size: 12px;
  font-weight: 600; padding: 6px 16px; text-align: left; }

/* 题目对照：A/B/C 字块 + 题名，栅格铺开（替代旧版「题目顺序」长段落） */
.share-page .sh-legend { display: grid; grid-template-columns: repeat(auto-fill, minmax(235px, 1fr));
  gap: 8px 16px; padding: 14px 16px; }
.share-page .sh-lg { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 12.5px; }
.share-page .sh-lg b { flex: none; display: grid; place-items: center; min-width: 20px; height: 20px;
  padding: 0 4px; border-radius: 6px; background: var(--surface-3); color: var(--text-2);
  font-family: var(--mono); font-size: 11.5px; font-weight: 600; }
.share-page .sh-lg span { color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.share-page .sh-empty { padding: 48px 20px; text-align: center; color: var(--text-3); }
.share-page .sh-foot { margin: 18px 4px 8px; text-align: center; font-size: 12px; color: var(--text-3); }

/* 详情页榜单（作业/比赛）复用整套 47 节：容器挂 share-page 类即可（pages/contests.mjs scoreTable）。
   这几条是详情页独有的状态：本人行高亮（原 .table tr.me 的平移）+ 计数筛空的红色提示 + 头部可换行 */
.share-page .sh-board tbody tr.me td { background: var(--brand-soft); }
.share-page .sh-board tbody tr.me:hover td { background: var(--brand-soft); }
.share-page .sh-count.is-empty { color: var(--danger); }
.share-page .sh-hd { flex-wrap: wrap; row-gap: 6px; }

/* 手机端（≤760px）：小榜整表放下，题多照旧横滑但「名次+学生」两列钉死左缘
   （2026-10-05 实测：只钉学生列的话名次会滑走；两列都钉要求名次列宽定死，
   否则表头 52 / 表身 34 不齐，偏移对不上。40px = 奖牌圈 20 + 左右 padding 7×2 + 余量） */
@media (max-width: 760px) {
  .share-page .sh-board { min-width: 0; }
  .share-page .sh-board thead th, .share-page .sh-board td { padding: 8px 7px; }
  .share-page .sh-board th.col-rk, .share-page .sh-board td.col-rk {
    width: 40px; min-width: 40px; max-width: 40px; }
  .share-page .sh-board thead th.col-rk, .share-page .sh-board tr:not(.sh-grp) td.col-rk,
  .share-page .sh-board thead th.st, .share-page .sh-board tr:not(.sh-grp) td.st {
    position: sticky; box-shadow: inset -1px 0 0 var(--border); }
  .share-page .sh-board thead th.col-rk { left: 0; top: 0; z-index: 4; background: var(--surface-2); }
  .share-page .sh-board tr:not(.sh-grp) td.col-rk { left: 0; z-index: 3; background: var(--surface); }
  .share-page .sh-board thead th.st { left: 40px; top: 0; z-index: 4; background: var(--surface-2); }
  .share-page .sh-board tr:not(.sh-grp) td.st { left: 40px; z-index: 3; background: var(--surface); }
  .share-page .sh-name { display: block; max-width: 84px; overflow: hidden; text-overflow: ellipsis; }
  .share-page .sh-ava { width: 20px; height: 20px; font-size: 11px; }
  .share-page .sc { min-width: 22px; height: 18px; font-size: 12px; padding: 0 5px; }
  .share-page .rk { min-width: 20px; height: 20px; font-size: 11.5px; }
  .share-page .sh-doc { display: none; }   /* 顶行放不下：文档标注藏掉，元信息条里有 */
  .share-page .sh-band { padding: 15px 14px 13px; }
  .share-page .sh-title { font-size: 18px; }
  .share-page .sh-meta { gap: 6px 16px; padding: 11px 14px; }
  /* 固定 2 列（2026-10-05 实测：auto-fill minmax(160px,1fr) 在 360~390px 可用宽 294~364px
     时只差几像素就掉成单列，20 行拉满一屏；minmax(0,1fr) 让超长题名走省略号不撑破） */
  .share-page .sh-legend { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 10px; padding: 12px; }
}

/* ==================== 课程题单（2026-10-08 新增「课程」区） ==================== */
/* 列表：2026-10-08 曾钦定竖向单列长条（仿作业时间线）——实测全宽卡里内容只占左 420px，
   右侧大片留白、159 张卡拉成超长一列（2026-10-17 用户报「有点丑」）。
   改 **auto-fill 网格**：桌面 3 列、中屏 2 列、手机自然落回单列（minmax 下限兜底，不写断点）。 */
.course-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; padding-top: 5px; padding-bottom: 8px; }
/* 顶部垫 5px：滚动到顶时第一张卡的上边框完整可见（hover 再上移 1px，不留缝会被容器裁掉——用户实测抓到） */
.co-card { display: flex; flex-direction: column; gap: 10px; padding: 15px 17px;
  border: 1px solid var(--border); border-radius: var(--r); background: var(--surface);
  box-shadow: var(--sh-1); color: var(--text); min-width: 0; }
.co-card:hover { border-color: var(--brand); box-shadow: var(--sh-2); transform: translateY(-1px); }
.co-card:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.co-top { display: flex; align-items: center; gap: 8px; min-width: 0; }
.co-name { font-size: 15.5px; font-weight: 600; letter-spacing: -.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.co-scope { margin-left: auto; flex: none; }
/* 老师视角课程卡的右上角「N 题」小徽章（学生卡不带——它的题数在进度条那行里） */
.co-n { margin-left: auto; flex: none; display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; color: var(--text-3); background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 999px; padding: 3px 10px; font-variant-numeric: tabular-nums; }
.co-n svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.co-card:hover .co-n { color: var(--brand); border-color: var(--brand); }
/* 完成度百分比徽章（2026-10-17 美化）：只在做过的课上亮，右上角锚住卡片的视觉重心；
   状态色由 .is-started/.is-done 接管，素卡（没动过）不出现。 */
.co-pct { margin-left: auto; flex: none; font-size: 12px; font-weight: 700; color: var(--brand);
  font-variant-numeric: tabular-nums; letter-spacing: .01em; }
/* 三态：进行中=品牌蓝徽章；完成=绿徽章+绿描边淡染；未动/空课=素卡不加态。
   百分比文字与「✓ 已通过」行是状态的文字表达，颜色只是第二通道（不靠颜色独扛）。 */
.co-card.is-done { border-color: color-mix(in srgb, var(--ac) 34%, var(--border)); }
.co-card.is-done .co-pct { color: var(--ac); }
.co-meta { display: flex; align-items: center; gap: 12px; font-size: 12px; color: var(--text-2); }
.co-mine { display: inline-flex; align-items: center; gap: 4px; }
.co-mine.is-done { color: var(--ac); font-weight: 600; }
/* 进度条：AC 绿填充 + 发丝轨道；宽度由服务端内联（无 JS 动画依赖），过渡只服务进度更新。
   2026-10-17 随网格化撤掉 max-width:420px——卡内通栏，右侧不再留白。 */
.co-prog { height: 6px; border-radius: 3px; background: var(--surface-3); overflow: hidden; }
.co-prog > i { display: block; height: 100%; border-radius: 3px; background: var(--ac); transition: width .3s ease; }
@media (prefers-reduced-motion: reduce) {
  .co-card:hover { transform: none; }
  .co-prog > i { transition: none; }
}

/* 详情页「题目 | 榜单」页签（作业/比赛/课程共用，2026-10-08 用户钦定）。
   分段控件：与题目页「标准｜文件」滑块同族——胶囊槽底 + 活动片浮起（surface 白底 + sh-1）。 */
.dt-tabs { display: inline-flex; gap: 4px; padding: 4px; margin: 2px 0 16px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface-2); }
.dt-tab { display: inline-flex; align-items: center; gap: 6px; padding: 7px 18px;
  border: 0; border-radius: 7px; background: transparent; color: var(--text-2);
  font-size: 13.5px; font-weight: 600; cursor: pointer; }
.dt-tab:hover { color: var(--text); }
.dt-tab.on { background: var(--surface); color: var(--text); box-shadow: var(--sh-1); }
.dt-tab:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.dt-panel[hidden] { display: none; }
/* 手机：页签通栏（两片各半，拇指好点） */
@media (max-width: 560px) {
  .dt-tabs { display: flex; width: 100%; }
  .dt-tab { flex: 1; justify-content: center; }
}
/* 文件名小签豁免（2026-10-08 课程题单）：.ct-prob .tags 默认隐藏是作业/比赛时代的口径
   （文件名在工作台里看）；课程题单没有整包上传，学生开题前就得知道文件名——
   带了 .has-chip 的行把小签放出来。 */
.ct-prob .tags.has-chip { display: flex; gap: 6px; }

/* 课程列表分节（2026-10-08 知识块化）：节头仿作业日视图的 day-head（圆点 + 块名 + 计数） */
.co-sec { margin-bottom: 22px; }
.co-sec-head { display: flex; align-items: center; gap: 8px; padding: 4px 2px 10px; font-size: 14.5px; }
.co-sec-head i { width: 8px; height: 8px; border-radius: 50%; background: var(--brand); flex: none; }
.co-sec-head .n { margin-left: auto; font-size: 12px; color: var(--text-3); font-weight: 400; }

/* ---------------- 知识块管理页（/admin/kb） ---------------- */
.kb-new { display: flex; gap: 10px; max-width: 560px; }
.kb-new .input { flex: 1; }
.kb-list { display: flex; flex-direction: column; gap: 10px; }
/* 块行：把手 + 行内改名 + 计数 + 删除；下面挂块内题单 */
.kb-row.kb-block { border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); padding: 10px 12px; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.kb-row.kb-block > .kb-name { max-width: 240px; font-weight: 600; }
.kb-row.kb-block > .kb-del { margin-left: auto; }
.kb-kids { display: flex; flex-direction: column; gap: 6px; flex-basis: 100%; padding: 4px 0 2px 18px; }
.kb-row.kb-tid { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2); font-size: 13.5px; }
.kb-row.kb-tid > .kb-out { margin-left: auto; opacity: 0; transition: opacity .15s; }
.kb-row.kb-tid:hover > .kb-out, .kb-row.kb-tid:focus-within > .kb-out { opacity: 1; }
.kb-uncat { margin-top: 18px; }
.kb-uncat-head { font-weight: 700; font-size: 13.5px; padding: 6px 2px; color: var(--text-2); }
.kb-uncat .kb-kids { padding-left: 2px; }
/* 把手：hover 才显形（行内不吵）；抓取光标 + 键盘可达（tabindex+方向键） */
.kb-grip { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 26px; border-radius: 5px; color: var(--text-3); cursor: grab; touch-action: none; flex: none; }
.kb-grip:hover, .kb-grip:focus-visible { background: var(--surface-3); color: var(--text); outline: none; }
.kb-grip:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
/* 拖拽 v2（2026-10-08 用户否掉 v1「左右晃、没有浮起感」）：
   浮起克隆（放大+阴影+微倾斜，跟随指针）+ 原位置虚线占位条推开其它行；原行 display:none。 */
.kb-ghost { position: fixed; z-index: 90; pointer-events: none; background: var(--surface);
  border: 1px solid var(--brand); border-radius: var(--r); box-shadow: var(--sh-2);
  transform: scale(1.03) rotate(.4deg); opacity: .97; padding: 8px 12px; display: flex; align-items: center; gap: 8px; }
.kb-ghost .kb-kids, .kb-ghost .kb-del, .kb-ghost .kb-out, .kb-ghost .kb-n { display: none !important; }
/* 占位视觉对齐 Element/Ant 的「空槽」惯例：与原位置同高的圆角虚线框 + 浅底，
   表示「这一整块会放到这里」（上一版只有一条居中线，用户否）。 */
.kb-ph { border: 2px dashed var(--brand); border-radius: var(--r); background: var(--brand-soft); opacity: .55; }
.kb-src { display: none !important; }
@media (prefers-reduced-motion: reduce) { .kb-row.kb-tid > .kb-out { transition: none; } }

/* ---------- 免登录参赛页 /r/:token（2026-10-11 用户钦定） ----------
   独立外壳没有站点导航；观感全部复用 app.css 既有令牌（卡片/按钮/徽章/榜单表格），
   这里只补这套页面自己的骨架：名字门、考场顶栏、题目导航 chips、提交卡与结果面板。 */
.guest-page { max-width: 980px; }
.guest-foot { display: flex; justify-content: center; gap: 8px; padding: 22px 16px 30px; color: var(--text-3); font-size: 12.5px; }
/* 名字门（2026-10-12 重设计，用户「巨丑」反馈）：品牌锚点 + 徽章/元信息胶囊化 + 大输入全宽主按钮。
   说明文字压成一行（完整规则放 hint 的 hover title——用户钦定「说明放悬停」）。 */
/* 名字门 2026-10-12 二次美化：无大图标——标题即门面；卡片浮起 + 输入聚焦微光，入场轻动效 */
.guest-hero { position: relative; text-align: center; padding: 64px 12px 8px; }
.guest-hero::before { content: ''; position: absolute; top: -40px; left: 22%; right: 22%; height: 220px;
  background: radial-gradient(55% 100% at 50% 0%, color-mix(in srgb, var(--brand) 10%, transparent), transparent 70%);
  pointer-events: none; }
.guest-hero > * { position: relative; }
.guest-tags { display: flex; justify-content: center; gap: 6px; }
.guest-hero h1 { font-size: 34px; font-weight: 800; letter-spacing: -0.5px; line-height: 1.25; margin: 14px 0 16px; }
.guest-meta { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.g-pill { display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; border: 1px solid var(--border);
  border-radius: 999px; background: color-mix(in srgb, var(--surface) 72%, transparent); color: var(--text-2); font-size: 13px; }
.g-pill svg { width: 14px; height: 14px; flex: none; opacity: .75; }
.guest-gate { max-width: 520px; margin: 34px auto 48px; padding: 30px 28px 22px; border-radius: var(--r-lg);
  box-shadow: var(--sh-2); }
.guest-gate form { display: flex; flex-direction: column; gap: 12px; }
.g-label { font-size: 13px; font-weight: 600; color: var(--text-2); }
.guest-gate .guest-name { height: 48px; font-size: 16px; padding: 0 15px; border-radius: var(--r); }
.guest-gate .guest-name:focus { box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 15%, transparent); }
.guest-join { height: 48px; font-size: 15.5px; border-radius: var(--r); }
.guest-hint { margin-top: 14px; text-align: center; cursor: help; }
.guest-error { padding: 9px 12px; border-radius: var(--r); background: var(--danger-soft, rgba(229,72,77,.08)); border: 1px solid rgba(229,72,77,.35); color: var(--danger, #e5484d); font-size: 13.5px; margin-bottom: 12px; }
@media (prefers-reduced-motion: no-preference) {
  .guest-hero { animation: g-up .5s cubic-bezier(.2, .7, .3, 1) both; }
  .guest-gate { animation: g-up .5s cubic-bezier(.2, .7, .3, 1) .08s both; }
  @keyframes g-up { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
}

.guest-top { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 14px; padding: 4px 2px 12px; }
.guest-top-main { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }
.guest-title { font-size: 19px; }
.guest-top-right { display: flex; align-items: center; gap: 10px; }
.g-clock { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 13.5px; padding: 3px 10px; border-radius: 999px; background: var(--surface-2); border: 1px solid var(--border); }
.g-clock[data-state="live"] { color: var(--brand); border-color: var(--brand); }
.g-clock[data-state="over"] { color: var(--text-3); }
.g-me { font-size: 13px; color: var(--text-2); }
.g-me b { color: var(--text); }
.guest-top .inline { display: inline; }

.g-nav { display: flex; flex-wrap: wrap; gap: 8px; padding-bottom: 12px; }
.g-chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface); color: var(--text-2); font-size: 13px; max-width: 100%; }
.g-chip b { color: var(--brand); font-family: var(--mono, monospace); }
.g-chip:hover { border-color: var(--brand); color: var(--text); }
.g-chip.on { background: var(--brand-soft); border-color: var(--brand); color: var(--text); }
.g-chip .badge { margin-left: 2px; }
.g-sec { display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 13.5px; margin: 14px 0 10px; }
.g-sec::before { content: ""; width: 3px; height: 14px; border-radius: 2px; background: var(--brand); }
.g-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 14px; }
.g-tab { appearance: none; border: 0; background: none; padding: 8px 14px; font: inherit; font-size: 14px; color: var(--text-3); cursor: pointer; border-bottom: 2px solid transparent; }
.g-tab.on { color: var(--text); font-weight: 600; border-bottom-color: var(--brand); }
.g-statement { padding: 6px 20px 12px; overflow-x: auto; }
.g-statement .statement { max-width: none; }
.g-submit-card { margin-top: 14px; }
.g-ed-row { display: flex; gap: 10px; align-items: center; margin-bottom: 10px; }
.g-ed-row select { width: auto; }
.g-ed-row .btn { white-space: nowrap; }
.g-submit-card .CodeMirror { border: 1px solid var(--border); border-radius: var(--r); height: 420px; }
.g-actions { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.g-result { margin-top: 14px; }
.g-verdict { display: flex; align-items: center; gap: 10px; font-size: 15px; }
.g-score { font-size: 18px; }
.g-cases { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; max-height: 320px; overflow: auto; }
.g-case { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.g-ce { margin: 10px 0 0; padding: 10px 12px; background: var(--surface-2); border-radius: var(--r); overflow: auto; max-height: 260px; font-size: 12.5px; white-space: pre-wrap; }
.g-sample-out pre { margin: 4px 0 10px; padding: 10px 12px; background: var(--surface-2); border-radius: var(--r); overflow: auto; max-height: 180px; font-size: 12.5px; }
.g-opts { display: flex; flex-direction: column; gap: 8px; }
.g-opt { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r); cursor: pointer; }
.g-opt:hover { border-color: var(--brand); }
.g-opt input { accent-color: var(--brand); }
.g-opt-key { font-weight: 700; color: var(--brand); min-width: 18px; }

/* ---------- 考场全屏双栏（2026-10-12 用户钦定：与正式工作台同款「左题面右编辑」，只是头顶无站点导航） ----------
   .g-room = 视口高的 app 壳（顶栏/题目 chips/页签 三条固定，下面双栏各自内部滚动）；
   未开局（g-one）没有编辑区 → 单栏窄版。窄屏塌成单列、回归页面滚动。 */
.g-room { display: flex; flex-direction: column; height: 100vh; }
.g-room .guest-top { flex: none; flex-wrap: nowrap; align-items: center; gap: 12px;
  padding: 10px 16px; border-bottom: 1px solid var(--border); background: var(--surface); }
.g-room .guest-top-main { flex-wrap: nowrap; min-width: 0; flex: 1; }
.g-room .guest-title { font-size: 16.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.g-room .guest-top-right { flex: none; }
.g-room .g-nav { flex: none; flex-wrap: nowrap; overflow-x: auto; padding: 10px 16px; scrollbar-width: thin; }
.g-room .g-nav:empty { display: none; }
.g-room .g-tabs { flex: none; margin: 0 16px; }
.g-pane { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.g-pane[hidden] { display: none; }
.g-pane-narrow { flex: 1; min-height: 0; overflow: auto; width: 100%; max-width: 980px; margin: 0 auto; padding: 16px; }
.g-one .g-pane-narrow { padding-top: 30px; }
.g-ws { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.g-ws-left { min-width: 0; overflow: auto; padding: 16px 18px 30px; border-right: 1px solid var(--border); }
.g-ws-left .g-statement { padding: 0; }
.g-ws-right { min-width: 0; overflow: auto; padding: 14px 18px 22px; display: flex; flex-direction: column; }
/* 工作台形态（编程题）：右栏直接复用 .ws-right 全套（ed-top/ed-body/dock/board-mode 的样式与
   760px 移动规则全继承），这里只收边：零内衬、结果面板浮边距、画板摊开时藏结果面板。
   左栏同理复用 .ws-left/.tabs/.pane-body，padding 归 pane-body 管。 */
.g-ws-right.ws-right { padding: 0; overflow: hidden; }
.g-ws-right.ws-right .g-result { margin: 12px 14px 14px; flex: none; }
.g-ws-right.ws-right.board-mode .g-result { display: none; }
.g-ws-left.ws-left { padding: 0; border-right: 0; }
.g-ws { position: relative; }
.g-ws > .g-ws-left.ws-left { border-right: 1px solid var(--border); }
.g-ws-left.ws-left .g-ph { padding: 0 0 12px; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
/* 题头（题号+标题+状态徽章，与正式工作台同款） */
.g-ph { display: flex; align-items: center; gap: 10px; padding-bottom: 10px; border-bottom: 1px solid var(--border); margin-bottom: 14px; }
.g-ph-no { font-family: var(--mono); color: var(--brand); font-weight: 700; font-size: 18px; }
.g-ph-title { font-size: 17px; min-width: 0; }
@media (max-width: 900px) {
  .g-room { height: auto; min-height: 100vh; }
  .g-ws { grid-template-columns: 1fr; }
  .g-ws-left { border-right: 0; border-bottom: 1px solid var(--border); overflow: visible; }
  .g-ws-right { overflow: visible; }
  .g-ws-right.ws-right { overflow: visible; }
  .g-ws-right.ws-right .ed-body { flex: none; height: 55vh; }
  .g-ws-right .g-editor .CodeMirror { flex: none; height: 420px; }
  .g-pane-narrow { overflow: visible; }
}
@media (max-width: 720px) {
  .guest-top { flex-direction: column; align-items: flex-start; }
  /* 表单桌面端也已竖排（全宽主按钮），移动端无需再改 */
  .g-ed-row { flex-wrap: wrap; }
  .guest-title { font-size: 16px; }
}

/* 「发送到笔记」（提交记录行 → 我的笔记，2026-10-11 用户要求）：
   老师视角的记录行外包一层 flex 行（行本体 + 行尾「发到笔记」钮）。 */
.rec-row-line { display: flex; align-items: center; gap: 8px; border-bottom: 1px solid var(--border); }
.rec-row-line:last-child { border-bottom: 0; }
.rec-row-line .rec-row { flex: 1; min-width: 0; border-bottom: 0; }
.rec-note-btn { flex: none; white-space: nowrap; }

/* ---------- 邀请赛（2026-10-11 用户钦定：拿到链接输名字即可参赛，可见范围里的第三个选项） ----------
   表单里就是一枚普通单选项（不写解说），下面两块是它的列表与详情徽章。 */
/* 卡片/详情页的「邀请赛」徽章（品牌色描边胶囊，与「进行中」等状态徽章并排不打架） */
.badge.ct-invite { display: inline-flex; align-items: center; gap: 4px; color: var(--brand);
  background: var(--brand-soft); border: 1px solid color-mix(in srgb, var(--brand) 35%, transparent); }
.badge.ct-invite svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; }

/* 侧栏「邀请赛」专项项（.scope-item.extra）：品牌色小图标，选中态与普通行同款 */
.scope-item.extra { color: var(--brand); }
.scope-item.extra .scope-ic { flex: none; display: inline-flex; }
.scope-item.extra .scope-ic svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.scope-item.extra:hover { background: var(--brand-soft); }

.adm-form .input:disabled { background: var(--surface-2); color: var(--text-3); cursor: not-allowed; }

/* 表单控件高度统一 36px（2026-10-11 用户「不要一会小一会大」）：实测 分段 44.4 / 胶囊 38.8
   / 输入框 34 / 下拉 36 四个族参差——全拉平到 36（输入框、单选胶囊、分段片、下拉同一条基准线）。 */
.adm-form .input { height: 36px; }
.adm-form .field > label.radio-line { height: 36px; padding: 0 13px; }
.adm-form .mode-opt > span { height: 30px; padding: 0 22px; }

/* 表单里的比赛方式切换（2026-10-11 二改：15px 图标在中文粗体旁显糊，弃图标弃单选圈，
   改成站内已验收的「分段控件」范式——编辑页那枚品牌填充活动片）：
   轨道=surface-3 凹槽，选中片=品牌填充白字，像按下去的模式开关。 */
.mode-seg { display: inline-flex; background: var(--surface-3); border-radius: 10px; padding: 3px; gap: 3px; }
.mode-opt { position: relative; }
.mode-opt input { position: absolute; inset: 0; opacity: 0; pointer-events: none; }
.mode-opt > span { display: inline-flex; align-items: center; justify-content: center; min-width: 96px;
  padding: 0 22px; font-size: 14px; font-weight: 500; color: var(--text-2);
  border-radius: 8px; cursor: pointer; transition: background .16s, color .16s, box-shadow .16s; }
.mode-opt:hover > span { color: var(--text); background: color-mix(in srgb, var(--surface) 65%, transparent); }
.mode-opt input:checked + span { background: var(--brand); color: #fff; font-weight: 600;
  box-shadow: 0 1px 3px color-mix(in srgb, var(--brand) 40%, transparent); }

/* 表单单选胶囊里的图标（2026-10-11 美化）：统一步调——描边图标 15px 与文字同色；
   .ic-fill = 实心图标（播放键这类几何图形描边会显得毛糙，实心才干净）。 */
.field > label.radio-line svg { flex: none; }
svg.ic-fill { fill: currentColor; stroke: none; }

/* ---------- 访客细条顶栏（2026-10-12 重做：访客=正式页面，导航全藏，只留身份条） ---------- */
body.guest-shell { --nav-h: 44px; }
.guest-topbar { height: var(--nav-h); }
.guest-topbar .brand { gap: 8px; }
.guest-topbar .brand-name { font-size: 14px; }
.guest-topbar .guest-me { color: var(--text-2); margin-left: 4px; }
.guest-topbar .guest-me b { color: var(--text); }
.guest-topbar .nav-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.guest-shell .tabbar, .guest-shell .footer, .guest-shell .nav-handle { display: none; }
/* ===== 知识块目录树（v3：父=文件夹可折叠不出题单，叶=课程题单）===== */

/* 行基础 */
.kb-nav-row { display: flex; align-items: center; min-height: 30px; border-radius: var(--r-sm); }
.kb-nav-row.t { cursor: grab; }
.kb-nav-row.t.dragging { opacity: .45; }

/* 文件夹行（有子块）：整行可点击折叠 */
.kb-nav-row.kb-folder { cursor: pointer; user-select: none; }
.kb-nav-row.kb-folder:hover { background: var(--surface-2); }

/* chevron */
.kb-tog { flex: none; width: 20px; height: 28px; display: inline-flex; align-items: center; justify-content: center; background: none; border: none; padding: 0; pointer-events: none; }
.kb-tog .kb-chev { display: block; width: 0; height: 0; border-left: 5px solid var(--text-3); border-top: 4px solid transparent; border-bottom: 4px solid transparent; transition: rotate .15s ease, border-color .12s; rotate: 90deg; }
.kb-nav-row.kb-folder:hover .kb-chev { border-left-color: var(--brand); }
.kb-tog.closed .kb-chev { rotate: 0deg; }
.kb-tog-sp { flex: none; width: 20px; }

/* 文件夹名（非链接 span） */
.kb-flink { flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px; padding: 4px 8px 4px 0; color: var(--text-2); font-size: 13px; }
.kb-flink .kb-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-flink .kb-n { flex: none; font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; }

/* 叶子链接（课程题单） */
.kb-nav-row.kb-leaf { cursor: pointer; }
.kb-nav-row.kb-leaf:hover { background: var(--surface-2); }
.kb-lnk { flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px; padding: 4px 8px 4px 0; color: var(--text-2); text-decoration: none; font-size: 13px; border-radius: var(--r-sm); transition: background .12s, color .12s; }
.kb-nav-row.kb-leaf:hover .kb-lnk { color: var(--text); }
.kb-lnk.on { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
.kb-lnk .kb-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-lnk .kb-n { flex: none; font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.kb-lnk.on .kb-n { color: var(--brand); }

/* 子块容器：缩进+左导线 */
.kb-kids { display: flex; flex-direction: column; margin-left: 9px; padding-left: 6px; border-left: 1.5px solid var(--border); }
.kb-kids.hid { display: none; }

/* 层级差异化 */
.kb-nav-row.kb-d0 .kb-flink { font-weight: 600; font-size: 14px; color: var(--text); }
.kb-nav-row.kb-d0 .kb-tog { width: 22px; height: 32px; }
.kb-nav-row.kb-d0 .kb-tog .kb-chev { border-left-width: 6px; border-top-width: 4.5px; border-bottom-width: 4.5px; }
.kb-nav-row.kb-d1 .kb-flink { font-weight: 500; font-size: 13px; color: var(--text-2); }
.kb-nav-row.kb-d2 .kb-lnk { font-size: 12.5px; color: var(--text-2); }
.kb-nav-row.kb-d2:hover { background: var(--brand-soft); }
.kb-nav-row.kb-d2 .kb-lnk.on { background: transparent; }
.kb-nav-row.kb-d3 .kb-lnk { font-size: 12px; color: var(--text-3); }

/* 老师工具 */
.kb-nav-row .kb-tools { opacity: 0; transition: opacity .12s; }
.kb-nav-row:hover .kb-tools { opacity: 1; }

/* 拖拽 */
.kb-nav-row.drop-before { box-shadow: inset 0 2px 0 var(--brand); }
.kb-nav-row.drop-after { box-shadow: inset 0 -2px 0 var(--brand); }
.kb-nav-row.drop-in { outline: 2px dashed var(--brand); outline-offset: -2px; background: color-mix(in srgb, var(--brand) 8%, transparent); }

/* 内容区分层 */
.co-sec.co-sec-d1 { margin: 0 0 12px 0; padding: 8px 0 0 14px; border-left: 3px solid var(--brand-soft); border-radius: 0 var(--r-sm) 0 0; }
.co-sec.co-sec-d1 > .co-sec-head { font-size: 14px; color: var(--text); font-weight: 600; margin-bottom: 6px; }
.co-sec.co-sec-d1 > .co-sec-head i { width: 7px; height: 7px; }
.co-sec.co-sec-d2 { margin: 0 0 4px 0; padding: 3px 0 0 12px; border-left: 2px solid var(--border); }
.co-sec.co-sec-d2 > .co-sec-head { font-size: 13px; color: var(--text-2); font-weight: 500; margin-bottom: 3px; }
.co-sec.co-sec-d2 > .co-sec-head i { width: 5px; height: 5px; background: var(--text-3); }

/* ---------- 阅读内容区用文楷（2026-10-15 用户钦定「读起来轻松」）----------
   圈定=「读的正文」：题面（.statement/.obj-statement/.obj-card）、文章（.markdown-body）、
   解析与判题结果正文；导航/按钮/标签/列表等界面骨架保持 --sans 黑体，代码保持 --mono。 */
.statement, .obj-statement, .obj-card, .statement p, .statement li, .statement td, .statement th,
.markdown-body p, .markdown-body li, .markdown-body td, .markdown-body th, .markdown-body blockquote {
  font-family: var(--font-read);
}
.markdown-body h1, .markdown-body h2, .markdown-body h3,
.markdown-body h4, .markdown-body h5, .markdown-body h6 {
  font-family: var(--font-read);
}

/* 课程页力扣式分组卡（2026-10-15 用户钦点，对标力扣学习计划）：
   每个子主题一张圆角分区卡，行=状态圈+题号+题名，右侧题目类型字（客观题/编程题，不放难度）。 */
.course-lc { display: flex; flex-direction: column; gap: 14px; } /* 外壳卡已去（2026-10-16 用户令「不需要题目这个外壳」）：分组卡直接落地与页签对齐 */
.lc-group { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
.lc-head { display: flex; align-items: center; justify-content: space-between; padding: 11px 16px; border-bottom: 1px solid var(--border); background: color-mix(in srgb, var(--brand) 6%, transparent); }
.lc-head .lc-t { font-weight: 700; font-size: 14px; }
.lc-head .lc-n { font-size: 12px; color: var(--text-2); font-weight: 500; }
.lc-row { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent); }
.lc-row:last-child { border-bottom: 0; }
.lc-row:hover { background: color-mix(in srgb, var(--brand) 5%, transparent); }
.lc-st { width: 18px; height: 18px; border-radius: 50%; border: 1.6px solid var(--border); flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; }
.lc-st.ac { border-color: var(--ac); background: var(--ac); color: #fff; }
.lc-st.try { border-color: #e8a33d; }
.lc-st.try::after { content: ''; width: 8px; height: 8px; border-radius: 50%; background: #e8a33d; }
.lc-idx { width: 22px; flex: 0 0 auto; font-size: 12px; color: var(--text-2); }
.lc-row .lc-ttl { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; font-weight: 500; color: var(--text); text-decoration: none; }
.lc-row .lc-ttl:hover { color: var(--brand); }
.lc-type { flex: 0 0 auto; margin-left: auto; font-size: 13px; font-weight: 600; }
.lc-type.t-obj { color: #8b5cf6; }
html[data-theme='dark'] .lc-type.t-obj { color: #b79bfa; }
.lc-type.t-prog { color: #e8a33d; }

/* 课程题目页右侧子主题导航（2026-10-16 用户令「题目这个也要支持右侧导航栏」）：
   宽屏=sticky 右栏（8 节清单、滚动高亮当前节、点击平滑滚动）；窄屏隐藏。 */
.lc-shell { display: flex; gap: 16px; align-items: flex-start; }
.lc-shell .course-lc { flex: 1 1 auto; min-width: 0; }
/* 点右栏跳节时，目标组的组头要落在 sticky 顶栏（--nav-h=56px）**下方**：
   原来只留 20px，组头正好藏进顶栏里（2026-10-17 用户报「定位到了第一题，但子主题标题
   被上方遮挡」）。56 + 12 留一条空隙；窄屏还要再让开顶部横排 chips 条（宽屏那条规则在下面）。 */
.lc-group { scroll-margin-top: calc(var(--nav-h, 56px) + 12px); }
/* 2026-10-16 修「右栏飞到头顶」：sticky 上沿 16px 会顶进页头区域——对齐文章目录的做法
   （top 84px，页头滚走后也不越界），并套用 art-toc 同款卡片观感（阴影+标题分隔线）。 */
.lc-nav { position: sticky; top: calc(var(--nav-h, 56px) + 16px); flex: 0 0 228px; max-height: calc(100vh - var(--nav-h, 56px) - 32px); overflow: auto;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--sh-1); padding: 0 8px 10px; }
.lc-nav-t { font-size: 12px; font-weight: 700; letter-spacing: .08em; color: var(--text-2);
  padding: 10px 10px 8px; border-bottom: 1px solid var(--border); margin-bottom: 6px;
  /* 清单比一屏长时栏内要自己滚（2026-10-17）：标题钉在栏顶，滚到后半段仍知道这是什么。
     栏的上内边距挪进标题里（.lc-nav 顶上不留 10px 缝），否则滚动时条目会从缝里露出来。 */
  position: sticky; top: 0; z-index: 2; background: var(--surface); }
.lc-nav-i { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 7px 10px; border-radius: 8px; font-size: 13px; color: var(--text-2); cursor: pointer; }
.lc-nav-i:hover { background: color-mix(in srgb, var(--brand) 8%, transparent); color: var(--text); }
.lc-nav-i.on { background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--text); font-weight: 600; }
.lc-nav-i em { font-style: normal; font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; }
/* 2026-10-17 同文章目录修法：窄屏不再隐藏——降级为顶部横向滚动条（分节 chips，点击跳节/高亮照旧） */
@media (max-width: 1099px) {
  .lc-shell { display: flex; flex-direction: column; }
  .lc-nav { display: flex; flex-direction: row; flex-wrap: nowrap; gap: 6px; align-items: center;
    order: -1; position: sticky; top: calc(var(--nav-h, 56px) + 8px); z-index: 40;
    flex: none; max-height: none; overflow-x: auto; overflow-y: hidden; padding: 8px; scrollbar-width: none; }
  .lc-nav::-webkit-scrollbar { display: none; }
  .lc-nav-t { display: none; }
  .lc-nav-i { flex: 0 0 auto; padding: 4px 12px; border-radius: 999px; font-size: 12.5px; }
  /* 跳节落点 = 顶栏下沿 + 横排 chips 条（top=nav-h+8、高约 46）+ 8px 余量 = 118 */
  .lc-group { scroll-margin-top: 118px; }
}
