/* components.css —— 全站复用的部件：进度胶囊、按钮、AI 助教面板、完成卡、口径角标、章节标、
   难题卡、指标表、原因树、可视化挂点、对话气泡、表单。
   同一位置同一含义（铁律六）：AI 助教永远在右栏或倒数第二栏；主按钮永远在右下；
   口径角标永远在数字右上；章节标永远在左下。
*/

/* ================= 进度导航（两级胶囊） ================= */

.progress-nav {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
}

.progress-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  overflow: hidden;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--c-line-strong);
  background: transparent;
  color: var(--c-text-3);
  font-size: var(--fs-xs);
  line-height: 1.6;
  white-space: nowrap;
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.pill:hover { border-color: var(--c-blue); color: var(--c-text-2); }
.pill .mark { font-size: var(--fs-xs); opacity: .9; }

.pill.done {
  color: var(--c-mint);
  border-color: rgba(61, 220, 151, 0.45);
  background: var(--c-mint-dim);
}
.pill.current {
  color: var(--c-text);
  border-color: var(--c-blue);
  background: var(--c-blue-dim);
  font-weight: 600;
}
.pill.locked { opacity: .55; }

.progress-row-2 .pill { padding: 2px 10px; font-size: var(--fs-xs); }
.progress-sep {
  color: var(--c-text-3);
  opacity: .4;
  font-size: var(--fs-xs);
}

.nav-host { min-width: 0; overflow: hidden; display: flex; justify-content: center; }
.foot-left { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.conn-chip.offline { color: var(--c-gold); }

/* 页面右上角的「了解更多」入口 */
.page-head > .stack { justify-self: end; align-items: flex-end; max-width: 46%; }
.page-head > .stack .more-body { text-align: left; max-height: 88px; overflow: auto; }

/* ================= 按钮（语义色） ================= */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 34px;
  padding: 0 18px;
  border-radius: var(--r-pill);
  border: 1px solid var(--c-line-strong);
  background: var(--c-slate-dim);
  color: var(--c-text-2);
  font-size: var(--fs-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: filter .15s, background .15s, border-color .15s;
}
.btn:hover { filter: brightness(1.15); }
.btn:disabled { opacity: .45; cursor: not-allowed; filter: none; }

/* 主流程：亮蓝 */
.btn-primary {
  background: var(--c-blue);
  border-color: var(--c-blue);
  color: var(--c-text-on-accent);
  font-weight: 600;
}
/* 确定 / 提交：绿 */
.btn-confirm {
  background: var(--c-mint);
  border-color: var(--c-mint);
  color: var(--c-text-on-accent);
  font-weight: 600;
}
/* 结束 / 清空：红 */
.btn-danger {
  background: transparent;
  border-color: var(--c-red);
  color: var(--c-red);
}
/* 次要：灰蓝 */
.btn-ghost {
  background: transparent;
  border-color: var(--c-line-strong);
  color: var(--c-slate);
}
.btn-sm { height: 26px; padding: 0 12px; font-size: var(--fs-xs); }
.btn-icon { width: 30px; height: 30px; padding: 0; border-radius: var(--r-sm); }

.seg-toggle {
  display: inline-flex;
  border: 1px solid var(--c-line-strong);
  border-radius: var(--r-pill);
  overflow: hidden;
}
.seg-toggle button {
  border: 0;
  background: transparent;
  color: var(--c-text-3);
  padding: 4px 10px;
  font-size: var(--fs-xs);
  cursor: pointer;
}
.seg-toggle button.on { background: var(--c-blue-dim); color: var(--c-blue); }

/* ================= 口径角标 ================= */

.cite {
  display: inline-block;
  margin-left: 2px;
  padding: 0 5px;
  border-radius: var(--r-pill);
  background: var(--c-slate-dim);
  border: 1px solid var(--c-line-strong);
  /* T46 对比度：角标压在自己那块胶囊底上，比一般次要文字的底更浅，所以单走 --c-cite-text 这一档
     （取值与前后对比写在 tokens.css 那两段注释里）。--c-text-3 与 --c-gold 都没有被改动。 */
  color: var(--c-cite-text);
  font-size: var(--fs-xs);
  line-height: 1.5;
  vertical-align: super;
  cursor: help;
}
.cite:hover { color: var(--c-blue); border-color: var(--c-blue); }
.cite.pending { color: var(--c-cite-pending); border-color: rgba(247, 189, 57, .5); background: var(--c-gold-dim); }

.num { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--c-blue); }
.num.measured { color: var(--c-gold); }
.num.verified { color: var(--c-mint); }

/* ================= 章节标（左下） ================= */

.chapter-mark {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--c-text-3);
  letter-spacing: 1px;
  white-space: nowrap;
}
.chapter-mark .cm-index { color: var(--c-gold); font-weight: 700; font-variant-numeric: tabular-nums; }
.chapter-mark .cm-total { opacity: .6; }
.chapter-mark .cm-title { color: var(--c-text-2); letter-spacing: 0; }

