/* ===========================================================
   智能作业批改系统 · 界面样式
   面向教室一体机 / 展台环境，触摸友好、浅色投影可读
   =========================================================== */

:root {
  /* 2026-09-18 界面升级：主色从正蓝换成靛蓝，配少量紫罗兰渐变点缀；
     内容区仍是浅色（教室投影可读），深色只用在侧边栏和首页横幅上。 */
  --c-primary: #4f46e5;
  --c-primary-dark: #4338ca;
  --c-primary-soft: #eef2ff;
  --c-accent: #7c3aed;
  --c-ok: #16a34a;
  --c-ok-soft: #eafaf0;
  --c-bad: #dc2626;
  --c-bad-soft: #fdeeee;
  --c-warn: #d97706;
  --c-warn-soft: #fff7e8;
  --c-ink: #172033;
  --c-ink-2: #45536a;
  --c-ink-3: #7b8798;
  --c-line: #e3e7f2;
  --c-line-2: #eef1f8;
  --c-bg: #f3f5fb;
  --c-panel: #ffffff;
  --c-side: #1e1b4b;
  --r: 12px;
  --r-sm: 8px;
  --shadow: 0 1px 2px rgba(16, 32, 56, .06), 0 8px 24px rgba(16, 32, 56, .07);
  --shadow-sm: 0 1px 2px rgba(16, 32, 56, .08);
  --ff: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", system-ui, -apple-system, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  font-family: var(--ff);
  color: var(--c-ink);
  background: var(--c-bg);
  font-size: 15px;
  -webkit-text-size-adjust: 100%;
}

button, input, select, textarea { font-family: inherit; font-size: inherit; color: inherit; }

/* ---------- 布局 ---------- */
#app { display: flex; min-height: 100vh; }

