/* ============================================================
   为民说 · 界面样式
   ------------------------------------------------------------
   全部颜色取自 tokens.css 的语义令牌，此处不出现写死色值。
   对比度已实测 52 项全部通过（python scripts/check-contrast.py）
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-base);
  color: var(--text-primary);
  background: var(--bg-base);
  min-height: 100vh;
  transition: background var(--dur-base) var(--ease-standard),
              color var(--dur-base) var(--ease-standard);
}

[hidden] { display: none !important; }
h1, h2, h3, h4, p, dl, dd, dt, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
/* 按钮默认样式一律清零，避免浏览器自带边框在浅色主题下变成突兀的黑框 */
button {
  font: inherit;
  color: inherit;
  border: 0;
  background: none;
}
code { font-family: var(--font-mono); font-size: .92em; }

/* ---------- 滚动条：跟随主题 ----------
   系统默认滚动条在深色界面上是一条亮白竖线，非常跳。
   统一改成细条 + 半透明内缩，颜色跟着 --border-strong 走。 */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  background-clip: padding-box;
  border: 3px solid transparent;
  border-radius: var(--radius-full);
}
::-webkit-scrollbar-thumb:hover {
  background: var(--text-tertiary);
  background-clip: padding-box;
}
::-webkit-scrollbar-corner { background: transparent; }

/* 全局焦点环：键盘用户必须看得见焦点在哪 */
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

.skip-link {
  position: absolute; left: var(--space-4); top: -80px; z-index: var(--z-toast);
  padding: var(--space-3) var(--space-5);
  background: var(--primary); color: var(--on-primary);
  border-radius: var(--radius-md); text-decoration: none;
  transition: top var(--dur-fast) var(--ease-standard);
}
.skip-link:focus { top: var(--space-4); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ============================================================
   主题切换（浮动右上角，全局可用）
   ============================================================ */
.theme-toggle {
  position: fixed;
  top: var(--space-4);
  right: var(--space-4);
  z-index: var(--z-dropdown);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 38px;
  padding: 0 var(--space-3);
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              background var(--dur-fast) var(--ease-standard);
}
.theme-toggle:hover { color: var(--text-primary); background: var(--bg-subtle); }
.theme-toggle__icon {
  width: 15px; height: 15px; flex: none;
  border-radius: var(--radius-full);
  background: var(--primary);
  box-shadow: inset -4px -4px 0 0 var(--bg-surface);
}

/* ============================================================
   按钮
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 40px;
  padding: 0 18px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard);
}
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn--lg { min-height: var(--tap-min); padding: 0 var(--space-6); font-size: var(--text-md); }
.btn--sm { min-height: 32px; padding: 0 var(--space-3); font-size: var(--text-sm); }
.btn--primary { background: var(--primary); color: var(--on-primary); }
.btn--primary:hover:not(:disabled) { background: var(--primary-hover); }
.btn--primary:active:not(:disabled) { background: var(--primary-active); transform: translateY(1px); }
.btn--secondary {
  background: var(--bg-surface);
  border-color: var(--border-strong);
  color: var(--text-primary);
}
.btn--secondary:hover:not(:disabled) { background: var(--bg-subtle); }
.btn--ghost { background: transparent; color: var(--text-secondary); }
.btn--ghost:hover:not(:disabled) { background: var(--bg-subtle); color: var(--text-primary); }
.btn--danger { background: transparent; border-color: var(--danger); color: var(--danger); }
.btn--danger:hover:not(:disabled) { background: var(--danger-soft); }

/* ============================================================
   难度分段控件
   ------------------------------------------------------------
   四档难度是「风险递进」，用 绿 → 蓝 → 橙 → 红 编码，
   与难度徽章共用同一组令牌（--diff-easy / normal / hard / real）。

   选中态由一块绝对定位的指示块承担：
   · 位置 —— transform: translateX(索引 × 自身宽度)
   · 颜色 —— background-color / border-color 同步过渡
   切换时因此是「边滑动、边渐变到目标难度的颜色」。
   ============================================================ */
.segmented {
  position: relative;
  display: inline-flex;
  padding: 3px;
  background: var(--bg-inset);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  min-height: var(--tap-min);
  align-items: stretch;
  isolation: isolate;
  /* 允许在控件上按住拖动来选难度，而不是带着页面一起滚 */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.segmented__thumb {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  width: calc((100% - 6px) / var(--seg-count, 4));
  border-radius: 7px;
  border: 1px solid var(--seg-color, var(--primary));
  background-color: var(--seg-soft, var(--primary-soft));
  background-image: linear-gradient(135deg,
    var(--seg-soft, var(--primary-soft)) 0%,
    color-mix(in srgb, var(--seg-soft, var(--primary-soft)) 55%, var(--seg-color, var(--primary))) 100%);
  box-shadow: var(--shadow-xs);
  transform: translateX(calc(var(--seg-idx, 0) * 100%));
  transition: transform var(--dur-slow) var(--ease-out),
              background-color var(--dur-slow) var(--ease-standard),
              border-color var(--dur-slow) var(--ease-standard),
              box-shadow var(--dur-base) var(--ease-standard);
  pointer-events: none;
  z-index: 0;
}

.segmented__item {
  position: relative;
  z-index: 1;
  flex: 1;
  min-height: 38px;
  padding: 0 var(--space-4);
  border: none;
  background: transparent;
  border-radius: 7px;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
  transition: color var(--dur-base) var(--ease-standard);
}
.segmented__item:hover { color: var(--text-primary); }
.segmented__item.is-selected { color: var(--seg-color, var(--primary)); }
.segmented:focus-within { border-color: var(--border-strong); }

/* 按住拖动选难度：指示块跟手移动（60ms 近乎无延迟），
   颜色仍走 300ms 渐变，所以拖动过程中也能看到「边滑边变色」 */
.segmented.is-dragging { cursor: grabbing; }
.segmented.is-dragging .segmented__item { cursor: grabbing; }
.segmented.is-dragging .segmented__thumb {
  transition: transform 60ms linear,
              background-color var(--dur-slow) var(--ease-standard),
              border-color var(--dur-slow) var(--ease-standard);
}

/* ============================================================
   首页
   ============================================================ */
.home-wrap {
  max-width: 1040px;
  margin: 0 auto;
  padding: var(--space-12) var(--space-6) var(--space-16);
}

.brand { text-align: center; margin-bottom: var(--space-8); }
.brand h1 {
  font-size: var(--text-3xl);
  font-weight: var(--weight-medium);
  letter-spacing: .04em;
  line-height: var(--leading-tight);
  margin-bottom: var(--space-3);
}
.brand h1 em { font-style: normal; color: var(--primary); }
.brand p { font-size: var(--text-md); color: var(--text-secondary); }
.tag-row {
  display: flex; gap: var(--space-2); justify-content: center;
  flex-wrap: wrap; margin-top: var(--space-4);
}

.tag {
  display: inline-flex; align-items: center;
  padding: 3px var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  background: var(--bg-subtle);
  color: var(--text-secondary);
}
.tag--ok { background: var(--success-soft); color: var(--success); }
.tag--warn { background: var(--warning-soft); color: var(--warning); }
.tag--ai { background: var(--primary-soft); color: var(--primary); }

.step {
  display: flex; align-items: center; gap: var(--space-3);
  margin: var(--space-10) 0 var(--space-4);
  flex-wrap: wrap;
}
.step__no {
  display: grid; place-items: center;
  width: 24px; height: 24px; flex: none;
  border-radius: var(--radius-full);
  background: var(--primary); color: var(--on-primary);
  font-size: var(--text-xs); font-weight: var(--weight-medium);
}
.step__title { font-size: var(--text-md); font-weight: var(--weight-medium); }
.step__hint { font-size: var(--text-sm); color: var(--text-tertiary); }

.college-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); }

.college-card {
  position: relative;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  cursor: pointer;
  text-align: left;
  transition: border-color var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard);
}
.college-card:hover { border-color: var(--border-strong); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.college-card.is-selected { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.college-card .c-icon {
  display: grid; place-items: center;
  width: 40px; height: 40px; margin-bottom: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--primary-soft); color: var(--primary);
  font-size: var(--text-base); font-weight: var(--weight-medium);
}
.college-card h3 { font-size: var(--text-md); font-weight: var(--weight-medium); margin-bottom: var(--space-1); }
.college-card p { font-size: var(--text-sm); color: var(--text-secondary); }

.scene-list { display: flex; flex-direction: column; gap: var(--space-4); }
.scene-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-xs);
}
.scene-card h4 { font-size: var(--text-lg); font-weight: var(--weight-medium); margin-bottom: var(--space-2); }
.scene-card .scene-brief {
  font-size: var(--text-sm); color: var(--text-secondary);
  line-height: var(--leading-base); margin-bottom: var(--space-4);
}
.scene-card__goal {
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--primary);
  background: var(--primary-soft);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--text-primary);
  margin-bottom: var(--space-4);
}
.scene-card__goal-k {
  display: block; font-size: var(--text-xs); font-weight: var(--weight-medium);
  color: var(--primary); margin-bottom: 2px;
}
.scene-card__foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4); flex-wrap: wrap;
}