/* 页脚链条：目标 → 活动 → 证据 → 判据 */
.chain { display: flex; align-items: center; gap: var(--sp-2); }
.chain b { font-weight: 600; color: var(--c-text-2); }
.chain span.arrow { opacity: .45; }

/* ================= AI 助教面板 ================= */

.ai-panel { }
.ai-panel .panel-head { color: var(--c-blue); }

.ai-state {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--c-text-3);
}
.ai-state .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--c-text-3); }
.ai-state.online .dot { background: var(--c-mint); }
.ai-state.offline .dot { background: var(--c-gold); }
.ai-state.busy .dot { background: var(--c-blue); animation: pulse 1.1s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity: .3 } 50% { opacity: 1 } }

.ai-log {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding-right: 2px;
}

.bubble {
  max-width: 92%;
  padding: 9px 12px;
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
}
.bubble.ai {
  align-self: flex-start;
  background: var(--c-panel-2);
  border: 1px solid var(--c-line);
  border-left: 2px solid var(--c-blue);
}
.bubble.me {
  align-self: flex-end;
  background: var(--c-gold-dim);
  border: 1px solid rgba(247, 189, 57, .35);
  text-align: left;
}
.bubble.sys {
  align-self: stretch;
  background: transparent;
  border: 1px dashed var(--c-line-strong);
  color: var(--c-text-3);
  font-size: var(--fs-xs);
}

.ai-input {
  flex: 0 0 auto;
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--c-line);
}
.ai-input textarea {
  flex: 1 1 auto;
  min-width: 0;
  height: 54px;
  resize: none;
  background: var(--c-panel-2);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--r-sm);
  padding: 7px 9px;
  font-size: var(--fs-sm);
  line-height: 1.5;
}
.ai-input textarea:focus { outline: none; border-color: var(--c-blue); }

.ai-offline-note {
  font-size: var(--fs-xs);
  color: var(--c-gold);
  background: var(--c-gold-dim);
  border: 1px solid rgba(247, 189, 57, .3);
  border-radius: var(--r-sm);
  padding: 6px 9px;
  line-height: 1.5;
}

/* ================= 完成卡（每段结束） ================= */

.overlay {
  position: fixed;
  inset: 0;
  background: rgba(4, 12, 24, .72);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 60;
  backdrop-filter: blur(2px);
}
.completion-card {
  width: 660px;
  max-width: 86vw;
  max-height: 84vh;
  overflow: auto;
  background: var(--c-panel);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-2);
  padding: var(--sp-8);
}
.completion-card .cc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
}
.completion-card .cc-seg { font-size: var(--fs-xl); font-weight: 700; }
.completion-card .cc-sub { font-size: var(--fs-xs); color: var(--c-text-3); }
.completion-card .cc-block { margin-bottom: var(--sp-5); }
.completion-card .cc-label {
  font-size: var(--fs-xs);
  color: var(--c-text-3);
  letter-spacing: 1px;
  margin-bottom: var(--sp-1);
}
.completion-card .cc-text { font-size: var(--fs-md); line-height: 1.65; }
.completion-card .cc-block.evidence .cc-text { color: var(--c-mint); }
.completion-card .cc-block.hook .cc-text { color: var(--c-gold); }
.completion-card .cc-actions { display: flex; justify-content: flex-end; gap: var(--sp-3); margin-top: var(--sp-6); }

/* 双曲线母题小图标：分开 → 靠近 → 重合 */
.motif { width: 54px; height: 26px; flex: 0 0 auto; }

/* ================= 难题卡 ================= */

