/* =============================================================================
 * components.css — 组件样式（运行时 Agent 拥有）
 * 仅用 theme.css 令牌。包含：卡片 / 按钮 / 代码块 / 伪代码表 /
 * 术语卡 / 测验 / 进度 / 徽章，以及「原文衬线 vs 讲解无衬线」视觉惯例。
 *
 * 编辑部风的三条组件原则：
 *   1) 立体感来自发丝线与底色差，不来自阴影与漂浮（圆角收到 2–6px）；
 *   2) 分组靠「上/下一条线 + 留白」，不靠给每块套一个框；
 *   3) 一个强调色（墨蓝）走到底，状态色只做点缀且低饱和。
 * ========================================================================== */

/* ---------- 核心视觉惯例：原文 vs 讲解 ----------
 * 英文原文段落用 --font-serif（像书一样），讲解补充用 --font-sans。
 * 配合 data-kind="source" / data-kind="note" 两种底色，一眼可分（红线 R3）。
 * 原文与讲解只差一层底色，靠**冷暖色相**而非明度分开，长时间阅读不刺眼。
 */
[data-kind="source"] {
  font-family: var(--font-serif);
  font-size: var(--fs-md);
  line-height: 1.75;
  background: var(--c-source);
  color: var(--fg-0);
  /* 原文 = 贴进页面的一页纸：四边发丝线 + 左侧稍重的书脊线 */
  border: var(--bd-w) solid color-mix(in srgb, var(--bd-0) 75%, var(--c-source));
  border-left: 3px solid var(--bd-1);
  border-radius: var(--radius-sm);
  padding: var(--sp-4) var(--sp-4) var(--sp-4) var(--sp-5);
}

/* 原文里的西文用引号时是弯引号，斜体保持衬线的斜体 */
[data-kind="source"] em,
[data-kind="source"] i {
  font-style: italic;
}

[data-kind="note"] {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: var(--lh-read);
  background: var(--c-note);
  color: var(--fg-0);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: var(--sp-4) var(--sp-4) var(--sp-4) var(--sp-5);
}

/* 一段话内部：原文（serif）与讲解（sans）并排对照 */
.prose-pair {
  display: grid;
  gap: var(--sp-3);
}
@media (min-width: 720px) {
  .prose-pair {
    grid-template-columns: 1fr 1fr;
  }
}

.kind-tag {
  display: inline-block;
  font-size: var(--fs-xs);
  font-family: var(--font-sans);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-2);
  margin-bottom: var(--sp-1);
}

/* ---------- 卡片 = 版块面板 ----------
 * 注意：这里的 .card 是内容容器（stages.js 用它包住每个阶段），
 * 不是「漂浮的卡片」。所以：发丝线 + 纸底，无阴影、无大圆角。
 */
.card {
  background: var(--bg-1);
  border: var(--bd-w) solid var(--bd-0);
  border-radius: var(--radius-sm);
  padding: var(--sp-5);
}

.card--link {
  display: block;
  text-decoration: none;
  color: inherit;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.card--link:hover,
.card--link:focus-visible {
  border-color: var(--bd-1);
  background: var(--bg-2);
  outline: none;
}

.card__title {
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: 700;
  letter-spacing: -0.005em;
  margin: 0 0 var(--sp-2);
}
.card__meta {
  font-size: var(--fs-sm);
  color: var(--fg-2);
}

/* ---------- 按钮 ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  line-height: 1.2;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--radius-sm);
  border: var(--bd-w) solid var(--bd-1);
  background: var(--bg-1);
  color: var(--fg-0);
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
    color var(--dur) var(--ease);
}
.btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.btn--primary {
  background: var(--accent);
  color: var(--accent-fg);
  border-color: var(--accent);
  font-weight: 600;
}
.btn--primary:hover {
  /* 主按钮的 hover 用加深而不是加亮，暗色下也成立 */
  background: color-mix(in srgb, var(--accent) 86%, var(--fg-0));
  color: var(--accent-fg);
  border-color: color-mix(in srgb, var(--accent) 86%, var(--fg-0));
}
.btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--fg-1);
}
.btn--ghost:hover {
  background: var(--bg-2);
  color: var(--fg-0);
  border-color: transparent;
}
.btn--sm {
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-xs);
}