.tech-note {
  margin-top: var(--space-12);
  padding: var(--space-5);
  border: 1px solid var(--border-subtle);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  font-size: var(--text-sm);
  line-height: var(--leading-base);
  color: var(--text-secondary);
}
.tech-note b { color: var(--text-primary); font-weight: var(--weight-medium); }
.tech-note .dim { display: block; color: var(--text-tertiary); font-size: var(--text-xs); margin-top: var(--space-2); }

/* ============================================================
   AI 出题 / 剧本库
   ============================================================ */
.section-head { margin: var(--space-10) 0 var(--space-4); }
.section-head__title { font-size: var(--text-md); font-weight: var(--weight-medium); }
.section-head__hint { font-size: var(--text-sm); color: var(--text-tertiary); margin-top: 2px; }

.gen-box {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-xs);
}
.gen-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-3);
}
.gen-row:last-child { margin-bottom: 0; }
.gen-k {
  flex: none;
  min-width: 62px;
  font-size: var(--text-sm);
  color: var(--text-tertiary);
}
.gen-row .input { flex: 1 1 240px; }

/* AI 出题弹窗里的「难度 + 开始」一行 */
.gen-diff-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.select {
  min-height: var(--tap-min);
  padding: 0 var(--space-3);
  font-family: inherit;
  font-size: var(--text-base);
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  cursor: pointer;
  max-width: 100%;
  transition: border-color var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard);
}
.select:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }

.gen-actions {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px dashed var(--border-subtle);
}
.gen-hint {
  flex: 1 1 200px;
  font-size: var(--text-xs);
  line-height: var(--leading-base);
  color: var(--text-tertiary);
}
.gen-hint.is-bad,
.gen-hint.err { color: var(--danger); }
.gen-note {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}

/* 剧本库卡片 */
.lib-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-2);
}
.lib-head h4 { font-size: var(--text-lg); font-weight: var(--weight-medium); margin: 0; }
.lib-meta { font-size: var(--text-xs); color: var(--text-tertiary); }

.scene-card__actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.mini-btn {
  min-height: 32px;
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-secondary);
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.mini-btn:hover { background: var(--bg-subtle); color: var(--text-primary); }


/* ============================================================
   对话页
   ============================================================ */
.chat-wrap {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--space-5) var(--space-5) var(--space-6);
  display: flex; gap: var(--space-4);
  align-items: flex-start;
}
.chat-main {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
  height: calc(100vh - 56px);
  gap: var(--space-3);
}

.chat-header {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  flex-wrap: wrap;
}
.chat-header .h-title {
  font-size: var(--text-base); font-weight: var(--weight-medium);
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 难度徽章：与选择器共用同一组难度色 */
.badge {
  display: inline-flex; align-items: center;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs); font-weight: var(--weight-medium);
  background: var(--bg-subtle); color: var(--text-secondary);
  white-space: nowrap;
}
.badge--easy { background: var(--diff-easy-soft); color: var(--diff-easy); }
.badge--normal { background: var(--diff-normal-soft); color: var(--diff-normal); }
.badge--hard { background: var(--diff-hard-soft); color: var(--diff-hard); }
.badge--real { background: var(--diff-real-soft); color: var(--diff-real); }

/* 实时训练状态条 · 1 + 3 智慧结构
   第一行＝1 个总指标（任务完成度），第二行＝3 个子指标的收缩栏 */
/* 顶部指标条：左边一整块「总目标 + 子目标」，右边「提示」 */
.tech-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-4);
  align-items: start;
  padding: var(--space-3) var(--space-4);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}
.tech-total { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.tech-total__row { display: flex; align-items: center; gap: var(--space-3); }
/* 子目标三条：并进总目标容器里，由「显示/隐藏」按钮控制 */
.tech-sub__body {
  display: flex; flex-wrap: wrap; gap: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-subtle);
}
.tech-sub__body[hidden] { display: none; }

/* 总指标行的文字样式（行本身由上面的 .tech-total__row 管） */
.tech-total .tech-k { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-secondary); }
.tech-total .tech-v { font-size: var(--text-sm); font-weight: var(--weight-medium); flex: none; }
.tech-note {
  color: var(--text-tertiary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.tech-cell { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-xs); min-width: 0; }
.tech-k { color: var(--text-tertiary); white-space: nowrap; }
.tech-v {
  color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 进度条：凹槽有内阴影、色条有顶部高光与柔和外发光，两种主题都立体 */
.meter {
  position: relative;
  width: 72px; height: 8px; flex: none;
  background: var(--bg-inset);
  border-radius: var(--radius-full);
  overflow: hidden;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.14);
}
.meter--lg { flex: 1 1 auto; width: auto; min-width: 110px; height: 14px; }
.meter i {
  position: relative;
  display: block; height: 100%; width: 0;
  background: var(--primary);
  border-radius: var(--radius-full);
  transition: width var(--dur-slow) var(--ease-out), background var(--dur-base) var(--ease-standard);
}
.meter i::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0) 62%);
  pointer-events: none;
}
/* 分数分级：高绿 / 中黄 / 低红，一律实心填充（不再使用斜纹） */
.meter i.is-good { background: var(--success); box-shadow: 0 0 10px -4px var(--success); }
.meter i.is-mid { background: var(--warning); box-shadow: 0 0 10px -4px var(--warning); }
.meter i.is-low { background: var(--danger); box-shadow: 0 0 10px -4px var(--danger); }

/* 任务完成度右侧的提示：默认只显示蒙版，轻触才换成真实文案。
   ⚠ 用 display 切换而不是「绝对定位 + opacity」——后者只要定位上下文出一点问题，
     real 就会裸露出来（2026-09-18 用户报「隐藏没生效」就是这个原因）。 */
.tech-note--veiled {
  position: relative;
  display: inline-flex; align-items: center;
  flex: none;
  padding: 3px var(--space-3);
  /* ⚠ 覆盖同名的 .tech-note 说明卡片样式（那个带 margin-top: space-12，
     不覆盖的话提示会被往下推一大截，2026-09-18 踩过） */
  margin-top: 0;
  border: 1px dashed var(--border-strong);
  border-left-width: 1px;
  border-radius: var(--radius-full);
  background: transparent;
  cursor: pointer;
  white-space: nowrap;
  max-width: none;
}
.tech-note--veiled .tech-note__real { display: none; }
.tech-note--veiled .tech-note__veil { display: inline-flex; align-items: center; }
.tech-note--veiled[data-open="true"] {
  border-color: transparent;
  border-style: solid;
}
.tech-note--veiled[data-open="true"] .tech-note__real { display: inline; }
.tech-note--veiled[data-open="true"] .tech-note__veil { display: none; }
.tech-note__veil {
  border-radius: inherit;
  background: var(--bg-inset);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  padding: 1px var(--space-2);
}

/* 设置项里的橙色提醒（例如「目前在场景对话中，此选项不可修改」） */
.setting-row__warn {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--warning);
  font-weight: var(--weight-medium);
}

/* 侧栏小标题 + 右侧动作按钮（档案区的「提示」） */
.panel-head-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3);
}

/* 首页：剧本库入口区 */
.lib-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4);
  margin: var(--space-8) 0 var(--space-3);
}
.lib-head__lead {
  font-size: var(--text-md);
  color: var(--text-secondary);
  line-height: 1.6;
}
.lib-actions {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.lib-actions__slot { min-height: 32px; }   /* 预留位：只占格子，不画任何东西 */

/* 消息区 */
.messages {
  flex: 1; overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--space-3);
  padding: var(--space-5);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}
.msg { display: flex; gap: var(--space-3); max-width: 68%; }
.msg__body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
/* 时间靠说话者那一侧对齐：自己的消息在右下，对方的在左下 */
.msg.user .msg__body { align-items: flex-end; }
.msg__time {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-standard);
}
.msg:hover .msg__time,
.msg:focus-within .msg__time,
.msg.is-open .msg__time { opacity: 1; }
.msg .avatar {
  width: 34px; height: 34px; flex: none;
  border-radius: var(--radius-full);
  display: grid; place-items: center;
  font-size: var(--text-xs); font-weight: var(--weight-medium);
  background: var(--bg-subtle); color: var(--text-secondary);
}
.msg .bubble {
  padding: var(--space-3) var(--space-4);
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) var(--radius-sm);
  font-size: var(--text-lg);
  line-height: 27px;
  white-space: pre-wrap;
  word-break: break-word;
}
.msg.user { align-self: flex-end; flex-direction: row-reverse; }
.msg.user .avatar { background: var(--primary); color: var(--on-primary); }
.msg.user .bubble {
  background: var(--primary-soft);
  border-color: var(--primary);
  border-radius: var(--radius-lg) var(--radius-lg) var(--radius-sm) var(--radius-lg);
}
.msg .sys-note { font-size: var(--text-sm); color: var(--text-secondary); line-height: var(--leading-base); }