.problem-card {
  background: var(--c-panel);
  border: 1px solid var(--c-line);
  border-left: 3px solid var(--c-blue);
  border-radius: var(--r-md);
  padding: var(--panel-pad);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-height: 0;
  overflow: auto;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.problem-card:hover { background: var(--c-panel-3); }
.problem-card.on { border-color: var(--c-gold); background: var(--c-panel-3); }
.problem-card .pc-top { display: flex; align-items: baseline; gap: var(--sp-2); }
.problem-card .pc-ord {
  font-size: var(--fs-xs);
  color: var(--c-gold);
  border: 1px solid rgba(247, 189, 57, .4);
  border-radius: var(--r-pill);
  padding: 0 8px;
  white-space: nowrap;
}
.problem-card .pc-title { font-size: var(--fs-lg); font-weight: 600; }
.problem-card .pc-symptom { font-size: var(--fs-sm); color: var(--c-text-2); line-height: 1.55; }
.problem-card .pc-row { font-size: var(--fs-xs); color: var(--c-text-3); line-height: 1.55; }
.problem-card .pc-row b { color: var(--c-text-2); font-weight: 600; }
.problem-card .pc-req { color: var(--c-blue); }
.problem-card .pc-chapter { color: var(--c-mint); }

/* ================= 表格 ================= */

.tbl { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.tbl th, .tbl td {
  text-align: left;
  padding: 7px 10px;
  border-bottom: 1px solid var(--c-line);
  vertical-align: top;
  line-height: 1.5;
}
.tbl th {
  position: sticky;
  top: 0;
  background: var(--c-panel);
  color: var(--c-text-3);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: .5px;
  z-index: 1;
}
.tbl tbody tr:hover { background: var(--c-panel-3); }
.tbl td.target { color: var(--c-blue); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ================= 表单 ================= */

.field { margin-bottom: var(--sp-4); }
.field > label {
  display: block;
  font-size: var(--fs-xs);
  color: var(--c-text-3);
  margin-bottom: var(--sp-1);
}
.field input[type="text"],
.field input[type="number"],
.field textarea,
.field select {
  width: 100%;
  background: var(--c-panel-2);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--r-sm);
  padding: 7px 9px;
  font-size: var(--fs-sm);
}
.field textarea { resize: vertical; min-height: 62px; line-height: 1.6; }
.field input:focus, .field textarea:focus, .field select:focus { outline: none; border-color: var(--c-blue); }
.field .hint { font-size: var(--fs-xs); color: var(--c-text-3); margin-top: 3px; }

.inline-form { display: grid; grid-template-columns: 1fr auto; gap: var(--sp-2); align-items: end; }

/* 第 2 步：技术指标的行编辑器 */
.ind-row {
  border: 1px solid var(--c-line);
  border-radius: var(--r-sm);
  background: var(--c-panel-2);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ind-row input, .ind-row select {
  width: 100%;
  min-width: 0;
  background: var(--c-panel);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--r-sm);
  padding: 4px 7px;
  font-size: var(--fs-xs);
}
.ind-row input:focus, .ind-row select:focus { outline: none; border-color: var(--c-blue); }
.ind-row .row { flex-wrap: nowrap; gap: 6px; }
.ind-row .row .btn { flex: 0 0 auto; }

textarea.req-area {
  width: 100%;
  background: var(--c-panel-2);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--r-sm);
  padding: 8px;
  font-size: var(--fs-sm);
  line-height: 1.6;
  resize: none;
}
textarea.req-area:focus { outline: none; border-color: var(--c-blue); }
textarea.req-area[readonly] { color: var(--c-text-2); border-style: dashed; }

textarea.code-area {
  font-family: "Consolas", "Cascadia Mono", ui-monospace, monospace;
  font-size: var(--fs-xs);
  line-height: 1.6;
  flex: 1 1 auto;
  min-height: 0;
  tab-size: 2;
}

/* 第 12 步的场景页签 */
.btn.on-tab {
  border-color: var(--c-gold);
  color: var(--c-gold);
  background: var(--c-gold-dim);
}

/* 读数条：主图下方的几个关键数值，每页不超过四个 */
.readouts {
  display: flex;
  gap: var(--sp-6);
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4) 0;
  font-size: var(--fs-sm);
}
.readouts .ro-label { display: block; font-size: var(--fs-xs); color: var(--c-text-3); }

/* ================= 原因树（第 4 步） ================= */

.cause-tree { display: flex; flex-direction: column; gap: var(--sp-3); }
.cause-branch {
  border: 1px solid var(--c-line);
  border-left: 3px solid var(--c-slate);
  border-radius: var(--r-sm);
  background: var(--c-panel-2);
  overflow: hidden;
}
.cause-branch.filled { border-left-color: var(--c-mint); }
.cause-branch > .cb-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 9px 12px;
  cursor: pointer;
  font-size: var(--fs-sm);
}
.cause-branch > .cb-head .cb-name { font-weight: 600; }
/* T19（复核 建7）：折叠条上那句常见例子，一行放不下就截断；展开后交给 .cb-examples */
.cause-branch > .cb-head .cb-eg {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--c-text-3); font-size: var(--fs-xs);
}
.cause-branch.open > .cb-head .cb-eg { display: none; }
.cause-branch > .cb-head .cb-hint { color: var(--c-text-3); font-size: var(--fs-xs); margin-left: auto; }
.cause-branch > .cb-head .cb-caret { color: var(--c-text-3); width: 12px; }
.cause-branch > .cb-body { padding: 0 12px 12px; display: none; }
.cause-branch.open > .cb-body { display: block; }
.cause-branch .cb-examples { font-size: var(--fs-xs); color: var(--c-text-3); margin-bottom: var(--sp-2); }
.cause-branch .cb-examples b { color: var(--c-slate); font-weight: 400; }

/* ================= 可视化挂点（第二波集成） ================= */

