/* =============================================================================
 * app.css — 版式与组件
 *
 * 形态纪律：0 圆角、0 阴影、0 渐变；分隔靠 1px 细线与定宽列，不靠卡片和斑马纹。
 * 唯一的色彩来自绘图仪的墨，只出现在数据上。
 *
 * 功能文字不小于 11px：按钮、标签、表头、表格单元格都遵守这条下限。
 * ========================================================================== */

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  padding: 10px;
  font-family: var(--cjk);
  font-size: var(--fs-base);
  line-height: 1.6;
  color: var(--ink);
  background: var(--desk);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

/* --------------------------------------------------------------- 纸张 */

.sheet {
  position: relative;
  display: flex;
  flex-direction: column;
  height: calc(100vh - 20px);
  min-height: 560px;
  padding: 0 22px;
  background: var(--paper);
  border: 1px solid var(--edge);
  overflow: hidden;
}

/* 拖纸孔与折痕：不是装饰，它标出"纸"的实际边界，并给内容让出安全边距 */
.sheet::before,
.sheet::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  width: 22px;
  background-image: radial-gradient(circle at 50% 50%, var(--band-edge) 0 3.2px, transparent 3.4px);
  background-size: 22px 20px;
  background-repeat: repeat-y;
  background-position: 0 7px;
  pointer-events: none;
}
.sheet::before { left: 0; border-right: 1px dashed var(--rule-soft); }
.sheet::after { right: 0; border-left: 1px dashed var(--rule-soft); }

/* ------------------------------------------------------------- 打印头 */

.printhead {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 8px 6px;
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: var(--fs-head);
  letter-spacing: .08em;
  white-space: nowrap;
  overflow: hidden;
}
.ph-title { font-weight: 700; letter-spacing: .13em; flex: none; }
.ph-meta { color: var(--ink-soft); flex: 1; overflow: hidden; text-overflow: ellipsis; }
.ph-actions { display: flex; gap: 4px; flex: none; }

/* ---------------------------------------------------------------- 台面 */

.bench {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 286px minmax(0, 1fr) 364px;
}

.rail {
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 10px 14px 18px;
}
.rail-data { border-right: 1px solid var(--rule); }
.rail-inspect { border-left: 1px solid var(--rule); padding: 0; display: flex; flex-direction: column; }

.railhead {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  font-family: var(--mono);
  font-size: var(--fs-label);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-faint);
  /* 标题上方留白多于下方，视线才会把它归给下面的内容 */
  padding: 17px 0 5px;
  margin-bottom: 7px;
  border-bottom: 1px solid var(--rule);
}
.railhead:first-child { padding-top: 2px; }

/* --------------------------------------------------------------- 控件 */

.btn {
  font-family: var(--mono);
  font-size: var(--fs-label);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--btn-bg);
  border: 1px solid var(--rule);
  border-radius: 0;
  padding: 6px 10px;
  cursor: pointer;
}
.btn:hover { background: var(--btn-bg-hover); }
.btn:focus-visible { outline: 2px solid var(--pen3); outline-offset: 1px; }
.btn.tiny { padding: 5px 9px; font-size: var(--fs-label); }
.btn.bare { border-color: transparent; color: var(--ink-soft); }
.btn.bare:hover { border-color: var(--rule); }
.btn.primary { background: var(--btn-primary-bg); color: var(--btn-primary-fg); border-color: var(--btn-primary-bg); }
.btn.danger { color: var(--danger); border-color: var(--rule); }
.btn.danger:hover { background: var(--btn-bg-hover); }
.btn:disabled { opacity: .42; cursor: not-allowed; }
.btn.tgl.on { background: var(--btn-primary-bg); color: var(--btn-primary-fg); border-color: var(--btn-primary-bg); }

.row-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }

input[type="text"], input[type="number"], select, textarea {
  font-family: var(--mono);
  font-size: var(--fs-data);
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 0;
  padding: 4px 6px;
  width: 100%;
}
textarea { line-height: 1.6; resize: vertical; }
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--pen3); outline-offset: -1px;
}
select { cursor: pointer; }

.fieldgrid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 8px;
  margin-bottom: 8px;
}
.fld { display: flex; flex-direction: column; gap: 3px; font-family: var(--mono); font-size: var(--fs-label); letter-spacing: .06em; color: var(--ink-soft); }
.fld.wide { margin-top: 4px; }
.fld select, .fld input { width: 100%; }