.typing { display: inline-flex; gap: 4px; padding: 6px 2px; }
.typing i { width: 6px; height: 6px; border-radius: var(--radius-full); background: var(--primary); animation: blink 1.2s infinite; }
.typing i:nth-child(2) { animation-delay: .2s; }
.typing i:nth-child(3) { animation-delay: .4s; }
@keyframes blink { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }

/* 输入区 */
.input-bar {
  display: flex; gap: var(--space-2);
  padding: var(--space-3);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}
.input {
  flex: 1; min-width: 0;
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  font-family: inherit; font-size: var(--text-base);
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  transition: border-color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-fast) var(--ease-standard);
}
.input::placeholder { color: var(--text-tertiary); }
.input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.input:disabled { background: var(--bg-subtle); color: var(--text-disabled); cursor: not-allowed; }

/* 对话撤回（按难度限次）—— 放在输入栏最左侧。
   剩余次数常显，学员能提前规划「这句话值不值得用掉一次机会」。 */
.retract-btn { flex: none; white-space: nowrap; }
.retract-btn__count {
  display: inline-block; min-width: 1.05em;
  font-variant-numeric: tabular-nums; font-weight: var(--weight-medium);
  text-align: center;
}
/* 现实档不给撤回：划线 + 压暗，一眼看出「这一档没有反悔的机会」 */
.retract-btn.is-off { text-decoration: line-through; }

/* ============================================================
   侧栏
   ============================================================ */
.side-panel {
  width: var(--aside-width); flex: none;
  height: calc(100vh - 56px);
  overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--space-3);
}
.panel-block {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
}
.panel-block h3 {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  font-size: var(--text-sm); font-weight: var(--weight-medium);
  color: var(--text-primary);
  margin-bottom: var(--space-3);
}
.panel-block .count { font-size: var(--text-xs); font-weight: var(--weight-normal); color: var(--text-tertiary); }

.persona-row { margin-bottom: var(--space-3); }
.persona-row:last-child { margin-bottom: 0; }
.persona-row .k { font-size: var(--text-xs); color: var(--text-tertiary); margin-bottom: 3px; }
.persona-row .v { font-size: var(--text-sm); line-height: var(--leading-base); color: var(--text-primary); }
.persona-row .v.unknown { color: var(--text-tertiary); letter-spacing: .08em; }

.panel-hint {
  font-size: var(--text-xs); line-height: var(--leading-base);
  color: var(--text-tertiary);
  padding-top: var(--space-3); margin-top: var(--space-3);
  border-top: 1px dashed var(--border-subtle);
}

.clue-grid { display: flex; flex-direction: column; gap: var(--space-2); }
.clue-item {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
  font-size: var(--text-sm); line-height: var(--leading-base);
  color: var(--text-secondary);
}
.clue-item .dot {
  width: 8px; height: 8px; flex: none;
  border-radius: var(--radius-full);
  border: 1.5px solid var(--border-strong);
}
.clue-item.hit { background: var(--success-soft); color: var(--success); }
.clue-item.hit .dot { background: var(--success); border-color: var(--success); }

/* 橙色：当事人**顺嘴说出来的**（不是学生问出来的）—— 凭运气捡到的信息。
   与绿色的"主动挖到"区分开。 */
.clue-item.leaked { background: var(--warning-soft); color: var(--warning); }
.clue-item.leaked .dot { background: var(--warning); border-color: var(--warning); }

/* 预展示 / 自选的线索：本难度开局就给了方向的那几条，或者轮次到了自选的。
   一律灰色 —— 可读、但明显区别于"自己问出来的"绿色。 */
.clue-item.preview {
  background: var(--bg-subtle);
  color: var(--text-secondary);
}
.clue-item.preview .dot {
  background: var(--text-tertiary);
  border-color: var(--text-tertiary);
  opacity: .75;
}

/* 自选时机到了：还没问到的线索变成可点，点一条看内容（不计分）。 */
.clue-item.is-pickable {
  cursor: pointer;
  border: 1px dashed var(--border-subtle);
  background: var(--bg-surface);
}
.clue-item.is-pickable:hover {
  background: var(--primary-soft);
  border-color: var(--primary);
  color: var(--primary);
}
.clue-item.is-pickable:hover .dot { border-color: var(--primary); }

/* 人物档案里「可以点开看」的行。 */
.persona-row.is-pickable {
  cursor: pointer;
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
  margin: 0 calc(var(--space-3) * -1) var(--space-2);
}
.persona-row.is-pickable:hover { background: var(--primary-soft); }
.persona-row.is-pickable .v.unknown::after {
  content: '点此查看';
  margin-left: var(--space-2);
  font-size: var(--text-xs);
  color: var(--primary);
  letter-spacing: 0;
}
/* 被规则锁住、当前点不了的说明（例如"10 轮后可选择查看"）。 */
.persona-lock-note {
  display: block;
  margin-top: 2px;
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  letter-spacing: 0;
}

/* 报告出来后，把「始终没问出来」的线索明确标红 —— 复盘时一眼能看到漏了什么。
   （对话进行中不标，否则等于提前给答案） */
.clue-item.missed {
  background: var(--danger-soft);
  color: var(--danger);
}
.clue-item.missed .dot {
  background: transparent;
  border-color: var(--danger);
  border-style: dashed;
}

/* 卡片标题右侧的收起/展开按钮（当前只用在「关键信息拼图」上）。 */
.panel-fold {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; flex: none;
  border-radius: var(--radius-sm);
  color: var(--text-tertiary);
  cursor: pointer;
}
.panel-fold:hover { background: var(--bg-subtle); color: var(--text-secondary); }
.panel-fold .caret {
  width: 0; height: 0;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  transition: transform var(--dur-base) var(--ease-standard);
}
.panel-fold[aria-expanded="false"] .caret { transform: rotate(-90deg); }

/* 每轮对话解析：卡片要能包住内容。
   ⚠ 之前 .trace-block 只写了 flex:1，而被 .trace-log 的 max-height 顶住不让收缩，
     结果是卡片背景被压扁、解析文字"溢出"到框外（2026-09-19 用户报的"背景框有问题"）。
     修法：卡片自身用 flex 列 + overflow:hidden，日志区 min-height:0 让它能真正收缩。 */
.trace-block {
  flex: 1 1 auto;
  min-height: 160px;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.trace-log {
  flex: 1 1 auto;
  min-height: 0;
  display: flex; flex-direction: column; gap: var(--space-3);
  overflow-y: auto;
}
.trace-empty { font-size: var(--text-xs); color: var(--text-tertiary); line-height: var(--leading-base); }
.trace-item {
  font-size: var(--text-xs); line-height: var(--leading-base);
  color: var(--text-secondary);
  padding-left: var(--space-3);
  border-left: 2px solid var(--primary-soft);
}
.trace-item b { color: var(--text-primary); font-weight: var(--weight-medium); }
.trace-item .warn { color: var(--warning); }

/* ============================================================
   弹窗
   ============================================================ */
.modal-mask {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-5);
  background: var(--overlay);
  backdrop-filter: blur(2px);
}
.modal {
  width: 620px; max-width: 100%; max-height: 88vh; overflow-y: auto;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  padding: var(--space-6);
  box-shadow: var(--shadow-lg);
}
.modal--wide { width: 780px; }

/* ============================================================
   设置面板（左上角入口 + 行式设置项）
   行布局参考：左侧大字标题 + 下方灰色小字，右侧胶囊开关
   ============================================================ */

.settings-btn {
  position: fixed; top: var(--space-4); left: var(--space-4); z-index: 30;
  display: inline-flex; align-items: center; gap: var(--space-2);
  min-height: 36px; padding: 0 var(--space-4);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-full);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
  transition: color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              background var(--dur-fast) var(--ease-standard);
}
.settings-btn:hover { color: var(--text-primary); border-color: var(--border-strong); }
.settings-btn__icon {
  width: 15px; height: 15px; flex: none;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.modal--settings { width: 560px; max-height: 86vh; overflow-y: auto; }
.modal--confirm { width: 440px; }

.settings-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4); margin-bottom: var(--space-4);
}
.settings-head h2 { font-size: var(--text-xl); font-weight: var(--weight-semibold); }

.settings-list {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.setting-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-5);
  padding: var(--space-4) var(--space-5);
  background: var(--bg-surface);
}
.setting-row + .setting-row { border-top: 1px solid var(--border-subtle); }
.setting-row--sub { padding-top: 0; }
.setting-row__text { min-width: 0; }
.setting-row__title { font-size: var(--text-base); color: var(--text-primary); }
.setting-row__title--sm { font-size: var(--text-sm); color: var(--text-secondary); }
.setting-row__desc {
  margin-top: 4px;
  font-size: var(--text-xs); color: var(--text-tertiary); line-height: 1.6;
}
/* 调试模式关着时，下面几行灰显 */
.setting-row[data-locked="true"] .setting-row__title,
.setting-row[data-locked="true"] .setting-row__desc,
.setting-row[data-locked="true"] .setting-range { opacity: 0.45; }