.viz-slot {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  height: 100%;
  border: 1px dashed var(--c-line-strong);
  border-radius: var(--r-sm);
  background:
    repeating-linear-gradient(45deg, transparent 0 12px, rgba(255,255,255,.018) 12px 24px),
    var(--c-panel-2);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  overflow: hidden;
}
.viz-slot-inner { padding: var(--sp-5); max-width: 80%; }
.viz-slot-name {
  display: inline-block;
  font-family: "Consolas", "Cascadia Mono", ui-monospace, monospace;
  font-size: var(--fs-sm);
  color: var(--c-blue);
  border: 1px solid var(--c-blue);
  border-radius: var(--r-pill);
  padding: 2px 12px;
  margin-bottom: var(--sp-3);
}
.viz-slot-note { font-size: var(--fs-xs); color: var(--c-text-3); line-height: 1.7; }
.viz-slot-note b { color: var(--c-text-2); font-weight: 600; }

/* ================= 小件 ================= */

.tag {
  display: inline-block;
  padding: 1px 8px;
  border-radius: var(--r-pill);
  border: 1px solid var(--c-line-strong);
  font-size: var(--fs-xs);
  color: var(--c-text-3);
  white-space: nowrap;
}
.tag.blue { color: var(--c-blue); border-color: rgba(99,167,255,.45); background: var(--c-blue-dim); }
.tag.gold { color: var(--c-gold); border-color: rgba(247,189,57,.45); background: var(--c-gold-dim); }
.tag.mint { color: var(--c-mint); border-color: rgba(61,220,151,.45); background: var(--c-mint-dim); }
.tag.red  { color: var(--c-red);  border-color: rgba(243,91,97,.45);  background: var(--c-red-dim); }

.kv { display: grid; grid-template-columns: auto 1fr; gap: 4px var(--sp-3); font-size: var(--fs-sm); }
.kv dt { color: var(--c-text-3); font-size: var(--fs-xs); white-space: nowrap; }
.kv dd { margin: 0; }

.stack { display: flex; flex-direction: column; gap: var(--sp-3); min-height: 0; }
.stack.tight { gap: var(--sp-2); }
.row { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.muted { color: var(--c-text-3); font-size: var(--fs-xs); line-height: 1.6; }
.spacer { flex: 1 1 auto; }
.hidden { display: none !important; }

.legend { display: flex; gap: var(--sp-4); font-size: var(--fs-xs); color: var(--c-text-3); }
.legend i { display: inline-block; width: 14px; height: 2px; margin-right: 5px; vertical-align: middle; }
.legend .theory i { background: var(--c-blue); }
.legend .measured i { background: var(--c-gold); }
.legend .gap i { background: var(--c-red); }

.note-strip {
  font-size: var(--fs-xs);
  color: var(--c-text-3);
  border-left: 2px solid var(--c-line-strong);
  padding-left: var(--sp-3);
  line-height: 1.65;
}

.doc-sheet .doc-title {
  font-size: var(--fs-2xl);
  font-weight: 700;
  padding-bottom: var(--sp-3);
  border-bottom: 2px solid var(--c-blue);
  margin-bottom: var(--sp-5);
}
.doc-sheet p { margin-bottom: var(--sp-4); line-height: var(--lh-body); }

/* 展开层入口 */
.more-link {
  background: transparent;
  border: 0;
  color: var(--c-text-3);
  font-size: var(--fs-xs);
  cursor: pointer;
  text-decoration: underline dotted;
  padding: 0;
  white-space: nowrap;
}
.more-link:hover { color: var(--c-blue); }

.more-body {
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--c-text-3);
  line-height: 1.7;
  border-left: 2px solid var(--c-line-strong);
  padding-left: var(--sp-3);
}

/* ================= T6 集成（第二波） =================
   只补集成需要的版面规则，不改 tokens 里的任何颜色取值。
   组件自己的配色由 app/js/viz/_chart.js 注入的 <style id="t2-viz-style"> 负责。 */

/* 挂点装上组件之后：虚线占位框收起来，交给组件自己的卡片 */
.viz-slot.viz-mounted {
  display: block;
  border-color: transparent;
  background: none;
  padding: 0;
  text-align: left;
}
.viz-slot.viz-mounted > .t2v {
  border: 0;
  padding: 8px 10px 6px;
  height: auto;
}
/* 标题长的时候副标题会被挤成竖排，让它自己占一行 */
.viz-slot.viz-mounted .t2v-head { flex-wrap: wrap; align-items: baseline; margin-bottom: 4px; }
.viz-slot.viz-mounted .t2v-title { flex: 1 1 auto; min-width: 0; }
.viz-slot.viz-mounted .t2v-basis { flex: 0 0 auto; }
/* T19 第 3 条：换行那三条（flex / order / min-width）T16 之后组件自己有了
   （app/js/viz/_chart.js：`.t2v-sub{…flex:1 1 100%;order:3;min-width:0}`），删掉，前后逐项比过无差别。
   字号与行距这两条留着，删了会变样：组件写死 12px / 1.45，而页面要跟 --fs-viz 走
   （基准 11px、1920×1080 12.5px）；紧凑档 `.t2v-compact .t2v-sub{line-height:1.4}` 的选择器比
   组件自己那条重，一旦这里不写行距，副标题会从 15.95px 掉到 15.4px，整张卡片跟着挪半像素。 */
