/* ============================================================
   题库网站 · 样式表

   组织方式：
   1. 设计令牌（颜色/间距/圆角/字号）—— 改主题只改这一节
   2. 基础重置与排版
   3. 布局骨架（顶栏 / 容器 / 页脚）
   4. 组件（按钮、表单、表格、卡片、标签、提示…）
   5. 页面级（落地页、仪表盘、题库、详情、表单）
   6. 深色模式覆盖

   约定：颜色一律走 CSS 变量，不要在组件里写死 #hex，
   否则深色模式一定会漏掉某处。
   ============================================================ */

/* ---------- 1. 设计令牌 ----------
   改主题只改这一节。原则（2026-10-05 重做）：
   · 90% 中性色 + 10% 强调色 —— 强调色只出现在**可交互**和**关键数字**上，
     不做大面积铺色，否则整页都在喊，反而没有重点。
   · 层次靠「字号 + 字重 + 间距」，不靠加粗边框或加满阴影。
   · 阴影只做「抬起来一点点」的三档，够用就停。 */
:root {
  /* 主色「珊瑚橙」（2026-10-07 三次调色，用户要「珊瑚橙」「不同地方用不同配色」）：
     暖色主色打底，配一个冷色的辅助色（松石青 --cool）做互补点缀 ——
     「暖橙 + 冷青」是经典互补色，比单色更高级、更有层次，又不会花。
     --accent 系仍是全站主力（品牌/按钮/链接/选中态）；
     --cool 系只给「数据型」区块（进度条、统计数字、题量条、导出）做对比点缀，
     让「内容」和「数据」在色相上分开，一眼分清。 */
  --accent: #e8613c;              /* 珊瑚橙主色，够艳但压住荧光 */
  --accent-hover: #c7482a;        /* hover 压暗 */
  --accent-hi: #f0784f;           /* 主按钮渐变顶边 */
  --accent-soft: #fdece6;         /* 浅橙底（标签、soft 按钮） */
  --accent-line: #f5c4b4;         /* 橙描边 */
  --accent-ink: #8a3a20;          /* 浅橙底上的文字 */
  --on-solid: #ffffff;            /* 实心语义色上的文字 */
  --accent-2: #f6a34f;            /* 主色渐变亮端（往金橙走） */

  /* 冷色辅助「松石青」：跟暖橙互补，专给数据型区块做点缀 */
  --cool: #0f8a9d;
  --cool-hover: #0b6f7f;
  --cool-soft: #e4f4f6;
  --cool-line: #a9dbe1;
  --cool-ink: #0a5560;

  --danger: #d92d20;
  --danger-soft: #feecea;
  --danger-line: #f6b8b3;
  --warn: #b36200;
  --warn-soft: #fef3e0;
  --warn-line: #f2d8a8;
  --ok: #2f9e44;
  --ok-soft: #e8f7ec;
  --ok-line: #bce4c6;

  /* 中性色「暖宣纸白」：珊瑚橙是暖色，背景回到极淡的暖白，比清透白更衬
     暖主色；surface 保持纯白，卡片在暖底上立得起来。 */
  --bg: #faf6f2;
  --surface: #ffffff;
  --surface-2: #f6efe9;
  --surface-3: #efe4db;
  --text: #1a1a1a;               /* 正文纯黑：题目题干等主文字用标准黑，清晰醒目 */
  --text-2: #55504a;             /* 次级文字：中性灰，去掉偏黄 */
  --text-3: #8a8178;             /* 三级文字：更浅的灰 */
  --line: #ede3da;
  --line-strong: #dbccc0;

  /* 难度星 */
  --star: #f0a020;

  --radius-sm: 10px;
  --radius: 14px;
  --radius-lg: 18px;
  --radius-pill: 999px;

  --gap-1: 4px;
  --gap-2: 8px;
  --gap-3: 12px;
  --gap-4: 16px;
  --gap-5: 24px;
  --gap-6: 32px;
  --gap-7: 40px;

  /* 三档抬升，别再加第四档（阴影转中性青灰，跟清透底同一个色温） */
  --sh-1: 0 1px 2px rgba(23, 37, 31, .05), 0 1px 3px rgba(23, 37, 31, .06);
  --sh-2: 0 2px 4px -1px rgba(23, 37, 31, .07), 0 4px 14px -2px rgba(23, 37, 31, .09);
  --sh-3: 0 8px 28px -6px rgba(23, 37, 31, .14), 0 16px 44px -12px rgba(23, 37, 31, .16);
  --shadow: var(--sh-1);          /* 旧名，保留兼容 */

  /* 字号体系：全站只用这几档，别临时插一个 15.5px */
  --fs-xs: 12px;
  --fs-sm: 13px;
  --fs-md: 14px;
  --fs-base: 15px;
  --fs-lg: 17px;
  --fs-xl: 20px;
  --fs-2xl: 26px;
  --fs-3xl: 30px;

  /* 统一过渡：只动 transform / opacity / 颜色，不动布局属性（会掉帧） */
  --dur: .18s;
  --ease: cubic-bezier(.4, 0, .2, 1);

  --font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB",
          "Microsoft YaHei", "Source Han Sans SC", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas,
               "Liberation Mono", monospace;

  --wrap: 1440px;
  --topbar-h: 60px;
  /* 题库页「页头 + 学段/目录页签」那截的高度（2026-10-11 实测 = 左栏自然顶边 − 顶栏 − 间距）。
     左栏要独立滚动就得把这一截从可用高度里减掉，否则页面没滚动时左栏底部够不着。
     改页头高度/页签样式后，用 _work/_probe_qside_scroll.py 量一下再回来校准这个值。 */
  --qgrid-top: 172px;

  /* 图形显示尺寸（「和题目协调」）：用 em 挂在正文字号上，别用孤立像素值。
     图形里的字母标注 ≈ 10pt，要跟同题正文（15px）视觉协调，图高约 11 行正文
     最合适 —— 11em × 15px ≈ 165px。三处图形（题库列表/详情/核对台）统一引用，
     未来若改正文字号，图会整体跟着缩放。 */
  --fig-max-h: 11em;
  --fig-max-w: 24em;               /* 核对台左栏并排时的宽度上限（约 360px） */
}

/* ---------- 2. 基础 ---------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* 选中文字用主色淡底：细节处的「这一站是刻意设计过的」 */
::selection { background: var(--accent-line); color: var(--accent-ink); }

body {
  margin: 0;
  min-height: 100dvh;              /* 移动端用 dvh，100vh 会被浏览器地址栏吞掉一截 */
  display: flex;
  flex-direction: column;
  font-family: var(--font);
  font-size: var(--fs-base);
  line-height: 1.62;
  color: var(--text);
  background: var(--bg);
  /* 中文点阵在高分屏上靠这两条才不"发胖" */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* 标题：层次交给字号与字重，不靠加粗边框。
   中文不做负字距（会挤在一起），只留一点点正向字距显得透气。 */
h1, h2, h3 { margin: 0; font-weight: 600; line-height: 1.3; letter-spacing: .01em; }
p { margin: 0 0 var(--gap-3); }

a {
  color: var(--accent);
  text-decoration: none;
  text-underline-offset: 3px;
  transition: color var(--dur) var(--ease);
}
a:hover { color: var(--accent-hover); text-decoration: underline; }

/* 数字一律等宽，表格与统计块里的数字才不会左右跳 */
.stat__num, .bars__val, .pager__info, .table td, .recent__time { font-variant-numeric: tabular-nums; }

::selection { background: var(--accent-soft); color: var(--accent-ink); }

/* 键盘焦点必须看得见 —— 只在键盘导航时出现，鼠标点击不显示 */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* 细滚动条：不抢视线，但能看出还有内容 */
* { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border: 3px solid transparent;
  border-radius: var(--radius-pill);
  background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--text-3); background-clip: content-box; }

code, .mono, .codeblock {
  font-family: var(--font-mono);
  font-size: .92em;
}
code {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 1px 5px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: var(--on-solid);
  padding: 10px 16px;
  z-index: 100;
}
.skip-link:focus { left: 0; }

/* ---------- 3. 布局骨架 ---------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  /* 毛玻璃：滚动时内容从下面透出来，比一条实心白条有质感 */
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}
.topbar__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--gap-5);
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  gap: var(--gap-4);
}

/* ⚠️ flex:0 0 auto + nowrap 缺一不可（原因同下面 .nav a 的注释）：
   「题库网站」四个字是 CJK，允许逐字断行 ⇒ min-content 宽度只有一个字，
   顶栏一挤就折成两行。2026-10-08 用户反馈「排列不协调，换行显示了」。 */
.brand { display: flex; align-items: center; gap: 9px; flex: 0 0 auto; color: var(--text); font-weight: 650; }
.brand:hover { text-decoration: none; color: var(--text); }
/* Logo（2026-10-08 换成内联 SVG，见 base.html）。
   display:block —— inline 元素会留出基线的那点下沉空间，logo 看着就歪了。 */
.brand__mark {
  display: block;
  width: 28px; height: 28px;
  border-radius: 9px;
  /* 一点点投影：让它从暖白背景上立起来，比纯平的高级 */
  box-shadow: 0 1px 3px color-mix(in srgb, var(--accent) 34%, transparent),
              0 2px 8px color-mix(in srgb, var(--accent) 16%, transparent);
  transition: transform var(--dur) var(--ease);
}
.brand:hover .brand__mark { transform: rotate(-4deg) scale(1.04); }
.brand__name { font-size: 16px; letter-spacing: .02em; white-space: nowrap; }

/* min-width:0 —— 没有它，下面那条横向滚动是摆设：flex 子项默认按
   min-content 撑开，容器永远不会溢出，也就永远不会滚。 */
/* 2026-10-11 用户两次要求「导航控件之间隔宽一点」⇒ gap 2px → 6px → 10px。
   宽屏（≥1441）还要把整条导航摊满（见下面那段）。 */
.nav { display: flex; gap: 10px; margin-right: auto; min-width: 0; }
.nav a {
  /* inline-flex：导航项右边可能挂一个待办角标（如「审核 3」），要能对齐 */
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* ⚠️ 高度被 responsive_test 卡着：导航项单行高必须 ≤ 40px。
     20px 行高 + 上下各 8px = 36px，留 4px 余量。改内边距前先想一下这条。 */
  padding: 8px 15px;
  line-height: 20px;
  /* 药丸（2026-10-11 第三批）：导航从「一排灰字」变成「一排药丸」 */
  border-radius: var(--radius-pill);
  color: var(--text-2);
  font-size: var(--fs-md);
  font-weight: 500;
  /* ⚠️ CJK 允许逐字断行 → 中文的 min-content 宽度就是「一个字」。
     不加这两条，窄屏下 flex 会把「题库」压成「题 / 库」两行（实测 768px 就中招）。
     flex:0 0 auto 禁止收缩，nowrap 禁止内部断行，两项缺一不可。 */
  white-space: nowrap;
  flex: 0 0 auto;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.nav a:hover {
  background: var(--surface-2);
  color: var(--text);
  text-decoration: none;
  transform: translateY(-1px);
}
/* 激活态（2026-10-11 第三批重做）：原来只是「淡橙底 + 一根橙描边」，远看跟
   没选中的行差不了多少，整条导航就显得灰扑扑。改成**主色实心渐变药丸 + 白字 +
   一点投影** —— 跟左上角 logo 用同一套渐变语言，一眼看得出「现在在哪」。
   渐变方向 180deg（上浅下深），比纯色块更有体积感。 */
.nav a.is-active {
  background: linear-gradient(180deg, var(--accent-hi), var(--accent));
  color: var(--on-solid);
  font-weight: 600;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--accent) 45%, transparent),
              0 4px 12px -4px color-mix(in srgb, var(--accent) 40%, transparent);
}
/* ⚠️ 必须写在 :hover 之后 —— 否则鼠标停在当前页上时，hover 的浅底会盖掉实心药丸 */
.nav a.is-active:hover { background: var(--accent-hover); color: var(--on-solid); }

/* 宽屏（> --wrap，即 1441px 起）：导航从「左边一小撮 + 右边一大片空」改成**摊满整条顶栏**。
   2026-10-11 用户截图框出顶栏中间那片空白 —— 原来 .nav 是 margin-right:auto，
   药丸挤在 logo 右边，离右侧用户菜单还有近千像素的空白。
   改成 flex:1 + space-between，让药丸均摊 logo 与用户菜单之间的全部空间
   （≤1440 的第二行布局用的也是 space-between，两处口径终于一致）。
   托盘底**去掉**：药丸都铺开了，「一排漂在暖白底上」的前提不存在；
   再垫一层整宽浅底只会变成一条压扁的色带。 */
@media (min-width: 1441px) {
  .nav {
    flex: 1 1 auto;
    margin: 0 var(--gap-5);
    justify-content: space-between;
  }
}

.nav__badge {
  min-width: 18px;
  padding: 0 5px;
  font-size: 11px;
  font-weight: 600;
  line-height: 16px;
  text-align: center;
  color: var(--on-solid);
  background: var(--danger);
  border-radius: var(--radius-pill);
  font-variant-numeric: tabular-nums;
}

.who { display: flex; align-items: center; gap: var(--gap-2); flex: 0 0 auto; min-width: 0; }
.who__name { color: var(--text-2); font-size: var(--fs-md); font-weight: 500; white-space: nowrap; max-width: 7em; overflow: hidden; text-overflow: ellipsis; }
/* 用户头像（2026-10-08 替掉那枚「管理员」标签）：
   珊瑚橙渐变的圆底 + 名字首字。和 logo 同一套渐变语言，把「人」和「品牌」串起来。
   flex:0 0 auto 在 .who 上 —— 顶栏一挤，最先被压的不能是头像（会被压扁成椭圆）。 */
.who__avatar {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: linear-gradient(145deg, var(--accent-hi) 0%, var(--accent) 100%);
  color: var(--on-solid);
  font-size: 13px; font-weight: 600; line-height: 1;
  letter-spacing: 0;                                  /* 单字别被 letter-spacing 推偏 */
  user-select: none;
  box-shadow: 0 1px 3px color-mix(in srgb, var(--accent) 32%, transparent);
}
.who__out { margin: 0; }
/* 头像换成真图（个人信息页上传后）：img 是替换元素，display 用 block + object-fit 裁圆。 */
.who__avatar--img, .usermenu__avatar--img {
  display: block;
  object-fit: cover;
  padding: 0;
  background: var(--surface-2);
  font-size: 0;
}

.wrap {
  flex: 1;
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: var(--gap-6) var(--gap-5) var(--gap-7);
}

.foot {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: var(--gap-5);
  color: var(--text-3);
  font-size: var(--fs-sm);
  display: flex;
  gap: var(--gap-2);
  align-items: center;
}
.foot__sep { opacity: .5; }

/* ---------- 4. 组件 ---------- */

/* 按钮：统一固定高度（不再靠内边距撑），hover 只改颜色不改尺寸 ——
   否则鼠标划过时整行会上下抖一下。 */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 36px;
  padding: 0 16px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-md);
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--sh-1);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
.btn:hover { background: var(--surface-2); text-decoration: none; }
.btn:active { transform: translateY(1px); box-shadow: none; }
.btn--primary {
  /* 极淡的纵向渐变：顶边提亮一档，比死平色多一层「厚度」，又不至于花哨 */
  background: linear-gradient(180deg, var(--accent-hi) 0%, var(--accent) 46%, var(--accent) 100%);
  border-color: var(--accent);
  color: var(--on-solid);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--accent) 22%, transparent),
              0 3px 10px -3px color-mix(in srgb, var(--accent) 45%, transparent);
}
.btn--primary:hover {
  background: linear-gradient(180deg, var(--accent) 0%, var(--accent-hover) 100%);
  border-color: var(--accent-hover);
}
.btn--danger { color: var(--danger); border-color: var(--danger-line); }
.btn--danger:hover { background: var(--danger-soft); }
.btn--ghost { background: transparent; border-color: transparent; color: var(--text-2); box-shadow: none; }
.btn--ghost:hover { background: var(--surface-2); color: var(--text); }

/* 次要主色按钮（2026-10-13 用户要求：「班型管理」按钮要跟「新建学生」一样醒目美观）。
   用辅助色松石青做实心 —— 与珊瑚橙的「新建学生」并排时，两个都是实心高饱和、
   分量相当，但颜色区分开「新建」与「管理」两条动线，不会看着像两个一模一样的按钮。
   令牌走 --cool*，改主题只需动第 1 节。 */
.btn--teal {
  background: linear-gradient(180deg, var(--cool) 0%, var(--cool) 46%, var(--cool) 100%);
  border-color: var(--cool);
  color: var(--on-solid);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--cool) 22%, transparent),
              0 3px 10px -3px color-mix(in srgb, var(--cool) 45%, transparent);
}
.btn--teal:hover {
  background: linear-gradient(180deg, var(--cool) 0%, var(--cool-hover) 100%);
  border-color: var(--cool-hover);
}
.btn--sm { height: 30px; padding: 0 11px; font-size: var(--fs-sm); }
.btn--block { width: 100%; }
.btn:disabled, .btn[disabled] { opacity: .5; cursor: not-allowed; transform: none; }

/* 🔴 `<summary class="btn">` 的文字会贴在盒子顶部（2026-10-15 用户报「按钮文字不在中间」）。
   根因：Chromium 对 `<summary>` 有自身的 display 处理，**不会采用 .btn 的 inline-flex**
   —— 实测 `/students/classes` 的「编辑」summary 算出 `display: inline-block`、
   文字中心比盒心高 8px，而同一份 .btn 用在 <button> 上完全正常。
   全站有十几处 summary 借用了 .btn（改/删/加练习/题库导入…），不修就会「有的按钮正、
   有的按钮歪」，看着像随机 bug。这里显式重申一次，让两者完全一致。 */
summary.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  list-style: none;
}
summary.btn::-webkit-details-marker { display: none; }
summary.btn::marker { content: none; }
/* 「加入试题篮」按钮 toggle（cart.js 加/去 is-in）：不在篮中=橙色实心「加入试题篮」，
   在篮中=浅绿描边「移出试题篮」。🔴 这里**不能**用 pointer-events:none —— 按钮要能再点一次
   把它移出（2026-10-09 用户要求）。旧版靠禁用点击来挡重复加，结果造成「只能进不能出」的死角。
   权重要压过 .btn--primary / .btn:hover，所以写成 `.btn.is-in`。 */
.btn.is-in {
  background: var(--ok-soft); border-color: var(--ok-line); color: var(--ok);
  box-shadow: none;
}
.btn.is-in:hover { background: color-mix(in srgb, var(--ok-soft) 70%, var(--surface)); }

/* 表单 */
.form { max-width: 460px; }
.form--wide { max-width: none; }

.field { margin-bottom: var(--gap-4); display: flex; flex-direction: column; }
.field--grow { flex: 1; min-width: 180px; }
.field > label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-2);
  margin-bottom: 6px;
}
.req { color: var(--danger); font-weight: 400; }

input[type="text"], input[type="password"], input[type="email"],
input[type="number"], input[type="search"], input[type="date"],
textarea, select {
  width: 100%;
  min-height: 38px;
  padding: 8px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-md);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              background var(--dur) var(--ease);
}
input[type="text"], input[type="password"], input[type="email"],
input[type="number"], input[type="search"], input[type="date"], select {
  /* 单行控件固定高度；textarea 用 min-height 自适应 */
  height: 38px;
  padding-top: 0;
  padding-bottom: 0;
}
textarea { resize: vertical; line-height: 1.65; }
textarea.mono { font-family: var(--font-mono); font-size: var(--fs-sm); }
select[multiple] { height: auto; min-height: 120px; padding: 6px; }
input:hover, select:hover, textarea:hover { border-color: var(--text-3); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
input::placeholder, textarea::placeholder { color: var(--text-3); }

.hint { margin: 5px 0 0; font-size: var(--fs-xs); color: var(--text-3); line-height: 1.55; }

/* 提示条：左侧一条彩色竖线，比整块铺色克制 */
.alert {
  padding: 11px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  border-left-width: 3px;
  font-size: var(--fs-md);
  margin-bottom: var(--gap-4);
}
.alert--error { background: var(--danger-soft); border-color: var(--danger-line); border-left-color: var(--danger); color: var(--danger); }
.alert--ok    { background: var(--ok-soft);     border-color: var(--ok-line);     border-left-color: var(--ok);     color: var(--ok); }
/* ⚠️ 这个变体以前漏了：base.html 会输出 alert--warn，但样式里没有，
   落到裸 .alert 上时边框取 currentColor，深色下很难看。 */
.alert--warn  { background: var(--warn-soft);   border-color: var(--warn-line);   border-left-color: var(--warn);   color: var(--warn); }
/* 中性通知（2026-10-17 加）：用于「AI 正在生成 / 已自动生成」这类说明 ——
   不是错误也不是成功，用冷色（--cool 系）跟语义色区分开。 */
.alert--note  { background: var(--cool-soft);   border-color: var(--cool-line);   border-left-color: var(--cool);   color: var(--cool-hover); }

/* 标签 */
.tag {
  display: inline-flex;
  align-items: center;
  padding: 0 9px;
  border-radius: var(--radius-pill);
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 20px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--text-2);
  white-space: nowrap;
}
.tag--accent { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-hover); }
.tag--role { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-hover); }
.tag--fig { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }
.tag--type { background: var(--surface-2); }
.tag--s-draft { background: var(--surface-2); }
.tag--s-pending { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }
.tag--s-published { background: var(--ok-soft); border-color: var(--ok-line); color: var(--ok); }
.tag--s-rejected { background: var(--danger-soft); border-color: var(--danger-line); color: var(--danger); }
.tag--s-archived { background: var(--surface-2); color: var(--text-3); }
/* 知识点（2026-10-08 用户要求）：用冷青 --cool 系，和「题型 / 分类」在色相上分开 ——
   分类是导航维度（中性），题型是归类（中性），知识点是「这题考了什么」的精确标签，
   冷青点缀让它在 meta 行里一眼可辨，也方便眼睛顺着色块扫。 */
.tag--kp { background: var(--cool-soft); border-color: var(--cool-line); color: var(--cool-ink); }
.tag--ok { background: var(--ok-soft); border-color: var(--ok-line); color: var(--ok); }

/* ---- 运维台：功能变更记录（2026-10-15 新增） ---- */
.page__head-actions { display: flex; gap: var(--gap-2); align-items: center; margin-left: auto; flex-wrap: wrap; }
.field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-4); }
.field-grid--3 { grid-template-columns: repeat(3, 1fr); }
.form__actions { display: flex; gap: var(--gap-2); margin-top: var(--gap-4); flex-wrap: wrap; }
.field__hint { font-size: var(--fs-xs); color: var(--text-3); margin-top: 4px; }
.req { color: var(--danger); font-style: normal; }
/* 变更记录表单在运维台内放宽，避免两栏文本框挤在一起 */
.ops form.form { max-width: 760px; }

.changelog__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--gap-4); flex-wrap: wrap; }
.changelog__meta { font-size: var(--fs-xs); color: var(--text-3); margin: 2px 0 0; }
.changelog__counts { display: flex; gap: 6px; flex-wrap: wrap; }
.changelog__body { white-space: pre-wrap; line-height: 1.7; color: var(--text-1); margin: var(--gap-3) 0; font-size: var(--fs-sm); }
.changelog__tasks { display: flex; gap: var(--gap-5); flex-wrap: wrap; margin-top: var(--gap-3); }
.changelog__col { flex: 1 1 260px; min-width: 240px; }
.changelog__col-title { font-size: var(--fs-sm); font-weight: 600; margin: 0 0 6px; color: var(--text-2); }
.changelog__list { margin: 0; padding-left: 1.1em; color: var(--text-1); font-size: var(--fs-sm); }
.changelog__list li { margin: 3px 0; }
.changelog__shots { margin-top: var(--gap-4); }
.changelog__gallery { display: flex; flex-wrap: wrap; gap: var(--gap-3); margin-top: 6px; }
.changelog__shot { display: block; border: 1px solid var(--line); border-radius: var(--radius-2); overflow: hidden; background: var(--surface-2); }
.changelog__shot img { display: block; width: 240px; height: auto; object-fit: cover; }
.changelog__shot:hover { border-color: var(--accent); }

/* 难度星 */
.stars { white-space: nowrap; letter-spacing: 1px; font-size: var(--fs-sm); }
.stars__on { color: var(--star); }
.stars__off { color: var(--line-strong); }

/* 空状态：给个"这里本该有内容"的图形暗示，别只有一行灰字（像坏了） */
.empty {
  position: relative;
  padding: var(--gap-6) var(--gap-5);
  text-align: center;
  color: var(--text-2);
  background: linear-gradient(180deg,
              var(--surface-2) 0%,
              color-mix(in srgb, var(--surface-2) 45%, var(--surface)) 100%);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: var(--fs-md);
  line-height: 1.7;
}
.empty::before {
  content: "";
  display: block;
  width: 40px; height: 40px;
  margin: 0 auto var(--gap-3);
  border-radius: 12px;
  border: 1px solid var(--accent-line);
  /* 三条渐短的"文字线"，暗示"这里本该有内容" */
  background-color: var(--accent-soft);
  background-image: linear-gradient(var(--accent), var(--accent)),
                    linear-gradient(var(--accent-line), var(--accent-line)),
                    linear-gradient(var(--accent-line), var(--accent-line));
  background-size: 18px 2px, 22px 2px, 13px 2px;
  background-position: 10px 12px, 10px 20px, 10px 28px;
  background-repeat: no-repeat;
  opacity: .9;
}

/* 通用面板 */
.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-5);
  margin-bottom: var(--gap-4);
  box-shadow: var(--sh-1);
}
.panel__head { display: flex; align-items: center; justify-content: space-between; gap: var(--gap-3); }
.panel__title { font-size: var(--fs-lg); font-weight: 600; margin-bottom: var(--gap-4); }
.panel__head .panel__title { margin-bottom: 0; }
/* 面板里的说明句。此前 `.panel__hint` **只有 `.panel__hint code` 一条规则**，
   段落本身没有任何样式 —— 运维台与 AI 页都在用它，看着就是普通正文。
   补一条克制的次级样式：让「说明」明显区别于「结论」。
   `:first-of-type` 之外的间距靠 margin 兜住，面板里可以连用多条。 */
.panel__hint { margin: 0 0 var(--gap-3); font-size: var(--fs-sm); color: var(--text-3); line-height: 1.7; }
.panel__title + .panel__hint { margin-top: calc(-1 * var(--gap-2)); }
.panel__hint:last-child { margin-bottom: 0; }
details.panel > summary { cursor: pointer; font-size: var(--fs-lg); font-weight: 600; }
details.panel[open] > summary { margin-bottom: var(--gap-4); }

.codeblock {
  margin: 0;
  padding: var(--gap-4);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.7;
}

/* 分页：翻页 + 「跳到第 N 页」（题库 / 组卷 / 审核三处共用）
   整条**居中**、横向一行排开。
   ⚠️ 必须 flex-wrap —— 390px 窄屏下这一条挤不下，不换行就是整页横向溢出。 */
.pager {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
  gap: var(--gap-2) var(--gap-3); margin-top: var(--gap-5);
}
.pager__info { color: var(--text-2); font-size: var(--fs-sm); }
/* 到头了的翻页按钮用 span 占位：留住位置（否则整条会因按钮消失而左右晃），但点不动 */
.btn.is-disabled { opacity: .45; cursor: not-allowed; pointer-events: none; }
/* 「跳到第 N 页」：所有元素在一条线上，与前面的翻页按钮略拉开距离 */
.pager__jump {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--gap-2); margin-left: var(--gap-2); max-width: 100%;
}
.pager__jumplabel {
  display: flex; align-items: center; gap: var(--gap-2);
  color: var(--text-2); font-size: var(--fs-sm); white-space: nowrap;
}
/* 页码框：下拉候选 + 手输**合并在这一个框**里（模板里是 input[list]+datalist）。
   单行控件的基础样式写死了 width:100% / height:38px，这里要收回到紧凑尺寸，
   否则这个框会独占一整行、把整条分页顶成两行。
   ⚠️ 选择器必须写成 `input.pager__jumpbox`：`input[type="text"] { width: 100%; }`
   的权重是 (0,1,1)，比光写类名（0,1,0）**重** —— 光写类名收不回来。
   加上 `input` 后权重同为 (0,1,1)，靠**源码顺序在后**取胜。 */
input.pager__jumpbox {
  width: 5em; height: 30px; min-height: 30px;
  padding: 0 8px; text-align: center; font-size: var(--fs-sm);
}

/* ---------- 5. 页面级 ---------- */

/* 落地页 */
.landing { max-width: 560px; margin: 9vh auto 0; text-align: center; }
.landing__title { font-size: var(--fs-3xl); margin-bottom: var(--gap-3); }
.landing__lead { color: var(--text-2); font-size: var(--fs-lg); margin-bottom: var(--gap-5); }
.landing__actions { display: flex; gap: var(--gap-3); justify-content: center; }
.landing__note { margin-top: var(--gap-5); color: var(--text-3); font-size: var(--fs-sm); }

/* 登录 / 注册 */
.authcard {
  max-width: 400px;
  margin: 8vh auto 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--gap-6) var(--gap-5);
  box-shadow: var(--sh-3);
}
.authcard__logo {
  width: 40px; height: 40px;
  margin: 0 auto var(--gap-4);
  border-radius: 12px;
  background: linear-gradient(145deg, var(--accent) 0%,
              color-mix(in srgb, var(--accent) 72%, #000) 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .18),
              inset 0 0 0 7px rgba(255, 255, 255, .30),
              0 4px 14px -2px color-mix(in srgb, var(--accent) 35%, transparent);
}
.authcard__title { font-size: var(--fs-xl); text-align: center; margin-bottom: var(--gap-2); }
.authcard__sub { margin: 0 0 var(--gap-5); text-align: center; font-size: var(--fs-sm); color: var(--text-3); }
/* 卡片内的表单撑满卡片宽度，别在卡片里再收一次窄 */
.authcard .form { max-width: none; }
.authcard__foot { margin: var(--gap-4) 0 0; text-align: center; font-size: var(--fs-sm); color: var(--text-3); }

/* 错误页 */
.msgpage { max-width: 480px; margin: 11vh auto 0; text-align: center; }
.msgpage__code { font-size: 56px; font-weight: 700; color: var(--line-strong); margin: 0; line-height: 1; }
.msgpage__title { font-size: var(--fs-xl); margin: var(--gap-3) 0; }
.msgpage__body { color: var(--text-2); margin-bottom: var(--gap-5); }

/* 页头：标题给足分量、副标题压低、动作靠右 —— 一眼就知道"这一页是干什么的" */
.page__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--gap-4);
  margin-bottom: var(--gap-5);
}
.page__title { font-size: var(--fs-2xl); font-weight: 650; line-height: 1.2; }
.page__sub {
  margin: var(--gap-2) 0 0;
  color: var(--text-3);
  font-size: var(--fs-sm);
  display: flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap;
}
/* 🔴 必须允许换行：窄屏（手机）下这一行常有 3~5 枚按钮（整卷预览 / 换一个文件 / 题库 /
   显示导入流程），不换行会横向溢出、把末尾按钮挤出视口 —— 用户会误以为「没有这个入口」。 */
.page__actions { display: flex; gap: var(--gap-2); align-items: center; flex-wrap: wrap; }
.page__actions form { margin: 0; }
/* #362「用 WPS 打开」那枚按钮是 **POST 表单**（刻意不用 `<a>` 链接，
   否则会被 base.html 的 speculationrules 提前预取 → 鼠标划过就弹 WPS）。
   这里把它压成「看起来就是一枚按钮」：不换行、不撑宽、不留外边距。 */
.page__actions .action-form { display: inline-flex; align-items: center; flex: none; }

/* 统计数据块：第一个数字放大当"主角"，其余均匀铺开。
   原来七个一模一样的小方块排成一行，看不出哪个重要。 */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(164px, 1fr));
  gap: var(--gap-3);
  margin-bottom: var(--gap-5);
}
.stat {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-4);
  box-shadow: var(--sh-1);
  transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.stat:hover { box-shadow: var(--sh-2); transform: translateY(-1px); }
.stat__num { margin: 0; font-size: var(--fs-2xl); font-weight: 650; line-height: 1.15; color: var(--text); }
.stat__label { margin: 4px 0 0; font-size: var(--fs-xs); color: var(--text-3); font-weight: 500; }

/* 桌面固定四列 + 主数字占两格。
   7 个指标的单位数是 2+6=8，正好是 4 的两倍 → 铺满两行、不留空洞。
   （交给 auto-fit 的话会变成 5+2，第二行两个孤零零的卡片很难看。） */
@media (min-width: 760px) {
  .stats { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .stats > .stat:first-child { grid-column: span 2; border-color: var(--cool-line); }
  .stats > .stat:first-child .stat__num { font-size: 34px; color: var(--cool); }
}
@media (max-width: 759px) {
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* 横向条形图 */
.bars { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--gap-4); }
.bars__row { display: grid; grid-template-columns: 84px 1fr 44px; align-items: center; gap: var(--gap-3); }
.bars__name { font-size: var(--fs-md); color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bars__track { height: 8px; background: var(--surface-3); border-radius: var(--radius-pill); overflow: hidden; }
.bars__fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--cool) 0%,
              color-mix(in srgb, var(--cool) 60%, var(--cool-hover)) 100%);
  transition: width .35s var(--ease);
}
.bars__val { text-align: right; font-size: var(--fs-md); font-weight: 600; color: var(--text); }

/* 最近录入 */
.recent { list-style: none; margin: 0; padding: 0; }
.recent__row {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  padding: 11px 10px;
  margin: 0 -10px;
  border-bottom: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: var(--fs-md);
  transition: background var(--dur) var(--ease);
}
.recent__row:last-child { border-bottom: 0; }
.recent__row:hover { background: var(--surface-2); }
/* 2026-10-14 #367：这枚原来是题号（PS-xxxxxx），现在换成题干摘要，
   链接指向不变。摘要要单行截断，所以给 min-width:0 + 省略号，
   宽度封在上限内 —— 否则长题干会把右边「主分类 / 题型 / 时间」挤走。 */
.recent__stem {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 46%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text);
  text-decoration: none;
}
.recent__stem:hover { color: var(--accent); }
.recent__topic { color: var(--text-2); margin-right: auto; }
.recent__time { color: var(--text-3); font-size: var(--fs-sm); }

/* ---- 「搜索 / 筛选」折叠外壳（2026-10-11 第三批）------------------------
   用户口径两条：① 面板得在**题目区上方**、别横跨左栏（已把 .filters 移回 .qmain）；
   ② 手机上**默认收起**（一屏先看到题目）。
   做法：外面套一层 <details class="filterbox">；桌面端把 summary 藏掉 ——
   展开态与改版前一模一样，窄屏才显出那行「搜索 / 筛选」标题。 */
.filterbox { margin: 0; }
.filterbox > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--gap-2);
  padding: 11px var(--gap-4);
  margin-bottom: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--sh-1);
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.filterbox > summary::-webkit-details-marker { display: none; }
.filterbox > summary:hover { border-color: var(--line-strong); }
.filterbox__ico { font-size: 15px; line-height: 1; }
.filterbox__t { flex: none; }
.filterbox__hint { margin-left: auto; font-size: var(--fs-xs); font-weight: 500; color: var(--text-3); }
/* 开合指示：一枚三角，展开时翻过来（比换字省事，也不用 JS） */
.filterbox > summary::after {
  content: "▾";
  font-size: 11px;
  color: var(--text-3);
  transition: transform var(--dur) var(--ease);
}
.filterbox[open] > summary::after { transform: rotate(180deg); }
/* 桌面端：标题行藏掉，面板常开 —— 大屏塞得下，多一次点击纯属添乱 */
@media (min-width: 721px) {
  .filterbox > summary { display: none; }
}


/* 搜索 / 筛选面板本体。字段走统一网格、**一律等宽**：以前关键词跨两列、
   别的挤一列，看着参差（用户反馈「有些比较宽」）；现在全部等宽、排出来齐整。
   动作单独一行靠右。位置见上面 .filterbox 的说明（在题目区上方，不跨左栏）。 */
.filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  align-items: end;
  gap: var(--gap-3) var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-4) var(--gap-5) var(--gap-5);
  margin-bottom: var(--gap-5);
  box-shadow: var(--sh-1);
}
.filters .field { margin-bottom: 0; min-width: 0; }
/* 关键词那格：不再「跨两列」、也不再带 min-width:180px —— 那两样都会让它比
   同伴宽一截。⚠️ min-width 尤其要清掉：留着会把它所在的**整列**顶宽，整排参差。 */
.filters .field--grow { grid-column: auto; min-width: 0; }

/* 动作区：独占一行、靠右，上面一条细线跟字段区隔开 */
.filters__actions {
  grid-column: 1 / -1;
  display: flex;
  gap: var(--gap-2);
  justify-content: flex-end;
  align-items: center;
  padding-top: var(--gap-3);
  border-top: 1px solid var(--line);
}
.filters__actions .btn { box-shadow: none; }

/* 页脚行（2026-10-11，**只题库页**用）：勾选框与动作按钮并排，替掉原来那两行中间的整条空带。
   .filters__actions 在页脚里要「退掉」它独占一行 / 自带分隔线的默认样式 ——
   分隔线与上内边距改由 .filters__foot 统一给。其它页（试卷库/学生档案/讲义）
   没包这层，照旧单独成行。 */
.filters__foot {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-4);
  padding-top: var(--gap-3);
  border-top: 1px solid var(--line);
}
.filters__foot > .filters__actions {
  grid-column: auto;
  padding-top: 0;
  border-top: 0;
}
.filters__foot .field--check { margin-bottom: 0; }

/* 四.2：考试日期「按年份 / 按日期」切换控件 —— 一枚分段按钮 + 两面板。
   珊瑚橙作为选中态，沿用全站主色；未选中是素净描边，眼睛先落到当前模式。 */
.datemode {
  display: inline-flex;
  gap: 4px;
  padding: 3px;
  margin-bottom: var(--gap-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
}
.datemode__tab {
  appearance: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: 6px 16px;
  border-radius: 999px;
  color: var(--text-2);
  background: transparent;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.datemode__tab:hover { color: var(--accent-hover); }
.datemode__tab.is-active {
  color: #fff;
  background: var(--accent);
  box-shadow: 0 2px 8px rgba(232, 97, 60, .35);
}
.datemode__panel { margin-top: 2px; }
.datemode__panel[hidden] { display: none; }

/* 四.1：起止日期并排，中间一个「至」；原生 date 控件统一高度与圆角，
   日历图标染成主色，跟整站输入框一个调性（不再是有框没边的系统控件）。 */
.date-range {
  display: flex;
  align-items: center;
  gap: var(--gap-2);
}
.date-range__sep { color: var(--text-3); font-size: var(--fs-sm); }
.date-range input[type="date"] {
  flex: 1 1 auto;
  min-width: 0;
}
.date-range input[type="date"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: .65;
  filter: invert(38%) sepia(72%) saturate(1800%) hue-rotate(330deg);
}
.date-range input[type="date"]:hover::-webkit-calendar-picker-indicator { opacity: 1; }

.resultline { color: var(--text-2); font-size: var(--fs-md); margin-bottom: var(--gap-3); }

/* 表格 */
.tablewrap {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow-x: auto;
  box-shadow: var(--sh-1);
}
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-md); }
.table th, .table td { padding: 12px 14px; text-align: left; vertical-align: top; }
.table thead th {
  background: var(--surface-2);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-3);
  letter-spacing: .03em;
  white-space: nowrap;
  border-bottom: 1px solid var(--line-strong);
}
.table tbody td { border-bottom: 1px solid var(--line); }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr { transition: background var(--dur) var(--ease); }
.table tbody tr:hover { background: var(--surface-2); }
/* 题干列：里面是带分式/根号的公式，行高必须给足，
   否则 KaTeX 把行盒撑高后会和上下行叠字（列表里最刺眼的毛病）。 */
.cell-stem { min-width: 320px; line-height: 1.9; }
.cell-stem .katex { font-size: .95em; }
.cell-src { color: var(--text-2); font-size: var(--fs-sm); white-space: nowrap; }

/* ---------- 题库列表：一题一框（题干一行 / 元信息一行） ----------
   2026-10-06 由表格改版：题干长短差得远，表格列宽被最长的那道牵着走，
   窄屏还非得靠横向滚动兜住（.cell-stem 的 min-width:320px）。
   改成一题一张卡，第二行专门放编号/分类/…/状态。
   ⚠️ 类名前缀刻意用 .qrow，**别**贪手感复用手感相近的 .qlist / .qcard ——
   那两个在组卷工作台里是「可拖拽的题目行」（`display:flex` + `cursor:grab`），
   复用会被样式表更靠后的定义压住（工程里已踩过一次，见第 2046 行那段说明）。 */
.qrows {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--gap-3);
}
.qrow {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-4);
  box-shadow: var(--sh-1);
  transition: border-color var(--dur) var(--ease);
  /* 两栏：左内容 + 右「加入试题篮」。flex-wrap 让窄屏（390px）把按钮折到下一行，
     这是「不横向溢出」的关键 —— 题干完整显示后一行可能很长。 */
  display: flex; align-items: flex-start; flex-wrap: wrap;
  gap: var(--gap-2) var(--gap-3);
}
.qrow:hover { border-color: var(--line-strong); }
/* 内容列。`min-width: 0` 不可省：flex 子项默认 min-width:auto，
   长题干会把卡片顶宽、连带整页横向滚动（同族的经典坑）。 */
.qrow__main { flex: 1 1 320px; min-width: 0; }
/* 学校来源角标（2026-10-11 用户要求：标在每道题所在框的左上角，鲜艳美观）。
   ★ 第三版（同日用户重新定口径，覆盖前一版）：
     「每道题的**来源日期 + 学校**显眼呈现在左上角；同一所学校考过的不同日期
      用一个**下拉框**收起来；考过这道题的**多个学校横向排列**。」
   所以从「一枚试卷名药丸」改成「**每所学校一枚药丸**，横排铺开」：
     · 药丸 = 实心松石青渐变 + 白字（暖橙管交互、冷青给数据型点缀，见 §1 口径）；
     · 药丸里写 `育才 · 2026.3.8`，右端白底数字＝**这所学校考过几次**；
     · 同一校有多个日期时，药丸变成 `<summary>`，右上角挂一枚 `+N`，
       点开是一张**浮层**（列出该校考过的每个日期 + 那天的试卷名）；
     · 多学校时药丸之间 flex-wrap 横向排列，窄屏自然折行，不竖向堆叠。
   ⚠️ 旧版的 `.qrow__src` / `.qrow__occs*` 系列已随本次改版删除 ——
      全站唯一渲染处是 `questions/_occbadge.html`。 */
.qsrcs { display: grid; gap: 6px; margin-bottom: var(--gap-2); }
.qsrcs__sum {
  margin: 0; font-size: var(--fs-xs); color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.qsrcs__sum b { color: var(--cool-ink); font-size: var(--fs-sm); }
.qsrcs__sep { padding: 0 2px; color: var(--line-strong); }
/* 学校药丸横向排列（用户明确要求「学校横向排列」） */
.qsrcs__row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px; }

.qsrc { display: block; position: relative; }
.qsrc__pill {
  display: inline-flex; align-items: center; gap: 7px;
  max-width: 100%; overflow: hidden;
  padding: 3px 9px 3px 11px;
  border-radius: var(--radius-pill);
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .02em;
  color: #fff; white-space: nowrap;
  background: linear-gradient(135deg, #14a7bd, var(--cool));
  box-shadow: 0 2px 8px rgba(15, 138, 157, .30);
}
/* 药丸前一个小白点，别让纯文字显得干巴 */
.qsrc__pill::before {
  content: ""; flex: none;
  width: 6px; height: 6px; border-radius: 50%;
  background: rgba(255, 255, 255, .9);
}
.qsrc__school { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* 日期：比学校轻一点（字重降一档、透明度略降），主次分明但仍读得清 */
.qsrc__date {
  flex: none; color: rgba(255, 255, 255, .9); font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* 「+N」：这所学校还有 N 个别的日期藏在下拉里 */
.qsrc__more {
  flex: none; padding: 0 5px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .22);
  font-size: 10.5px; font-weight: 800; line-height: 15px;
  font-variant-numeric: tabular-nums;
}
/* 次数徽标：白底深青字，压在药丸右端（等宽数字，一排卡扫下来不会跳） */
.qsrc__count {
  flex: none;
  min-width: 17px; padding: 0 5px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .93);
  color: var(--cool-ink);
  font-size: 11px; font-weight: 800; line-height: 16px;
  text-align: center; font-variant-numeric: tabular-nums;
}
/* 多日期时药丸是 <summary>：去掉三角标记，自己补一枚会转的「▾」 */
details.qsrc > summary.qsrc__pill { cursor: pointer; list-style: none; }
details.qsrc > summary.qsrc__pill::-webkit-details-marker { display: none; }
details.qsrc > summary.qsrc__pill::after {
  content: "▾"; flex: none;
  font-size: 9px; color: rgba(255, 255, 255, .88);
  transition: transform var(--dur) var(--ease);
}
details.qsrc[open] > summary.qsrc__pill { background: linear-gradient(135deg, var(--cool), var(--cool-hover)); }
details.qsrc[open] > summary.qsrc__pill::after { transform: rotate(180deg); }

/* 下拉明细：**浮**在卡片上方，不把下面的题顶下去（列表上下乱跳比浮层难用得多）。
   `.qsrc` 自己当锚点：里面只有药丸那一行是真高度，`top: 100%` 正好落在药丸下方。
   ⚠️ 祖先链上没有 overflow:hidden，所以不会被裁掉（改版式时要重新确认这一条）。 */
.qsrc__panel {
  position: absolute; top: calc(100% - 4px); left: 0; z-index: 6;
  width: min(360px, calc(100vw - 56px));
  padding: 10px 12px 12px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: var(--sh-3);
}
.qsrc__ph {
  margin: 0 0 8px; padding-bottom: 7px;
  border-bottom: 1px dashed var(--line);
  font-size: var(--fs-xs); color: var(--text-2);
}
.qsrc__ph b { color: var(--cool-ink); }
.qsrc__dates { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.qsrc__drow {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 8px;
  font-size: var(--fs-xs); color: var(--text-2);
}
/* 日期：等宽数字，一列对齐（下拉里一行一天，最要紧的是日期好对） */
.qsrc__ddate {
  flex: none; padding: 1px 9px; border-radius: var(--radius-pill);
  background: rgba(15, 138, 157, .12);
  color: var(--cool-ink); font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* 那天的试卷名：浅底小标，跟在日期后面 */
.qsrc__dpaper {
  min-width: 0; padding: 1px 8px; border-radius: var(--radius-pill);
  background: var(--surface-2); border: 1px solid var(--line);
  color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 「最新」那行（用户口径：「按时间顺序从上到下排列，显示最新的日期」）。
   最近一次考试打头，并给一枚暖橙小标 + 左侧一条橙线 ——
   暖橙是全站管交互/强调的色，这样「最新」在冷青的一列日期里一眼跳出来。 */
.qsrc__drow.is-latest .qsrc__ddate {
  background: linear-gradient(135deg, var(--accent), var(--accent-hover));
  color: var(--on-solid);
}
.qsrc__drow.is-latest { padding-left: 7px; border-left: 3px solid var(--accent); }
.qsrc__dnew {
  flex: none; padding: 0 6px; border-radius: var(--radius-pill);
  background: var(--accent-soft); color: var(--accent-ink);
  font-size: 10.5px; font-weight: 800; line-height: 15px;
}
/* 紧凑模式：内边距收一档；第二行的「知识点/题型/难度/日期」本来就不渲染 */
.qrows--compact .qrow { padding: var(--gap-3) var(--gap-4); }


/* 第一行：题干（吃掉剩余宽度）+ 含图/公式徽标 */
.qrow__head { display: flex; align-items: flex-start; gap: var(--gap-3); }
/* 行高必须给足：KaTeX 会把行盒撑高，紧了就和上一行叠字（同老 .cell-stem 的顾虑） */
.qrow__stem { flex: 1; min-width: 0; line-height: 1.9; word-break: break-word; }
.qrow__stem a { color: var(--text); }
.qrow__stem a:hover { color: var(--text); text-decoration: none; }
.qrow__stem .katex { font-size: .95em; }
.qrow__flags { flex: none; display: flex; align-items: center; gap: var(--gap-1); padding-top: 3px; }
/* ⚠️ 2026-10-08：左上角勾选框（`.qrow__check`）按用户要求删掉了。
   连带把 `.qrow__figs` / `.qrow__meta` 的 `padding-left: calc(16px + var(--gap-3))`
   一起去掉 —— 那两处缩进本来就是为了**绕开勾选框、对齐到题干左边缘**。
   框没了还留缩进，整块内容会平白右移一格（改完必须目视成品，结构断言看不出来）。
   `.qrow__check` 的样式规则也删了：留着就是给不存在的元素写着色情书。 */

/* 图形：题干下方按原样出图（TikZ 在服务端编成 SVG，矢量的）。
   `margin-top` 写在图上而**不是容器上** —— 图都取不到时容器是空的，
   空容器带 margin 会平白撑出一道空隙。 */
.qrow__figs {
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--gap-3);
}
.qrow__fig, .qrow__figfail { margin-top: var(--gap-3); }
.qrow__fig {
  /* 只给上限、不给固定宽高：图按原比例缩，绝不会撑破卡片。
     max-height 是给个别超大图设的闸，不然一张图就把一页顶得老长。
     高度闸挂在正文 em 上（--fig-max-h），图随正文字号缩放，和题目协调。
     🔴 2026-10-08 用户要求「图片外面的矩形框可以不用」→ 不画 border / 圆角 / 白底。
     图本身就是有边线的矢量图，再套一圈外框就成了多余的「框里框」。 */
  max-width: 100%; max-height: var(--fig-max-h); width: auto; height: auto;
}
.qrow__figfail { margin-bottom: 0; color: var(--text-2); font-size: var(--fs-sm); }

/* 第二行：编号 · 分类 · 知识点 · 题型 · 难度 · 日期 · 质量 · 状态
   （2026-10-08 去掉了原来「对齐到题干左边缘」的 padding-left —— 勾选框已删；
    2026-10-11「来源」从这一行移到卡片左上角的来源角标（.qsrcs），这里不再有它） */
.qrow__meta {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 5px var(--gap-4);
  margin-top: var(--gap-3); padding-top: var(--gap-3);
  border-top: 1px dashed var(--line);
  font-size: var(--fs-sm); color: var(--text-2);
}
.qrow__mi { display: inline-flex; align-items: center; gap: 5px; min-width: 0; max-width: 100%; }
/* 栏目名（编号 / 分类 / …）：表格没了表头，靠它告诉人「这是哪一项」 */
.qrow__k { color: var(--text-3); font-size: var(--fs-xs); }
/* 2026-10-11：卡片第二行那枚可见编号控件（.qrow__code）已按用户要求删除。
   题号改由 <li class="qrow" data-code> 承载（只给测试/脚本用，不上界面）。 */

/* 就地展开的「答案与解析」（2026-10-08 新增，用户要求不跳页就能看）。
   用原生 `<details>`：无 JS 也能开合；三角标是浏览器自带的，不另画图标。
   视觉上刻意**弱于题干**（虚线边 + 次要色），别让答案抢了题目的注意力。 */
.qrow__ans { margin-top: var(--gap-3); }
/* 左栏（组卷素材列表）里的折叠块要**贴着同一行右端**（#242，2026-10-12）：
   margin-top 归零，否则会把行高撑开、题干与它错位。 */
.plist__head .qrow__ans { margin-top: 0; flex: none; }
.qrow__anssum {
  cursor: pointer;
  display: inline-block; user-select: none;
  padding: 3px 8px;
  font-size: var(--fs-sm); color: var(--accent-ink);
  background: var(--accent-soft);
  border: 1px dashed var(--accent-line); border-radius: var(--radius-sm);
}
.qrow__anssum:hover { border-color: var(--accent); }
.qrow__ans[open] .qrow__anssum { margin-bottom: var(--gap-3); }
.qrow__ansbody { border-left: 3px solid var(--line-strong); padding-left: var(--gap-3); }
.qrow__ansrow { display: flex; align-items: flex-start; gap: var(--gap-3); }
.qrow__ansrow + .qrow__ansrow { margin-top: var(--gap-3); }
/* 栏目名定宽：两行正文左边缘对齐，不会因为「答案」比「解析」窄而错开 */
.qrow__ansrow > .qrow__k { flex: none; width: 2.2em; padding-top: 2px; }
.qrow__ansex {
  flex: 1; min-width: 0;
  font-size: var(--fs-sm); color: var(--text-2);
  line-height: 1.85; word-break: break-word;
}
.qrow__ansex .katex { font-size: .95em; }
/* 卡片里就地展开的「答案与解析」：答案用珊瑚橙高亮（全卡唯一确定值，眼睛第一眼落下），
   解析用冷青块，和答案在色相上分开（暖橙 = 答案，冷青 = 解析思路）。
   步骤保持中性灰，不上色 —— 答案已经占了暖色重点，再加就两个重点了。 */
.qrow__ansex--answer {
  color: var(--accent-ink); font-weight: 600;
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  padding: 6px 10px; border-radius: var(--radius-sm);
}
.qrow__ansex--steps { color: var(--text-2); }
.qrow__ansex--sol {
  color: var(--cool-ink);
  background: var(--cool-soft);
  border-left: 3px solid var(--cool-line);
  padding: 6px 10px; border-radius: var(--radius-sm);
}
/* 知识点可能一题多个，允许这格换行，别挤在一行把 meta 行撑爆 */
.qrow__mi--kps { flex-wrap: wrap; }
/* ⚠️ 别做「折叠时跳过渲染」的优化：KaTeX 是在整页 renderDocument() 里遍历
   `[data-tex]` 渲染的。一旦让折叠内容不进渲染树，展开后就是一片 `$...$` 源码
   （本工程在别处踩过同族的坑）。 */

@media (max-width: 720px) {
  .qrow { padding: var(--gap-3); }
  .qrow__meta { gap: 4px var(--gap-3); }
  /* 窄屏把「答案 / 解析」的栏目名挪到正文上方，省下一列宽度 */
  .qrow__ansrow { display: block; }
  .qrow__ansrow > .qrow__k { display: block; width: auto; padding-top: 0; margin-bottom: 2px; }
}

/* 题目详情 */
.qcard {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-5);
  margin-bottom: var(--gap-4);
  box-shadow: var(--sh-1);
}
.qcard__block + .qcard__block { margin-top: var(--gap-5); padding-top: var(--gap-5); border-top: 1px solid var(--line); }
/* 小标签 + 一道主色短线：让人知道"下面是题干 / 是答案"，
   比只有一个灰色小字有指向性。 */
.qcard__label {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-3);
  letter-spacing: .06em;
  margin-bottom: var(--gap-3);
}
.qcard__label::before {
  content: "";
  width: 3px;
  height: 12px;
  border-radius: var(--radius-pill);
  background: var(--accent-line);
}
.tex { white-space: pre-wrap; word-break: break-word; }

/* 答案高亮（2026-10-08 用户要求）：全页唯一确定的值，给珊瑚橙块 + 加粗，
   眼睛第一眼落到这儿。背景走 --accent-soft，文字走 --accent-ink（浅橙底上的深字）。 */
.qans {
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  color: var(--accent-ink);
  font-weight: 600;
  line-height: 1.9;
  word-break: break-word;
}
.tex.qans .katex { color: var(--accent-ink); }

/* 解题步骤：放在答案区内部，用极淡的描边暗示「这是步骤」，不做抢眼配色。
   步骤是「怎么写」，解析才是「为什么」—— 答案占了暖橙重点，步骤保持克制。 */
.qsteps { border-left: 3px solid var(--line-strong); }
.qsteps > .tex { padding-left: var(--gap-3); line-height: 1.95; }
.qsteps--empty > .qsteps__sum { cursor: pointer; color: var(--text-3); font-size: var(--fs-sm); }
.qsteps--empty > p.empty { margin: var(--gap-3) 0 0; }

/* 解析「专门的背景框」（2026-10-08 用户要求）：用冷青 --cool 系做盒子，
   把「为什么这么想」和「答案 / 步骤」在色相上分开 —— 暖橙讲做法，冷青讲思路。
   收起时就是一条标题，展开后才是带冷青底的盒子。 */
.qsol { background: var(--cool-soft); border-color: var(--cool-line); padding: 0; }
.qsol > summary { padding: 12px 16px; color: var(--cool-ink); font-weight: 600; }
.qsol[open] > summary { border-bottom: 1px solid var(--cool-line); }
.qsol__body { padding: 14px 16px; color: var(--cool-ink); line-height: 1.95; }
.qsol__body .katex { color: var(--cool-ink); }

/* 选择题选项：横向排列（自动换行，4 个选项一行、窄屏自动折成 2 个）。
   flex-wrap + 每项的弹性宽度，比写死列数更稳 —— 题干窄时自然收成两列，不会溢出卡片。 */
/* 选项排列（2026-10-09 用户口径：短选项横排、长选项竖排）。
   变体类由 `opts_inline` 过滤器判定（与 LaTeX 导出共用同一判据，两边口径一致）：
   `.options--row` 短选项一行排开、放不下再换行；`.options--col` 长选项一行一个。 */
/* 列间距（横排时选项之间的距离）2026-10-11 由 18px 放宽到 32px：
   用户口径「选项横排不要太拥挤」—— 原来四个选项之间只隔约 1.2 个字，
   看不出哪段文字跟着哪个字母；现在约 2 个字宽，与 LaTeX 导出的 2 em 口径对齐。 */
.options { list-style: none; margin: 0; padding: 0; display: flex; gap: 6px 32px; }
.options--row { flex-wrap: wrap; }
.options--row li { flex: 0 1 auto; }
.options--col { flex-direction: column; gap: 6px; }
.options--col li { flex: 0 0 auto; }
/* 中等长度 → 两行两列（2026-10-13 用户口径「中等长度的就排列成两行两列的格局」）。
   用 grid 而不是 flex-wrap：flex 的换行由「剩余宽度够不够」决定，四个选项宽窄不一时
   会掉成 3+1 或 2+1+1，看着散；grid 两列等宽、左对齐，天然就是一个工整的 2×2。
   minmax(0, 1fr) 里的 0 不能省 —— 用 1fr 时内容（长公式）会把列撑破。 */
.options--grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 24px; }
.options--grid li { flex: 0 1 auto; }
/* 窄屏两列会挤，直接塌成一列 */
@media (max-width: 560px) {
  .options--grid { grid-template-columns: 1fr; }
}
.options li { display: flex; gap: 6px; min-width: 0; align-items: baseline; }
.options__key { font-weight: 600; color: var(--accent-hover); min-width: 1.2em; flex: none; }
/* 题库列表卡里的选项：贴在题干下面，比详情页更紧凑一点 */
.options--inrow { margin-top: 6px; font-size: var(--fs-md); gap: 4px 28px; color: var(--text-2); }

.meta { display: grid; grid-template-columns: 90px 1fr; gap: 10px var(--gap-4); margin: 0; font-size: var(--fs-md); }
.meta dt { color: var(--text-3); }
.meta dd { margin: 0; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

/* 表单分区 */
.formsec {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-5);
  margin-bottom: var(--gap-5);
  box-shadow: var(--sh-1);
}
.formsec__title { font-size: var(--fs-lg); font-weight: 600; margin-bottom: var(--gap-4); padding-bottom: var(--gap-3); border-bottom: 1px solid var(--line); }

.grid { display: grid; gap: var(--gap-4); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

.chipbox {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-2);
  max-height: 220px;
  overflow-y: auto;
  padding: var(--gap-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.chip { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-sm); cursor: pointer; }
.chip input { width: auto; margin: 0; }

/* 知识点按板块分组（2026-10-07）：每个大类一个标题 + 一块 chipbox */
.kpg { margin-bottom: var(--gap-3); }
.kpg__head {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--accent);
  margin-bottom: 6px;
}
.kpg .chipbox { max-height: 160px; }
/* 自定义新增知识点：输入框 + 大类下拉并排 */
.kpg__new { display: flex; gap: var(--gap-2); align-items: center; }
.kpg__new input { flex: 1; }
.kpg__new select { width: 100px; flex: none; }

.formactions { display: flex; gap: var(--gap-3); align-items: center; }

/* 由 KaTeX 接管后，源码文本不再直接展示 */
.tex.is-typeset { white-space: normal; }

/* ---------- 6. 深色模式 ----------
   深色不是把亮色取反：背景要够深（否则发灰显脏），
   层次靠"越靠前越亮"（bg < surface < surface-2），描边比亮色模式更弱。 */
@media (prefers-color-scheme: dark) {
  :root {
    /* 暗色主色往珊瑚橙提亮（更鲜），冷色松石青同步提亮 */
    --accent: #ff8a63;
    --accent-hover: #ffa98b;
    --accent-hi: #ff9d7a;
    --accent-soft: #3d2318;
    --accent-line: #6e3b28;
    --accent-ink: #ffd6c4;
    --on-solid: #2a120a;          /* 深色下实心色偏亮，白字糊，改深字 */
    --accent-2: #ffc07a;

    --cool: #5bd0df;
    --cool-hover: #8ce3ee;
    --cool-soft: #10282c;
    --cool-line: #1f4d54;
    --cool-ink: #bfeef3;

    --danger: #f09a95;
    --danger-soft: #3a1c1a;
    --danger-line: #66302b;
    --warn: #e9ad4e;
    --warn-soft: #362a15;
    --warn-line: #63491c;
    --ok: #9aca6a;
    --ok-soft: #1e2d16;
    --ok-line: #3b5527;

    --bg: #16110e;
    --surface: #1e1611;
    --surface-2: #28201a;
    --surface-3: #332922;
    --text: #f2ebe4;
    --text-2: #b6a99d;
    --text-3: #8a7b6e;
    --line: #2c231c;
    --line-strong: #3d3229;

    --star: #e8a33d;

    /* 深色下阴影几乎看不见，改用"更暗"来体现抬升 */
    --sh-1: 0 1px 2px rgba(0, 0, 0, .35);
    --sh-2: 0 2px 8px rgba(0, 0, 0, .42);
    --sh-3: 0 12px 32px rgba(0, 0, 0, .55);
    --shadow: var(--sh-1);
  }

  /* 深色模式下 logo 是**唯一一块亮面**，靠一点深色把它压回页面上，
     否则会像浮在最顶上。注意：logo 已换成内联 SVG（不再有 inset 缓存的那种色块），
     所以这里只能用外阴影 —— inset 打在 <svg> 上是看不见的。 */
  .brand__mark {
    box-shadow: 0 1px 3px rgba(0, 0, 0, .45),
                0 3px 10px rgba(0, 0, 0, .34);
  }
  .empty { background: var(--surface-2); }
  .empty::before { background-color: var(--accent-soft); }
  .table thead th { background: var(--surface-2); }
}

/* 尊重"减少动态效果"的系统偏好 —— 前庭敏感的用户会被动效伤到 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .stat:hover { transform: none; }
}

/* ---------- 7. 移动端 ---------- */
@media (max-width: 720px) {
  .wrap { padding: var(--gap-5) var(--gap-4); }
  .topbar__inner { padding: 0 var(--gap-4); gap: var(--gap-3); }
  .who__name { display: none; }
  /* 窄屏顶栏只留「退出」：名字已经收起来了，再摆一个「改密码」会把题篮挤掉。
     改密码在窄屏走「更多」不划算 —— 直接藏掉，桌面端有的是入口。 */
  .who__pwd { display: none; }
  .page__head { flex-direction: column; }
  /* 筛选条是 grid 了，这里只把列数收紧（宽表单一列最不容易填错） */
  .filters { grid-template-columns: 1fr; }
  .filters .field { min-width: 0; }
  .recent__time { display: none; }
  .meta { grid-template-columns: 1fr; gap: 2px; }
  .meta dt { margin-top: var(--gap-2); }
}
/* 561～720 之间：两列，别挤成一列 */
@media (min-width: 561px) and (max-width: 720px) {
  .filters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---------- 7b. 顶栏改两行（平板与手机都落在这里） ----------
   一行排不下「品牌 + 导航项 + 题篮 + 用户」，而导航项又不能收缩
   （收缩就变「题/库」两行）。所以把导航整条挪到第二行，第二行再放不下就横向滑动
   —— 比塞一个需要 JS 的汉堡菜单稳，也不影响无障碍。
   放在 720px 那段**之后**：两段都命中时以后者为准，否则 720 会把纵向内边距清零。

   🔴 断点 = **内容最大宽度 --wrap**（2026-10-11 由 1120 提到 1440：页面加宽了，
      断点必须跟着走，否则 1121~1440 这一段又会冒出「导航条比内容短」的老毛病）。
      用户当时报的 bug：「手机上把屏幕缩小后，最上面的导航栏比下面的题目短」。
      根因：断点以下那一段走**单行**布局，导航项排成一条跟内容等宽的**短条**，
      而内容占满整宽 —— 平板横屏正是这个区间。
      所以：≤ --wrap 时导航独占一整行、与内容等宽；
      > --wrap 时内容与顶栏都锁在居中的同一个盒子里，左边缘自然对齐。
      守：responsive_test 里「导航条右缘不得短于内容右缘」那条。 */
@media (max-width: 1440px) {
  .topbar__inner {
    height: auto;
    min-height: var(--topbar-h);
    flex-wrap: wrap;
    row-gap: var(--gap-1);
    /* 🔴 左右内边距必须与 .wrap 完全一致（这里 .wrap 是 24px）——
       不然顶栏内容会比正文多出/少掉 8px，一眼看着就是「顶栏跟正文没对齐」。 */
    padding: var(--gap-2) var(--gap-5);
  }
  /* 导航被挪走后，靠品牌把右侧的题篮/用户顶到最右边 */
  .brand { margin-right: auto; }
  .nav {
    order: 3;              /* DOM 里导航在中间，靠 order 移到末位 → 独占第二行 */
    width: 100%;
    margin-right: 0;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;  /* 滑动条本身不显示，但依然能滑 */
  }
  .nav::-webkit-scrollbar { display: none; }
  /* 🔴 导航项均摊满整行（用户报的「导航栏比下面的题目短」就在这里）。
     导航项自身宽度固定（7~11 项合计约 700px），光给容器 width:100% 是没用的
     —— 链接仍是挤在左边的一小撮，1024px 时只到内容的 70%。
     只有 ≥3 项时才均摊：学生只有「题库 / 目录」两项，把两项拉到整行两端反而是坏的。 */
  .nav:has(a:nth-child(3)) { justify-content: space-between; }
}
/* 手机：正文自己也是 16px 内边距，顶栏跟着回到 16px（放在 1120 那段之后才生效） */
@media (max-width: 720px) {
  .topbar__inner { padding: var(--gap-2) var(--gap-4); }
}

/* ---------- 公式渲染（KaTeX） ---------- */
.tex { line-height: 1.95; overflow-wrap: break-word; }
.tex .katex { font-size: 1.06em; }
.tex .katex-display {
  margin: .55em 0;
  padding: 2px 0;
  /* 长公式（多行对齐、矩阵）在窄屏上要能横向滚，别把布局撑破 */
  overflow-x: auto;
  overflow-y: hidden;
}
.qcard__block > .tex > .katex-display:first-child { margin-top: 0; }
.qcard__block > .tex > .katex-display:last-child { margin-bottom: 0; }
.tex--pad { padding-top: var(--gap-4); }

/* ---------- 录题页：左边写源码，右边即时看效果 ---------- */
.writing {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--gap-3);
}
.writing__side {
  min-height: 92px;
  padding: var(--gap-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.writing__head {
  margin-bottom: var(--gap-2);
  font-size: .76rem;
  color: var(--text-3);
  letter-spacing: .04em;
}
.writing__body { font-size: .98rem; }
.writing__body.is-empty { color: var(--text-3); }
.writing__warn { margin: var(--gap-2) 0 0; font-size: .8rem; color: var(--danger); }
@media (max-width: 900px) { .writing { grid-template-columns: 1fr; } }

/* ---------- LaTeX 常用写法速查 ---------- */
.cheatsheet { margin: var(--gap-3) 0 var(--gap-4); }
.cheatsheet > summary { cursor: pointer; font-size: .9rem; color: var(--accent); }
.cheatsheet__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
  gap: var(--gap-2);
  margin-top: var(--gap-3);
}
.snippet {
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-items: flex-start;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
  text-align: left;
  font: inherit;
}
.snippet:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.snippet code { font-family: var(--font-mono); font-size: .78rem; color: var(--text); }
.snippet span { font-size: .74rem; color: var(--text-3); }

/* ---------- 相似题 ---------- */
.simlist { display: grid; }
.simlist__item {
  display: flex;
  gap: var(--gap-3);
  align-items: baseline;
  padding: 10px 0;
  border-top: 1px solid var(--line);
  color: inherit;
  text-decoration: none;
}
.simlist__item:first-child { border-top: 0; }
.simlist__item:hover .simlist__stem { color: var(--accent); }
.simlist__stem { min-width: 0; flex: 1; font-size: .95rem; }
.stars--sm { flex: none; font-size: .8rem; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ---------- 8. 批量导入 ---------- */

/* 通用信息卡片（与题目详情页的 .qcard 区分开，别抢那个名字） */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-5);
  margin-bottom: var(--gap-5);
}
.card__title {
  font-size: 15px;
  margin-bottom: var(--gap-4);
  padding-bottom: var(--gap-3);
  border-bottom: 1px solid var(--line);
}
.card--result { border-color: var(--accent-line); }

.stack { display: flex; flex-direction: column; gap: var(--gap-4); }
.stack .field { margin-bottom: 0; }
.stack .btn { align-self: flex-start; }

.muted { color: var(--text-2); }

.steps { margin: 0; padding-left: 1.4em; display: flex; flex-direction: column; gap: var(--gap-2); }
.steps li::marker { color: var(--accent); font-weight: 600; }

.alert--warn { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }
.alert--tip { background: var(--surface-2); border-color: var(--line-strong); color: var(--text-2); }
.alert--tip b { color: var(--text); }

.table--compact th, .table--compact td { padding: 8px 12px; }
.ok-cell { color: var(--ok); }
.warn-cell { color: var(--warn); }
.bad-cell { color: var(--danger); }

.tag--kind {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent-hover);
  font-family: var(--font-mono);
}

/* 导入信息条 */
.importbar {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  flex-wrap: wrap;
  margin-bottom: var(--gap-4);
  font-size: 14px;
}
.importbar__file { font-weight: 500; word-break: break-all; }

/* 工具栏 */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-3) var(--gap-4);
  margin-bottom: var(--gap-4);
}
.toolbar__group { display: flex; align-items: center; gap: var(--gap-2); }
.toolbar__group label { font-size: 13px; color: var(--text-3); white-space: nowrap; }
.toolbar__group select { width: auto; min-width: 132px; }
.toolbar__group--right { margin-left: auto; }

/* 校验卡片列表 */
.qlist { display: flex; flex-direction: column; gap: var(--gap-4); }

.icard {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-4);
}
/* 正在编辑哪一张一眼看得出来 */
.icard:focus-within { border-color: var(--accent-line); }

.icard__head {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  flex-wrap: wrap;
  padding-bottom: var(--gap-3);
  margin-bottom: var(--gap-4);
  border-bottom: 1px solid var(--line);
}
.icard__pick { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; cursor: pointer; }
.icard__pick input { width: auto; margin: 0; }
.icard__no { font-family: var(--font-mono); font-size: 13px; color: var(--text-2); }
.icard__sec {
  font-size: 12.5px;
  color: var(--text-3);
  background: var(--surface-2);
  border-radius: 999px;
  padding: 1px 10px;
}
.icard__spacer { flex: 1; }

/* 卡片上的质检徽章 */
.icard__qc {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: calc(-1 * var(--gap-2)) 0 var(--gap-4);
}
.qcflag {
  font-size: 12px;
  line-height: 1.5;
  padding: 1px 9px;
  border-radius: 999px;
  border: 1px solid transparent;
  cursor: help;
}
.qcflag--blocker {
  background: color-mix(in srgb, var(--danger) 14%, var(--surface));
  border-color: color-mix(in srgb, var(--danger) 40%, var(--surface));
  color: var(--danger);
}
.qcflag--warning {
  background: var(--warn-soft);
  border-color: var(--warn-line);
  color: var(--warn);
}

/* 校对页顶部的质检汇总条 */
.qcbar {
  margin: 0 0 var(--gap-4);
  padding: 10px var(--gap-4);
  border-radius: var(--radius-sm);
  font-size: 13.5px;
  line-height: 1.7;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text-2);
}
.qcbar--warn { background: var(--warn-soft); border-color: var(--warn-line); color: var(--text); }
.qcbar--ok { background: color-mix(in srgb, var(--ok) 12%, var(--surface)); border-color: color-mix(in srgb, var(--ok) 35%, var(--surface)); color: var(--text); }

.resultwarn {
  margin-top: var(--gap-2);
  padding: 8px var(--gap-3);
  border-radius: var(--radius-sm);
  background: var(--warn-soft);
  color: var(--text);
  font-size: 13.5px;
  line-height: 1.7;
}

.icard__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--gap-3);
  margin-bottom: var(--gap-3);
}
.icard .field { margin-bottom: var(--gap-3); }
.icard .field > span { display: block; font-size: 12.5px; color: var(--text-3); margin-bottom: 4px; }
.icard .field--full { grid-column: 1 / -1; }
.icard textarea { font-family: var(--font-mono); font-size: 13.5px; line-height: 1.6; }
.hint-inline { margin-left: 6px; color: var(--text-3); font-weight: 400; }

/* 校对页顶部：自动拾取状态条 + AI 可用性说明。
   用中性底（--surface-2）而不是主色底 —— 它和下面的质检汇总条（qcbar）
   是两条相邻的提示，都染成彩色会互相抢，看不出哪条更要紧。 */
.pickbar {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--gap-2) var(--gap-4);
  margin: 0 0 var(--gap-4);
  padding: 10px var(--gap-4);
  border-radius: var(--radius-sm);
  font-size: 13.5px;
  line-height: 1.7;
  background: var(--surface-2);
  border: 1px solid var(--line);
}
.pickbar__txt { flex: 1 1 24ch; min-width: 0; }
.pickbar__off {
  color: var(--warn);
  font-size: 12.5px;
  cursor: help;
  border-bottom: 1px dashed currentColor;
}

/* 卡片上的拾取结果：AI 建议一行（要人点采纳）、规则依据折起来备查 */
.icard__pick {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: calc(-1 * var(--gap-2)) 0 var(--gap-4);
}
.pickrow { font-size: 12.5px; line-height: 1.6; }
.pickrow--ai {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-2);
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  color: var(--accent-ink);
}
.pickrow__txt { flex: 1 1 18ch; min-width: 0; }
.pickrow--rule > summary {
  cursor: pointer;
  color: var(--text-3);
  width: fit-content;
}
.pickchips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 5px;
}
.pickchip {
  padding: 1px 9px;
  border-radius: 999px;
  font-size: 12px;
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
}
.pickchip { cursor: help; }
.btn--ai { border-color: var(--accent-line); }
.js-adopt.is-adopted { opacity: .55; }

/* 入库结果 */
.resultcodes { font-family: var(--font-mono); font-size: 13px; word-break: break-all; }
.errlist {
  margin: var(--gap-3) 0;
  padding-left: 1.3em;
  color: var(--danger);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.errline { color: var(--danger); }
.resultacts { display: flex; gap: var(--gap-3); margin-top: var(--gap-4); }

.commitbar { margin: var(--gap-5) 0; display: flex; justify-content: flex-end; gap: var(--gap-3); }

/* 原文对照 */
.rawbox { margin: var(--gap-5) 0; }
.rawbox summary { cursor: pointer; color: var(--text-2); font-size: 14px; padding: var(--gap-2) 0; }
.rawpre {
  max-height: 420px;
  overflow: auto;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--gap-4);
  font-family: var(--font-mono);
  font-size: 12.5px;
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--text-2);
}

.discardbar {
  margin: var(--gap-6) 0 var(--gap-5);
  padding-top: var(--gap-5);
  border-top: 1px dashed var(--line);
}

/* ---------- 9. 学段切换器 / 目录页签 / 目录树 ---------- */
/* 这三块是 PRD 里「分类是数据」的界面体现，全部只吃 CSS 变量，
   所以深色模式不用额外写覆盖。 */

/* 学段切换器：整站一级维度。做成分段控件而不是下拉，
   因为只有 2 个选项 —— 一眼看得见、点一下就切，比展开下拉快。 */
.segmented {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  margin-bottom: var(--gap-4);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
}
.segmented__item {
  padding: 6px 18px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 500;
  color: var(--text-2);
}
.segmented__item:hover { background: var(--surface); color: var(--text); text-decoration: none; }
.segmented__item.is-active {
  background: var(--accent);
  color: var(--on-solid);
  box-shadow: var(--shadow);
}

/* 目录页签：切换分类体系时「不清条件」（PRD FR-3.4），
   所以它是链接而不是表单控件 —— 点一下带着现有条件换棵树。 */
.tabs {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--gap-1);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--gap-4);
}
.tabs__item {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 10px 14px;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  color: var(--text-2);
  font-size: var(--fs-md);
  font-weight: 500;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.tabs__item:hover { color: var(--text); text-decoration: none; }
.tabs__item.is-active { color: var(--accent-hover); border-bottom-color: var(--accent); font-weight: 600; }
.tabs__note { font-size: var(--fs-xs); color: var(--text-3); font-weight: 400; }
.tabs__manage { margin-left: auto; font-size: var(--fs-sm); color: var(--text-3); padding: 9px 4px; }

/* 生效中的条件 */
.chips { display: flex; flex-wrap: wrap; gap: var(--gap-2); margin-bottom: var(--gap-3); }

/* 复选框型筛选项（紧凑模式） */
.field--check { justify-content: flex-end; min-width: 0; }
.field--check label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 0;
  white-space: nowrap;
}
.field--check input { width: auto; margin: 0; }

/* 筛选条里的勾选框（如「只看待反馈」）与相邻下拉**对齐**（2026-10-13 用户报）。
   🔴 真症结：模板里它是 `<label class="field field--check">` —— 这一个元素**同时**
      是 .field（`display:flex; flex-direction:column`）又是 .field--check。
      于是勾选框和文字被当成**纵向两行**摆开：勾选框在上、文字在下，
      看起来就是「选框和文字没对齐」。
      修法：把这一格改成**横向一行 + 垂直居中**，再给它和下拉控件等高（38px），
      中线就与旁边的下拉对齐了。 */
.filters .field--check {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  min-height: 38px;
}
.filters .field--check input { flex: 0 0 auto; }
/* 页脚行（题库页）里的勾选框本就与按钮同排，保留横向即可 */
.filters__foot .field--check { min-height: 0; }

/* 记一次课页里的「这次课后作业另发 PDF」勾选行（2026-10-13 需求⑥ 收尾）。
   与 textarea 紧邻，要**贴着它**（不像筛选条那样要跟下拉等高），所以：
   横向一行、垂直居中、字色略淡 —— 它是辅助开关，不该抢正文的注意力。 */
.checkline {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: var(--gap-3);
  cursor: pointer;
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.55;
}
.checkline input {
  flex: 0 0 auto;
  width: auto;
  /* 与首行文字的中线对齐（文字行高 1.55 ⇒ 约 0.42em 的位置最稳） */
  margin: 2px 0 0;
}
.checkline:hover { color: var(--text); }
.checkline input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.checkline:has(input:checked) { color: var(--accent-ink); }

/* 目录树：用嵌套 ul 表达层级。缩进靠 padding-left，
   左侧那条竖线让「这是第几层」一眼可辨。 */
.tree { list-style: none; margin: 0; padding: 0; }
.tree .tree { padding-left: 18px; border-left: 1px dashed var(--line-strong); margin-left: 6px; }
.tree__item { padding: 1px 0; }
.tree__row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--gap-2);
  padding: 5px 8px;
  border-radius: var(--radius-sm);
  transition: background var(--dur) var(--ease);
}
.tree__row:hover { background: var(--surface-2); }
.tree__name { font-size: var(--fs-md); }
.tree__item--l1 > .tree__row .tree__name { font-weight: 650; }
.tree__code {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-3);
  margin-right: 4px;
  padding: 0 4px;
  border-radius: 4px;
  background: var(--surface-2);
}
.tree__intro { font-size: var(--fs-xs); color: var(--text-3); }

/* 学校字典：按分组排成多列卡片 */
.schoolgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--gap-5);
}
.schoolgroup__title {
  font-size: 14px;
  color: var(--text-2);
  padding-bottom: var(--gap-2);
  margin-bottom: var(--gap-2);
  border-bottom: 1px solid var(--line);
}
.schoolgroup__list { list-style: none; margin: 0; padding: 0; }
.schoolitem { padding: 3px 0; font-size: 14px; }
.schoolitem__kids {
  list-style: none;
  margin: 2px 0 2px 0;
  padding-left: 14px;
  border-left: 1px dashed var(--line-strong);
  color: var(--text-2);
  font-size: 13.5px;
}
.schoolitem__kids li { padding: 2px 0; }

/* 目录页标题上的版本号 */
.page__note { font-size: 13px; font-weight: 400; color: var(--text-3); }

/* 分类列：路径较长，允许换行，并给个下限宽度避免被挤成一条 */
.cell-cat { min-width: 200px; color: var(--text-2); font-size: 13px; }

/* 质检 / 质量状态用到的标签配色 */
.tag--danger { background: var(--danger-soft); border-color: var(--danger-line); color: var(--danger); }
.tag--warn { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }
.tag--q-flagged { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }
.tag--q-reviewed { background: var(--ok-soft); border-color: var(--accent-line); color: var(--ok); }

@media (max-width: 720px) {
  .segmented { width: 100%; justify-content: space-between; }
  .segmented__item { flex: 1; text-align: center; padding: 6px 10px; }
  .tabs__manage { margin-left: 0; }
  .cell-cat { min-width: 0; }
}


/* ============================================================
   第 10 节 · 录题表单的五要素区与详情页信息条
   ------------------------------------------------------------
   这一节只服务两件事：
     · 录题时「主分类」要能在几套目录里各选一个、并指定哪一个是主 ——
       每套目录一行，行首是单选钮，行内是节点下拉；
     · 详情页顶部那一行「学段 · 难度 · 主分类 · 题型 · 学校 · 日期」，
       出卷前扫一眼就知道这道题的属性齐不齐。
   ============================================================ */

/* 学段切换器与提示并排：切换会重载页面，提示必须紧挨着它 */
.stagebar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--gap-2) var(--gap-4);
  margin-bottom: var(--gap-5);
}
.stagebar .segmented { margin-bottom: 0; }
.stagebar__hint { margin: 0; font-size: 12.5px; color: var(--text-3); }

/* 表单小节标题右侧的补充说明 */
.formsec__note {
  font-size: 12px;
  font-weight: 400;
  color: var(--text-3);
  margin-left: var(--gap-2);
}

/* 校验失败时的多条错误：一条一行，一眼看全缺什么 */
.alert__list { margin: var(--gap-2) 0 0; padding-left: 1.2em; }
.alert__list li { margin-top: 3px; }

/* 主分类：一套目录一行 */
.nodegrid {
  display: grid;
  gap: var(--gap-2);
  margin-top: var(--gap-2);
}
.nodegrid__row {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: var(--gap-3);
  align-items: center;
  padding: var(--gap-3);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.nodegrid__pick {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-2);
  cursor: pointer;
  white-space: nowrap;
}
/* 勾中「主分类」的那一行整行高亮 —— 选完目录后最容易忘了指定主分类 */
.nodegrid__row:has(.nodegrid__pick input:checked) {
  background: var(--accent-soft);
  border-color: var(--accent-line);
}
.nodegrid__row:has(.nodegrid__pick input:checked) .nodegrid__pick { color: var(--accent-hover); }
.nodegrid__pick input { width: auto; margin: 0; }
.nodegrid__body { min-width: 0; }
.nodegrid__title { font-size: 13px; color: var(--text-2); margin-bottom: 5px; }
.nodegrid__body select { width: 100%; }

@media (max-width: 640px) {
  .nodegrid__row { grid-template-columns: 1fr; }
}

/* 详情页的五要素信息条 */
.propbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px var(--gap-2);
}
.propbar__sep { color: var(--text-3); }
.tag--stage { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-hover); }
.tag--quality-flagged { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }
.tag--quality-reviewed { background: var(--ok-soft); border-color: var(--accent-line); color: var(--ok); }

/* 详情页：这道题挂在哪几套目录下 */
.catlist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--gap-2); }
.catlist__item {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--gap-2);
  font-size: 14px;
}
.catlist__kind {
  flex: 0 0 76px;
  font-size: 12.5px;
  color: var(--text-3);
}
.catlist__badge {
  font-size: 11.5px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-solid);
}
.catlist__path { color: var(--text-2); }
.catlist__link { margin-left: auto; font-size: 13px; color: var(--text-3); }

/* ---------- 11. 题篮（顶部入口 / 右侧抽屉 / 管理页 / 列表页批量条） ---------- */

/* 顶部入口按钮：和导航、用户名并排，角标是「所有篮子加起来几道」。
   尺寸刻意收小（之前偏大，中屏会把「批量导入 / 运维」这些相邻项挤到重叠），
   中屏只留图标 + 角标，长名字截断，避免顶栏一行放不下时互相遮住。 */
.cartbtn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
  padding: 4px 9px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-2);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.cartbtn:hover { background: var(--surface-2); color: var(--text); }
.cartbtn__icon { width: 16px; height: 16px; flex: none; }
.cartbtn__badge {
  min-width: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-solid);
  font-size: 11.5px;
  line-height: 18px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
/* 0 道时角标淡出，但**不隐藏** —— 位置固定，不会因为有没有数字让按钮左右跳 */
.cartbtn__badge.is-zero { background: var(--surface-2); color: var(--text-3); }
html.has-drawer, body.has-drawer { overflow: hidden; }

/* 右侧抽屉 */
.drawer { position: fixed; inset: 0; z-index: 60; }
.drawer[hidden] { display: none; }
.drawer__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(12, 18, 15, .42);
  animation: qbFade .16s ease-out;
}
.drawer__panel {
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: min(420px, 92vw);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--line-strong);
  box-shadow: -8px 0 28px rgba(16, 24, 20, .14);
  animation: qbSlideIn .2s ease-out;
}
@keyframes qbFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes qbSlideIn { from { transform: translateX(14px); opacity: .6; } to { transform: none; opacity: 1; } }

.drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-3);
  padding: var(--gap-4) var(--gap-5);
  border-bottom: 1px solid var(--line);
}
.drawer__title { font-size: 16px; margin: 0; }
.drawer__x {
  border: 0;
  background: none;
  font-size: 22px;
  line-height: 1;
  padding: 2px 8px;
  border-radius: var(--radius-sm);
  color: var(--text-3);
  cursor: pointer;
}
.drawer__x:hover { background: var(--surface-2); color: var(--text); }
.drawer__body { flex: 1; overflow-y: auto; padding: var(--gap-4) var(--gap-5); }
.drawer__loading { color: var(--text-3); font-size: 14px; }
.drawer__foot {
  display: flex;
  justify-content: space-between;
  gap: var(--gap-2);
  padding: var(--gap-3) var(--gap-5);
  border-top: 1px solid var(--line);
}
/* 「去组卷」改成了表单（POST 直达新建卷），去掉 form 自带的 margin，
   让它和旁边的「管理题篮」链接在 flex 里对齐。 */
.drawer__gopaper { margin: 0; display: flex; }

/* 导出抽屉里的字段 */
.expfield { margin-bottom: var(--gap-4); }
.expfield__label { display: block; font-size: 13px; color: var(--text-2); margin-bottom: 6px; }
.expfield__hint { margin: 6px 0 0; font-size: 12px; color: var(--text-3); line-height: 1.5; }
.expfield--split { display: flex; gap: var(--gap-3); }
.expfield--split > div { flex: 1; }
.expfield--split .expfield__label { margin-bottom: 6px; }
.expfield__row { display: flex; align-items: center; gap: var(--gap-2); margin-bottom: var(--gap-2); }
.expfield__row:last-child { margin-bottom: 0; }
.expfield__rowlabel { flex: none; font-size: 13px; color: var(--text-2); width: 32px; }
.expfield__row .segmented { flex: 1; }
.expfield--check { margin-bottom: var(--gap-3); }
.expfield__check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text); cursor: pointer; }
.expfield__check input { width: 16px; height: 16px; accent-color: var(--accent); }

/* 导出生成状态条 */
.expstatus {
  margin: var(--gap-2) 0 var(--gap-4);
  padding: 10px var(--gap-3);
  border-radius: var(--radius-sm);
  font-size: 13px;
  background: var(--surface-2);
  color: var(--text-2);
}
.expstatus--busy { background: color-mix(in srgb, var(--accent) 12%, var(--surface)); color: var(--text); }
.expstatus--ok { background: color-mix(in srgb, var(--ok) 16%, var(--surface)); color: var(--text); }
.expstatus--fail { background: color-mix(in srgb, var(--warn) 16%, var(--surface)); color: var(--text); }
.expstatus a { font-weight: 600; }

/* 导出预览图 */
.exppreview { margin: var(--gap-3) 0; border: 1px solid var(--line); border-radius: 8px; padding: var(--gap-3); background: var(--surface-2); }
.exppreview__head { display: flex; align-items: center; justify-content: space-between; gap: var(--gap-2); margin-bottom: var(--gap-2); flex-wrap: wrap; }
.exppreview__head .board__subtitle { margin: 0; }
.exppreview__ops { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.exppreview__img { display: block; width: 100%; height: auto; max-height: 60vh; object-fit: contain; background: #fff; border-radius: 4px; box-shadow: 0 1px 4px rgba(0,0,0,.08); cursor: zoom-in; }
.exppreview__hint { margin: 6px 0 0; font-size: 12px; color: var(--text-3); }

/* ---- 全屏预览查看器（灯箱）：图上全屏居中，可翻页看每一页 ---- */
.lightbox { position: fixed; inset: 0; z-index: 90; display: flex; flex-direction: column; }
.lightbox[hidden] { display: none; }
.lightbox__backdrop { position: absolute; inset: 0; background: rgba(10, 14, 12, .78); animation: qbFade .16s ease-out; }
.lightbox__stage {
  position: relative; flex: 1; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  padding: var(--gap-4);
}
.lightbox__img {
  max-width: min(1100px, 94vw); max-height: 100%; width: auto; height: auto;
  background: #fff; border-radius: 6px; box-shadow: 0 12px 44px rgba(0,0,0,.45);
  object-fit: contain;
}
.lightbox__loading {
  position: absolute; color: #fff; font-size: 14px;
  background: rgba(0,0,0,.55); padding: 8px 18px; border-radius: 999px;
}
.lightbox__loading[hidden] { display: none; }
.lightbox__bar {
  position: relative; display: flex; align-items: center; justify-content: center;
  gap: var(--gap-3); padding: var(--gap-3) var(--gap-4);
  padding-bottom: calc(var(--gap-3) + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(to top, rgba(10,14,12,.72), rgba(10,14,12,0));
}
.lightbox__pos { color: #fff; font-size: 14px; min-width: 96px; text-align: center; }
.lightbox__pos b { font-size: 16px; }
.lightbox__btn {
  appearance: none; border: 1px solid rgba(255,255,255,.3); background: rgba(255,255,255,.12);
  color: #fff; font-size: 14px; padding: 8px 16px; border-radius: 999px; cursor: pointer;
  line-height: 1.2;
}
.lightbox__btn:hover:not(:disabled) { background: rgba(255,255,255,.24); }
.lightbox__btn:disabled { opacity: .32; cursor: default; }
.lightbox__btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.lightbox__close {
  position: absolute; top: var(--gap-4); right: var(--gap-4); z-index: 1;
  width: 40px; height: 40px; padding: 0; font-size: 22px; line-height: 1;
}
@media (max-width: 640px) {
  .lightbox__img { max-width: 96vw; }
  .lightbox__btn { padding: 8px 12px; font-size: 13px; }
  .lightbox__pos { min-width: 72px; }
}

/* 课后作业的全屏预览（2026-10-22）：同一个灯箱放进 <dialog> 里用 ——
   它要盖在 `#hw-view` 那个 dialog 之上，而 modal dialog 在 top layer，
   普通 div 的 z-index 再大也压不住。所以只补「当 dialog 用时」的尺寸复位。 */
.lightbox--dlg {
  position: fixed; inset: 0;
  width: 100vw; height: 100dvh;
  max-width: none; max-height: none;
  margin: 0; padding: 0; border: 0; background: transparent;
}
/* 🔴 与 `.hwpick:not([open])` 同一条坑：上面 `.lightbox{display:flex}` 是 author 规则，
   权重压得过 UA 的 `dialog:not([open]){display:none}` —— 不补这条，关掉后灯箱会
   一直以内联的方式摊在页面上。 */
.lightbox--dlg:not([open]) { display: none; }
.lightbox--dlg::backdrop { background: transparent; }

/* 导出历史列表 */
.explist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--gap-2); }
.explist__empty { color: var(--text-3); font-size: 13px; }
.explist__item {
  display: flex; align-items: center; justify-content: space-between; gap: var(--gap-2);
  padding: var(--gap-2) var(--gap-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 13px;
}
.explist__meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.explist__name { font-weight: 500; }
.explist__sub { color: var(--text-3); font-size: 12px; }
.explist__state { flex: none; font-size: 12px; padding: 2px 8px; border-radius: 999px; }
.explist__state--done { background: color-mix(in srgb, var(--ok) 18%, var(--surface)); color: var(--text); }
.explist__state--busy { background: var(--surface-2); color: var(--text-2); }
.explist__state--failed { background: color-mix(in srgb, var(--warn) 18%, var(--surface)); color: var(--text); }
.explist__dl { flex: none; font-size: 12px; font-weight: 600; color: var(--accent); text-decoration: none; }
.explist__dl:hover { text-decoration: underline; }
.explist__dl[aria-disabled="true"] { color: var(--text-3); pointer-events: none; }

/* 抽屉里的篮子切换 */
.cartpane__top { display: flex; align-items: center; gap: var(--gap-2); margin-bottom: var(--gap-3); }
.cartpane__label { font-size: 13px; color: var(--text-2); flex: none; }
.cartpane__pick { flex: 1; min-width: 0; }

/* 篮子里的条目 */
.cartlist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--gap-2); }
.cartlist__item {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-2);
  padding: var(--gap-2) var(--gap-2) var(--gap-2) 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.cartlist__item:hover { border-color: var(--line-strong); }
.cartlist__item.is-dragging { opacity: .5; border-style: dashed; }
.cartlist__no {
  flex: none;
  width: 30px;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  cursor: grab;
  border-right: 1px solid var(--line);
  /* 整条都当拖拽把手，比只抓数字好点中 */
  background: var(--surface-2);
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
}
.cartlist__item.is-dragging .cartlist__no { cursor: grabbing; }
.cartlist__main { flex: 1; min-width: 0; display: grid; gap: 3px; }
.cartlist__stem {
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--text);
  /* 2026-10-14 #367：题干自己成了进详情页的链接，别让浏览器加下划线。 */
  text-decoration: none;
  /* 摘要两行封顶：长题干不在这里读 */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.cartlist__stem:hover { color: var(--accent); }
.cartlist__meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: 12px; }
.cartlist__cat {
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 190px;
}
.cartlist__ops { display: flex; flex-direction: column; gap: 2px; }
.cartlist__move, .cartlist__del {
  border: 0;
  background: none;
  padding: 2px 7px;
  border-radius: var(--radius-sm);
  color: var(--text-3);
  font-size: 13px;
  line-height: 1.4;
  cursor: pointer;
}
.cartlist__move:hover { background: var(--surface-2); color: var(--text); }
.cartlist__del { font-size: 17px; }
.cartlist__del:hover { background: var(--danger-soft); color: var(--danger); }
.cartlist__hint { margin-top: var(--gap-3); font-size: 12.5px; color: var(--text-3); }

.cartempty { padding: var(--gap-5) 0; text-align: center; }
.cartempty__title { font-size: 15px; color: var(--text); margin-bottom: 6px; }
.cartempty__tip { font-size: 13.5px; color: var(--text-3); margin-bottom: var(--gap-4); line-height: 1.7; }

/* 轻提示 */
.toasts {
  position: fixed;
  left: 50%;
  bottom: 26px;
  transform: translateX(-50%);
  z-index: 70;
  display: grid;
  gap: var(--gap-2);
  justify-items: center;
  pointer-events: none;
}
.toast {
  padding: 9px 16px;
  border-radius: 999px;
  background: var(--text);
  color: var(--surface);
  font-size: 13.5px;
  box-shadow: 0 6px 20px rgba(16, 24, 20, .22);
  animation: qbToastIn .18s ease-out;
}
.toast--ok { background: var(--ok); color: var(--on-solid); }
.toast--warn { background: var(--warn); color: var(--on-solid); }
.toast.is-out { opacity: 0; transition: opacity .24s; }
@keyframes qbToastIn { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } }

/* 题篮管理页：左篮子列表 + 右明细 */
.carts { display: grid; grid-template-columns: 260px 1fr; gap: var(--gap-5); align-items: start; }
.carts__h { font-size: 15px; margin: 0 0 var(--gap-3); }
.carts__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--gap-3);
  margin-bottom: var(--gap-4);
}
.carts__ops { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap-2); }
.carts__ops form { margin: 0; }
.carts__actions { display: flex; align-items: center; gap: var(--gap-3); margin-top: var(--gap-3); }
.inlineform { display: flex; gap: var(--gap-1); }
.inlineform input { width: 140px; }
.cell-check { width: 34px; text-align: center; }
.cell-check input { width: auto; margin: 0; }

.cartchips { list-style: none; margin: 0 0 var(--gap-4); padding: 0; display: grid; gap: var(--gap-1); }
.cartchips__item { border-radius: var(--radius-sm); }
.cartchips__item.is-active { background: var(--accent-soft); }
.cartchips__link {
  display: flex;
  align-items: center;
  gap: var(--gap-2);
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 14px;
}
.cartchips__link:hover { background: var(--surface-2); text-decoration: none; }
.cartchips__item.is-active .cartchips__link:hover { background: var(--accent-soft); }
.cartchips__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cartchips__flag {
  flex: none;
  font-size: 11px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-solid);
}
.cartchips__n { flex: none; font-size: 12.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }

.cartnew { padding-top: var(--gap-3); border-top: 1px solid var(--line); }
.cartnew__label { display: block; font-size: 13px; color: var(--text-2); margin-bottom: 6px; }
.cartnew__row { display: flex; gap: var(--gap-1); }
.cartnew__row input { flex: 1; min-width: 0; }

/* 题库列表页底部的批量加入条 */
.cartbulk {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  z-index: 50;
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  padding: 10px 16px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: 0 8px 26px rgba(16, 24, 20, .18);
  font-size: 14px;
}
.cartbulk[hidden] { display: none; }
.cartbulk b { font-variant-numeric: tabular-nums; }

@media (prefers-color-scheme: dark) {
  .toast { background: var(--surface-2); color: var(--text); }
  .drawer__backdrop { background: rgba(0, 0, 0, .55); }
}

@media (max-width: 720px) {
  .carts { grid-template-columns: 1fr; }
  .cartbtn__text { display: none; }
  .drawer__panel { width: 100vw; }
  .cartbulk { left: var(--gap-4); right: var(--gap-4); transform: none; justify-content: space-between; }
}

/* 中屏：导航项变多后，题篮按钮只留图标 + 角标，给左侧导航留出空间，
   避免一行放不下时彼此遮挡（题篮文字本就是冗余 —— 图标 + 数字足够表意）。 */
@media (max-width: 960px) {
  .cartbtn__text { display: none; }
}

/* 只给读屏用的文字：视觉上不占位，但会被无障碍树读到 */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* 生效条件那一排：这里只是给「全选本页」找个落脚点，不需要那么大间距 */
.chips--tight { margin-bottom: var(--gap-2); }

/* ---------- 12. 组卷工作台（/papers 列表 + 三栏工作台） ---------- */

/* 组卷页的容器（试卷列表） */
.newpaper {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--gap-3);
  padding: var(--gap-3) var(--gap-4);
  margin-bottom: var(--gap-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.newpaper .field { margin: 0; }

.papergrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: var(--gap-3);
}
.papercard {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.papercard:hover { border-color: var(--line-strong); }
.papercard__main { padding: var(--gap-4); color: inherit; }
.papercard__main:hover { text-decoration: none; }
.papercard__title { font-size: 16px; margin: 0 0 4px; line-height: 1.4; }
.papercard__sub { margin: 0 0 var(--gap-2); font-size: 13px; color: var(--text-3); }
.papercard__meta { margin: 0; font-size: 13.5px; color: var(--text-2); display: flex; gap: 6px; }
.papercard__meta b { font-variant-numeric: tabular-nums; }
.papercard__sep { color: var(--line-strong); }
.papercard__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-2);
  padding: 10px var(--gap-4);
  border-top: 1px solid var(--line);
  background: var(--surface-2);
  font-size: 12.5px;
  margin-top: auto;
}
.papercard__foot form { margin: 0; }

/* 新建卷子卡片：与卷子卡片同尺寸，放在最前面（三）。
   虚线珊瑚橙边框 + 居中「＋ 新建一份卷子」，点一下在卡片内填名字新建。 */
.papercard--new {
  border-style: dashed;
  border-color: var(--accent-ink);
  background: color-mix(in srgb, var(--accent-ink) 6%, var(--surface));
}
.papercard--new:hover {
  border-color: var(--accent-ink);
  background: color-mix(in srgb, var(--accent-ink) 10%, var(--surface));
}
.papercard__newform {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--gap-2);
  height: 100%;
  padding: var(--gap-4);
  text-align: center;
}
.papercard__newico {
  font-size: 36px;
  line-height: 1;
  font-weight: 300;
  color: var(--accent-ink);
}
.papercard__newlabel {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-1);
  cursor: text;
}
.papercard__newinput {
  width: 100%;
  text-align: center;
  margin: 2px 0;
}
.papercard__newbtn { width: 100%; }

/* ---- 工作台整体：三栏，比常规页更宽，允许突破 --wrap ---- */
.board {
  --board-w: min(1580px, calc(100vw - 40px));
  width: var(--board-w);
  margin-left: calc((100% - var(--board-w)) / 2);
  margin-right: calc((100% - var(--board-w)) / 2);
}

.board__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--gap-3);
  padding-bottom: var(--gap-3);
  margin-bottom: var(--gap-4);
  border-bottom: 1px solid var(--line);
}
.board__name { display: flex; align-items: center; gap: var(--gap-2); min-width: 0; flex: 1 1 320px; }
.board__back {
  flex: none;
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--text-2);
  font-size: 15px;
}
.board__back:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.board__titleform { display: flex; gap: var(--gap-1); flex: 1 1 auto; min-width: 0; margin: 0; }
.board__titleform input {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 16px;
  font-weight: 600;
  padding: 6px 10px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
}
.board__titleform input:hover { border-color: var(--line); background: var(--surface); }
.board__saved { flex: none; font-size: 12.5px; color: var(--text-3); min-width: 76px; }
.board__actions { display: flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap; }
.board__actions form { margin: 0; }

.board__cols {
  display: grid;
  grid-template-columns: 296px minmax(0, 1fr) 312px;
  gap: var(--gap-4);
  align-items: start;
}
.board__col {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-4);
}
/* 左右两栏跟着滚，长卷子也不用先滚回顶部再选题 */
.board__col--src, .board__col--insp {
  position: sticky;
  top: 74px;
  max-height: calc(100dvh - 96px);
  overflow-y: auto;
}
.board__coltitle { font-size: 14px; margin: 0 0 var(--gap-2); letter-spacing: .02em; }
.board__colhint { font-size: 12.5px; color: var(--text-3); line-height: 1.7; margin: 0 0 var(--gap-3); }
.board__subtitle {
  font-size: 13px;
  margin: var(--gap-4) 0 var(--gap-2);
  padding-top: var(--gap-3);
  border-top: 1px solid var(--line);
  color: var(--text-2);
}

/* ---- 左栏：素材面板 ---- */
.palette__tabs {
  display: flex;
  gap: 2px;
  padding: 2px;
  margin-bottom: var(--gap-3);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.palette__tab {
  flex: 1;
  padding: 6px 8px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  font: inherit;
  font-size: 13.5px;
  color: var(--text-2);
  cursor: pointer;
}
.palette__tab:hover { background: var(--surface); color: var(--text); }
.palette__tab.is-active { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: var(--shadow); }

.palette__pick { display: block; margin-bottom: var(--gap-2); }
.palette__pick select { width: 100%; }
.palette__search { display: flex; gap: var(--gap-1); margin-bottom: var(--gap-2); }
.palette__search input { flex: 1; min-width: 0; }
.palette__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-2);
  font-size: 12.5px;
  margin-bottom: var(--gap-2);
}
.palette__bar form { margin: 0; }
.palette__empty {
  font-size: 13px;
  line-height: 1.8;
  color: var(--text-3);
  padding: var(--gap-4) 0;
}
.palette__pane.is-loading { opacity: .5; }

/* FR-7.1：素材里被挡掉的「待审核」题 —— 说明条，不占太多地方 */
.palette__note {
  margin: 0 0 var(--gap-2);
  padding: 6px 8px;
  border: 1px solid var(--warn-line);
  border-radius: var(--radius-sm);
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 12px;
  line-height: 1.7;
}

.plist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--gap-1); }
.plist__item {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-1);
  padding: 7px 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.plist__item:hover { border-color: var(--line-strong); }
.plist__item.is-in { background: var(--surface-2); }
.plist__item form { margin: 0; flex: none; }
.plist__main { flex: 1; min-width: 0; display: grid; gap: 2px; }
/* 题干行 + 右端「查看 / 含图 / 答案与解析」一行（#242，2026-10-12）。
   题干占满剩余宽度，右端那一撮固定靠右 —— 所以窄屏下题干折行时，
   它们仍然整整齐齐在右边，不会跟题干文字混在一起。 */
.plist__head { display: flex; align-items: baseline; gap: 6px; }
.plist__head .plist__stem { flex: 1; min-width: 0; }
.plist__head .plist__code { flex: none; }
.plist__head .tag--fig { flex: none; }
.plist__code { font-size: 12px; color: var(--accent-hover); }
/* 题干右边那枚链接（2026-10-11 起：左栏不出图，想看图/解析点它在新窗口打开；
   2026-10-14 #367：链接文字从题号改成了「查看」）。
   链接在深色底上容易被当成装饰文字，所以给一个能认出来的落点：
   下划线的虚线 + hover 变实线并加深。 */
.plist__code a {
  color: inherit;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.plist__code a:hover { color: var(--accent); text-decoration-style: solid; }
.plist__tags { display: flex; flex-wrap: wrap; gap: 3px; }
.plist__stem {
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.plist__add {
  flex: none;
  width: 26px; height: 26px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--accent-hover);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}
.plist__add:hover { background: var(--accent); border-color: var(--accent); color: var(--on-solid); }
.plist__flag { flex: none; font-size: 11px; color: var(--text-3); padding-top: 4px; }

/* ---- 中栏：卷面 ---- */
.sheet__empty {
  padding: var(--gap-6) var(--gap-5);
  text-align: center;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.sheet__emptytitle { font-size: 15px; color: var(--text); margin: 0 0 6px; }
.sheet__emptytip { font-size: 13.5px; color: var(--text-3); line-height: 1.9; margin: 0 0 var(--gap-4); }
.sheet__emptytip b { color: var(--text-2); }

.psec {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-3);
  margin-bottom: var(--gap-4);
  background: var(--surface-2);
}
.psec--loose { background: transparent; border-style: dashed; }
.psec__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--gap-2);
  margin-bottom: var(--gap-3);
}
.psec__grip {
  cursor: grab;
  color: var(--text-3);
  font-size: 15px;
  line-height: 1;
  padding: 2px 4px;
  border-radius: var(--radius-sm);
  user-select: none;
}
.psec__grip:hover { background: var(--surface); color: var(--text); }
.psec__title { font-size: 15px; margin: 0; color: var(--text-2); }
.psec__titleinput {
  font-size: 15px;
  font-weight: 600;
  width: auto;
  min-width: 90px;
  max-width: 260px;
  padding: 4px 8px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
}
.psec__titleinput:hover { border-color: var(--line-strong); background: var(--surface); }
.psec__score { display: inline-flex; align-items: center; gap: 4px; font-size: 12.5px; color: var(--text-2); }
.psec__score select { padding: 3px 6px; font-size: 12.5px; }
.psec__score input { width: 62px; padding: 3px 6px; font-size: 12.5px; }
.psec__unit { color: var(--text-3); }
.psec__meta { font-size: 12.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.psec__ops { margin-left: auto; display: flex; gap: 2px; }
.psec__del {
  border: 0; background: none; cursor: pointer;
  font-size: 18px; line-height: 1; padding: 2px 8px;
  border-radius: var(--radius-sm); color: var(--text-3);
}
.psec__del:hover { background: var(--danger-soft); color: var(--danger); }

.qlist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--gap-2); min-height: 20px; }
/* ⚠️ 下面这四条必须挂在 `.board` 下。
   `.qcard` 这个类名**两处都在用**：录题详情页（`questions/detail.html`）拿它当
   「题干/选项/答案」的整块卡片，组卷工作台拿它当「可拖拽的一行题」。
   工作台这份在样式表里更靠后，不加作用域就会把详情页整页压成横向一排，
   鼠标还会变成抓手 —— 同一类名两副面孔，页面自己看不出错，
   只有把两个页面并排截图才照得出来。 */
.board .qcard {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-2);
  padding: var(--gap-2) var(--gap-2) var(--gap-2) 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: grab;
}
.board .qcard:hover { border-color: var(--line-strong); }
.board .qcard.is-dragging { opacity: .45; border-style: dashed; cursor: grabbing; }
/* 落点提示：在被插入的那张卡上画一条上边线 */
.board .qcard.is-dropbefore { box-shadow: 0 -3px 0 -1px var(--accent); border-color: var(--accent-line); }
/* 落到「末尾」时，在列表底部开一个虚线槽 */
.qlist.is-dropend::after {
  content: '';
  height: 34px;
  border: 1px dashed var(--accent-line);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
}
body.is-dragging-qcard { cursor: grabbing; }

.qcard__no {
  flex: none;
  width: 34px;
  min-height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: stretch;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  color: var(--text-3);
  border-right: 1px solid var(--line);
  background: var(--surface-2);
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
}
.qcard__body { flex: 1; min-width: 0; display: grid; gap: 5px; padding: 2px 0; }
/* 来源角标在 grid 卡里：grid 会把 inline-flex 项 blockify 成整列宽 ——
   必须 justify-self:start 让它缩到内容宽；margin 交给父级 gap，别再叠一层。
   （`.qsrc` 是「同一校多日期」时的外层 <details>，它才是 grid 项，一起收进来。） */
.qcard__body .qsrcs, .qcard__body .qsrc { justify-self: start; margin-bottom: 0; }
.qcard__stem { font-size: 14px; line-height: 1.65; }
.qcard__stem > :first-child { margin-top: 0; }
.qcard__stem > :last-child { margin-bottom: 0; }
/* 组卷卡里的选项：两列横排（窄卡放不下 4 个一行，2×2 比竖排更省纵向空间）。 */
/* 组卷页/素材面板的选项：短横长纵，同 `.options` 口径 */
.qcard__opts { list-style: none; margin: 0; padding: 0; display: flex; gap: 2px 24px; font-size: 13.5px; }
.qcard__opts--row { flex-wrap: wrap; }
.qcard__opts--row li { flex: 0 1 auto; }
.qcard__opts--col { flex-direction: column; gap: 2px; }
.qcard__opts--col li { flex: 0 0 auto; }
/* 中等长度 → 2×2（与 `.options--grid` 同一口径，只是更紧凑、字号更小） */
.qcard__opts--grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2px 18px; }
.qcard__opts--grid li { flex: 0 1 auto; }
.qcard__opts li { display: flex; gap: 6px; line-height: 1.6; min-width: 0; align-items: baseline; }
.qcard__optno { flex: none; font-family: var(--font-mono); color: var(--text-3); }
.qcard__meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: 12px; }
.qcard__ops { flex: none; display: flex; align-items: center; gap: 2px; }
.qcard__score {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 3px 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 12.5px;
  color: var(--text-2);
}
.qcard__score input { width: 48px; padding: 1px 4px; border: 0; background: none; text-align: right; font-size: 12.5px; color: inherit; }
.qcard__score input:focus { outline: none; }
.qcard__score.is-locked { background: var(--surface-2); color: var(--text-3); }
.qcard__unit { color: var(--text-3); }
.qcard__op, .qcard__del {
  border: 0; background: none; cursor: pointer;
  border-radius: var(--radius-sm); color: var(--text-3);
}
.qcard__op { font-size: 13px; padding: 3px 6px; }
.qcard__op:hover { background: var(--surface-2); color: var(--text); }
.qcard__del { font-size: 17px; line-height: 1; padding: 2px 7px; }
.qcard__del:hover { background: var(--danger-soft); color: var(--danger); }
.qdrop {
  min-height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12.5px;
  color: var(--text-3);
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
}

.sheet__foot { display: flex; align-items: center; gap: var(--gap-3); }
.sheet__foot form { margin: 0; }
.sheet__foothint { font-size: 12px; color: var(--text-3); }

.sheetstats {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: var(--gap-4);
  padding: 10px var(--gap-4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: 13.5px;
  color: var(--text-2);
}
.sheetstats b { font-variant-numeric: tabular-nums; color: var(--text); }
.sheetstats__sep { color: var(--line-strong); }
.sheetstats__note { margin-left: auto; font-size: 12.5px; color: var(--warn); }

/* ---- 右栏：卷头表单与统计 ---- */
.hfields { display: grid; gap: var(--gap-2); }
.hfield {
  padding: 7px 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.hfield--fixed { background: var(--surface-2); }
.hfield__head { display: flex; align-items: center; gap: 6px; cursor: pointer; }
.hfield__head input { width: auto; margin: 0; flex: none; }
.hfield__label { font-size: 13px; color: var(--text); }
.hfield__lock { margin-left: auto; font-size: 11px; color: var(--text-3); }
.hfield__hint { margin: 4px 0 0 20px; font-size: 11.5px; color: var(--text-3); line-height: 1.6; }
.hfield__input {
  margin: 6px 0 0 20px;
  width: calc(100% - 20px);
  padding: 4px 6px;
  font-size: 13px;
}
.hfield--align { display: flex; align-items: center; justify-content: space-between; gap: var(--gap-2); }
.segmented--sm { margin-bottom: 0; padding: 2px; border-radius: var(--radius-sm); }
.segmented__opt { position: relative; }
.segmented__opt input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.segmented__opt span {
  display: block;
  padding: 4px 12px;
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  color: var(--text-2);
  cursor: pointer;
}
.segmented__opt input:checked + span { background: var(--accent); color: var(--on-solid); }
.segmented__opt input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

.hpreview {
  display: grid;
  gap: 3px;
  padding: var(--gap-2) var(--gap-3);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: 12.5px;
}
.hpreview__line { display: flex; gap: 6px; }
.hpreview__k { flex: none; color: var(--text-3); }
.hpreview__v { color: var(--text); }
.hpreview__empty { margin: 0; color: var(--text-3); }

.statlist { display: grid; gap: 5px; margin: 0; font-size: 13px; }
.statlist > div { display: flex; justify-content: space-between; gap: var(--gap-2); }
.statlist dt { color: var(--text-3); }
.statlist dd { margin: 0; font-variant-numeric: tabular-nums; color: var(--text); }

.seclist { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; font-size: 13px; }
.seclist__item { display: flex; justify-content: space-between; gap: var(--gap-2); }
.seclist__name { color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seclist__mode { flex: none; color: var(--text-3); font-size: 12px; }
.seclist__empty { color: var(--text-3); font-size: 12.5px; }

@media (prefers-color-scheme: dark) {
  .qlist.is-dropend::after { background: rgba(15, 110, 86, .18); }
}

@media (max-width: 1180px) {
  .board__cols { grid-template-columns: 260px minmax(0, 1fr); }
  .board__col--insp { grid-column: 1 / -1; position: static; max-height: none; }
}
@media (max-width: 860px) {
  .board { --board-w: 100%; width: 100%; margin-left: 0; margin-right: 0; }
  .board__cols { grid-template-columns: 1fr; }
  .board__col--src, .board__col--insp { position: static; max-height: none; }
}

/* ============================================================
   13. 审核流（/review 待审核列表 + 三栏审核页）
   ============================================================ */

/* ---- 队列页签上的数量 ---- */
.tabs__n {
  display: inline-block;
  min-width: 20px;
  margin-left: 6px;
  padding: 1px 6px;
  font-size: 11.5px;
  line-height: 1.5;
  text-align: center;
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}
.tabs__item.is-active .tabs__n {
  color: var(--accent-hover);
  background: var(--accent-soft);
  border-color: var(--accent-line);
}

.filters__meta { margin: 0 0 var(--gap-4); font-size: 13.5px; color: var(--text-2); }
.filters__meta b { font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }
/* 题干列吃掉剩余宽度：不然「质检问题」几枚徽章会把题干挤成一行几个字 */
.table .cell-stem { width: 46%; }
.table .cell-src { white-space: nowrap; color: var(--text-2); font-size: 13px; }

/* ---- 中栏：题目卡 ----
   ⚠️ 刻意**不复用** .qcard：那个类名已经被组卷工作台占了（是「可拖拽的题目行」，
   带 display:flex 和 cursor:grab），复用会让答案和解析并排显示。 */
.rvcard {
  padding: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.rvcard__block + .rvcard__block {
  margin-top: var(--gap-4);
  padding-top: var(--gap-4);
  border-top: 1px solid var(--line);
}
.rvcard__label {
  margin: 0 0 var(--gap-2);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-3);
  letter-spacing: .02em;
}
/* 通用 .empty 是个大虚线框（给整页空状态用的），塞进题目卡里太沉 —— 这里收成一行提示 */
.rvcard .empty {
  padding: 0;
  text-align: left;
  background: none;
  border: 0;
  font-size: 13px;
}

/* ---- 质检徽章（列表行内的小圆片） ---- */
.qbadge {
  display: inline-block;
  margin: 2px 4px 2px 0;
  padding: 1px 7px;
  font-size: 12px;
  line-height: 1.6;
  border-radius: 999px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.qbadge--blocker { color: var(--danger); background: var(--danger-soft); border-color: var(--danger-line); }
.qbadge--warning { color: var(--warn); background: var(--warn-soft); border-color: var(--warn-line); }
.qbadge--more { color: var(--text-3); background: var(--surface-2); border-color: var(--line); }

/* ---- 键盘按键 ---- */
kbd {
  display: inline-block;
  min-width: 18px;
  padding: 0 5px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 18px;
  text-align: center;
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-bottom-width: 2px;
  border-radius: 4px;
}
.btn kbd { flex: none; }

/* ---- 三栏审核页：与组卷工作台一样突破 --wrap，三栏才放得下 ---- */
.review {
  --board-w: min(1580px, calc(100vw - 40px));
  width: var(--board-w);
  margin-left: calc((100% - var(--board-w)) / 2);
  margin-right: calc((100% - var(--board-w)) / 2);
}

.review__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-3);
  padding-bottom: var(--gap-3);
  margin-bottom: var(--gap-4);
  border-bottom: 1px solid var(--line);
}
.review__id { display: flex; align-items: center; flex-wrap: wrap; gap: var(--gap-2); font-size: 13.5px; }
.review__back { font-size: 18px; line-height: 1; padding: 0 5px; color: var(--text-3); }
.review__back:hover { color: var(--accent); text-decoration: none; }
.review__pos { color: var(--text-3); font-variant-numeric: tabular-nums; }
.review__nav { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.review__nav .btn.is-disabled { opacity: .45; cursor: not-allowed; }

.review__cols {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr) 340px;
  gap: var(--gap-4);
  align-items: start;
}
.review__col { min-width: 0; }
.review__col--queue,
.review__col--judge {
  position: sticky;
  top: var(--gap-4);
  max-height: calc(100dvh - 116px);
  overflow: auto;
}
.review__coltitle {
  display: flex;
  align-items: center;
  gap: var(--gap-2);
  margin: 0 0 var(--gap-2);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-2);
}
.review__col--main .review__coltitle { margin-top: var(--gap-5); }
.review__col--main > .review__coltitle:first-child { margin-top: 0; }
.review__colhint { margin: 0 0 var(--gap-3); font-size: 12.5px; line-height: 1.65; color: var(--text-3); }
.review__colhint a { color: var(--accent); }
.review__coltitle .count {
  display: inline-block;
  min-width: 20px;
  padding: 0 6px;
  font-size: 11.5px;
  text-align: center;
  color: var(--danger);
  background: var(--danger-soft);
  border: 1px solid var(--danger-line);
  border-radius: 999px;
}
.review__coltitle .count--zero { color: var(--text-3); background: var(--surface-2); border-color: var(--line); }

/* ---- 左栏：队列窗口 ---- */
.qqueue { list-style: none; margin: 0 0 var(--gap-2); padding: 0; display: grid; gap: 3px; }
.qqueue__item { border: 1px solid transparent; border-radius: var(--radius-sm); }
.qqueue__item.is-current { background: var(--accent-soft); border-color: var(--accent-line); }
.qqueue__link { display: grid; gap: 3px; padding: 7px 9px; color: inherit; border-radius: var(--radius-sm); }
.qqueue__link:hover { text-decoration: none; background: var(--surface-2); }
.qqueue__item.is-current .qqueue__link:hover { background: transparent; }
.qqueue__top { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.qqueue__stem {
  font-size: 12.5px; line-height: 1.5; color: var(--text-2);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ---- 中栏：质检问题卡 ---- */
.qcblock { list-style: none; margin: 0 0 var(--gap-3); padding: 0; display: grid; gap: var(--gap-2); }
.qccard {
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left-width: 3px;
  border-radius: var(--radius-sm);
}
.qccard--blocker { border-left-color: var(--danger); background: var(--danger-soft); }
.qccard--warning { border-left-color: var(--warn); background: var(--warn-soft); }
.qccard__head { display: flex; align-items: center; gap: var(--gap-2); font-size: 13.5px; font-weight: 600; }
.qccard__sev { font-size: 11.5px; font-weight: 500; padding: 0 6px; border: 1px solid currentColor; border-radius: 999px; }
.qccard__detail { margin: 4px 0 0; font-size: 13px; color: var(--text-2); }

/* ---- 中栏：就地修订表单 ---- */
.reviseform {
  display: grid;
  gap: var(--gap-3);
  padding: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.revfield label { display: block; margin-bottom: 5px; font-size: 13px; font-weight: 600; color: var(--text-2); }
.revfield__hint { margin-left: var(--gap-2); font-weight: 400; font-size: 12px; color: var(--text-3); }
.revfield textarea {
  width: 100%;
  padding: 9px 11px;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.7;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  resize: vertical;
}
.revfield .writing { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.revfield textarea:focus { outline: 2px solid var(--accent-line); border-color: var(--accent); }
.reviseform__foot { display: flex; align-items: center; flex-wrap: wrap; gap: var(--gap-3); }
.reviseform__note { font-size: 12.5px; color: var(--text-3); }

/* ---- 右栏：判定 ---- */
.judge {
  display: grid;
  gap: var(--gap-2);
  padding: var(--gap-3);
  margin-bottom: var(--gap-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.judge__notelabel { font-size: 13px; font-weight: 600; color: var(--text-2); }
.judge__hint { display: block; margin-top: 2px; font-weight: 400; font-size: 12px; color: var(--text-3); }
.judge textarea {
  width: 100%;
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  resize: vertical;
}
.judge textarea:focus { outline: 2px solid var(--accent-line); border-color: var(--accent); }
/* 按钮里带着 kbd，做成「左边文字、右边按键」的一行，像操作清单 */
.judge .btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-2);
  width: 100%;
  text-align: left;
}
.judge .btn kbd { margin-left: 0; }

/* ---- 右栏：修订历史 ---- */
.hist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--gap-2); }
.hist__item {
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.hist__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 6px;
  font-size: 12.5px;
  color: var(--text-3);
}
.hist__when { color: var(--text-2); font-variant-numeric: tabular-nums; }
.hist__by { color: var(--text-2); }
.hist__rows { list-style: none; margin: 0 0 6px; padding: 0; display: grid; gap: 6px; }
.hist__row { font-size: 12.5px; line-height: 1.55; }
.hist__field { display: inline-block; min-width: 42px; color: var(--text-3); }
.hist__diff code {
  padding: 1px 4px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  background: var(--surface-2);
  border-radius: 3px;
  word-break: break-all;
}
.hist__arrow { margin: 0 3px; color: var(--text-3); }
.hist__sup { display: block; margin-top: 2px; font-size: 11.5px; color: var(--warn); }
.hist__blocked { margin: 0; font-size: 12px; color: var(--text-3); }

/* ---- 快捷键帮助浮层 ---- */
.kbdhelp {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--gap-4);
}
.kbdhelp[hidden] { display: none; }
.kbdhelp__backdrop { position: absolute; inset: 0; background: rgba(16, 24, 20, .45); }
.kbdhelp__panel {
  position: relative;
  width: min(420px, 100%);
  padding: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.kbdhelp__panel h2 { margin-bottom: var(--gap-3); font-size: 16px; }
.kbdhelp__list { display: grid; gap: 7px; margin: 0 0 var(--gap-3); }
.kbdhelp__list > div { display: flex; align-items: center; justify-content: space-between; gap: var(--gap-3); font-size: 13.5px; }
.kbdhelp__list dt { flex: none; }
.kbdhelp__list dd { margin: 0; color: var(--text-2); }
.kbdhelp__note { font-size: 12.5px; color: var(--text-3); }

@media (prefers-color-scheme: dark) {
  .kbdhelp__backdrop { background: rgba(0, 0, 0, .62); }
}

@media (max-width: 1180px) {
  .review__cols { grid-template-columns: 240px minmax(0, 1fr); }
  .review__col--judge { grid-column: 1 / -1; position: static; max-height: none; }
}
@media (max-width: 860px) {
  .review { --board-w: 100%; width: 100%; margin-left: 0; margin-right: 0; }
  .review__cols { grid-template-columns: 1fr; }
  .review__col--queue, .review__col--judge { position: static; max-height: none; }
  .review__col--queue { order: 2; }
  .review__col--main { order: 1; }
  .review__col--judge { order: 3; }
}


/* ============================================================
   14. 组卷工作台：撤销 / 重做 · 多选 · 键盘
   ------------------------------------------------------------
   只做「交互状态」的呈现，不动版面骨架（骨架在第 12 节）。
   颜色一律走令牌 —— 深色模式才不用逐条补。
   ============================================================ */

/* ---- 顶栏的撤销 / 重做 ---- */
.undoredo { display: inline-flex; gap: 4px; }
.undoredo .btn[disabled] { opacity: .42; cursor: not-allowed; }

/* ---- 卷面顶部那行键盘提示 ----
   功能藏起来等于没有；这行字就是它们的「发现路径」。 */
.sheet__keys {
  margin: 0 0 var(--gap-3);
  font-size: 12px;
  line-height: 1.9;
  color: var(--text-3);
}
.sheet__keys kbd { margin: 0 1px; }

/* ---- 题目卡：键盘焦点与选中态 ----
   🔴 焦点环**不能去**：键盘移动全靠它告诉用户「现在停在哪一道」。 */
.board .qcard:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.board .qcard.is-sel {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  box-shadow: inset 3px 0 0 var(--accent);
}
.board .qcard.is-sel .qcard__no { color: var(--accent-hover); }
/* 选中 + 焦点同时出现时，别把 inset 阴影盖掉 */
.board .qcard.is-sel:focus-visible { outline-offset: 1px; }

/* ---- 多选工具条 ----
   fixed 定位浮在底部：它在 #board 外面，不会被中栏的整块替换刷掉。 */
.picks {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 40;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--gap-2) var(--gap-3);
  max-width: calc(100vw - 32px);
  padding: 8px 14px;
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  background: var(--surface);
  box-shadow: 0 12px 34px rgba(0, 0, 0, .18);
  font-size: 13px;
}
/* ⚠️ `[hidden]` 必须显式写：UA 样式表里的 `display:none` 打不过上面的 `display:flex`，
   不写这一条工具条就永远藏不住。 */
.picks[hidden] { display: none; }
.picks__count { font-weight: 600; color: var(--accent-hover); font-variant-numeric: tabular-nums; }
.picks__hint { font-size: 12px; color: var(--text-3); }
.picks__ops { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.picks__ops select {
  max-width: 190px;
  padding: 4px 6px;
  font-size: 13px;
}

@media (prefers-color-scheme: dark) {
  .picks { box-shadow: 0 12px 34px rgba(0, 0, 0, .55); }
}

@media (max-width: 860px) {
  .picks {
    left: 12px; right: 12px;
    transform: none;
    max-width: none;
    border-radius: var(--radius);
    justify-content: center;
  }
}


/* ============================================================
   15. 分类目录：管理态
   ------------------------------------------------------------
   浏览态与之前完全一样，这里只加「管理态下长出来的那些东西」。
   小表单做成 <details> + 绝对定位的小面板：
   · 绝对定位而不是把表单塞进行内 —— 一个 8 字段的表单塞进
     flex 行会把行高撑爆，整棵树都没法看了；
   · 面板上限高 60vh 且自身可滚 —— 免得最后一个节点展开后
     长风出屏幕底部、又没有滚动空间可以够到。
   ============================================================ */

/* ---- 行尾的操作按钮组 ---- */
.tree__tools {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
}
/* 表单只用来提交一个按钮时，别让 form 变成块级、把行撑开 */
.inanform { display: inline; margin: 0; }
/* 树行里的小按钮：整体 .btn 现在是固定 36px 高，放在树行里太高，
   这里单独压到 26px（只影响这一处，不动全局） */
.tree__tools .btn { height: 26px; padding: 0 9px; font-size: var(--fs-xs); }

/* 🔴 目录树「＋ 子节点」（2026-10-15 用户口径：更显眼、更美观）：
   同排的 ↑↓/改/删 都是素净的灰按钮，唯独「加子节点」是老师最常点的动作，
   给它珊瑚橙的浅底 + 橙字 + 橙描边；hover / 展开时转实心橙，眼睛一下就能抓住。
   不要用 .btn--ghost（那是透明的，等于没做）。 */
.tree__addbtn {
  font-weight: 600;
  color: var(--accent-ink);
  background: var(--accent-soft);
  border-color: var(--accent-line);
}
.tree__addbtn:hover,
.nodeedit[open] > summary.tree__addbtn {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
}

/* 目录树就地编辑的三枚工具按钮：加子节点=珊瑚橙（最常用）、改=松石青、删=警示红。
   三枚都给浅底 + 描边 + 加粗，避免「改 / 删」是透明 ghost 按钮时容易被看漏（五.1）。 */
.tree__editbtn {
  font-weight: 600;
  color: var(--cool-ink);
  background: var(--cool-soft);
  border-color: var(--cool-line);
}
.tree__editbtn:hover,
.nodeedit[open] > summary.tree__editbtn {
  color: #fff;
  background: var(--cool);
  border-color: var(--cool);
}
.tree__delbtn {
  font-weight: 600;
  color: var(--danger);
  background: var(--danger-soft);
  border-color: var(--danger-line);
}
.tree__delbtn:hover,
.nodeedit--danger[open] > summary.tree__delbtn {
  color: #fff;
  background: var(--danger);
  border-color: var(--danger);
}

/* 目录树管理态：批量导入/结构调整整组置顶（五.2），与下面的树卡区分开 */
.batchgroup {
  margin-bottom: var(--gap-6);
  padding-bottom: var(--gap-5);
  border-bottom: 1px dashed var(--line);
}

/* ---- 就地编辑面板 ---- */
details.nodeedit { position: relative; display: inline-block; }
details.nodeedit > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
}
details.nodeedit > summary::-webkit-details-marker { display: none; }
details.nodeedit[open] > summary {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent-hover);
}
details.nodeedit--danger[open] > summary {
  background: var(--danger-soft);
  border-color: var(--danger-line);
  color: var(--danger);
}

.nodeedit__form {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 30;
  width: min(620px, 82vw);
  max-height: 60vh;
  overflow: auto;
  padding: var(--gap-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: 0 14px 40px rgba(0, 0, 0, .18);
}
.nodeedit__form .field { margin-bottom: var(--gap-3); }
.nodeedit__note { margin: 0 0 var(--gap-3); font-size: 13px; }
.nodeedit__impact {
  margin: 0 0 var(--gap-3);
  padding-left: 1.2em;
  font-size: 12.5px;
  color: var(--text-2);
}
.nodeedit__foot {
  display: flex;
  align-items: center;
  gap: var(--gap-2);
  flex-wrap: wrap;
}

/* ---- 目录设置卡（可折叠） ---- */
details.cardset > summary {
  cursor: pointer;
  list-style: none;
}
details.cardset > summary::-webkit-details-marker { display: none; }
details.cardset > summary::before {
  content: "▸ ";
  color: var(--text-3);
}
details.cardset[open] > summary { margin-bottom: var(--gap-4); }
details.cardset[open] > summary::before { content: "▾ "; }
.cardset__danger {
  margin-top: var(--gap-5);
  padding-top: var(--gap-4);
  border-top: 1px dashed var(--danger-line);
}

/* 上传导入的「还等着确认」那一段（#368）：用提醒色起头，
   与上面那个「再传一份」的表单分开 —— 两个动作别混成一片。 */
.cardset__pending {
  margin-top: var(--gap-4);
  padding: var(--gap-4);
  border: 1px dashed var(--warn-line);
  border-radius: var(--radius);
  background: var(--warn-soft);
}

/* ---- 「刚动过的是哪一个」高亮 ----
   300 个节点的树里，没有这一下就找不到自己刚才改的是哪儿。 */
@keyframes nodeflash {
  0%   { background: var(--warn-soft); }
  100% { background: transparent; }
}
.tree__item.is-flash > .tree__row {
  animation: nodeflash 1.8s ease-out;
  outline: 2px solid var(--accent-line);
  outline-offset: 1px;
}

@media (prefers-color-scheme: dark) {
  .nodeedit__form { box-shadow: 0 14px 40px rgba(0, 0, 0, .6); }
  .covmatrix__miss { background: rgba(255, 255, 255, .04); }
}

/* 窄屏：小面板改成整行展开，浮层在手机上很容易顶到屏幕外 */
@media (max-width: 860px) {
  .nodeedit__form {
    position: static;
    width: auto;
    max-height: none;
    margin-top: 6px;
  }
  .tree__tools { margin-left: 0; width: 100%; }
}

/* ================================================================
   16. 统计看板（切片 9B：覆盖率矩阵 / 目录空点 / 归档树）
   ================================================================ */

/* ---- 学校 × 年份矩阵 ---- */
.covmatrix {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.covmatrix th, .covmatrix td {
  padding: 5px 10px;
  border-bottom: 1px solid var(--line);
  text-align: right;
  white-space: nowrap;
}
.covmatrix__side {
  text-align: left;
  font-weight: 500;
}
.covmatrix__col { color: var(--text-3); font-weight: 600; }
.covmatrix__sum { font-weight: 700; }
.covmatrix__group th { border-top: 2px solid var(--line); }
.covmatrix__group > .covmatrix__side { padding-top: 10px; }
.covmatrix__school > .covmatrix__side { padding-left: 18px; color: var(--text-2); }
.covmatrix__hit { font-weight: 600; }
.covmatrix__miss { color: var(--text-3); background: rgba(0, 0, 0, .03); }
.covmatrix__blankrow > td { padding: 0 10px; }
.covmatrix__fold { display: inline-block; padding: 3px 0; }
.covmatrix__fold summary {
  cursor: pointer; color: var(--text-3); font-size: 12px; user-select: none;
}
.covmatrix__fold summary:hover { color: var(--text-2); }
.covmatrix tfoot th { border-top: 2px solid var(--line); padding-top: 8px; }

/* ---- 目录空点 ---- */
.covgap { padding: 10px 0; border-bottom: 1px dashed var(--line); }
.covgap:last-child { border-bottom: 0; }
.covgap__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.covgap__name { font-weight: 600; }
.covgap__sample { margin: 6px 0 0; font-size: 13px; }

/* ---- 归档树 ---- */
.archtree__group { padding: 14px 0; border-bottom: 1px solid var(--line); }
.archtree__group:last-child { border-bottom: 0; }
.archtree__groupname { margin: 0 0 8px; font-size: 15px; }
.archtree__school { padding: 6px 0 6px 14px; }
.archtree__schoolname { margin: 0 0 4px; font-size: 13.5px; }
.archtree__years { list-style: none; margin: 0; padding: 0 0 0 14px; }
.archtree__year {
  padding: 3px 0; display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.archtree__yearlabel { min-width: 64px; font-weight: 600; font-variant-numeric: tabular-nums; }
.archtree__papers { list-style: none; margin: 0; padding: 0; display: inline; }
.archtree__paper { display: inline-block; margin-right: 14px; }

@media (max-width: 860px) {
  .covmatrix th, .covmatrix td { padding: 4px 6px; font-size: 13px; }
  .covmatrix__school > .covmatrix__side { padding-left: 8px; }
  .archtree__yearlabel { min-width: 48px; }
}

/* ================================================================
   17. 批量导入四步向导（切片 7：stepper / 解析摘要 / 原卷对照 / 报告页）
   ================================================================ */

.wiz {
  list-style: none; display: flex; flex-wrap: wrap; gap: 6px 18px;
  margin: 0 0 18px; padding: 10px 16px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 10px; font-size: 14px;
}
.wiz__step {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--text-3);
}
.wiz__step b { font-weight: 600; }
.wiz__step.is-done { color: var(--text); }
.wiz__step.is-done::after { content: "✓"; margin-left: 4px; color: var(--ok); font-size: 12px; }
.wiz__step.is-current { color: var(--text); font-weight: 700; }
.wiz__step.is-current::after {
  content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent); margin-left: 6px;
}

/* ---- B. 导入流程可视化（步骤指示器）----
   和顶栏 .wiz 同一套语言：冷色/暖色分工 —— 完成走松石青(--ok)、进行中走珊瑚橙(--accent)。 */
.card--steps { padding: 10px 16px; }
.steps__summary {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  list-style: none; padding: 0;
}
.steps__summary::-webkit-details-marker { display: none; }
.steps__summary > b { font-size: 15px; }
.steps__hint { color: var(--text-3); font-size: 13px; }
.steps__hide {
  margin-left: auto; border: 0; background: none; color: var(--text-3);
  font-size: 12px; cursor: pointer; padding: 2px 6px; border-radius: 6px;
}
.steps__hide:hover { background: var(--surface-2); color: var(--text); }
.stepslist {
  list-style: none; margin: 10px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 8px 16px;
}
.step {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 14px; color: var(--text-3);
}
.step__mark { font-weight: 700; width: 1.2em; text-align: center; flex: 0 0 auto; }
.step__label { font-weight: 600; color: var(--text); }
.step__desc { color: var(--text-3); font-size: 12px; }
.step.is-done .step__mark { color: var(--ok); }
.step.is-current .step__mark { color: var(--accent); }
.step.is-current .step__label::after { content: " 进行中"; color: var(--accent); font-size: 12px; font-weight: 400; }
.step.is-pending .step__mark { color: var(--text-3); }

/* ---- A. 整卷预览 ---- */
.card--wholeprev { padding: 14px 16px; }
.wholeprev__head { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; }
.wholeprev__head .card__title { margin: 0; }
.wholeprev__tools { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.wholeprev__ans { font-size: 13px; color: var(--text-2); display: inline-flex; align-items: center; gap: 4px; }
.wholeprev__note { margin: 0 0 10px; }
.wholeprev__consist { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.consist {
  font-size: 13px; padding: 6px 10px; border-radius: 8px; border: 1px solid var(--line);
  background: var(--surface-2);
}
.consist--warn { border-color: #e8c36a; background: #fff7e6; color: #8a6d1b; }
.consist--info { color: var(--text-3); }
.wholeprev__body { display: grid; grid-template-columns: 1fr; gap: 12px; }
.wholeprev__pdfwrap {
  position: relative; min-height: 70vh; border: 1px solid var(--line);
  border-radius: 10px; overflow: hidden; background: var(--surface-2);
}
.wholeprev__frame { width: 100%; height: 80vh; border: 0; display: block; }
.wholeprev__loading {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--text-3); font-size: 14px;
}
.wholeprev__srcbox { border-top: 1px solid var(--line); padding-top: 8px; }
.wholeprev__srcbox summary { cursor: pointer; font-size: 13px; color: var(--text-2); }
.wholeprev__src {
  max-height: 320px; overflow: auto; background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 10px;
  font-size: 12px; line-height: 1.5; white-space: pre-wrap; word-break: break-all;
}

.card--parse .parsebar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 8px;
}
.parsebar__file { font-weight: 600; word-break: break-all; }

/* ---- 解析进度页（2026-10-17：导入改异步，扫描件在后台识别） ----
   冷色（--cool）在这里是正确的用法：它管的是「数据型」区块，
   而进度条就是纯数据；暖色主色留给按钮与品牌。 */
.parsing { max-width: 720px; }
.parsing__head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 14px; }
.parsing__title { margin: 0 0 4px; font-size: 17px; }
.parsing__file { margin: 0; font-size: 13px; word-break: break-all; }
.parsing__detail { margin: 8px 0 0; font-size: 13px; color: var(--cool); font-weight: 600; }
/* 逐页出结果的实时预览（2026-10-17）：第 1 页认完就列出前几道题，不用干等整卷 */
.parsing__preview {
  margin-top: var(--gap-3); padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px dashed var(--line-strong);
}
.parsing__preview[hidden] { display: none; }
.parsing__previewcap { margin: 0 0 6px; font-size: var(--fs-sm); color: var(--text-3); }
.parsing__previewlist {
  margin: 0; padding-left: 1.6em;
  font-size: var(--fs-sm); color: var(--text-2); line-height: 1.7;
}
.parsing__previewlist li { margin: 2px 0; }
.parsing__previewlist li b { color: var(--accent-ink); margin-right: 4px; }
.parsing__err { margin-top: 12px; white-space: pre-wrap; }
.parsing__acts { display: flex; gap: 8px; margin-top: 16px; }

.parsing__spin {
  width: 18px; height: 18px; margin-top: 2px; flex: 0 0 auto;
  border: 2px solid var(--cool-line); border-top-color: var(--cool);
  border-radius: 50%; animation: parse-spin 0.9s linear infinite;
}
@keyframes parse-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .parsing__spin { animation-duration: 3s; } }

.pbar {
  height: 8px; border-radius: 999px; overflow: hidden;
  background: var(--cool-soft);
}
.pbar__fill {
  height: 100%; border-radius: 999px; min-width: 6px;
  background: linear-gradient(90deg, var(--cool), var(--accent));
  transition: width 0.4s ease;
}

/* ---- 校对页布局：左原卷对照，右题目卡片 ---- */
.reviewwrap {
  display: grid; grid-template-columns: minmax(280px, 380px) 1fr;
  gap: 18px; align-items: start;
}
/* 没有原卷对照栏时（Word / 纯文本 / md 导入 —— `page_count` 为 0，模板不渲染
   `<aside class="srcview">`），题目列表就成了唯一的子元素，会**掉进上面那个
   280–380px 的第一列**：整页只剩左边一条窄栏，右边全空。
   这个坑在 PDF 导入时看不出来（那时永远有对照栏），只有导 Word 才现形。 */
.reviewwrap > .qlist:only-child { grid-column: 1 / -1; }
@media (max-width: 1080px) {
  .reviewwrap { grid-template-columns: 1fr; }
}

.srcview {
  /* 🔴 top 必须避开顶栏（原来写 12px，整块被 fixed 顶栏盖住 ⇒ 用户看不到
     「原卷对照 / 上一页 / 下一页」那一行，也就没法翻页）。 */
  position: sticky; top: calc(var(--topbar-h, 56px) + 10px);
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); padding: 10px 12px;
  /* 🔴 2026-10-17 用户报「左边原卷滑不动」：原先是 max-height + overflow:auto 一把梭，
     图片撑满时 aside 自己变成滚动容器，滚轮经常被外层页面抢走（右边越长越明显）。
     改成 **flex 竖排 + 固定高度 + 中间那层自己滚**：头部不动、只有页面图滚，
     再给 overscroll-behavior: contain 让滚轮到底也不往外漏。
     高度用 100dvh（移动端 100vh 会把地址栏算进去，底部永远差一截）。 */
  display: flex; flex-direction: column;
  height: calc(100dvh - var(--topbar-h, 56px) - 34px);
  max-height: calc(100dvh - var(--topbar-h, 56px) - 34px);
  overflow: hidden;
}
/* 原卷对照栏在窄屏会叠到题目上面，那时不该再锁高度 */
@media (max-width: 1080px) {
  .srcview { position: static; height: auto; max-height: 70dvh; }
}
.srcview__head {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  margin-bottom: 8px; font-size: 14px;
  flex: 0 0 auto;
}
.srcview__nav { display: inline-flex; align-items: center; gap: 6px; }
/* 只有这层滚：滚轮在这里一定生效，且滚到底不把整页带走 */
.srcview__page {
  position: relative; border: 1px solid var(--line);
  border-radius: 6px; background: var(--surface-2);
  flex: 1 1 auto; min-height: 120px;
  overflow: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.srcview__page img { display: block; width: 100%; height: auto; min-height: 120px; }
.srcview__hl {
  position: absolute; left: 2%; width: 96%;
  /* #e5484d 是有意写死的：这个框画在**白纸扫描件**上，
     而深色模式里 var(--danger) 会变浅粉，压在白底上反而看不见。 */
  border: 2px solid #e5484d; background: rgba(229, 72, 77, 0.12);
  border-radius: 3px; pointer-events: none;
  transition: top 0.15s ease, height 0.15s ease;
}
.srcview__hint { font-size: 12px; color: var(--text-3); margin: 8px 0 0; }

/* 审核页 / 详情页里的原卷截图（flag → 原卷定位） */
.srcfig { margin: 10px 0; }
.srcfig img {
  display: block; max-width: 100%;
  /* 同理：扫描件本身就是白纸，容器必须白底，不能跟随深色模式。 */
  border: 1px solid var(--line); border-radius: 8px; background: #fff;
}
.srcfig figcaption { font-size: 12px; color: var(--text-3); margin-top: 4px; }

/* ================================================================
   18. 运维台 /ops（切片 10：探活 / 存储 / 备份 / 全库导出）
   ================================================================ */

.opsgrid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.opsgrid--tight { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }

/* AI 总开关（/ai 页，2026-10-15）：网站里点动、立即生效 —— 要一眼看见、重点凸显 */
.aiswitch {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-3); flex-wrap: wrap;
  margin: var(--gap-3) 0;
  padding: 12px 14px;
  border: 1px solid var(--accent-line);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius);
  background: var(--accent-soft);
}
.aiswitch__state { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.aiswitch__label { font-size: var(--fs-lg); }
.aiswitch__src { font-size: var(--fs-xs); }
.aiswitch__act { display: flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap; }
.aiswitch__act form { margin: 0; }

.opscard {
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); padding: 12px 14px;
}
.opscard--warn { border-color: var(--warn-line); background: var(--warn-soft); }
.opscard--num { text-align: center; padding: 14px 10px; }

.opscard__head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-size: 13px; color: var(--text-2); margin-bottom: 6px;
}
.opscard__num {
  margin: 0; font-size: 22px; font-weight: 700; color: var(--text);
  line-height: 1.25; word-break: break-all;
}
a.opscard__num { color: var(--accent); text-decoration: none; }
a.opscard__num:hover { text-decoration: underline; }
.opscard__desc { margin: 6px 0 0; font-size: 12px; color: var(--text-3); line-height: 1.6; }

.opstable { border-collapse: collapse; width: 100%; font-size: 13px; }
.opstable th, .opstable td {
  border-bottom: 1px solid var(--line); padding: 7px 10px; text-align: left;
  vertical-align: top;
}
.opstable thead th { background: var(--surface-2); font-weight: 600; color: var(--text-2); }
.opstable__mono { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; font-size: 12px; }

/* 邀请码卡片（切片 27）：注册模式 + 邀请码本体。等宽、单击即全选 ——
   管理员要把它复制出去发给申请人，「好选」比「好看」更要紧。 */
.opsinvite {
  display: grid; gap: 10px;
  margin: 10px 0 14px; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-2);
}
.opsinvite__row { display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; }
.opsinvite__label {
  flex: 0 0 auto; min-width: 5em;
  font-size: 13px; font-weight: 600; color: var(--text-2);
}
.opsinvite__code {
  user-select: all;                 /* 单击即全选，方便直接复制 */
  font-family: var(--font-mono);
  font-size: 15px; letter-spacing: .04em;
  color: var(--accent-hover);
  background: var(--surface);
  border: 1px dashed var(--accent-line);
  border-radius: 6px; padding: 3px 10px;
}

.opsactions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-top: 12px;
}
.ops-error {
  margin: 6px 0 0; font-size: 12px; color: var(--danger);
  word-break: break-all;
}
/* 导出失败日志（xelatex 的整段输出）。要 pre-wrap 而不能用默认的 pre：
   日志里有长路径，默认不换行会把表格顶宽、整页横向滚动。 */
.ops-error__log {
  margin: 0;
  max-height: 14em;
  overflow: auto;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-all;
  color: var(--danger);
}
.ops-sub { margin: 18px 0 8px; font-size: 14px; color: var(--text-2); }
.ops-note { color: var(--warn); }

/* 让运维页的 <code> 在小字里也能看清命令 */
.ops-note code, .panel__hint code {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 4px; padding: 1px 5px; font-size: 12px;
}

/* 卡片里的文件路径：用 <code> 是为了被 KaTeX 跳过（见 ops/index.html 的注释），
   但不要 <code> 默认那个边框盒子 —— 长路径换行后太笨重，这里压成一行等宽小字。 */
.ops-path {
  display: inline-block; max-width: 100%; margin-top: 3px;
  background: none; border: 0; padding: 0;
  font-family: var(--font-mono); font-size: 11px;
  color: var(--text-3); word-break: break-all;
}

/* ---------------------------------------------------------------- 题目图形（TikZ）
   KaTeX / MathJax 都渲染不了 TikZ，几何图由后端编译成 **SVG**
   （backend/app/services/figures.py）。产物是矢量、自带 pt 尺寸，
   所以这里只做三件事：别撑破容器、给个干净白底、失败时把话说清楚。 */
.qfig {
  margin: 6px 0 16px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
}
.qfig__img {
  display: block;
  max-width: 100%; height: auto;          /* 矢量图：放大也不会糊 */
  /* 高度闸挂在正文 em 上（--fig-max-h，与题库列表 .qrow__fig 同档）：SVG 自带
     印刷物理尺寸（最大 13.2cm ≈ 500px），屏幕上照印刷尺寸出就显得过大 ——
     统一压到与题目文字协调的档位。矢量缩小依然锐利，点开看原始尺寸走右键。 */
  max-height: var(--fig-max-h); width: auto;
  /* #164（2026-10-12 收尾）：这几个 educated box 以前只在**列表页**撤掉了，
     详情页 / 审核页这一档还套着一圈矩形外框。同一个自带边线的矢量图，
     外面再画一圈就成了用户说的「框里框」—— 三件套全撤：border / radius / padding。
     🔴 白底**必须保留，且必须是硬白 #fff**（不能跟 `var(--surface)` 走）：
        编译出来的 SVG 是**透明底 + 黑线**，深色模式下 `--surface` 是深灰，
        黑线直接隐形、整张图变一张黑方块（以前就是这样，等于有个暗病）。
        硬白底 = 永远是「白纸上的图」，两种模式都说得通。原卷截图 `.srcfig` 同理。 */
  background: #fff;
}
/* 渲染失败：不装没事，直说，并把源码摊开（默认展开）让人能改 */
.qfig__fail {
  max-width: 560px; padding: 10px 12px;
  background: var(--danger-soft); border: 1px dashed var(--danger-line);
  border-radius: 8px; color: var(--danger); font-size: 13px; line-height: 1.55;
}
.qfig__fail p { margin: 0 0 4px; }
.qfig__fail p:last-child { margin: 0; font-family: var(--font-mono); font-size: 12px; }
.qfig__src { width: 100%; }
.qfig__src > summary {
  cursor: pointer; user-select: none;
  font-size: 12px; color: var(--text-3); list-style: none;
}
.qfig__src > summary::-webkit-details-marker { display: none; }
.qfig__src > summary::before { content: "▸ "; }
.qfig__src[open] > summary::before { content: "▾ "; }
.qfig__src > summary:hover { color: var(--accent); }
.qfig__src .codeblock { margin-top: 6px; }

/* ================================================================
   图形核对台（/figures/review）
   一题一卡：上面是题干，中间「库里现在的图 ↔ 原卷对应区域」并排，
   下面是体检结论和三个动作按钮。

   命名刻意新开一个 `fcard` 前缀，**不复用 `.qcard` / `.qlist`** ——
   那两个在组卷工作台里是"可拖拽的题目行"（display:flex + cursor:grab），
   复用会被样式表里更靠后的定义压住（这个坑 app.css:2046 已经记过一次）。
   ================================================================ */
.fcard {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--sh-1);
  padding: var(--gap-4);
  margin-bottom: var(--gap-4);
}

.fcard__head {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--gap-2);
  padding-bottom: var(--gap-2);
  border-bottom: 1px solid var(--line);
}
.fcard__qlink {
  font-size: 13px; font-weight: 600;
  color: var(--accent); text-decoration: none;
}
.fcard__qlink:hover { text-decoration: underline; }
.fcard__meta { font-size: 12px; color: var(--text-3); }

/* 状态徽章：四个状态各一色，扫一眼就知道这堆图里哪些要动手 */
.fcard__state {
  font-size: 12px; font-weight: 600;
  padding: 1px 8px; border-radius: var(--radius-pill);
}
.fcard__state--pending { background: var(--surface-3); color: var(--text-2); }
.fcard__state--ok      { background: var(--ok-soft);     color: var(--ok); }
.fcard__state--issue   { background: var(--danger-soft); color: var(--danger); }
.fcard__state--stale   { background: var(--warn-soft);   color: var(--warn); }

.fcard__stem {
  margin: var(--gap-3) 0;
  line-height: 1.9;
  word-break: break-word;
}

/* 对照区：宽屏左右并排，窄屏上下堆叠（几何图横着比才看得清，所以给足宽度） */
.fcard__pair {
  display: flex; flex-wrap: wrap; gap: var(--gap-4);
}
.fcard__side {
  flex: 1 1 240px;
  min-width: 0;                    /* flex 子项默认 min-width:auto，图宽会顶破卡片 */
  margin: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.fcard__side figcaption {
  font-size: 12px; color: var(--text-3);
}
/* 两张对照图统一用同一套内边距与白底：白底是刻意的 ——
   渲染出来的 SVG/PNG 都是白纸黑线，给白底才不会看着"脏"。
   ⚠️ 别写 `width: 100%`：会把小图（库里最窄才 1.59cm）硬拉伸到填满 320px 栏，
   又大又糊。这里跟详情页 `.qfig__img` 一个原则 —— **保持原尺寸、只设上限**，
   超宽才收缩，窄图自然显示。
   #164（2026-10-12）：矩形外框 / 圆角 / 内边距一并撤掉 —— 这是**题目配图**，
   不是截图；硬白底留着（SVG 透明底，见上方 `.qfig__img` 的说明）。 */
.fcard__side img {
  display: block; max-width: 100%; height: auto;
  background: #fff;
}
/* 左栏 TikZ 图另加双闸（与全站 .qfig__img / .qrow__fig 同档，都挂 --fig-max-h）：
   SVG 自带印刷物理尺寸（最大 13.2cm），不限就顶满半栏，两张对照挤在一起。
   只锁左栏 —— 右栏「原卷对应区域」是**整页宽的文字条带**，限高会把字压小到读不了。 */
.fcard__side img.fcard__tikz {
  max-width: min(100%, var(--fig-max-w)); max-height: var(--fig-max-h); width: auto;
}
.fcard__miss {
  padding: 12px 14px;
  background: var(--surface-2);
  border: 1px dashed var(--line-strong);
  border-radius: 8px;
  font-size: 13px; line-height: 1.6; color: var(--text-2);
}
.fcard__miss--bad {
  background: var(--danger-soft); border-color: var(--danger-line); color: var(--danger);
}

.fcard__pts { margin: var(--gap-3) 0 0; }
.fcard__pts code { font-size: 12px; }

/* 动作区：体检按钮靠左，核对表单占右边 */
.fcard__acts {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--gap-3);
  margin-top: var(--gap-3);
  padding-top: var(--gap-3);
  border-top: 1px solid var(--line);
}
.fcard__check { display: inline-flex; }
.fcard__form {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--gap-2);
  margin-left: auto;
}
.fcard__note { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-3); }
/* 备注框要**提一级选择器**写 `input.fcard__note-x`：
   全局那条 `input[type="text"]{width:100%;min-height:38px}` 权重是 (0,1,1)，
   只写类名 (0,1,0) 收不回来（分页条那个框踩过一次，见第 4 节的注释）。 */
input.fcard__noteinput {
  width: 240px; min-height: 30px; height: 30px;
  font-size: 13px;
}
@media (max-width: 720px) {
  .fcard__form { margin-left: 0; width: 100%; }
  input.fcard__noteinput { width: 100%; }
  .fcard__note { width: 100%; }
}

/* ================================================================
   14. 题目详情页：快速编辑 + 备注留言（2026-10-06 用户要求）
   ----------------------------------------------------------------
   「✎ 改」用 <details> 做展开，零 JS 依赖；提交走 POST → 303 回详情页，
   派生字段/质检/修订记录由后台自动更新。类名 qedit / qnotes 都是新生，
   不与 .qcard__* / .hist（审核页历史）抢名 —— .hist 直接复用不重定义。
   ================================================================ */

/* 内容块的标题行：左边「题干」右边「✎ 改」。
   flex-wrap 是给展开态准备的：details 一旦 open，让它整体换行、独占一整行
   （不然编辑框会挤在「题干」两个字的右边，标题行被撑得老高）。 */
.qcard__headrow {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-3); flex-wrap: wrap;
}
.qcard__headrow .qedit[open] { flex-basis: 100%; }

.qedit { position: relative; }
.qedit__btn {
  cursor: pointer; user-select: none;
  font-size: 12.5px; font-weight: 500; color: var(--text-2);
  padding: 3px 10px; border: 1px solid var(--line); border-radius: var(--radius-pill);
  background: var(--surface);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              background var(--dur) var(--ease);
  list-style: none;                       /* 去掉 details 自带的三角 */
}
.qedit__btn::-webkit-details-marker { display: none; }
.qedit__btn:hover { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.qedit[open] > summary.qedit__btn { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }

/* 展开后的编辑框：占一行，别挤在标题旁边 */
.qedit__form {
  margin-top: var(--gap-3);
  padding: var(--gap-3);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.qedit__form .hint { margin: 6px 0 0; }
.qedit__ta {
  width: 100%; min-height: 0; font-size: 13px; line-height: 1.6;
  font-family: var(--font-mono);
}
.qedit__actions { display: flex; gap: var(--gap-2); margin-top: var(--gap-2); }

/* 解析是 details.panel，里面的 qedit 展开框别被折叠内容的缩进影响 */
details.panel .qedit__form { background: var(--surface); }

/* ---------- 备注与留言 ---------- */
.qnotes__count {
  display: inline-block; min-width: 20px; text-align: center;
  padding: 1px 7px; border-radius: var(--radius-pill);
  background: var(--accent-soft); color: var(--accent-ink);
  font-size: 12px; font-weight: 600; vertical-align: 2px;
}
.qnotes__list { list-style: none; margin: 0 0 var(--gap-4); padding: 0; }
.qnote {
  padding: var(--gap-3) 0;
  border-top: 1px solid var(--line);
}
.qnote:last-child { border-bottom: 1px solid var(--line); }
.qnote__head {
  display: flex; gap: var(--gap-3); align-items: baseline;
  margin-bottom: 4px; font-size: 12.5px;
}
.qnote__by { font-weight: 600; color: var(--text); }
.qnote__at { color: var(--text-3); font-variant-numeric: tabular-nums; }
.qnote__body { font-size: 14px; }

.qnotes__form { margin-top: var(--gap-4); }
.qnotes__ta { width: 100%; font-size: 14px; }
.qnotes__actions { display: flex; justify-content: flex-end; margin-top: var(--gap-2); }

/* ---------- 列表行的操作组 ---------- */
.qrow__acts {
  display: flex; flex-direction: column; gap: var(--gap-2);
  align-items: stretch;
}
.qrow__notebtn { position: relative; }
.qrow__notecount {
  display: inline-block; min-width: 16px; text-align: center;
  padding: 0 5px; border-radius: var(--radius-pill);
  background: var(--accent-soft); color: var(--accent-ink);
  font-size: 11px; font-weight: 600;
}
@media (max-width: 720px) {
  .qrow__side { width: 100%; }
  .qrow__acts { flex-direction: row; flex-wrap: wrap; }
}


/* ================================================================
   16. 原卷库（/library）：上传的整份试卷原件，按学校归档
   —— 与「归档树」(.archtree) 的区别写在 routers/library.py 开头，
      这里只管样式。整段只用 1 节设计令牌，不引新颜色。
   ================================================================ */

/* ---- 上传区：用原生 <details> 折叠，库里已有卷子时默认收起 ---- */
.libup { margin-bottom: var(--gap-5); }
.libup__sum {
  cursor: pointer; margin-bottom: var(--gap-3);
  list-style: none;              /* 去掉默认三角，改用下面的 ::before 自绘 */
  display: flex; align-items: center; gap: var(--gap-2);
}
.libup__sum::-webkit-details-marker { display: none; }
.libup__sum::before {
  content: "＋"; color: var(--accent); font-weight: 700;
  transition: transform var(--dur) var(--ease);
}
.libup[open] > .libup__sum::before { content: "－"; }
.libup > .stack { margin-top: var(--gap-3); }

/* 上传 / 编辑表单里的两列网格：窄屏自动落成单列 */
.libgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--gap-4);
}

/* ---- 分组：一个学校一段 ---- */
.libgroup { margin-bottom: var(--gap-5); }
.libgroup__name {
  display: flex; align-items: center; gap: var(--gap-2);
  font-size: var(--fs-lg); font-weight: 600;
  padding-bottom: var(--gap-2); margin-bottom: var(--gap-3);
  border-bottom: 2px solid var(--accent-line);
}
.libgroup__name a { color: var(--text); }
.libgroup__name a:hover { color: var(--accent-hover); }
.libgroup__n {
  display: inline-block; min-width: 22px; text-align: center;
  padding: 1px 7px; border-radius: var(--radius-pill);
  background: var(--accent-soft); color: var(--accent-ink);
  font-size: var(--fs-xs); font-weight: 600;
}

/* ---- 卷子卡片：左内容 + 右操作；「改信息」展开时占满整行 ---- */
.librows {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--gap-3);
}
.librow {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--gap-3) var(--gap-4);
  align-items: start;
  padding: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--sh-1);
}
/* min-width:0 不可省：长卷名会把网格列顶宽，整页横向滚动 */
.librow__main { min-width: 0; }
.librow__title {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap-2);
  font-size: var(--fs-base); font-weight: 600; line-height: 1.6;
  word-break: break-word;
}
.librow__meta {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 2px var(--gap-4); margin-top: var(--gap-2);
  font-size: var(--fs-sm); color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.librow__note {
  margin-top: var(--gap-2); font-size: var(--fs-sm); color: var(--text-2);
  padding-left: var(--gap-2); border-left: 2px solid var(--line-strong);
}
.librow__acts {
  display: flex; flex-wrap: wrap; gap: var(--gap-2);
  align-items: flex-start; justify-content: flex-end;
}
.librow__inline { display: inline; }
/* 展开的编辑面板横跨整行：挤在右侧按钮栏里会窄得没法填 */
.librow__edit { grid-column: 1 / -1; }
.librow__editsum { list-style: none; display: inline-block; }
.librow__editsum::-webkit-details-marker { display: none; }
.librow__form {
  margin-top: var(--gap-3); padding: var(--gap-4);
  background: var(--surface-2); border-radius: var(--radius-sm);
}

@media (max-width: 860px) {
  .librow { grid-template-columns: minmax(0, 1fr); }
  .librow__acts { justify-content: flex-start; }
}

/* ---- 年级标签：和知识点同为「冷青点缀」一族，视觉上区分于分类/题型 ---- */
.tag--grade { background: var(--cool-soft); border-color: var(--cool-line); color: var(--cool-ink); }

/* ---- 面包屑 ---- */
.crumbs {
  display: flex; align-items: center; gap: var(--gap-2);
  font-size: var(--fs-sm); color: var(--text-3);
  margin-bottom: var(--gap-3);
}
.crumbs a { color: var(--text-2); }
.crumbs a:hover { color: var(--accent-hover); }
.crumbs__sep { color: var(--text-3); }

/* ================================================================
   16b. 原卷库 · 入口三选项卡 + 导入页（2026-10-08 重做）
   ================================================================ */

/* ---- 入口：三个大选项卡 ---- */
.libhub {
  display: grid; gap: var(--gap-5);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.libhub__card {
  display: flex; flex-direction: column; gap: var(--gap-2);
  padding: var(--gap-6) var(--gap-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--sh-1);
  text-decoration: none; color: var(--text);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.libhub__card:hover {
  text-decoration: none; transform: translateY(-3px);
  box-shadow: var(--sh-3);
}
.libhub__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 54px; height: 54px; border-radius: var(--radius);
  margin-bottom: var(--gap-2);
}
.libhub__card--ps .libhub__icon { background: var(--accent-soft); color: var(--accent-hover); }
.libhub__card--jr .libhub__icon { background: var(--cool-soft); color: var(--cool-hover); }
.libhub__card--imp .libhub__icon {
  background: linear-gradient(135deg, var(--accent-soft), var(--cool-soft));
  color: var(--accent-hover);
}
.libhub__card--ps:hover { border-color: var(--accent-line); }
.libhub__card--jr:hover { border-color: var(--cool-line); }
.libhub__title { font-size: var(--fs-2xl); font-weight: 700; line-height: 1.2; }
.libhub__desc { font-size: var(--fs-md); color: var(--text-2); line-height: 1.7; flex: 1; }
.libhub__count {
  margin-top: var(--gap-2);
  font-size: var(--fs-sm); color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.libhub__go {
  margin-top: var(--gap-1);
  font-size: var(--fs-md); font-weight: 600;
  color: var(--accent-hover);
}
.libhub__card--jr .libhub__go { color: var(--cool-hover); }

/* ---- 最近导入记录 ---- */
.libhub__recent { margin-top: var(--gap-6); }
.libhub__reclist { list-style: none; margin: var(--gap-3) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--gap-2); }
.libhub__rec {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap-2) var(--gap-3);
  font-size: var(--fs-sm); color: var(--text-2);
  padding: var(--gap-2) 0; border-bottom: 1px dashed var(--line);
}
.libhub__rec:last-child { border-bottom: none; }
.libhub__recmode { color: var(--text-3); white-space: nowrap; }
.libhub__recnames { flex: 1; min-width: 0; color: var(--text); word-break: break-word; }
.libhub__rectime { color: var(--text-3); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* ---- 导入页 ---- */
.libimp { max-width: 860px; margin: 0 auto; }
.libimp__step {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-5);
  margin-bottom: var(--gap-4);
  box-shadow: var(--sh-1);
}
.libimp__steptitle {
  display: flex; align-items: center; gap: var(--gap-3);
  font-size: var(--fs-lg); font-weight: 600; margin-bottom: var(--gap-4);
}
.libimp__num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--radius-pill);
  background: var(--accent); color: var(--on-solid);
  font-size: var(--fs-sm); font-weight: 700;
}
.libimp__targets { display: grid; gap: var(--gap-4); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.libimp__target {
  position: relative; cursor: pointer;
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--gap-4) var(--gap-5);
  border: 1.5px solid var(--line); border-radius: var(--radius);
  background: var(--surface-2);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.libimp__target input { position: absolute; opacity: 0; pointer-events: none; }
.libimp__targetname { font-size: var(--fs-xl); font-weight: 700; }
.libimp__targetdesc { font-size: var(--fs-sm); color: var(--text-3); }
.libimp__target--ps:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent-line); }
.libimp__target--jr:has(input:checked) { border-color: var(--cool); background: var(--cool-soft); box-shadow: inset 0 0 0 1px var(--cool-line); }

/* 拖拽区 */
.dropzone {
  border: 2px dashed var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
  padding: var(--gap-7) var(--gap-5);
  text-align: center; cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
  outline: none;
}
.dropzone:hover, .dropzone:focus-visible { border-color: var(--accent); }
.dropzone.is-drag {
  border-color: var(--accent); background: var(--accent-soft);
  box-shadow: inset 0 0 0 2px var(--accent-line);
}
.dropzone__inner { display: flex; flex-direction: column; align-items: center; gap: var(--gap-2); color: var(--text-3); }
.dropzone.is-drag .dropzone__inner { color: var(--accent-hover); }
.dropzone__main { font-size: var(--fs-lg); font-weight: 600; color: var(--text); }
.dropzone__pick {
  border: none; background: none; padding: 0; margin: 0;
  color: var(--accent-hover); font: inherit; font-weight: 700; cursor: pointer;
  text-decoration: underline;
}
.dropzone__hint { font-size: var(--fs-sm); color: var(--text-3); }
.libimp__filelist {
  margin-top: var(--gap-3); font-size: var(--fs-sm); color: var(--text-2);
  font-variant-numeric: tabular-nums; word-break: break-word;
}
.libgrid__wide { grid-column: 1 / -1; }
.libimp__recent { margin-top: var(--gap-6); }

@media (max-width: 600px) {
  .libhub__card { padding: var(--gap-5); }
  .dropzone { padding: var(--gap-5) var(--gap-3); }
}

/* ================================================================
   17. 登录 / 注册（2026-10-10 重做：左侧品牌面板 + 右侧表单卡）
   —— 模板见 templates/auth/_base.html（两页共用一个外壳）。

   颜色约定：除左栏那块「品牌面」外，其余一律走第 1 节令牌。
   左栏**故意写死色值**：它是一张不随页面主题变化的海报面 —— 底色要做到
   白字 4.5:1 以上（所以是深珊瑚而不是亮珊瑚），跟着 --accent 走的话，
   深色模式下 --accent 会被提亮成浅橙，白字直接糊掉。
   ================================================================ */

/* ---- 整屏画布 ----
   顶栏在这两页整体不渲染（auth/_base.html 清空了 base.html 的 topbar 块），
   所以主区直接顶到页面最上沿，右栏底色一直铺到页脚。 */
.authpage .wrap {
  flex: 1 1 auto;
  display: flex;
  max-width: none;
  padding: 0;
}
/* 页脚在这两页整体撤掉：它是给「有顶栏有导航」的页面收尾用的，
   摆在一块整屏画布下面只会把画布切成两半。版本号与「运行状态」入口
   改挂在左栏底部那行小字上（见 auth/_base.html）。 */
.authpage .foot { display: none; }

.authshell {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
  align-items: stretch;
}

/* ================= 左栏：品牌面 ================= */
.authaside {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--gap-6);
  padding: var(--gap-7) var(--gap-7) var(--gap-6);
  color: #fff;
  background:
    radial-gradient(120% 78% at 92% -8%, rgba(255, 176, 130, .52) 0%, rgba(255, 176, 130, 0) 56%),
    radial-gradient(96% 72% at -8% 106%, rgba(15, 138, 157, .46) 0%, rgba(15, 138, 157, 0) 62%),
    linear-gradient(158deg, #c8492a 0%, #b03d1c 48%, #77270f 100%);
}

/* 点阵格子：只在左上角显影，往右下淡出 —— 一块「稿纸」的暗示 */
.authaside__grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: radial-gradient(rgba(255, 255, 255, .17) 1px, transparent 1px);
  background-size: 24px 24px;
  -webkit-mask-image: radial-gradient(120% 92% at 10% 4%, #000 0%, transparent 70%);
          mask-image: radial-gradient(120% 92% at 10% 4%, #000 0%, transparent 70%);
}

/* 漂浮的数学符号：极淡，斜着铺在右半边；鼠标划过时整层跟着轻微视差（auth.js）。
   容器做视差、每个字自己上下飘，两层动画互不打架。 */
.authaside__glyphs {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transition: transform .5s var(--ease);
}
.authaside__glyphs span {
  position: absolute;
  font-family: "Times New Roman", Georgia, "Songti SC", serif;
  font-weight: 700;
  line-height: 1;
  color: rgba(255, 255, 255, .13);
  will-change: transform;
  animation: authdrift 10s ease-in-out infinite;
}
/* ⚠️ 一律落在 left ≥ 68%：左栏正文（标题 + 功能清单）最宽到 30em ≈ 69%，
   符号压进去就会显得「字背后有脏东西」——它们只是纸纹，不该抢字。 */
.authaside__glyphs span:nth-child(1) { top: 6%;  left: 70%; font-size: 58px; animation-duration: 11s; }
.authaside__glyphs span:nth-child(2) { top: 23%; left: 86%; font-size: 42px; animation-duration: 13s; animation-delay: -2s; }
.authaside__glyphs span:nth-child(3) { top: 40%; left: 72%; font-size: 34px; animation-duration: 9s;  animation-delay: -4s; }
.authaside__glyphs span:nth-child(4) { top: 57%; left: 88%; font-size: 48px; animation-duration: 12s; animation-delay: -1s; }
.authaside__glyphs span:nth-child(5) { top: 73%; left: 70%; font-size: 38px; animation-duration: 10s; animation-delay: -6s; }
.authaside__glyphs span:nth-child(6) { top: 11%; left: 90%; font-size: 30px; animation-duration: 14s; animation-delay: -3s; }
.authaside__glyphs span:nth-child(7) { top: 86%; left: 87%; font-size: 40px; animation-duration: 11s; animation-delay: -5s; }
.authaside__glyphs span:nth-child(8) { top: 46%; left: 92%; font-size: 26px; animation-duration: 15s; animation-delay: -7s; }

@keyframes authdrift {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
  50%      { transform: translate3d(-6px, -18px, 0) rotate(-4deg); }
}

/* 极光层：两团大范围柔光极慢地来回移动，给纯色渐变加一点"活气"。
   刻意做得非常淡（透明度 .5 上下、blur 很大）—— 这是底色，不是主角；
   太多或者太亮就会把白字衬花。prefers-reduced-motion 下直接停掉。 */
.authaside__aurora {
  position: absolute;
  inset: -20%;
  pointer-events: none;
  opacity: .5;
  background:
    radial-gradient(closest-side, rgba(255, 205, 168, .75), transparent 70%) 18% 22% / 62% 62% no-repeat,
    radial-gradient(closest-side, rgba(15, 138, 157, .62), transparent 72%) 84% 78% / 58% 58% no-repeat;
  filter: blur(26px);
  animation: authaurora 22s ease-in-out infinite alternate;
}

@keyframes authaurora {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(4%, -3%, 0) scale(1.06); }
  100% { transform: translate3d(-3%, 3%, 0) scale(1.02); }
}

@media (prefers-reduced-motion: reduce) {
  .authaside__aurora,
  .authaside__glyphs span,
  .authticker__track { animation: none !important; }
}

.authaside__inner { position: relative; z-index: 1; max-width: 30em; }

.authbrand {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-3);
  margin-bottom: var(--gap-7);
  color: #fff;
  text-decoration: none;
}
.authbrand:hover { color: #fff; text-decoration: none; }
.authbrand__mark {
  flex: none;
  width: 42px; height: 42px;
  /* 垫一圈白底：logo 本身是珊瑚色渐变，直接摆在同色系的品牌面上会融成一块
     （顶栏里它衬在暖白底上才好看）。padding + border-box 把图形缩进 3px，
     白边就成了「托盘」。 */
  padding: 3px;
  background: #fff;
  border-radius: 13px;
  box-shadow: 0 4px 14px -3px rgba(0, 0, 0, .45);
}
.authbrand__name { font-size: var(--fs-lg); font-weight: 650; letter-spacing: .02em; }

.authaside__title {
  margin: 0 0 var(--gap-3);
  font-size: var(--fs-3xl);
  font-weight: 650;
  line-height: 1.42;
  letter-spacing: .01em;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .16);
}
.authaside__lead {
  margin: 0 0 var(--gap-6);
  font-size: var(--fs-md);
  color: rgba(255, 255, 255, .9);
}

.authfeat { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--gap-4); }
.authfeat__item { display: flex; gap: var(--gap-3); align-items: flex-start; }
.authfeat__icon {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border-radius: 10px;
  background: rgba(255, 255, 255, .16);
  border: 1px solid rgba(255, 255, 255, .26);
  color: #fff;
}
.authfeat__icon svg { width: 18px; height: 18px; }
/* 功能行：鼠标扫过时整行轻微右移，像「被点了一下」。只是视觉暗示，不是可点元素。 */
.authfeat__item { transition: transform var(--dur) var(--ease); }
.authfeat__item:hover { transform: translateX(3px); }
.authfeat__txt { font-size: var(--fs-md); line-height: 1.6; color: rgba(255, 255, 255, .92); }
.authfeat__txt b { display: block; color: #fff; font-weight: 650; }

/* 能力标签条：介于「一句话介绍」与「三条功能」之间的信息层。
   半透明描边胶囊，轻，但一眼能看到这站支持什么。 */
.authchips {
  list-style: none;
  margin: 0 0 var(--gap-6);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-width: 26em;
}
.authchip {
  padding: 5px 12px;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: rgba(255, 255, 255, .95);
  background: rgba(255, 255, 255, .13);
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: 999px;
  backdrop-filter: blur(2px);
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
/* 一点「活气」：鼠标扫过时轻微上浮 + 提亮。纯装饰，不影响可读性。 */
.authchip:hover {
  transform: translateY(-1px);
  background: rgba(255, 255, 255, .22);
  border-color: rgba(255, 255, 255, .46);
}

/* 底部公式走马灯：轨道里放**两份完全相同**的内容，整体匀速左移 50%
   （正好等于一份的宽度）→ 第一份滚出去时第二份无缝补位，循环处看不出接缝。
   ⚠️ 轨道必须 `width: max-content`（不能被压窄），否则 -50% 的距离与内容宽度对不上会跳。 */
.authticker {
  position: relative;
  z-index: 1;
  overflow: hidden;
  margin: 0 calc(-1 * var(--gap-7));
  padding: var(--gap-3) 0;
  border-top: 1px solid rgba(255, 255, 255, .18);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.authticker__track {
  display: flex;
  width: max-content;
  gap: var(--gap-7);
  white-space: nowrap;
  font-family: "Times New Roman", Georgia, serif;
  font-size: var(--fs-md);
  color: rgba(255, 255, 255, .62);
  animation: authtick 42s linear infinite;
}
@keyframes authtick {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

.authaside__foot {
  position: relative; z-index: 1;
  margin: 0;
  font-size: var(--fs-xs);
  color: rgba(255, 255, 255, .72);
  line-height: 1.9;
}
.authaside__link { color: rgba(255, 255, 255, .92); text-decoration: underline; text-underline-offset: 3px; }
.authaside__link:hover { color: #fff; }

/* ================= 右栏：表单 ================= */
.authmain {
  position: relative;
  display: flex;
  align-items: stretch;      /* 由卡片的 margin:auto 负责居中，别用 align-items:center */
  justify-content: center;
  padding: var(--gap-7) var(--gap-5);
  background: var(--bg);
}
/* 右栏底纹：一层极淡的点阵 + 右上角一点暖光，呼应左栏的"稿纸"暗示。
   全部走 ::before 且 pointer-events:none —— 不碰布局、不吃点击。 */
.authmain::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    radial-gradient(circle at 88% 6%, color-mix(in srgb, var(--accent) 9%, transparent), transparent 46%),
    radial-gradient(color-mix(in srgb, var(--text-3) 18%, transparent) 1px, transparent 1px);
  background-size: 100% 100%, 26px 26px;
  -webkit-mask-image: radial-gradient(120% 100% at 50% 0%, #000 0%, transparent 78%);
          mask-image: radial-gradient(120% 100% at 50% 0%, #000 0%, transparent 78%);
}
.authmain > * { position: relative; z-index: 1; }

.authcard {
  width: 100%;
  max-width: 420px;
  /* 🔴 margin:auto 而不是 align-items:center —— 注册页在手机上比屏幕还高，
     flex 的居中对「比容器高的子项」会**从顶部裁掉**（经典 flex 陷阱，
     用户看到的是第一项被砍掉的半截卡片）。auto 外边距只在有富余空间时才居中，
     不够高的时候老老实实从顶部开始、正常滚动。 */
  margin: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--gap-6) var(--gap-6) var(--gap-5);
  box-shadow: var(--sh-3);
  animation: authrise .44s var(--ease) both;
}
/* 注册字段多，卡片放宽一点，不然六个字段挤成一条 */
.authcard:has(.aform--register) { max-width: 464px; }

@keyframes authrise {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

.authcard__title { font-size: var(--fs-2xl); font-weight: 650; text-align: left; margin: 0 0 var(--gap-2); }
/* 「内部工具站 · 仅限授权账号」：一枚小圆点 + 小字。
   放在标题上方当"眉标"，比直接顶一个 h1 更有层次。 */
.authcard__eyebrow {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0 0 var(--gap-3);
  font-size: var(--fs-sm);
  letter-spacing: .02em;
  color: var(--text-3);
}
.authcard__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.authcard__sub   { margin: 0 0 var(--gap-5); text-align: left; font-size: var(--fs-md); color: var(--text-2); }
.authcard__foot  { margin: var(--gap-5) 0 0; text-align: center; font-size: var(--fs-md); color: var(--text-2); }
/* 登录卡片底部那两行（忘记密码 / 还没有账号）—— 第一行走得近一点，看起来是一组。
   ⚠️ 单独一个类名，不合用 .authcard__foot：Playwright 严格模式按 `.authcard__foot`
   取元素，一页两个会直接报错（2026-10-10 踩过）。 */
.authcard__forgot { margin: var(--gap-4) 0 0; text-align: center; font-size: var(--fs-md); color: var(--text-2); }

/* 改密码页下半段「绑定邮箱/手机号」：一条细分割线 + 一个小标题。
   同一张卡片里放两组表单，靠分隔线划清边界，不然会看成一个大表单。 */
.authcard__sep { height: 1px; margin: var(--gap-6) 0 var(--gap-5); background: var(--line); border: 0; }
.authcard__h2 { margin: 0 0 6px; text-align: left; font-size: var(--fs-lg); font-weight: 700; color: var(--text); }
.authcard__sub--sm { font-size: var(--fs-sm); margin-bottom: var(--gap-4); }

/* 带着错误回来时抖一下：动静很小，但能立刻把视线拉到那句话上 */
.authcard__alert { animation: authshake .42s var(--ease) both; }
@keyframes authshake {
  0%   { transform: translateX(0); }
  18%  { transform: translateX(-6px); }
  38%  { transform: translateX(5px); }
  58%  { transform: translateX(-3px); }
  78%  { transform: translateX(2px); }
  100% { transform: translateX(0); }
}

/* ---- 字段 ---- */
.aform .afield { position: relative; margin-bottom: var(--gap-4); }

.afield__label {
  display: block;
  margin-bottom: 6px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-2);
}
.afield__req { color: var(--danger); font-weight: 400; }
.afield__opt { color: var(--text-3); font-weight: 400; font-size: var(--fs-xs); }

.afield__wrap { position: relative; }

/* ⚠️ 选择器要带 .afield__wrap 前缀：第 4 节 `input[type="text"] { height: 38px }`
   的权重是 (0,1,1)，只写类名收不回来；这里同为 (0,1,1) 但源码在后，才压得住。 */
.afield__wrap > input {
  height: 44px;
  min-height: 44px;
  padding-left: 42px;
  border-radius: var(--radius);
  font-size: var(--fs-base);
}
/* 有眼睛按钮的（密码类）右边才留位置；没按钮的字段留一大块空白会显得错位 */
.afield__wrap:has(.afield__eye) > input { padding-right: 44px; }

.afield__icon {
  position: absolute;
  left: 13px; top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  width: 18px; height: 18px;
  color: var(--text-3);
  pointer-events: none;
  transition: color var(--dur) var(--ease);
}
.afield__icon svg { width: 100%; height: 100%; }
.afield__wrap:focus-within .afield__icon { color: var(--accent); }

.afield__wrap > input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
}

.afield__eye {
  position: absolute;
  right: 5px; top: 50%;
  transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-3);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.afield__eye:hover { background: var(--surface-2); color: var(--text); }
.afield__eye svg { width: 19px; height: 19px; }
.afield__eye-closed { display: none; }
.afield__eye[aria-pressed="true"] .afield__eye-open { display: none; }
.afield__eye[aria-pressed="true"] .afield__eye-closed { display: block; }

/* 「获取验证码」按钮：贴在验证码输入框右端（与眼睛按钮同一处，互斥使用）。
   倒计时期间用 [disabled] 锁住 —— 但**别用 opacity:.5**，那会让人看不清还有几秒。 */
.afield__otp {
  position: absolute;
  right: 4px; top: 50%;
  transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 96px; height: 36px;
  padding: 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--accent);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.afield__otp:hover:not([disabled]) { background: var(--accent-soft); border-color: var(--accent); }
.afield__otp[disabled] { cursor: default; color: var(--text-3); background: var(--surface-2); }
/* 带这个按钮的字段，右边要给按钮留出位置（与眼睛按钮同理） */
.afield__wrap:has(.afield__otp) > input { padding-right: 112px; }

/* 大写锁定提示：贴到「密码」这一行的右端（.afield 是 relative，wrap 不是它爹）。
   ⚠️ 必须自己写 [hidden] 规则 —— 下面 display 一写就把 UA 的 [hidden]{display:none} 顶掉了。 */
.afield__caps {
  position: absolute;
  right: 0; top: 0;
  display: inline-flex; align-items: center;
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  background: var(--warn-soft);
  border: 1px solid var(--warn-line);
  color: var(--warn);
  font-size: var(--fs-xs);
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
  animation: authpop .18s var(--ease) both;
}
.afield__caps[hidden] { display: none; }

/* 就地校验的红字。:empty 时整块撤掉，免得空占一行高 */
.afield__msg { margin: 5px 0 0; font-size: var(--fs-xs); line-height: 1.5; color: var(--danger); }
.afield__msg:empty { display: none; }
.afield__msg.is-shown { animation: authpop .2s var(--ease) both; }
/* 「获取验证码」的回执（otp.js 写进来的）成功时走绿色，别跟报错一个颜色 */
.afield__msg.is-ok { color: var(--ok); }

@keyframes authpop {
  from { opacity: 0; transform: translateY(-3px); }
  to   { opacity: 1; transform: none; }
}

.afield.is-bad .afield__wrap > input {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px var(--danger-soft);
}
.afield.is-bad .afield__icon { color: var(--danger); }

/* ---- 密码强度条 ---- */
.astrength { display: flex; align-items: center; gap: var(--gap-3); margin-top: 8px; }
.astrength[hidden] { display: none; }
.astrength__bars { display: flex; gap: 4px; flex: 1; }
.astrength__bars i {
  flex: 1; height: 5px;
  border-radius: var(--radius-pill);
  background: var(--line-strong);
  transition: background var(--dur) var(--ease);
}
.astrength__text {
  min-width: 2.6em; text-align: right;
  font-size: var(--fs-xs); color: var(--text-3); white-space: nowrap;
}
.astrength[data-level="1"] .astrength__bars i:nth-child(-n+1) { background: var(--danger); }
.astrength[data-level="2"] .astrength__bars i:nth-child(-n+2) { background: var(--warn); }
.astrength[data-level="3"] .astrength__bars i:nth-child(-n+3) { background: var(--accent); }
.astrength[data-level="4"] .astrength__bars i:nth-child(-n+4) { background: var(--ok); }
.astrength[data-level="1"] .astrength__text { color: var(--danger); }
.astrength[data-level="2"] .astrength__text { color: var(--warn); }
.astrength[data-level="3"] .astrength__text { color: var(--accent-hover); }
.astrength[data-level="4"] .astrength__text { color: var(--ok); }

/* ---- 身份选择：两个并排的大块（原生的 radio 藏起来，靠 label 点） ---- */
.aseg { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-3); }
.aseg__opt { position: relative; cursor: pointer; }
.aseg__opt input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.aseg__box {
  display: block;
  padding: var(--gap-3) var(--gap-4);
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.aseg__box b { display: block; font-size: var(--fs-md); font-weight: 650; color: var(--text); }
.aseg__box em { display: block; margin-top: 2px; font-style: normal; font-size: var(--fs-xs); color: var(--text-3); }
.aseg__opt:hover .aseg__box { border-color: var(--accent-line); }
.aseg__opt input:checked + .aseg__box {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent-line);
}
.aseg__opt input:checked + .aseg__box b { color: var(--accent-ink); }
.aseg__opt input:focus-visible + .aseg__box { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- 主按钮 ----
   独立的 .abtn 而不是复用 .btn：这一页的按钮要更高更宽、字号更大，
   还要能挂转圈和「扫光」，塞进 .btn 的小尺寸体系里只会互相打架。 */
.abtn {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap-2);
  width: 100%;
  height: 46px;
  margin-top: var(--gap-2);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--accent-hi) 0%, var(--accent) 48%, var(--accent) 100%);
  color: var(--on-solid);
  font: inherit;
  font-size: var(--fs-lg);
  font-weight: 600;
  letter-spacing: .05em;
  cursor: pointer;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--accent) 24%, transparent),
              0 6px 16px -6px color-mix(in srgb, var(--accent) 52%, transparent);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              background var(--dur) var(--ease);
}
/* ⚠️ 必须自己写 :hover 的颜色：全站 `a:hover { color: var(--accent-hover) }`
   的权重 (0,1,1) 压得过光写类名的 `.abtn` (0,1,0)，否则注册成功页那个
   <a class="abtn">「去登录」一悬停就变成深橙底 + 深橙字，直接看不见。 */
.abtn:hover {
  background: linear-gradient(180deg, var(--accent) 0%, var(--accent-hover) 100%);
  color: var(--on-solid);
  transform: translateY(-1px);
  box-shadow: 0 2px 4px color-mix(in srgb, var(--accent) 26%, transparent),
              0 10px 24px -8px color-mix(in srgb, var(--accent) 58%, transparent);
}
.abtn:active { transform: translateY(1px); }
.abtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* 提交中：不能再点（用 class 挡住，不用 disabled —— 见 auth.js 里的说明） */
.abtn.is-busy { pointer-events: none; filter: saturate(.7) brightness(1.05); }

/* 悬停时一道斜向扫光掠过按钮 —— 只在 hover 触发一次，不循环闪 */
.abtn::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 24%, rgba(255, 255, 255, .32) 50%, transparent 76%);
  transform: translateX(-130%);
  pointer-events: none;
}
.abtn:hover::after { animation: authsheen .75s var(--ease) both; }
@keyframes authsheen {
  from { transform: translateX(-130%); }
  to   { transform: translateX(130%); }
}

.abtn__spin {
  display: none;
  width: 16px; height: 16px;
  flex: none;
  border: 2px solid color-mix(in srgb, var(--on-solid) 32%, transparent);
  border-top-color: var(--on-solid);
  border-radius: var(--radius-pill);
  animation: authspin .7s linear infinite;
}
.abtn.is-busy .abtn__spin { display: inline-block; }
@keyframes authspin { to { transform: rotate(360deg); } }

/* 注册成功页 */
.adone { text-align: center; }
.adone__mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 58px; height: 58px;
  margin: 0 auto var(--gap-4);
  border-radius: var(--radius-pill);
  background: var(--ok-soft);
  border: 1px solid var(--ok-line);
  color: var(--ok);
  animation: authpop .3s var(--ease) both;
}
.adone__mark svg { width: 28px; height: 28px; }
.adone .authcard__title,
.adone .authcard__sub { text-align: center; }

/* ---- 窄屏：左栏收成顶部一条品牌带，右栏表单居中 ---- */
@media (max-width: 900px) {
  .authshell { grid-template-columns: minmax(0, 1fr); }
  .authaside { gap: var(--gap-4); padding: var(--gap-5) var(--gap-5) var(--gap-4); }
  .authaside__inner { max-width: none; }
  .authbrand { margin-bottom: var(--gap-4); }
  .authaside__title { font-size: var(--fs-xl); margin-bottom: var(--gap-2); }
  .authaside__lead { margin-bottom: 0; font-size: var(--fs-sm); }
  /* 功能清单与漂浮符号在窄屏撤掉，只留「我们是谁」；
     底部那行小字（含「运行状态」入口）保留 —— 页脚全站已撤，这行是它在这两页的替身。 */
  .authfeat,
  .authaside__glyphs { display: none; }
  .authmain { padding: var(--gap-5) var(--gap-4); }
}

@media (max-width: 560px) {
  .authmain { padding: var(--gap-4) var(--gap-3) var(--gap-5); }
  .authcard { padding: var(--gap-5) var(--gap-4); border-radius: var(--radius); }
  .authcard__title { font-size: var(--fs-xl); }
  .aseg { grid-template-columns: minmax(0, 1fr); }
}


/* ============================================================
   学生档案与学情反馈（切片 22，2026-10-10 用户需求③）
   色彩一律走令牌 —— 深色模式自动跟随，这一节不需要单独写覆盖。
   ============================================================ */

/* ---- 班型小色点：列表 / 档案 / 班型管理三处共用 ---- */
.ctdot {
  display: inline-block;
  width: 9px; height: 9px;
  margin-right: 5px;
  border-radius: 50%;
  vertical-align: baseline;
  box-shadow: 0 0 0 2px var(--surface);
  flex: none;
}

/* ---- 列表页：班型筛选条 ---- */
.stutabs { display: flex; flex-wrap: wrap; gap: var(--gap-2); margin-bottom: var(--gap-4); }
.stutab {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-2);
  font-size: var(--fs-sm); font-weight: 500;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.stutab:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.stutab.is-active {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent-ink);
  font-weight: 600;
}
.stutab__n { font-size: var(--fs-xs); color: var(--text-3); font-variant-numeric: tabular-nums; }
.stutab.is-active .stutab__n { color: var(--accent-ink); }

/* ---- 列表行 ---- */
.stuname { font-weight: 600; }
.sturow__sub { margin-top: 2px; font-size: var(--fs-xs); }
.sturow__num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.sturow__act { white-space: nowrap; }
.sturow__act .btn + .btn { margin-left: 4px; }

/* ---- 档案页头部 ---- */
.stusub { font-size: var(--fs-lg); font-weight: 500; color: var(--text-3); }
.stumeta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap-2); }

/* ---- 档案信息 ---- */
.stuinfo {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--gap-3) var(--gap-5);
  margin-bottom: var(--gap-4);
}
.stuinfo__k { margin: 0 0 2px; font-size: var(--fs-xs); color: var(--text-3); }
.stuinfo__k--note { margin-top: var(--gap-2); }
.stuinfo__v { margin: 0; font-size: var(--fs-md); word-break: break-word; }
.stuinfo__v--muted { color: var(--text-3); }
.stutags { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.stunote { white-space: pre-wrap; line-height: 1.75; }

/* ---- 上课记录时间线 ---- */
.tl { list-style: none; margin: 0; padding: 0; }
.tl__item { position: relative; padding: 0 0 var(--gap-5) 24px; }
.tl__item::before {
  content: ""; position: absolute; left: 4px; top: 16px; bottom: 0;
  width: 2px; background: var(--line);
}
.tl__item:last-child { padding-bottom: 0; }
.tl__item:last-child::before { display: none; }
.tl__dot {
  position: absolute; left: 0; top: 7px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.tl__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap-2); }
.tl__date { font-weight: 600; font-variant-numeric: tabular-nums; }
.tl__topic { color: var(--text-2); }
.tl__act { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.tl__act form { margin: 0; }
.tl__fb { margin-top: var(--gap-2); }
.tl__fb > summary { cursor: pointer; font-size: var(--fs-sm); color: var(--accent); }

/* ---- 反馈纯文本（微信版）---- */
.fbcopy {
  margin: 0;
  padding: 13px 15px;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: var(--font);
  font-size: var(--fs-md);
  line-height: 1.75;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  max-height: 380px;
  overflow: auto;
}
.tl__fb .fbcopy { margin-top: var(--gap-2); }
/* 复制源：内容藏在 DOM 里给按钮读，不占地方也不用 data- 属性（换行会丢） */
.fbsrc { display: none; }

/* ---- 微信预览的版本切换（原文版 / AI 润色版，2026-10-13 需求⑤）----
   用「分段控件」而不是两枚独立按钮：两版是互斥的，视觉上得看出"在哪一档"。
   ⚠️ 这不是 .tabs（那是页面级导航），是面板内的小开关，所以另起一套类名。 */
.fbtabs {
  display: inline-flex;
  padding: 3px;
  gap: 2px;
  margin-bottom: var(--gap-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.fbtab {
  appearance: none;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--text-2);
  padding: 5px 14px;
  border-radius: calc(var(--radius-sm) - 2px);
  cursor: pointer;
  transition: background .15s, color .15s;
}
.fbtab:hover { color: var(--text); }
.fbtab.is-on {
  background: var(--surface);
  color: var(--accent);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .06);
}
/* 键盘焦点必须看得见（a11y 硬要求，别去掉 outline） */
.fbtab:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* 润色过程/结果的提示条 */
.fbmsg {
  margin: var(--gap-2) 0 0;
  padding: 8px 11px;
  font-size: var(--fs-sm);
  line-height: 1.6;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--text-2);
}
.fbmsg[data-kind="ok"] { color: var(--ok); border-color: var(--ok-line); }
.fbmsg[data-kind="warn"] { color: var(--warn); border-color: var(--warn-line); }

/* ---- 上课记录表单：左填写、右预览 ---- */
.lessongrid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--gap-4);
  align-items: start;
}
.lessongrid > .panel { margin-bottom: 0; }
.lessongrid__main > .panel:last-child { margin-bottom: 0; }
.fbpreview { position: sticky; top: calc(var(--topbar-h) + var(--gap-3)); }
.fbhead {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-2); margin-bottom: 6px;
}
.fbhead label { margin: 0; }
.fbfields textarea { min-height: 96px; }
.lesson-foot {
  display: flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap;
  margin-top: var(--gap-4);
}
.lesson-foot__del { margin: 0 0 0 auto; }

/* 二.3：记课「上课时间」—— 常用时段排成一排药丸按钮，点一下即选，比原生 time 控件好看。 */
.timesel__chips {
  display: flex; flex-wrap: wrap; gap: var(--gap-2);
  margin-bottom: var(--gap-2);
}
.timesel__chip {
  appearance: none; cursor: pointer;
  font: inherit; font-weight: 600; font-size: var(--fs-sm);
  padding: 8px 16px; border-radius: 999px;
  color: var(--accent-ink);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.timesel__chip:hover { border-color: var(--accent); }
.timesel__chip.is-active {
  color: #fff; background: var(--accent); border-color: var(--accent);
  box-shadow: 0 2px 8px rgba(232, 97, 60, .35);
}
.timesel__custom { display: flex; align-items: center; gap: var(--gap-2); }
.timesel__custom input[type="time"] {
  width: auto; flex: 0 1 160px;
}
.timesel__custom input[type="time"]::-webkit-calendar-picker-indicator {
  cursor: pointer; opacity: .65;
  filter: invert(38%) sepia(72%) saturate(1800%) hue-rotate(330deg);
}
.timesel__custom input[type="time"]:hover::-webkit-calendar-picker-indicator { opacity: 1; }
.timesel__or { color: var(--text-3); font-size: var(--fs-sm); white-space: nowrap; }

/* 上课时间「时间段胶囊」（2026-10-16 用户需求）：开始–结束两个 time 控件 +
   常用时段药丸（复用 .timesel__chip）+ 自动算出的时长。 */
.timerange { display: flex; flex-direction: column; gap: var(--gap-2); }
.timerange__inputs { display: flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap; }
.timerange__inputs input[type="time"] {
  width: auto; flex: 0 1 150px;
}
.timerange__inputs input[type="time"]::-webkit-calendar-picker-indicator {
  cursor: pointer; opacity: .65;
  filter: invert(38%) sepia(72%) saturate(1800%) hue-rotate(330deg);
}
.timerange__inputs input[type="time"]:hover::-webkit-calendar-picker-indicator { opacity: 1; }
.timerange__sep { color: var(--text-3); font-size: var(--fs-sm); white-space: nowrap; }
.timerange__chips { display: flex; flex-wrap: wrap; gap: var(--gap-2); }
.timerange__dur {
  font-size: var(--fs-sm); font-weight: 600; color: var(--accent-ink);
  font-variant-numeric: tabular-nums; visibility: hidden;
}
.timerange__dur.is-shown { visibility: visible; }

/* 详情页 / 班级页展示用的上课时间段小胶囊 */
.timepill {
  display: inline-block; font-size: var(--fs-xs); font-weight: 600;
  font-variant-numeric: tabular-nums; line-height: 1.4;
  padding: 1px 10px; border-radius: 999px;
  color: var(--accent-ink); background: var(--accent-soft);
  border: 1px solid var(--accent-line); white-space: nowrap;
}
.btn.is-copied { color: var(--ok); border-color: var(--ok-line); }
.btn.is-copyfail { color: var(--danger); border-color: var(--danger-line); }

/* ---- 学生表单 ---- */
.stuform .req { color: var(--danger); }
.stuform__foot { display: flex; gap: var(--gap-2); margin-top: var(--gap-4); }
.chip.is-off { opacity: .45; cursor: not-allowed; }
.chip .ctdot { margin-right: 4px; }

/* ---- 二.2 排课行（编辑页「上课时间」面板） ---- */
.slotrows { display: flex; flex-direction: column; gap: var(--gap-2); margin-bottom: var(--gap-2); }
.slotrows__empty { margin: 0 0 var(--gap-2); }
.slotrow { display: flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap; }
.slotrow select, .slotrow input[type="time"], .slotrow input[type="text"] {
  padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); min-height: 34px;
}
.slotrow .slot-wd { width: 88px; }
.slotrow .slot-st, .slotrow .slot-en { width: 116px; }
.slotrow .slot-ct { flex: 1 1 140px; min-width: 120px; }
.slotrow .slot-note { flex: 1 1 160px; min-width: 120px; }
.slotrow .slot-dash { color: var(--text-2); }
.slotrow .slot-del {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--border);
  background: var(--surface); color: var(--danger); font-size: 18px; line-height: 1; cursor: pointer;
}
.slotrow .slot-del:hover { background: var(--danger); color: #fff; border-color: var(--danger); }

/* 未来 30 天预览 */
.upclist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--gap-1); }
.upcrow {
  display: flex; align-items: center; gap: var(--gap-2); padding: 8px 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
}
.upcrow__date { flex: 0 0 auto; min-width: 78px; font-variant-numeric: tabular-nums; font-weight: 600; }
.upcrow__date i { font-style: normal; font-weight: 400; margin-left: 6px; font-size: 12px; }
.upcrow__time { flex: 0 0 auto; min-width: 120px; font-variant-numeric: tabular-nums; color: var(--text); }

/* ---- 班型管理 ---- */
.ctcell { display: flex; align-items: flex-start; gap: var(--gap-2); flex-wrap: wrap; }
.ctcell form { margin: 0; }

/* 编辑弹窗（2026-10-15 #396）：原来「编辑」是 <details> 浮层（position:absolute）
   住在 `<div class="tablewrap">`（overflow:auto）里，展开后下半截被容器裁掉、
   底部的「排序」字段看不到 —— 用户报的「相邻控件拥挤、彼此重叠」就是它。
   改用 <dialog>：showModal() 顶层渲染，任何祖先 overflow 都裁不到。 */
.ctdlg {
  width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - 48px);
  max-height: calc(100dvh - 48px);
  overflow: auto;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--sh-3);
}
.ctdlg::backdrop { background: rgba(15, 22, 19, .45); }
.ctdlg__head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--gap-3);
  padding: var(--gap-4) var(--gap-5);
  border-bottom: 1px solid var(--line);
}
.ctdlg__title { margin: 0; font-size: var(--fs-lg); font-weight: 700; }
.ctdlg__x {
  flex: none; padding: 2px 10px; border: none; border-radius: var(--radius-sm);
  background: none; color: var(--text-3); font-size: 20px; line-height: 1.3; cursor: pointer;
}
.ctdlg__x:hover { background: var(--surface-2); color: var(--text); }
.ctdlg__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--gap-3) var(--gap-4);
  padding: var(--gap-5);
}
.ctdlg__grid .field { margin-bottom: 0; min-width: 0; }
.ctdlg__foot {
  display: flex; justify-content: flex-end; gap: var(--gap-2);
  padding: var(--gap-4) var(--gap-5);
  border-top: 1px solid var(--line);
}

/* ---- 班型两级管理（2026-10-15 用户需求④：大类型 → 具体班）---- */

/* 顶部两个新增表单并排（宽屏两列，窄屏自动落单列） */
.ctadds {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: var(--gap-5);
  align-items: start;
}
.ctadds .panel { margin: 0; }

/* 每个大类型 = 一张卡片，头部淡色区分，下面挂具体班表格 */
.ctgroup { padding: 0; overflow: hidden; }
.ctgroup__head {
  display: flex; align-items: center; gap: var(--gap-3) var(--gap-5);
  flex-wrap: wrap;
  padding: var(--gap-4) var(--gap-5);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.ctgroup__title {
  display: inline-flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap;
  min-width: 0;
}
.ctgroup__name { font-size: var(--fs-lg); font-weight: 700; }
.ctgroup__meta {
  display: inline-flex; align-items: center; gap: var(--gap-3);
  margin-left: auto;
  color: var(--text-3); font-size: var(--fs-sm);
}
.ctgroup__meta span + span::before { content: "·"; margin-right: var(--gap-3); color: var(--line-strong); }
.ctgroup__actions { display: inline-flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap; }
.ctgroup__body { padding: 0; }
.ctgroup__body .tablewrap { border: none; border-radius: 0; margin: 0; }
.ctgroup__body .empty { margin: var(--gap-5); }
/* 停用的大类型整卡降饱和，一眼看出不是主力 */
.ctgroup--off .ctgroup__head { background: var(--surface); }
.ctgroup--off .ctgroup__name { color: var(--text-2); }

/* 二.1 下钻：大类型下面挂的具体班列表（首页「我的班级」用）。
   每个具体班 = 一张可点的小卡，点进去就是「这个班的学生」。 */
.clslist {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: var(--gap-4);
  padding: var(--gap-5);
}
.clsmini {
  display: flex; flex-direction: column; gap: var(--gap-2);
  padding: var(--gap-4) var(--gap-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-card);
  text-decoration: none; color: inherit;
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.clsmini:hover {
  border-left-color: var(--brand);
  box-shadow: var(--shadow-card);
  transform: translateY(-2px);
}
.clsmini__top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--gap-3); }
.clsmini__name { font-size: var(--fs-base); font-weight: 700; }
.clsmini__n { color: var(--text-3); font-size: var(--fs-xs); white-space: nowrap; }
.clsmini__note { font-size: var(--fs-sm); color: var(--text-2); }
.clsmini__syl {
  margin: 0; font-size: var(--fs-sm); line-height: 1.5; color: var(--text-2);
  max-height: 4.5em; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
}

@media (max-width: 900px) {
  .lessongrid { grid-template-columns: minmax(0, 1fr); }
  .fbpreview { position: static; }
  .lesson-foot__del { margin-left: 0; }
}

/* ============================================================
   语音输入（切片 23，2026-10-10 用户需求）
   只用了既有令牌 —— 深色模式自动跟随，这一节不用单独写覆盖。
   ============================================================ */

/* 反馈框标题行：左边 label，右边一串小按钮（说话 / 填入模板） */
.fbhead__acts { display: inline-flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap; }

/* 麦克风按钮：升级成**主色药丸** —— 用户 2026-10-10 要求「显眼、直观、好看」。
   以前是一枚小灰按钮（和「填入模板」长得一模一样），一眼看不出是语音。
   ⚠️ 交互上**绝不**用 disabled（见 voice.js 头注释：禁用=点不动=没法停）。 */
.micbtn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 34px;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-weight: 600;
  overflow: visible;                 /* 让脉冲环能溢到按钮外 */
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.micbtn:hover,
.micbtn:focus-visible {
  border-color: var(--accent);
  background: var(--surface-2);
  color: var(--accent-ink);
}
.micbtn__ico { width: 15px; height: 15px; flex: none; }
.micbtn__label { font-size: var(--fs-sm); }

/* 脉冲环：录音中出现在按钮外圈，不用读字也知道「正在录」 */
.micbtn__ring {
  display: none;
  position: absolute;
  inset: -4px;
  border-radius: inherit;
  border: 2px solid var(--danger);
  pointer-events: none;
}
.micbtn.is-rec .micbtn__ring { display: block; }

/* 声浪条：录音中替换掉静态麦克风图标 —— 四根跳动竖条比一个图标直白得多 */
.micbtn__wave { display: none; align-items: flex-end; gap: 2px; height: 15px; }
.micbtn.is-rec .micbtn__wave { display: inline-flex; }
.micbtn.is-rec .micbtn__ico { display: none; }
.micbtn__wave i {
  display: block; width: 3px; height: 100%;
  border-radius: 2px; background: currentColor;
  transform-origin: bottom;
}
.micbtn__wave i:nth-child(1) { animation-delay: -.30s; }
.micbtn__wave i:nth-child(2) { animation-delay: -.60s; }
.micbtn__wave i:nth-child(3) { animation-delay: -.15s; }
.micbtn__wave i:nth-child(4) { animation-delay: -.45s; }

/* 录音中：整枚按钮转红 —— 当前状态最醒目 */
.micbtn.is-rec {
  border-color: var(--danger);
  background: var(--danger);
  color: var(--on-solid);
}
/* 识别中：转灰 + 转圈光标。不可点但**会自动恢复**，不是死角 */
.micbtn.is-busy {
  border-color: var(--line-strong);
  background: var(--surface-2);
  color: var(--text-3);
  cursor: progress;
}

@media (prefers-reduced-motion: no-preference) {
  .micbtn.is-rec .micbtn__ring { animation: micring 1.5s ease-out infinite; }
  @keyframes micring {
    0% { transform: scale(.94); opacity: .55; }
    100% { transform: scale(1.22); opacity: 0; }
  }
  .micbtn.is-rec .micbtn__wave i { animation: micwave .9s ease-in-out infinite; }
  @keyframes micwave {
    0%, 100% { transform: scaleY(.32); }
    50% { transform: scaleY(1); }
  }
}
/* 「别动我屏幕」：声浪条停在中位，不跳 */
@media (prefers-reduced-motion: reduce) {
  .micbtn__wave i { transform: scaleY(.6); }
}

/* 识别状态行：默认 hidden（不占位），有话说才出现。
   ⚠️ 下面写了 display:flex，就必须自己补 [hidden]{display:none} ——
   UA 的 `[hidden]{display:none}` 权重与 `.micmsg` 相同，源码在后就把它顶掉了（本工程踩过好几回）。 */
.micmsg {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 8px 0 0;
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: var(--text-3);
}
.micmsg[hidden] { display: none; }
.micmsg__txt { min-width: 0; }
.micmsg__stop {
  flex: 0 0 auto;
  padding: 4px 14px;
  border: 1px solid var(--danger-line);
  border-radius: var(--radius-pill);
  background: var(--danger-soft);
  color: var(--danger);
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: 700;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.micmsg__stop[hidden] { display: none; }
.micmsg__stop:hover { background: var(--danger); color: var(--on-solid); border-color: var(--danger); }
.micmsg.is-live { color: var(--accent-ink); font-weight: 600; }

/* ---- 撤销 / 重做（2026-10-18）：feedback 页书写区的小按钮组 ---- */
.undogrp { display: inline-flex; gap: 4px; }
.undobtn {
  flex: 0 0 auto;
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-2);
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.undobtn:hover {
  background: var(--accent-soft);
  color: var(--accent-ink);
  border-color: var(--accent-line);
}
.undobtn.is-off { opacity: .38; }

/* ---- 全站自绘确认框（2026-10-18 用户要求替换浏览器原生 confirm）---- */
.qbcf {
  position: fixed; inset: 0; z-index: 400;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.qbcf[hidden] { display: none; }
.qbcf__mask {
  position: absolute; inset: 0;
  background: rgba(60, 40, 30, .42);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  animation: qbcf-fade .18s ease both;
}
.qbcf__card {
  position: relative;
  width: min(400px, 92vw);
  background: var(--surface);
  border-radius: 16px;
  padding: 22px 22px 18px;
  box-shadow: 0 18px 50px rgba(60, 35, 20, .28), 0 2px 8px rgba(60, 35, 20, .12);
  animation: qbcf-pop .22s cubic-bezier(.2, .9, .3, 1.2) both;
}
.qbcf__title {
  margin: 0 0 8px; font-size: 16px; font-weight: 700; color: var(--text);
}
.qbcf__text {
  margin: 0 0 16px; font-size: 13.5px; line-height: 1.75;
  color: var(--text-2); white-space: pre-line; word-break: break-word;
}
.qbcf__acts { display: flex; justify-content: flex-end; gap: 8px; }
/* 危险操作：确定钮变红 + 标题左侧一条红杠，一眼知道这是删除类 */
.qbcf__card.is-danger .qbcf__title { padding-left: 10px; border-left: 4px solid var(--danger, #d64545); border-radius: 2px; }
.qbcf__card.is-danger .qbcf__ok {
  background: linear-gradient(180deg, #e05c50, var(--danger, #d64545));
  border-color: transparent;
}
@keyframes qbcf-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes qbcf-pop {
  from { opacity: 0; transform: translateY(14px) scale(.94); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .qbcf__mask, .qbcf__card { animation: none; }
}
.micmsg.is-ok { color: var(--ok); }
.micmsg.is-err { color: var(--danger); }

/* 语音提示条（切片 23）。2026-10-10 用户要求「记得允许麦克风」那句要醒目，
   所以从一行灰字升级成带图标的浅橙提示块，权限那句单独成行加粗。
   浅色/深色都只靠令牌，主题切换自动跟随。 */
.micnote {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin: 0 0 var(--gap-3);
  padding: 10px 13px;
  font-size: var(--fs-xs);
  line-height: 1.75;
  color: var(--accent-ink);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
}
.micnote__ico { flex: 0 0 auto; margin-top: 2px; color: var(--accent); }
.micnote__ico svg { display: block; width: 16px; height: 16px; }
.micnote__body { min-width: 0; }
.micnote__title { margin: 0 0 3px; font-weight: 700; }
.micnote__line { margin: 0; }
.micnote__line + .micnote__line { margin-top: 3px; }
.micnote__line b { font-weight: 700; }
.micnote__perm {
  margin: 7px 0 0;
  padding-top: 7px;
  border-top: 1px dashed var(--accent-line);
  font-weight: 600;
}
.micnote__perm b { font-weight: 800; }
/* 云端识别没配 → 整块转暖黄，且说的是「怎么升级」，不用主色假装一切正常 */
.micnote--local {
  color: var(--warn);
  background: var(--warn-soft);
  border-color: var(--warn-line);
  border-left-color: var(--warn);
}
.micnote--local .micnote__ico { color: var(--warn); }
.micnote--local .micnote__perm { border-top-color: var(--warn-line); }

/* ---------- 20. 顶栏账号菜单 / 审核模块切换 / 学生档案首页（2026-10-10） ----------
   本轮三处改版的样式，颜色一律走令牌（深色模式自动跟随，不写死 #hex）。

   20.1 顶栏「账号与更多功能」折叠菜单：把原来的「改密码 + 退出」两个按钮
        收成一个「头像 + 名字 + ☰」触发器，点开是账号面板（低频动作都塞里面）。
   20.2 审核模块切换：导航栏把「审核」「图形核对」并成一格，进来用页签分。
   20.3 学生档案首页：「我的班级」卡片墙 + 「我的学生」卡片网格。 */

/* ---- 20.1 顶栏账号菜单 ---- */
.usermenu { position: relative; }
.usermenu__btn {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-2);
  padding: 5px 9px 5px 6px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: transparent;
  color: inherit;
  cursor: pointer;
  position: relative;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.usermenu__btn:hover { background: var(--surface-2); border-color: var(--line); }
.usermenu__btn[aria-expanded="true"] { background: var(--surface-2); border-color: var(--line-strong); }
.usermenu__bars { width: 18px; height: 18px; flex: 0 0 auto; color: var(--text-2); }

.usermenu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  z-index: 60;
  min-width: 232px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--sh-3);
}
.usermenu__head {
  display: flex;
  align-items: center;
  gap: var(--gap-2);
  padding: 9px 10px 11px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 6px;
}
/* 面板顶部的头像/名字是个通往「账号设置」的链接（用户要求），
   所以补上链接态与 hover —— 别让它看着像普通文字。 */
a.usermenu__head {
  color: var(--text);
  text-decoration: none;
  border-radius: var(--radius-sm);
  transition: background var(--dur) var(--ease);
}
a.usermenu__head:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
a.usermenu__head:hover .usermenu__name { color: var(--accent-hover); }
.usermenu__avatar {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-pill);
  background: linear-gradient(140deg, var(--accent-hi), var(--accent-hover));
  color: var(--on-solid);
  font-size: var(--fs-lg);
  font-weight: 700;
}
.usermenu__id { display: grid; min-width: 0; line-height: 1.3; }
.usermenu__name { font-size: var(--fs-md); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.usermenu__role { font-size: var(--fs-xs); color: var(--text-3); }
.usermenu__list { display: grid; gap: 2px; }
.usermenu__section + .usermenu__section { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--line); }
.usermenu__label { font-size: var(--fs-xs); color: var(--text-3); padding: 3px 10px 2px; letter-spacing: .05em; }
.usermenu__dot {
  position: absolute; top: 5px; right: 5px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--danger); box-shadow: 0 0 0 2px var(--surface);
}
.usermenu__badge {
  flex: 0 0 auto; margin-left: auto;
  min-width: 18px; height: 18px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; background: var(--danger); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 1;
}
.usermenu__form { margin: 0; }
.usermenu__item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 9px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-md);
  text-align: left;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.usermenu__item:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.usermenu__item--danger { color: var(--danger); }
.usermenu__item--danger:hover { background: var(--danger-soft); color: var(--danger); }
.usermenu__ico { width: 18px; flex: 0 0 auto; text-align: center; }

/* ---- 20.2 审核模块切换 ---- */
.rvtabs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--gap-3);
  margin-bottom: var(--gap-5);
}
.rvtabs__item {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  padding: 13px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--sh-1);
  color: var(--text);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
.rvtabs__item:hover {
  border-color: var(--accent-line);
  box-shadow: var(--sh-2);
  transform: translateY(-1px);
  text-decoration: none;
  color: var(--text);
}
.rvtabs__item.is-active {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent-line);
}
.rvtabs__ic { font-size: var(--fs-2xl); line-height: 1; flex: 0 0 auto; }
.rvtabs__body { display: grid; gap: 2px; min-width: 0; }
.rvtabs__t { font-size: var(--fs-lg); font-weight: 700; }
.rvtabs__item.is-active .rvtabs__t { color: var(--accent-hover); }
.rvtabs__d { font-size: var(--fs-xs); color: var(--text-3); }

/* ---- 20.3 学生档案首页 ---- */
.stuhome__sec + .stuhome__sec { margin-top: var(--gap-6); }
.stuhome__head {
  display: flex;
  align-items: baseline;
  gap: var(--gap-3);
  flex-wrap: wrap;
  margin-bottom: var(--gap-3);
}
.stuhome__title { margin: 0; font-size: var(--fs-xl); }
.stuhome__title::before {
  content: "";
  display: inline-block;
  width: 4px; height: .95em;
  margin-right: 9px;
  border-radius: var(--radius-pill);
  background: linear-gradient(180deg, var(--accent-hi), var(--accent));
  vertical-align: -2px;
}
.stuhome__hint { font-size: var(--fs-xs); color: var(--text-3); }

/* 整体周课表（2026-10-15 板块三「我的课表」）：横向 7 天 + 时间列，格子按班分块 */
.table--schedule { table-layout: fixed; min-width: 720px; }
.table--schedule th, .table--schedule td { vertical-align: top; }
.table--schedule .sched__timeh, .table--schedule .sched__time { width: 76px; }
.sched__time {
  font-variant-numeric: tabular-nums;
  font-weight: 600; color: var(--text-2);
  white-space: nowrap;
}
.sched__dayh { text-align: left; }
.sched__cell { min-height: 64px; }
.schedcell {
  padding: 7px 8px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border-left: 3px solid var(--accent);
}
.schedcell + .schedcell { margin-top: 6px; }
.schedcell__top { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.schedcell__cls { font-size: var(--fs-sm); font-weight: 700; color: var(--text); }
.schedcell__range { font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
.schedcell__stu { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
.tag--stu {
  font-size: var(--fs-xs);
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--text-2);
}

/* 待反馈提醒条：暖黄（是提醒不是报错），一行说完「几个学生 / 几次课 / 怎么看」 */
.stunotify {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  flex-wrap: wrap;
  margin: 0 0 var(--gap-5);
  padding: 12px var(--gap-4);
  border: 1px solid var(--warn-line);
  border-left: 4px solid var(--warn);
  border-radius: var(--radius-md);
  background: var(--warn-soft);
}
.stunotify__ic { font-size: var(--fs-xl); line-height: 1; flex: 0 0 auto; }
.stunotify__body { display: grid; gap: 2px; min-width: 0; flex: 1; }
.stunotify__body .muted { font-size: var(--fs-xs); }
.stunotify__act { display: flex; gap: var(--gap-2); flex: 0 0 auto; }

/* 班级卡片墙：复用 .stutabs 容器（回归按这个类名判「有班型筛选」），换成网格 */
.stutabs--cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--gap-3);
  margin-bottom: 0;
}
.stucard {
  position: relative;
  display: grid;
  gap: 4px;
  padding: 14px 15px 13px 18px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--sh-1);
  color: var(--text);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
.stucard:hover {
  border-color: var(--accent-line);
  box-shadow: var(--sh-2);
  transform: translateY(-1px);
  text-decoration: none;
  color: var(--text);
}
.stucard.is-active { border-color: var(--accent); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent-line); }
.stucard__bar { position: absolute; left: 0; top: 0; bottom: 0; width: 4px; }
.stucard__name { font-size: var(--fs-lg); font-weight: 600; line-height: 1.25; }
.stucard.is-active .stucard__name { color: var(--accent-hover); }
.stucard__n { font-size: var(--fs-xs); color: var(--text-3); font-variant-numeric: tabular-nums; }
.stucard__n b { font-size: var(--fs-lg); color: var(--text); margin-right: 2px; }
.stucard--ghost {
  place-content: center;
  text-align: center;
  border-style: dashed;
  background: transparent;
  box-shadow: none;
  color: var(--text-3);
}
.stucard--ghost:hover { color: var(--accent-hover); }
.stucard__ic { font-size: var(--fs-xl); color: var(--accent); line-height: 1; }

/* 学生卡片网格 */
.stugrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: var(--gap-3);
  margin-top: var(--gap-3);
}
.stucard2 {
  display: grid;
  gap: 11px;
  padding: 15px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--sh-1);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.stucard2:hover { border-color: var(--line-strong); box-shadow: var(--sh-2); }
.stucard2__top {
  display: flex;
  align-items: center;
  gap: 11px;
  color: var(--text);
}
.stucard2__top:hover { text-decoration: none; color: var(--text); }
.stucard2__av {
  flex: 0 0 auto;
  width: 42px; height: 42px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-pill);
  background: linear-gradient(140deg, var(--accent-hi), var(--accent-hover));
  color: var(--on-solid);
  font-size: var(--fs-xl);
  font-weight: 700;
}
.stucard2__id { display: grid; gap: 2px; min-width: 0; flex: 1; }
.stucard2__id .stuname { font-size: var(--fs-lg); }
.stucard2__id .tag { justify-self: start; }
.stucard2__sub { font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stucard2__classes { display: flex; flex-wrap: wrap; gap: 5px; }
.stucard2__stats {
  display: flex;
  align-items: center;
  gap: var(--gap-4);
  flex-wrap: wrap;
  padding-top: 11px;
  border-top: 1px dashed var(--line);
}
.stucard2__stat { display: grid; gap: 1px; font-size: var(--fs-xs); color: var(--text-3); }
.stucard2__stat b { font-size: var(--fs-lg); color: var(--text); font-variant-numeric: tabular-nums; }
.stucard2__stat i { font-style: normal; }
.stucard2__act { display: flex; gap: var(--gap-2); flex-wrap: wrap; }

/* 窄屏：卡片铺满一列，别把动作按钮挤到看不见 */
@media (max-width: 560px) {
  .stugrid { grid-template-columns: 1fr; }
  .stutabs--cards { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
  .usermenu__panel { min-width: 210px; }
}

/* ---- 20.4 每周课表（学生档案 · 2026-10-13）----
   用户需求：「在学生档案这个页面添加一个课表显示的功能，
   每个学生每一周的上课时间也方便我查看。」
   一周七格平铺（grid），有课的格子用主色软底 + 左侧色条点亮，没课的就一个「—」。 */
.weekgrid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--gap-2);
}
.weekday {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: var(--gap-2) 8px var(--gap-3);
  min-height: 88px;
  min-width: 0;
}
.weekday.is-busy {
  border-color: var(--accent-line);
  background: var(--accent-soft);
}
.weekday__name {
  margin: 0 0 6px;
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--text-3);
  text-align: center;
  letter-spacing: .02em;
}
.weekday.is-busy .weekday__name { color: var(--accent-hover); }
.weekday__none { margin: 0; text-align: center; color: var(--line-strong); font-size: var(--fs-sm); }
.slot {
  display: grid;
  gap: 2px;
  padding: 5px 7px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border-left: 3px solid var(--accent);
  margin-bottom: 5px;
  min-width: 0;
}
.slot:last-child { margin-bottom: 0; }
.slot__time {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.slot__time .muted { font-weight: 500; font-size: var(--fs-xs); }
.slot__cls {
  margin: 0;
  font-size: var(--fs-xs);
  color: var(--text-2);
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
}
.slot__cls .ctdot { flex: 0 0 auto; }
.slot__note {
  margin: 0;
  font-size: var(--fs-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 排课表：每行「周几 | 开始 | 结束 | 班型 | 备注」横排，窄屏自动折行 */
.schedule__edit { margin-top: var(--gap-4); border-top: 1px dashed var(--line); padding-top: var(--gap-4); }
.slotrow {
  display: grid;
  grid-template-columns: 92px 116px 116px minmax(120px, 1fr) minmax(140px, 1.4fr);
  gap: var(--gap-2);
  align-items: center;
  margin-bottom: var(--gap-2);
}
.slotrow > * { min-width: 0; }
.schedule__foot { display: flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap; margin-top: var(--gap-3); }
@media (max-width: 900px) {
  .weekgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .slotrow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .weekgrid { grid-template-columns: 1fr; }
  .slotrow { grid-template-columns: 1fr; }
}

/* ---------- 21. 账号设置页（切片 27 · 2026-10-10） ----------
   账号信息 + 修改密码入口 + 注销账号（危险区）。
   危险区单独一条红描边：不可逆的操作要在视觉上就和别的不一样。 */
.panel--danger { border-color: var(--danger-line); }
.acctdel {
  margin: 0 0 var(--gap-4);
  padding-left: 1.15em;
  font-size: var(--fs-sm);
  line-height: 1.95;
  color: var(--text-2);
}
.acctdel li + li { margin-top: 6px; }
.acctdel b { color: var(--text); }
.acctclose { max-width: 520px; }
.acctclose .field + .field { margin-top: var(--gap-3); }
.acctclose .btn { margin-top: var(--gap-4); }

/* ---------- 22. 题库左栏检索（切片 27 · 2026-10-10） ----------
   用户要求：「题库左侧检索（模块 / 专题大类）」。
   左栏 = 位置导航（模块 → 专题）+ 知识点大类；右栏 = 筛选表单 + 题目列表。
   🔴 两列都用 `minmax(0, 1fr)`，且 .qmain 显式 min-width:0：
      否则最长的那道题干会把整页顶出横向滚动条（宽屏看不出来，手机上一眼就废）。 */
.qgrid {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  gap: var(--gap-5);
  align-items: start;
}
.qmain { min-width: 0; }

/* 左栏（2026-10-11 用户要求）：页面加宽后左栏也跟着放宽（264 → 300）。
   跟随页面滚动 / 自身滚动见下面 ≥1024px 那段。 */
.qside { display: flex; flex-direction: column; gap: var(--gap-3); min-width: 0; }
.qside__block {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--sh-1);
  padding: var(--gap-3) var(--gap-3) var(--gap-4);
  overflow: hidden;
  /* 🔴 不能收缩（2026-10-11 修「左栏滚不动」）：
     .qside 是 flex 纵向容器 + max-height + overflow-y:auto。子项默认 flex-shrink:1，
     内容再高也会被**压扁**到容器高度 —— 于是容器永远不溢出、永远没有滚动条，
     而每个 block 自己的 overflow:hidden 又把列表**裁掉**，看起来就是「滚不动 + 看不全」。
     写死 flex:0 0 auto 让它保持自然高度，溢出交给 .qside 的滚动条。 */
  flex: 0 0 auto;
}
/* 标题条：图标 + 「模块 / 专题」。底下一条细线把「标题」和「列表」分开 ——
   以前标题就是一行小灰字，和下面那堆链接糊在一起，看不出这是一块控件。 */
.qside__title {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0 0 var(--gap-3);
  padding: 0 2px var(--gap-3);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--text);
  letter-spacing: .01em;
}
.qside__ico { font-size: 14px; line-height: 1; }
/* 「/ 专题」是同一枚标题的第二段：压小、变灰，当副题读 */
.qside__sub { font-weight: 500; font-size: var(--fs-sm); color: var(--text-3); }
.qside__tree, .qside__kids { list-style: none; margin: 0; padding: 0; }

/* 通用行：更高的行距 + 圆角，让「可点的一行」看着像按钮而不是一行文字 */
.qside__node {
  display: flex;
  align-items: center;
  gap: var(--gap-2);
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.35;
  text-decoration: none;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
.qside__node:hover {
  background: var(--surface-2);
  color: var(--text);
  text-decoration: none;
  transform: translateX(1px);
}
/* 激活态：淡橙底 + 主色字 + **左侧一条主色竖条**（比整块铺色克制，也更好认） */
.qside__node.is-active {
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-weight: 700;
  box-shadow: inset 3px 0 0 var(--accent);
}
/* 「全部」那一行（.qside__tree 的第一个 li）：比模块行矮一档、灰一档 ——
   它是「取消选择」，不该和具体模块抢视觉重量。 */
.qside__tree > li:first-child > .qside__node { font-weight: 600; }
.qside__tree > li:first-child { margin-bottom: 4px; }
.qside__tree > li:first-child > .qside__node.is-active {
  background: var(--surface-2);
  color: var(--text);
  box-shadow: inset 3px 0 0 var(--line-strong);
}

/* 子节点：一条竖向引导线 + 行首圆点，层级一眼看得出。
   缩进要把标记那 12px 也算上，否则子项反而比父项更靠左。 */
.qside__kids {
  margin: 2px 0 6px;
  padding-left: 14px;
  border-left: 1px solid var(--line);
}
.qside__node--kid {
  position: relative;
  padding-left: calc(var(--gap-3) + 8px);
  font-weight: 400;
}
.qside__node--kid::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 5px;
  height: 5px;
  margin-top: -2.5px;
  border-radius: 50%;
  background: var(--line-strong);
  transition: background var(--dur) var(--ease);
}
.qside__node--kid:hover::before { background: var(--accent); }
.qside__node--kid.is-active::before { background: var(--accent); }

/* 三级及以上（教材目录的「节」、模块/专题的「考点」）—— 2026-10-14 补（#368）。
   左栏以前只画两级，一条 14px 缩进就够了；现在能到任意深度，每下一级都得再缩
   14px + 一条竖线，四层下来内容列只剩百来像素，长一点的考点名要逐字换行。
   第三层起把引导线间距收到 10px、字号降一档、折叠钮缩一号：
   层级仍然一眼看得出，但不再挤成一团。 */
.qside__kids .qside__kids {
  margin: 1px 0 4px;
  padding-left: 10px;
}
.qside__kids .qside__kids .qside__node--kid { font-size: var(--fs-xs); }
.qside__kids .qside__kids .qside__caret { width: 16px; height: 16px; }
/* 二级以下的行：折叠钮不再让出 4px 左外边距（多出来的是纯缩进，白占宽度） */
.qside__kids .qside__row > .qside__caret { margin-left: 0; }

/* 折叠标记（▸ / ▾）：一枚小圆底。**它现在是真的开关**（<button data-qside-fold>）——
   以前只是个塞在筛选链接里的符号，点它等于重新筛一次，于是「展开了就回不去」
   （2026-10-11 用户报的 bug；逻辑见 js/qside.js）。
   固定宽度，有/无标记的行左边缘才对得齐。 */
.qside__caret {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--surface-2);
  font: inherit;
  font-size: 9px;
  line-height: 1;
  color: var(--text-3);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
button.qside__caret { cursor: pointer; }
button.qside__caret:hover { background: var(--surface-3); color: var(--text-2); }
button.qside__caret:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* 叶子行（没有子项）：只为对齐留个占位，透明、不可点 */
.qside__caret--leaf { background: transparent; }
/* ▸ 转 90° 变 ▾。用 transform 而不是换字符，展开时有个小动效 */
.qside__caret-ico { display: block; transition: transform var(--dur) var(--ease); }
.qside__mod.is-open .qside__caret-ico { transform: rotate(90deg); }

/* 模块行 = [折叠按钮][筛选链接]，两者是**兄弟**而不是嵌套 ——
   交互元素不能互相嵌套，所以按钮挪到链接外面来（对齐仍是 36px，和以前一样）。 */
.qside__row { display: flex; align-items: center; gap: 4px; }
.qside__row > .qside__caret { margin-left: 4px; }
.qside__row > .qside__node { flex: 1 1 auto; min-width: 0; }

/* 收起：子列表整块隐藏。子列表**始终在 DOM 里**，折叠只切 class ⇒ 瞬时、不走网络。 */
.qside__mod:not(.is-open) > .qside__kids { display: none; }
/* 🔴 长专题名（「数据的收集、整理与描述」）必须能断行，否则把左栏撑宽 → 整页横滚 */
.qside__name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
/* 题数：做成**药丸**（冷青点缀 = 数据型区块，见 §1 配色口径）。
   等宽数字，右端对齐，扫一列数字时不会跳。 */
.qside__n {
  flex: none;
  min-width: 30px;
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  background: var(--cool-soft);
  color: var(--cool-ink);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.qside__node.is-active .qside__n { background: var(--accent); color: var(--on-solid); }
/* 「全部」那行没选中时：药丸退回中性灰，别抢具体模块的视线 */
.qside__tree > li:first-child > .qside__node:not(.is-active) .qside__n {
  background: var(--surface-2);
  color: var(--text-2);
}

/* 左栏底部「当前范围」卡片（2026-10-11 用户要求「丰富一下左侧的空间」）。
   比上面的树轻一档：虚线边 + 浅底，填住左栏的下半段，但不跟主控件抢注意力。 */
.qside__aux { border-style: dashed; background: var(--surface-2); }
.qside__auxline { margin: 0; font-size: var(--fs-sm); color: var(--text-2); }
.qside__auxline b { color: var(--cool-ink); font-size: var(--fs-md); font-variant-numeric: tabular-nums; }
.qside__auxhint { margin: 0; font-size: var(--fs-xs); color: var(--text-3); }
.qside__clear {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: 2px;
  font-size: var(--fs-xs); font-weight: 600; color: var(--accent);
}
.qside__clear::before { content: "✕"; font-size: 10px; }
/* 「增删改分类目录」入口（#368，2026-10-14）。与「清除全部条件」同一族，
   但走中性色：它是**去别处干活**（跳目录管理页），不是清条件，
   用主色会跟左栏里真正的主控件抢注意力。 */
.qside__edit {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: var(--gap-2);
  padding: 5px 10px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs); font-weight: 600; color: var(--text-2);
}
.qside__edit:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-ink);
  text-decoration: none;
}
.qside__edit:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* 宽屏：左栏**独立上下滚动**（2026-10-11 用户第二次反馈「左侧模块不支持上下滚动」）。
   🔴 三条缺一不可，每条都是踩出来的：
   1. align-self:start —— grid 子项默认被拉伸到整行高（stretch），那样 sticky 没有可滑余量，
      表现成「左栏根本不跟着滚」。
   2. 高度用 100dvh（不是 100vh）—— 手机地址栏收放时 100vh 会算歪。
   3. 还得再减掉「页头 + 学段/目录页签」那截（--qgrid-top）：左栏在页面顶部时是从
      页头**下面**才开始画的；不减这一截，页面没滚动时左栏底部就掉到折叠线以下、
      够不着 —— 这才是「不支持上下滚动」的真相（内容本该溢出，却因 max-height 偏大
      没溢出，于是连滚动条都没有）。
   最后 .qside__aux 吸收剩余高度，左栏一直铺到视口底，不再留一截空白。 */
@media (min-width: 1024px) {
  .qside {
    position: sticky;
    top: calc(var(--topbar-h) + var(--gap-4));
    max-height: calc(100dvh - var(--topbar-h) - var(--gap-4) - var(--qgrid-top));
    min-height: min(520px, calc(100dvh - var(--topbar-h) - var(--gap-4) - var(--qgrid-top)));
    overflow-y: auto;
    overscroll-behavior: contain;
    align-self: start;
    scrollbar-gutter: stable;          /* 滚不滚都不抖 */
    scrollbar-width: thin;
    scrollbar-color: var(--line-strong) transparent;
  }
  /* 「当前范围」卡吸收剩余高度 → 左栏底部铺满，不再是参差不齐的一小撮 */
  .qside__aux { flex: 1 1 auto; }
}

/* 窄屏（手机 / 平板竖屏）：**不并排**，左栏收成上方两块并排卡片。
   并排 264px 会把正文挤到横向滚动 —— responsive_test 会红。 */
@media (max-width: 1023px) {
  .qgrid { grid-template-columns: minmax(0, 1fr); gap: var(--gap-4); }
  .qside { flex-direction: row; flex-wrap: wrap; }
  .qside__block { flex: 1 1 240px; min-width: 0; }
}

/* ================================================================
   23. 「加入试卷」选择器（新#1 · 去掉题篮后的直通路）
   ================================================================ */
.paperpick {
  border: none;
  border-radius: var(--radius);
  padding: 0;
  width: min(440px, 92vw);
  background: var(--surface);
  box-shadow: 0 24px 60px rgba(20, 24, 40, 0.28);
  color: var(--text);
}
.paperpick::backdrop { background: rgba(15, 18, 30, 0.42); }
.paperpick__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--gap-4) var(--gap-5);
  border-bottom: 1px solid var(--line);
}
.paperpick__title { margin: 0; font-size: var(--fs-lg); }
.paperpick__x {
  border: none; background: none; cursor: pointer;
  font-size: 22px; line-height: 1; color: var(--text-3); padding: 4px 8px;
}
.paperpick__x:hover { color: var(--text); }
.paperpick__body { padding: var(--gap-4) var(--gap-5) var(--gap-5); }
.paperpick__hint { margin: 0 0 var(--gap-3); font-size: var(--fs-sm); color: var(--text-3); }
.paperpick__list {
  list-style: none; margin: 0 0 var(--gap-3); padding: 0;
  max-height: 40vh; overflow-y: auto;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.paperpick__empty { padding: var(--gap-4); color: var(--text-3); font-size: var(--fs-sm); }
.paperpick__row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--gap-2);
  width: 100%; padding: var(--gap-3) var(--gap-4);
  border: none; background: none; cursor: pointer; font: inherit; color: var(--text);
  text-align: left; border-bottom: 1px solid var(--line);
}
.paperpick__row:last-child { border-bottom: none; }
.paperpick__row:hover { background: var(--surface-2); }
.paperpick__name { min-width: 0; overflow-wrap: anywhere; }
.paperpick__n { flex: none; font-size: var(--fs-sm); color: var(--text-3); }
.paperpick__new { display: flex; gap: var(--gap-2); }
.paperpick__new input {
  flex: 1; min-width: 0;
  padding: var(--gap-2) var(--gap-3);
  border: 1px solid var(--line); border-radius: var(--radius-sm); font: inherit;
}

/* ================================================================
   24. 个人信息页（新任务2）：头像与昵称编辑
   ================================================================ */
.acctprofile {
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr);
  gap: var(--gap-6);
  align-items: start;
}
.acctprofile__avatar { display: flex; flex-direction: column; align-items: center; gap: var(--gap-3); text-align: center; }
.acctprofile__img, .acctprofile__init {
  width: 96px; height: 96px; border-radius: 50%;
  object-fit: cover;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(145deg, var(--accent-hi) 0%, var(--accent) 100%);
  color: var(--on-solid); font-size: 34px; font-weight: 700;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--accent) 28%, transparent);
}
.acctprofile__img { background: var(--surface-2); }
.acctprofile__up { margin: 0; }
.acctprofile__name { align-self: center; }
@media (max-width: 640px) {
  .acctprofile { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- 23. 考查记录（详情页那一节 · 2026-10-11 第三批） ----------
   用户要求：「所有考查的学校及其考查日期都要列出来」「统计在所有学校、所有试卷中
   总共考查了多少次」。列表页/卷面上那枚角标是**摘要**，这里才是管理入口：
   统计行 + 逐场明细 + 「再记一条」。全部走令牌，深色模式自动跟随。 */
.panel__title--split {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 10px;
}
.panel__title--split .occsum { margin-left: auto; }
.occsum { font-size: var(--fs-sm); font-weight: 500; color: var(--text-2); white-space: nowrap; }
.occsum b { color: var(--cool-ink); font-size: var(--fs-md); font-variant-numeric: tabular-nums; }
.occsum__sep { margin: 0 5px; color: var(--line-strong); }

.occlist { list-style: none; margin: 0 0 var(--gap-4); padding: 0; display: grid; gap: 6px; }
.occlist__item {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px;
  padding: 9px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--cool-line);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
}
/* 序号做成小青圆：一眼数得出「一共几场」 */
.occlist__no {
  flex: none;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--cool-soft); color: var(--cool-ink);
  font-size: 11px; font-weight: 700; line-height: 20px; text-align: center;
  font-variant-numeric: tabular-nums;
}
.occlist__school { font-weight: 700; color: var(--text); }
.occlist__date { color: var(--cool-ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.occlist__paper {
  padding: 1px 8px; border-radius: var(--radius-pill);
  background: var(--surface-2); color: var(--text-2); font-size: var(--fs-xs);
}
.occlist__note { color: var(--text-3); font-size: var(--fs-xs); }
/* 行右侧工具区（编辑 + 删除）整块靠右；两个按钮间距统一在这里给 */
.occlist__tools { margin: 0 0 0 auto; display: inline-flex; align-items: center; gap: 6px; }
.occlist__del { margin: 0; }
.occlist__empty { margin: 0 0 var(--gap-4); font-size: var(--fs-sm); color: var(--text-3); }

/* 编辑（2026-10-11 用户要求）：点开是**浮层**表单 —— 明细行不会被撑开，
   展开/收起时整页不上下跳。right: 0 让它朝左铺开，避免顶出容器右边界。 */
.occlist__edit { position: relative; display: inline-block; }
.occlist__edit > summary { list-style: none; cursor: pointer; }
.occlist__edit > summary::-webkit-details-marker { display: none; }
.occlist__edit[open] > summary { background: var(--surface-2); }
.occlist__editform {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 7;
  width: min(460px, calc(100vw - 48px));
  /* #396（2026-10-15）：浮层没限高 ⇒ 在页面靠底的位置展开时，下半个表单
     落到视口外、够不着也看不见。限高 + 自己滚。dvh 写两遍：老内核忽略第二行。 */
  max-height: calc(100vh - 120px);
  max-height: calc(100dvh - 120px);
  overflow: auto;
  overscroll-behavior: contain;
  padding: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: var(--sh-3);
  text-align: left;
}

/* 「再记一条」：虚线框 + 浅底，与上面的明细列表明确分开（不是又一条记录） */
.occform {
  padding: var(--gap-4);
  background: var(--surface-2);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
}
.occform__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--gap-3) var(--gap-4);
  align-items: end;
}
.occform .field { margin-bottom: 0; min-width: 0; }
.occform .field--wide { grid-column: 1 / -1; }
.occform__actions { display: flex; justify-content: flex-end; margin-top: var(--gap-3); }

/* ---------- 24. 讲义（2026-10-11 新任务） ----------
   三页共用一套骨架：选择页「学段 → 版本 → 线 → 书」(index)、目录 (book)、制作页 (lesson)。
   一律走令牌（--accent/--cool/--surface…），深色模式自动跟随，不写死 hex。 */

/* ---- 选择页：两分区快跳 + 学段 → 版本 → 线 → 书（#364 改版） ----
   2026-10-15 用户口径：「首页分小学奥数 / 初中数学两板块，要改成两个明显分区，
   可以参考同站内『试卷库』页面的布局。」⇒ 顶部一排分区快跳卡 + 下面每个学段一张
   独立板块卡（surface 底 + 边框 + 圆角 + 内边距），学段之间一眼分开。 */

/* 顶部两分区快跳卡：小学奥数 / 初中数学，点了滚到下面各自的板块 */
.lecjump {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--gap-3); margin-bottom: var(--gap-6);
}
.lecjump__item {
  display: flex; align-items: center; justify-content: space-between; gap: var(--gap-3);
  padding: var(--gap-4) var(--gap-5);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); text-decoration: none; color: var(--text);
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.lecjump__item:hover {
  border-color: var(--accent-line); box-shadow: var(--sh-2); transform: translateY(-2px);
}
.lecjump__label { position: relative; padding-left: 13px; font-size: var(--fs-lg); font-weight: 700; }
/* 左侧一道暖橙渐变竖条：两个分区各自一眼可辨，比加粗边框克制 */
.lecjump__label::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 4px; height: 1.05em; border-radius: 2px;
  background: linear-gradient(180deg, var(--accent), var(--accent-2));
}
.lecjump__n { font-size: var(--fs-sm); color: var(--text-3); }
.lecjump__n b { color: var(--cool-ink); font-size: var(--fs-md); font-variant-numeric: tabular-nums; }

/* 学段板块卡：一个学段一整块，视觉上成为「明显分区」 */
.lecstage {
  margin-bottom: var(--gap-6);
  padding: var(--gap-5);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  scroll-margin-top: calc(var(--topbar-h) + var(--gap-3));
}
.lecstage__head {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--gap-3);
  margin-bottom: var(--gap-4); padding-bottom: var(--gap-3);
  border-bottom: 2px solid var(--line);
}
.lecstage__hd { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px; }
.lecstage__title {
  position: relative; margin: 0; padding-left: 15px;
  font-size: var(--fs-2xl); font-weight: 800;
}
.lecstage__title::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 5px; height: 1.1em; border-radius: 2px;
  background: linear-gradient(180deg, var(--accent), var(--accent-2));
}
.lecstage__desc { margin: 0; font-size: var(--fs-sm); color: var(--text-3); }
.lecstage__count {
  flex: none; display: inline-flex; align-items: baseline; gap: 3px;
  padding: 4px 12px; border-radius: var(--radius-pill);
  background: var(--accent-soft); color: var(--accent-ink);
  font-size: var(--fs-sm); font-weight: 600;
}
.lecstage__count b { font-size: var(--fs-lg); font-variant-numeric: tabular-nums; }


.leced { margin: 0 0 var(--gap-5) var(--gap-2); }
.leced__label { margin: 0 0 var(--gap-3); }
.lectrack { margin: 0 0 var(--gap-4); }
.lectrack__label {
  margin: 0 0 var(--gap-2); font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-2); letter-spacing: .04em;
}

.lecgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--gap-3); }
.leccard {
  display: flex; flex-direction: column; gap: 6px;
  padding: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-decoration: none; color: var(--text);
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.leccard:hover { border-color: var(--accent-line); box-shadow: var(--sh-2); transform: translateY(-2px); }
.leccard__subject { font-size: var(--fs-lg); font-weight: 700; color: var(--accent-ink); }
.leccard__title { font-size: var(--fs-sm); color: var(--text-2); line-height: 1.5; }
.leccard__meta {
  margin-top: auto; padding-top: var(--gap-2);
  font-size: var(--fs-xs); color: var(--text-3);
}
.leccard__meta b { color: var(--cool-ink); font-size: var(--fs-md); font-variant-numeric: tabular-nums; }

/* ---- 目录（book.html）---- */
.leclist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.leclist__row { display: flex; align-items: center; gap: var(--gap-2); }
.leclist__main {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: var(--gap-3);
  padding: 12px 14px; text-decoration: none; color: var(--text);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  transition: border-color .15s, background .15s;
}
.leclist__main:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.leclist__no {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent-ink);
  font-size: var(--fs-sm); font-weight: 700; line-height: 26px; text-align: center;
  font-variant-numeric: tabular-nums;
}
.leclist__title { flex: 1; min-width: 0; font-weight: 600; }
.leclist__meta { flex: none; display: inline-flex; gap: 6px; }
.leclist__del { flex: none; margin: 0; }

/* ---- 制作页（lesson.html）---- */
.leclist--items { gap: var(--gap-5); }
.lecblock { list-style: none; }
.lecitem {
  padding: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.lecitem__head { display: flex; align-items: center; gap: var(--gap-2); margin-bottom: var(--gap-2); }
.lecitem__label {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 12px; border-radius: var(--radius-pill);
  background: var(--accent); color: var(--on-solid);
  font-size: var(--fs-sm); font-weight: 700; letter-spacing: .03em;
}
/* 三种题型的标签配色（#335，2026-10-13）——与所在区的色条、抬头图案**同一套色**，
   形状（图案）+ 颜色双通道区分。⚠️ 修了一处老 bug：CSS 里原来写的选择器是
   `--pra`，而模板输出的是 `--practice`，两者对不上 → 练习标签一直没吃到青色。
   这里统一按模板的 kind 命名（example / practice / extend）。 */
.lecitem__label--example { background: var(--cool); color: var(--on-solid); }
.lecitem__label--practice { background: var(--accent); }
.lecitem__label--extend { background: var(--accent-2, var(--accent)); }
/* 标签里那枚小图案：跟着标签文字同色（currentColor），尺寸压到 1em 上下 */
.lecitem__label .lecico { width: 1em; height: 1em; }
.lecitem__tools { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; }
/* 网页 → PDF 的页码直达链接（2026-10-11 双向跳转）。
   用松石青（数据/导航型信息）与珊瑚橙的编辑按钮区分；没导出过 PDF 时整块不渲染。 */
.lecitem__pdf {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px 9px; border-radius: var(--radius-pill);
  background: var(--cool-soft, color-mix(in srgb, var(--cool) 12%, transparent));
  color: var(--cool-ink); font-size: var(--fs-xs); font-weight: 600;
  text-decoration: none; white-space: nowrap;
  border: 1px solid color-mix(in srgb, var(--cool) 30%, transparent);
}
.lecitem__pdf:hover { background: color-mix(in srgb, var(--cool) 20%, transparent); }
/* #332（2026-10-12）「跳到网页对应位置」的按钮 —— 与旁边「📄 书中位置」成对出现，
   一个往网页跳、一个往 PDF 跳。故意做成**中性灰**：青色（--cool）已经让给了
   「PDF / 页码」这条线索，暖色（--accent）是编辑类按钮的领地（↑↓、编辑、删除），
   跳转属于「导航」，用灰的才不会跟它们抢注意力。 */
.lecitem__web {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px 9px; border-radius: var(--radius-pill);
  background: var(--surface-2); color: var(--text-2);
  font-size: var(--fs-xs); font-weight: 600;
  text-decoration: none; white-space: nowrap;
  border: 1px solid var(--line);
}
.lecitem__web:hover { background: var(--surface); color: var(--text); border-color: var(--text-2); }
/* 整本预览（#319）：目录页每讲右侧的「📄 整本第 N 页」—— 与题行的页码链接同款，
   只是它在 meta 里，得多留一点左边距才不和前面的标签黏在一起。 */
.leclist__pdf { margin-left: 6px; }
.lecitem__type { margin: 0 0 6px; font-size: var(--fs-sm); font-weight: 600; color: var(--cool-ink); }
.lecitem__stem { font-size: var(--fs-base); line-height: 1.8; white-space: pre-wrap; }
/* 讲义配图（2026-10-12 修 bug：以前题干里只剩下 TikZ 源码，图从来没渲染过）。
   与 `.qfig__img`（题库详情页）同一套口径：
     · 背景写死 `#fff` —— 编译出来的是**透明底黑线**的 SVG，跟主题色走的话
       深色模式下透明处会吃深色背景，整张图变成一块黑方块（#164 的教训）；
     · 不画边框 / 不加内边距（#164 同一口径）；
     · 高度闸门挂在 --fig-max-h 上，与列表页取同一个档位。 */
.lecitem__figs {
  display: flex; flex-wrap: wrap; gap: var(--gap-3);
  margin-top: var(--gap-2);
}
.lecitem__fig {
  display: block; max-width: 100%; height: auto;
  max-height: var(--fig-max-h); width: auto;
  background: #fff;
}
.lecitem__ans { margin-top: var(--gap-3); padding-top: var(--gap-2); border-top: 1px dashed var(--line-strong); }
.lecitem__ans > summary { cursor: pointer; font-size: var(--fs-sm); font-weight: 600; color: var(--accent-hover); }
.lecitem__answer, .lecitem__solution {
  margin-top: 8px; font-size: var(--fs-sm); line-height: 1.75; white-space: pre-wrap;
}
.lecitem__answer { color: var(--text); font-weight: 600; }
.lecitem__solution { color: var(--text-2); }
.lecitem__danger { margin: var(--gap-3) 0 0; text-align: right; }

/* 练习题：缩进到例题下面，左侧一道青线把「从属关系」画出来 */
.lecpralist {
  list-style: none;
  margin: var(--gap-3) 0 var(--gap-2) 26px; padding-left: var(--gap-4);
  border-left: 2px solid var(--cool-line);
  display: flex; flex-direction: column; gap: var(--gap-3);
}
.lecitem--pra { background: var(--surface-2); }

/* ---- ★ 例题底下紧跟的练习题（2026-10-12 用户口径：「每道例题后面跟着同类型的
   练习题，一道或者两道，数量可以动态添加」）----
   视觉上要成立的是**从属关系**：练习必须一眼看出「挂在上面那道例题下」——
     · 左缩进 + 一道竖线：沿用例题卡左侧 26px 的手柄位，竖线一直连到例题卡，
       中间不会被任何东西打断（这是「谁跟谁」的唯一线索，别省）；
     · 背景比例题卡更浅一级（surface-2）：越往下层越淡，不跟例题抢注意力；
     · ⚠️ 底色用**令牌**而不是写死 #fff —— 这里放的是**图文混排的内容**，
       不像配图那样怕深色模式（配图那条 #fff 的规矩见 `.lecitem__fig` 注释）。 */
.lecpracs { margin: var(--gap-3) 0 0 26px; }
.lecpracs__list {
  list-style: none;
  margin: 0 0 var(--gap-2); padding: var(--gap-2) 0 var(--gap-2) var(--gap-4);
  border-left: 2px solid var(--line);
  display: flex; flex-direction: column; gap: var(--gap-3);
}
.lecpracs__item { padding: 0; }
.lecitem--prac {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-3) var(--gap-4);
}
.lecitem--prac .lecitem__head { margin-bottom: var(--gap-2); }
.lecpracs__empty { margin: var(--gap-2) 0 0; font-size: var(--fs-sm); color: var(--text-3); }
/* 「➕ 给这道例题加练习」：展开后的三方式比区级的紧凑一档（它在层级里更下一层） */
.lecadd--prac { margin: var(--gap-2) 0 0; }
.lecadd--prac > summary { font-size: var(--fs-sm); }
.lecadd-group--prac { gap: var(--gap-2); margin-top: var(--gap-2); }
.lecadd-group--prac .lecform { padding: var(--gap-3); }
.lecprac__quick { margin: var(--gap-2) 0 0; }
/* 「➕ 给这道例题加课后作业」（2026-10-15 三类题口径）：与练习入口同规格，
   只是往外挪半格、左缘加一道金橙色条（--accent-2），一眼区分「课上练」与「课下做」。
   ⚠️ 颜色跟 `.lecsec--extend`（课后作业区）同源 —— 同一类题在页面各处同一个色。 */
.lecadd--hw { margin: var(--gap-2) 0 0; }
.lecadd--hw > summary { font-size: var(--fs-sm); }
.lecadd-group--hw { gap: var(--gap-2); margin-top: var(--gap-2); }
.lecadd-group--hw .lecform { padding: var(--gap-3); }

/* 「＋ 加练习题 / 加例题 / 编辑」：折叠框（<details>，无 JS 也能开合） */
.lecadd { margin: var(--gap-3) 0 0; }
.lecadd--pra { margin-left: 26px; }
.lecadd--ex { margin-top: var(--gap-5); }
/* ⚠️ 同上：不在 `.lecadd > summary` 里写 display —— 它会压掉 .btn 的居中，文字贴顶 */
.lecadd > summary { list-style: none; cursor: pointer; }
.lecadd > summary::-webkit-details-marker { display: none; }

.lecform {
  margin-top: var(--gap-3); padding: var(--gap-4);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius);
  display: flex; flex-direction: column; gap: var(--gap-3);
}
.lecform .field { margin-bottom: 0; }
.lecform input[type="text"], .lecform textarea { width: 100%; }
.lecform textarea { font: inherit; line-height: 1.7; }
.lecform__actions { display: flex; align-items: center; gap: var(--gap-3); }

/* 「加到哪儿（插入位置）」下拉（2026-10-13 用户口径 B）
   三条录入路径共用同一个宏 `.field--after > .after-select`：
     · 讲义制作页：三种录入表单里各一个，吃满表单宽（跟题干这类大输入一致）；
     · 挑题页：挤在提交栏右侧，窄一点、不抢「加入这一讲」的视觉重心。
   沿用全局 select 的既有高度与边框，不另造一套，免得跟别的下拉不一样高。 */
.field--after > label {
  display: flex; align-items: center; gap: 6px;
  font-weight: 600;
}
.after-select {
  width: 100%; min-width: 0;
  max-width: 420px;      /* 选项文字最长是「插到「练 3-12」之后」，420 够且不浪费横向 */
}
.pickbar__after {
  display: inline-flex; align-items: center; gap: 8px;
  margin-left: auto;     /* 推到提交栏最右 —— 与「加入这一讲」分开，别挨着误点 */
}
.pickbar__after-k { font-size: var(--fs-sm); color: var(--text-2); white-space: nowrap; }
.pickbar__after .after-select { width: auto; min-width: 180px; max-width: 260px; }

/* 编辑：点开是**浮层**，卡片本身不被撑开、展开收起时整页不跳（同 23 节做法） */
.lecitem__edit { position: relative; display: inline-block; }
.lecitem__edit > summary { list-style: none; cursor: pointer; }
.lecitem__edit > summary::-webkit-details-marker { display: none; }
.lecitem__edit .lecform {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 8;
  width: min(560px, calc(100vw - 48px));
  /* #396（2026-10-15）：同上 —— 编辑框很高（题干/答案/步骤/解析四个大 textarea），
     不限高的话靠底展开会有一大截落在视口外。限高 + 自己滚。 */
  max-height: calc(100vh - 120px);
  max-height: calc(100dvh - 120px);
  overflow: auto;
  overscroll-behavior: contain;
  margin-top: 0;
  background: var(--surface);
  border-color: var(--line-strong);
  box-shadow: var(--sh-3);
}

/* ---- 制作页增强（2026-10-11 第二批）：三种来源 / 拖拽排序 / 挑题页 ---- */

/* 拖拽手柄：只有它能起拖；卡片其余部分仍可正常选字、点链接 */
.lecdrag {
  flex: none; cursor: grab; user-select: none;
  color: var(--text-3); font-size: 15px; line-height: 1;
  padding: 2px 5px; border-radius: 5px;
}
.lecdrag:hover { color: var(--accent); background: var(--accent-soft); }
.lecdrag:active { cursor: grabbing; }
.lecblock.is-dragging, .lecitem.is-dragging { opacity: .55; }

/* ↑ / ↓ 微调（无 JS 时的排序手段；有 JS 时也可用拖拽） */
.lecmove { display: inline-flex; gap: 4px; margin: 0; }
.btn--icon { width: 30px; padding: 0; justify-content: center; font-size: 14px; line-height: 1; }

/* 拓展题：与练习题区分（练习题走松石青、拓展题走珊瑚橙）
   ⚠️ #335：`--extend` 的标签底色已在上方「三种题型标签配色」段里统一按模板
   的 kind 命名重定义（example/practice/extend 三色），这里不再重复定义标签色，
   只留「题卡本体」的淡橙底（表示它是选做/延伸）。 */
.lecitem--extend { background: var(--accent-soft); }

/* 「来自题库」小标 */
.lecitem__src { margin: 8px 0 0; font-size: var(--fs-xs); color: var(--text-3); }

/* 三种来源（手动录入 / 从题库挑选 / 本地文件）并排；展开的表单占满整行 */
.lecadd-group {
  display: flex; flex-wrap: wrap; align-items: flex-start;
  gap: var(--gap-2); margin: var(--gap-3) 0 0;
}
.lecadd-group > .lecadd { margin: 0; }
.lecadd-group .lecform { flex-basis: 100%; }
.chips--kinds { margin-bottom: 0; }
.field__label { display: block; margin-bottom: 6px; font-size: var(--fs-sm); font-weight: 600; color: var(--text-2); }
.panel__title--sub { margin-top: var(--gap-6); }

/* 挑题页 */
.filters--pick { grid-template-columns: minmax(200px, 2fr) minmax(140px, 1fr); }
.filters--pick .filters__actions { grid-column: 1 / -1; }
.pick__count { margin-bottom: var(--gap-3); }
.qrows--pick { gap: var(--gap-2); }
.qrow--pick { padding: var(--gap-3) var(--gap-4); align-items: flex-start; }
.qrow--pick .qrow__main { flex: 1 1 240px; }
.qpick { flex: none; display: inline-flex; align-items: center; padding-top: 2px; cursor: pointer; }
.qpick input { width: 18px; height: 18px; margin: 0; accent-color: var(--accent); cursor: pointer; }
/* 二.5：挑题时已经加入这节课课后作业的题，打一枚醒目角标，并禁用勾选，避免重复添加。 */
.qrow--in { background: var(--accent-soft); }
.qrow__inflag {
  display: inline-block; margin-bottom: var(--gap-2);
  padding: 3px 10px; border-radius: 999px;
  font-size: var(--fs-xs); font-weight: 700;
  color: var(--accent-ink); background: var(--accent);
}
/* 挑题页底部的「加入这一讲」提交栏：粘在视口底部，长列表里也随时能点。
   🔴 2026-10-17 用户报「导入试卷 → 校对页」那段自动拾取说明文字悬浮挡住内容、
   滑不走。根因：这条 `.pickbar` 与校对页的说明条（review.html，role="note"）撞了
   同一个类名，把 sticky 粘底 + 阴影一起带了进去。说明条不是提交栏，用
   `:not([role="note"])` 把它排除 —— 校对页说明条照旧随页面滚动、不再悬浮。 */
.pickbar:not([role="note"]) {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap-3);
  margin-top: var(--gap-4); padding: var(--gap-3) var(--gap-4);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius);
  position: sticky; bottom: var(--gap-3);
  box-shadow: var(--sh-2);
}
.chip--all { margin: 0; }

/* ---- 知识点框的「网页版」（#359 / #360，2026-10-14）----
   与 PDF 的 `kpbox` 同一套配色与形制：暖宣纸底（--bg，= 导出的 SOFT #faf6f2）
   + 珊瑚橙左条 + **没有整框描边**。
   🔴 「没有描边」是关键：例题区 / 练习区 / 拓展区（`.lecsec`）都是
      「浅底 + 整框描边 + 左色条」，知识点框要是也描边，两者就成了同一家人、
      用户说的「背景框重复」就是这么来的；只留一条左色条，一眼就分得开。 */
.kpcard {
  margin: 0 0 var(--gap-4);
  padding: var(--gap-3) var(--gap-4);
  background: var(--bg);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}
.kpcard__head {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px;
  margin-bottom: 6px;
}
.kpcard__t { font-size: var(--fs-sm); font-weight: 700; color: var(--accent-ink); }
.kpcard__hint { font-size: var(--fs-xs); color: var(--text-3); }
.kpcard__list { margin: 0; padding-left: 1.5em; display: grid; gap: 5px; }
.kpcard__list li { line-height: 1.75; }
/* 按句切出来的点自己带一颗珊瑚橙圆点（原标记保留的那类不加，它自己有「一、/1.」） */
.kpcard__list--dot { list-style: none; padding-left: 0; }
.kpcard__list--dot li { position: relative; padding-left: 1.1em; }
.kpcard__list--dot li::before {
  content: ""; position: absolute; left: 2px; top: .72em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--accent);
}
/* 内容自带排版（表格 / 换行）时不硬拆，原样保留换行 */
.kpcard__raw { margin: 0; line-height: 1.75; white-space: pre-wrap; }

/* ---- 讲义制作页：两板块编辑布局（#408，2026-10-15 用户口径） ----
   把一讲的内容分成两块并排的面板：左 = 【讲首呈现 + 考点分类 + 练习】（主讲内容），
   右 = 【课后作业】。窄屏自动上下堆叠，不挤卡片。两面板内部结构与拖拽逻辑
   完全不动（只是外层多包了一层 .lecpanes div），所以不会影响录入 / 排序交互。 */
.lecpane { min-width: 0; }
@media (min-width: 1180px) {
  .lecpanes {
    display: grid;
    grid-template-columns: 1.7fr 1fr;
    gap: var(--gap-6);
    align-items: start;
  }
  /* 课后作业面板吸顶，长讲往下滚时也能随时看到 / 加作业 */
  .lecpane--hw { position: sticky; top: var(--gap-4); }
}

/* ---- 例题区 / 练习区：各自一个背景框（#328-C，2026-10-11 用户口径） ----
   用户原话：「录入新的例题和练习的控件**分别用一个背景框包裹**，
   背景框可以参考试卷导入的背景框，可以是透明背景或者浅色背景等等，
   要求设计得美观」。

   做法：一个 `.lecsec` 就是一个区（背景框）。
     · 底色是**极浅的暖纸色**（比页面底略深一点）—— 比纯白框更透气，
       一眼能看出「这是一个独立的区」，但又不跟里面的题卡抢注意力；
     · 左侧一道 3px 的**色条**区分两个区：例题＝松石青（`--cool`）、
       练习＝珊瑚橙（`--accent`）、拓展＝橙的浅一档；
     · 抬头那枚小圆点 `·lecsec__dot` 与色条同色，标题右边挂一个题数气泡。 */
.lecsec {
  margin-top: var(--gap-6);
  padding: var(--gap-5) var(--gap-5) var(--gap-4);
  border: 1px solid var(--line);
  border-left: 3px solid var(--cool);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.lecsec--example { border-left-color: var(--cool); }
.lecsec--practice { border-left-color: var(--accent); }
.lecsec--extend { border-left-color: var(--accent-2, var(--accent)); }
/* 空的拓展区：弱化到「只是一个入口」，免得看着像忘了填 */
.lecsec--muted { background: transparent; border-style: dashed; border-left-style: solid; }

.lecsec__head { margin-bottom: var(--gap-3); }
.lecsec__title {
  display: flex; align-items: center; gap: 8px;
  margin: 0; font-size: var(--fs-lg); font-weight: 700;
}
/* 旧版抬头那枚小圆点（仅颜色）——#335 起换成有**图案**的徽章 `.lecsec__badge`，
   形状+颜色双通道。`.lecsec__dot` 保留兼容（若别处还在用），不再由本节模板输出。 */
.lecsec__dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--cool); flex: none;
}
.lecsec--practice .lecsec__dot { background: var(--accent); }
.lecsec--extend .lecsec__dot { background: var(--accent-2, var(--accent)); }
/* #335 抬头图案徽章：圆底 + 白图案，底色跟区色一致（例题青 / 练习橙 / 拓展灰）。
   图案形状本身也已不同（灯泡 / 铅笔 / 星），色弱也分得出。 */
.lecsec__badge {
  width: 26px; height: 26px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  flex: none; color: var(--on-solid); background: var(--cool);
}
.lecsec__badge .lecico { width: 15px; height: 15px; }
.lecsec__badge--example { background: var(--cool); }
.lecsec__badge--practice { background: var(--accent); }
.lecsec__badge--extend { background: var(--accent-2, var(--accent)); }
/* 题型图案的统一底座（形状靠各自的 <path>，颜色吃 currentColor） */
.lecico { display: inline-block; vertical-align: -0.14em; fill: currentColor; flex: none; }
.lecsec__n {
  font-size: var(--fs-xs); font-weight: 600; line-height: 1;
  padding: 3px 8px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  color: var(--text-2);
}
.lecsec__note { margin: 6px 0 0; font-size: var(--fs-sm); color: var(--text-3); }
.lecsec__empty {
  margin: var(--gap-3) 0 0; padding: var(--gap-5);
  text-align: center; color: var(--text-3); font-size: var(--fs-sm);
  border: 1px dashed var(--line-strong); border-radius: var(--radius);
  background: var(--surface);
}

/* 三种录入方式：三块并排（窄屏自动换行堆叠），一眼看到三条路 */
.lecsec .lecadd-group { margin-top: var(--gap-3); }
.lecsec .lecadd > summary {
  /* 三个入口做成同宽的「药丸按钮」，视觉上秤不出轻重就说明排对了 */
  min-width: 108px; text-align: center; justify-content: center;
}
/* 展开之后的表单**占满整行**（三块并排时表单要是也跟着挤，就没法填了） */
.lecsec .lecadd[open] { flex-basis: 100%; }
.lecsec .lecadd[open] > summary { margin-bottom: var(--gap-2); }

/* ---- 空拓展区的**轻入口**（#335，2026-10-13）----
   用户口径：「拓展题有就出、没有就不显示」。没有拓展题时**不再**摆一个
   大虚线框（那看着像漏填），只留一行浅色可点入口；点开才出录入控件。
   样式上刻意比 `.lecsec` 轻一档：无底色、无左色条、只一条细虚线，收在页面尾部。 */
.lecsec-addon {
  margin-top: var(--gap-5);
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background: transparent;
}
.lecsec-addon__sum {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px; cursor: pointer;
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-2);
  list-style: none;
}
.lecsec-addon__sum::-webkit-details-marker { display: none; }
.lecsec-addon__sum:hover { color: var(--accent-ink); }
.lecsec-addon__badge {
  width: 22px; height: 22px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  flex: none; color: var(--text-3);
  background: color-mix(in srgb, var(--accent-2, var(--accent)) 14%, transparent);
}
.lecsec-addon__badge .lecico { width: 13px; height: 13px; }
.lecsec-addon__sum .hint { font-weight: 400; }
.lecsec-addon__body { padding: 0 14px 14px; }

/* 区里的题卡：比页面默认更浅，与背景框的浅色底拉开一点点层次 */
.lecsec .lecblock { list-style: none; }
.lecsec .lecitem { background: var(--surface); }
.lecsec .leclist--items { margin-top: var(--gap-3); }

/* ---- 实时预览（2026-10-11 新#2：PDF ↔ 网页双向跳转）----
   一块内联的 PDF 阅读区：iframe 高一点（约一屏），四周留白少一些，
   手机上也保持可用高度（用 dvh 而不是 vh —— 移动端地址栏会吃掉 100vh）。 */
.lecpreview__hint {
  margin-left: 10px; font-size: var(--fs-sm); font-weight: 400; color: var(--text-3);
}
.lecpreview__hint b { color: var(--cool-ink); }
.lecpreview__close { float: right; }
/* 版本切换条（#313）：一排「版本 [下拉框] + 一句话说明」。
   说明用 text-3 弱化 —— 它是解释，不是正文，别跟下拉框抢视线。 */
.lecver {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px 14px;
  margin-top: var(--gap-2);
}
.lecver__field { display: inline-flex; align-items: center; gap: 8px; }
.lecver__cap { font-size: var(--fs-sm); color: var(--text-3); }
.lecver__select {
  padding: 6px 10px; border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--surface); color: var(--text-1); font-size: var(--fs-sm);
}
.lecver__note {
  margin: 0; font-size: var(--fs-sm); color: var(--text-3); flex: 1 1 240px;
}

/* #405（2026-10-15 用户口径「切换版本后应当立即刷新预览」）：
   换版本 / 重载预览时，等待期的那条提示。默认 hidden（由 lecture.js 控制）——
   这里**不能用 `display:none` 之外的方式藏**，否则 [hidden] 会被下面的
   `display:inline-flex` 覆盖掉（属性选择器权重不够，[hidden] 会失效）。 */
.lecpreview__loading {
  display: inline-flex; align-items: center; gap: 8px;
  margin: var(--gap-2) 0 0; padding: 6px 12px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  color: var(--accent-ink); font-size: var(--fs-sm); font-weight: 600;
}
.lecpreview__loading[hidden] { display: none; }
.lecpreview__spin {
  width: 13px; height: 13px; flex: none;
  border: 2px solid var(--accent-line); border-top-color: var(--accent);
  border-radius: 50%;
  animation: lecspin .8s linear infinite;
}
@keyframes lecspin { to { transform: rotate(360deg); } }

/* ---- 「要不要转成解答题形式」确认浮层（#355，2026-10-14）----
   与审核页的快捷键帮助浮层（.kbdhelp）同一套形制：半透明遮罩 + 居中卡片。
   三个出口都做成按钮，不留「点了没反应」的模糊态 —— 老师点「取消」后
   页面什么都不发生是**正确**的，但按钮上得写明白它是「取消这次加入」。 */
.askdlg {
  position: fixed; inset: 0; z-index: 85;
  display: flex; align-items: center; justify-content: center;
  padding: var(--gap-4);
}
.askdlg[hidden] { display: none; }
.askdlg__backdrop { position: absolute; inset: 0; background: rgba(16, 24, 20, .45); }
.askdlg__panel {
  position: relative;
  width: min(520px, 100%);
  padding: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.askdlg__t { margin: 0 0 var(--gap-3); font-size: 16px; }
.askdlg__d { margin: 0 0 var(--gap-3); font-size: 14px; line-height: 1.7; color: var(--text-2); }
/* 两种做法的对比列：左边是做法名，右边一句说明 —— 竖着读得清，不用来回对照。 */
.askdlg__ways { display: grid; gap: 7px; margin: 0 0 var(--gap-4); padding: 0; list-style: none; }
.askdlg__ways li {
  display: grid; grid-template-columns: 5.5em minmax(0, 1fr); gap: 10px;
  padding: 8px 10px; border-radius: var(--radius);
  background: var(--surface-2); font-size: 13.5px; color: var(--text-2);
}
.askdlg__ways b { color: var(--text); font-weight: 600; white-space: nowrap; }
.askdlg__acts { display: flex; flex-wrap: wrap; gap: 10px; }
.askdlg__acts .btn { flex: 1 1 auto; }

@media (max-width: 560px) {
  .askdlg__ways li { grid-template-columns: 1fr; gap: 2px; }
  .askdlg__acts .btn { flex: 1 1 100%; }
}
@media (prefers-color-scheme: dark) {
  .askdlg__backdrop { background: rgba(0, 0, 0, .62); }
}

/* 页内逐页预览（2026-10-16 用户口径）：把 PDF **逐页出图**铺在框里，往下拉＝翻页。
   为什么不用 iframe 直嵌 PDF：手机 / 平板 / 微信内置浏览器的内嵌阅读器往往
   **只画第一页**（「只看到封面」的根源）。出图则任何环境都能看完全部。 */
.lecpreview__pages {
  margin-top: var(--gap-3);
  display: flex; flex-direction: column; gap: var(--gap-3);
  max-height: 80dvh; overflow: auto;
  padding: var(--gap-3);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--surface-2);
  -webkit-overflow-scrolling: touch;
}
.lecpreview__pages:empty { display: none; }
/* 🔴 每页**整页缩进框里**（2026-10-17 第二轮修）：
   上一版写的是 `width:auto; max-width:100%; max-height:74dvh` —— 那要**等图片加载完
   拿到固有尺寸**才有宽度：图没下来之前元素是 0 尺寸，容器跟着塌成一条，手机上很容易看到
   「一片空白/只有半页」。现在固定成
     `width:100%`（立刻就有确定宽度、不等加载）+ `max-height:74dvh`（太高就压到框里）
   + `object-fit:contain`（压的时候**整页等比缩放居中**，绝不裁切）。
   这样无论什么引擎、图片在不在加载中，框里永远是一整页。 */
/* 🔴 每页 = 一个**固定 A4 比例的框**（.lecpage）+ 图绝对定位填满（2026-10-17 第三轮修）。
   前三版都栽在同一件事上：**框的尺寸依赖「图片加载完拿到固有尺寸」**——
   `width:auto` 时图没下来元素就是 0 尺寸，容器跟着塌成一条；`max-height` 也只在加载后
   才起作用；`aspect-ratio` 在 flex 列里不生效（实测被压成 ~54px 高）。手机上网络慢一点
   就表现成「一整片空白 / 只露半页」。
   现在用**padding-top 百分比**这个老办法定比例（`height:0 + padding-top:141.44%`，
   1123/794 = A4），尺寸与任何加载无关、flex 里也稳；图 `position:absolute; inset:0`
   + `object-fit:contain` 填进去：整页永远完整可见、绝不裁切。
   框里还带「第 N 页 · 载入中…」占位（加载完由 JS 加 `.is-ok` 收掉），
   真取不到显示「没取到」—— 不再出现「一片白，看不出是在加载还是坏了」。 */
.lecpage {
  position: relative; display: block; width: 100%;
  height: 0; padding-top: 141.44%;        /* 1123 / 794 —— A4，尺寸立刻确定 */
  border-radius: 4px; overflow: hidden;
  background: #fff; box-shadow: var(--sh-1);
}
.lecpage__img {
  position: absolute; top: 0; left: 0; width: 100%; height: 100%;
  display: block; object-fit: contain;    /* 压的时候整页等比居中，不裁切 */
}
.lecpage::before {
  content: "第 " attr(data-n) " 页 · 载入中…";
  position: absolute; top: 0; right: 0; bottom: 0; left: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--text-3); font-size: var(--fs-sm);
}
.lecpage.is-ok::before { content: none; }
.lecpage--bad::before {
  content: "第 " attr(data-n) " 页没取到 —— 点「收起」再点一次预览"; color: #a32d2d;
}
/* 这一版没编出来时，把原因直接写在框里（不再无限转圈） */
.lecpreview__failed {
  margin: var(--gap-2) 0 0; padding: 8px 12px;
  border-radius: var(--radius-sm);
  background: rgba(192, 57, 43, .08); border: 1px solid rgba(192, 57, 43, .30);
  color: #a32d2d; font-size: var(--fs-sm); white-space: pre-wrap;
}
.lecpreview__failed[hidden] { display: none; }
.lecpreview__loadhint { color: var(--text-3); font-weight: 400; }

@media (max-width: 700px) {
  .lecpralist, .lecadd--pra { margin-left: 10px; }
  .lecgrid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .filters--pick { grid-template-columns: 1fr; }
  /* 手机上一行放不下三个入口 → 堆叠，且都占满宽度（好点） */
  .lecsec { padding: var(--gap-4) var(--gap-3) var(--gap-3); }
  .lecsec .lecadd-group { flex-direction: column; align-items: stretch; }
  .lecsec .lecadd > summary { width: 100%; }
}


/* ================================================================
   25. 图片识题 + 批量上传左右结构（2026-10-11 第六批）
   ----------------------------------------------------------------
   两件事：
     · .upcfg / .imgup：把「配置表单」和「拖拽上传」并排 —— 用户原话
       「每次拖拽试卷都要下拉到下面，非常麻烦」。并排之后拖拽不用再滚。
     · .dropzone--tall + 缩略图：拖拽框做高一点，好瞄、好拖。
   窄屏（<900px）一律堆叠成上下，免得两栏都挤成一条缝。
   ================================================================ */

.upcfg, .imgup {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--gap-6);
  align-items: start;
}
.upcfg__left, .upcfg__right, .imgup__left, .imgup__right { min-width: 0; }

/* 左栏是长表单，右栏是拖拽区 —— 拖拽区「粘」在视口里，滚表单时它不跑走 */
.upcfg__right, .imgup__right { position: sticky; top: 84px; }

.dropzone--tall { padding: var(--gap-7) var(--gap-5); min-height: 240px;
                  display: flex; align-items: center; justify-content: center; }
.dropzone--tall .dropzone__inner { gap: var(--gap-3); }

/* 识别结果页的缩略图 */
.imgup__thumbs { display: flex; flex-wrap: wrap; gap: var(--gap-3); margin-top: var(--gap-4); }
.imgup__thumb {
  position: relative; width: 88px; height: 88px; border-radius: var(--radius-sm);
  overflow: hidden; border: 1px solid var(--line); background: var(--surface-2);
}
.imgup__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.imgup__thumb-x {
  position: absolute; top: 2px; right: 2px; width: 20px; height: 20px; line-height: 18px;
  border: 0; border-radius: 50%; background: rgba(0,0,0,.55); color: #fff;
  font-size: 13px; cursor: pointer; padding: 0;
}
.imgup__thumb-x:hover { background: var(--danger, #c0392b); }

/* 识别结果：每题一个小卡片 */
.imgdraft {
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-2);
  padding: var(--gap-4) var(--gap-5); margin-bottom: var(--gap-4);
}
.imgdraft__head { display: flex; align-items: center; gap: var(--gap-3);
                  margin-bottom: var(--gap-2); flex-wrap: wrap; }
.imgdraft__no { font-weight: 800; color: var(--accent-hover); }
.imgdraft__stem { white-space: pre-wrap; word-break: break-word; }
.imgdraft__meta { font-size: var(--fs-sm); color: var(--text-3); margin-top: var(--gap-3); }
.imgdraft__low { color: var(--warn, #b8860b); font-weight: 600; }

@media (max-width: 900px) {
  .upcfg, .imgup { grid-template-columns: minmax(0, 1fr); }
  .upcfg__right, .imgup__right { position: static; }
  .dropzone--tall { min-height: 170px; padding: var(--gap-6) var(--gap-4); }
}

/* ================================================================
   26. 讲义目录：拖拽手柄 / ↑↓ 工具条 / 新建一讲的行内布局（2026-10-11 #311）

   改动背景：用户要「进书先看目录」「新建一讲别占一大块」「目录能拖能上下移」。
   配色沿用本项目既有令牌：暖色 = 交互主色，青 = 从属信息。
   ================================================================ */

/* 手柄：只在可排序目录里出现。2026-10-14 #361 用户要「更醒目、美观、可爱」——
   从原来那个暗暗的盲文点「⣿」换成六点抓握图标（内嵌 SVG），做成一颗小圆章：
   平时浅底浅字不抢戏，悬停整颗变珊瑚橙、微微放大并轻轻晃一下（可爱感来自这个动作）。

   ⚠️ touch-action:none 是触屏能拖的前提：否则手指按住手柄一移动，浏览器先当成
      「滚动页面」把指针抢走（pointercancel），永远拖不动。 */
.leclist__grip {
  flex: none; width: 26px; height: 30px;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3);
  cursor: grab; user-select: none; touch-action: none;
  border-radius: 999px;
  background: var(--surface-2);
  transition: color .15s, background .15s, transform .15s, box-shadow .15s;
}
.leclist__grip svg { display: block; fill: currentColor; pointer-events: none; }
.leclist__grip:hover {
  color: #fff; background: var(--accent);
  transform: scale(1.12) rotate(3deg);
  box-shadow: 0 3px 10px rgba(232, 97, 60, .32);
  animation: lecgrip-wiggle .5s ease-in-out;
}
.leclist__grip:active { cursor: grabbing; transform: scale(1.04); }
@keyframes lecgrip-wiggle {
  0%, 100% { transform: scale(1.12) rotate(3deg); }
  35%      { transform: scale(1.16) rotate(-6deg); }
  70%      { transform: scale(1.12) rotate(5deg); }
}
/* 键鼠用户也要看得见焦点（a11y） */
.leclist__grip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* 拖动中的那一行：抬起来的感觉 —— 放大一点 + 投影 + 去掉指针事件。
   ⚠️ pointer-events:none 是必需的：脚本用 document.elementFromPoint 探「指针下面
      是哪一行」，被拖的行如果不让开，探到的永远是它自己，就换不了位（#361）。 */
.leclist__row.is-dragging {
  pointer-events: none;
  opacity: .96;
  transform: scale(1.015);
  box-shadow: 0 10px 24px rgba(0, 0, 0, .16);
  border-radius: var(--radius);
  position: relative; z-index: 3;
}
.leclist__row.is-dragging .leclist__main {
  border-style: solid; border-color: var(--accent); background: var(--accent-soft);
}
/* 拖动进行中：整列给一点提示底色，明确「现在可以往这儿放」。
   ⚠️ 选择器要对准**真正挂 class 的那个元素**：lecture-order.js 把 `is-reordering`
      加在 `[data-lesson-order]` 容器（模板里是 <section class="panel">）上，
      而不是它内部的 <ol class="leclist--sortable">。写成 `.leclist--sortable.is-reordering`
      永远匹配不上（两个 class 在**不同**元素上）—— #361 自查时抓到的哑弹。 */
[data-lesson-order].is-reordering { background: linear-gradient(var(--accent-soft), transparent); }

/* 每行右侧的 ↑ ↓ 删除：紧凑一组，别把它们撑得太宽 */
.leclist__tools { flex: none; display: inline-flex; align-items: center; gap: 6px; }
.leclist__tools form { margin: 0; }
.btn--icon {
  width: 30px; min-width: 30px; padding: 0;
  font-size: 14px; line-height: 1; font-variant-numeric: tabular-nums;
}
/* 禁用的箭头：留位置（别让行宽跳动），但要明显「这里不能点」 */
.btn--icon:disabled,
.btn--icon[disabled] {
  opacity: .35; cursor: not-allowed; box-shadow: none;
}

/* 目录面板：标题行下方给一句操作提示 */
.leclist--sortable { gap: 8px; }

/* 窄屏：手柄收窄、工具条换行到下一行，别和标题挤成一条 */
@media (max-width: 640px) {
  .leclist__grip { width: 24px; height: 28px; }
  .leclist__row { flex-wrap: wrap; }
  .leclist__main { flex-basis: calc(100% - 32px); }
  .leclist__tools { margin-left: 32px; }
  .leclist__meta { display: none; }   /* 手机上先让标题完整显示 */
}

/* ================================================================
   第 27 节：讲义条目的「答案 / 解题步骤 / 解析」三层（2026-10-11 #313）
   用户口径：「讲义里面的答案解析格式要跟题目界面保持一致。」
   → 结构照题库详情页：答案（珊瑚橙高亮块）→ 解题步骤（克制，浅描边）
     → 解析（折叠，想深究再点）。
   之所以不直接复用题库的 .qsteps / .qsol：那两个类是配 .qcard__block 的
   外框布局，讲义条目没有那层卡片，硬套会多出一圈边框。
   ================================================================ */

/* 答案区外框：与题干之间一条虚线分隔，收起时不占高度。 */
.lecitem__ans {
  margin-top: var(--gap-3);
  padding-top: var(--gap-3);
  border-top: 1px dashed var(--line-strong);
  display: grid;
  gap: var(--gap-3);
}

/* 一行 = 标签 + 内容，两栏对齐。
   🔴 #402（2026-10-15 用户口径：「答案的具体内容距离『答案』字样太远了，
       答案框被拉伸占满整行」）：
       · 标签列原先**写死 68px**（为「解题步骤」四个字留的），可「答案」两字只占
         ~28px，剩下 40px 全是空的 ⇒ 内容被推得老远。改成 `max-content`：
         标签**按自己的字数收窄**，内容紧贴着它起排。
       · `gap` 从 gap-3(12px) 收到 gap-2(8px)，近一步贴近。
       （旧写法还有个副作用：短答案的橙底框被 1fr 撑成整行宽，看着像空了一大片。） */
.lecitem__ansrow {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--gap-2);
  align-items: start;
}
/* 🔴 #411（2026-10-15 用户口径）：「网页版每道题答案不要跟题号后，应在题号下一行显示、
   写『答案』标识、**与解析用不同颜色区分**」。
   → 标签**跟着答案块走珊瑚橙**（原来写的是松石青，于是「答案」俩字和「解析」同色，
     等于没区分）；解题步骤保持中性（它是垫底的，不抢戏）。 */
.lecitem__anslabel {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--accent-ink);
  padding-top: 2px;
}
.lecitem__anslabel--steps { color: var(--text-2); }

/* 答案本身用珊瑚橙高亮块：全页唯一确定的值，眼睛先落这儿。
   #402：`justify-self: start` + `max-width: 100%` —— 橙底框**按内容收窄**
   （短答案不再被拉成整行宽的空白条），长答案仍能正常换行不溢出。 */
.lecitem__ansrow .qans {
  padding: 8px 12px;
  justify-self: start;
  max-width: 100%;
}

/* 解析：折叠起来，标题像个小按钮。
   🔴 #411：整块改成**松石青**（原先是灰底灰边），与珊瑚橙的答案成对 ——
   配色与 PDF 侧一致（答案橙 / 解析青），也和**题库详情页**的 `.qsol` 同口径
   （用户 #313 提过「讲义里的答案解析格式要跟题目界面保持一致」）。 */
.lecitem__sol > summary {
  cursor: pointer;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--cool-ink);
}
.lecitem__sol > summary::marker { color: var(--cool); }
.lecitem__sol > .tex {
  margin-top: var(--gap-2);
  padding: 10px 12px;
  background: var(--cool-soft);
  border-left: 3px solid var(--cool);
  border-radius: var(--radius-sm);
  color: var(--text);
  line-height: 1.95;
}

@media (max-width: 640px) {
  .lecitem__ansrow { grid-template-columns: 1fr; gap: 4px; }
  .lecitem__anslabel { padding-top: 0; }
}

/* ================================================================
   第 28 节：讲内二级目录 + 分组标题（2026-10-11 #313）
   用户口径：「讲义里面能不能也像题目界面一样有个小目录，按题型分」。
   目录横排成胶囊（题型数一般 3~6 个，横排比竖排省高度）
   → 点了跳到那一组（锚点 #g-<key>）；分组标题在每组第一道例题上方画一条
     带色的细线，横向把「这几种题型」在版面上分开。
   ================================================================ */

.lecsub {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-bottom: var(--gap-4);
  padding: 10px 12px;
  background: var(--cool-soft);
  border: 1px solid var(--cool-line);
  border-radius: var(--radius-sm);
}
.lecsub__cap {
  font-size: var(--fs-sm); font-weight: 700; color: var(--cool-ink);
  margin-right: 2px;
}
.lecsub__item {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: var(--radius-pill);
  background: var(--surface); border: 1px solid var(--cool-line);
  color: var(--cool-ink); font-size: var(--fs-sm); font-weight: 600;
  text-decoration: none;
  transition: background .15s, border-color .15s, color .15s;
}
.lecsub__item:hover {
  background: var(--cool); border-color: var(--cool);
  color: var(--on-solid);
}
.lecsub__n {
  font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
  padding: 0 5px; border-radius: var(--radius-pill);
  background: var(--cool-soft); color: var(--cool-ink);
}
.lecsub__item:hover .lecsub__n { background: rgba(255, 255, 255, .28); color: var(--on-solid); }

/* 分组标题：题型名 + 一条渐隐的横线，把版面横向切开（不占太多高度）。 */
.lecgroup {
  list-style: none;
  display: flex; align-items: center; gap: var(--gap-3);
  margin: var(--gap-2) 0 0;
}
.lecgroup__name {
  flex: none;
  font-size: var(--fs-md); font-weight: 700; color: var(--accent-ink);
  padding-left: 10px;
  border-left: 4px solid var(--accent);
  line-height: 1.35;
}
.lecgroup__rule {
  flex: 1; height: 1px;
  background: linear-gradient(to right, var(--accent-line), transparent);
}
/* 锚点跳过来时给个落点偏移，别被吸顶的顶栏盖住标题。 */
.lecgroup, .lecblock { scroll-margin-top: 84px; }

@media (max-width: 640px) {
  .lecsub { padding: 8px 10px; }
  .lecsub__cap { flex-basis: 100%; margin-bottom: 2px; }
}

/* ================================================================
   第 29 节：背景框「从题库补」选择页（2026-10-11 #313）
   知识点动辄几百个，用 chip 云而不是长列表：一行能塞 4~6 个，
   扫读快、勾选轻；容器给个上限高度 + 滚动，别把按钮顶到屏幕外。
   ================================================================ */

.ipick {
  max-height: 340px;
  overflow-y: auto;
  align-content: flex-start;
  padding: 4px 2px;
}
.ipick__chip {
  cursor: pointer;
  user-select: none;
}
.ipick__chip input { margin-right: 4px; }
.ipick__chip:hover { border-color: var(--accent-line); }
/* 勾中的 chip 高亮（`:has()` 现代浏览器都支持；不支持的只是不高亮，不影响功能） */
.ipick__chip:has(input:checked) {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
}

/* ================================================================
   第 30 节：挑题 → 课后作业（2026-10-12「一条龙」）
   浮层里嵌的是一张完整的挑题页，所以这里只管两件事：
     · 浮层本身的尺寸（够大才扫得快，但不能超出矮屏）；
     · 嵌入态（body.pickembed）把挑题页的顶栏 / 页脚 / 面包屑收掉，
       免得在一屏里出现两套导航。挑题页的列表、筛选、分页一律复用已有样式。
   ================================================================ */

.hwpick {
  border: none;
  border-radius: var(--radius);
  padding: 0;
  width: min(940px, 94vw);
  height: min(86vh, 800px);
  background: var(--surface);
  box-shadow: 0 24px 60px rgba(20, 24, 40, 0.28);
  color: var(--text);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* 🔴 2026-10-22 修：`<dialog>` 关闭态本靠 UA 的 `dialog:not([open]){display:none}`
   隐藏，但上面 `.hwpick{display:flex}` 是 author 规则，权重压过 UA 那条，
   于是 dialog 关了还在页面上内联渲染 —— 手机上就是「一个大框 + 一直显示正在打开题库」。
   这里显式补一条 `:not([open])` 把关闭态摁死（与 .hwview 同款，见 8359）。 */
.hwpick:not([open]) { display: none; }
.hwpick::backdrop { background: rgba(15, 18, 30, 0.5); }
.hwpick__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--gap-3) var(--gap-5);
  border-bottom: 1px solid var(--line);
}
.hwpick__title { margin: 0; font-size: var(--fs-lg); }
.hwpick__x {
  border: none; background: none; cursor: pointer;
  font-size: 22px; line-height: 1; color: var(--text-3); padding: 4px 8px;
}
.hwpick__x:hover { color: var(--text); }
/* 2026-10-22：iframe 外包一层 stage，载入中盖一块说明（以前是整块白，像坏了）。
   stage 用 flex 撑满、min-height:0 让里面的 iframe 能正确收缩（否则 flex 子项
   默认 min-height:auto，会被挑题页的内容顶得很高）。 */
.hwpick__stage { position: relative; flex: 1 1 auto; min-height: 0; display: flex; }
.hwpick__frame { flex: 1 1 auto; width: 100%; height: 100%; border: none; background: var(--surface); }
.hwpick__loading {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--gap-3);
  background: var(--surface); color: var(--text-3); font-size: var(--fs-sm);
}
.hwpick__loading[hidden] { display: none; }
.hwpick__retry {
  border: 1px solid var(--accent-line); background: var(--accent-soft);
  color: var(--accent-ink); border-radius: var(--radius-pill);
  padding: 6px 14px; font-size: var(--fs-sm); cursor: pointer;
}
.hwpick__retry[hidden] { display: none; }
.hwpick__foot {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  flex-wrap: wrap;
  padding: var(--gap-3) var(--gap-5);
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}
.hwpick__count { font-size: var(--fs-sm); color: var(--text-3); }
.hwpick__acts { margin-left: auto; display: flex; gap: var(--gap-2); }

/* 嵌入态：挑题页自己的 chrome 全部撤掉，只留内容 */
body.pickembed .topbar,
body.pickembed .foot,
body.pickembed .skip-link,
body.pickembed .crumbs { display: none; }
body.pickembed .wrap { padding: var(--gap-3) var(--gap-4) 0; max-width: none; }
body.pickembed .paperpick { display: none; }        /* 浮层里不需要「加入试卷」 */

.picknav {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  flex-wrap: wrap;
  margin-bottom: var(--gap-3);
}
.pickbar--sticky {
  position: sticky;
  bottom: 0;
  background: var(--surface);
  box-shadow: 0 -6px 18px rgba(20, 24, 40, 0.08);
}
.pickbar__n { font-size: var(--fs-sm); color: var(--text-2); }

/* ================================================================
   第 30b 节：4️⃣周中作业（2026-10-13 需求⑥）

   与「3️⃣课后作业」并排的两个面板，但性质完全不同：那个是**贴微信的纯文本**，
   这个是**能打印发下去的真题文档**（带图带格式）。所以这里刻意把它做「重」一点：
     · 每道题一行，左边一个大号序号（打出来一栏能对上），右边题干；
     · 操作按钮（↑ ↓ ×）平时**压到很淡**，鼠标/键盘进到这一行才显出来 ——
       一屏十几行时，满屏的按钮会把题干压没。
     · 底部一条导出栏，和组卷页的导出观感对齐（同一批 .btn--ghost）。
   数据型区块（「共 N 道」）借 --cool 冷色点缀，与主色区分开。 */

.midweek .hint { margin-bottom: var(--gap-3); }
.midweek__acts { margin-left: auto; }
.midweek__newhint { padding: var(--gap-4); }

.mwlist {
  list-style: none;
  margin: 0 0 var(--gap-4);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--gap-2);
}

.mwrow {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-3);
  padding: var(--gap-3) var(--gap-3) var(--gap-3) var(--gap-4);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm, 8px);
  transition: border-color .15s ease, background .15s ease;
}
.mwrow:hover,
.mwrow:focus-within {
  background: var(--surface);
  border-color: var(--accent-line);
}

/* 序号：定宽右对齐，两列数字也在一条线上（打完题号栏很整齐） */
.mwrow__no {
  flex: 0 0 auto;
  min-width: 1.8em;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: var(--fs-lg);
  line-height: 1.3;
  color: var(--cool);
}

.mwrow__body { flex: 1 1 auto; min-width: 0; }
.mwrow__stem {
  line-height: 1.65;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.mwrow__stem p { margin: 0 0 var(--gap-2); }
.mwrow__stem p:last-child { margin-bottom: 0; }
.mwrow__body .tag { margin-top: var(--gap-2); margin-right: var(--gap-2); }

/* 操作区：默认淡出，进来才亮 —— 见本节开头说明 */
.mwrow__ops {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 2px;
  /* 🔴 #429 修复：操作按钮（上移/下移/移出）常驻可见，不再用 opacity:0 仅 hover 显形。
     旧写法在触屏笔记本上 Windows 媒体查询报 hover:hover，@media (hover:none) 永不开火，
     × 按钮永远看不见也点不到，老师就以为「删除按钮失效」。
     hover 现在只做轻微强调（背景色在下面 .mwrow__btn:hover 里），不再承担「显形」职责。 */
  opacity: 1;
}

.mwrow__btn {
  border: 1px solid transparent;
  background: none;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 6px 8px;
  border-radius: 6px;
  color: var(--text-3);
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.mwrow__btn:hover:not(:disabled) {
  background: var(--surface-3);
  color: var(--text);
}
.mwrow__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.mwrow__btn--del:hover:not(:disabled) {
  background: var(--danger-soft);
  color: var(--danger);
  border-color: var(--danger-line);
}
/* disabled 只做「按不动」的视觉，不摘掉 hover 之外的可读性 */
.mwrow__btn:disabled { opacity: .3; cursor: default; }

.midweek__foot {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  flex-wrap: wrap;
  padding-top: var(--gap-3);
  border-top: 1px dashed var(--line);
}
.midweek__foot .hint { margin: 0; }
.midweek__foot .hint b { color: var(--cool); font-variant-numeric: tabular-nums; }
.midweek__footacts { margin-left: auto; display: flex; gap: var(--gap-2); flex-wrap: wrap; }

/* 「课后作业一键导出 PDF」那一行：一句话 + 一个按钮，同基线、留白克制。
   为什么不用 .hint 直接塞按钮：.hint 是段落级（有上边距），这里的按钮要跟文字
   在同一行里居中，单独一个档位更稳，也不会被 .hint 的样式牵着走。 */
.hint--act {
  margin: var(--gap-2) 0 0;
  display: flex;
  align-items: center;
  gap: var(--gap-2);
  flex-wrap: wrap;
}

/* ================================================================
   「新建一讲」表单（#337，2026-10-12 用户反馈「太丑了，一点也不美观」）

   重做前：三列硬排一行（挑专题 / 标题 / 插入位置），列宽靠
   `grid-template-columns` 硬分。窄一点就塌 —— 徽章折行、hint 竖成三条、
   下拉和按钮上下拆开，参差难看（用户截图就是这个）。

   重做后：**主次分行，一行一件事**。每行是 flex，行内元素按内容给宽，
   窄屏自己换行 —— 不再让「列宽」去猜「内容宽度」。
     · .lecnew__row            一行；行间用 gap 拉开
     · .lecnew__row--main      标题（主输入位，整行吃满）
     · .lecnew__row--tail      插入位置 + 提交按钮（按钮紧跟在插入位置后面）
   `panel--newlesson` 只把内边距放宽一点，让整个表单透气。

   #344（2026-10-13，用户第三次发同一张截图）：宽屏下「挑专题」下拉被
   `width:100%` 拉到近 900px，右边把「➕ 补一个新专题」甩出半个屏幕；且它与
   「插入位置」下拉一宽一窄，两行不对齐。改法：**两个下拉共用 `--lecnew-ctl`
   这一档宽（420px）**，按钮紧贴各自下拉，两行左右成一条线。 */
.panel--newlesson { padding: var(--gap-5); }
/* 表单里三个「控件列」统一宽度：挑专题下拉 / 插入位置下拉 / 提交按钮都按这个档
   排版，两行下拉自然左右对齐、按钮跟在各自下拉后面（#344）。 */
.panel--newlesson { --lecnew-ctl: 420px; }
.lecnew { display: flex; flex-direction: column; gap: var(--gap-4); }
.lecnew__row {
  display: flex; align-items: flex-end; gap: var(--gap-4); flex-wrap: wrap;
}
.lecnew__row > .field { margin-bottom: 0; }
.lecnew__row--main .field--grow { flex: 1 1 100%; min-width: 0; }
/* 插入位置固定一段宽（够放「放到第 12 讲「……」之后」），提交按钮跟在后面 */
.lecnew__row--tail { justify-content: flex-start; }
.lecnew__row--tail .field--after { flex: 0 1 var(--lecnew-ctl, 420px); min-width: 220px; }
.lecnew__actions { display: flex; align-items: center; gap: var(--gap-2); }
.lecnew__actions--end { margin-left: auto; }
/* 表单里的 label 是主信息，比 .filters 那套重一点，和输入框成对 */
.lecnew .field > label {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-weight: 600;
}
/* 徽章（「本书大类：计算」）：挨着标签、可自己折行，不顶乱 label */
.lecnew .lec-pick__own { margin-left: 0; white-space: normal; }
/* 🔴 #344（用户第三次发同一张截图说还丑）：宽屏下「挑专题」下拉被拉满整行，
   里面只写着一句「（不用，我自己写）」，右边空出一大段，而「➕ 补一个新专题」
   被甩到面板另一头 —— 两件相关的事隔了半个屏幕。改法：**给下拉一个舒服的
   上限宽**（和「插入位置」下拉同宽），按钮紧跟在它右边；一行里的东西才会
   「看起来是一起的」。窄屏时按钮自然折到下一行，不挤。 */
.lecnew .lec-pick { width: 100%; align-items: flex-end; }
.lecnew .lec-pick select { flex: 0 1 var(--lecnew-ctl, 420px); min-width: 0; }
/* 「➕ 补一个新专题」跟旁边的下拉**等高**（下拉 38px；`.btn--sm` 本档只有 30px，
   矮半头看着像附属品）。提到 36px，和提交按钮同档，一排控件齐平。 */
.lecnew .lec-pick .btn { flex: none; height: 36px; }
.lecnew .hint { margin-top: 5px; }
/* 🔴 #337 第二遍（用户第二次发同一张截图说还丑）：上一版已把「三列塌方」治了，
   剩下三处「一眼就不齐」，这版逐条收掉 ——

   ① 面板头「新建一讲」和副标题挤在同一行（`panel__head` 是横向 flex），
      副标题还被推到最右、离开标题老远。改成**上下两行**：标题在上、说明在下面
      紧挨着，左对齐，跟表单的左边缘成一条线。
   ② 提交按钮单独占一行、跑在「插入位置」右边，中间空一大片；按钮还只有 30px
      高（.btn--sm 那一档），比旁边的下拉（~36px）矮半头，看着更掉价。
      改成：插入位置 + 按钮同处一行、**都按内容给宽、按钮紧跟在插入位置后面**
      （不再 `space-between` 顶到最右），并让按钮与下拉**等高**。
   ③ 标签与输入框之间只隔 2px，挤在一起；统一放到 6px，标签和控件有呼吸。
   —— 这三条改的都是「对齐与呼吸」，不动字段与提交逻辑。 */
.panel--newlesson .panel__head {
  display: block;                 /* 标题 / 说明改成上下两行 */
  margin-bottom: var(--gap-4);
}
.panel--newlesson .panel__title { margin-bottom: 3px; }
.panel--newlesson .panel__hint { margin-top: 0; }
/* 标签与控件之间留一口气（原来是紧挨着的） */
.lecnew .field > label { margin-bottom: 6px; }
/* 🔴 提交按钮与同排的下拉**等高**：`align-items:flex-end` 只对齐底边，
   高度差照样看得见（按钮矮半头）。让这一行内所有控件取同一高度 —— 36px
   是全站输入框的既有高度（.input / select 的档位），按钮跟它齐平最稳。 */
.lecnew__row--tail { align-items: flex-end; }
.lecnew__row--tail .lecnew__actions { height: 36px; }
.lecnew__row--tail .btn { height: 36px; padding: 0 16px; }
.lecnew .lecnew__actions { margin-left: 0; }

/* ================================================================
   「新建一讲」标题下拉 + 「➕ 补一个新专题」（2026-10-12 #327）
   下拉和按钮同排，按钮不喧宾夺主；补专题时行长在下面展开，不挤走下拉。 */
.lec-pick { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.lec-pick select { flex: 1 1 220px; min-width: 0; }
.lec-pick__own {
  margin-left: 8px; font-size: var(--fs-sm); font-weight: 400;
  color: var(--accent-ink); background: var(--accent-soft);
  border-radius: var(--radius-sm); padding: 1px 8px;
}
.lec-pick__new { display: inline-flex; align-items: center; gap: 6px; margin-top: 6px; }
.lec-pick__new input { flex: 1 1 180px; min-width: 0; }
.lec-pick__msg { display: block; margin-top: 6px; font-size: var(--fs-sm); color: var(--ok-ink, #16794a); }
.lec-pick__msg.is-bad { color: var(--danger-ink, #b3261e); }

/* 「往下拉看全部 / 另开新窗口」提示条（2026-10-16 用户口径：两条路都由用户自己选） */
.lecpreview__bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 var(--gap-2); padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--accent-soft); color: var(--text-2); font-size: var(--fs-sm);
}
.lecpreview__barhint { flex: 1 1 200px; min-width: 0; }
/* 「在新窗口打开完整版」：做成主色描边的药丸（带外链图标），比裸文字按钮更有分量 */
.lecpreview__openlink {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  padding: 8px 14px; border-radius: var(--radius-pill);
  background: var(--surface); border: 1px solid var(--accent-line);
  color: var(--accent-hover); font-size: var(--fs-sm); font-weight: 600;
  text-decoration: none; box-shadow: var(--sh-1);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), transform var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.lecpreview__openlink svg { flex: 0 0 auto; }
.lecpreview__openlink:hover {
  background: var(--accent); border-color: var(--accent); color: var(--on-solid);
  text-decoration: none; transform: translateY(-1px); box-shadow: var(--sh-3);
}
.lecpreview__openlink:active { transform: translateY(0); }

/* ================================================================
   整班反馈（2026-10-16）：班级页 + 整班反馈表单
   ================================================================ */

/* 班级页：加学生表单 / 整体情况 / 整班反馈列表 */
.clsadd { margin-top: var(--gap-2); align-items: flex-end; }
.clsyl { margin: 0 0 10px; }
.clsyl b { display: block; margin-bottom: 2px; color: var(--text-2); font-size: var(--fs-sm); }
.clsyl p { margin: 0; white-space: pre-wrap; }
.clmetrics { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 6px; color: var(--text-2); }
.clmetrics b { color: var(--text-1); font-size: 1.1em; }

.clsles { display: flex; flex-direction: column; gap: 10px; }
.clsles__item {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px;
  padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.clsles__main { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.clsles__acts { margin-left: auto; display: flex; gap: 8px; }
.clsles__mw { flex-basis: 100%; margin: 0; font-size: var(--fs-sm); }

/* 整班反馈表单 */
.clform { display: flex; flex-direction: column; gap: var(--gap-2); }
.clform__main { display: flex; flex-direction: column; gap: var(--gap-2); }
.clparts { display: flex; flex-direction: column; gap: 14px; }
.clpart {
  padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); border-left: 3px solid var(--accent-teal, #0f8a9d);
}
.clpart__head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.clpart__name { display: inline-flex; align-items: center; gap: 8px; font-size: 1.02em; }
.clpart__av {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--accent-teal-soft, #e3f3f6); color: var(--accent-teal, #0f8a9d);
  font-size: var(--fs-sm); font-weight: 600;
}
.clpart__acts { margin-left: auto; display: flex; gap: 8px; }
.clpart__preview { margin-top: 8px; }
.clpart__preview[hidden] { display: none; }

/* AI 智能拆分 */
.clsplit__body { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.clsplit__body[hidden] { display: none; }
.clsplit__acts { display: flex; align-items: center; gap: 10px; }
.clsplit__msg { font-size: var(--fs-sm); color: var(--text-2); }

/* 首页「我的班级」：大类型快速导航（点击平滑滚动到对应区块） */
.clnav { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 14px; }
.clnav__chip {
  display: inline-flex; align-items: center; padding: 5px 14px;
  border-radius: 999px; background: var(--surface); color: var(--text-1);
  border: 1px solid var(--border); font-size: var(--fs-sm); text-decoration: none;
  transition: background .15s, border-color .15s;
}
.clnav__chip:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-ink); }
.claddbtn { margin-top: 10px; }


/* ================================================================
   运行状态页（/status）—— 2026-10-15
   页脚原来直指 /healthz（JSON），用户点开满屏代码、像网站坏了。
   这一节把同一批检查渲染成「绿点 / 红点 + 人话」。 */
.statusz {
  display: flex; align-items: center; gap: var(--gap-3);
  padding: var(--gap-4) var(--gap-4);
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface-2);
}
.statusz--ok { border-color: var(--ok-line); background: var(--ok-soft); }
.statusz--bad { border-color: var(--danger-line); background: var(--danger-soft); }
.statusz__dot {
  flex: 0 0 auto; width: 12px; height: 12px; border-radius: 50%;
  background: var(--text-3); box-shadow: 0 0 0 4px rgb(0 0 0 / 5%);
}
.statusz--ok .statusz__dot, .statusz__row--ok .statusz__dot { background: var(--ok); }
.statusz--bad .statusz__dot, .statusz__row--bad .statusz__dot { background: var(--danger); }
.statusz__title { font-size: 1.15rem; font-weight: 700; color: var(--text); }
.statusz__sub { font-size: var(--fs-sm); color: var(--text-2); margin-top: 2px; }

.statusz__list { list-style: none; margin: var(--gap-4) 0 0; padding: 0; }
.statusz__row {
  display: flex; align-items: center; gap: var(--gap-3);
  padding: 10px var(--gap-3); border-bottom: 1px solid var(--line);
}
.statusz__row:last-child { border-bottom: 0; }
.statusz__row .statusz__dot { width: 9px; height: 9px; box-shadow: none; }
.statusz__name { font-weight: 600; min-width: 6em; color: var(--text); }
.statusz__detail { color: var(--text-2); font-size: var(--fs-sm); word-break: break-word; }

/* ---------- 全站子页面「返回上一级」（js/backnav.js 注入） ---------- */
.backnav { margin: 0 0 var(--gap-4); }
.backnav__link {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 13px 6px 9px;
  font-size: var(--fs-sm); font-weight: 600; line-height: 1;
  color: var(--accent-ink);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, transform .08s ease;
}
.backnav__link:hover { background: #fbe2d6; border-color: var(--accent); color: var(--accent-hover); }
.backnav__link:active { transform: translateY(1px); }
.backnav__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.backnav__ico { width: 18px; height: 18px; flex: 0 0 auto; }

/* ---------- 学校来源「系 → 校区」两级联动（js/schoolcascade.js） ---------- */
.schoolcascade { display: flex; flex-wrap: wrap; gap: 8px; }
.schoolcascade select { flex: 1 1 150px; min-width: 150px; }

/* ============================================================
   上课时间「时间段胶囊」高级版（2026-10-17，需求①）
   替换原生 <input type=time>：自绘胶囊 + 弹层时/分药丸 + 时长胶囊 + 日期快捷药丸。
   设计语言：珊瑚橙主色管交互、松石青点缀时长；圆角药丸 + 轻阴影，年轻化。
   ============================================================ */
.timerange__display { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.trcap {
  appearance: none; cursor: pointer; font: inherit;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 10px 18px; border-radius: var(--radius-pill);
  background: var(--surface); color: var(--text);
  border: 1.5px solid var(--accent-line);
  font-weight: 700; font-size: var(--fs-lg); font-variant-numeric: tabular-nums;
  letter-spacing: .5px;
  box-shadow: var(--sh-1);
  transition: border-color .15s, box-shadow .15s, transform .15s, background .15s;
}
.trcap:hover { border-color: var(--accent); transform: translateY(-1px); }
.trcap__t { line-height: 1; }
.trcap::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent); flex: 0 0 auto;
}
.trcap[data-tr-cap="end"]::before { background: var(--cool); }
.timerange.is-open .trcap { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.timerange__sep { color: var(--text-3); font-weight: 700; font-size: var(--fs-lg); }
.trcap__dur {
  font-size: var(--fs-sm); font-weight: 700; color: var(--cool);
  background: rgba(15, 138, 157, .12);
  border: 1px solid rgba(15, 138, 157, .30);
  padding: 3px 12px; border-radius: var(--radius-pill); white-space: nowrap;
  font-variant-numeric: tabular-nums; visibility: hidden;
}
.trcap__dur.is-shown { visibility: visible; }

/* 弹层：开始 / 结束 两栏，时 / 分各一排药丸（5 分钟步进） */
.trpop {
  margin-top: 10px; display: flex; gap: 16px; flex-wrap: wrap;
  padding: 16px; background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: var(--radius-lg);
  box-shadow: var(--sh-3); position: relative;
}
.trpop[hidden] { display: none; }
.trpop__side { display: flex; flex-direction: column; gap: 8px; min-width: 150px; }
.trpop__label { font-weight: 700; font-size: var(--fs-sm); color: var(--text-2); }
.trpop__group { display: flex; align-items: center; gap: 8px; }
.trpop__glabel { font-size: var(--fs-xs); color: var(--text-3); width: 14px; flex: 0 0 auto; }
.trpop__hours, .trpop__mins {
  display: flex; flex-wrap: wrap; gap: 6px; padding: 2px;
  max-height: 132px; overflow: auto;
}
.trpop__hours { max-width: 224px; }
.trpop__mins { max-width: 332px; }
.trpill {
  appearance: none; cursor: pointer; font: inherit; font-weight: 600;
  font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
  width: 38px; height: 34px; border-radius: 10px;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border);
  transition: background .12s, color .12s, border-color .12s, transform .12s;
}
.trpill:hover { border-color: var(--accent); transform: translateY(-1px); }
.trpill.is-on {
  background: var(--accent); color: #fff; border-color: var(--accent);
  box-shadow: 0 2px 8px rgba(232, 97, 60, .35);
}
.trpop__divider { width: 1px; background: var(--line); align-self: stretch; }
.trpop__foot { flex-basis: 100%; display: flex; justify-content: flex-end; margin-top: 4px; }

/* 日期快捷药丸（今天 / 昨天 / 前天） */
.datecap__quick { display: flex; gap: 8px; margin-top: 8px; }
.datecap__quick button {
  appearance: none; cursor: pointer; font: inherit; font-weight: 600; font-size: var(--fs-sm);
  padding: 6px 14px; border-radius: var(--radius-pill);
  background: var(--surface-2); color: var(--text-2); border: 1px solid var(--border);
  transition: background .12s, color .12s, border-color .12s;
}
.datecap__quick button:hover { border-color: var(--accent); color: var(--accent-ink); }
.datecap__quick button.is-on { background: var(--accent-soft); color: var(--accent-ink); border-color: var(--accent-line); }

/* ============================================================
   多选下拉（加入学生，需求③）：搜索 + 复选框 + 已选人数胶囊，年轻化。
   ============================================================ */
.mselect { position: relative; }
.mselect__trigger {
  appearance: none; cursor: pointer; font: inherit; text-align: left;
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 14px; border-radius: var(--radius);
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border);
  transition: border-color .12s, box-shadow .12s;
}
.mselect__trigger:hover { border-color: var(--accent); }
.mselect.is-open .mselect__trigger { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.mselect__placeholder { color: var(--text-3); }
.mselect__count {
  margin-left: auto; font-size: var(--fs-xs); font-weight: 700; color: var(--accent-ink);
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  padding: 1px 10px; border-radius: var(--radius-pill); white-space: nowrap;
}
.mselect__caret { color: var(--text-3); transition: transform .15s; }
.mselect.is-open .mselect__caret { transform: rotate(180deg); }
.mselect__panel {
  position: absolute; z-index: 30; top: calc(100% + 6px); left: 0; right: 0;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius); box-shadow: var(--sh-3); padding: 10px;
  max-height: 320px; display: flex; flex-direction: column; gap: 8px;
}
.mselect__panel[hidden] { display: none; }
.mselect__search input {
  width: 100%; padding: 8px 12px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--surface-2); font: inherit;
}
.mselect__opts { overflow: auto; display: flex; flex-direction: column; gap: 2px; }
.mselect__opt {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  border-radius: var(--radius-sm); cursor: pointer; font-size: var(--fs-base);
  transition: background .1s;
}
.mselect__opt:hover { background: var(--surface-2); }
.mselect__opt input { width: 16px; height: 16px; accent-color: var(--accent); }
.mselect__opt-name { flex: 1 1 auto; }
.mselect__foot { display: flex; justify-content: space-between; gap: 8px; }
.mselect__newstu { margin-left: auto; white-space: nowrap; }

/* ============================================================
   班型人数小徽章（需求⑤）+ 顶部班型导航锚点平滑滚动（需求⑥）
   ============================================================ */
.ctbadge {
  display: inline-flex; align-items: center; font-size: var(--fs-xs); font-weight: 700;
  color: var(--cool); background: rgba(15, 138, 157, .12);
  border: 1px solid rgba(15, 138, 157, .30);
  padding: 2px 12px; border-radius: var(--radius-pill); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.clslist__empty { grid-column: 1 / -1; }
.stucard--anchor { cursor: pointer; }
html { scroll-behavior: smooth; }
.ctgroup { scroll-margin-top: 84px; }

/* ============================================================
   学生档案首页 · 三个入口卡片（2026-10-16 需求⑤）
   样式对标「试卷库」hub；图标与配色是本站自己的一套（珊瑚橙 / 松石青 / 紫罗兰）。
   ============================================================ */
.stuhub {
  display: grid; gap: var(--gap-5);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.stuhub__card {
  display: flex; flex-direction: column; gap: var(--gap-2);
  padding: var(--gap-6) var(--gap-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--sh-1);
  text-decoration: none; color: var(--text);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.stuhub__card:hover { text-decoration: none; transform: translateY(-3px); box-shadow: var(--sh-3); }
.stuhub__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 54px; height: 54px; border-radius: var(--radius);
  margin-bottom: var(--gap-2);
}
.stuhub__card--cls .stuhub__icon { background: var(--accent-soft); color: var(--accent-hover); }
.stuhub__card--stu .stuhub__icon { background: var(--cool-soft); color: var(--cool-hover); }
.stuhub__card--sch .stuhub__icon { background: #efeafd; color: #6a4ae0; }
.stuhub__card--cls:hover { border-color: var(--accent-line); }
.stuhub__card--stu:hover { border-color: var(--cool-line); }
.stuhub__card--sch:hover { border-color: #cabdf7; }
.stuhub__title { font-size: var(--fs-2xl); font-weight: 700; line-height: 1.2; }
.stuhub__desc { font-size: var(--fs-md); color: var(--text-2); line-height: 1.7; flex: 1; }
.stuhub__meta {
  margin-top: var(--gap-2); font-size: var(--fs-sm); color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.stuhub__go { margin-top: var(--gap-1); font-size: var(--fs-md); font-weight: 600; color: var(--accent-hover); }
.stuhub__card--stu .stuhub__go { color: var(--cool-hover); }
.stuhub__card--sch .stuhub__go { color: #6a4ae0; }

/* 首页「我的班级」浏览区顶部导航卡（沿用 stutabs--cards 长相，仅此处加个修饰类） */
.stutabs--browse { margin-bottom: var(--gap-4); }

/* 「班型管理」折叠区（点开才展开，页面保持干净） */
.ctmanage {
  margin-top: var(--gap-6);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 0 var(--gap-5) var(--gap-5);
}
.ctmanage__sum {
  cursor: pointer; list-style: none;
  padding: var(--gap-4) 0; font-weight: 700; font-size: var(--fs-lg);
  display: flex; align-items: center; gap: var(--gap-2);
}
.ctmanage__sum::-webkit-details-marker { display: none; }
.ctmanage__sum::after {
  content: '▾'; margin-left: auto; color: var(--text-3);
  transition: transform var(--dur) var(--ease);
}
.ctmanage[open] .ctmanage__sum::after { transform: rotate(180deg); }
.ctmanage__hint { margin-top: 0; }

/* 「我的班级」班型折叠块（2026-10-16 用户口径）：外面**只列班型**，
   点开某个班型才显示它下面的具体班（clslist/clsmini）。 */
details.ctacc {
  margin-bottom: var(--gap-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
details.ctacc > .ctacc__sum { cursor: pointer; list-style: none; }
details.ctacc > .ctacc__sum::-webkit-details-marker { display: none; }
details.ctacc:not([open]) > .ctacc__sum { border-bottom: none; }
details.ctacc > .ctacc__sum::after {
  content: '▾'; margin-left: auto; color: var(--text-3); font-size: 14px;
  transition: transform var(--dur) var(--ease);
}
details.ctacc[open] > .ctacc__sum::after { transform: rotate(180deg); }
.ctacc__hint { color: var(--text-3); font-size: var(--fs-sm); white-space: nowrap; }
details.ctacc[open] .ctacc__hint { display: none; }
details.ctacc .ctgroup__body { padding: var(--gap-4) var(--gap-5) var(--gap-5); }

/* 课后作业「预览 / 导出」弹层（2026-10-22 用户口径）：
   页面上不再摆课后作业的大输入框 —— 点按钮进来先看**排好版的成品**
   （PDF 逐页转 PNG，口径与组卷页 / 周中作业灯箱一致），顶部切学生/教师版，
   底部下载 PDF / Word；要手改才点「编辑原文」把 textarea 叫出来。
   手机上弹层直接铺满整屏（100dvh，避开 Safari 地址栏那截）。 */
.hwview {
  width: min(880px, 94vw);
  height: min(92vh, 980px);
  max-height: min(92vh, 980px);
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--sh-3);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* dialog 关闭时必须真的不显示：上面写了 display:flex，把 UA 的 display:none 盖掉了 */
.hwview:not([open]) { display: none; }
.hwview::backdrop { background: rgba(30, 20, 14, .48); }

.hwview__head {
  display: flex; align-items: center; gap: var(--gap-3); flex-wrap: wrap;
  padding: var(--gap-3) var(--gap-5);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}
/* 顺序：标题 → 版本切换 → 关闭。窄屏时让「学生版/教师版」整条换到第二行，
   关闭按钮始终留在标题那一行的最右（以前它会孤零零掉到第三行）。 */
.hwview__headmain { order: 1; flex: 1 1 160px; min-width: 0; }
.hwview__tabs { order: 2; }
.hwview__x { order: 3; }
.hwview__title { margin: 0; font-size: var(--fs-lg); font-weight: 700; }
.hwview__sub { margin: 2px 0 0; font-size: var(--fs-xs); color: var(--text-3); }
.hwview__x {
  border: none; background: none; cursor: pointer; font-size: 22px; line-height: 1;
  color: var(--text-3); padding: 0 4px;
}
.hwview__x:hover { color: var(--accent-hover); }

/* 学生版 / 教师版：一个药丸分段控件（教师版卷末才有答案） */
.hwview__tabs {
  display: inline-flex; gap: 2px; padding: 3px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius-pill);
}
.hwview__tabs[hidden] { display: none; }
.hwview__tab {
  border: none; background: none; cursor: pointer;
  padding: 5px 12px; border-radius: var(--radius-pill);
  font-size: var(--fs-sm); color: var(--text-3); white-space: nowrap;
}
.hwview__tab.is-on {
  background: var(--surface); color: var(--text);
  font-weight: 600; box-shadow: var(--sh-1);
}

.hwview__body {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
  padding: var(--gap-4) var(--gap-5);
  background: var(--surface-2);
}
.hwview__body[hidden] { display: none; }

/* 「刚改过/未保存」这类说明条：只做提示，不挡操作 */
.hwview__notice {
  margin: 0 0 var(--gap-3);
  padding: var(--gap-2) var(--gap-3);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-size: var(--fs-sm); line-height: 1.6;
}
.hwview__notice[hidden] { display: none; }

.hwview__stage {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.hwview__stage[hidden] { display: none; }
.hwview__page {
  display: block; margin: auto;
  width: auto; height: auto;
  max-width: 100%; max-height: 100%;
  background: #fff; border-radius: 6px;
  box-shadow: 0 6px 24px rgba(20, 24, 40, .16);
  cursor: zoom-in;
}
.hwview__page[hidden] { display: none; }
.hwview__plain {
  width: 100%; max-height: 100%; overflow: auto; margin: 0; padding: var(--gap-4);
  white-space: pre-wrap; word-break: break-word;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--text); font-family: var(--font); font-size: var(--fs-md);
  line-height: 1.8;
}
.hwview__plain[hidden] { display: none; }
.hwview__msg {
  margin: auto; padding: var(--gap-6) var(--gap-3);
  color: var(--text-3); font-size: var(--fs-sm); text-align: center; line-height: 1.7;
}
.hwview__msg[hidden] { display: none; }

.hwview__pager {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  gap: var(--gap-3); margin-top: var(--gap-3);
}
.hwview__pager[hidden] { display: none; }
.hwview__nav {
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--surface);
  color: var(--text-2); font-size: 20px; line-height: 1; cursor: pointer;
}
.hwview__nav:hover { border-color: var(--accent-line); color: var(--accent-hover); }
.hwview__pos { font-size: var(--fs-sm); color: var(--text-3); }

.hwview__editor {
  flex: 1 1 auto; min-height: 0; overflow: auto;
  margin-top: var(--gap-4); padding-top: var(--gap-3);
  border-top: 1px dashed var(--line-strong);
}
.hwview__editor[hidden] { display: none; }
.hwview__editor textarea { width: 100%; }

.hwview__foot {
  display: flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap;
  padding: var(--gap-3) var(--gap-5);
  border-top: 1px solid var(--line);
  background: var(--surface);
}
.hwview__footacts { margin-left: auto; display: flex; gap: var(--gap-2); flex-wrap: wrap; }
.hwview__footacts a[hidden] { display: none; }

@media (max-width: 640px) {
  .hwview {
    width: 100vw; max-width: 100vw;
    height: 100dvh; max-height: 100dvh;
    border: none; border-radius: 0;
  }
  .hwview__head { padding: var(--gap-3) var(--gap-4); }
  /* 窄屏：关闭按钮留在标题行最右，版本切换整条换到下一行居中 */
  .hwview__x { order: 2; margin-left: auto; }
  .hwview__tabs { order: 3; flex: 1 1 100%; justify-content: center; }
  .hwview__body { padding: var(--gap-3); }
  .hwview__foot { padding: var(--gap-3) var(--gap-4); }
  .hwview__footacts { width: 100%; margin-left: 0; }
  .hwview__footacts .btn { flex: 1 1 auto; }
  /* 挑题浮层同样铺满：手机上留边只会让 iframe 更窄、更难勾题 */
  .hwpick { width: 100vw; max-width: 100vw; height: 100dvh; border-radius: 0; }
}

/* 「选择班级」分组下拉（2026-10-16 需求②）：
   班型（大类型）+ 它自己的下拉（具体班）；**具体班不单独摆在外面**。 */
.grpicklist { display: grid; gap: var(--gap-3); }
.grpick {
  display: flex; align-items: center; gap: var(--gap-3); flex-wrap: wrap;
  padding: var(--gap-3) var(--gap-4);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius);
}
.grpick--off { opacity: .72; }
.grpick__name { display: inline-flex; align-items: center; gap: 7px; min-width: 118px; font-size: var(--fs-md); }
.grpick__name .ctdot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
.grpick__sel { flex: 1 1 180px; min-width: 0; }

/* 档案页「课表」紧凑条（2026-10-16 需求①）：一周七格撤掉，只留一个「排课表」入口。 */
.schbar { display: flex; align-items: center; gap: var(--gap-4); flex-wrap: wrap; }
.schbar__txt { flex: 1 1 220px; min-width: 0; }
.schbar__txt .panel__hint { margin: 2px 0 0; }
.schbar__btn { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.schbar__btn svg { flex: 0 0 auto; }

@media (max-width: 560px) {
  .grpick { align-items: stretch; flex-direction: column; gap: var(--gap-2); }
  .grpick__sel { flex: 1 1 auto; width: 100%; }
}

/* 整班反馈「草稿 / 已同步」（2026-10-16 需求）：草稿条目虚线框，一眼看出还没同步。 */
.clsles__item--draft { border-style: dashed; border-color: var(--line-strong); }
.clfoot__hint { margin: 10px 0 0; }

/* ============================================================
   自定义日期选择器（2026-10-16 需求②）
   JS 把原生 <input type="date"> 就地换成「输入框 + 自绘日历」。
   ============================================================ */
.dp { position: relative; display: block; }
.dp__input { cursor: pointer; }
.dp__pop {
  position: absolute; z-index: 60; top: calc(100% + 6px); left: 0;
  width: 288px; max-width: 92vw;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--sh-3);
  padding: var(--gap-3);
  animation: dpIn var(--dur) var(--ease);
}
@keyframes dpIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.dp__hd { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--gap-2); }
.dp__label { font-weight: 700; font-size: var(--fs-md); font-variant-numeric: tabular-nums; }
.dp__nav {
  width: 32px; height: 32px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--surface-2);
  color: var(--text-2); font-size: 18px; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.dp__nav:hover { background: var(--accent-soft); color: var(--accent-hover); border-color: var(--accent-line); }
.dp__dow {
  display: grid; grid-template-columns: repeat(7, 1fr);
  font-size: var(--fs-xs); color: var(--text-3); text-align: center;
  margin-bottom: 4px;
}
.dp__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dp__day {
  aspect-ratio: 1 / 1; border: none; background: transparent; cursor: pointer;
  border-radius: var(--radius-sm); font-size: var(--fs-sm); color: var(--text);
  font-variant-numeric: tabular-nums;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.dp__day:hover { background: var(--surface-2); }
.dp__day--out { color: var(--text-3); opacity: .5; }
.dp__day.is-today { box-shadow: inset 0 0 0 1px var(--accent-line); color: var(--accent-hover); font-weight: 700; }
.dp__day.is-sel {
  background: linear-gradient(180deg, var(--accent) 0%, var(--accent-hover) 100%);
  color: var(--on-solid); font-weight: 700;
}
.dp__ft { display: flex; justify-content: space-between; gap: var(--gap-2); margin-top: var(--gap-2); }
.dp__quick {
  flex: 1; padding: 7px 10px; cursor: pointer;
  border: 1px solid var(--line); background: var(--surface-2);
  border-radius: var(--radius-sm); font-size: var(--fs-sm); color: var(--text-2);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.dp__quick:hover { background: var(--accent-soft); color: var(--accent-hover); border-color: var(--accent-line); }

@media (prefers-color-scheme: dark) {
  .stuhub__card--sch .stuhub__icon { background: rgba(122, 90, 248, .20); color: #b7a6fb; }
  .stuhub__card--sch:hover { border-color: rgba(122, 90, 248, .48); }
  .stuhub__card--sch .stuhub__go { color: #b7a6fb; }
}



/* ================================================================
   校对页改版（2026-10-17 用户需求②）
   ----------------------------------------------------------------
   原话：「每一道题的显示都要求和题库页面的题一样，方便我观察，把考试日期、
   知识点、标签、选项、答案、解析等放在题目框下面，我点击该题之后，
   才以弹框的显示显示，要求弹框高级美观」。

   做法：卡片＝**只读展示**（题库 qrow 那套：题干完整 + 选项 + 元信息行 + 答案解析摘要），
   编辑控件全部搬进 <dialog>（顶层渲染，不会被祖先 overflow 裁掉）。
   这套规则放文件末尾，是为了覆盖上面第一批 .icard 的旧样式（同权重时后者生效）。
   ================================================================ */

/* ---- 卡片：两栏（内容 + 右侧操作），与题库列表一个观感 ---- */
.icard {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--gap-4);
  transition: box-shadow .18s ease, border-color .18s ease;
}
.icard:hover { border-color: var(--accent-line); box-shadow: var(--sh-2); }
.icard__main { flex: 1 1 auto; min-width: 0; }
.icard__side {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: stretch;
  min-width: 116px;
}
.icard__side .btn { white-space: nowrap; }

.icard__head {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--gap-2);
  padding-bottom: var(--gap-2); margin-bottom: var(--gap-3);
  border-bottom: 1px dashed var(--line);
}
.icard__spacer { flex: 1 1 auto; }
.icard__hintopen { font-size: 12px; white-space: nowrap; }

/* 题干：整段显示、可换行，点它就是「看详情 / 编辑」 */
.icard__stem {
  font-size: 15px; line-height: 1.75; color: var(--text);
  word-break: break-word; overflow-wrap: anywhere;
  cursor: pointer; border-radius: var(--radius-sm);
  padding: 2px 6px; margin: 0 -6px var(--gap-2);
  transition: background .15s ease;
}
.icard__stem:hover, .icard__stem:focus-visible { background: var(--accent-soft); outline: none; }
.icard__img {
  display: block; max-width: 100%; height: auto; margin: var(--gap-2) 0;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}

/* AI 视觉识别出的 TikZ 图形（题未入库，没有 QuestionFig 行，走 /figures/preview 即时编译）。 */
.icard__fig {
  display: flex; justify-content: center; align-items: center;
  padding: var(--gap-2) 0; margin: var(--gap-2) 0;
  border: 1px dashed var(--line); border-radius: var(--radius-sm);
  background: var(--accent-soft, #f6f8fb);
}
.icard__figimg { display: block; max-width: 100%; height: auto; }

.icard__opts { margin: 0 0 var(--gap-3); }

/* 元信息行：分类 · 知识点 · 标签 · 题型 · 难度 · 日期 · 来源 */
.icard__meta {
  display: flex; flex-wrap: wrap; gap: 6px 14px;
  font-size: 12.5px; color: var(--text-2); line-height: 1.7;
  padding-top: var(--gap-2); border-top: 1px dashed var(--line);
}
.icard__mi { display: inline-flex; align-items: baseline; gap: 4px; min-width: 0; }
.icard__mi i { font-style: normal; color: var(--text-3); }
.icard__mi b { font-weight: 600; color: var(--text); word-break: break-word; }

/* 答案 / 解析摘要 + 「AI 生成」药丸 */
.icard__answrap { margin-top: var(--gap-2); }
.icard__ans {
  background: var(--surface-2); border-radius: var(--radius-sm);
  padding: 8px 10px; font-size: 13px; line-height: 1.7;
  display: flex; flex-direction: column; gap: 2px;
}
.icard__ansrow { display: flex; gap: 8px; align-items: baseline; min-width: 0; }
.icard__k { flex: 0 0 auto; color: var(--text-3); font-size: 12.5px; }
.icard__ansv { min-width: 0; word-break: break-word; }
/* 可点击展开的答案/解析行（2026-10-18：点击后显示完整解析，公式整段渲染） */
.icard__ansrow--click { cursor: pointer; border-radius: var(--radius-sm); transition: background .15s ease; }
.icard__ansrow--click:hover { background: var(--surface-3); }
/* 「答案」「解析」标签做成双色药丸：橙=答案、青=解析，一眼区分 */
.icard__ansrow .icard__k {
  padding: 1px 9px; border-radius: var(--radius-pill);
  font-weight: 600; font-size: 11.5px; line-height: 1.7; letter-spacing: .02em;
}
.icard__ansrow[data-ansfull="answer"] .icard__k {
  background: var(--accent-soft); color: var(--accent-ink); border: 1px solid var(--accent-line);
}
.icard__ansrow[data-ansfull="solution"] .icard__k {
  background: var(--cool-soft); color: var(--cool-ink); border: 1px solid var(--cool-line);
}
/* 展开按钮：渐变橙圆钮（2026-10-18 用户要求更大更显眼高级），hover 放大，
   展开后旋转 180° 且加深阴影 */
.icard__anscaret {
  flex: 0 0 auto; margin-left: auto; align-self: center;
  width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-style: normal; font-size: 14px; font-weight: 700;
  color: #fff; border: none;
  background: linear-gradient(180deg, var(--accent-hi), var(--accent));
  box-shadow: 0 2px 6px rgba(232, 97, 60, .35);
  transition: transform .2s ease, box-shadow .2s ease, filter .15s ease;
}
.icard__ansrow--click:hover .icard__anscaret {
  transform: scale(1.1);
  filter: brightness(1.05);
  box-shadow: 0 3px 10px rgba(232, 97, 60, .45);
}
.icard__ansrow--click.is-open .icard__anscaret {
  transform: rotate(180deg);
  background: linear-gradient(180deg, var(--accent), var(--accent-hover));
  box-shadow: 0 3px 8px rgba(199, 72, 42, .4);
}
/* 展开时隐藏截断摘要（用户要求：展开后摘要行不再重复展示），行首的
   「答案/解析」标签与圆钮保留 —— 点它就是收起 */
.icard__ansrow--click.is-open [data-disp="answer-preview"],
.icard__ansrow--click.is-open [data-disp="solution-preview"] {
  display: none;
}
.icard__ansrow--click.is-open { padding: 3px 0; }
.icard__ansfull {
  padding: 8px 2px 4px 2px; border-top: 1px dashed var(--line);
  word-break: break-word; font-size: 13px;
}
.aiTag {
  align-self: flex-start;
  font-size: 11px; line-height: 1.6; padding: 0 8px; border-radius: var(--radius-pill);
  background: var(--cool-soft); color: var(--cool-hover);
  border: 1px solid var(--cool-line); font-weight: 600;
}
.icard__ans .aiTag { margin-bottom: 4px; }

/* ---- 弹窗：编辑一题（showModal 顶层渲染，居中，背景虚化） ---- */
.qdlg {
  padding: 0; border: none; background: transparent;
  width: min(820px, 94vw); max-width: 94vw; max-height: 90vh;
}
.qdlg::backdrop { background: rgba(24, 16, 12, .45); backdrop-filter: blur(2px); }
.qdlg__form {
  display: flex; flex-direction: column; max-height: 90vh;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--sh-3);
  overflow: hidden;
}
.qdlg[open] .qdlg__form { animation: qdlg-in .18s ease-out; }
@keyframes qdlg-in { from { opacity: 0; transform: translateY(8px) scale(.99); } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .qdlg[open] .qdlg__form { animation: none; } }

.qdlg__head {
  display: flex; align-items: center; gap: var(--gap-2);
  padding: 14px var(--gap-4);
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, var(--accent-soft), var(--surface));
}
.qdlg__title { margin: 0; font-size: 16px; flex: 1 1 auto; min-width: 0; }
.qdlg__sec {
  font-size: 12px; color: var(--text-3); background: var(--surface-2);
  border-radius: var(--radius-pill); padding: 1px 10px; margin-left: 6px;
}
.qdlg__x {
  flex: 0 0 auto; width: 32px; height: 32px; line-height: 1;
  border: 1px solid var(--line); background: var(--surface); color: var(--text-2);
  border-radius: var(--radius-pill); font-size: 18px; cursor: pointer;
}
.qdlg__x:hover { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-ink); }

.qdlg__body { padding: var(--gap-4); overflow-y: auto; }
.qdlg__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--gap-3); margin-bottom: var(--gap-3);
}
.qdlg__grid .field--full { grid-column: 1 / -1; }
.qdlg__body .field { display: block; margin-bottom: var(--gap-3); }
.qdlg__body .field > span { display: block; font-size: 12.5px; color: var(--text-3); margin-bottom: 4px; }
.qdlg__body textarea { font-family: var(--font-mono); font-size: 13.5px; line-height: 1.6; }
.qdlg__pick { margin-top: var(--gap-3); }

.qdlg__foot {
  display: flex; align-items: center; gap: var(--gap-2);
  padding: 12px var(--gap-4);
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}
.qdlg__hint { flex: 1 1 auto; font-size: 12.5px; }

@media (max-width: 720px) {
  .icard { flex-direction: column; }
  .icard__side { flex-direction: row; flex-wrap: wrap; min-width: 0; }
  .icard__side .btn { flex: 1 1 auto; }
}

/* ================================================================
   文档中心：原卷 ⇄ 新卷（2026-10-17 需求④）
   ----------------------------------------------------------------
   「原文档和新生成的文档放在两个不同的地方，查看原文档和查看新文档可以选择
   调整到原文档或者他对应的新文档」—— 这一页把两边并排摆在同一个屏里，
   中间一枚 ⇄ 提示「可以来回跳」。
   ================================================================ */
.docpair {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: var(--gap-4);
  align-items: start;
}
.docpair__swap {
  align-self: center;
  font-size: 26px; color: var(--accent);
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  border-radius: var(--radius-pill); width: 46px; height: 46px;
  display: flex; align-items: center; justify-content: center;
}
@media (max-width: 860px) {
  .docpair { grid-template-columns: 1fr; }
  .docpair__swap { justify-self: center; transform: rotate(90deg); }
}

.doccard {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--gap-4);
  display: flex; flex-direction: column; gap: var(--gap-2);
}
.doccard--new { border-color: var(--accent-line); box-shadow: var(--sh-1); }
.doccard__head { display: flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap; }
.doccard__tag {
  font-size: 12px; font-weight: 700; padding: 1px 10px;
  border-radius: var(--radius-pill);
  background: var(--surface-2); color: var(--text-2); border: 1px solid var(--line);
}
.doccard__tag--new { background: var(--accent-soft); color: var(--accent-ink); border-color: var(--accent-line); }
.doccard__title { margin: 0; font-size: 16px; word-break: break-all; }
.doccard__desc { margin: 0; font-size: 13.5px; line-height: 1.7; color: var(--text-2); }
.doccard__acts { display: flex; gap: var(--gap-2); flex-wrap: wrap; margin-top: var(--gap-2); }

.doclist { display: flex; flex-direction: column; gap: var(--gap-2); margin-top: var(--gap-2); }
.doclist__row {
  display: flex; align-items: center; gap: var(--gap-2); flex-wrap: wrap;
  background: var(--surface-2); border-radius: var(--radius-sm);
  padding: 8px 10px; font-size: 13px;
}
.doclist__name { min-width: 64px; }
.doclist__err { margin: 0; padding: 4px 8px; font-size: 12px; }

/* ================================================================
   AI 智能改题（导入校对弹窗内）+ 图形工坊（2026-10-21）
   ----------------------------------------------------------------
   用户口径：「为提取的每道题的编辑框里面，添加一个 AI 智能改题的功能，
   如果这道题有问题，我直接交给 AI 修改，并跟他说哪里的问题，尤其是图形」。
   配色：改题块用主色（珊瑚橙）= 交互；图形工坊用冷色（松石青）= 看图对照这类数据型区块。
   ⚠️ 图形画布背景必须写死 #fff：服务端出的是透明底黑线 SVG，
      跟随 --surface 会在深色模式下变成一块黑方块、线条看不见（见第 18 节的老坑）。
   ================================================================ */
.afix {
  margin-top: var(--gap-4);
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-md);
  background: linear-gradient(180deg, var(--accent-soft), var(--surface) 46%);
  overflow: hidden;
}
.afix__head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 12px;
}
.afix__badge {
  font-size: 11px; font-weight: 800; letter-spacing: .06em;
  color: var(--on-solid);
  background: linear-gradient(135deg, var(--accent-hi), var(--accent));
  border-radius: 6px; padding: 2px 7px;
}
.afix__tip { flex: 1 1 auto; min-width: 0; font-size: 12px; color: var(--text-3); line-height: 1.6; }
/* 2026-10-22：两个执行按钮收进独立的「行动行」，强制不换行（用户要求同行）。
   状态文字在窄屏下收缩、不挤掉按钮。 */
.afix__acts { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }
.afix__acts .btn { flex: 0 0 auto; }
/* 智能改题被挪到弹窗最上方时，去掉它跟弹窗头之间的多余间距 */
.afix:first-child { margin-top: 0; }

.afix__body { display: flex; flex-direction: column; gap: 10px; padding: 0 12px 12px; }
/* 写了 display:flex 就必须自己补 [hidden] —— UA 的 [hidden] 权重与类选择器相同，
   会被源码在后的规则顶掉，于是「收起了还显示」。本工程已踩过多次。 */
.afix__body[hidden] { display: none; }

.afix__chips { display: flex; gap: 6px; flex-wrap: wrap; }
.afix__chip {
  font-size: 12px; padding: 3px 10px; cursor: pointer;
  border: 1px dashed var(--accent-line); border-radius: var(--radius-pill);
  background: var(--surface); color: var(--accent-ink);
}
.afix__chip:hover { background: var(--accent-soft); border-style: solid; }

.afix__note {
  width: 100%; min-height: 62px; resize: vertical;
  font-family: var(--font-sans); font-size: 13.5px; line-height: 1.65;
  padding: 8px 10px; color: var(--text);
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
}
.afix__note:focus { outline: 2px solid var(--accent-line); outline-offset: 1px; }

.afix__row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.afix__label { font-size: 12.5px; color: var(--text-3); }
.afix__picks { display: flex; gap: 10px; flex-wrap: wrap; }
.afix__pick {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12.5px; color: var(--text-2); cursor: pointer;
}
.afix__pick input { width: auto; min-height: 0; margin: 0; }
.afix__status { flex: 1 1 160px; min-width: 0; font-size: 12.5px; color: var(--text-3); }
.afix__status.is-busy { color: var(--accent-ink); }
.afix__status.is-ok { color: var(--ok); }
.afix__status.is-bad { color: var(--danger); }
.afix__off { margin: 0; font-size: 12px; color: var(--warn); }

.afix__out {
  display: flex; flex-direction: column; gap: 10px;
  border-top: 1px dashed var(--line-strong); padding-top: 10px;
}
.afix__out[hidden] { display: none; }
.afix__sum { font-size: 13.5px; line-height: 1.7; }
.afix__cost { margin-left: 8px; font-size: 12px; color: var(--text-3); }
.afix__notes { margin: 0; padding-left: 18px; font-size: 12.5px; line-height: 1.7; color: var(--warn); }
.afix__warn {
  font-size: 12.5px; line-height: 1.6; padding: 6px 9px;
  color: var(--danger); background: var(--danger-soft);
  border: 1px solid var(--danger-line); border-radius: var(--radius-sm);
}

.afix__item {
  padding: 8px 10px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.afix__itemhead { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.afix__itemhead b { flex: 1 1 auto; font-size: 13px; }
.afix__diff { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.afix__col i, .afix__fig figcaption {
  display: block; margin-bottom: 3px; font-style: normal;
  font-size: 11.5px; color: var(--text-3);
}
.afix__col pre, .afix__src pre {
  margin: 0; max-height: 170px; overflow: auto;
  padding: 8px; font-size: 12px; line-height: 1.55;
  white-space: pre-wrap; word-break: break-word;
  background: var(--surface-2); border-radius: 6px;
}
/* 改前 / 改后正文（stem / answer / solution）：改用 data-tex 的 div 以渲染 LaTeX，
   观感与上面 <pre> 对齐（同款底色 / 圆角 / 行高）。 */
.afix__tex {
  margin: 0; max-height: 170px; overflow: auto;
  padding: 8px; font-size: 12px; line-height: 1.7;
  white-space: normal; word-break: break-word;
  background: var(--surface-2); border-radius: 6px;
}
.afix__figs { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.afix__fig { margin: 0; }
.afix__fig img {
  display: block; max-width: 100%; max-height: 190px;
  padding: 4px; background: #fff;
  border: 1px solid var(--line); border-radius: 6px;
}
.afix__src { margin-top: 6px; }
.afix__src summary { font-size: 12px; color: var(--text-3); cursor: pointer; }
.afix__src pre { margin-top: 4px; }
.afix__note2 { margin: 6px 0 0; font-size: 12px; color: var(--cool-ink); }
.afix__foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.afix__foot .muted { font-size: 12px; }
@media (max-width: 640px) {
  .afix__diff, .afix__figs { grid-template-columns: 1fr; }
}

/* ---------- 图形工坊 ---------- */
.figdlg {
  padding: 0; border: none; background: transparent;
  width: min(1180px, 96vw); max-width: 96vw;
}
.figdlg::backdrop { background: rgba(24, 16, 12, .5); backdrop-filter: blur(2px); }
.figdlg__wrap {
  display: flex; flex-direction: column; max-height: 92vh; overflow: hidden;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg); box-shadow: var(--sh-3);
}
.figdlg__head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 16px; border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, var(--cool-soft), var(--surface));
}
.figdlg__title { margin: 0; font-size: 16px; flex: 1 1 auto; min-width: 0; }
.figdlg__tools { display: flex; align-items: center; gap: 6px; }
.figdlg__x {
  width: 32px; height: 32px; line-height: 1; cursor: pointer;
  border: 1px solid var(--line); background: var(--surface); color: var(--text-2);
  border-radius: var(--radius-sm); font-size: 18px;
}
.figdlg__x:hover { background: var(--cool-soft); border-color: var(--cool-line); color: var(--cool-ink); }
.figdlg__body {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
  padding: 14px 16px; overflow: auto;
}
.figdlg__pane { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.figdlg__pane h4 { margin: 0; font-size: 12.5px; font-weight: 600; color: var(--text-3); }
.figdlg__canvas {
  position: relative; display: flex; align-items: center; justify-content: center;
  min-height: 220px; max-height: 46vh; overflow: auto;
  background: #fff;                       /* 必写：透明底 SVG 的底 */
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.figdlg__canvas img { display: none; max-width: 100%; max-height: 44vh; transition: transform .15s ease; }
.figdlg__canvas[hidden] { display: none; }
.figdlg__canvas.has-img img { display: block; }
.figdlg__canvas.has-img .figdlg__empty { display: none; }
.figdlg__empty { padding: 26px 18px; font-size: 12.5px; line-height: 1.7; color: var(--text-3); text-align: center; }
.figdlg__airow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 0 16px 10px; }
.figdlg__noteinput { flex: 1 1 320px; min-width: 0; }
.figdlg__status { font-size: 12.5px; color: var(--text-3); flex: 1 1 100%; }
.figdlg__hint {
  margin: 0; padding: 0 16px 12px; font-size: 12.5px; line-height: 1.5;
  color: var(--text-3);
}
.figdlg__hint b { color: var(--brand); }
.figdlg__src { padding: 0 16px 10px; }
.figdlg__src summary { font-size: 12.5px; color: var(--text-3); cursor: pointer; }
.figdlg__src textarea {
  width: 100%; margin-top: 6px; resize: vertical;
  font-family: var(--font-mono); font-size: 12.5px; line-height: 1.55;
}
.figdlg__foot {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 12px 16px; border-top: 1px solid var(--line); background: var(--surface-2);
}
.figdlg__foot .muted { flex: 1 1 240px; font-size: 12.5px; }
@media (max-width: 860px) {
  .figdlg__body { grid-template-columns: 1fr; }
}

/* ---------- 手动框选补图（2026-10-24）----------
 * 整页原卷 + 拖框 → 只把框内那一块送去转 TikZ。
 * 底图用 --surface（白）而不是暖白：原卷是纸，白底最接近肉眼所见。 */
.figdlg__mode { display: inline-flex; gap: 4px; margin-left: 8px; vertical-align: middle; }
.figdlg__mode .btn.is-on {
  background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-ink);
}
.figdlg__pick { display: flex; flex-direction: column; gap: 8px; }
.figdlg__pick[hidden] { display: none; }
.figdlg__pickimg {
  position: relative; overflow: hidden; cursor: crosshair;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: #fff; max-height: 46vh; display: flex;
  align-items: flex-start; justify-content: center;
}
.figdlg__pickimg img {
  display: block; max-width: 100%; max-height: 46vh; user-select: none;
  -webkit-user-drag: none; touch-action: none;
}
.figdlg__sel {
  position: absolute; pointer-events: none;
  border: 2px solid var(--accent); background: rgba(232, 97, 60, .16);
  border-radius: 2px;
}
.figdlg__sel[hidden] { display: none; }
.figdlg__pickbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.figdlg__pickbar .muted { font-size: 12.5px; min-width: 62px; text-align: center; }
.figdlg__pickbar .figdlg__status { flex: 0 1 auto; }

/* ---------- 入库报告 · 抽样自检（2026-10-24）----------
 * 左原卷 / 右入库，两栏等宽并排；窄屏自动上下叠。 */
.selfcheck { display: flex; flex-direction: column; gap: 12px; }
.selfcheck__row {
  display: grid; grid-template-columns: minmax(200px, 38%) 1fr; gap: 12px;
  padding: 10px; border: 1px solid var(--line); border-radius: var(--radius-md);
  background: var(--surface-2);
}
.selfcheck__orig {
  display: flex; align-items: flex-start; justify-content: center;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-sm);
  min-height: 90px; overflow: hidden;
}
.selfcheck__orig img { display: block; max-width: 100%; max-height: 320px; }
.selfcheck__orig .selfcheck__ph { display: none; }
.selfcheck__orig.is-empty .selfcheck__ph,
.selfcheck__row > .selfcheck__orig > .selfcheck__ph {
  display: block; padding: 16px 12px; font-size: 12.5px; color: var(--text-3);
  line-height: 1.6; text-align: center;
}
.selfcheck__mine { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.selfcheck__meta { margin: 0; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 12.5px; }
.selfcheck__stem { margin: 0; font-size: 13.5px; line-height: 1.7; }
.selfcheck__ans { margin: 0; font-size: 12.5px; color: var(--text-3); }
.selfcheck__fig { margin-top: 2px; }
.selfcheck__fig img { max-width: 100%; max-height: 180px; display: block; background: #fff; }
@media (max-width: 760px) {
  .selfcheck__row { grid-template-columns: 1fr; }
}