.setting-range { display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-2); }
.setting-range input[type="range"] { flex: 1; max-width: 220px; accent-color: var(--primary); }
.setting-range__value { font-size: var(--text-xs); color: var(--text-secondary); min-width: 3em; }

/* 下拉选择（结局选择） */
.setting-select {
  flex: none; min-width: 118px; min-height: 34px;
  padding: 0 var(--space-3);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font-size: var(--text-sm);
}
.setting-select:hover:not(:disabled) { border-color: var(--border-strong); }
.setting-select:disabled { opacity: 0.4; cursor: not-allowed; }

/* 一行里右侧的多个控件（折叠箭头 + 开关） */
.setting-row__ctl { display: flex; align-items: center; gap: var(--space-3); flex: none; }

/* V 字折叠箭头：收起时朝下，展开时朝上 */
.fold-caret {
  position: relative;
  width: 26px; height: 26px; flex: none;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
}
.fold-caret::before {
  content: '';
  position: absolute; left: 50%; top: 50%;
  width: 7px; height: 7px;
  border-right: 1.5px solid var(--text-secondary);
  border-bottom: 1.5px solid var(--text-secondary);
  transform: translate(-50%, -65%) rotate(45deg);
  transition: transform var(--dur-base) var(--ease-standard);
}
.fold-caret[aria-expanded="true"]::before { transform: translate(-50%, -35%) rotate(-135deg); }
.fold-caret:hover:not(:disabled) { border-color: var(--border-strong); }
.fold-caret:disabled { opacity: 0.4; cursor: not-allowed; }

.setting-more[hidden] { display: none; }

/* 胶囊开关 */
.switch {
  position: relative; flex: none;
  width: 46px; height: 26px; padding: 0;
  background: var(--bg-inset);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-full);
  transition: background var(--dur-base) var(--ease-standard),
              border-color var(--dur-base) var(--ease-standard);
}
.switch::after {
  content: '';
  position: absolute; top: 2px; left: 2px;
  width: 20px; height: 20px;
  background: var(--bg-surface);
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform var(--dur-base) var(--ease-standard);
}
.switch[data-on="true"] { background: var(--primary); border-color: var(--primary); }
.switch[data-on="true"]::after { transform: translateX(20px); }
.switch:disabled { opacity: 0.4; cursor: not-allowed; }

.settings-note {
  margin-top: var(--space-4);
  font-size: var(--text-xs); color: var(--text-secondary);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-inset);
  border-radius: var(--radius-md);
}

.confirm-text { margin: var(--space-3) 0 var(--space-2); font-size: var(--text-base); color: var(--text-primary); }
.confirm-note { margin-bottom: var(--space-5); font-size: var(--text-xs); color: var(--text-tertiary); }

/* 实心红底的危险按钮（二次确认的「确定」） */
.btn--danger-solid { background: var(--danger); color: #FFFFFF; }
.btn--danger-solid:hover:not(:disabled) { filter: brightness(0.92); }
.btn--danger-solid:disabled { opacity: 0.5; cursor: not-allowed; }

/* 演示模式挂件 */
.demo-badge {
  position: fixed; right: var(--space-5); bottom: var(--space-5); z-index: 40;
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-full);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
  font-size: var(--text-sm); color: var(--text-secondary);
}
.demo-badge__dot {
  width: 8px; height: 8px; flex: none; border-radius: 50%;
  background: var(--danger);
  animation: demoPulse 1.4s ease-in-out infinite;
}
.demo-badge__stop {
  padding: 2px var(--space-3); border-radius: var(--radius-full);
  font-size: var(--text-xs); color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
}
.demo-badge__stop:hover { color: var(--text-primary); border-color: var(--border-strong); }

@keyframes demoPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}
.modal .m-tag {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--primary-soft); color: var(--primary);
  font-size: var(--text-xs); font-weight: var(--weight-medium);
  margin-bottom: var(--space-3);
}
.modal h2 { font-size: var(--text-xl); font-weight: var(--weight-medium); margin-bottom: var(--space-4); }
.modal .m-row { margin-bottom: var(--space-4); }
.modal .m-row .k { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--primary); margin-bottom: 2px; }
.modal .m-row .v { font-size: var(--text-base); line-height: var(--leading-loose); color: var(--text-primary); }
.modal .m-actions { display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-5); }

/* ============================================================
   报告
   ============================================================ */
.report-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--space-4); flex-wrap: wrap;
  margin-bottom: var(--space-5);
}
.report-body { font-size: var(--text-sm); }
/* 报告里的 1 + 3 总览：任务完成度 + 三个子指标 */
.overall-bar {
  height: 10px; background: var(--bg-inset); border-radius: var(--radius-full);
  overflow: hidden; margin: var(--space-2) 0 var(--space-4);
}
.overall-bar i { display: block; height: 100%; width: 0; background: var(--primary); border-radius: var(--radius-full); }
.overall-grid { display: flex; flex-direction: column; gap: var(--space-2); }
.overall-row { display: flex; align-items: center; gap: var(--space-3); font-size: var(--text-xs); }
.overall-row .ok { flex: none; width: 6em; color: var(--text-secondary); }
.overall-row .ometer { flex: 1; height: 6px; background: var(--bg-inset); border-radius: var(--radius-full); overflow: hidden; }
.overall-row .ometer i { display: block; height: 100%; width: 0; background: var(--primary); border-radius: var(--radius-full); }
.overall-row .ov { flex: none; width: 2.5em; text-align: right; color: var(--text-primary); }
.overall-note { color: var(--text-tertiary); font-size: var(--text-xs); margin-top: var(--space-3); }

/* 报告里的「实际 vs 预期」折线图（手绘 SVG） */
.chart { display: block; width: 100%; height: auto; margin: var(--space-3) 0 var(--space-2); }
.chart__title { font-size: 13px; font-weight: var(--weight-medium); fill: var(--text-secondary); }
.chart__legend { font-size: 11px; fill: var(--text-tertiary); }
.chart__grid { stroke: var(--border-subtle); stroke-width: 0.5; }
.chart__axis { font-size: 11px; fill: var(--text-tertiary); }
.chart__line { fill: none; }
.chart__line--actual { stroke: var(--primary); stroke-width: 2; }
.chart__line--plan { stroke: var(--success); stroke-width: 1.5; stroke-dasharray: 4 4; }
.chart__dot { fill: var(--bg-surface); stroke: var(--primary); stroke-width: 1.5; }
.chart__value { font-size: 12px; font-weight: var(--weight-medium); fill: var(--primary); }
.chart-toggle { margin-top: var(--space-3); }

/* 四个专业维度卡片：可点击展开对应走势图 */
.score-card {
  display: block; width: 100%; text-align: left;
  font: inherit; color: inherit; cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-standard);
}
.score-card:hover { border-color: var(--border-strong); }
.score-card[aria-expanded="true"] { border-color: var(--primary); }
.score-card__hint {
  display: block; margin-top: var(--space-2);
  font-size: var(--text-xs); color: var(--text-tertiary);
}
.score-card[aria-expanded="true"] .score-card__hint { color: var(--primary); }

.dim-charts { margin-top: var(--space-4); }
.dim-chart[hidden] { display: none; }
.chart-detail {
  display: flex; flex-direction: column; gap: var(--space-5);
  margin-top: var(--space-4); padding-top: var(--space-4);
  border-top: 1px dashed var(--border-subtle);
}
.chart-detail[hidden] { display: none; }

/* 报告里的进度条与实时栏同样走三级实心配色 */
.overall-bar i.is-good, .overall-row .ometer i.is-good { background: var(--success); }
.overall-bar i.is-mid, .overall-row .ometer i.is-mid { background: var(--warning); }
.overall-bar i.is-low, .overall-row .ometer i.is-low { background: var(--danger); }

.report-scores { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: var(--space-3); margin: var(--space-5) 0; }
.score-card {
  padding: var(--space-4);
  background: var(--bg-subtle);
  border-radius: var(--radius-md);
}
.score-card .sk { display: flex; justify-content: space-between; font-size: var(--text-xs); color: var(--text-secondary); }
.score-card .sv { display: block; font-size: var(--text-2xl); font-weight: var(--weight-medium); color: var(--primary); margin: var(--space-1) 0; }
.score-card .sbar { height: 5px; background: var(--bg-inset); border-radius: var(--radius-full); overflow: hidden; }
.score-card .sbar i { display: block; height: 100%; background: var(--primary); }

.report-sec { padding-top: var(--space-4); margin-top: var(--space-4); border-top: 1px solid var(--border-subtle); }
.report-sec:first-child { border-top: none; margin-top: 0; padding-top: 0; }
.report-sec h4 { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--primary); margin-bottom: var(--space-2); }
.report-sec p { line-height: var(--leading-loose); color: var(--text-secondary); margin-bottom: var(--space-2); }
.report-sec ul { display: flex; flex-direction: column; gap: var(--space-2); }
.report-sec li {
  font-size: var(--text-sm); line-height: var(--leading-base);
  color: var(--text-secondary);
  padding-left: var(--space-4); position: relative;
}
.report-sec li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 5px; height: 5px; border-radius: var(--radius-full); background: var(--border-strong);
}
.report-sec .good { color: var(--success); }
.report-sec .bad { color: var(--danger); }
/* 当事人主动透漏的线索：橙色，和"问出来的"区分开 */
.report-sec .revealed { color: var(--warning); }