.viz-slot.viz-mounted .t2v-sub { font-size: var(--fs-viz); line-height: 1.45; }

/* 装进步骤页之后，图例 / 读数 / 说明 / 控件比演示页再紧一档，
   把省下来的高度让给图本身（演示页 app/dev/viz-gallery.html 不受影响）。 */
.viz-slot.viz-mounted .t2v-legend { font-size: var(--fs-viz); line-height: 1.35; gap: 2px 12px; margin-top: 5px; }
.viz-slot.viz-mounted .t2v-readout { font-size: var(--fs-viz); line-height: 1.4; gap: 2px 14px; margin-top: 5px; }
.viz-slot.viz-mounted .t2v-note { font-size: var(--fs-viz); line-height: 1.5; margin-top: 5px; }
.viz-slot.viz-mounted .t2v-ctrl { margin-top: 6px; padding-top: 6px; gap: 6px 12px; }
.viz-slot.viz-mounted .t2v-btn { padding: 3px 10px; }
/* 质量屋这类固定尺寸的大表：按自然尺寸显示，只让表格本身在框内滚动，
   图例、读数、控件留在框底不动，不把整张表等比缩到看不清。 */
.viz-slot.viz-natural { overflow: hidden; }
.viz-slot.viz-natural .t2v-plot { width: auto; height: auto; max-width: 100%; }
.viz-slot.viz-natural > .t2v { height: 100%; display: flex; flex-direction: column; overflow: hidden; }
.viz-slot.viz-natural > .t2v > div:not([class]) { flex: 1 1 auto; min-height: 0; overflow: auto; }

/* 组件自己把高度写死、实在压不进一屏时，给它一个可滚动的框（第 12 步的四场景对照）；
   这种页面的控制按钮由步骤页自己在左栏给出，学生不必滚到底才能操作 */
.viz-slot.viz-scroll { overflow-y: auto; }

/* 三维器件与电路仿真器占满挂点 */
.viz-slot.viz-mounted > .p3d-root,
.viz-slot.viz-mounted > .circuitjs-embed { height: 100%; }