/* ---------- 代码块 / 伪代码 ----------
 * 代码是这本书的主角之一，所以给它「清单」的待遇：
 * 行号独立成栏、栏间一条发丝线、行高放松到 1.7。
 */
.code {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.7;
  background: var(--bg-2);
  color: var(--fg-0);
  border: var(--bd-w) solid var(--bd-0);
  border-radius: var(--radius-sm);
  padding: var(--sp-4);
  overflow-x: auto;
  white-space: pre;
  tab-size: 4;
}

/* 语法高亮：core/highlight.js 只负责切 token，颜色全在这里。
   刻意不加粗（除关键词）、不换字号 —— 代码的等宽栅格不能被打乱。 */
.tok-comment { color: var(--tok-comment); font-style: italic; }
.tok-str     { color: var(--tok-str); }
.tok-num     { color: var(--tok-num); }
.tok-kw      { color: var(--tok-kw); font-weight: 600; }
.tok-pre     { color: var(--tok-pre); }
.tok-fn      { color: var(--tok-fn); }

.code-block {
  margin: var(--sp-4) 0;
}

/* 伪代码表：逐行、带行号、可高亮某行 */
.pseudocode {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.7;
  background: var(--bg-2);
  border: var(--bd-w) solid var(--bd-0);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) 0;
  margin: var(--sp-4) 0;
  counter-reset: pc;
  overflow-x: auto;
}
.pc-line {
  display: grid;
  grid-template-columns: 2.75rem 1fr;
  align-items: baseline;
  padding: var(--sp-1) var(--sp-5) var(--sp-1) var(--sp-2);
  white-space: pre;
}
.pc-line .pc-no {
  color: var(--fg-2);
  text-align: right;
  padding-right: var(--sp-3);
  border-right: var(--bd-w) solid var(--bd-0);
  margin-right: var(--sp-3);
  user-select: none;
  font-variant-numeric: tabular-nums;
}
.pc-line .pc-code {
  color: var(--fg-0);
}
/* 高亮当前执行的伪代码行：左侧竖条 + 纸底，不靠加粗 */
.pc-line.is-active {
  background: var(--bg-1);
  box-shadow: inset 3px 0 0 var(--viz-active);
}
.pc-line.is-active .pc-no {
  color: var(--viz-active);
  font-weight: 700;
}
.pc-line.is-done .pc-code {
  color: var(--fg-2);
}
/* 伪代码行上了语法高亮后，"走过的那几行变淡"这条状态提示会被 token 自己的
   颜色盖掉（子元素颜色优先于父元素继承）。这里让已执行行的着色全部让位，
   保证动画里「已经走完」仍然看得出来。 */
.pc-line.is-done .pc-code span {
  color: inherit;
  font-style: inherit;
  font-weight: inherit;
}

/* ---------- 原书插图（PDF 裁图，不是重绘的示意图）----------
 * 版式取向：像「夹进讲义的一页书」——纸色底 + 发丝边框，图注走衬线体，
 * 与 data-kind="source" 的原文惯例一致（图注是原文的一部分，不是我们的讲解）。
 * 暗色下 --fig-paper 会压一档亮度，避免黑底上一块发光的白板。
 */
.fig-plate {
  margin: var(--sp-5) 0 0;
  padding: var(--sp-3) var(--sp-4) var(--sp-4);
  border: var(--bd-w) solid var(--bd-0);
  border-radius: var(--radius-md);
  background: var(--bg-1);
}
.fig-plate__label {
  font-size: var(--fs-xs);
  letter-spacing: 0.12em;
  color: var(--fg-2);
  margin-bottom: var(--sp-1);
}
.book-fig {
  margin: var(--sp-4) 0 0;
}
.book-fig__link {
  display: block;
  background: var(--fig-paper);
  border: var(--bd-w) solid var(--fig-edge);
  border-radius: var(--radius-sm);
  padding: var(--sp-2);
}
.book-fig__link:hover {
  border-color: var(--accent);
}
.book-fig img {
  display: block;
  width: 100%;
  height: auto;
}
.book-fig__cap {
  font-family: var(--font-serif);
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--fg-1);
  margin-top: var(--sp-2);
}
.book-fig__page {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-2);
  margin-left: var(--sp-2);
  white-space: nowrap;
}