.ending-chip {
  display: inline-flex; align-items: center;
  padding: 3px var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs); font-weight: var(--weight-medium);
}
.ending-good { background: var(--success-soft); color: var(--success); }
.ending-neutral { background: var(--warning-soft); color: var(--warning); }
.ending-bad { background: var(--danger-soft); color: var(--danger); }

/* ============================================================
   响应式
   ============================================================ */
@media (max-width: 1024px) {
  :root { --aside-width: 100%; }
  .chat-wrap { flex-direction: column; }
  .chat-main { height: auto; min-height: 60vh; }
  .side-panel { width: 100%; height: auto; }
  .messages { min-height: 320px; }
}

@media (max-width: 900px) {
  .home-wrap { padding: var(--space-8) var(--space-5) var(--space-12); }
  .college-grid { grid-template-columns: repeat(2, 1fr); }
  .brand h1 { font-size: var(--text-2xl); }
  .msg { max-width: 88%; }
  /* 窄屏下所有按钮提升到 44px 触控标准 */
  .btn { min-height: var(--tap-min); }
  .btn--sm { min-height: 38px; }
  .segmented__item { min-height: 38px; }
  .tech-bar { gap: var(--space-2); }
  .tech-sub__body { flex-direction: column; align-items: stretch; gap: var(--space-2); }
  .tech-total { flex-wrap: wrap; }
  .tech-note { flex: 1 1 100%; }
  .chat-header .h-title { width: 100%; flex: none; order: -1; }
}

@media (max-width: 620px) {
  .college-grid { grid-template-columns: 1fr; }
  .scene-card__foot { flex-direction: column; align-items: stretch; }
  .scene-card__foot .btn { width: 100%; }
  .segmented { width: 100%; }
  .report-scores { grid-template-columns: 1fr; }
  .modal { padding: var(--space-5); border-radius: var(--radius-lg); }
  .theme-toggle { top: var(--space-3); right: var(--space-3); }
  .theme-toggle__text { display: none; }
}

/* 打印：提交物要嵌进设计文档 PDF */
@media print {
  .theme-toggle, .skip-link, .input-bar, .chat-header .btn { display: none !important; }
  body { background: #fff; }
  .messages, .side-panel, .panel-block, .scene-card, .college-card, .modal { box-shadow: none; }

  /* ------------------------------------------------------------
     报告要能完整打印出来（2026-09-21 修复）
     ------------------------------------------------------------
     原来只去了阴影，弹窗本身还是「fixed + max-height: 88vh + overflow: auto」，
     打印时只出首屏那一截，后面的分数明细全被裁掉；
     「返回对话 / 打印 / 换个难度再练一次」这几个按钮也会一起印上去。

     修法：打印时把遮罩和弹窗都「摊平」成普通流式内容，并只保留打开的弹窗。
     ⚠ 用 `:has()` 限定「有弹窗打开时」才隐藏背景 —— 否则直接打印首页会是一片空白。
     ⚠ 7 个 .modal-mask 都是 <body> 的直接子元素（见 index.html 的 </main> 之后）。
     ------------------------------------------------------------ */
  body:has(> .modal-mask:not([hidden])) > *:not(.modal-mask) { display: none !important; }

  .modal-mask[hidden] { display: none !important; }
  .modal-mask:not([hidden]) {
    position: static !important;
    inset: auto !important;
    padding: 0 !important;
    background: none !important;
    backdrop-filter: none !important;
    display: block !important;
  }
  .modal,
  .modal--wide,
  .modal--settings {
    position: static !important;
    width: auto !important;
    max-width: none !important;
    max-height: none !important;   /* ← 关键：不再限高，长报告不会被切成首屏 */
    overflow: visible !important;  /* ← 关键：不再内部滚动 */
    padding: 0 !important;
    border: none !important;
    border-radius: 0 !important;
    box-shadow: none !important;
  }
  /* 弹窗内部所有滚动容器一并摊开 */
  .modal * { max-height: none !important; overflow: visible !important; }

  /* 操作按钮与关闭按钮不进打印内容 */
  .m-actions,
  .modal .report-head .btn,
  .modal .m-close { display: none !important; }

  /* 报告里表格/图表别被跨页切断 */
  .report-body table, .report-body .score-row, .report-body li { break-inside: avoid; }
}
/* ============================================================
 * 剧本库（独立页面）
 *
 * ⚠ 这一页之上浮着两个「固定定位」的全局按钮：
 *     · .settings-btn  fixed，left + top(16px)，高 36px → 中心 y=34
 *     · .theme-toggle  fixed，right + top(16px)，高 38px → 中心 y=35
 *   原来的问题是顶栏从 y=0 起算，中心只有 y=20，和两个按钮**错开 14px**，
 *   看起来就是"浮层压在页面上、还没对齐"。
 *
 *   现在的做法：给页面加 16px 上内边距把顶栏推到和按钮同一个水平带，
 *   顶栏高度也定成 36px，三者中心对齐；再把两个按钮在本页统一成 36px。
 * ============================================================ */
.lib-page {
  display: flex; flex-direction: column; gap: var(--space-5);
  /* 和首页保持同一个内容宽度并居中 —— 不加这条宽屏下会直接铺满整个视口，
     看起来就像"一整块盖在屏幕上"，没有呼吸感 */
  max-width: 1180px; margin: 0 auto; width: 100%;
  padding: var(--space-4) var(--space-6) var(--space-12);
}

.lib-topbar {
  display: flex; align-items: center; gap: var(--space-3);
  /* ⚠ flex-wrap: wrap —— 原来是不换行的单行 flex。
     窗口一窄，右侧那几个按钮要么被压扁、要么被裁掉。
     允许换行后最坏情况是顶栏变两行，但**按钮一定还在**（2026-09-21 用户报过
     「剧本库页看不到预览版按钮」，见下面 .top-actions 的 flex: none 注释）。 */
  flex-wrap: wrap;
  min-height: 44px; padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border-subtle);
}

/* 被搬进顶栏的全局按钮：取消固定定位，变成普通行内元素，
   这样它们就和返回、标题、计数在同一行、同一个基线上。

   ⚠ 右上角现在是一个容器（预览版 Beta + 主题按钮装在一起），
     要取消 fixed 的是**容器**本身 —— 只取消里面按钮的定位没用，
     容器还是 fixed 的话，整个组合会继续贴在屏幕右上角。 */
.lib-topbar.has-global .settings-btn,
.lib-topbar.has-global .top-actions {
  position: static;
  top: auto; left: auto; right: auto;
  min-height: 36px;
  margin: 0;
  /* ⚠ 必须 flex: none —— 顶栏是 flex 容器，这两项默认 flex-shrink: 1，
     空间一紧就会被压扁到**宽度 0**：左侧的「返回首页 / 标题 / 计数」都还在，
     唯独按钮凭空消失（2026-09-21 用户报的就是这个现象）。
     flex: none = 不放大也不缩小，永远保持自身宽度。 */
  flex: none;
}
.lib-topbar.has-global .settings-btn { order: -1; }
.lib-topbar.has-global .top-actions { margin-left: var(--space-2); }

/* 容器里的两个按钮同样禁止被压缩 —— 别让它们互相挤 */
.lib-topbar.has-global .beta-btn,
.lib-topbar.has-global .theme-toggle { flex: none; }

/* 主题按钮自己是 static 的（外层容器负责定位），搬进顶栏后不用额外处理 */
.lib-topbar.has-global .theme-toggle { position: static; top: auto; right: auto; }

/* ⚠ **绝对不要**把 .beta-btn 也改成 static！
   它那条循环掠光是 `.beta-btn::after { position: absolute; inset: 0 }`，
   靠 .beta-btn 的 position: relative 当包含块。
   一旦改成 static，::after 的包含块会退到「最近的非 static 祖先」——
   而顶栏和 .top-actions 都是 static，最终落到**初始包含块（视口）**，
   于是那束白光会铺满整页（2026-09-21 用户实测反馈）。
   它本来就是 relative，搬进顶栏不需要动。 */

.lib-back {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 36px; padding: 0 14px 0 10px;
  font-size: var(--text-sm); color: var(--text-secondary);
  background: transparent;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-full);
  cursor: pointer;
  transition: color var(--dur-base) var(--ease-standard),
              border-color var(--dur-base) var(--ease-standard);
}
.lib-back:hover { color: var(--primary); border-color: var(--primary); }
.lib-topbar__title {
  margin: 0; font-size: var(--text-xl); font-weight: var(--weight-medium);
  color: var(--text-primary); line-height: 36px;
}
.lib-topbar__count {
  margin-left: auto; font-size: var(--text-sm); color: var(--text-tertiary);
  line-height: 36px;
}