.hint { font-family: var(--mono); font-size: calc(11px + var(--step)); color: var(--ink-faint); line-height: 1.6; margin: 8px 0 0; }
.hint code, code { font-family: var(--mono); background: var(--band); padding: 0 3px; }

kbd {
  font-family: var(--mono); font-size: .92em;
  border: 1px solid var(--rule); border-bottom-width: 2px;
  padding: 0 4px; background: var(--band);
}

/* --------------------------------------------------------------- 表格 */

table.listing {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: var(--fs-data);
  font-variant-numeric: tabular-nums;
}
table.listing th {
  font-size: var(--fs-label);
  letter-spacing: .11em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--ink-faint);
  text-align: right;
  padding: 0 0 5px;
  border-bottom: 1px solid var(--rule);
  white-space: nowrap;
}
table.listing th:first-child { text-align: left; }
table.listing td {
  padding: 2px 0;
  text-align: right;
  border-bottom: 1px solid var(--rule-soft);
  white-space: nowrap;
}
table.listing td:first-child { text-align: left; color: var(--ink-faint); }
table.listing tr.on td { background: var(--band); font-weight: 700; }

/* 数据点表格：可编辑输入格 */
#pointTable th.c-i, #pointTable td.c-i { width: 26px; }
#pointTable th.c-a, #pointTable td.c-a { width: 24px; }
#pointTable td { padding: 0; border-bottom: 1px solid var(--rule-soft); }
#pointTable td.c-i { color: var(--ink-faint); text-align: center; font-size: calc(11px + var(--step)); }
#pointTable input {
  border: 0; padding: 3px 2px; text-align: right; background: transparent; width: 100%;
}
#pointTable input:hover { background: var(--band); }
#pointTable input:focus-visible { outline: 2px solid var(--pen3); outline-offset: -2px; background: var(--band); }
#pointTable tr.on td { background: var(--band); }
#pointTable tr.bad input { color: var(--danger); }
#pointTable tr.bad td.c-i::after { content: "!"; color: var(--danger); font-weight: 700; }
#pointTable .del {
  border: 0; background: transparent; color: var(--ink-faint); cursor: pointer;
  padding: 0; margin: 0 auto; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  width: 100%; min-height: 22px;
}
#pointTable .del svg { display: block; }
#pointTable .del:hover { color: var(--danger); }
#pointTable .del:focus-visible { outline: 2px solid var(--pen3); }

.tablewrap { overflow-x: auto; }

/* 导出代码区：左边一列行号，右边是可选中的 textarea。
   行号不做进文本里——那样用户一复制就把行号一起带走了。 */
.codewrap {
  display: flex;
  border: 1px solid var(--rule);
  background: var(--paper);
  min-height: 0;
}
.codewrap .gutter {
  flex: none;
  width: 38px;
  padding: 10px 6px 10px 0;
  text-align: right;
  font-family: var(--mono);
  font-size: calc(11px + var(--step));
  line-height: 1.62;
  color: var(--ink-faint);
  background: var(--band);
  border-right: 1px solid var(--rule);
  white-space: pre;
  overflow: hidden;
  user-select: none;
}
.codewrap textarea {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: transparent;
  resize: none;
  /* 代码不折行：折了行，左边那列行号就对不上了。
     长行靠横向滚动，和任何代码编辑器一样。 */
  white-space: pre;
  overflow-x: auto;
  overflow-y: auto;
}

/*
 * 诊断表必须允许换行：英文标签（"weight spread"、"evaluation path"）
 * 比中文长得多，配上 table.listing td 的 nowrap 会被整段裁掉——
 * 这个问题在中文界面下几乎看不见，只有切到英文才暴露。
 *
 * ⚠ 这里有个坑：结论行只有一个 colspan=2 的单元格，它**同时**是
 * :first-child 和 :last-child。而下面那条 :first-child 规则的权重比
 * 通用的 td 规则高，会把 nowrap + width:42% 又盖回去，把整句话压成一行裁掉。
 * 所以第一列规则必须显式排除 .verdict 行。
 */