/* ---------- 术语卡（中英对照） ---------- */
.term {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-2);
  background: transparent;
  border: var(--bd-w) solid var(--bd-0);
  border-radius: var(--radius-sm);
  padding: var(--sp-1) var(--sp-2);
  font-size: var(--fs-sm);
}
.term .term-en {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--fg-0);
}
.term .term-zh {
  color: var(--fg-1);
}

/* ---------- 测验题 ---------- */
.quiz {
  border: var(--bd-w) solid var(--bd-0);
  border-left: 3px solid var(--bd-1);
  border-radius: var(--radius-sm);
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-1);
  margin: var(--sp-4) 0;
}
.quiz__q {
  font-family: var(--font-sans);
  font-weight: 600;
  line-height: var(--lh-base);
  margin-bottom: var(--sp-3);
}
.quiz__options {
  display: grid;
  gap: var(--sp-2);
}
.quiz__opt {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: var(--bd-w) solid var(--bd-0);
  border-radius: var(--radius-sm);
  cursor: pointer;
  background: transparent;
  color: var(--fg-0);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  text-align: left;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.quiz__opt:hover {
  border-color: var(--accent);
  background: var(--bg-2);
}
.quiz__opt.is-correct {
  border-color: var(--c-ok);
  background: color-mix(in srgb, var(--c-ok) 12%, var(--bg-1));
}
.quiz__opt.is-wrong {
  border-color: var(--c-err);
  background: color-mix(in srgb, var(--c-err) 10%, var(--bg-1));
}
.quiz__why {
  margin-top: var(--sp-3);
  padding-left: var(--sp-3);
  border-left: 2px solid var(--bd-0);
  font-size: var(--fs-sm);
  line-height: var(--lh-read);
  color: var(--fg-1);
}
.quiz__why[data-ok="1"] {
  border-left-color: var(--c-ok);
}

/* ---------- 进度 ----------
 * 不做「有背景轨道的填充进度条」（那是仪表盘语言）。
 * 需要表达 n / m 时用 .ticks（见 layout.css）；这个类保留给需要连续进度的场合，
 * 只画填充部分，不画轨道。
 */
.progress {
  position: relative;
  height: 2px;
  width: 100%;
  background: var(--bd-0);
  border: 0;
  border-radius: 0;
  overflow: hidden;
}
.progress__fill {
  height: 100%;
  width: 0%;
  background: var(--accent);
  border-radius: 0;
  transition: width var(--dur) var(--ease);
}

/* ---------- 徽章 ---------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: var(--fs-xs);
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
  padding: 0 var(--sp-2);
  border-radius: var(--radius-sm);
  border: var(--bd-w) solid var(--bd-0);
  background: transparent;
  color: var(--fg-1);
}
.badge--done {
  background: color-mix(in srgb, var(--c-ok) 12%, transparent);
  border-color: color-mix(in srgb, var(--c-ok) 45%, var(--bd-0));
  color: var(--c-ok);
}
.badge--locked {
  opacity: 0.55;
}

/* ---------- 错题本（#/wrong） ----------
 * 排版取「档案卡」意：一组 = 一关，组内每题一张卡。
 * 「你的答案 / 正确答案」用状态色对置，且颜色之外还有文字标签 ——
 * 色觉障碍下也读得出来（与可视化引擎同一条原则）。
 */
.wb-lede {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--fg-1);
}
.wb-lede b {
  font-family: var(--font-mono);
  color: var(--fg-0);
}

.wb-group {
  border-top: 2px solid var(--fg-0);
  padding-top: var(--sp-3);
}
.wb-group__head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}
.wb-group__title {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: 700;
}
.wb-group__count {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-2);
}
.wb-group__head .spacer,
.wb-item__head .spacer {
  flex: 1 1 auto;
}