/* 筛选栏：横排，窄屏自动换行 */
.lib-filters {
  display: flex; align-items: flex-end; gap: var(--space-4); flex-wrap: wrap;
  padding: var(--space-4) var(--space-5);
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}
.filter-item { display: flex; flex-direction: column; gap: 6px; }
.filter-item__k {
  font-size: var(--text-xs); color: var(--text-tertiary); letter-spacing: .02em;
  line-height: 16px;          /* 与下面控件一起构成固定行高，保证各列基线一致 */
}
.filter-item select {
  min-width: 136px; max-width: 230px; height: 36px;
  padding: 0 var(--space-3);
  font-size: var(--text-sm); color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  cursor: pointer;
}
.filter-item select:hover:not(:disabled) { border-color: var(--border-strong); }
.filter-item select:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.filter-item select option:disabled { color: var(--text-tertiary); }

/* 锁定态：专业在未选学院时不可用（专业隶属于学院，没选学院就无从谈起） */
.filter-item select:disabled {
  color: var(--text-tertiary);
  background: var(--bg-subtle);
  border-style: dashed;
  cursor: not-allowed;
  opacity: .65;
}
.filter-item select:disabled:hover { border-color: var(--border-subtle); }

/* 「重置」和下拉框是同一行，必须同高 —— 否则底边参差 */
.lib-filters > .btn { height: 36px; min-height: 36px; }

/* 卡片网格：最小 320px，宽屏最多三到四列（原来 280px 会挤成五列） */
.lib-grid {
  display: grid; gap: var(--space-4);
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.lib-card {
  display: flex; flex-direction: column; gap: var(--space-3); text-align: left;
  padding: var(--space-5);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
  cursor: pointer;
  transition: border-color var(--dur-base) var(--ease-standard),
              box-shadow var(--dur-base) var(--ease-standard),
              transform var(--dur-base) var(--ease-standard);
}
.lib-card:hover {
  border-color: var(--primary);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}
.lib-card:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.lib-card__tags { display: flex; flex-wrap: wrap; gap: 6px; }
.lib-tag {
  padding: 2px 8px;
  font-size: var(--text-xs); line-height: 1.7;
  border-radius: var(--radius-sm);
  background: var(--bg-subtle); color: var(--text-secondary);
}
.lib-tag.cat--preset { background: var(--success-soft); color: var(--success); }
.lib-tag.cat--generated { background: var(--warning-soft); color: var(--warning); }
/* 草稿：用中性灰，视觉上明确弱于「预设 / AI生成」—— 它是半成品，不该抢眼 */
.lib-tag.cat--draft {
  background: var(--bg-inset); color: var(--text-secondary);
  border: 1px dashed var(--border-strong);
}
/* 全行业（beta测试版）：紫色（用户 2026-09-22 指定）。
   它和「AI生成」是并列的独立类别，用色相直接区分，不靠深浅。
   两个主题各有一套 token，见 tokens.css 的 --beta / --beta-soft。 */
.lib-tag.cat--beta { background: var(--beta-soft); color: var(--beta); }
/* 自制（工作室定稿的剧本）：青色，见 tokens.css 的 --custom */
.lib-tag.cat--custom { background: var(--custom-soft); color: var(--custom); }

.lib-card__title {
  margin: 0; font-size: var(--text-base); font-weight: var(--weight-medium);
  color: var(--text-primary); line-height: var(--leading-tight);
}
.lib-card__role { margin: 0; font-size: var(--text-sm); color: var(--text-secondary); }
.lib-card__sum {
  margin: 0; font-size: var(--text-sm); color: var(--text-tertiary);
  line-height: var(--leading-base);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.lib-card__meta {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-top: auto; padding-top: var(--space-2);
  font-size: var(--text-xs); color: var(--text-tertiary);
  border-top: 1px solid var(--border-subtle);
}
.lib-card__dot { opacity: .5; }

.lib-loading, .lib-empty {
  grid-column: 1 / -1;
  padding: var(--space-7) 0; text-align: center;
  font-size: var(--text-sm); color: var(--text-tertiary);
}
.lib-empty__ico { display: block; font-size: 28px; margin-bottom: var(--space-3); opacity: .5; }

/* 该列被锁定时，标签也一起变淡，视觉上更明确"这一项现在不能用" */
.filter-item:has(select:disabled) .filter-item__k { opacity: .5; }

/* 层次标签：本科用主色、专科用中性色，和「类别」标签区分开 */
.lib-tag.lv--undergrad { background: var(--primary-soft); color: var(--primary); }
.lib-tag.lv--junior { background: var(--bg-subtle); color: var(--text-secondary); }

/* 筛选项变多了（学院/层次/专业/类别/排序/顺序 + 重置），
   把下拉收窄一点，让整条筛选栏在常见宽度下尽量排成一行 */
.filter-item select { min-width: 124px; max-width: 208px; }
.filter-item__k { white-space: nowrap; }

/* 筛选栏里的「重置」推到最右，和前面的条件组拉开距离 */
.lib-filters > .btn { margin-left: auto; }

/* 卡片底部：难度选择 + 开始按钮。
   卡片本身不再整体可点（内部有交互控件了），点击区域收敛到按钮上 */
.lib-card { cursor: default; }
.lib-card:hover { transform: none; }
.lib-card__foot {
  display: flex; align-items: center; gap: var(--space-3);
  margin-top: var(--space-2); padding-top: var(--space-3);
  border-top: 1px solid var(--border-subtle);
}
.lib-card__foot .segmented { flex: 1; min-width: 0; }
.lib-card__foot .btn { flex: none; }

/* ============================================================
 * 难度选择弹窗
 * 刻意把难度从卡片上收进这里：四档的可见度规则差别很大，
 * 卡片没地方写说明；弹窗里分段器有整行宽度，下面还能跟一行小字。
 * ============================================================ */
.diff-pick__scene {
  margin: calc(var(--space-2) * -1) 0 var(--space-5);
  font-size: var(--text-sm); color: var(--text-secondary);
}

/* 弹窗里的分段器占满整行 —— 每个选项都有足够宽度，文字不会折成竖排 */
.segmented--wide { display: flex; width: 100%; }
.segmented--wide .segmented__item { flex: 1; min-width: 0; }

/* 难度说明：固定最小高度，切换难度时弹窗不会跳高跳矮 */
.diff-pick__note {
  margin: var(--space-4) 0 0;
  min-height: 42px;
  font-size: var(--text-sm); color: var(--text-secondary);
  line-height: var(--leading-base);
}

/* 「还没有 AI 剧本」的空态提示 —— 剧本库入口保持可见，只把列表换成这句话 */
.lib-empty-hint {
  margin: 0; padding: var(--space-4) var(--space-5);
  font-size: var(--text-sm); line-height: var(--leading-base);
  color: var(--text-secondary);
  background: var(--bg-subtle);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-md);
}

/* ============================================================
   语音输入（对话输入框 · 发送按钮左侧）
   ============================================================
   点一下开始录、再点一下停；识别结果**实时**填进输入框，学生改完再发。
   录音时：按钮变红色渐变 + 呼吸光圈，旁边出现一条跳动的波形。

   ⚠ 只支持「点一下录/再点一下停」这一种交互 —— 按住说话在触屏/鼠标上
     都要额外处理 pointerdown/up 与拖出按钮的情况，先不做。
   ============================================================ */

.voice-btn {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-secondary);
  border-radius: 50%;
  background: var(--bg-surface);
  color: var(--text-secondary);
  cursor: pointer;
  transition: color .16s, border-color .16s, background .16s, transform .12s;
}
.voice-btn:hover:not(:disabled) {
  color: var(--text-primary);
  border-color: var(--text-tertiary);
}
.voice-btn:active:not(:disabled) { transform: scale(.94); }
.voice-btn:disabled { opacity: .45; cursor: not-allowed; }
.voice-btn svg { width: 20px; height: 20px; display: block; }
.voice-btn__stop { display: none; }

/* 录音中：红色渐变 + 呼吸光圈 */
.voice-btn.is-recording {
  color: #fff;
  border-color: transparent;
  background: linear-gradient(135deg, #FF7A7A 0%, #DC2F2F 100%);
  animation: voicePulse 1.5s ease-in-out infinite;
}
.voice-btn.is-recording .voice-btn__mic { display: none; }
.voice-btn.is-recording .voice-btn__stop { display: block; }

@keyframes voicePulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(220, 47, 47, .42); }
  60%      { box-shadow: 0 0 0 8px rgba(220, 47, 47, 0); }
}
/* 尊重系统的「减少动态效果」设置 */
@media (prefers-reduced-motion: reduce) {
  .voice-btn.is-recording { animation: none; }
}

/* 连接中 / 识别中：按钮转圈提示还没就绪 */
.voice-btn.is-busy { color: var(--text-tertiary); cursor: progress; }