table.listing.diag { width: 100%; table-layout: fixed; }
table.listing.diag td { white-space: normal; overflow-wrap: break-word; vertical-align: top; }
table.listing.diag tr:not(.verdict) td:first-child { white-space: nowrap; width: 42%; padding-right: 10px; }
table.listing.diag tr:not(.verdict) td:last-child { text-align: right; }
table.listing.diag tr.verdict td { text-align: left; white-space: normal; width: auto; }
/*
 * 选择器必须带上 table.listing：单写 .ddtable td 的权重低于 table.listing td，
 * 会被 padding-right:0 覆盖掉，相邻数字就会粘成 "2.439024-9.756096"。
 * 这里踩过一次，凡是对表格单元格的局部覆盖都要带完整前缀。
 */
table.listing.ddtable { width: auto; min-width: 100%; }
table.listing.ddtable td, table.listing.ddtable th { padding-right: 15px; }
table.listing.ddtable td:first-child { color: var(--ink-soft); }
table.listing.coefftable td:first-child { width: 38px; }
table.listing.cmp th, table.listing.cmp td { text-align: left; padding-right: 12px; white-space: normal; }
table.listing.cmp td { font-size: calc(11.5px + var(--step)); line-height: 1.55; color: var(--ink-soft); }
table.listing.cmp td:first-child { color: var(--ink); }
table.listing.keys td:first-child { width: 42%; color: var(--ink); }
table.listing.keys td { border-bottom: 1px solid var(--rule-soft); white-space: normal; text-align: left; }

/* 表格被横向裁切时的常驻提示：滚动条只在滚动时可见，等于没有信号 */
.scrollhint {
  font-family: var(--mono); font-size: calc(11px + var(--step));
  color: var(--ink-soft); background: var(--band);
  border: 1px solid var(--rule); padding: 5px 9px; margin-top: 7px;
}
.scrollhint[hidden] { display: none; }

/* 结论是一整句话，挤在窄列里会断气；跨满整行才读得通 */
table.listing tr.verdict td {
  text-align: left; white-space: normal;
  padding: 7px 0 2px; border-top: 1px solid var(--rule);
}
table.listing tr.verdict .vk {
  color: var(--ink-faint); margin-right: 9px;
  font-size: calc(11px + var(--step)); letter-spacing: .12em;
}

/* --------------------------------------------------------------- 消息 */

/* 不用彩色左边条：那是「AI 味」最典型的标记之一。
   改成整圈 1px 边框 + 行首的机器标签，也更像行式打印机会输出的东西。 */
.msgbox { margin-top: 10px; }
.msg {
  font-family: var(--mono);
  font-size: calc(11.5px + var(--step));
  line-height: 1.55;
  padding: 7px 9px;
  margin-bottom: 6px;
  border: 1px solid var(--rule);
  background: var(--band);
  color: var(--ink);
}
.msg .tag { font-weight: 700; letter-spacing: .1em; margin-right: 9px; color: var(--ink-soft); }
.msg.err { border-color: var(--danger); }
.msg.err .tag { color: var(--danger); }
.msg.warn { border-color: var(--warn); }
.msg.warn .tag { color: var(--warn); }
.msg.ok { border-color: var(--ok); }
.msg.ok .tag { color: var(--ok); }

/* --------------------------------------------------------------- 预设 */

.presets { display: flex; flex-direction: column; gap: 0; }
.preset {
  display: flex; flex-direction: column; gap: 1px;
  text-align: left; border: 0; border-bottom: 1px solid var(--rule-soft);
  background: transparent; color: var(--ink); cursor: pointer;
  padding: 7px 2px; font-family: var(--cjk); font-size: calc(12.5px + var(--step));
}
.preset:hover { background: var(--band); }
.preset:focus-visible { outline: 2px solid var(--pen3); outline-offset: -2px; }
.preset small { font-family: var(--mono); font-size: calc(11px + var(--step)); color: var(--ink-faint); letter-spacing: .02em; }

/* ---------------------------------------------------------------- 图版 */

.stage { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.stagebar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 12px; border-bottom: 1px solid var(--rule-soft);
  flex-wrap: wrap;
}
.platetag {
  font-family: var(--mono); font-size: var(--fs-label);
  letter-spacing: .13em; text-transform: uppercase; color: var(--ink-faint);
}
.toggles { display: flex; gap: 3px; flex-wrap: wrap; }

.canvaswrap { position: relative; flex: 1; min-height: 200px; background: var(--paper); }
.canvaswrap.small { flex: none; height: 208px; border: 1px solid var(--rule); }
.canvaswrap canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }

/* ---------------------------------------------------------- 函数解析式 */
/* 图版正下方的常驻公式条。它是这个工具的头号产出，不该藏在标签页里。 */
.plate {
  display: flex; align-items: baseline; gap: 10px;
  padding: 9px 12px; border-top: 1px solid var(--ink);
  background: var(--band);
  font-family: var(--mono); font-size: calc(13.5px + var(--step));
  max-height: 96px; overflow-y: auto;
}
.plate-k { flex: none; color: var(--ink-soft); letter-spacing: .08em; }
.plate-body { flex: 1; min-width: 0; line-height: 1.85; overflow-wrap: break-word; }
.plate-body sup { font-size: .72em; vertical-align: super; line-height: 0; }
.plate-tag {
  flex: none; color: var(--ink-faint);
  font-size: calc(11px + var(--step)); letter-spacing: .1em; text-transform: uppercase;
  white-space: nowrap;
}
.plate:hover .plate-k { color: var(--ink); }
.plate:focus-visible { outline: 2px solid var(--pen3); outline-offset: -2px; }
.plate.building .plate-k { color: var(--pen3); font-weight: 700; }
.plate .term { white-space: nowrap; }
.plate .term.more { color: var(--pen3); font-weight: 700; }

.pens {
  display: flex; flex-wrap: wrap; gap: 2px 16px;
  padding: 7px 12px; border-top: 1px solid var(--rule);
  font-family: var(--mono); font-size: calc(11.5px + var(--step));
  /* 点数多时笔架会占满中栏，把图版挤扁；封顶两行多一点，
     露出第三行的一角，滚动这件事才看得出来。 */
  max-height: 78px; overflow-y: auto; overscroll-behavior: contain;
}
.pen { display: flex; align-items: center; gap: 6px; cursor: pointer; border: 0; background: transparent; color: var(--ink); padding: 2px 4px; }
.pen:hover { background: var(--band); }
.pen:focus-visible { outline: 2px solid var(--pen3); }
.pen .idx { color: var(--ink-faint); font-size: calc(11px + var(--step)); letter-spacing: .04em; }
.pen .tip { width: 26px; height: 2px; flex: none; }
.pen.off { opacity: .42; }
.pen.off .nm { text-decoration: line-through; }
/* 逐项累加时还没轮到的那几支笔：暗下去，但不划掉（它不是被关掉了） */
.pen.pending { opacity: .28; }