.wb-item {
  border: var(--bd-w) solid var(--bd-0);
  border-left: 3px solid var(--c-err);
  border-radius: var(--radius-sm);
  background: var(--bg-1);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-3);
}
.wb-item__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}
.wb-item__kind {
  font-size: var(--fs-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-2);
}
.wb-item__id {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-2);
}
.wb-item__q {
  margin: 0 0 var(--sp-2);
  font-family: var(--font-sans);
  line-height: var(--lh-base);
}
.wb-item__ans {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  font-size: var(--fs-sm);
}
.wb-ans--bad {
  color: var(--c-err);
}
.wb-ans--ok {
  color: var(--c-ok);
}
.wb-item__why {
  margin: var(--sp-2) 0 0;
  padding-left: var(--sp-3);
  border-left: 2px solid var(--bd-0);
  font-size: var(--fs-sm);
  color: var(--fg-1);
  line-height: var(--lh-base);
}

/* ---------- 术语表（#/glossary） ----------
 * 与错题本共用「档案」的排法，但这里条目密集得多：
 * 所以靠字母分组头 + 每行左英文右出处来建立视线节奏，条目之间不套框（只留分隔线）。
 */
.gloss-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  padding-bottom: var(--sp-3);
  border-bottom: var(--bd-w) solid var(--bd-0);
}
.gloss-search {
  flex: 1 1 18rem;
}
.gloss-count {
  font-size: var(--fs-xs);
  color: var(--fg-2);
}

.gloss-group {
  border-top: 2px solid var(--fg-0);
  padding-top: var(--sp-2);
}
/* 字母头像词典的边标：展示衬线 + 强调色，不做成大标题 */
.gloss-letter {
  margin: 0 0 var(--sp-2);
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: 700;
  color: var(--accent);
  line-height: 1;
}

.gloss-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: var(--sp-2) var(--sp-5);
  align-items: baseline;
  padding: var(--sp-2) 0;
  border-bottom: var(--bd-w) solid var(--bd-0);
}
@media (max-width: 760px) {
  .gloss-item {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-1);
  }
}

/* 英文名用衬线体（与原文一致），中文译名用黑体（与讲解一致）—— 沿用全站视觉惯例 */
.gloss-term {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-3);
}
.gloss-en {
  font-family: var(--font-serif);
  font-size: var(--fs-md);
  color: var(--fg-0);
}
.gloss-zh {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--fg-1);
}

.gloss-src {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
}
.gloss-link {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--fg-1);
  text-decoration: none;
  border-bottom: var(--bd-w) solid var(--bd-0);
}
.gloss-link:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.gloss-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.gloss-link__where {
  font-family: var(--font-sans);
}

/* ---------- 伪代码速查（#/pseudocode） ----------
 * 这里只列「算法名 + 行数 + 出处」，不铺开代码：
 * 一页铺 130 段伪代码会变成没法扫的墙；要看代码点进那一关的「伪代码骨架」段，
 * 那里有逐行中文讲解与变量表。所以本页的角色是**索引**，不是第二份代码。
 */
.pcx-group {
  border-top: 2px solid var(--fg-0);
  padding-top: var(--sp-2);
}
.pcx-chapter {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-2);
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: 700;
}
.pcx-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
  gap: 0 var(--sp-5);
}
.pcx-item {
  padding: var(--sp-2) 0;
  border-bottom: var(--bd-w) solid var(--bd-0);
  min-width: 0;
}
.pcx-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
/* 算法名是等宽（与伪代码正文同一套字形），像清单里的条目 */
.pcx-name {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--fg-0);
}
.pcx-sig {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-2);
}
.pcx-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
  margin-top: var(--sp-1);
}
.pcx-dim {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-2);
}

/* ---------- 复杂度对照表（#/complexity） ----------
 * 结论与语境两列：左列是短公式（不换行、等宽数字），右列是中文长句（要能换行）。
 * 与「复杂度」阶段（.kv--claims）同一份数据、不同用途：那里是单关内自上而下读，
 * 这里是全书横向扫 —— 所以每条都带可点的节号，扫到可疑的一行能直接跳过去。
 */
.cx-group {
  border-top: 2px solid var(--fg-0);
  padding-top: var(--sp-2);
}
.cx-chapter {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-2);
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: 700;
}
.cx-chapter__link {
  color: inherit;
  text-decoration: none;
}
.cx-chapter__link:hover {
  color: var(--accent);
}
.cx-chapter__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.cx-chapter__count {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--fg-2);
}