/* 跳动波形 —— 只在录音时出现，平时 hidden 不占位 */
.voice-wave {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  height: 26px;
  padding: 0 var(--space-1);
}
.voice-wave[hidden] { display: none; }
.voice-wave i {
  width: 3px;
  height: 6px;
  border-radius: 2px;
  background: linear-gradient(180deg, #FF8A8A 0%, #D92B2B 100%);
  transition: height .07s linear;
}

/* 录音状态 / 出错提示 */
.voice-tip {
  margin: var(--space-2) 0 0;
  font-size: var(--text-xs);
  line-height: 1.6;
  color: var(--text-tertiary);
}
.voice-tip[hidden] { display: none; }
.voice-tip.is-error { color: var(--danger); }
.voice-tip__dot {
  display: inline-block;
  width: 6px; height: 6px;
  margin-right: 6px;
  border-radius: 50%;
  background: var(--danger);
  vertical-align: middle;
  animation: voiceBlink 1.1s ease-in-out infinite;
}
@keyframes voiceBlink { 0%, 100% { opacity: 1 } 50% { opacity: .25 } }
@media (prefers-reduced-motion: reduce) {
  .voice-tip__dot { animation: none; }
}


/* ---- 语音输入面板（高级参数里的一节）---- */
.st-voice {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
}
.st-voice__row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  justify-content: space-between;
}
.st-voice__row .st-pname { flex: 1 1 auto; min-width: 0; }
.st-voice__row select {
  flex: 0 0 auto;
  min-width: 260px;
  max-width: 62%;
}
.st-voice__row select:disabled { opacity: .5; cursor: not-allowed; }
.st-voice__note {
  margin: 0;
  font-size: var(--text-xs);
  line-height: 1.6;
  color: var(--text-tertiary);
  padding-top: var(--space-1);
  border-top: 1px dashed var(--border-subtle);
}
/* 窄屏：两栏改成上下堆叠，不然下拉会被挤得看不清 */
@media (max-width: 720px) {
  .st-voice__row { flex-direction: column; align-items: stretch; gap: var(--space-2); }
  .st-voice__row select { min-width: 0; max-width: 100%; }
}

/* ═══════════════════════════════════════════════════════════════
   语音朗读（TTS）—— 2026-09-23 新增
   配套：public/tts.js（逻辑 ✗）、lib/tts.js（服务端合成 ✗）
   ═══════════════════════════════════════════════════════════════ */

/* 气泡要成为定位基准，里面的重播按钮才能贴右下角
   （原来 `.msg .bubble` 没设 position ✗ 追加一条不冲突 ✓） */
.msg .bubble { position: relative; }

/* 「重播这一条」按钮：平时几乎看不见，别干扰阅读；
   鼠标移到气泡上才显现，聚焦（键盘 Tab）时也显现 —— 不然键盘用户找不到它。 */
.bubble__speak {
  position: absolute;
  right: 6px;
  bottom: 4px;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-standard),
              background var(--dur-fast) var(--ease-standard);
}
.msg .bubble:hover .bubble__speak { opacity: .6; }
.bubble__speak:hover { opacity: 1 !important; background: var(--bg-subtle); }
.bubble__speak:focus-visible {
  opacity: 1;
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}

/* 正在朗读的那一条：一层柔和的外圈 —— 让人一眼知道「声音是这条发出来的」 */
.msg .bubble.is-speaking { box-shadow: 0 0 0 2px var(--primary-soft); }

/* 顶栏的朗读开关。关掉时降一点存在感，但**要还能看清、能点** ——
   做到「看不见」就等于用户没法把它打开了。 */
#ttsBtn.is-off { opacity: .55; }

/* 合成中：在 🔊 的位置转圈 —— 明确告诉用户「在忙，马上就好」
   （首次要点一下才出声（现场生成声音样本 ✗ 3~5 秒 ✗）
     没有这个反馈的话，用户会以为卡死了 —— 2026-09-24 修） */
@keyframes wm-tts-spin { to { transform: rotate(360deg); } }
.msg .bubble.is-loading { box-shadow: 0 0 0 2px var(--primary-soft); }
.bubble.is-loading .bubble__speak { opacity: 1; color: transparent; }
.bubble.is-loading .bubble__speak::after {
  content: '';
  position: absolute;
  left: 4px; top: 4px; right: 4px; bottom: 4px;
  border: 2px solid var(--text-tertiary);
  border-top-color: transparent;
  border-radius: 50%;
  animation: wm-tts-spin .7s linear infinite;
}

/* 被服务端锁定的开关：禁用 + 降透明度 + 提示不可点 */
.switch.is-locked,
.switch:disabled {
  opacity: .5;
  cursor: not-allowed;
}

/* ═══════════════════════════════════════════════════════════════
   账号系统 —— 2026-09-25 新增
   配套：public/account.js（逻辑）、lib/handlers-account.js（接口）
   配色一律走主题变量 ✗ 明暗两套主题都正常 ✓
   ═══════════════════════════════════════════════════════════════ */

/* 右上角的用户按钮：和主题按钮、设置按钮同一排 */
.account-btn {
  margin-left: 8px;
  padding: 6px 12px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
  color: var(--text-secondary);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
}
.account-btn:hover { color: var(--text-primary); border-color: var(--border-strong); }
/* 已登录：用主色描边 ✗ 一眼能看出"现在是登录状态" ✓ */
.account-btn.is-in {
  color: var(--primary);
  border-color: var(--primary);
  background: var(--primary-soft);
}

/* 弹窗里的表单行 */
.acc-field {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}
.acc-field > span {
  flex: 0 0 74px;
  color: var(--text-secondary);
  font-size: 13px;
  text-align: right;
}
.acc-field > input,
.acc-field > select {
  flex: 1;
  min-width: 0;
  padding: 8px 10px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-size: 14px;
  font-family: inherit;
}
.acc-field > input:focus,
.acc-field > select:focus {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}

/* 登录 / 注册 的切换 */
.acc-tabs {
  display: flex;
  gap: 6px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--border-subtle);
}
.acc-tab {
  padding: 8px 16px;
  border: none;
  border-bottom: 2px solid transparent;
  background: none;
  color: var(--text-tertiary);
  font-size: 14px;
  font-family: inherit;
  cursor: pointer;
}
.acc-tab.is-on {
  color: var(--primary);
  border-bottom-color: var(--primary);
  font-weight: 600;
}