/* 主视觉容器：挂点所在的那一格要能被压扁，否则组件量不到高度 */
.viz-host {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* 面板标题右侧的小页签条（第 5、6、8、11 步用同一套） */
.viz-tabs { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.viz-tabs .btn { white-space: nowrap; }

/* 段间钩子：进入新一段的第一屏时，把上一段完成卡上的问题接上 */
.seg-hook {
  grid-column: 1 / -1;
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: var(--c-text-2);
  border-left: 2px solid var(--c-gold);
  padding-left: var(--sp-3);
}
.seg-hook b { color: var(--c-gold); font-weight: 600; }

/* 左栏放不下时的紧凑行：内边距与行距各收一档，字号不变 */
.ind-row.compact { padding: 6px 8px; gap: 4px; }
.ind-row.compact input[type="range"] { width: 100%; margin: 0; }

/* 逐项核对清单（第 10 步把第 4 步的判据搬过来用） */
.check-row {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  font-size: var(--fs-xs);
  line-height: 1.55;
  color: var(--c-text-2);
}
.check-row input[type="checkbox"] { margin-top: 3px; accent-color: var(--c-mint); flex: 0 0 auto; }
.check-row.on { color: var(--c-mint); }

/* 六条约束的实时核对（第 8 步左栏） */
.cons-row {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  font-size: var(--fs-xs);
  line-height: 1.45;
}
.cons-row .cons-name { flex: 1 1 auto; color: var(--c-text-2); }
.cons-row .cons-val { font-family: "Consolas", "Cascadia Mono", ui-monospace, monospace; color: var(--c-text-3); }
.cons-row.ok .cons-val { color: var(--c-mint); }
.cons-row.bad .cons-val { color: var(--c-red); }

/* 第 7 步：质量屋占主区，使用说明收进面板脚，只留两块 */
.tpl-matrix.variant-qfd > .page-body {
  grid-template-columns: minmax(0, 74fr) minmax(0, 26fr);
}

/* 第 6 步：参数表单 / 随当前项切换的图 / 助教，仍是三块 */
.tpl-dialog.variant-sweep > .page-body {
  grid-template-columns: minmax(0, 36fr) minmax(0, 38fr) minmax(0, 26fr);
}

/* 顶栏"关于"入口（主控补充，指向 about.html） */
.about-link { color: var(--c-text-3); font-size: var(--fs-xs); text-decoration: none; margin-left: 8px; opacity: .85; }
.about-link:hover { color: var(--c-text); text-decoration: underline; }

/* ================= T13 多分辨率适配 =================
   三档分辨率的分界与理由写在 app/styles/templates.css 的同名小节里。
   这一节只调版面尺寸，不动 tokens 里的任何颜色取值，也不动组件自己的画法。 */

/* 主视觉里的组件卡片：本来是 overflow:hidden，容器矮一点就把最后一行读数直接切掉，
   学生看不到也滚不到。改成放不下时框内可滚，页面本身仍然不滚。
   质量屋那种按自然尺寸显示的（.viz-natural）有自己的内滚动，不动它。 */
.viz-slot.viz-mounted:not(.viz-natural) { overflow-y: auto; }

/* 展开层「了解更多」的正文高度跟着屏高走 */
.page-head > .stack .more-body { max-height: clamp(88px, 12vh, 170px); }

/* ---- 矮屏与基准屏（≤ 899px 高）：组件卡片的外壳再紧一档，高度让给图 ---- */
@media (max-height: 899px) {
  .viz-slot.viz-mounted .t2v-head { margin-bottom: 3px; }
  .viz-slot.viz-mounted .t2v-legend { line-height: 1.3; margin-top: 4px; }
  .viz-slot.viz-mounted .t2v-readout { line-height: 1.35; margin-top: 4px; }
  .viz-slot.viz-mounted .t2v-note { line-height: 1.45; margin-top: 4px; }
  .viz-slot.viz-mounted .t2v-ctrl { margin-top: 5px; padding-top: 5px; }
  /* 表单行距与卡片行距各收 4px：第 6 步的参数表、第 13 步的成果卡本来都差一行才放得下 */
  .field { margin-bottom: var(--sp-3); }
  .problem-card { gap: var(--sp-1); }
  /* T19（复核 建9）：第 6 步五行参数在 1366×768 下正好差 15px，第五项「检波 RC 时间常数」
     的估值框被面板底边切掉；而这一步的判定就是「五项都要有值」。紧凑行再收一档。 */
  .ind-row.compact { padding: 4px 8px; gap: 3px; }
  .ind-row.compact input[type="text"] { padding: 3px 7px; }
}

/* ---- 矮屏（1280×720）：再收一档，并把几处写死的高度压下来 ---- */
@media (max-height: 760px) {
  .viz-slot.viz-mounted > .t2v { padding: 6px 8px 4px; }
  .viz-slot.viz-mounted .t2v-head { margin-bottom: 2px; }
  .viz-slot.viz-mounted .t2v-legend { line-height: 1.25; margin-top: 3px; gap: 1px 10px; }
  .viz-slot.viz-mounted .t2v-readout { line-height: 1.3; margin-top: 3px; gap: 1px 12px; }
  .viz-slot.viz-mounted .t2v-note { line-height: 1.4; margin-top: 3px; }
  .viz-slot.viz-mounted .t2v-ctrl { margin-top: 4px; padding-top: 4px; gap: 4px 10px; }
  .viz-slot.viz-mounted .t2v-btn { padding: 2px 9px; }
  .ai-input textarea { height: 46px; }
  .completion-card { padding: var(--sp-6); }
  .completion-card .cc-block { margin-bottom: var(--sp-4); }
  .field { margin-bottom: var(--sp-3); }
  .field textarea { min-height: 54px; }
  .problem-card { gap: var(--sp-1); padding: var(--sp-4); }
  /* 同上（复核 建9）：720 高这一档要收 37px 才放得下第 6 步的五行 */
  .ind-row.compact { padding: 3px 8px; gap: 2px; }
  .ind-row.compact input[type="text"] { padding: 2px 7px; }
}

/* ---- 大屏（1920×1080）：控件与卡片跟着字号一起放大一档 ---- */
@media (min-width: 1600px) and (min-height: 900px) {
  .btn { height: 38px; padding: 0 20px; }
  .btn-sm { height: 29px; padding: 0 14px; }
  .btn-icon { width: 34px; height: 34px; }
  .pill { padding: 4px 14px; }
  .ai-input textarea { height: 64px; }
  .ai-panel .bubble { max-width: 94%; }
  .completion-card { width: clamp(660px, 42vw, 860px); padding: var(--sp-8) calc(var(--sp-8) * 1.2); }
  .motif { width: 62px; height: 30px; }

  /* T19 第 3 条：这里原来有两条给质量屋做大屏拉伸的外部补丁
     （`.viz-natural > .t2v > div:not([class]) > div{height:100%}` 与 `.viz-natural .t2v-plot{height:100%…}`）。
     T16 把 `qfd-matrix` 的 cellSize 改成「最小格边长、容器放得下就往上长」之后，
     这张表的尺寸由组件自己按容器算（1920×1080 实测 674×669，与补丁在不在场完全一样），
     补丁已经不起作用，删掉；前后逐项比过几何与截图哈希，无差别。 */
}

/* ---- T25（五秒章法二轮复核 必5）：第 10 步左栏「参数回填」 ---- */
/* 三项回填卡 + 判据清单合起来比左栏面板高：1366×768 的 .panel-body 实测 clientH 289 / scrollH 326
   （溢出 37 px），1280×720 是 258 / 308（溢出 50 px），面板底边把最后一块切成半行残字。
   三项回填是这一步的主动作，必须整块露出来，所以内边距、行距与物理说明行的行高各再收一档。
   只作用于第 10 步（step10.js 给面板加了 .step10-backfill），第 2 步的指标行编辑器与
   第 6 步的参数估算表用的同样是 .ind-row.compact，不受影响。 */
.step10-backfill .panel-body > .stack { gap: 5px; }
.step10-backfill .ind-row.compact { padding: 3px 7px; gap: 2px; }
.step10-backfill .ind-row.compact .muted { line-height: 1.38; }
.step10-backfill .panel-foot { padding-top: var(--sp-2); margin-top: var(--sp-2); }

/* 1280×720 这一档还要再收 ——「矮屏」媒体查询里 .ind-row.compact 已是 3px/2px，这里接着往下收一档 */
@media (max-height: 760px) {
  .step10-backfill .panel-body > .stack { gap: 4px; }
  .step10-backfill .ind-row.compact { padding: 2px 7px; gap: 1px; }
  .step10-backfill .ind-row.compact .muted { line-height: 1.32; }
  .step10-backfill .ind-row.compact input[type="text"] { padding: 1px 7px; }
}

/* ---- T27（T25 末尾「看到但没改」第 1 条）：第 12 步左栏「四个难题」 ---- */
/* 四个难题页签 + 这一张怎么看合起来比左栏面板高：1366×768 实测 .panel-body clientH 323 / scrollH 337
   （溢出 14 px），1280×720 是 301 / 337（溢出 36 px），最后那条 note-strip 被面板底边切掉。
   只在放不下的两档（视口高 ≤ 820 px）收一档；1536×864 与 1920×1080 本来就不溢出，一行不动。 */
@media (max-height: 820px) {
  .step12-scenes .stack.tight { gap: 5px; }
  .step12-scenes .btn-sm { height: 24px; }
  .step12-scenes .muted, .step12-scenes .note-strip { line-height: 1.45; }
  .step12-scenes .note-strip { padding-left: var(--sp-2); }
}
/* 1280×720 且切到难题四时，左栏脚多一排「极坐标 / 直角坐标」，面板体再矮 29 px，还差 8 px */
@media (max-height: 760px) {
  .step12-scenes .stack.tight { gap: 4px; }
  .step12-scenes .muted, .step12-scenes .note-strip { line-height: 1.38; }
}
/* ---- T41（薄弱基础试用）：三段只作用于特定屏的新增规则 ---- */

/* 目标 8（建 1）：第 1、12、13 步没有助教面板，学生卡住时无处可问。
   引导语下面加一行灰字，说明这一屏没有助教、看不懂的词去右上角「了解更多」。
   文案在 app/data/steps.json 的 no_ai_note，由 step01 / step12 / step13.js 渲染。
   .page-head 是 1fr auto 的网格，这一行与引导语同占左列，不与右上角的「了解更多」抢位置。 */
.no-ai-note {
  grid-column: 1 / 2;
  margin-top: 2px;
  font-size: var(--fs-xs);
  line-height: 1.35;
  color: var(--c-text-3);
}

/* 必 6（T24 必 5、T25 之后第三轮）：第 10 步左栏「参数回填」。
   判据清单原来在 .panel-foot 里，而 .panel-body 被写成 flex: 1 0 auto 不许收缩，
   内容一高就把面板脚整个顶到面板外（实测五条判据的底边 686 / 713 对面板底边 664），
   且 .panel-body 的 scrollHeight == clientHeight，学生根本滚不到它。
   现在左栏只有一块可滚区：三项回填与判据清单都装在 .step10-scroll 里，
   .panel-body 自己不滚（overflow: hidden），它的溢出恒为 0。 */
.step10-backfill .panel-body {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding-right: 0;
}
.step10-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: var(--sp-1);
}
/* T25 那几条收一档的规则是按 .panel-body > .stack 写的，现在中间多了一层 .step10-scroll，
   原样补一份（那几条留在原处不动，它们已经命中不到，也不会打架）。 */
.step10-backfill .step10-scroll > .stack { gap: 5px; }
@media (max-height: 760px) {
  .step10-backfill .step10-scroll > .stack { gap: 4px; }
}

/* 必 5（T24 必 2、T25 之后第三轮）：第 7 步质量屋，滚到能点下面几行时八条列名全出框。
   .qfd-colbar 是固定在滚动框顶的列名条，由 step07.js 把 SVG 里那八条斜排列名照原样复制上去
   （同一套 x 坐标与缩放比，与下面的列对得齐）；停在默认位置时它整条隐藏，不做重复。
   背景色由 step07.js 按 SVG 自己的底色写进 style，这里只管定位与那条分隔线。 */
.qfd-colbar {
  position: absolute;
  left: 0;
  z-index: 3;
  overflow: hidden;
  border-bottom: 1px solid var(--c-line-strong);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .35);
}
.qfd-colbar-svg { display: block; }