.cx-table {
  table-layout: fixed;
}
.cx-table thead th {
  font-size: var(--fs-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-2);
  font-weight: 500;
}
.cx-table .cx-expr {
  width: 34%;
  white-space: normal;
  vertical-align: top;
}
.cx-table .cx-when {
  vertical-align: top;
  font-size: var(--fs-sm);
  line-height: var(--lh-base);
  color: var(--fg-1);
}
.cx-src {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-3);
  margin-top: var(--sp-1);
}
.cx-link {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--accent);
  text-decoration: none;
  border-bottom: var(--bd-w) solid color-mix(in srgb, var(--accent) 40%, transparent);
}
.cx-link:hover {
  border-bottom-color: var(--accent);
}
.cx-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* 窄屏：两列挤不下，改成一块一块地摞（结论在上、语境在下） */
@media (max-width: 700px) {
  .cx-table,
  .cx-table tbody,
  .cx-table tr,
  .cx-table th,
  .cx-table td {
    display: block;
    width: auto;
  }
  .cx-table thead {
    display: none;
  }
  .cx-table tr {
    padding: var(--sp-2) 0;
    border-bottom: var(--bd-w) solid var(--bd-0);
  }
  .cx-table th,
  .cx-table td {
    border-bottom: none;
    padding: 0;
  }
}

/* ---------- 复习模式（#/review） ----------
 * 复习页每题上方有一条「来历」行：哪一关的题、记得牢不牢、逾期多久、回原关的链接。
 * 放在题干上方而不是下方，是因为复习时第一件事是想起「这是哪儿的题」，
 * 而不是做完再看它出自哪里。
 */
.rev-summary__lead {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: var(--lh-base);
}
.rev-summary__lead b {
  font-family: var(--font-mono);
}

.rev-progress {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--fg-1);
}

.rev-origin {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
  margin-bottom: var(--sp-2);
  padding-bottom: var(--sp-2);
  border-bottom: var(--bd-w) solid var(--bd-0);
  font-size: var(--fs-xs);
}
.rev-origin__where {
  font-family: var(--font-sans);
  font-weight: 600;
  color: var(--fg-0);
}
.rev-origin__box {
  color: var(--accent);
  border: var(--bd-w) solid color-mix(in srgb, var(--accent) 45%, var(--bd-0));
  border-radius: var(--radius-pill);
  padding: 0 var(--sp-2);
}
.rev-origin__due {
  color: var(--fg-2);
}
.rev-origin__link {
  margin-left: auto;
  color: var(--fg-1);
  text-decoration: none;
  border-bottom: var(--bd-w) solid var(--bd-0);
}
.rev-origin__link:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.rev-origin__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* ---------- 章末 Boss 区（#/chNN/boss） ----------
 * 这一页的语义是「整章收口」：徽章在最上（一眼看到通没通），
 * 关卡进度条居中（看清差哪一关），Problems 在最后（压轴题，难而长）。
 */
.boss-head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border: var(--bd-w) solid var(--bd-0);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--bg-1);
}
.boss-badge {
  align-self: flex-start;
  font-size: var(--fs-md);
  padding: var(--sp-1) var(--sp-3);
}
.boss-badge__mark {
  font-size: var(--fs-lg);
  line-height: 1;
}
.boss-head__note {
  margin: 0;
  max-width: var(--measure);
  font-size: var(--fs-sm);
  line-height: var(--lh-read);
  color: var(--fg-1);
}

.boss-levels {
  display: flex;
  flex-direction: column;
}
.boss-level {
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr) auto 1.4rem;
  gap: var(--sp-3);
  align-items: baseline;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: var(--bd-w) solid var(--bd-0);
  text-decoration: none;
  color: inherit;
}
.boss-level:hover {
  background: var(--bg-2);
}
.boss-level:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.boss-level.is-done .boss-level__no,
.boss-level.is-done .boss-level__mark {
  color: var(--c-ok);
}
.boss-level__no {
  font-family: var(--font-display);
  color: var(--fg-2);
}
.boss-level__prog {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-2);
}
.boss-level__mark {
  font-size: var(--fs-sm);
}