/* 提示文字（灰）与错误（红） */
.acc-hint {
  margin: 10px 0 0;
  color: var(--text-tertiary);
  font-size: 12px;
  line-height: 1.7;
}
.acc-note {
  margin: 10px 0 0;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  color: var(--text-secondary);
  font-size: 13px;
}
.acc-note--bad {
  background: var(--danger-soft, rgba(220, 38, 38, .12));
  color: var(--danger, #dc2626);
}
.acc-bad { color: var(--danger, #dc2626); font-size: 12px; }

/* 账号下拉菜单 */
.acc-menu { display: flex; flex-direction: column; gap: 2px; }
.acc-menu__item {
  padding: 10px 12px;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-primary);
  font-size: 14px;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.acc-menu__item:hover { background: var(--bg-subtle); }

/* 成绩表 ✗ 列多 ✗ 允许横向滚动 ✓ */
.acc-scroll { overflow-x: auto; margin-top: 12px; }
.acc-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.acc-table th,
.acc-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-subtle);
  text-align: left;
  white-space: nowrap;
}
.acc-table th {
  color: var(--text-tertiary);
  font-weight: 500;
  font-size: 12px;
}
.acc-table tbody tr:hover { background: var(--bg-subtle); }
.acc-num { text-align: right; font-variant-numeric: tabular-nums; }
.acc-acts { display: flex; flex-wrap: wrap; gap: 4px; }
.acc-danger { color: var(--danger, #dc2626); }
.acc-role {
  padding: 3px 6px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-size: 12px;
  font-family: inherit;
}
.acc-tag {
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--bg-subtle);
  color: var(--text-secondary);
  font-size: 12px;
}
.acc-dim { color: var(--text-tertiary); font-size: 12px; }
.acc-head { margin-bottom: 10px; }
.acc-report {
  max-height: 52vh;
  overflow: auto;
  margin: 0;
  padding: 12px;
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  color: var(--text-primary);
  font-size: 13px;
  line-height: 1.8;
  white-space: pre-wrap;
  word-break: break-word;
}

/* 顶部飘一句提示（登录成功 / 已退出 之类） */
.acc-toast {
  position: fixed;
  left: 50%;
  top: 76px;
  z-index: 9999;
  padding: 10px 18px;
  border-radius: var(--radius-md);
  background: var(--text-primary);
  color: var(--bg-base);
  font-size: 13px;
  opacity: 0;
  transform: translate(-50%, -8px);
  pointer-events: none;
  transition: opacity .22s ease, transform .22s ease;
}
.acc-toast.is-on { opacity: 1; transform: translate(-50%, 0); }

/* 顶部飘一句提示（通用）—— 2026-09-25 补
   配 public/app.js 的 toast() ✗ 以及 library.js 通过 __weiminToast 借用 ✓ */
.wm-toast {
  position: fixed;
  left: 50%;
  top: 76px;
  z-index: 9998;
  max-width: 76vw;
  padding: 10px 18px;
  border-radius: var(--radius-md);
  background: var(--text-primary);
  color: var(--bg-base);
  font-size: 13px;
  line-height: 1.6;
  text-align: center;
  opacity: 0;
  transform: translate(-50%, -8px);
  pointer-events: none;
  transition: opacity .22s ease, transform .22s ease;
}
.wm-toast.is-on { opacity: 1; transform: translate(-50%, 0); }

/* ═══════════════════════════════════════════════════════════════════
   个人中心（独立界面）—— 2026-09-25 新增
   配 public/me.js
   ⚠ 颜色一律走主题变量 ✗ 不写死 ✓ 明暗两套主题都正常 ✓
   ⚠ 可点元素统一 min-height: var(--tap-min) ✗ 满足 WCAG 的 44px 触控目标 ✓
   ═══════════════════════════════════════════════════════════════════ */

.me {
  position: fixed;
  inset: 0;
  z-index: 900;
  overflow-y: auto;
  background: var(--bg-base);
  color: var(--text-primary);
}

/* ── 页头 ── */
.me__head {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-surface);
  position: sticky;
  top: 0;
  z-index: 2;
}
.me__back {
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-family: inherit;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
}
.me__back:hover { color: var(--text-primary); border-color: var(--border-strong); }
.me__back:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.me__title {
  flex: 1;
  margin: 0;
  font-size: var(--text-lg, 18px);
  font-weight: var(--weight-medium, 500);
}
.me__who { display: flex; align-items: baseline; gap: var(--space-3); }
.me__who-name { font-size: var(--text-base); font-weight: var(--weight-medium, 500); }
.me__who-meta { color: var(--text-tertiary); font-size: var(--text-xs, 12px); }

/* ── 两栏（教师 / 管理员）── */
.me__body {
  display: flex;
  align-items: flex-start;
  max-width: 1180px;
  margin: 0 auto;
  padding: var(--space-6);
  gap: var(--space-6);
}
.me__nav {
  flex: 0 0 168px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  position: sticky;
  top: 88px;
}
.me__nav-item {
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  border: none;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.me__nav-item:hover { background: var(--bg-subtle); color: var(--text-primary); }
.me__nav-item.is-on {
  background: var(--primary-soft);
  color: var(--primary);
  font-weight: var(--weight-medium, 500);
}
.me__nav-item:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.me__main { flex: 1; min-width: 0; }
.me__main--single { max-width: 880px; margin: 0 auto; padding: var(--space-6); }

/* ── 区块 ── */
.me__sec { margin-bottom: var(--space-8); }
.me__sec-t {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin: 0 0 var(--space-3);
  font-size: var(--text-md, 15px);
  font-weight: var(--weight-medium, 500);
}
.me__sec-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); }
.me__count { color: var(--text-tertiary); font-size: var(--text-xs, 12px); font-weight: 400; }

/* ── 四维分数卡 ── */
.me__cards {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-3);
}
.me__cards--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.me__card {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
}
.me__card-k { margin: 0; color: var(--text-secondary); font-size: var(--text-xs, 12px); }
.me__card-v {
  margin: 4px 0 0;
  font-size: 22px;
  font-weight: var(--weight-medium, 500);
  font-variant-numeric: tabular-nums;
}

/* ── 表格 ── */
.me__scroll { overflow-x: auto; }
.me__table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.me__table th,
.me__table td {
  padding: var(--space-3);
  border-bottom: 1px solid var(--border-subtle);
  text-align: left;
  white-space: nowrap;
}
.me__table th { color: var(--text-tertiary); font-size: var(--text-xs, 12px); font-weight: 400; }
.me__table tbody tr:hover { background: var(--bg-subtle); }
.me__num { text-align: right; font-variant-numeric: tabular-nums; }
.me__idx { color: var(--text-tertiary); }
.me__scene { max-width: 260px; overflow: hidden; text-overflow: ellipsis; }
.me__time { color: var(--text-tertiary); font-size: var(--text-xs, 12px); }
.me__acts { display: flex; flex-wrap: wrap; gap: 4px; }
.me__danger { color: var(--danger); }
.me__bad { color: var(--danger); font-size: var(--text-xs, 12px); }
.me__flag {
  margin-left: var(--space-2);
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--bg-subtle);
  color: var(--text-tertiary);
  font-size: 11px;
}
.me__tag {
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--bg-subtle);
  color: var(--text-secondary);
  font-size: var(--text-xs, 12px);
}
.me__select {
  min-height: 32px;
  padding: 0 var(--space-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--bg-elevated, var(--bg-surface));
  color: var(--text-primary);
  font-size: var(--text-xs, 12px);
  font-family: inherit;
}

/* ── 空状态 / 提示 ── */
.me__empty { padding: var(--space-12) var(--space-6); text-align: center; }
.me__empty-t { margin: 0; font-size: var(--text-md, 15px); font-weight: var(--weight-medium, 500); }
.me__empty-d { margin: var(--space-2) 0 var(--space-6); color: var(--text-tertiary); font-size: var(--text-sm); }
.me__hint { margin: var(--space-3) 0; color: var(--text-tertiary); font-size: var(--text-xs, 12px); line-height: 1.8; }
.me__note {
  margin: var(--space-3) 0;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  font-size: var(--text-sm);
}
.me__note--bad { background: var(--danger-soft); color: var(--danger); }
.me__note--ok { background: var(--success-soft, rgba(16,185,129,.14)); color: var(--success, #10b981); }
.me__note--warn { background: var(--warning-soft, rgba(245,158,11,.14)); color: var(--warning, #f59e0b); }
.me__meta { margin: 0 0 var(--space-3); color: var(--text-secondary); font-size: var(--text-sm); }
.me__report {
  max-height: 56vh;
  overflow: auto;
  margin: 0;
  padding: var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  font-size: var(--text-sm);
  line-height: 1.9;
  white-space: pre-wrap;
  word-break: break-word;
}

/* ── 表单 ── */
.me__form { max-width: 420px; }
.me__field { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
.me__field > span { flex: 0 0 76px; color: var(--text-secondary); font-size: var(--text-sm); text-align: right; }
.me__field > input,
.me__field > select {
  flex: 1;
  min-width: 0;
  min-height: var(--tap-min);
  padding: 0 var(--space-3);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--bg-elevated, var(--bg-surface));
  color: var(--text-primary);
  font-size: var(--text-base);
  font-family: inherit;
}
.me__field > input:focus,
.me__field > select:focus { outline: 2px solid var(--primary); outline-offset: 1px; }
.me__form-acts { margin-top: var(--space-4); }

/* ── 设置行（复用首页那套规则的视觉）── */
.me__list { display: flex; flex-direction: column; }
.me__row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--border-subtle);
}
.me__row-text { flex: 1; min-width: 0; }
.me__row-t { margin: 0; font-size: var(--text-sm); }
.me__row-d { margin: 2px 0 0; color: var(--text-tertiary); font-size: var(--text-xs, 12px); }
.me__row-warn { margin: 4px 0 0; color: var(--warning, #f59e0b); font-size: var(--text-xs, 12px); }

/* ── 弹窗（报告 / 新建账号 ✗ 比首页的 modal 轻一点 ✓）── */
.me__modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
  background: rgba(0, 0, 0, .46);
}
.me__modal-box {
  width: 100%;
  max-width: 720px;
  max-height: 86vh;
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  overflow: hidden;
}
.me__modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
}
.me__modal-t { margin: 0; font-size: var(--text-md, 15px); font-weight: var(--weight-medium, 500); }
.me__modal-x {
  width: var(--tap-min);
  height: var(--tap-min);
  border: none;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-tertiary);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}
.me__modal-x:hover { background: var(--bg-subtle); color: var(--text-primary); }
.me__modal-body { flex: 1; overflow: auto; padding: var(--space-5); }
.me__modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--border-subtle);
}

/* ── 窄屏：侧边栏变横向标签条 ✓ ── */
@media (max-width: 760px) {
  .me__body { flex-direction: column; padding: var(--space-4); gap: var(--space-4); }
  .me__nav {
    position: static;
    flex: none;
    width: 100%;
    flex-direction: row;
    overflow-x: auto;
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--border-subtle);
  }
  .me__nav-item { flex: 0 0 auto; text-align: center; }
  .me__main--single { padding: var(--space-4); }
  .me__cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .me__cards--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .me__head { padding: var(--space-3) var(--space-4); flex-wrap: wrap; }
  .me__who { width: 100%; }
  .me__field { flex-direction: column; align-items: stretch; gap: var(--space-1); }
  .me__field > span { text-align: left; }
  .me__modal { padding: var(--space-3); }
}

/* ── 尊重「减少动效」偏好（无障碍 ✗ WCAG 2.3.3）── */
@media (prefers-reduced-motion: reduce) {
  .me__nav-item,
  .me__back,
  .me__modal-box { transition: none; }
}