.buildbar {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 12px; border-top: 1px solid var(--rule);
}
.buildbar .spacer { flex: 1; }
.buildlabel { font-family: var(--mono); font-size: calc(11.5px + var(--step)); color: var(--ink-soft); white-space: nowrap; }
input[type="range"] {
  -webkit-appearance: none; appearance: none;
  flex: 1; min-width: 80px; height: 18px; background: transparent; cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track { height: 2px; background: var(--rule); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 11px; height: 15px; background: var(--ink); border: 0; margin-top: -6.5px;
}
input[type="range"]::-moz-range-track { height: 2px; background: var(--rule); }
input[type="range"]::-moz-range-thumb { width: 11px; height: 15px; background: var(--ink); border: 0; border-radius: 0; }
input[type="range"]:focus-visible { outline: 2px solid var(--pen3); outline-offset: 2px; }

/* ------------------------------------------------------- 单位分解探针 */

.unitypanel { border-top: 1px solid var(--rule); padding: 0 12px 12px; }
.unitypanel .railhead { padding-top: 9px; margin-bottom: 6px; }
.unity { display: flex; align-items: stretch; gap: 1px; height: 88px; }
.ubar { position: relative; flex: 1; min-width: 0; border-left: 1px solid var(--rule-soft); }
.ubar:first-child { border-left: 0; }
.ubar .zero { position: absolute; left: 0; right: 0; top: 50%; border-top: 1px solid var(--rule); }
.ubar .fill { position: absolute; left: 14%; right: 14%; }
.ubar .fill.pos { bottom: 50%; background: var(--pen3); }
.ubar .fill.neg { top: 50%; background: var(--pen2); }
.ubar.hi .fill.pos { background: var(--ink); }
.ubar.hi .fill.neg { background: var(--ink); }
.ubar .lb {
  position: absolute; left: 0; right: 0; bottom: -2px;
  font-family: var(--mono); font-size: calc(11px + var(--step));
  text-align: center; color: var(--ink-soft); letter-spacing: .02em;
}
.unitylegend {
  font-family: var(--mono); font-size: calc(11.5px + var(--step)); color: var(--ink-soft);
  display: flex; gap: 16px; margin-top: 6px; flex-wrap: wrap;
}
.unitylegend b { color: var(--ink); font-weight: 700; }
.swatch { display: inline-block; width: 16px; height: 0; border-top: 2px solid; vertical-align: middle; margin-right: 4px; }

/* ---------------------------------------------------------- 右栏面板 */

.tabs { display: flex; border-bottom: 1px solid var(--rule); flex: none; }
.tab {
  flex: 1; border: 0; border-right: 1px solid var(--rule-soft);
  background: transparent; color: var(--ink-soft);
  font-family: var(--mono); font-size: var(--fs-label);
  letter-spacing: .08em; padding: 10px 4px; cursor: pointer;
}
.tab:last-child { border-right: 0; }
.tab:hover { background: var(--band); }
.tab.on { background: var(--ink); color: var(--paper); font-weight: 700; }
.tab:focus-visible { outline: 2px solid var(--pen3); outline-offset: -2px; }

.panels { flex: 1; min-height: 0; overflow-y: auto; }
.panel { display: none; padding: 0 14px 22px; }
.panel.on { display: block; }

.derive { font-family: var(--mono); font-size: calc(12px + var(--step)); line-height: 1.85; }
.derive .step { border-bottom: 1px solid var(--rule-soft); padding: 10px 0; }
.derive .step:last-child { border-bottom: 0; }
.derive .sn {
  color: var(--ink-faint); font-size: calc(11px + var(--step));
  letter-spacing: .12em; text-transform: uppercase; display: block; margin-bottom: 4px;
}
/* 公式容器允许在运算符处折行：一长串展开式在 364px 的右栏里
   靠横向滚动是看不到结尾的，折行才读得完整 */
.derive .fx {
  font-size: calc(12.5px + var(--step));
  padding: 2px 0;
  white-space: normal;
  overflow-wrap: break-word;
  word-break: normal;
}
.derive .note { font-family: var(--cjk); font-size: calc(12px + var(--step)); color: var(--ink-soft); line-height: 1.7; white-space: normal; margin-top: 4px; }
.derive .hl { color: var(--pen3); }

/* 分式排版：自绘，不引入 KaTeX/MathJax，零依赖。
 *
 * 不要用 inline-flex + vertical-align: -.55em —— 那个写法把分数线的位置
 * 押在「inline-flex 容器的基线 = 第一个 flex 项的基线」这条合成规则上，
 * 而各浏览器对没有基线对齐项的 flex 容器处理并不一致（Firefox 尤甚），
 * 一旦合成规则不同，整条分数线就会相对 x 漂移。
 *
 * 改用 inline-block + vertical-align: middle：盒子的垂直中点对齐到
 * 父级 x-height 的中点，几何完全由盒子决定，与内容宽度和浏览器规则都无关。
 * 顺带还更对：x-height 中点约在基线上方 0.25em，正是分数线该在的数学轴位置。
 * 子元素用 display:block，两个块同为收缩宽度，分数线自动横跨较宽的那一边。 */
.frac {
  display: inline-block;
  vertical-align: middle;
  text-align: center;
  margin: 0 3px;
  font-size: .94em;
  line-height: 1.25;
}
.frac > .n { display: block; border-bottom: 1px solid currentColor; padding: 0 4px 1px; }
.frac > .d { display: block; padding: 1px 4px 0; }
.derive sub { font-size: .72em; }

/* 展开式折叠项 */
.litem { border-bottom: 1px solid var(--rule-soft); padding: 2px 0 5px; }
.litem:last-child { border-bottom: 0; }
.litem > summary {
  cursor: pointer; list-style: none; padding: 4px 2px;
  font-family: var(--mono); font-size: calc(12px + var(--step)); color: var(--ink);
}
.litem > summary::-webkit-details-marker { display: none; }
.litem > summary::before { content: "+ "; color: var(--ink-faint); font-weight: 700; }
.litem[open] > summary::before { content: "\2212 "; }
.litem > summary:hover { background: var(--band); }
.litem > summary:focus-visible { outline: 2px solid var(--pen3); outline-offset: -2px; }

.note-line { font-family: var(--mono); font-size: calc(11.5px + var(--step)); line-height: 1.6; color: var(--ink-soft); padding: 6px 0 2px; }
.note-line.err { color: var(--danger); }

.queryrow { display: flex; gap: 6px; align-items: center; }
.queryrow input { flex: 1; }
.queryrow .btn { flex: none; }

.chips { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 8px; }
.chip {
  font-family: var(--mono); font-size: calc(11px + var(--step)); letter-spacing: .08em; text-transform: uppercase;
  border: 1px solid var(--rule); background: transparent; color: var(--ink-soft);
  padding: 4px 9px; cursor: pointer;
}
.chip:hover { background: var(--btn-bg-hover); }
.chip.on { background: var(--ink); color: var(--paper); border-color: var(--ink); font-weight: 700; }
.chip:focus-visible { outline: 2px solid var(--pen3); }

#exportArea { font-size: calc(11.5px + var(--step)); }

/* -------------------------------------------------------------- 状态行 */

.status {
  display: flex; flex-wrap: wrap; align-items: stretch;
  border-top: 1px solid var(--ink);
  background: var(--band);
  font-family: var(--mono);
  font-size: var(--fs-label);
  letter-spacing: .04em;
  flex: none;
}
.status span.cell { padding: 5px 12px; border-right: 1px solid var(--band-edge); white-space: nowrap; }
.status .k { color: var(--ink-soft); }
.status b { font-weight: 700; }

/* --------------------------------------------------------------- 模态 */

.modal {
  position: fixed; inset: 0; z-index: 40;
  background: var(--desk);
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
}
.modal[hidden] { display: none; }
.modalsheet {
  width: 100%; max-width: 1360px;
  /* 必须有确定高度：只给 max-height 的话，内部的 flex 子项没有高度可分配，
     画布容器会塌成 0 —— 这里踩过一次。 */
  height: calc(100vh - 32px);
  max-height: calc(100vh - 32px);
  display: flex; flex-direction: column;
  background: var(--paper); border: 1px solid var(--edge);
  overflow: hidden;
}
.modalsheet.narrow { max-width: 720px; height: auto; max-height: calc(100vh - 32px); }
.pair { display: grid; grid-template-columns: 1fr 1fr; flex: 1; min-height: 0; }
.paircell { display: flex; flex-direction: column; min-width: 0; border-right: 1px solid var(--rule); }
.paircell:last-child { border-right: 0; }
.paircell .platetag { padding: 9px 12px; border-bottom: 1px solid var(--rule-soft); flex: none; }
.paircell .canvaswrap { flex: 1; min-height: 220px; }
.helpbody { padding: 4px 22px 22px; overflow-y: auto; }
.helpbody h3 {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: .13em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 400; margin: 20px 0 6px;
}
.helpbody p { margin: 0 0 8px; color: var(--ink-soft); }
.helpbody b { color: var(--ink); }

/* --------------------------------------------------------- 滚动条 */

.rail::-webkit-scrollbar, .panels::-webkit-scrollbar, .tablewrap::-webkit-scrollbar, .helpbody::-webkit-scrollbar { width: 10px; height: 10px; }
.rail::-webkit-scrollbar-track, .panels::-webkit-scrollbar-track, .tablewrap::-webkit-scrollbar-track, .helpbody::-webkit-scrollbar-track { background: var(--paper); }
.rail::-webkit-scrollbar-thumb, .panels::-webkit-scrollbar-thumb, .tablewrap::-webkit-scrollbar-thumb, .helpbody::-webkit-scrollbar-thumb {
  background: var(--rule); border: 3px solid var(--paper);
}

/* ----------------------------------------------------------- 响应式 */

@media (max-width: 1420px) {
  .bench { grid-template-columns: 254px minmax(0, 1fr) 330px; }
}
@media (max-width: 1200px) {
  .bench { grid-template-columns: 228px minmax(0, 1fr) 296px; }
  .rail { padding-left: 10px; padding-right: 10px; }
}

/* 窄屏：单栏堆叠，图版优先，功能一个不少 */
@media (max-width: 980px) {
  body { overflow: auto; padding: 0; }
  .sheet { height: auto; min-height: 100vh; padding: 0 14px; border: 0; }
  .sheet::before, .sheet::after { display: none; }
  .bench { display: flex; flex-direction: column; }
  .stage { order: 1; }
  /* 用 clamp 而不是裸 vh：长页面上 62vh 会把图版拉到上千像素，曲线被拉变形 */
  .canvaswrap { height: clamp(300px, 52vh, 520px); flex: none; min-height: 300px; }
  .rail-data { order: 2; border-right: 0; border-top: 1px solid var(--rule); overflow: visible; }
  .rail-inspect { order: 3; border-left: 0; border-top: 1px solid var(--rule); overflow: visible; }
  .panels { overflow: visible; }
  .pair { grid-template-columns: 1fr; }
  .paircell { border-right: 0; border-bottom: 1px solid var(--rule); }
  .paircell .canvaswrap { height: clamp(240px, 40vh, 420px); }
  .printhead { flex-wrap: wrap; white-space: normal; row-gap: 4px; }
  .ph-meta { flex-basis: 100%; order: 3; }
  /* 按钮文字不换行，窄屏下 buildbar 允许折行，否则会挤成竖排 */
  .btn { white-space: nowrap; }
  .buildbar { flex-wrap: wrap; row-gap: 6px; }
  .buildbar .spacer { display: none; }
  .buildbar input[type="range"] { flex-basis: 100%; order: 3; }
  .pens { max-height: none; }
  .status span.cell { padding: 5px 9px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ------------------------------------------------------------- 打印 */

/* =============================================================================
 * 中文排版适配
 *
 * 界面改成中文之后，为西文大写标签准备的那套排版必须跟着改：
 *   · text-transform: uppercase 对中文完全无效，只会让同一行的数字和
 *     英文缩写显得突兀 —— 全部去掉。
 *   · 宽字距（.13em）是大写西文的需要；中文用宽字距会把词拆散 —— 收到 .04em。
 *   · 数字继续走等宽 + tabular-nums，汉字回落到中文黑体，但表格数值列必须对齐。
 * 这些规则统一放在文件末尾，靠源码顺序覆盖前面的西文版本。
 * ========================================================================== */

.ph-title, .railhead, .btn, .tab, .platetag, .chip,
.plate-tag, .derive .sn, .helpbody h3, table.listing th {
  text-transform: none;
  letter-spacing: .04em;
}
.ph-title { letter-spacing: .06em; }
.derive .sn { letter-spacing: .05em; }

/* ---------------------------------------------------------- 左栏分块 */

.rail-intro {
  font-family: var(--cjk);
  font-size: calc(12px + var(--step));
  line-height: 1.7;
  color: var(--ink-soft);
  padding: 2px 0 12px;
  border-bottom: 1px solid var(--rule);
}

.block { padding-bottom: 4px; }
.block + .block { margin-top: 10px; }

.blockdesc {
  font-family: var(--cjk);
  font-size: calc(11.5px + var(--step));
  line-height: 1.65;
  color: var(--ink-faint);
  margin: 0 0 8px;
}

/* 输入语法说明：用等宽体，因为里面全是 1/3、√2、(1+√5)/2 这类要照着敲的字面量 */
.blockdesc.syntax {
  font-family: var(--mono);
  font-size: calc(11px + var(--step));
  color: var(--ink-soft);
  line-height: 1.7;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--rule-soft);
}

.panelsub {
  font-family: var(--cjk);
  font-size: calc(12px + var(--step));
  line-height: 1.65;
  color: var(--ink-soft);
  padding: 12px 0 10px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--rule-soft);
}

.range-row { display: flex; align-items: center; gap: 6px; }
.range-dash { color: var(--ink-faint); font-family: var(--mono); flex: none; }

/* ------------------------------------------------------------- 折叠块 */

.fold { border-bottom: 1px solid var(--rule-soft); }
.fold > summary {
  cursor: pointer;
  list-style: none;
  padding: 9px 2px;
  font-family: var(--mono);
  font-size: var(--fs-label);
  letter-spacing: .04em;
  color: var(--ink-soft);
  display: flex;
  /* 必须是 flex-start：space-between 会把 ::before 的 +/− 和文字推到两端，
     看起来像两个不相干的东西。计数靠 margin-left:auto 单独推到右边。 */
  justify-content: flex-start;
  align-items: baseline;
  gap: 0;
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::before { content: "+"; color: var(--ink-faint); font-weight: 700; margin-right: 7px; flex: none; }
.fold[open] > summary::before { content: "\2212"; }
.fold > summary:hover { background: var(--band); }
.fold > summary:focus-visible { outline: 2px solid var(--pen3); outline-offset: -2px; }
.foldbody { padding: 4px 2px 14px; }
.foldcount { font-family: var(--mono); font-size: calc(11px + var(--step)); color: var(--ink-faint); margin-left: auto; flex: none; }

/* 图版工具条里的「显示」：横排按钮，展开时浮在画布之上 */
.fold.inline { position: relative; border-bottom: 0; }
.fold.inline > summary {
  padding: 5px 9px; border: 1px solid var(--rule);
  display: inline-flex; align-items: center;
}
.fold.inline > summary::before { content: ""; margin: 0; }
.fold.inline > summary::after { content: " ▾"; color: var(--ink-faint); }
.fold.inline[open] > summary::after { content: " ▴"; }
.fold.inline > summary:hover { background: var(--btn-bg-hover); }
.fold.inline .foldbody {
  position: absolute; left: 0; top: calc(100% + 5px); z-index: 20;
  background: var(--paper); border: 1px solid var(--rule);
  padding: 7px; display: flex; flex-direction: column; gap: 5px;
  min-width: 120px;
}

/* 图版开关处于关闭态时按钮本身就要看得出来 */
.tgl[aria-pressed="false"] { color: var(--ink-faint); }

/* ------------------------------------------------------- 笔架的行内说明 */

.penscap {
  font-family: var(--cjk);
  font-size: calc(11px + var(--step));
  color: var(--ink-faint);
  align-self: center;
  padding-right: 8px;
}

/* ------------------------------------------------------------- 分步引导 */
/* 世界的语法里没有阴影和压暗层，所以引导用「校样上圈出一块区域」的做法：
   双重套准方框 + 一张说明卡，不做遮罩、不做动画。 */

.coach { position: fixed; inset: 0; z-index: 60; pointer-events: none; }
.coach[hidden] { display: none; }

/* 盖版：四块围出一个洞。用矩形而不是 box-shadow 撑出来的遮罩——
   这个世界没有阴影，而"盖一张半透明墨版、只留一处不盖"本来就是校样的做法。
   洞口本身不盖，所以高亮的那块仍然可以点。 */
.coach-scrim {
  position: fixed;
  background: var(--scrim);
  pointer-events: auto;   /* 洞外挡住，引导期间不会误触到别的控件 */
}

.coach-ring {
  position: fixed;
  border: 2px solid var(--pen3);
  pointer-events: none;
}
.coach-ring::after {
  content: "";
  position: absolute;
  inset: -6px;
  border: 1px solid var(--pen3);
  opacity: .55;
}

.coach-card {
  position: fixed;
  pointer-events: auto;
  width: min(346px, calc(100vw - 24px));
  background: var(--paper);
  border: 1px solid var(--pen3);
  padding: 12px 14px 13px;
  font-family: var(--cjk);
  font-size: calc(12.5px + var(--step));
  line-height: 1.7;
  color: var(--ink);
}
.coach-card:focus { outline: none; }
.coach-card:focus-visible { outline: 2px solid var(--pen3); outline-offset: 2px; }

.coach-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; margin-bottom: 7px; }
.coach-step { font-family: var(--mono); font-size: calc(11px + var(--step)); color: var(--ink-faint); letter-spacing: .04em; }
.coach-skip {
  border: 0; background: transparent; color: var(--ink-soft); cursor: pointer; padding: 0;
  font-family: var(--mono); font-size: calc(11px + var(--step));
  text-decoration: underline; text-underline-offset: 3px;
}
.coach-skip:hover { color: var(--ink); }
.coach-skip:focus-visible { outline: 2px solid var(--pen3); outline-offset: 2px; }

.coach-title { font-size: calc(14px + var(--step)); font-weight: 700; margin: 0 0 5px; }
.coach-body { margin: 0 0 12px; color: var(--ink-soft); }
.coach-foot { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.coach-dots { display: flex; gap: 4px; }
.coach-dot { width: 6px; height: 6px; border: 1px solid var(--rule); display: block; }
.coach-dot.on { background: var(--ink); border-color: var(--ink); }

@media print {
  .coach { display: none !important; }
}

/* ------------------------------------------------------------- 打印样式 */

@media print {
  body { background: #fff; overflow: visible; padding: 0; }
  .sheet { height: auto; border: 0; padding: 0; }
  .sheet::before, .sheet::after { display: none; }
  .rail, .toggles, .buildbar, .row-actions, .ph-actions, .tabs { display: none !important; }
  .bench { display: block; }
  .canvaswrap { height: 420px; }
  .panel { display: block !important; }
  .modal { display: none !important; }
  .status { background: #fff; }
  .coach { display: none !important; }
}