/* ================= T46 焦点可见：键盘走到哪儿要看得出来 ================= */
/* 现状（tools/a11y_check.py 十三步实测）：全站原来一条 :focus-visible 都没有，
   能看见的焦点环全是 Chromium 自带的 outline: auto；而本文件有四处写了 outline: none
   （.ai-input textarea / .field 三件 / .ind-row 两件 / textarea.req-area），
   键盘 Tab 走到这些输入框时只有 1px 边框变蓝，1366x768 上几乎看不出来
   —— 第 2 步 10 个、第 6 步 11 个、第 3 步 5 个、第 4 步 1 个元素就是这么丢的。
   那四条 outline: none 保留（它们去掉的是浏览器默认那圈难看的直角实线），
   下面逐条给出配套的可见描边。

   颜色只用已有令牌，一个新颜色都不加：
     --c-blue = 深色主题 #63a7ff / 浅色主题 #1f6fd0。
     深色下压在面板底（#12294a / #0b1f3a / #081426）上 5.7 - 6.7:1；
     浅色下压在面板底（#eef2f7 / #ffffff）上 4.2 - 4.6:1。
     两个主题都远高于焦点指示器要求的 3:1（WCAG 2.2 SC 1.4.11）。
   不拿 --c-gold / --c-mint 画环：那两个在本站是语义色（金 = 学生产物、青 = 已核验），
   拿来画焦点环会和「颜色即角色」打架。

   用 :focus-visible 而不是 :focus：鼠标点一下不画环，键盘走到才画。

   为什么分「外环」与「内环」两套：outline 会被祖先的 overflow: hidden / auto 剪掉。
   进度胶囊（.progress-row 是 overflow: hidden，胶囊正好填满这一行）、分段开关
   （.seg-toggle 自己 overflow: hidden）、原因树分支（.cause-branch）、可视化挂点
   （.viz-slot）这四处把环画在元素外面会被剪掉一部分甚至整圈，还有 textarea.req-area
   —— 第 2、11 步它正好填满 .panel-body 的内容盒，画外面四边全被剪掉（实测）——
   所以它们改画在元素内侧
   （outline-offset 取负）。其余一律画在元素外侧 2px：画在外面压的是面板底色，
   对比度最稳 —— 尤其主按钮自己就是蓝底，环压在上面等于没画。
   outline 不进 scrollable overflow，不会给面板引出新的滚动条（已由两种分辨率的
   page_check 复验：十三步横纵滚动量仍然是 0）。 */