/* Problems 比节末练习长得多，出处链接贴在题号旁而不是压到标题下方 */
.boss-problem__src {
  font-size: var(--fs-xs);
  color: var(--fg-1);
  text-decoration: none;
  border-bottom: var(--bd-w) solid var(--bd-0);
}
.boss-problem__src:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* 自评勾选：章末题不给答案、不判分，所以这里是**读者自己的**完成标记。
   视觉上刻意做得轻（左侧一条细线 + 题号旁的小方框），不学「正确答案」那种
   实心色块 —— 免得看起来像系统判过的成绩。 */
.boss-problem__mark {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  cursor: pointer;
}
.boss-problem__check {
  width: 1rem;
  height: 1rem;
  accent-color: var(--c-ok);
  cursor: pointer;
}
.boss-problem__check:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.boss-problem.is-done {
  border-left: 3px solid var(--c-ok);
}
.boss-problem.is-done .drill-exercise__id {
  color: var(--c-ok);
}

/* 侧栏里的 Boss 入口：与关卡条目同族，但不参与「第 N 关」编号 */
.rail-item--boss {
  margin-top: var(--sp-2);
  border-top: var(--bd-w) solid var(--bd-0);
  font-weight: 600;
}
.rail-item--boss .rail-no {
  color: var(--accent);
}

/* ---------- 算法选择器（#/algorithms） ----------
 * 一屏要能横向对照「排序类有哪些、各自多快」，所以每条压成三行：
 *   ① 名称 + 可单步标记；② 出处（节号 + 印刷页）；③ 复杂度结论。
 * 不做卡片、不留大片空白 —— 这一页的价值是密度，不是好看。
 */
.algo-group {
  border-top: 2px solid var(--fg-0);
  padding-top: var(--sp-2);
}
.algo-part {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-2);
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: 700;
}
.algo-part__no {
  font-family: var(--font-display);
  color: var(--accent);
}
.algo-part__count {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--fg-2);
}

.algo-row {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: var(--sp-1) var(--sp-5);
  align-items: baseline;
  padding: var(--sp-2) 0;
  border-bottom: var(--bd-w) solid var(--bd-0);
}
@media (max-width: 760px) {
  .algo-row {
    grid-template-columns: minmax(0, 1fr);
  }
}

.algo-row__main {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-3);
  min-width: 0;
}
.algo-row__name {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--fg-0);
  text-decoration: none;
  border-bottom: var(--bd-w) solid var(--bd-0);
}
.algo-row__name:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.algo-row__name:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.algo-row__sig {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-2);
}
/* 「可单步」是真实能力（阶段 5 有生成器驱动动画），不是装饰徽章 */
.algo-row__anim {
  font-size: var(--fs-xs);
  text-decoration: none;
  color: var(--c-ok);
  border-color: color-mix(in srgb, var(--c-ok) 45%, var(--bd-0));
}

.algo-row__where {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-3);
  font-size: var(--fs-xs);
}
.algo-row__level {
  color: var(--fg-1);
  text-decoration: none;
  border-bottom: var(--bd-w) solid var(--bd-0);
}
.algo-row__level:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.algo-row__extras {
  grid-column: 1 / -1;
  font-size: var(--fs-xs);
  color: var(--fg-2);
}
.algo-row__extra {
  font-family: var(--font-mono);
  color: var(--fg-1);
  text-decoration: none;
  border-bottom: var(--bd-w) solid var(--bd-0);
}
.algo-row__extra:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.algo-row__extra-page {
  font-family: var(--font-mono);
}

.algo-row__cost {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  font-size: var(--fs-sm);
}
.algo-cost {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-2);
}

/* ---------- 提示框（callout） ---------- */
.callout {
  border-radius: var(--radius-sm);
  border: var(--bd-w) solid var(--bd-0);
  border-left-width: 3px;
  padding: var(--sp-3) var(--sp-4);
  margin: var(--sp-4) 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-read);
}
.callout--ok {
  border-left-color: var(--c-ok);
  background: color-mix(in srgb, var(--c-ok) 8%, var(--bg-1));
}
.callout--warn {
  border-left-color: var(--c-warn);
  background: color-mix(in srgb, var(--c-warn) 10%, var(--bg-1));
}
.callout--err {
  border-left-color: var(--c-err);
  background: color-mix(in srgb, var(--c-err) 8%, var(--bg-1));
}