.sidebar {
  width: 208px;
  flex: 0 0 208px;
  background: linear-gradient(180deg, #1e1b4b 0%, #312e81 100%);
  border-right: 0;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  box-shadow: 2px 0 12px rgba(30, 27, 75, .18);
}

.brand {
  padding: 18px 18px 14px;
  border-bottom: 1px solid rgba(255, 255, 255, .09);
}
.brand h1 { margin: 0; font-size: 17px; letter-spacing: .2px; color: #fff; }
.brand .sub { margin-top: 4px; font-size: 12px; color: #a5b4fc; }

.nav { padding: 10px 10px 20px; overflow: auto; flex: 1; }
.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 12px;
  margin-bottom: 2px;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  cursor: pointer;
  text-align: left;
  color: #c7d2fe;
  min-height: 44px;
  transition: background .12s, color .12s, box-shadow .12s;
}
.nav-item:hover { background: rgba(255, 255, 255, .08); color: #fff; }
.nav-item.active {
  background: linear-gradient(135deg, #6366f1, #8b5cf6);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 4px 14px rgba(99, 102, 241, .38);
}
.nav-item .ic { width: 20px; text-align: center; font-size: 16px; }
.nav-item .badge {
  margin-left: auto;
  background: var(--c-bad);
  color: #fff;
  font-size: 11px;
  border-radius: 999px;
  padding: 1px 7px;
  font-weight: 600;
}

.sidebar .foot { padding: 12px 16px; border-top: 1px solid rgba(255, 255, 255, .09); font-size: 12px; color: #818cf8; }

/* 侧边栏的班级名：做成按钮，鼠标移上去才显出铅笔，平时看着仍像一行字 */
.cls-name {
  margin-top: 2px;
  padding: 3px 7px 3px 8px;
  border: 1px dashed transparent;
  border-radius: 6px;
  background: transparent;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: #e0e7ff;
  cursor: pointer;
  max-width: 100%;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cls-name:hover { border-color: rgba(255, 255, 255, .25); background: rgba(255, 255, 255, .08); }
.cls-edit { margin-left: 5px; font-size: 11px; color: #a5b4fc; opacity: 0; }
.cls-name:hover .cls-edit, .cls-name:focus .cls-edit { opacity: 1; }

@media print { .cls-name { border: 0; } .cls-edit { display: none; } }

/* 侧栏班级：自绘「点击展开」下拉（2026-09-18）。
   原生 select 在深色侧栏里体验不稳，改成自绘列表：点标题展开、
   点选项切换、点空白或 Esc 才收。菜单向上弹（footer 贴着底边）。 */
.cls-label { color: #818cf8; }
.cls-row { display: flex; align-items: center; gap: 4px; margin-top: 3px; }
.cls-dd { position: relative; flex: 1; min-width: 0; }
.cls-dd-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 8px;
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 7px;
  background: rgba(255, 255, 255, .07);
  color: #e0e7ff;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  text-align: left;
  transition: background .15s, border-color .15s;
}
.cls-dd-btn:hover { background: rgba(255, 255, 255, .12); border-color: rgba(255, 255, 255, .28); }
.cls-dd.open .cls-dd-btn { border-color: rgba(165, 180, 252, .6); background: rgba(255, 255, 255, .13); }
.cls-dd-cur { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.cls-dd-car { font-size: 10px; color: #a5b4fc; transition: transform .16s; }
.cls-dd.open .cls-dd-car { transform: rotate(180deg); }
.cls-dd-menu {
  display: none;
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + 6px);      /* 向上弹，不然会顶出屏幕 */
  z-index: 60;
  padding: 5px;
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 10px;
  background: #262254;
  box-shadow: 0 12px 30px rgba(0, 0, 0, .45);
  max-height: 300px;
  overflow-y: auto;
}
.cls-dd.open .cls-dd-menu { display: block; }
.cls-dd-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 8px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: #cbd5e1;
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
  text-align: left;
}
.cls-dd-item:hover { background: rgba(255, 255, 255, .1); color: #fff; }
.cls-dd-item.on { background: linear-gradient(90deg, var(--c-primary), var(--c-accent)); color: #fff; font-weight: 600; }
.cls-dd-tick { width: 12px; font-size: 11px; }
.cls-dd-name { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.cls-dd-n { font-size: 11px; opacity: .75; }
.cls-dd-sep { height: 1px; margin: 4px 6px; background: rgba(255, 255, 255, .12); }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  min-height: 60px;
  flex: 0 0 auto;
  background: #fff;
  border-bottom: 1px solid var(--c-line);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  padding: 8px 22px;
  position: sticky;
  top: 0;
  z-index: 20;
}
.topbar h2 { margin: 0; font-size: 17px; }
.topbar .spacer { flex: 1; }
/* 顶栏工具窄窗口时允许换行，但换出来的行必须贴右、留在白条里，
   不能悬到页面内容上（2026-09-20 老师截图：删除场次悬空看着奇怪） */
#topbar-tools { justify-content: flex-end; }

.page { padding: 20px 22px 60px; }

/* ---------- 通用组件 ---------- */
.card {
  background: var(--c-panel);
  border: 1px solid var(--c-line);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  margin-bottom: 16px;
  overflow: hidden;
}
.card-h {
  padding: 13px 16px;
  border-bottom: 1px solid var(--c-line-2);
  display: flex;
  align-items: center;
  gap: 10px;
  background: #fcfdff;
}
.card-h h3 { margin: 0; font-size: 15px; }
.card-h .spacer { flex: 1; }
.card-h .hint { font-size: 12px; color: var(--c-ink-3); }
.card-b { padding: 16px; }
.card-b.tight { padding: 0; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 9px 15px;
  min-height: 40px;
  border-radius: var(--r-sm);
  border: 1px solid var(--c-line);
  background: #fff;
  color: var(--c-ink);
  cursor: pointer;
  white-space: nowrap;
  transition: .12s;
  font-weight: 500;
}
.btn:hover { border-color: #cfd8e6; background: #fafcff; }
.btn:active { transform: translateY(1px); }
.btn.primary {
  background: linear-gradient(135deg, var(--c-primary), #6366f1);
  border-color: transparent;
  color: #fff;
  box-shadow: 0 2px 8px rgba(79, 70, 229, .24);
}
.btn.primary:hover {
  background: linear-gradient(135deg, var(--c-primary-dark), var(--c-primary));
  border-color: transparent;
}
.btn.ok { background: var(--c-ok); border-color: var(--c-ok); color: #fff; }
.btn.ok:hover { filter: brightness(.94); }
.btn.bad { background: var(--c-bad); border-color: var(--c-bad); color: #fff; }
.btn.bad:hover { filter: brightness(.94); }
.btn.danger { background: #fff; border-color: #fecaca; color: #b91c1c; }
.btn.danger:hover { background: #fee2e2; border-color: #b91c1c; }
.btn.ghost-danger { background: transparent; border-color: transparent; color: #b91c1c; }
.btn.ghost-danger:hover { background: #fee2e2; border-color: #fecaca; }
.btn.ghost { background: transparent; border-color: transparent; color: var(--c-primary); }
.btn.ghost:hover { background: var(--c-primary-soft); }

/* ---------- 试卷排版编辑器（#35） ---------- */
.paper-layout { padding: 14px 16px; background: #fbfcfe; border-top: 1px solid var(--c-line-2); }
.lay-tip { background: #fff; border: 1px dashed #c7d6ee; border-radius: 8px; padding: 8px 12px; margin-bottom: 12px; line-height: 1.7; }

/* 两栏：左边改，右边实时看。预览放在下面根本看不到"宽度变了没有"，
   而排版这件事本身就是在调宽度和留白，所以必须并排。 */
.lay-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(340px, 42%);
  gap: 16px;
  align-items: start;
}
.lay-left { min-width: 0; }
.lay-right {
  min-width: 0;
  position: sticky;
  top: 12px;
  background: #fff;
  border: 1px solid var(--c-line);
  border-radius: 10px;
  padding: 10px;
}
.lay-right-h {
  display: flex; align-items: center; gap: 8px;
  padding-bottom: 8px; margin-bottom: 8px;
  border-bottom: 1px solid var(--c-line-2);
  font-size: 13.5px;
}
.lay-right-h .spacer { flex: 1; }
.lay-zoom { display: inline-flex; align-items: center; gap: 4px; font-size: 12.5px; color: var(--c-ink-2); }
.lay-zoom select { width: auto; min-height: 30px; padding: 2px 6px; font-size: 12.5px; }

/* 工具条：全选 + 批量设置。一屏改完十几题的下拉，不然要一个个点。 */
/* 老浏览器（希沃一体机的内核较老）不支持 flex 的 gap，控件会贴死叠在一起 ——
   排版区一律改用 margin 留缝，新老浏览器间距一致（2026-09-22 老师截图：叠在一起了） */
.lay-bar {
  display: block;
  background: #fff; border: 1px solid var(--c-line); border-radius: 8px;
  padding: 8px 12px 2px; margin-bottom: 10px;
}
/* 三十轮：工具条与题参数行整体退出 flex —— 老内核（希沃 Chromium<84）算 inline-flex
   固有宽度时会把「输入框后面的文字」整个丢掉（flex:none / min-width:max-content
   都救不了，因为 max-content 本身就算错了）。改 block + inline-block：
   inline-block 的收缩适用宽度走最古老的行内测量（与普通文字同一套代码），
   文字+输入框+单位一起量，任何内核都没有算错的空间。 */
.lay-bar > * { display: inline-block; vertical-align: middle; margin: 0 10px 6px 0; }
.lay-bar .lay-all { font-size: 13px; cursor: pointer; }
.lay-bar .lay-all > input { margin-right: 6px; vertical-align: middle; }
.lay-bar .lay-num { font-size: 12.5px; color: var(--c-ink-2); }
.lay-bar .lay-num b { color: var(--c-primary); font-size: 14px; }
.lay-bar select { width: auto; min-height: 36px; padding: 2px 8px; font-size: 12.5px; }
/* 数字框加大好按（2026-09-22 老师：间距框总点不到）；宽度钉死，数字变长框也不动 */
.lay-bar input[type=number] { width: 72px; min-height: 36px; padding: 4px 8px; font-size: 14px; text-align: center; box-sizing: border-box; flex: none; }

/* 列表自己滚：行数一多，「保存排版」就被顶到屏幕外，老师得翻半天才找得到。
   让列表内部滚动，按钮永远露在下面。 */
.lay-list { max-height: calc(100vh - 330px); overflow-y: auto; padding-right: 4px; }
/* 三十轮：列表也退出 flex（老内核不支持 flex 的 gap，行距会贴死），改块级 + margin。 */
.lay-row {
  display: flex; flex-direction: column; align-items: stretch;
  padding: 7px 12px;
  background: #fff; border: 1px solid var(--c-line); border-radius: 8px;
  cursor: grab; margin-bottom: 6px;
}
.lay-head { display: flex; align-items: center; min-width: 0; margin-bottom: 5px; }
.lay-head > * { margin-right: 10px; }
.lay-head > *:last-child { margin-right: 0; }
.lay-ctrls { display: block; padding-left: 79px; }
.lay-row.dragging { opacity: .55; border-color: var(--c-primary); box-shadow: 0 2px 8px rgba(37,99,235,.15); }
.lay-row:hover { border-color: #c7d6ee; }
.lay-row.picked { background: var(--c-primary-soft); border-color: #a9c2f5; }
.lay-pick { width: 17px; height: 17px; flex: 0 0 auto; cursor: pointer; accent-color: var(--c-primary); }
.lay-handle { font-size: 18px; color: var(--c-ink-3); cursor: grab; user-select: none; }
.lay-no { font-size: 13px; color: var(--c-ink-2); font-variant-numeric: tabular-nums; min-width: 24px; }
.lay-stem { flex: 1; min-width: 0; font-size: 13.5px; color: var(--c-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lay-ctrl { display: inline-block; vertical-align: middle; font-size: 12.5px; color: var(--c-ink-2); white-space: nowrap; margin: 0 18px 6px 0; }
/* 三十轮：文字/单位全部拆成显式元素（.lc-t），与输入框/下拉 vertical-align:middle 对齐，
   span 里不再有任何裸文本 —— 老内核测宽时丢「输入框后面的文字」也就无从丢起；
   inline-block 自身永不收缩，放不下整块换行，绝不叠。 */
.lay-ctrl .lc-t { display: inline-block; vertical-align: middle; }
/* 🔴 三十轮定论：这一行在 26/27 轮加过 flex:none 和 min-width:max-content 两层保险仍叠字
   （老师 2026-09-23 下午再次截图）—— 真根因是老内核算 inline-flex 固有宽度时
   把「输入框后面的文字」整个丢掉，两层保险依赖的 max-content 本身就算错。
   最终方案：整行退出 flex（见 .lay-bar > * 与 .lay-ctrls 的注释）。 */
.lay-ctrl > input, .lay-ctrl > select { vertical-align: middle; margin-left: 6px; }
.lay-ctrl input { width: 72px; box-sizing: border-box; }
.lay-ctrl select { min-width: 118px; }
.lay-ctrl.muted { color: var(--c-ink-3); font-style: italic; }
/* 排版行里的控件要"瘦"一点：全局控件是 40px 高，一行行摞起来
   十几题就有一屏多，老师得翻半天。 */
.lay-row input[type=number], .lay-bar input[type=number] { min-height: 36px; padding: 4px 8px; font-size: 14px; text-align: center; }
.lay-row select, .lay-bar select { min-height: 36px; padding: 2px 8px; font-size: 12.5px; }
/* 数字框右侧自带的上下小箭头（spinner）在 72px 窄框里又挤又难点 —— 统一藏掉，
   调值直接敲键盘 / 触屏输入即可（2026-09-22 老师截图：小箭头和文字叠在一起） */
.lay-row input[type=number]::-webkit-inner-spin-button,
.lay-row input[type=number]::-webkit-outer-spin-button,
.lay-bar input[type=number]::-webkit-inner-spin-button,
.lay-bar input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.lay-row input[type=number], .lay-bar input[type=number] { -moz-appearance: textfield; appearance: textfield; }

/* 「保存排版」这些按钮贴着屏幕底边：列表再长也一眼看得见。 */
.lay-actions {
  position: sticky; bottom: 0; z-index: 2;
  background: #fbfcfe; border-top: 1px solid var(--c-line-2);
  padding: 10px 0 4px;
}

/* 间距控件：大一号的数字框（2026-09-22 老师：总点不到），框里按空格 +1 行、退格 −1 行（onLayGapKey）。
   宽度钉死 72px，数字位数变多框也不动；原来后面那根「▔」可视化小横条按老师要求删了（影响美观）。 */
.lay-gap input { width: 72px; }

.lay-preview {
  border: 1px dashed var(--c-line); border-radius: 10px; padding: 10px;
  background: #e9edf4;
  max-height: 74vh;
  overflow: auto;
}
.lay-preview-inner { transform-origin: top left; }
.lay-preview-inner .sheet { margin: 0 auto 10px; }
.lay-preview-foot { padding-top: 8px; font-size: 12px; }
.lay-preview .empty { background: transparent; }

/* 窄屏（教室一体机竖屏、笔记本小窗）自动改成上下排，
   免得右边预览把左边挤成一条缝。 */
@media (max-width: 1180px) {
  .lay-wrap { grid-template-columns: minmax(0, 1fr); }
  .lay-right { position: static; }
  .lay-preview { max-height: 60vh; }
}
@media print {
  .paper-layout, .lay-row { display: none !important; }
}
.btn.sm { min-height: 32px; padding: 4px 10px; font-size: 13px; }
.btn.lg { min-height: 52px; padding: 12px 24px; font-size: 17px; }
.btn.block { width: 100%; }
.btn:disabled { opacity: .45; cursor: not-allowed; }

input[type=text], input[type=number], input[type=date], select, textarea {
  width: 100%;
  padding: 9px 11px;
  min-height: 40px;
  border: 1px solid var(--c-line);
  border-radius: var(--r-sm);
  background: #fff;
  outline: none;
  transition: border-color .12s, box-shadow .12s;
}
input:focus, select:focus, textarea:focus { border-color: var(--c-primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .12); }
textarea { min-height: 76px; resize: vertical; line-height: 1.6; }
label.fld { display: block; margin-bottom: 12px; }
label.fld > span { display: block; font-size: 12.5px; color: var(--c-ink-2); margin-bottom: 5px; font-weight: 500; }
.row { display: flex; gap: 12px; flex-wrap: wrap; }
.row > * { flex: 1; min-width: 0; }
.row.fixed > * { flex: 0 0 auto; }

.tag {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 12px;
  background: var(--c-line-2);
  color: var(--c-ink-2);
  white-space: nowrap;
}
.tag.blue { background: var(--c-primary-soft); color: var(--c-primary-dark); }
.tag.ok { background: var(--c-ok-soft); color: #15803d; }
.tag.bad { background: var(--c-bad-soft); color: #b91c1c; }
.tag.warn { background: var(--c-warn-soft); color: #b45309; }
.tag.purple { background: #f3edff; color: #6d28d9; }

/* ---------- AI 出题：知识模块标签 + 题型勾选 ---------- */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--c-line);
  background: #fff;
  color: var(--c-ink-2);
  font-size: 13px;
  line-height: 1.4;
  cursor: pointer;
  transition: .14s;
}
.chip:hover { border-color: var(--c-primary); color: var(--c-primary-dark); }
.chip i {
  font-style: normal;
  font-size: 11px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--c-line-2);
  color: var(--c-ink-3);
}
.chip.on {
  background: var(--c-primary);
  border-color: var(--c-primary);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 2px 8px rgba(37, 99, 235, .22);
}
.chip.on i { background: rgba(255, 255, 255, .28); color: #fff; }

.ai-grp {
  border: 1px solid var(--c-line-2);
  border-radius: 10px;
  padding: 8px 12px 10px;
  margin-bottom: 10px;
  background: #fcfdff;
}
.ai-grp-h {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding-bottom: 6px;
  border-bottom: 1px dashed var(--c-line-2);
  margin-bottom: 6px;
}
.ai-grp-h b { font-size: 13.5px; color: var(--c-ink); }
.ai-item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 0;
  cursor: pointer;
  font-size: 13px;
  color: var(--c-ink-2);
}
.ai-item input { width: auto; flex: 0 0 auto; }

table.tbl { width: 100%; border-collapse: collapse; }
table.tbl th, table.tbl td { padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--c-line-2); font-size: 14px; }
table.tbl th { background: #fafbfe; font-weight: 600; color: var(--c-ink-2); font-size: 13px; white-space: nowrap; }
table.tbl tbody tr:hover { background: #fafcff; }
table.tbl td.num { font-variant-numeric: tabular-nums; }
table.t, table.tbl { width: 100%; border-collapse: collapse; }
table.t th, table.t td, table.tbl th, table.tbl td { padding: 9px 12px; text-align: left; border-bottom: 1px solid var(--c-line-2); font-size: 13.5px; }
table.t th, table.tbl th { background: #fafbfe; font-weight: 600; color: var(--c-ink-2); font-size: 12.5px; white-space: nowrap; }
table.t tbody tr.on, table.tbl tbody tr.on { background: #f5f9ff; }
table.t tbody tr:hover, table.tbl tbody tr:hover { background: #fafcff; }
table.t td.center, table.tbl td.center { text-align: center; font-variant-numeric: tabular-nums; }
table.t td.right, table.tbl td.right { text-align: right; }

.empty { text-align: center; padding: 44px 20px; color: var(--c-ink-3); }
.empty .big { font-size: 34px; margin-bottom: 10px; opacity: .5; }

.grid { display: grid; gap: 14px; }
.grid.g2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.g3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.g4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1100px) { .grid.g4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .grid.g3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 820px) { .grid.g2, .grid.g3, .grid.g4 { grid-template-columns: 1fr; } }

.stat {
  background: #fff; border: 1px solid var(--c-line); border-radius: var(--r);
  padding: 15px 16px 13px; position: relative; overflow: hidden;
}
/* 顶条给数字卡一点颜色（2026-09-18 界面升级）—— 3px 高，浅色投影下也看得清 */
.stat::before {
  content: ''; position: absolute; left: 0; top: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, var(--c-primary), #8b5cf6);
  opacity: .85;
}
.stat.ok::before { background: linear-gradient(90deg, var(--c-ok), #4ade80); }
.stat.bad::before { background: linear-gradient(90deg, var(--c-bad), #f87171); }
.stat.warn::before { background: linear-gradient(90deg, var(--c-warn), #fbbf24); }
.stat .k { font-size: 12.5px; color: var(--c-ink-3); margin-bottom: 6px; }
.stat .v { font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -.5px; }
.stat .v small { font-size: 13px; font-weight: 500; color: var(--c-ink-3); margin-left: 3px; }
.stat.blue .v { color: var(--c-primary); }
.stat.ok .v { color: var(--c-ok); }
.stat.bad .v { color: var(--c-bad); }
.stat.warn .v { color: var(--c-warn); }

/* ---------- 首页横幅（2026-09-18 界面升级） ----------
   深靛→紫渐变，让"工作台"第一眼有精神；右侧常驻三个高频入口。
   深色面积控制在一块横幅里，正文区仍是浅色，投影环境可读。 */
.hero {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  background: linear-gradient(120deg, #312e81 0%, #4f46e5 55%, #7c3aed 100%);
  border-radius: 14px;
  padding: 20px 22px;
  margin-bottom: 16px;
  color: #fff;
  box-shadow: 0 10px 28px rgba(79, 70, 229, .28);
}
.hero-l { flex: 1; min-width: 260px; }
.hero-hi { font-size: 19px; font-weight: 700; letter-spacing: .3px; }
.hero-sub { margin-top: 5px; font-size: 13px; color: #c7d2fe; line-height: 1.7; }
.hero-sub b { color: #fff; }
.hero-r { display: flex; gap: 8px; flex-wrap: wrap; }
.hero .btn.inv { background: rgba(255, 255, 255, .12); border-color: rgba(255, 255, 255, .35); color: #fff; }
.hero .btn.inv:hover { background: rgba(255, 255, 255, .22); }
.hero .btn.white { background: #fff; border-color: #fff; color: var(--c-primary-dark); font-weight: 600; }
.hero .btn.white:hover { background: #eef2ff; }

/* 「错题与复习」页的立即生成区（2026-09-18）。
   左边说明现状（到期几题、覆盖几人），右边是变式口径 + 一颗大按钮 ——
   老师要的是"随时点一下就有"，所以按钮刻意做得比别处大。 */
.gen-now { border-color: #c7d2fe; background: linear-gradient(120deg, #eef2ff 0%, #f5f3ff 100%); }
.gen-now .card-b { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; padding: 16px 18px; }
.gen-now-l { flex: 1; min-width: 240px; }
.gen-now-t { font-size: 17px; font-weight: 700; color: var(--c-primary-dark); }
.gen-now-s { margin-top: 5px; font-size: 12.5px; color: #475569; line-height: 1.8; }
.gen-now-s b { color: var(--c-primary-dark); }
.gen-now-r { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.fld.compact { min-width: 0; }
.fld.compact > span { font-size: 12px; }
.fld.compact select, .fld.compact input { min-height: 34px; padding: 5px 8px; font-size: 13px; }
.fld.compact select { min-width: 116px; }
.fld.compact input[type="number"] { width: 84px; }

/* 复习单预览块（生成结果就地显示，不跳页） */
.rv-preview { max-height: 620px; overflow-y: auto; background: #f1f5f9; border-radius: 8px; padding: 10px; }
.rv-preview .empty { background: transparent; }

/* ---------- 题目卡片 ---------- */
.qitem { padding: 14px 16px; border-bottom: 1px solid var(--c-line-2); }
.qitem:last-child { border-bottom: 0; }
.qhead { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
.qno { font-weight: 700; color: var(--c-primary); font-variant-numeric: tabular-nums; }
.qstem { line-height: 1.85; white-space: pre-wrap; word-break: break-word; }
.qopts { margin-top: 8px; display: grid; gap: 4px; }
.qopt { padding: 5px 9px; border-radius: var(--r-sm); line-height: 1.7; }
.qopt.correct { background: var(--c-ok-soft); color: #15803d; font-weight: 600; }
.qopt.chosen-wrong { background: var(--c-bad-soft); color: #b91c1c; font-weight: 600; }
.qans { margin-top: 9px; font-size: 13.5px; color: var(--c-ink-2); background: #f8fafd; border-left: 3px solid var(--c-primary); padding: 7px 11px; border-radius: 0 var(--r-sm) var(--r-sm) 0; line-height: 1.7; }

/* 三十一轮：题目行里的「分值」就地改输入框（老师原话"单独修改每道题的分值"）。
   窄一点像标签，hover 才亮边框 —— 平时看着还是原来那个"5 分"标签的样子。 */
.qscore { display: inline-flex; align-items: center; gap: 0; }
.qscore input {
  width: 58px; min-height: 26px; padding: 2px 6px;
  font-size: 12.5px; font-weight: 700; text-align: center;
  border: 1px solid var(--c-line-2); border-radius: 999px 0 0 999px;
  background: #fff; color: var(--c-ink); box-sizing: border-box;
}
.qscore input:hover, .qscore input:focus { border-color: var(--c-primary); outline: none; }
.qscore .qscore-u {
  font-size: 12px; font-weight: 600; color: var(--c-ink-3);
  border: 1px solid var(--c-line-2); border-left: 0;
  border-radius: 0 999px 999px 0; padding: 2px 8px 2px 4px;
  background: #f8fafd; box-sizing: border-box; line-height: 1.55;
}
/* 三十一轮：按题型批量设分弹窗的行 */
.bs-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border: 1px solid var(--c-line); border-radius: var(--r-sm);
  margin-bottom: 8px; background: #fbfcfe;
}
.bs-type { display: flex; flex-direction: column; min-width: 96px; }
.bs-type .bs-n { font-size: 12px; color: var(--c-ink-3); }
.bs-cur { flex: 1 1 auto; font-size: 12.5px; color: var(--c-ink-3); white-space: nowrap; }
.bs-inp {
  width: 88px; min-height: 34px; padding: 4px 8px; box-sizing: border-box;
  text-align: center; font-weight: 700;
}

/* 判分行 */
.mark-btns { display: flex; gap: 6px; }
.mark-btns button {
  width: 40px; height: 40px; border-radius: var(--r-sm);
  border: 1px solid var(--c-line); background: #fff; cursor: pointer;
  font-size: 18px; line-height: 1; transition: .1s;
}
.mark-btns button:hover { background: #fafcff; }
.mark-btns button.on-ok { background: var(--c-ok); border-color: var(--c-ok); color: #fff; }
.mark-btns button.on-bad { background: var(--c-bad); border-color: var(--c-bad); color: #fff; }

/* ---------- 扫描台 ---------- */
.scan-wrap { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 16px; align-items: start; }
@media (max-width: 1180px) { .scan-wrap { grid-template-columns: 1fr; } }
.cam-stage { position: relative; background: #10151c; border-radius: var(--r); overflow: hidden; aspect-ratio: 16/10; }
.cam-stage video, .cam-stage canvas.overlay { position: absolute; inset: 0; width: 100%; height: 100%; }
.cam-stage canvas.overlay { pointer-events: none; }
.cam-stage video { object-fit: contain; background: #10151c; }
.cam-off { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; color: #93a1b5; gap: 8px; }
.cam-off .big { font-size: 40px; opacity: .6; }
.scan-status { display: flex; align-items: center; gap: 8px; padding: 10px 13px; border-radius: var(--r-sm); background: #f8fafd; border: 1px solid var(--c-line); font-size: 13.5px; }
.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--c-ink-3); flex: 0 0 auto; }
.dot.live { background: var(--c-ok); box-shadow: 0 0 0 4px rgba(22,163,74,.15); animation: pulse 1.4s infinite; }
.dot.err { background: var(--c-bad); }
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .35 } }

/* ---- 二十八轮需求三（2026-09-23）：摄像头下方的「当前扫描结果」----
   原来这里是一大块"卷子印了两面？/识别原理/读成未涂？"说明文字，老师要求去掉，
   换成大字结果条：正在批改（或上一张）+ 姓名 + 得分 + 一句状态。
   面向一体机：不用 flex gap，子项各自 margin（老 Chromium 教训）。 */
.scan-result {
  display: flex; align-items: center; flex-wrap: wrap;
  padding: 11px 14px; border-radius: var(--r-sm);
  background: #fff; border: 1px solid var(--c-line); font-size: 15px;
}
.scan-result > * { margin-right: 10px; }
.scan-result > *:last-child { margin-right: 0; }
.scan-result .sr-k {
  font-size: 12.5px; font-weight: 700; color: var(--c-primary-dark);
  background: var(--c-primary-soft); border-radius: 6px; padding: 3px 9px; flex: none;
}
.scan-result .sr-name { font-size: 17px; font-weight: 700; color: var(--c-ink); flex: none; }
.scan-result .sr-score { font-size: 21px; font-weight: 700; color: var(--c-primary-dark); flex: none; }
.scan-result .sr-score em { font-style: normal; font-size: 13px; color: var(--c-ink-3); }
.scan-result .sr-sub { color: var(--c-ink-2); font-size: 13px; }

.thumb-strip { display: flex; gap: 8px; overflow-x: auto; padding-top: 10px; }
.thumb-strip img { height: 68px; border-radius: 6px; border: 1px solid var(--c-line); }

/* ---------- 第二十轮：扫描页顶部统计"细带"（需求三）----------
   原来四张 .stat 大卡占掉整整一行（每张上下 ~78px），老师嫌"上下占得太宽"。
   压成一条 34px 的横带：试卷 / 题目 / 已批 / 自动识别，用竖线分隔。 */
.scan-statbar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  padding: 7px 14px; margin-bottom: 12px;
  background: var(--c-panel); border: 1px solid var(--c-line);
  border-radius: 999px; box-shadow: var(--shadow-sm);
  font-size: 13px; line-height: 1.4;
}
.scan-statbar .ss-k { color: var(--c-ink-3); }
.scan-statbar .ss-v {
  font-weight: 700; color: var(--c-ink);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.scan-statbar .ss-v em { font-style: normal; font-weight: 500; color: var(--c-ink-3); }
.scan-statbar .ss-v.ss-ok { color: var(--c-ok); }
.scan-statbar .ss-v.ss-warn { color: var(--c-warn); }
.scan-statbar > i {
  width: 1px; height: 15px; background: var(--c-line); flex: 0 0 auto;
}

/* ---------- 第二十轮：「今天已批」紧凑列表（需求四）----------
   目标：一屏尽量多塞人。每行 = 姓名 + 得分 + 错题签（题号 你的答案→正确答案）+ 对了几题，
   行高压到 30px，错题签横向自动换行；正确的题不占地方（只在末尾给个"✓ N 题"）。
   整栏可上下滚动，新批的自动滚到底，队列里的学生一眼看到自己的错题。 */
.done-scroll {
  max-height: 46vh; overflow-y: auto; padding-right: 4px;
  scrollbar-width: thin;
}
.done-scroll.slim { max-height: 34vh; }
.done-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 5px 9px; border-radius: var(--r-sm);
  border: 1px solid var(--c-line-2); background: #fff;
  margin-bottom: 5px; cursor: pointer; transition: .12s;
}
.done-row:hover { border-color: #c7d2fe; background: #f8faff; }
.done-row.editing { border-color: var(--c-primary); background: var(--c-primary-soft); box-shadow: 0 0 0 2px rgba(79,70,229,.12); }
.dr-name { font-size: 13.5px; color: var(--c-ink); flex: 0 0 auto; min-width: 52px; }
.dr-score {
  flex: 0 0 auto; font-size: 14px; font-weight: 800; color: var(--c-ink);
  font-variant-numeric: tabular-nums;
}
.dr-score em { font-style: normal; font-size: 11px; font-weight: 500; color: var(--c-ink-3); }
.dr-score.pass { color: var(--c-ok); }
.dr-score.fail { color: var(--c-bad); }
.dr-wrongs { display: flex; flex-wrap: wrap; gap: 4px; flex: 1 1 120px; min-width: 0; }
.dr-okc {
  flex: 0 0 auto; margin-left: auto; font-size: 11.5px; color: var(--c-ink-3);
  white-space: nowrap;
}
/* 错题签（需求二·二十一轮：只写"题号 正确答案"，答案走蓝色）
   原来写的是"题号 你的答案→正确答案"，红底红字 —— 老师反馈学生还得自己对比两遍。
   现在只留该改成哪个：蓝底蓝字，扫一眼就能抄。 */
.wchip {
  font-size: 11.5px; line-height: 1.5; font-weight: 700;
  color: #1d4ed8; background: #eef4ff;
  border: 1px solid #c3d9fb; border-radius: 5px;
  padding: 0 5px; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.wchip.ok { color: #15803d; background: var(--c-ok-soft); border-color: #c7eed6; }

/* ---------- 第二十轮：成绩分析里的"错题显示正确答案"（需求五）---------- */
.cell-ok { color: #15803d; background: var(--c-ok-soft); }
.cell-bad { color: #b91c1c; background: var(--c-bad-soft); }
/* 正确答案徽章：二十一轮改成蓝色 —— 红格子里放蓝徽章，学生一眼分清"这格错了"和"要改成这个" */
.rca {
  display: inline-block; margin-left: 0; padding: 1px 6px;
  font-size: 11.5px; font-weight: 800; color: #1d4ed8;
  background: #e8f1ff; border: 1px solid #b9d4fb; border-radius: 4px;
  vertical-align: middle;
}
.qrow-click { cursor: pointer; }
.qrow-click:hover { background: #f8faff; }

/* ---------- 打印页（A4） ---------- */
.sheet-scroller { overflow: auto; background: #e9edf4; padding: 18px; border-radius: var(--r); }
.sheet {
  position: relative;
  width: 210mm;
  height: 297mm;
  background: #fff;
  margin: 0 auto 18px;
  box-shadow: 0 3px 18px rgba(20,32,56,.16);
  overflow: hidden;
  color: #000;
  font-size: 10.5pt;
  line-height: 1.5;
}
.sheet .abs { position: absolute; }

/* 打印输出区（屏幕隐藏） */
#print-root { display: none; }

@media print {
  @page { size: A4; margin: 0; }
  html, body { background: #fff !important; height: auto; }
  #app { display: none !important; }
  #print-root { display: block !important; }
  /* print-color-adjust:exact —— 让卷面上的"背景色型"元素（如答题卡底、二维码白盒）
     也能打进纸里。页首分隔线本身已经改用 border-top 画（背景默认不印，
     线就是这么在打印预览里消失的），这里再兜一道底。 */
  .sheet {
    box-shadow: none !important; margin: 0 !important; page-break-after: always; break-after: page;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .sheet:last-child { page-break-after: auto; break-after: auto; }
  .no-print { display: none !important; }
}

/* ---------- 弹层 ---------- */
.modal-mask {
  position: fixed; inset: 0; background: rgba(14, 22, 36, .48);
  display: flex; align-items: center; justify-content: center; z-index: 100; padding: 20px;
}
.modal {
  background: #fff; border-radius: var(--r); width: min(720px, 100%);
  max-height: 88vh; display: flex; flex-direction: column; box-shadow: 0 20px 60px rgba(10,20,40,.3);
}
.modal.wide { width: min(1080px, 100%); }
.modal-h { padding: 16px 18px; border-bottom: 1px solid var(--c-line); display: flex; align-items: center; }
.modal-h h3 { margin: 0; font-size: 16px; }
.modal-h .spacer { flex: 1; }
.modal-b { padding: 18px; overflow: auto; }
.modal-f { padding: 14px 18px; border-top: 1px solid var(--c-line); display: flex; gap: 10px; justify-content: flex-end; }
.x-btn { border: 0; background: transparent; font-size: 22px; line-height: 1; cursor: pointer; color: var(--c-ink-3); padding: 4px 8px; border-radius: 6px; }
.x-btn:hover { background: var(--c-line-2); color: var(--c-ink); }

/* 学生勾选弹窗（为指定学生生成题单 / 复习单） */
.pick-stu-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 8px; }
.pick-stu {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  border: 1px solid var(--c-line); border-radius: 8px; cursor: pointer; background: #fff;
}
.pick-stu:hover { border-color: var(--c-acc, #3d7eff); background: #f5f8ff; }
.pick-stu input { width: 16px; height: 16px; accent-color: #3d7eff; flex: 0 0 auto; }
.pick-stu .ps-name { font-weight: 600; font-size: 14px; }
.pick-stu .ps-no { color: var(--c-ink-3); font-size: 12px; }

/* 同步设备列表的「删」按钮：低调的红，只提示危险不抢视线 */
.peer-del { color: #a32d2d; border-color: #e8c4c4; background: #fff; padding: 2px 10px; }
.peer-del:hover { background: #fcebeb; border-color: #d89494; }

/* ---------- 提示条 ---------- */
/* 挂右下角（2026-09-21 十五轮）：原来钉在右上，正好压住打印中心的预览区
   —— 老师截图里两条提示把答题卡挡了个严实。挪到底部谁都不挡。 */
.toast-wrap { position: fixed; bottom: 16px; right: 16px; z-index: 200; display: flex; flex-direction: column; gap: 8px; }
.toast {
  background: #16202e; color: #fff; padding: 11px 15px; border-radius: var(--r-sm);
  box-shadow: var(--shadow); font-size: 14px; max-width: 380px; animation: slidein .18s ease-out;
}
.toast.ok { background: #15803d; }
.toast.bad { background: #b91c1c; }
.toast.warn { background: #b45309; }
@keyframes slidein { from { opacity: 0; transform: translateX(14px) } to { opacity: 1; transform: none } }

.note {
  background: var(--c-primary-soft); border: 1px solid #d6e2ff; color: #1e40af;
  padding: 10px 13px; border-radius: var(--r-sm); font-size: 13.5px; line-height: 1.7;
}
.note.warn { background: var(--c-warn-soft); border-color: #fbe3b8; color: #92400e; }
.note.ok { background: var(--c-ok-soft); border-color: #c7eed6; color: #166534; }

.kbd {
  display: inline-block; padding: 1px 6px; border: 1px solid var(--c-line);
  border-bottom-width: 2px; border-radius: 5px; background: #fbfcfe;
  font-size: 12px; font-family: ui-monospace, Consolas, monospace;
}

/* 答题卡上的填涂点（屏幕预览与打印共用） */
/* 填涂点：细灰描边方框 + 淡灰字母 A/B/C/D。
   注意 —— 圆心与直径是 OMR 采样逻辑依赖的参数，改外观没问题，
   改几何尺寸要同步 sheet.js 的 G.bubbleD / G.bubbleGap，并重跑自测。
   OMR 扫描完全依赖 model.bubbles 里的 (x,y,r) 坐标采样，
   与 .bub 的视觉表现无关 —— 这里去掉了 0×0 隐藏，让卷面真正"看得见、能涂"，判分仍然准确。 */
.bub {
  position: absolute;
  /* 4.8mm 见方，跟 OMR 采样的圆心 (cx,cy) 对齐——方框正中央就是采样点。
     学生 2B 铅笔涂满整格，就能压中采样圆盘。 */
  width: 4.8mm; height: 4.8mm;
  border: 0.5pt solid #5b6470;
  border-radius: 0.7mm;          /* 单选柔润 */
  background: #fff;
  display: flex; align-items: center; justify-content: center;
  font: 7.5pt/1 ui-sans-serif, "PingFang SC", "Microsoft YaHei", sans-serif;
  color: #6b7280;
  letter-spacing: 0;
  overflow: hidden;
}
.bub.sq { border-radius: 0.4mm; }    /* 多选：方框，更接近"勾选格" */
.bub > .bub-l { line-height: 1; user-select: none; }

/* ---------- 涂卡圈：印在每个选项的正前方（2026-09-16 晚改版） ----------
   学生涂哪个选项，就涂那个选项前面的圈 —— 跟着选项走，不用"题下找一行格"。
   ⚠️ 圈心坐标由 sheet.js 的 measureBlock() 实测 DOM 位置登记进 OMR 采样模型，
   所以这里的宽高就是"采样圆盘"的大小。改外观随便改（模型跟着实测走），
   改尺寸后务必重跑 .workbuddy/tmp/bubomr.js 的合成识别测试。 */
.obub {
  display: inline-block;
  box-sizing: border-box;
  width: 4.2mm; height: 4.2mm;
  margin-right: 1.2mm;
  border: 0.5pt solid #5b6470;
  border-radius: 50%;
  background: #fff;
  /* 与选项文字行内对齐；选项折行时圈停在第一行行首，位置直觉自然 */
  vertical-align: middle;
}

/* ---------- 数学公式渲染（math.js 的输出） ----------
   ⚠️ .mfrac 必须用 vertical-align:middle（几何对齐）：
   inline-flex 的"基线"取第一个子元素（分子）的文字基线，
   若用 length 型 vertical-align 会把分子基线压到正文基线之下，
   整个分式下坠；分子内容不同时合成基线还会漂移（忽高忽低）。
   middle 把盒子中点（=分数线）对到 x 高度中线（≈数学轴），
   与 .mimg 公式图的对齐口径一致，任何上下文都稳定。 */
.mfrac {
  display: inline-flex; flex-direction: column; vertical-align: middle;
  text-align: center; margin: 0 .14em; line-height: 1.14; font-size: .95em;
}
.mfrac > .mn { padding: 0 .2em; }
.mfrac > .md { border-top: .055em solid currentColor; padding: 0 .2em; }
.msqrt { display: inline-block; white-space: nowrap; }
.msqrt > .mo { font-size: .62em; vertical-align: .45em; margin-right: -.1em; }
.msqrt > .mi { font-size: 1.08em; }
.msqrt > .mr { border-top: .055em solid currentColor; padding: 0 .16em 0 .08em; }
.movl { border-top: .055em solid currentColor; padding-top: .06em; }
.muw { border-bottom: .055em solid currentColor; padding-bottom: .06em; }
.mtag { position: relative; display: inline-block; }
.mtag > .mmk { font-size: .72em; margin-left: -.6em; position: relative; top: -.5em; }

/* 导入卷子时从 WMF 转出来的公式图（MathType 对象）。
   MathType 的外框把下伸部分也算进去了，所以用 middle 对齐才和旁边的字齐平；
   宽度限死 100%，免得一道长公式把打印栏挤爆。 */
.mimg {
  vertical-align: middle; max-width: 100%;
  background: #fff; border: 0;
  /* 打印时别让浏览器把公式拆到两页去 */
  break-inside: avoid; page-break-inside: avoid;
}
/* 图没转出来时的占位。它一定是"这里本该有东西"，所以给个底色让人一眼看到 */
.mimg-miss {
  display: inline-block; padding: 0 .3em; border-radius: 3px;
  background: #fff4e5; color: #a36b00; font-size: .88em;
  border: 1px dashed #e0a94a;
}

/* ---------- 选项排版：A．正文 ---------- */
/* 默认横排（短-长都行）；用户/排版器可强制 row-4/row-2/col 三档 */
.mopts { margin-left: 6mm; }
.mopt { display: inline-block; min-width: 43mm; padding-right: 3mm; vertical-align: top; }
.mopt > .ml { font-weight: 700; }

/* 短（每条 ≤14 视觉宽）：四列平铺，最省纸 */
.mopts.row-4 { display: grid; grid-template-columns: repeat(4, 1fr); column-gap: 3mm; }
.mopts.row-4 .mopt { display: block; min-width: 0; padding-right: 0; }

/* 中（≤26）：两列并排，单题占两行 —— 视觉上比 row-4 多呼吸一些 */
.mopts.row-2 { display: grid; grid-template-columns: repeat(2, 1fr); column-gap: 6mm; }
.mopts.row-2 .mopt { display: block; min-width: 0; padding-right: 0; }

/* 长（>26）：竖列，一题一行（保纸用 4 列会挤成蚂蚁） */
.mopts.col .mopt { display: block; min-width: 0; width: 100%; padding-right: 0; }

.progressbar { height: 7px; border-radius: 999px; background: var(--c-line-2); overflow: hidden; }
.progressbar > i { display: block; height: 100%; background: var(--c-primary); border-radius: 999px; transition: width .3s; }

.qnav { display: flex; flex-wrap: wrap; gap: 6px; }
.qnav button {
  width: 38px; height: 38px; border-radius: var(--r-sm); border: 1px solid var(--c-line);
  background: #fff; cursor: pointer; font-size: 13px; font-variant-numeric: tabular-nums;
}
.qnav button.cur { border-color: var(--c-primary); background: var(--c-primary-soft); font-weight: 700; color: var(--c-primary-dark); }
.qnav button.done { background: var(--c-ok-soft); border-color: #c7eed6; color: #15803d; }

.scroll-y { overflow-y: auto; }

.hidden { display: none !important; }
.muted { color: var(--c-ink-3); }
.small { font-size: 12.5px; }
.c-ok-text { color: #15803d; }
.c-bad-text { color: #b91c1c; }

/* ---------- 设置页：AI 配置的两栏小盒 ---------- */
.ai-box {
  border: 1px solid var(--c-line-2);
  border-radius: 10px;
  padding: 12px 14px 14px;
  background: #fcfdff;
}
.ai-box-h {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--c-ink);
  padding-bottom: 8px;
  margin-bottom: 10px;
  border-bottom: 1px dashed var(--c-line-2);
}
.ai-box a { color: var(--c-primary); word-break: break-all; }
.mono { font-family: ui-monospace, Consolas, "Courier New", monospace; }

/* ---------- 手写作答识别结果 ---------- */
.mb8 { margin-bottom: 8px; }
.ocr-row {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px solid #dbe6f5;
  border-radius: 10px;
  background: #f7faff;
}
.ocr-crop {
  flex: 0 0 auto;
  width: 168px;
  max-height: 120px;
  object-fit: contain;
  background: #fff;
  border: 1px solid var(--c-line-2);
  border-radius: 6px;
  /* 裁出来的作答区本来是横向长条，给个浅色底方便看清边界 */
  box-shadow: inset 0 0 0 1px #fff;
}
.ocr-crop.nocrop {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 60px;
  color: var(--c-ink-3);
  font-size: 12px;
}
.ocr-txt { flex: 1 1 auto; min-width: 0; }
.ocr-txt-body {
  margin-top: 3px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--c-ink);
  white-space: pre-wrap;
  word-break: break-word;
  /* 手写答案常带分数线、根号，等宽一点更好认 */
  font-family: "Cambria Math", "Times New Roman", "KaiTi", serif;
}
.ocr-tag { flex: 0 0 auto; white-space: nowrap; }
@media print { .ocr-row { display: none; } }
.right { text-align: right; }
.center { text-align: center; }
.mb0 { margin-bottom: 0 !important; }
.mt8 { margin-top: 8px; } .mt12 { margin-top: 12px; } .mt16 { margin-top: 16px; }
.gap8 { gap: 8px; } .gap12 { gap: 12px; }
.flex { display: flex; align-items: center; }
.flex-wrap { flex-wrap: wrap; }

/* ===========================================================
   学生错题本
   =========================================================== */

/* ---------- 学生选择带 ---------- */
.nb-picker {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding: 4px 2px 12px;
  margin-bottom: 4px;
}
.nb-chip {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 14px 8px 9px;
  border: 1px solid var(--c-line);
  border-radius: 999px;
  background: #fff;
  cursor: pointer;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.nb-chip:hover { border-color: #c7d6ee; box-shadow: var(--shadow-sm); }
.nb-chip.on {
  border-color: var(--c-primary);
  background: var(--c-primary-soft);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, .10);
}
.nb-av {
  width: 32px; height: 32px;
  flex: 0 0 32px;
  border-radius: 50%;
  background: #e7eefb;
  color: var(--c-primary-dark);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 15px;
  position: relative;
}
.nb-av.hot::after {
  content: '';
  position: absolute; top: -1px; right: -1px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--c-bad);
  border: 2px solid #fff;
}
.nb-chip.on .nb-av { background: var(--c-primary); color: #fff; }
.nb-chip-t { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.25; }
.nb-chip-t b { font-size: 14px; font-weight: 600; }
.nb-chip-t span { font-size: 11.5px; color: var(--c-ink-3); }

/* ---------- 总览卡 ---------- */
.nb-head {
  display: grid;
  grid-template-columns: 172px minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 22px;
  align-items: start;
  padding: 20px 22px;
}
.nb-head-l { display: flex; align-items: center; justify-content: center; }
.nb-ring { width: 150px; height: 150px; }
.nb-ring-v { font-size: 25px; font-weight: 700; fill: var(--c-ink); }
.nb-ring-k { font-size: 11px; fill: var(--c-ink-3); }
.nb-name { font-size: 20px; font-weight: 700; margin-bottom: 12px; }
.nb-mini { gap: 10px !important; }
.nb-mini .stat { padding: 10px 12px; border-color: var(--c-line-2); background: #f8fafd; }
.nb-mini .stat .v { font-size: 21px; }
.nb-tl-h, .nb-sec-t {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--c-ink-3);
  letter-spacing: .3px;
  margin: 16px 0 9px;
}
.nb-sec-t { margin: 22px 0 11px; font-size: 14px; color: var(--c-ink-2); }
.nb-sec-list { margin-top: 20px; }

/* ---------- 复习时间轴 ---------- */
.nb-tl {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  position: relative;
  padding-top: 3px;
}
.nb-tl::before {
  content: '';
  position: absolute; left: 6px; right: 6px; top: 16px;
  height: 2px; background: var(--c-line-2);
}
.nb-tl-node { flex: 1 1 0; text-align: center; position: relative; }
.nb-tl-dot {
  width: 28px; height: 28px;
  margin: 0 auto 6px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--c-line);
  color: var(--c-ink-3);
  font-size: 12.5px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  position: relative; z-index: 1;
  font-variant-numeric: tabular-nums;
}
.nb-tl-node.on .nb-tl-dot { border-color: var(--c-primary); color: var(--c-primary-dark); background: var(--c-primary-soft); }
.nb-tl-node.now .nb-tl-dot { border-color: var(--c-ok); color: #15803d; }
.nb-tl-node.now.on .nb-tl-dot { border-color: var(--c-bad); background: var(--c-bad-soft); color: #b91c1c; }
.nb-tl-lab { display: flex; flex-direction: column; line-height: 1.3; }
.nb-tl-lab b { font-size: 11.5px; font-weight: 600; color: var(--c-ink-2); }
.nb-tl-lab span { font-size: 10.5px; color: var(--c-ink-3); }

/* ---------- 知识点薄弱分布 ---------- */
.nb-kp { display: grid; grid-template-columns: minmax(0, 1fr) 108px 46px; gap: 10px; align-items: center; margin-bottom: 9px; }
.nb-kp-k {
  font-size: 12.5px;
  color: var(--c-ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nb-kp-bar { display: flex; height: 8px; border-radius: 999px; overflow: hidden; background: var(--c-line-2); }
.nb-kp-bar > i { display: block; height: 100%; }
.nb-kp-bar > i.bad { background: #f0a3a3; }
.nb-kp-bar > i.ok { background: #8fd3a6; }
.nb-kp-n { font-size: 12px; color: var(--c-ink-3); text-align: right; font-variant-numeric: tabular-nums; }
.nb-kp-n b { color: var(--c-bad); }

/* ---------- 错题卡 ---------- */
.nb-card {
  background: #fff;
  border: 1px solid var(--c-line);
  border-radius: var(--r);
  padding: 16px 18px;
  margin-bottom: 12px;
  box-shadow: var(--shadow-sm);
}
.nb-card.done { opacity: .72; background: #fbfdfc; }
.nb-card-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.nb-no {
  width: 24px; height: 24px;
  border-radius: 7px;
  background: var(--c-primary-soft);
  color: var(--c-primary-dark);
  font-size: 12.5px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.nb-card.done .nb-no { background: var(--c-ok-soft); color: #15803d; }
.nb-card-h .spacer { flex: 1; }
.nb-wrong-n { font-size: 12px; color: var(--c-ink-3); font-variant-numeric: tabular-nums; }
.tag.kp { background: #eef2f7; color: var(--c-ink-2); }

.nb-stem {
  font-size: 15.5px;
  line-height: 1.75;
  color: var(--c-ink);
  white-space: pre-wrap;
  word-break: break-word;
  margin-bottom: 10px;
}
.nb-opts { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-bottom: 12px; }
.nb-opt { font-size: 14px; color: var(--c-ink-2); display: flex; gap: 6px; }
.nb-opt b { color: var(--c-ink-3); font-weight: 600; }

.nb-ans { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.nb-ans-cell {
  border-radius: var(--r-sm);
  padding: 9px 12px;
  border: 1px solid var(--c-line-2);
  background: #fafbfd;
  min-width: 0;
}
.nb-ans-cell.bad { background: #fdf6f6; border-color: #f6dede; }
.nb-ans-cell.ok { background: var(--c-ok-soft); border-color: #d6f0e0; }
.nb-ans-k {
  font-size: 11.5px;
  color: var(--c-ink-3);
  margin-bottom: 5px;
  display: flex; align-items: center; gap: 6px;
}
.nb-ans-cell.ok .nb-ans-k { color: #15803d; }
.nb-ans-cell.bad .nb-ans-k { color: #b91c1c; }
.nb-ans-v {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--c-ink);
  white-space: pre-wrap;
  word-break: break-word;
  font-family: "Cambria Math", "Times New Roman", "KaiTi", serif;
}
.nb-src {
  font-size: 10.5px;
  padding: 1px 5px;
  border-radius: 4px;
  background: #eef2f7;
  color: var(--c-ink-3);
  font-family: var(--ff);
}

.nb-more { margin-top: 12px; }
.nb-more > summary {
  cursor: pointer;
  font-size: 13px;
  color: var(--c-primary);
  list-style: none;
  user-select: none;
}
.nb-more > summary::-webkit-details-marker { display: none; }
.nb-more > summary::before { content: '▸ '; }
.nb-more[open] > summary::before { content: '▾ '; }
.nb-analysis {
  margin-top: 8px;
  padding: 10px 12px;
  border-left: 3px solid #cfe0fb;
  background: #f8fbff;
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  font-size: 14px;
  line-height: 1.7;
  color: var(--c-ink-2);
  white-space: pre-wrap;
  word-break: break-word;
}

.nb-card-f {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px dashed var(--c-line);
}
.nb-card-f .spacer { flex: 1; }
.nb-steps { display: flex; gap: 4px; align-items: center; }
.nb-step { width: 16px; height: 6px; border-radius: 3px; background: var(--c-line); display: block; }
.nb-step.ok { background: #8fd3a6; }
.nb-step.cur { background: var(--c-warn); }
.nb-hists { display: flex; gap: 4px; align-items: center; }
.nb-h { width: 8px; height: 8px; border-radius: 50%; display: block; }
.nb-h.ok { background: var(--c-ok); }
.nb-h.bad { background: #f0a3a3; }

@media print {
  .nb-picker, .nb-card-f { display: none; }
  .nb-head { grid-template-columns: 150px minmax(0, 1fr); }
  .nb-head-r { display: none; }
  .nb-card { break-inside: avoid; page-break-inside: avoid; box-shadow: none; }
  .nb-more { display: none; }
}

/* ===========================================================
   题库：筛选栏 / 批量操作栏 / 题目卡片
   =========================================================== */

.bank-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding-bottom: 16px;
}

/* 搜索框要比普通输入框显眼一点 —— 老师第一反应是打字找题，不是翻下拉 */
.bank-search {
  flex: 1 1 220px;
  min-width: 180px;
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--c-line);
  border-radius: var(--r-sm);
  background: #fff;
  outline: none;
}
.bank-search::-webkit-search-cancel-button { cursor: pointer; }
.bank-search:focus { border-color: var(--c-primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .12); }

.bank-bar select {
  height: 34px;
  padding: 0 8px;
  border: 1px solid var(--c-line);
  border-radius: var(--r-sm);
  background: #fff;
  cursor: pointer;
  max-width: 200px;
}
/* 有值的下拉框描个蓝边：一眼能看出"现在筛着呢" */
.bank-bar select.bank-sel.on {
  border-color: var(--c-primary);
  background: var(--c-primary-soft);
  color: var(--c-primary-dark);
  font-weight: 600;
}

.bank-batch {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 10px 16px;
  border-top: 1px solid var(--c-line-2);
  border-bottom: 1px solid var(--c-line-2);
  background: #fbfcfe;
}
.bank-batch.on { background: var(--c-primary-soft); border-color: #cddffd; }
.bank-cnt { font-size: 13px; color: var(--c-ink-2); }
.bank-cnt b { color: var(--c-primary-dark); font-size: 15px; }

.bank-ck { display: inline-flex; align-items: center; }
.bank-ck input { width: 17px; height: 17px; cursor: pointer; accent-color: var(--c-primary); }

.bank-item { transition: background .12s; }
.bank-item.on { background: #f5f9ff; box-shadow: inset 3px 0 0 var(--c-primary); }

.bank-tags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }

.tag.gray { background: #eef2f7; color: var(--c-ink-3); }
.tag.d1 { background: var(--c-ok-soft); color: #15803d; }
.tag.d2 { background: var(--c-warn-soft); color: #b45309; }
.tag.d3 { background: var(--c-bad-soft); color: #b91c1c; }

.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn:disabled:hover { transform: none; }

@media print {
  .bank-bar, .bank-batch { display: none; }
}

/* ===========================================================
   教师题库（独立模块）：左分类树 · 中题目网格 · 右预览与组卷
   =========================================================== */
.lib {
  display: grid;
  grid-template-columns: 214px minmax(0, 1fr) 296px;
  gap: 14px;
  align-items: start;
}
@media (max-width: 1320px) { .lib { grid-template-columns: 196px minmax(0, 1fr) 268px; } }
@media (max-width: 1120px) {
  .lib { grid-template-columns: minmax(0, 1fr); }
  .lib-cats, .lib-side { position: static; max-height: none; }
}

.lib-col { background: var(--c-panel); border: 1px solid var(--c-line); border-radius: var(--r); }
/* 左右两列各自吸附，只有中间那列跟页面滚 —— 否则翻到第 80 题时
   分类树早跑没了，老师得一路滚回顶上重新点分类。
   topbar 本身 sticky 高 60px：钉住时贴在它正下方，顶部不会再被盖掉一截。 */
.lib-cats, .lib-side {
  position: sticky;
  top: 60px;
  max-height: calc(100vh - 72px);
  overflow: auto;
  padding: 10px;
}
.lib-main { border: 0; background: transparent; }

/* 中间列顶部的筛选条 + 批量栏钉住不跟着滚（2026-09-18 老师补充）：
   往下翻题时搜索、筛选、批量操作一直在手边，只有题单在下面滚。
   两条拼成一张卡（筛选条去下外距/下圆角，批量栏接上并补回与题单的间距）；
   z 值压过题卡，低于弹窗(100)和侧栏(60)。 */
.lib-pin { position: sticky; top: 60px; z-index: 30; }
.lib-pin .lib-tool { margin-bottom: 0; border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.lib-pin .bank-batch { border-radius: 0 0 var(--r) var(--r); margin-bottom: 14px; }

.lib-col-hd { display: flex; align-items: center; gap: 6px; padding: 2px 4px 8px; }
.lib-col-hd h3 {
  margin: 0; font-size: 12px; font-weight: 600;
  color: var(--c-ink-3); letter-spacing: .5px;
}

.lib-ico {
  width: 20px; height: 20px; padding: 0; line-height: 18px;
  text-align: center; font-size: 12px; cursor: pointer;
  border: 1px solid var(--c-line); border-radius: 6px;
  background: #fff; color: var(--c-ink-3);
}
.lib-ico:hover { border-color: var(--c-primary); color: var(--c-primary); background: var(--c-primary-soft); }
.lib-ico.bad:hover { border-color: var(--c-bad); color: var(--c-bad); background: var(--c-bad-soft); }

.lib-tree { font-size: 13px; }
.lib-node {
  display: flex; align-items: center; gap: 4px;
  padding: 5px 6px; border-radius: 7px;
  cursor: pointer; color: var(--c-ink-2);
}
.lib-node:hover { background: var(--c-line-2); }
.lib-node.on { background: var(--c-primary-soft); color: var(--c-primary-dark); font-weight: 600; }
.lib-arrow { flex: 0 0 14px; width: 14px; text-align: center; font-size: 11px; color: var(--c-ink-3); }
.lib-arrow.none { visibility: hidden; }
.lib-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-num {
  font-size: 11px; color: var(--c-ink-3);
  background: var(--c-line-2); border-radius: 9px; padding: 1px 6px;
}
.lib-node.on .lib-num { background: #fff; color: var(--c-primary); }
.lib-ops { display: none; gap: 3px; }
.lib-node:hover .lib-ops { display: flex; }
.lib-tree .lib-ico { width: 18px; height: 18px; line-height: 16px; font-size: 11px; }
.lib-clear { width: 100%; margin: 4px 0 2px; }

.lib-tags { display: flex; flex-wrap: wrap; gap: 5px; padding: 0 4px 4px; }
.lib-tag {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 12px; padding: 3px 8px; border-radius: 999px;
  border: 1px solid var(--c-line); background: #fff;
  color: var(--c-ink-2); cursor: pointer;
}
.lib-tag:hover { border-color: var(--c-primary); color: var(--c-primary); }
.lib-tag-n { font-style: normal; font-size: 10px; opacity: .75; }
.lib-tag .lib-ico { width: 15px; height: 15px; line-height: 13px; font-size: 10px; border: 0; background: transparent; }
.lib-tag.c-blue { border-color: #c3cdf9; background: #f1f2ff; color: #4338ca; }
.lib-tag.c-green { border-color: #bfe6cd; background: #f0fbf4; color: #15803d; }
.lib-tag.c-amber { border-color: #f0d9a8; background: #fff9ec; color: #b45309; }
.lib-tag.c-red { border-color: #f5c2c2; background: #fdf1f1; color: #b91c1c; }
.lib-tag.c-purple { border-color: #d9c9f7; background: #f7f3ff; color: #6d28d9; }
.lib-tag.c-teal { border-color: #b6e3dc; background: #eefaf7; color: #0f766e; }
.lib-tag.on { background: var(--c-primary); border-color: var(--c-primary); color: #fff; }
.lib-tag.sm { padding: 2px 7px; font-size: 11px; }

.lib-tool {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: var(--c-panel); border: 1px solid var(--c-line);
  border-radius: var(--r); padding: 8px 10px; margin-bottom: 12px;
}
.lib-tool select {
  height: 34px; padding: 0 8px; cursor: pointer; max-width: 150px;
  border: 1px solid var(--c-line); border-radius: var(--r-sm); background: #fff;
}
.lib-tool select.bank-sel.on {
  border-color: var(--c-primary); background: var(--c-primary-soft);
  color: var(--c-primary-dark); font-weight: 600;
}

.lib-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 12px;
}
.lib-card {
  display: flex; flex-direction: column; gap: 7px;
  background: var(--c-panel); border: 1px solid var(--c-line);
  border-radius: var(--r); padding: 10px 12px 9px;
  cursor: pointer; transition: border-color .12s, box-shadow .12s;
}
.lib-card:hover { border-color: #c7d6ef; box-shadow: var(--shadow-sm); }
.lib-card.on { border-color: var(--c-primary); box-shadow: 0 0 0 2px var(--c-primary-soft); }
.lib-card.open { border-color: var(--c-primary-dark); box-shadow: 0 0 0 3px var(--c-primary-soft); }
.lib-card-top { display: flex; align-items: center; gap: 5px; }
.lib-score { font-size: 12px; color: var(--c-ink-3); }
.lib-ck { display: flex; align-items: center; }
.lib-ck input { width: auto; margin: 0; }

/* 有图的题先给张缩略图 —— 一眼认出来比读两行字快 */
.lib-thumb {
  height: 54px; display: flex; align-items: center; justify-content: center;
  background: #fafbfd; border: 1px solid var(--c-line-2);
  border-radius: var(--r-sm); overflow: hidden;
}
.lib-thumb img { max-height: 48px; max-width: 92%; object-fit: contain; }

.lib-stem {
  margin: 0; font-size: 13px; line-height: 1.6; color: var(--c-ink);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; word-break: break-word;
}
.lib-stem img { max-height: 26px; vertical-align: middle; }
.lib-card-bot { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; font-size: 11px; }
.lib-cat {
  color: var(--c-ink-3); background: var(--c-line-2); border-radius: 5px;
  padding: 1px 6px; max-width: 120px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- 左栏分类树 · 视觉增强（2026-09-18 老师第一条） ----------
   浅靛渐变底 + 选中态左侧色条，让"竖列标签栏"不再是一排灰字。 */
.lib-cats {
  background: linear-gradient(180deg, #ffffff 0%, #f6f8ff 100%);
  border-color: #d9e2f5;
  box-shadow: var(--shadow-sm);
}
.lib-col-hd h3::before {
  content: ''; display: inline-block; width: 6px; height: 6px;
  border-radius: 50%; background: var(--c-primary); opacity: .55;
  margin-right: 6px; vertical-align: 2px;
}
.lib-tree .lib-node {
  position: relative; padding: 6px 8px; margin: 1px 0;
  transition: background .12s, color .12s;
}
.lib-tree .lib-node:hover { background: #edf2fd; }
.lib-tree .lib-node.on {
  background: linear-gradient(90deg, var(--c-primary-soft), rgba(238, 242, 255, .35));
  color: var(--c-primary-dark); font-weight: 600;
  box-shadow: inset 3px 0 0 var(--c-primary);
}
.lib-num { font-weight: 600; }
.lib-tree .lib-node.on .lib-num { background: var(--c-primary); color: #fff; }

/* ---------- 组卷网式横向题卡（默认视图，2026-09-18） ----------
   一道题占满一整行：左侧题号块、中间题干全文 + 选择题选项、右侧勾选与单题操作。
   类名沿用 .lib-card —— 点开预览 / 勾选批量 / 筛选计数都挂在它上面。 */
.lib-zj { display: flex; flex-direction: column; gap: 10px; }
.lib-zj .zjcard {
  flex-direction: row; gap: 12px; align-items: stretch;
  padding: 12px 14px;
}
.zj-no {
  flex: 0 0 34px; width: 34px; align-self: flex-start;
  text-align: center; font-size: 15px; font-weight: 700;
  color: var(--c-primary); background: var(--c-primary-soft);
  border-radius: 8px; padding: 5px 0 4px; margin-top: 2px;
}
.zj-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
.zj-head { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; font-size: 11px; }
.zj-cat {
  color: var(--c-ink-3); background: var(--c-line-2); border-radius: 5px;
  padding: 1px 6px; max-width: 180px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.zj-stem { font-size: 13.5px; line-height: 1.75; color: var(--c-ink); word-break: break-word; }
.zj-stem img { max-height: 60px; vertical-align: middle; }
/* 选项两列起步：每个选项至少 300px，碰到长选项自动收敛成单列 */
.zj-opts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 3px 18px; padding: 2px 0 0 4px;
}
.zj-opt { font-size: 13px; line-height: 1.6; color: var(--c-ink-2); min-width: 0; }
.zj-opt img { max-height: 26px; vertical-align: middle; }
.zj-foot { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; font-size: 11px; }
.zj-side {
  flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding-left: 12px; border-left: 1px dashed var(--c-line);
}
/* 勾选框常显（组卷要靠它），三个单题操作图标悬停才出现，一屏几十行也不吵 */
.zj-side .lib-ico { opacity: 0; transition: opacity .12s; }
.zjcard:hover .zj-side .lib-ico, .zjcard.open .zj-side .lib-ico { opacity: 1; }
.zj-side .lib-ck input { width: 16px; height: 16px; cursor: pointer; }
.lib-view-group { display: inline-flex; gap: 4px; }

.lib-list { background: var(--c-panel); border: 1px solid var(--c-line); border-radius: var(--r); overflow: hidden; }
.lib-row {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px; font-size: 13px; cursor: pointer;
  border-bottom: 1px solid var(--c-line-2);
}
.lib-row:last-child { border-bottom: 0; }
.lib-row:hover { background: #fafbfd; }
.lib-row.on { background: var(--c-primary-soft); }
.lib-row.open { box-shadow: inset 3px 0 0 var(--c-primary); }
.lib-row-stem { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--c-ink-2); }
.lib-row-stem img { max-height: 20px; vertical-align: middle; }
/* 行尾的单题操作：平时不出现，悬停或这行正被预览时露出来，
   免得一屏十几行全是图标、看着吵 */
.lib-row .lib-ops { display: none; gap: 2px; flex: none; }
.lib-row:hover .lib-ops, .lib-row.open .lib-ops { display: flex; }
.lib-row .lib-ico { width: 20px; height: 20px; line-height: 17px; font-size: 11px; }

.lib-side-btns { display: flex; flex-direction: column; gap: 6px; padding: 0 4px 6px; }
.lib-side-btns .btn { width: 100%; }
.lib-side-empty { padding: 4px 6px 8px; font-size: 12px; line-height: 1.7; color: var(--c-ink-3); }
.lib-side-empty p { margin: 0 0 8px; }

.lib-preview {
  background: #fbfcfe; border: 1px solid var(--c-line-2);
  border-radius: var(--r-sm); padding: 9px 10px;
  font-size: 13px; line-height: 1.7;
  max-height: 330px; overflow: auto;
}
.lib-prev-meta { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 7px; }
.lib-prev-stem img { max-height: 92px; }
.lib-prev-ans {
  margin-top: 8px; padding-top: 7px;
  border-top: 1px dashed var(--c-line); color: #15803d;
}
.lib-prev-an { margin-top: 7px; font-size: 12px; color: var(--c-ink-2); }
.lib-prev-an summary { cursor: pointer; color: var(--c-ink-3); }

.lib-quick { padding: 8px 4px 2px; }
.lib-quick-tags { display: flex; flex-wrap: wrap; gap: 5px; padding: 3px 0; }

@media print {
  .lib-tool, .lib-cats, .lib-side, #bank-batch { display: none !important; }
}

/* ===========================================================
   扫描批改：选项对错面板（2026-09-21 第十二轮，需求四/五）
   目标：对错强对比、一眼扫完、排列绝对对齐、每题一格可容纳更多学生。
   · 用 CSS grid 固定列宽 —— 题号/选项/正确答案三段位置永远对齐，不随内容跳动
   · 对 = 绿底 + 绿粗边 + ✓；错 = 红底 + 红粗边 + ✗；未涂/存疑 = 灰底 + ?
   · 「正确答案」徽章只在错题旁出现（需求五），带独立底色，不与下一格混淆
   =========================================================== */
.gc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 7px;
}
.gc-cell {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: 9px;
  border: 1.6px solid var(--c-line-2); background: #fff;
  min-height: 42px;
}
.gc-cell.ok { background: var(--c-ok-soft); border-color: #7fd6a3; }
.gc-cell.bad { background: var(--c-bad-soft); border-color: #f0a0a0; }
.gc-cell.warn { background: #f8fafc; border-color: #d8dfe8; }
/* 三十一轮：多选漏选"部分分"—— 琥珀色，介于对（绿）与错（红）之间 */
.gc-cell.part { background: #fffbeb; border-color: #f5c66b; }
.gc-part {
  flex: 0 0 auto; margin-left: auto;
  font-size: 11.5px; font-weight: 700; color: #92400e;
  background: #fef3c7; border: 1px solid #f5c66b;
  border-radius: 6px; padding: 1px 6px; white-space: nowrap;
}
.gc-left { display: flex; align-items: center; gap: 5px; flex: 0 0 auto; }
.gc-no {
  font-size: 12px; font-weight: 600; color: var(--c-ink-3);
  min-width: 18px; text-align: right;
}
.gc-mark {
  font-size: 17px; font-weight: 800; line-height: 1; width: 18px; text-align: center;
}
.gc-cell.ok .gc-mark { color: var(--c-ok); }
.gc-cell.bad .gc-mark { color: var(--c-bad); }
.gc-cell.warn .gc-mark { color: #94a3b8; }
.gc-cell.part .gc-mark { color: #b45309; }
.gc-mid { display: flex; align-items: baseline; gap: 5px; flex: 1 1 auto; min-width: 0; }
.gc-got {
  font-size: 16px; font-weight: 800; letter-spacing: .4px;
  color: var(--c-ink); font-family: inherit;
}
.gc-cell.ok .gc-got { color: #15803d; }
.gc-cell.bad .gc-got { color: #b91c1c; }
.gc-cell.warn .gc-got { color: #64748b; }
.gc-note {
  font-size: 11px; color: var(--c-ink-3);
  background: #fff; border: 1px solid var(--c-line-2);
  border-radius: 999px; padding: 0 6px; white-space: nowrap;
}
/* 「正确 X」徽章：2026-09-21 十五轮老师要求改绿色（原来是琥珀色）——
   绿色 = 正确答案的直觉色，红底错题行上对比也更清楚。 */
.gc-right {
  flex: 0 0 auto; margin-left: auto;
  font-size: 11.5px; font-weight: 600; color: #166534;
  background: #f0fdf4; border: 1px solid #a7d7b9;
  border-radius: 6px; padding: 1px 6px; white-space: nowrap;
}
.gc-right b { font-size: 13px; font-weight: 800; color: #14532d; }
.gc-right.ok { color: #15803d; background: var(--c-ok-soft); border-color: #c7eed6; }

/* ---- 扫完一张卡的分数跳出动画（需求三）---- */
.score-pop {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none; background: rgba(15,23,42,.32);
  animation: scoreFadeIn .18s ease-out;
}
.score-pop-card {
  background: #fff; border-radius: 20px; padding: 26px 44px 22px;
  text-align: center; box-shadow: 0 18px 50px rgba(15,23,42,.3);
  animation: scoreJump .55s cubic-bezier(.2,1.5,.4,1);
  min-width: 260px;
}
.score-pop-name { font-size: 17px; font-weight: 700; color: var(--c-ink-2); margin-bottom: 2px; }
.score-pop-num {
  font-size: 60px; font-weight: 800; line-height: 1.1; letter-spacing: -1px;
  color: var(--c-primary); font-variant-numeric: tabular-nums;
}
.score-pop-num .u { font-size: 22px; color: var(--c-ink-3); font-weight: 600; }
.score-pop-sub { font-size: 14px; color: var(--c-ink-3); margin-top: 4px; }
.score-pop-bar { margin-top: 12px; height: 8px; border-radius: 99px; background: #eef2f7; overflow: hidden; }
.score-pop-bar > i { display: block; height: 100%; border-radius: 99px; background: linear-gradient(90deg,#4ade80,#16a34a);
  animation: scoreGrow .7s .12s cubic-bezier(.3,1.2,.4,1) both; }
.score-pop.perfect .score-pop-num { color: var(--c-ok); }
.score-pop.bad .score-pop-num { color: var(--c-bad); }
/* 需求六（第二十轮）：得分率 ≥ 60% 走"金色卡片"——
   学生扫完抬头看到卡是金色的，不用听播报也知道"这次过了"。 */
.score-pop.gold .score-pop-card {
  border: 2px solid #eac659;
  background: linear-gradient(180deg, #fffefa 0%, #fff6dd 100%);
  box-shadow: 0 18px 50px rgba(180, 140, 20, .32);
}
.score-pop.gold .score-pop-name { color: #8a6415; }
.score-pop.gold .score-pop-num { color: #b8860b; }
.score-pop.gold .score-pop-num .u { color: #b99a4e; }
.score-pop.gold .score-pop-sub { color: #a07b1e; }
.score-pop.gold .score-pop-bar { background: #f7ecd0; }
.score-pop.gold .score-pop-bar > i { background: linear-gradient(90deg, #f7d774, #d4a029); }
@keyframes scoreFadeIn { from { opacity: 0 } to { opacity: 1 } }
@keyframes scoreJump {
  0%   { transform: scale(.4) translateY(30px); opacity: 0 }
  60%  { transform: scale(1.08) translateY(0); opacity: 1 }
  100% { transform: scale(1) translateY(0); opacity: 1 }
}
@keyframes scoreGrow { from { width: 0 } }
@media print { .score-pop { display: none !important } }

/* ============================================================
   第二十一轮（2026-09-22）
   一、成绩分析两栏改"左窄右宽"，明细表姓名/得分横排不折行，错题格只留正确答案
   二、扫描页右栏错题签只留题号 + 蓝色正确答案（见上方 .wchip）
   三、逐题讲评弹窗全屏 + 触屏双指缩放 + 右下角关闭
   四、满分选手专属庆祝弹窗
   ============================================================ */

/* ---- 需求一：左窄右宽 ---- */
.grid.stats-grid { grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.72fr); }
@media (max-width: 1000px) { .grid.stats-grid { grid-template-columns: minmax(0, 1fr); } }

/* ---- 需求一：学生成绩明细表 ----
   原来列宽被挤得很窄，"王梓涵"这种三字姓名会一个字一行竖着排。
   现在姓名 / 得分强制不折行，题号列压紧；题太多时表格自己横向滚动，不撑破卡片。 */
.tbl-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.tbl.detail-tbl th, table.tbl.detail-tbl td { padding: 7px 7px; white-space: nowrap; font-size: 13px; }
table.tbl.detail-tbl th { font-size: 12.5px; }
table.tbl.detail-tbl .stu { font-size: 13.5px; }
table.tbl.detail-tbl .score { white-space: nowrap; }
table.tbl.detail-tbl .score b { font-size: 14.5px; }
table.tbl.detail-tbl td.center { padding: 7px 5px; }
table.tbl.detail-tbl .rca { margin: 0; }

/* ---- 需求三：讲评弹窗全屏 ----
   希沃一体机上投屏讲题，后排学生也得看清公式，所以整屏铺开、去掉圆角与留白。 */
.modal-mask.full { padding: 0; }
.modal.full {
  position: relative;
  width: 100vw; max-width: 100vw; height: 100vh; max-height: 100vh;
  border-radius: 0; box-shadow: none;
}
.modal.full .modal-h { padding: 10px 18px; }
.modal.full .modal-h h3 { font-size: 15px; }
.modal.full .modal-b {
  padding: 20px 26px; flex: 1 1 auto; overscroll-behavior: contain;
  /* 交给 JS 处理双指手势，禁掉浏览器自带的页面级缩放 */
  touch-action: pan-x pan-y;
}
.modal.full .modal-f {
  /* 需求三：右下角保留关闭按钮 —— 浮在内容之上，不占版面、不随滚动跑掉 */
  position: fixed; right: 22px; bottom: 22px; z-index: 5;
  border: 0; padding: 0; background: transparent;
}
.modal.full .modal-f .btn.lg { box-shadow: 0 10px 26px rgba(15,23,42,.3); }

/* ---- 需求三：双指缩放的内容层 ----
   原点默认放左上：放大后只会往右下溢出，不会出现"左上角滚不到"的负向溢出。
   捏合时 JS 会把原点临时改到两指中点（捏哪儿放哪儿）。 */
.zoom-stage {
  transform-origin: 0 0;
  will-change: transform;
  backface-visibility: hidden;
}

/* ---- 需求三：全屏讲评里的大字号选项，正确答案高亮 ----
   二十七轮：老师反馈"不缩放时题干整体偏小，学生看不清"——选项 17→20px，
   题干在 openStatsQuestion 里 20→24px，答案解析 17→20px。 */
.qopts.big { gap: 8px; margin-top: 14px; }
.qopts.big .qopt {
  padding: 12px 16px; font-size: 20px; border-radius: 10px;
  border: 1px solid var(--c-line-2); background: #fff;
}
.qopts.big .qopt .opt-l { display: inline-block; min-width: 30px; color: var(--c-ink-3); }
.qopts.big .qopt.right-opt {
  background: #eefbf2; border-color: #86d9a3; color: #14532d; font-weight: 700;
  box-shadow: inset 0 0 0 1px rgba(22,163,74,.16);
}
.qopts.big .qopt.right-opt .opt-l { color: #15803d; }

/* ---- 需求四：满分选手的专属庆祝弹窗 ----
   老师原话："满分选手给设计一个炫酷的弹窗，要有视觉冲击力，让大家羡慕。"
   满屏金色放射光 + 30 片彩纸 + 奖杯浮动 + 分数滚动 + 星标逐个亮起。 */
.score-pop.perfect { background: rgba(38,24,2,.58); overflow: hidden; }
.pf-rays {
  position: absolute; left: 50%; top: 50%; width: 200vmax; height: 200vmax;
  margin: -100vmax 0 0 -100vmax; pointer-events: none;
  background: repeating-conic-gradient(from 0deg,
    rgba(255,205,80,.34) 0deg 8deg, rgba(255,205,80,0) 8deg 17deg);
  animation: pfRays 10s linear infinite;
}
@keyframes pfRays { to { transform: rotate(360deg) } }
.pf-confetti { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.pf-confetti .cf {
  position: absolute; top: -8vh; border-radius: 2px; opacity: 0;
  animation-name: pfFall; animation-timing-function: linear;
  animation-iteration-count: 1; animation-fill-mode: both;
}
@keyframes pfFall {
  0%   { transform: translateY(-10vh) rotate(0deg); opacity: 0 }
  12%  { opacity: 1 }
  100% { transform: translateY(114vh) rotate(700deg); opacity: .9 }
}
.score-pop.perfect .pf-card {
  position: relative; z-index: 2; overflow: hidden;
  padding: 30px 58px 26px; border-radius: 26px; border: 3px solid #e9bd4b;
  background: radial-gradient(120% 110% at 50% 0%, #fffdf3 0%, #fff3cf 56%, #ffe7a3 100%);
  box-shadow: 0 0 0 8px rgba(255,214,102,.26), 0 26px 70px rgba(150,105,10,.42);
  animation: pfIn .7s cubic-bezier(.16,1.5,.36,1) both;
}
.score-pop.perfect .pf-card::after {
  /* 一道白光横扫而过，卡片"亮"一下 */
  content: ''; position: absolute; top: -60%; left: -70%; width: 55%; height: 220%;
  background: linear-gradient(100deg, rgba(255,255,255,0), rgba(255,255,255,.85), rgba(255,255,255,0));
  transform: rotate(16deg); animation: pfShine 2.2s .35s ease-out 1 both; pointer-events: none;
}
@keyframes pfShine { from { left: -70% } to { left: 130% } }
@keyframes pfIn {
  0%   { transform: scale(.35) rotate(-7deg); opacity: 0 }
  55%  { transform: scale(1.1) rotate(2deg); opacity: 1 }
  76%  { transform: scale(.97) rotate(-1deg) }
  100% { transform: scale(1) rotate(0deg); opacity: 1 }
}
.pf-trophy {
  font-size: 62px; line-height: 1;
  animation: pfTrophy 1.5s .1s ease-in-out infinite alternate;
  filter: drop-shadow(0 8px 16px rgba(180,130,20,.45));
}
@keyframes pfTrophy { from { transform: translateY(0) scale(1) } to { transform: translateY(-9px) scale(1.07) } }
.pf-ribbon {
  display: inline-block; margin: 8px 0 4px; padding: 3px 20px;
  font-size: 15px; font-weight: 800; letter-spacing: 5px; color: #fff;
  background: linear-gradient(90deg, #e0a01e, #b8860b);
  border-radius: 999px; box-shadow: 0 4px 12px rgba(180,130,20,.4);
}
.score-pop.perfect .pf-name {
  font-size: 26px; font-weight: 800; letter-spacing: 2px; color: #7a5a0d; margin: 4px 0 0;
}
.score-pop.perfect .pf-num {
  font-size: 92px; font-weight: 900; line-height: 1.05; letter-spacing: -2px;
  font-variant-numeric: tabular-nums;
  color: #b8860b;
  background: linear-gradient(180deg, #e8b62c 0%, #b8860b 62%, #8a6415 100%);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
  animation: pfNum .6s .18s cubic-bezier(.2,1.6,.4,1) both;
}
.score-pop.perfect .pf-num .u {
  font-size: 30px; font-weight: 700;
  color: #b99a4e; -webkit-text-fill-color: #b99a4e;
}
@keyframes pfNum { from { transform: scale(.4); opacity: 0 } to { transform: scale(1); opacity: 1 } }
.pf-banner {
  margin-top: 10px; padding: 7px 20px; border-radius: 999px;
  font-size: 17px; font-weight: 800; color: #7a5a0d;
  background: linear-gradient(90deg, #fff2c2, #ffe08a, #fff2c2);
  border: 1px solid #eac659;
}
.pf-stars { margin-top: 10px; font-size: 24px; letter-spacing: 6px; color: #e9b422; }
.pf-star { display: inline-block; animation: pfStar .5s cubic-bezier(.2,1.6,.4,1) both; }
@keyframes pfStar { from { opacity: 0; transform: scale(0) rotate(-90deg) } to { opacity: 1; transform: scale(1) rotate(0) } }
@media (max-width: 620px) {
  .score-pop.perfect .pf-card { padding: 22px 26px 20px; }
  .score-pop.perfect .pf-num { font-size: 64px; }
  .score-pop.perfect .pf-name { font-size: 21px; }
  .pf-trophy { font-size: 46px; }
  .pf-banner { font-size: 15px; }
}
@media print { .score-pop.perfect { display: none !important } }

/* ===========================================================
   第三十四轮 · 错题攻克鼓励系统
   段位徽章 / 攻克英雄榜 / 成就墙（翻卡）/ 成就揭晓庆祝
   =========================================================== */
/* 段位徽章（跟着学生名走的小标签） */
.achv-rank {
  display: inline-block; padding: 1px 8px; border-radius: 999px;
  font-size: 11.5px; font-weight: 700; white-space: nowrap;
  color: #92400e; background: linear-gradient(90deg, #fef3c7, #fde68a);
  border: 1px solid #f59e0b55; vertical-align: middle;
}
/* 英雄榜 */
.achv-top1 td { background: rgba(245, 158, 11, .06); }
.achv-top1 .achv-n { color: #b45309; }
.achv-medal { font-size: 20px; }
.achv-place { display: inline-block; min-width: 26px; text-align: center; font-weight: 700; color: var(--c-ink-3); }
.achv-n { font-size: 15px; }
.achv-star { font-size: 15px; opacity: .25; filter: grayscale(1); margin: 0 2px; transition: all .25s; }
.achv-star.got { opacity: 1; filter: none; text-shadow: 0 0 6px rgba(245, 158, 11, .55); }
/* 成就墙（弹窗） */
.ac-wall-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.ac-wall-icon {
  width: 52px; height: 52px; border-radius: 14px; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 28px; background: linear-gradient(135deg, #fef3c7, #fde68a);
  border: 1px solid #f59e0b55;
}
.ac-wall-name { font-size: 17px; font-weight: 800; }
.ac-wall-rank { font-size: 13px; color: var(--c-ink-2); }
.ac-wall-cards { display: flex; gap: 12px; flex-wrap: wrap; }
/* 成就卡：3D 翻转进场（achvFlip / 抽卡翻牌） */
.ac-card {
  flex: 1 1 150px; min-width: 150px; max-width: 210px;
  padding: 16px 12px 12px; border-radius: 14px; text-align: center;
  background: #f1f5f9; border: 1.5px dashed #cbd5e1; color: var(--c-ink-3);
  animation: achvFlip .55s cubic-bezier(.2, 1.1, .4, 1) both;
}
.ac-card.got {
  background: linear-gradient(160deg, #fffbeb, #fef3c7 55%, #fde68a);
  border: 1.5px solid #f59e0b; color: #78350f;
  box-shadow: 0 6px 18px rgba(245, 158, 11, .28), inset 0 0 0 3px #fffbeb;
}
.ac-card-top { font-size: 34px; line-height: 1.15; }
.ac-card-name { font-size: 17px; font-weight: 800; margin-top: 4px; }
.ac-card-sub { font-size: 12.5px; font-weight: 700; letter-spacing: 3px; margin-top: 1px; opacity: .8; }
.ac-card-date { font-size: 12px; margin-top: 8px; }
.ac-card-desc { font-size: 11px; margin-top: 6px; opacity: .75; line-height: 1.5; }
.ac-card-bar {
  height: 7px; border-radius: 999px; background: #e2e8f0;
  overflow: hidden; margin-top: 8px;
}
.ac-card-bar-in { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, #f59e0b, #ef4444); }
@keyframes achvFlip {
  from { transform: perspective(700px) rotateY(92deg) scale(.86); opacity: 0; }
  to { transform: perspective(700px) rotateY(0) scale(1); opacity: 1; }
}
/* 成就揭晓庆祝层（扫描批改时达成 → 满屏金光 + 彩纸 + 翻卡揭晓） */
.achv-pop {
  position: fixed; inset: 0; z-index: 1300; display: flex;
  align-items: center; justify-content: center;
  background: rgba(38, 24, 2, .58); overflow: hidden; pointer-events: none;
}
.ac-rays {
  position: absolute; left: 50%; top: 50%; width: 240vmax; height: 240vmax;
  margin: -120vmax 0 0 -120vmax; border-radius: 50%;
  background: repeating-conic-gradient(rgba(247, 215, 116, .16) 0 9deg, transparent 9deg 18deg);
  animation: acRays 9s linear infinite;
}
@keyframes acRays { to { transform: rotate(360deg) } }
.ac-confetti { position: absolute; inset: 0; }
.ac-cf {
  position: absolute; top: -14px; border-radius: 2px; opacity: .92;
  animation: acFall linear infinite;
}
@keyframes acFall {
  to { transform: translateY(108vh) rotate(540deg); }
}
.ac-stage {
  position: relative; display: flex; flex-direction: column; align-items: center;
  padding: 26px 40px 22px; border-radius: 20px;
  background: rgba(15, 12, 4, .44); border: 1px solid rgba(247, 215, 116, .4);
  backdrop-filter: blur(2px);
}
.ac-ribbon {
  padding: 5px 22px; border-radius: 999px; font-size: 15px; font-weight: 800;
  color: #7a5a0d; background: linear-gradient(90deg, #fff2c2, #ffe08a, #fff2c2);
  border: 1px solid #eac659; animation: pfNum .5s cubic-bezier(.2, 1.4, .4, 1) both;
}
.ac-name { margin-top: 8px; font-size: 26px; font-weight: 800; color: #fff; text-shadow: 0 2px 8px rgba(0, 0, 0, .5); }
.ac-cards { display: flex; gap: 16px; margin-top: 14px; }
.ac-flip { animation: achvFlip .6s cubic-bezier(.2, 1.1, .4, 1) both; }
.ac-stage .ac-card { max-width: 200px; animation: none; }
.ac-stage .ac-card .ac-count { font-size: 20px; color: #b45309; }
.ac-banner {
  margin-top: 14px; padding: 6px 20px; border-radius: 999px;
  font-size: 15px; font-weight: 800; color: #fff;
  background: linear-gradient(90deg, #b45309, #f59e0b, #b45309);
  animation: pfNum .5s .35s cubic-bezier(.2, 1.4, .4, 1) both;
}
@media (max-width: 620px) {
  .ac-stage { padding: 20px 16px 16px; }
  .ac-name { font-size: 21px; }
  .ac-cards { gap: 10px; }
  .ac-card { min-width: 120px; }
}
@media print { .achv-pop { display: none !important } }

/* ===========================================================
   第二十三轮 · 讲题投屏 + 图转题（js/teach.js）
   =========================================================== */
.teach { display: grid; grid-template-columns: 300px 1fr; gap: 14px; align-items: start; }
@media (max-width: 900px) { .teach { grid-template-columns: 1fr; } }

.teach-side { display: flex; flex-direction: column; gap: 12px; }
.teach-side .card { padding: 14px; }
.teach-h { margin: 0 0 10px; font-size: 15px; color: var(--c-ink); }
.t-search { width: 100%; padding: 8px 10px; border: 1px solid var(--c-line); border-radius: var(--r-sm); margin-bottom: 8px; }
.t-qsel { width: 100%; min-height: 180px; border: 1px solid var(--c-line); border-radius: var(--r-sm); padding: 4px; background: #fff; }
.t-qsel option { padding: 6px 8px; }
.teach-or { text-align: center; color: var(--c-ink-3); font-size: 12px; margin: 10px 0 8px; }
.demo-btn { margin-top: 6px; text-align: left; }
.blk { display: block; width: 100%; }

.teach-welcome { padding: 22px 24px; }
.teach-welcome h2 { margin: 0 0 10px; }
.big-line { font-size: 16px; line-height: 1.9; margin: 0 0 10px; }
.teach-steps-ol { line-height: 2.1; margin: 0 0 8px; padding-left: 22px; }
.teach-demos { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; margin-top: 14px; }
.demo-card { padding: 16px; display: flex; flex-direction: column; gap: 8px; }
.demo-t { font-weight: 700; }

.teach-qcard { padding: 18px 20px; }
.teach-qhead { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.teach-stem { font-size: 19px; line-height: 2; }
.teach-empty-plan { padding: 26px; text-align: center; }
.teach-busy { font-size: 17px; line-height: 2; }

.teach-approach {
  display: flex; align-items: flex-start; gap: 10px;
  background: linear-gradient(90deg, #eef2ff, #f5f3ff);
  border: 1px solid #dfe3ff; border-radius: var(--r);
  padding: 12px 16px; margin-bottom: 12px; font-size: 16px; line-height: 1.8;
}
.ta-badge { flex: 0 0 auto; background: var(--c-primary); color: #fff; font-size: 12px; border-radius: 6px; padding: 2px 8px; margin-top: 3px; }

.teach-plan { padding: 16px 18px; }
.teach-tools { display: flex; gap: 8px; justify-content: flex-end; margin-bottom: 10px; }
.teach-step { background: var(--c-primary-soft); border: 1px solid #dfe3ff; border-radius: var(--r); padding: 18px 22px; }
.teach-steps-all { display: flex; flex-direction: column; gap: 10px; }
.ts-no { font-size: 13px; color: var(--c-primary); font-weight: 700; letter-spacing: 1px; margin-bottom: 6px; }
.ts-title { font-size: 21px; font-weight: 700; margin-bottom: 8px; }
.ts-content { font-size: 17px; line-height: 2; color: var(--c-ink-2); }
.ts-done { margin-top: 12px; font-size: 15px; color: var(--c-ok); font-weight: 600; }

.teach-ctrl { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 14px; }
.tdots { display: flex; gap: 8px; }
.tdot {
  width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--c-line);
  background: #fff; color: var(--c-ink-2); font-size: 13px; cursor: pointer;
}
.tdot.on { background: var(--c-primary); border-color: var(--c-primary); color: #fff; font-weight: 700; }

.teach-fig { margin-top: 14px; }
.teach-nofig { text-align: center; color: var(--c-ink-3); font-size: 14px; padding: 14px 0 4px; }

/* 函数图象（Canvas + 滑块） */
.tfig-wrap { position: relative; border: 1px solid var(--c-line); border-radius: var(--r); overflow: hidden; background: #fff; }
.tfig-cv { display: block; width: 100%; touch-action: none; cursor: grab; }
.tfig-tip { position: absolute; right: 10px; top: 8px; font-size: 12px; color: var(--c-ink-3); background: rgba(255,255,255,.85); border-radius: 6px; padding: 2px 8px; pointer-events: none; }
.tfig-sliders { display: flex; flex-wrap: wrap; gap: 10px 22px; padding: 12px 6px 2px; }
.tsl { display: flex; align-items: center; gap: 8px; min-width: 220px; }
.tsl-k { font-weight: 700; font-size: 16px; color: var(--c-accent); min-width: 26px; }
.tsl input[type=range] { flex: 1; accent-color: var(--c-primary); height: 26px; }
.tsl-v { font-variant-numeric: tabular-nums; font-size: 14px; color: var(--c-ink-2); min-width: 44px; text-align: right; }

/* 几何图（SVG 可拖点） */
.tgeo { border: 1px solid var(--c-line); border-radius: var(--r); background: #fff; position: relative; }
.tgeo-svg { display: block; width: 100%; height: 360px; touch-action: none; }

/* 投屏（全屏弹窗内） */
.tproj { padding: 6px 4px; }
.tproj-q { font-size: 24px; line-height: 2; }
.tproj-opts { margin-top: 8px; }
.tproj-step { margin-top: 14px; }
.tproj-step .ts-title { font-size: 26px; }
.tproj-step .ts-content { font-size: 21px; }
.tproj-pos { color: var(--c-ink-3); font-size: 14px; }

/* 图转题 */
.i2q-drop {
  border: 2px dashed var(--c-line); border-radius: var(--r);
  padding: 26px 18px; text-align: center; cursor: pointer; line-height: 2;
  background: #fbfcfe; transition: border-color .15s;
}
.i2q-drop:hover { border-color: var(--c-primary); }

/* ---- 排版动作行的老浏览器兜底：去掉 flex gap 改 margin（与上面排版区同因） ---- */
.row.gap8.lay-actions { gap: 0; }
.lay-actions .btn { margin-right: 8px; }
.lay-actions .btn:last-child { margin-right: 0; }

/* ---- 作业保密（第二十五轮，2026-09-22）----
   未批阅的作业在大屏上不显示答案；右下角小锁是老师的解锁入口 */
.qans.seal-note {
  color: #92400e; background: #fffbeb;
  border: 1px dashed #f0b429; border-radius: 8px;
  padding: 8px 12px; font-size: 13px;
}
.seal-fab {
  position: fixed; right: 18px; bottom: 76px; z-index: 90;
  width: 46px; height: 46px; border-radius: 50%;
  border: 2px solid #f59e0b; background: #fffbeb;
  font-size: 20px; line-height: 1; cursor: pointer;
  box-shadow: 0 4px 14px rgba(0,0,0,.16);
  display: flex; align-items: center; justify-content: center;
  padding: 0;
}
.seal-fab.open { border-color: #16a34a; background: #f0fdf4; }
.seal-fab:active { transform: scale(.94); }
#seal-pwd.bad { border-color: #e05656; }

/* ---- 二十七轮需求一：讲评弹窗画笔层（"玻璃层"标注） ----
   画布铺满弹窗、不随内容缩放滚动 —— 笔迹留在屏幕上，像在玻璃上圈画。
   .pass = 移动模式：画布放行触摸（pointer-events:none），单指照常拖动内容；
   画笔/橡皮模式拦截触摸用于圈画，点 ✋ 回到移动。工具条浮在右下（关闭按钮上方）。 */
.annot-cv {
  position: absolute; inset: 0; z-index: 4;
  touch-action: none; cursor: crosshair;
}
.annot-cv.pass { pointer-events: none; }
.annot-bar {
  position: absolute; right: 22px; bottom: 88px; z-index: 6;
  display: flex; align-items: center; gap: 6px;
  background: rgba(15, 23, 42, .84); border-radius: 999px;
  padding: 8px 12px; box-shadow: 0 10px 26px rgba(15, 23, 42, .32);
}
.annot-btn {
  border: 0; background: transparent; font-size: 20px; line-height: 1;
  padding: 5px 7px; border-radius: 9px; cursor: pointer; opacity: .62;
}
.annot-btn.on { opacity: 1; background: rgba(255, 255, 255, .24); }
/* 二十九轮：粗细/大小切换钮（显示 细/中/粗 或 小/大 文字） */
.annot-sz { font-size: 13px; font-weight: 700; min-width: 34px; text-align: center; color: #fff; }
.annot-colors { display: flex; gap: 6px; margin: 0 4px; }
.annot-colors i {
  width: 18px; height: 18px; border-radius: 50%; cursor: pointer;
  border: 2px solid transparent; display: inline-block;
}
.annot-colors i.on { border-color: #fff; }

/* ============================================================
   第三十五轮（2026-09-24 晚）
   一、批改页实时攻克榜（「正确答案」关闭时替换批改记录面板，FLIP 位次动画）
   二、品质卡随机掉落（弹窗内金卡/普通卡 + 设置页编辑器 + 成就墙卡册）
   三、里程碑成就卡大数字改版（50 一档上不封顶）
   四、段位专属弹窗特效（20 主题：通用/男生向/女生向，随段位升级换发）
   ============================================================ */

/* ---------- 一、实时攻克榜 ---------- */
.live-board { display: flex; flex-direction: column; gap: 4px; max-height: 46vh; overflow: auto; }
.lv-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: 12px;
  background: #f8fafc; border: 1px solid transparent;
  will-change: transform;
}
.lv-row.achv-top1 { background: linear-gradient(90deg, #fffbeb, #fef3c7); border-color: #fde68a; }
.lv-row .achv-medal { font-size: 20px; }
.lv-place {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: #e2e8f0; color: #64748b; font-size: 13px; font-weight: 700;
}
.lv-name { font-size: 15px; min-width: 3.2em; }
.lv-row .achv-rank { margin-left: auto; font-size: 11px; padding: 2px 7px; }
.lv-n { position: relative; font-weight: 800; font-size: 16px; color: #b45309; min-width: 52px; text-align: right; }
.lv-n em { font-style: normal; font-size: 11px; color: #94a3b8; font-weight: 600; margin-left: 1px; }
.lv-float {
  position: absolute; right: 0; top: -4px; text-decoration: none;
  font-size: 13px; font-weight: 800; color: #16a34a;
  animation: lvFloat 1.4s ease-out forwards; pointer-events: none;
}
@keyframes lvFloat {
  0% { opacity: 0; transform: translateY(6px) scale(.7); }
  25% { opacity: 1; transform: translateY(-4px) scale(1.15); }
  100% { opacity: 0; transform: translateY(-22px) scale(1); }
}

/* ---------- 二、品质卡（弹窗掉落行 + 成就墙卡册 + 设置编辑器） ---------- */
.qc-row { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 12px; }
.qc-chip {
  position: relative; display: inline-flex; align-items: center; gap: 6px;
  background: #fff; border: 2px solid #bfdbfe; border-radius: 14px;
  padding: 6px 10px; box-shadow: 0 4px 14px rgba(15,23,42,.12);
  animation: qcIn .5s cubic-bezier(.2,1.5,.4,1) both;
}
@keyframes qcIn { from { opacity: 0; transform: translateY(18px) scale(.5) rotate(-6deg); } to { opacity: 1; transform: none; } }
.qc-chip b { font-size: 14px; color: #1e40af; }
.qc-face {
  width: 30px; height: 30px; border-radius: 9px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: #eff6ff; font-size: 19px; font-style: normal; overflow: hidden;
}
.qc-face img { width: 100%; height: 100%; object-fit: cover; border-radius: 9px; }
.qc-chip.gold {
  border-color: #f59e0b;
  background: linear-gradient(160deg, #fffbeb 0%, #fef3c7 45%, #fde68a 100%);
  box-shadow: 0 0 0 3px rgba(245,158,11,.25), 0 6px 20px rgba(180,120,10,.35);
  overflow: hidden;
}
.qc-chip.gold b { color: #92400e; }
.qc-chip.gold .qc-face { background: rgba(255,255,255,.75); }
/* 稀有金卡闪光：一道高光从左上扫到右下，循环播放 */
.qc-chip.gold::after {
  content: ''; position: absolute; inset: -40%;
  background: linear-gradient(115deg, transparent 42%, rgba(255,255,255,.85) 50%, transparent 58%);
  animation: qcShine 2.2s ease-in-out infinite; pointer-events: none;
}
@keyframes qcShine { 0% { transform: translateX(-70%); } 55%, 100% { transform: translateX(70%); } }
.qc-rare {
  font-style: normal; font-size: 10px; font-weight: 800; color: #fff;
  background: linear-gradient(135deg, #f59e0b, #d97706);
  border-radius: 6px; padding: 1px 5px; margin-left: 2px;
}
/* 成就墙里的品质卡册 */
.ac-qc-title { font-weight: 800; font-size: 16px; margin: 18px 0 8px; color: #9d174d; }
.qc-wall { display: flex; flex-wrap: wrap; gap: 8px; }
.qc-wall .qc-chip { animation: none; }
/* 设置页编辑器 */
.qc-pool { border: 1px dashed #cbd5e1; border-radius: 12px; padding: 10px; margin-bottom: 10px; background: #f8fafc; }
.qc-cardrow { display: flex; align-items: center; gap: 8px; padding: 4px 0; flex-wrap: wrap; }
.qc-cardrow input[type="text"] { min-height: 32px; }

/* ---------- 三、里程碑成就卡 · 大数字 ---------- */
.ac-card-num {
  font-size: 52px; font-weight: 900; line-height: 1.05; letter-spacing: -1px;
  background: linear-gradient(160deg, #fbbf24, #b45309);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  font-variant-numeric: tabular-nums;
}
.ac-card:not(.got) .ac-card-num {
  background: linear-gradient(160deg, #94a3b8, #475569);
  -webkit-background-clip: text; background-clip: text;
}

/* ---------- 四、段位专属弹窗特效 ----------
   主题类挂在 .score-pop-card 上（fx-<id>）。每个主题两层：
   ① 边框/底光动画（纯 CSS，全部主题都有）；② 飘落/上升装饰元素
   （JS 生成 .sfx-deco，仅部分主题）。段位越高池子越炫，主题由
   store.ensureFx 按段位+性别随机分配并记档。 */
.score-pop-card { position: relative; }
.score-pop-card .sfx-deco, .score-pop-card .qc-row, .score-pop-card .fx-rankup,
.score-pop-card .fx-rank-badge { position: relative; z-index: 1; }
.sfx-deco { position: absolute; inset: 0; overflow: hidden; pointer-events: none; border-radius: inherit; z-index: 0; }
.sfx-deco i { position: absolute; top: -14%; line-height: 1; opacity: .92; animation: sfxFall 3s linear infinite; }
.sfx-deco.rise i { top: auto; bottom: -14%; animation-name: sfxRise; }
.sfx-deco.flutter i { top: 6%; animation: sfxFlutter 2.8s ease-in-out infinite alternate; }
@keyframes sfxFall { to { transform: translateY(400px) rotate(280deg); } }
@keyframes sfxRise { to { transform: translateY(-400px) rotate(-36deg); } }
@keyframes sfxFlutter {
  0% { transform: translate(0, 0) rotate(0deg); }
  30% { transform: translate(-16px, 34px) rotate(-14deg); }
  65% { transform: translate(12px, 70px) rotate(12deg); }
  100% { transform: translate(-6px, 108px) rotate(-6deg); }
}
@keyframes fxPulse {
  0%, 100% { box-shadow: var(--fx-shadow, 0 0 0 3px rgba(245,158,11,.3)), 0 18px 50px rgba(15,23,42,.3); }
  50% { box-shadow: var(--fx-shadow-hi, 0 0 0 6px rgba(245,158,11,.45)), 0 18px 64px rgba(245,158,11,.5); }
}
/* —— 通用 —— */
.score-pop-card.fx-gold-rim { border: 2px solid #fbbf24; --fx-shadow: 0 0 0 3px rgba(251,191,36,.35); --fx-shadow-hi: 0 0 0 7px rgba(251,191,36,.5); animation: fxPulse 1.3s ease-in-out infinite; }
.score-pop-card.fx-star-dust { border: 2px solid #a5b4fc; --fx-shadow: 0 0 0 3px rgba(165,180,252,.35); --fx-shadow-hi: 0 0 0 7px rgba(129,140,248,.5); animation: fxPulse 1.6s ease-in-out infinite; }
.score-pop-card.fx-silver-flow { border: 2px solid #cbd5e1; overflow: hidden; }
.score-pop-card.fx-silver-flow::before {
  content: ''; position: absolute; inset: -40%; z-index: 0; pointer-events: none;
  background: linear-gradient(115deg, transparent 40%, rgba(203,213,225,.65) 50%, transparent 60%);
  animation: qcShine 1.9s linear infinite;
}
.score-pop-card.fx-sun-burst { border: 2px solid #f59e0b; --fx-shadow: 0 0 0 3px rgba(245,158,11,.4); --fx-shadow-hi: 0 0 0 8px rgba(245,158,11,.55); animation: fxPulse 1.1s ease-in-out infinite; }
.score-pop-card.fx-rainbow-flow { border: 2px solid transparent; background-clip: padding-box; overflow: hidden; }
.score-pop-card.fx-rainbow-flow::before {
  content: ''; position: absolute; inset: -60%; z-index: 0; pointer-events: none; opacity: .5;
  background: conic-gradient(#f87171, #fbbf24, #4ade80, #38bdf8, #a78bfa, #f87171);
  animation: fxSpin 3.2s linear infinite;
}
@keyframes fxSpin { to { transform: rotate(360deg); } }
.score-pop-card.fx-rainbow-flow > * { position: relative; z-index: 1; }
.score-pop-card.fx-aurora { border: 2px solid #7dd3fc; overflow: hidden; }
.score-pop-card.fx-aurora::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: .38;
  background: linear-gradient(120deg, #22d3ee, #a78bfa, #34d399, #22d3ee);
  background-size: 300% 300%; animation: fxPan 3.6s ease-in-out infinite;
}
@keyframes fxPan { 0%,100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }
.score-pop-card.fx-aurora > * { position: relative; z-index: 1; }
.score-pop-card.fx-firework { border: 2px solid #fb7185; --fx-shadow: 0 0 0 3px rgba(251,113,133,.35); --fx-shadow-hi: 0 0 0 8px rgba(251,113,133,.55); animation: fxPulse 1s ease-in-out infinite; }
.score-pop-card.fx-legend-fire { border: 3px solid #f59e0b; --fx-shadow: 0 0 24px rgba(245,158,11,.7), 0 0 0 3px rgba(217,119,6,.4); --fx-shadow-hi: 0 0 44px rgba(245,158,11,.95), 0 0 0 8px rgba(217,119,6,.55); animation: fxPulse .8s ease-in-out infinite; }
/* —— 男生向 —— */
.score-pop-card.fx-flame-edge { border: 3px solid #f97316; --fx-shadow: 0 0 20px rgba(249,115,22,.65), 0 0 0 3px rgba(249,115,22,.35); --fx-shadow-hi: 0 0 40px rgba(249,115,22,.95), 0 0 0 7px rgba(234,88,12,.5); animation: fxPulse .85s ease-in-out infinite; }
.score-pop-card.fx-thunder { border: 2px solid #facc15; --fx-shadow: 0 0 18px rgba(250,204,21,.6), 0 0 0 3px rgba(250,204,21,.4); --fx-shadow-hi: 0 0 42px rgba(250,204,21,.95), 0 0 0 8px rgba(250,204,21,.6); animation: fxPulse .62s ease-in-out infinite; }
.score-pop-card.fx-blade-flash { border: 2px solid #94a3b8; overflow: hidden; }
.score-pop-card.fx-blade-flash::before {
  content: ''; position: absolute; inset: -40%; z-index: 0; pointer-events: none;
  background: linear-gradient(115deg, transparent 44%, rgba(226,232,240,.95) 50%, transparent 56%);
  animation: qcShine 1.4s linear infinite;
}
.score-pop-card.fx-blade-flash > * { position: relative; z-index: 1; }
.score-pop-card.fx-cyber-blue { border: 2px solid #22d3ee; --fx-shadow: 0 0 18px rgba(34,211,238,.6), 0 0 0 3px rgba(34,211,238,.4); --fx-shadow-hi: 0 0 40px rgba(34,211,238,.95), 0 0 0 8px rgba(34,211,238,.6); animation: fxPulse .9s ease-in-out infinite; }
.score-pop-card.fx-lava-burst { border: 3px solid #dc2626; --fx-shadow: 0 0 24px rgba(220,38,38,.7), 0 0 0 3px rgba(220,38,38,.4); --fx-shadow-hi: 0 0 48px rgba(220,38,38,1), 0 0 0 8px rgba(220,38,38,.55); animation: fxPulse .7s ease-in-out infinite; }
.score-pop-card.fx-dragon-gold { border: 3px solid #eab308; overflow: hidden; }
.score-pop-card.fx-dragon-gold::before {
  content: ''; position: absolute; inset: -60%; z-index: 0; pointer-events: none; opacity: .6;
  background: conic-gradient(#eab308, #f97316, #eab308, #a16207, #eab308);
  animation: fxSpin 2.6s linear infinite;
}
.score-pop-card.fx-dragon-gold > * { position: relative; z-index: 1; }
/* —— 女生向 —— */
.score-pop-card.fx-petal-rain { border: 2px solid #f9a8d4; --fx-shadow: 0 0 0 3px rgba(249,168,212,.4); --fx-shadow-hi: 0 0 0 7px rgba(249,168,212,.6); animation: fxPulse 1.5s ease-in-out infinite; }
.score-pop-card.fx-pink-aurora { border: 2px solid #f0abfc; overflow: hidden; }
.score-pop-card.fx-pink-aurora::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: .4;
  background: linear-gradient(120deg, #f0abfc, #c4b5fd, #fda4af, #f0abfc);
  background-size: 300% 300%; animation: fxPan 3.2s ease-in-out infinite;
}
.score-pop-card.fx-pink-aurora > * { position: relative; z-index: 1; }
.score-pop-card.fx-heart-bubble { border: 2px solid #fb7185; --fx-shadow: 0 0 0 3px rgba(251,113,133,.4); --fx-shadow-hi: 0 0 0 7px rgba(251,113,133,.6); animation: fxPulse 1.2s ease-in-out infinite; }
.score-pop-card.fx-star-magic { border: 2px solid #c084fc; --fx-shadow: 0 0 14px rgba(192,132,252,.55), 0 0 0 3px rgba(192,132,252,.4); --fx-shadow-hi: 0 0 34px rgba(192,132,252,.9), 0 0 0 7px rgba(192,132,252,.6); animation: fxPulse 1.1s ease-in-out infinite; }
.score-pop-card.fx-butterfly { border: 2px solid #a78bfa; --fx-shadow: 0 0 0 3px rgba(167,139,250,.4); --fx-shadow-hi: 0 0 0 7px rgba(167,139,250,.6); animation: fxPulse 1.4s ease-in-out infinite; }
.score-pop-card.fx-candy-rain { border: 3px solid #f472b6; overflow: hidden; }
.score-pop-card.fx-candy-rain::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: .32;
  background: linear-gradient(120deg, #f9a8d4, #fbcfe8, #d8b4fe, #fda4af, #f9a8d4);
  background-size: 300% 300%; animation: fxPan 2.8s ease-in-out infinite;
}
.score-pop-card.fx-candy-rain > * { position: relative; z-index: 1; }
/* —— 卡上段位徽章与晋升横幅 —— */
.fx-rank-badge { margin-top: 10px; font-size: 13px; }
.fx-rankup {
  margin-top: 8px; font-size: 15px; font-weight: 800; color: #fff;
  background: linear-gradient(90deg, #f59e0b, #ef4444, #f59e0b);
  background-size: 200% 100%; border-radius: 999px; padding: 6px 16px;
  animation: fxRankUp .5s cubic-bezier(.2,1.5,.4,1) both, fxPan 1.6s linear infinite;
}
@keyframes fxRankUp { from { opacity: 0; transform: translateY(14px) scale(.6); } to { opacity: 1; transform: none; } }

/* 打印不输出任何浮层/特效装饰 */
@media print {
  .live-board, .lv-row, .qc-row, .qc-chip, .sfx-deco, .fx-rankup, .fx-rank-badge { display: none !important; }
}

/* ===========================================================
   归零 · 界面升级层（2026-09-25）
   —— 只做覆写不动老规则；教室一体机老内核兼容（无 inset/gap/新函数）
   =========================================================== */

:root {
  --r: 14px;
  --r-sm: 10px;
  --shadow: 0 2px 6px rgba(30, 27, 75, .05), 0 12px 32px rgba(30, 27, 75, .08);
  --shadow-sm: 0 1px 3px rgba(30, 27, 75, .06);
}

/* 侧栏：深空渐变，品牌更醒目 */
.sidebar {
  background: linear-gradient(168deg, #171543 0%, #241f5c 46%, #3b2a86 100%);
  box-shadow: 2px 0 18px rgba(23, 21, 67, .28);
}
.brand h1 { letter-spacing: 6px; font-weight: 700; }
.brand .sub { color: #8f9bf0; }

.nav-item {
  border-radius: 11px;
  transition: background .16s ease, color .16s ease, box-shadow .16s ease, transform .16s ease;
}
.nav-item:hover { background: rgba(129, 140, 248, .16); color: #fff; transform: translateX(2px); }
.nav-item.active {
  background: linear-gradient(135deg, #4F46E5, #7C3AED);
  box-shadow: 0 6px 18px rgba(99, 102, 241, .45);
}

/* 卡片：更轻的框、柔和阴影、悬浮微升、进场淡入 */
.card {
  border: 1px solid #eaecf6;
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  transition: box-shadow .18s ease, transform .18s ease;
  animation: gzCardIn .22s ease both;
}
.card:hover { box-shadow: var(--shadow); }
@keyframes gzCardIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.card-h { background: transparent; }
.card-h h3 { font-weight: 600; letter-spacing: .3px; }

/* 按钮：品牌渐变主按钮 + 悬浮手感 */
.btn { border-radius: var(--r-sm); transition: all .16s ease; font-weight: 600; }
.btn:hover { border-color: #c7cdf0; background: #f7f8ff; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(30, 27, 75, .08); }
.btn:active { transform: translateY(0); box-shadow: none; }
.btn.primary { background: linear-gradient(135deg, #4F46E5, #7C3AED); box-shadow: 0 4px 14px rgba(99, 102, 241, .32); }
.btn.primary:hover { background: linear-gradient(135deg, #4338CA, #6D28D9); box-shadow: 0 6px 20px rgba(99, 102, 241, .42); transform: translateY(-1px); }
.btn.bad:hover, .btn.ok:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(220, 38, 38, .22); }

/* 输入聚焦：品牌色光圈 */
input:focus, select:focus, textarea:focus { border-color: var(--c-primary); box-shadow: 0 0 0 3px rgba(79, 70, 229, .12); }

/* 徽章、弹窗统一圆角 */
.badge, .tag { border-radius: 999px; }

/* ============================================================
   归零 · 界面升级层 · 第二批（三十六轮）
   ============================================================ */
/* 全局底色微调：更干净的冷灰底，卡片更立体 */
body{background:linear-gradient(180deg,#F7F8FD 0%,#F1F2FA 100%);}
/* 卡片标题统一品牌色条（所有页面可见的升级） */
.card-h h3{position:relative;padding-left:12px;}
.card-h h3:before{content:'';position:absolute;left:0;top:4px;bottom:4px;width:4px;border-radius:2px;background:linear-gradient(180deg,#4F46E5,#8B5CF6);}
/* 顶栏：白底描边 + 标题加重 */
.topbar{background:#fff;border-bottom:1px solid #ECEDF6;}
#page-title{letter-spacing:1px;}
/* 侧栏品牌 logo（空集 ∅） */
.brand{display:flex;align-items:center;gap:10px;}
.brand-logo{width:42px;height:42px;border-radius:11px;display:block;flex:none;box-shadow:0 4px 14px rgba(0,0,0,.28);}
/* 管理员侧栏的「未开放」模块：置灰可见可进（老师 2026-09-25："别给管理员也隐藏了"） */
.nav-item.dim{opacity:.45;}
.nav-item.dim:hover{opacity:.8;}
.nav-item.dim .ic{filter:grayscale(.7);}
.dimbadge{background:rgba(255,255,255,.14);color:#C7C9E8;font-size:10px;padding:1px 7px;border-radius:99px;margin-left:auto;flex:none;}
/* 侧栏用户卡（点头像进个人中心） */
.side-user-btn{display:flex;align-items:center;width:100%;background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.12);border-radius:12px;padding:8px 10px;cursor:pointer;margin-bottom:10px;text-align:left;font-family:inherit;}
.side-user-btn:hover{background:rgba(255,255,255,.14);}
.su-t{display:flex;flex-direction:column;min-width:0;margin-left:9px;text-align:left;}
.su-t b{color:#fff;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.su-t span{color:#9AA0C8;font-size:11px;}
/* 学生错题本 · 分段 tab（全班复习 / 错题本） */
.seg-tabs{display:flex;background:#fff;border:1.5px solid var(--c-line);border-radius:12px;padding:4px;max-width:400px;margin-bottom:14px;}
.seg-tab{flex:1;border:none;background:none;padding:8px 0;font-size:13.5px;cursor:pointer;border-radius:9px;color:#666C93;font-family:inherit;font-weight:600;}
.seg-tab.on{background:linear-gradient(135deg,#4F46E5,#7C3AED);color:#fff;}
/* 学生错题本 · 荣誉墙（成就卡 + 品质卡，拖动排序） */
.wall-grid{display:flex;flex-wrap:wrap;margin:0 -6px 16px;}
.wall-card{position:relative;width:152px;box-sizing:border-box;background:#fff;border:1.5px solid var(--c-line);border-radius:14px;padding:12px 10px 10px;margin:6px;text-align:center;cursor:grab;box-shadow:0 2px 8px rgba(20,20,60,.06);transition:box-shadow .15s,transform .15s;}
.wall-card:hover{box-shadow:0 8px 22px rgba(79,70,229,.16);transform:translateY(-2px);}
.wall-card.dragging{opacity:.45;transform:scale(.96);}
.wall-card.gold{background:linear-gradient(160deg,#FFFBEB,#FEF3C7);border-color:#F59E0B;}
.wall-card b{display:block;font-size:13.5px;margin:4px 0 2px;color:#1F2359;}
.wall-card .small{display:block;}
.wc-rank{font-size:30px;line-height:1.2;display:block;}
.wc-num{font-size:28px;line-height:1.25;display:block;font-weight:bold;background:linear-gradient(135deg,#4F46E5,#8B5CF6);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;}
.wc-img{width:44px;height:44px;border-radius:50%;object-fit:cover;display:block;margin:0 auto;}
.wc-mv{position:absolute;top:4px;right:4px;display:none;}
.wall-card:hover .wc-mv{display:block;}
.wc-btn{border:none;background:#EEF0FA;border-radius:6px;font-size:10px;padding:2px 6px;cursor:pointer;color:#4F46E5;margin-left:2px;font-family:inherit;}
.wc-btn:hover{background:#4F46E5;color:#fff;}

/* ============================================================
   归零 · 界面升级层 · 第三批（三十七轮）
   覆盖剩余页：扫描阅卷 / 打印中心 / 成绩分析 / 弹窗提示等
   —— 仍然只做覆写不动老规则；老内核不认识的新属性会被安全忽略
   ============================================================ */

/* 1) 扫描页顶部统计带：白底品牌描边 + 每组关键词前小圆点 */
.scan-statbar{background:#fff;border:1.5px solid #E4E6F5;box-shadow:0 2px 8px rgba(30,27,75,.06);}
.scan-statbar .ss-k{position:relative;padding-left:11px;font-weight:600;}
.scan-statbar .ss-k:before{content:'';position:absolute;left:0;top:50%;margin-top:-3px;width:6px;height:6px;border-radius:50%;background:linear-gradient(135deg,#4F46E5,#8B5CF6);}

/* 2) 扫描状态条：白卡化 */
.scan-status{background:#fff;border:1.5px solid #ECEDF6;box-shadow:0 1px 3px rgba(30,27,75,.05);}

/* 3) 摄像头未启动空态：大镜头 emoji 配一圈品牌柔光底 */
.cam-off .big{width:86px;height:86px;line-height:86px;border-radius:50%;background:rgba(129,140,248,.16);opacity:1;font-size:38px;margin:0 auto;}

/* 4) 提示块 note：左侧品牌色竖条，说明文字不再是一整块平涂 */
.note{position:relative;border-left:4px solid #4F46E5;border-radius:0 10px 10px 0;background:#F5F6FF;border-color:#E4E6F5;}
.note.warn{border-left-color:#F59E0B;background:#FFFBF3;}
.note.ok{border-left-color:#22C55E;background:#F4FBF6;}

/* 5) 表格：表头浅靛底、行 hover 带品牌（成绩分析/名单/批改记录全吃到） */
table.tbl th, table.t th{background:#F4F5FE;color:#4B5080;}
table.tbl tbody tr:hover, table.t tbody tr:hover{background:#F7F7FF;}

/* 6) 空态：emoji 配圆形品牌渐变底徽章 */
.empty .big{width:72px;height:72px;line-height:72px;border-radius:50%;background:linear-gradient(160deg,#EEF0FF,#F5F0FF);margin:0 auto 12px;font-size:34px;opacity:1;}

/* 7) 弹窗：更大圆角 + 标题品牌色条 + 遮罩略深更有层次 */
.modal{border-radius:16px;}
.modal-mask{background:rgba(20,20,55,.45);}
.modal-h h3{position:relative;padding-left:12px;font-weight:600;}
.modal-h h3:before{content:'';position:absolute;left:0;top:3px;bottom:3px;width:4px;border-radius:2px;background:linear-gradient(180deg,#4F46E5,#8B5CF6);}

/* 8) toast 提示：渐变底 + 更圆润 */
.toast{border-radius:12px;box-shadow:0 8px 24px rgba(10,15,40,.28);font-weight:500;}
.toast.ok{background:linear-gradient(120deg,#15803D,#16A34A);}
.toast.bad{background:linear-gradient(120deg,#B91C1C,#DC2626);}
.toast.warn{background:linear-gradient(120deg,#B45309,#D97706);}

/* 9) 进度条：品牌渐变填充 */
.progressbar{background:#EEF0FA;border-radius:999px;}
.progressbar i{background:linear-gradient(90deg,#4F46E5,#8B5CF6);border-radius:999px;}

/* 10) 首页数字卡：悬浮微升 */
.stat{transition:box-shadow .18s ease,transform .18s ease;}
.stat:hover{transform:translateY(-2px);box-shadow:0 8px 22px rgba(30,27,75,.1);}

/* 11) 首页 hero：右上角加一枚金色点睛光晕（品牌点睛金） */
.hero{position:relative;overflow:hidden;}
.hero:after{content:'';position:absolute;right:-70px;top:-70px;width:230px;height:230px;border-radius:50%;background:radial-gradient(circle,rgba(250,204,21,.22),rgba(250,204,21,0) 68%);pointer-events:none;}

/* 12) 全局细滚动条（老内核不认识就按原样显示，无副作用） */
::-webkit-scrollbar{width:9px;height:9px;}
::-webkit-scrollbar-thumb{background:#C9CDE8;border-radius:99px;border:2px solid transparent;background-clip:padding-box;}
::-webkit-scrollbar-thumb:hover{background:#A9AEDA;}
::-webkit-scrollbar-track{background:transparent;}

/* 13) 侧栏提示小字统一冷灰蓝 */
.hint{color:#7A80A8;}

/* 14) 侧栏底部拉齐（三十八轮）：班级条与「个人中心」按钮等高等宽；
     单班时班级名也渲染成同款条子，铅齿按钮全部收进班级页 */
.cls-row{gap:0;margin-top:8px;}
.cls-dd-btn{min-height:38px;}
.cls-name-text{display:flex;align-items:center;box-sizing:border-box;min-height:38px;padding:0 12px;border:1px solid rgba(255,255,255,.14);border-radius:10px;background:rgba(255,255,255,.07);font-size:13.5px;}
.foot .btn.sm.block{min-height:38px;}

/* 15) 个人中心设置：主标题竖排菜单 → 点击进副页详细设置（三十八轮） */
.pf-set-menu{padding:2px 0;}
.pf-set-item{display:flex;align-items:center;width:100%;box-sizing:border-box;background:none;border:none;border-bottom:1px solid var(--c-line-2);padding:14px 8px;cursor:pointer;font-family:inherit;font-size:14.5px;color:var(--c-ink);text-align:left;transition:background .14s ease;}
.pf-set-item:last-child{border-bottom:0;}
.pf-set-item:hover{background:#F6F7FF;}
.pf-set-ic{width:32px;font-size:19px;flex:none;text-align:center;}
.pf-set-t{flex:1;min-width:0;font-weight:600;}
.pf-set-ar{color:#A6ABD6;font-size:20px;flex:none;font-weight:700;}
.pf-set-item:hover .pf-set-ar{color:#4F46E5;transform:translateX(2px);}
.pf-set-back{margin-bottom:12px;position:sticky;top:12px;z-index:30;box-shadow:0 6px 18px rgba(30,27,75,.16);}