/* 兜底一条（特指度 0,1,0，被下面每一条压住）：Chromium 会让「自己能滚」的容器也吃 Tab，
   这种容器没有 tabindex，下面按标签名点名的那条选择器够不着它 —— 实测有两处：
   第 7 步质量屋里那个 div:not([class]) 滚动框、第 13 步 .report-wall 里的三张 .problem-card。
   它们原来只有 Chromium 自带的 outline: auto（浅色主题下是近黑色的 #101010，
   压在深色面板上只有 1.31:1，等于看不见）。这类框大多正好填满父容器，
   环画到外面会被父容器剪掉，所以兜底这条画在内侧。 */
:focus-visible {
  outline: 2px solid var(--c-blue);
  outline-offset: -2px;
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
iframe:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--c-blue);
  outline-offset: 2px;
}

/* 逐条压住本文件里已有的四处 outline: none —— 它们写的是 :focus，特指度 (0,2,1)，
   比上面那条 (0,1,1) 高，选择器不一一对上就压不住。
   这里压住的只是 outline 一个属性，它们原来的 border-color 变蓝照旧。 */
.ai-input textarea:focus-visible,
.field input:focus-visible,
.field textarea:focus-visible,
.field select:focus-visible,
.ind-row input:focus-visible,
.ind-row select:focus-visible,
textarea.req-area:focus-visible {
  outline: 2px solid var(--c-blue);
  outline-offset: 2px;
}

/* 内环：这几处的祖先在剪切，环画到元素外面就看不全。
   只改 outline-offset，环的颜色与粗细跟上面同一套。 */
.progress-row .pill:focus-visible,
.seg-toggle button:focus-visible,
textarea.req-area:focus-visible,
.cause-branch input:focus-visible,
.cause-branch textarea:focus-visible,
.cause-branch select:focus-visible,
.cause-branch button:focus-visible,
.viz-slot button:focus-visible,
.viz-slot input:focus-visible,
.viz-slot select:focus-visible,
.viz-slot textarea:focus-visible,
.viz-slot [tabindex]:focus-visible {
  outline-offset: -2px;
}