/* ---------- 等宽小工具 ---------- */
.mono {
  font-family: var(--font-mono);
  font-size: 0.95em;
  background: var(--bg-2);
  border: var(--bd-w) solid var(--bd-0);
  border-radius: var(--radius-sm);
  padding: 0 0.25em;
}

/* ---------- 数学公式（katex 极简渲染输出；真 KaTeX 可覆盖） ---------- */
.katex-inline {
  font-family: var(--font-serif);
  font-style: normal;
  font-variant-numeric: tabular-nums;
  /* 行内公式不能被折行（Θ(n lg n) 被拆成两行是最刺眼的排版事故） */
  white-space: nowrap;
}
/* 独立公式按印刷惯例：上下各一条发丝线，不加底色框 */
.katex-block {
  display: block;
  text-align: center;
  font-family: var(--font-serif);
  font-size: var(--fs-lg);
  background: transparent;
  border: 0;
  border-top: var(--bd-w) solid var(--bd-0);
  border-bottom: var(--bd-w) solid var(--bd-0);
  border-radius: 0;
  padding: var(--sp-4) var(--sp-2);
  margin: var(--sp-5) 0;
  overflow-x: auto;
}
.frac {
  display: inline-flex;
  flex-direction: column;
  text-align: center;
  vertical-align: middle;
  margin: 0 0.15em;
}
.frac > .num {
  border-bottom: var(--bd-w) solid currentColor;
  padding: 0 0.3em;
  line-height: 1.1;
}
.frac > .den {
  padding: 0 0.3em;
  line-height: 1.1;
}
/* \binom{n}{k}：两层堆叠 + 包住的大括号，与 .frac 的关键区别是**不画横线** */
.binom {
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
  margin: 0 0.15em;
}
.binom__stack {
  display: inline-flex;
  flex-direction: column;
  text-align: center;
  line-height: 1.15;
  padding: 0 0.15em;
}
.binom__paren {
  font-size: 2em;
  line-height: 1;
}
/* \overline{X}：整段内容加顶线（组合字符只能盖住最后一个字符，所以用 span） */
.overline {
  text-decoration: overline;
  padding: 0 0.05em;
}
.sqrt-arg {
  border-top: var(--bd-w) solid currentColor;
  padding: 0 0.15em;
}
/* \text{...}：正体，与数学斜体区分 */
.tex-text {
  font-style: normal;
  white-space: pre;
}
/* \begin{cases}：左花括号 + 两列（值 / 条件） */
.cases {
  display: inline-flex;
  align-items: stretch;
  vertical-align: middle;
  margin: 0 0.15em;
}
.cases__brace {
  display: flex;
  align-items: center;
  font-size: 2.4em;
  line-height: 1;
  font-weight: 300;
  padding-right: 0.08em;
}
.cases__rows {
  display: flex;
  flex-direction: column;
  gap: 0.3em;
  text-align: left;
}
.cases__row {
  display: flex;
  gap: 0.9em;
  align-items: baseline;
}
.cases__val {
  min-width: 2.5em;
}
.cases__cond {
  color: var(--fg-1);
}
/* \underbrace{...}_{...}：主体 + 下方标注（含一条表示覆盖范围的横线） */
.ubrace {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  vertical-align: middle;
  margin: 0 0.15em;
}
.ubrace__body {
  border-bottom: var(--bd-w) solid currentColor;
  padding: 0 0.2em;
}
.ubrace__label {
  font-size: 0.78em;
  line-height: 1.2;
  padding-top: 0.05em;
}
/* \xrightarrow{...}：箭头上方标注 */
.xarrow {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  vertical-align: middle;
  margin: 0 0.3em;
}
.xarrow__label {
  font-size: 0.78em;
  line-height: 1.2;
}
.xarrow__arrow {
  line-height: 1;
}

/* 可视化图例（可选，供 viz 引擎复用） */
.viz-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  font-size: var(--fs-xs);
  color: var(--fg-1);
  margin-top: var(--sp-2);
}
.viz-legend .swatch {
  display: inline-block;
  width: 0.8em;
  height: 0.8em;
  border-radius: var(--radius-sm);
  margin-right: var(--sp-1);
  vertical-align: -0.05em;
}
