/* ==========================================================================
   AGENTS.md 生成器 —— 样式表
   简洁卡片式设计 · 系统字体 · 响应式 · 移动端友好 · 柔和配色
   ========================================================================== */

:root {
  --bg: #f4f6fa;
  --surface: #ffffff;
  --surface-alt: #fafbfd;
  --border: #e4e8f0;
  /* 输入框与下拉框的边界原来 1.4:1：控件在白底上几乎看不出边界在哪，
     键盘用户尤其依赖它判断焦点位置。1.4.11 要求控件边界 ≥3:1。 */
  --border-strong: #7e8b9e;
  --text: #1b2436;
  --text-soft: #475467;
  /* 次要文字（状态提示、编号、时间、页脚、窄屏卡片行的列名）原来 3.4–3.7:1，
     全部达不到正文要求的 4.5:1，而它偏偏是全页最小的字。
     「该语种暂无译文」标记也用它，那是最该被看清的一处提示。 */
  --muted: #5f6a7c;
  --primary: #2f6fed;
  --primary-dark: #1f56c6;
  --primary-soft: #ecf2ff;
  --success: #16794c;
  --success-soft: #e7f6ee;
  --warn: #91591a;
  --warn-soft: #fdf3e2;
  --danger: #b42318;
  --danger-soft: #fdecea;
  --neutral-soft: #f0f2f6;
  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.04);
  --shadow: 0 1px 3px rgba(16, 24, 40, 0.06), 0 8px 24px rgba(16, 24, 40, 0.05);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB",
    "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 650;
  line-height: 1.35;
}

p {
  margin: 0;
}

a {
  /* --primary 在页面底色（--bg）上只有 4.2:1，正文尺寸的链接要求 4.5:1。
     卡片内部是白底，两者都够；这里统一用更深一档，视觉差别很小。 */
  color: var(--primary-dark);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* ------------------------------- 导航栏 -------------------------------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: saturate(180%) blur(8px);
  border-bottom: 1px solid var(--border);
}

.nav-inner {
  max-width: 1080px;
  margin: 0 auto;
  padding: 12px 20px;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.brand {
  font-weight: 700;
  font-size: 15px;
  color: var(--text);
  letter-spacing: 0.2px;
  white-space: nowrap;
}

.brand:hover {
  text-decoration: none;
}

.brand-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--primary);
  margin-right: 8px;
  vertical-align: 2px;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-left: auto;
}

.nav-link {
  padding: 6px 12px;
  border-radius: 999px;
  color: var(--text-soft);
  font-size: 14px;
  white-space: nowrap;
}

.nav-link:hover {
  background: var(--neutral-soft);
  text-decoration: none;
}

.nav-link.active {
  background: var(--primary-soft);
  color: var(--primary-dark);
  font-weight: 600;
}

/* ------------------------- 下拉框（语言 / 用户） --------------------------
   两者结构一致：相对定位的容器 + 触发按钮 + 绝对定位的面板。
   面板必须脱离文档流：否则展开时会把导航栏整行撑高。
   -------------------------------------------------------------------------- */

.lang-select,
.user-select {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.lang-select-trigger,
.user-select-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--text-soft);
  font-size: 14px;
  font-family: inherit;
  cursor: pointer;
  line-height: 1.2;
}

.lang-select-trigger:hover,
.user-select-trigger:hover {
  background: var(--neutral-soft);
}

.lang-select.open .lang-select-trigger,
.user-select.open .user-select-trigger {
  background: var(--neutral-soft);
  border-color: var(--border);
  color: var(--text);
}

.lang-select-trigger:focus-visible,
.user-select-trigger:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.lang-icon,
.user-caret {
  flex: none;
}

.user-caret {
  opacity: 0.6;
}

.user-avatar {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary-dark);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
}

.user-select-name {
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
}

.lang-select-menu,
.user-select-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 30;
  /* 宽度由内容决定。菜单项必须完整落在一行内：如果给一个很窄的
     min-width，弹性子项会被压到一两个字宽，「中文」就被拆成两行。
     max-width 只在极窄屏幕兜底，超长时由各项自己截断。 */
  width: max-content;
  min-width: 190px;
  max-width: min(80vw, 320px);
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.lang-select-menu[hidden],
.user-select-menu[hidden] {
  display: none;
}

/* ---------------------------- 语言下拉项 -------------------------------- */

.lang-select-option {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-size: 14px;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  /* 语言名永远一行：这是选择器里的标签，不是段落 */
  white-space: nowrap;
}

.lang-select-option:hover,
.lang-select-option:focus-visible {
  background: var(--neutral-soft);
  outline: none;
}

.lang-select-option.selected {
  background: var(--primary-soft);
  color: var(--primary-dark);
  font-weight: 600;
}

.lang-name {
  /* 不参与弹性伸缩：一旦被压缩，中文会被逐字拆行。
     允许收缩是为了在菜单撞上 max-width 时能截断而不是换行。 */
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lang-check-wrap {
  display: inline-flex;
  color: var(--primary-dark);
}

/* ---------------------------- 用户下拉菜单 ------------------------------ */

.user-menu-head {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}

.user-menu-email {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.user-menu-role {
  margin-top: 2px;
  font-size: 12px;
  color: var(--muted);
}

.user-menu-item {
  display: block;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-size: 14px;
  font-family: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}

.user-menu-item:hover,
.user-menu-item.focused {
  background: var(--neutral-soft);
  text-decoration: none;
}

/* 当前所在页面对应的菜单项，与导航项的选中态保持一致 */
.user-menu-item.active {
  background: var(--primary-soft);
  color: var(--primary-dark);
  font-weight: 600;
}

.user-menu-item:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}

.user-menu-item.danger {
  color: var(--danger);
}

.user-menu-item.danger:hover,
.user-menu-item.danger.focused {
  background: var(--danger-soft);
}

.user-menu-sep {
  height: 1px;
  margin: 4px 0;
  background: var(--border);
}

/* ------------------------------- 布局 ---------------------------------- */

.container {
  max-width: 1080px;
  margin: 0 auto;
  padding: 24px 20px 72px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* 后台是数据工具页：条目库一张表九列，1080px 的容器会把它挤成两三个字的宽度。
   给它更宽的容器，九列才能各自拿到该有的份额。 */
body[data-page="admin"] .container {
  max-width: 1320px;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: 22px;
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.card-head h2 {
  font-size: 17px;
}

.hero h1 {
  font-size: 26px;
  margin-bottom: 10px;
}

.hero .subtitle {
  color: var(--text-soft);
  max-width: 720px;
}

.muted {
  color: var(--muted);
}

.small {
  font-size: 13px;
}

.subtitle {
  color: var(--text-soft);
}

/* ------------------------------- 表单 ---------------------------------- */

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}

.field-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
}

input[type="text"],
input[type="email"],
input[type="password"],
textarea,
select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  line-height: 1.55;
  transition: border-color 0.15s, box-shadow 0.15s;
}

textarea {
  resize: vertical;
  min-height: 96px;
}

input:focus,
textarea:focus,
select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(47, 111, 237, 0.14);
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}

/* --------------------- 条目表单：语种标签页 + 三档正文 --------------------- */

/*
  输入框数量与语种数量无关：语种只决定上面有几个标签页，下面始终是同一套
  标题输入框 + 三档正文输入框。加一种语言时这里一个字都不用改。
*/
.lang-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 10px;
}

.lang-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 6px 14px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-soft);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}

.lang-tab:hover {
  background: var(--neutral-soft);
}

.lang-tab.is-active {
  border-color: var(--primary);
  background: var(--primary);
  color: #fff;
}

/* 必填语种（默认语种）打一个实心点，缺译文的语种打一个空心点 */
.lang-tab.is-required::before {
  content: "●";
  font-size: 9px;
  opacity: 0.9;
}

.lang-tab.is-missing:not(.is-required)::before {
  content: "○";
  font-size: 10px;
  opacity: 0.7;
}

/*
  三档正文并排：三列各自成段，写规范时才能对着另外两档改。
  窄屏落回单列——三列挤在手机屏上，每列只剩十几个字宽，根本没法读。
*/
.rule-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.rule-cell {
  margin-bottom: 14px;
}

.rule-cell-head {
  min-height: 52px;
}

.rule-cell-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}

/* 最高档允许整条留空，列头标出来，避免被当成「漏写了」 */
.rule-cell.omittable .rule-cell-title::after {
  content: " ·";
  color: var(--muted);
}

@media (max-width: 900px) {
  .rule-grid {
    grid-template-columns: 1fr;
  }

  .rule-cell-head {
    min-height: 0;
  }
}

/* --------------------------- 智力等级选择器 ----------------------------- */

.level-picker {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.level-picker-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
}

.level-select {
  max-width: 320px;
}

.level-picker.compact {
  gap: 4px;
}

.level-picker.compact .level-select {
  max-width: 240px;
}

.filter-level {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

/* ------------------------------- 按钮 ---------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 9px 16px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.05s;
  white-space: nowrap;
  /* 按钮外观也用在 <a> 上（跳转到另一个页面的「浏览条目库」这类），
     不清掉下划线的话，链接看起来就不像按钮 */
  text-decoration: none;
}

.btn:hover:not(:disabled) {
  background: var(--neutral-soft);
}

.btn:active:not(:disabled) {
  transform: translateY(1px);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn.primary {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

.btn.primary:hover:not(:disabled) {
  background: var(--primary-dark);
  border-color: var(--primary-dark);
}

.btn.ghost {
  border-color: transparent;
  background: transparent;
  color: var(--text-soft);
}

.btn.ghost:hover:not(:disabled) {
  background: var(--neutral-soft);
}

.btn.danger {
  color: var(--danger);
  border-color: #f0c8c4;
  background: var(--danger-soft);
}

.btn.danger:hover:not(:disabled) {
  background: #fbdcd8;
}

.btn.success {
  color: var(--success);
  border-color: #bfe3d0;
  background: var(--success-soft);
}

.btn.success:hover:not(:disabled) {
  background: #d9f0e4;
}

.btn.small {
  padding: 5px 10px;
  font-size: 13px;
  font-weight: 500;
}

.btn-link {
  border: none;
  background: none;
  color: var(--primary);
  cursor: pointer;
  font-family: inherit;
  font-size: 14px;
  padding: 0;
  text-decoration: underline;
}

.row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.row-between {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}

.mt-12 {
  margin-top: 12px;
}

.mt-20 {
  margin-top: 20px;
}

/* ------------------------------- 徽章 ---------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.7;
  white-space: nowrap;
}

.badge.checked {
  background: var(--success-soft);
  color: var(--success);
}

.tag-chip.is-judged {
  /* 需要判断的条目用另一种底色：这一列回答的是「会不会交给判断」，
     而两种结果在清单里的后果完全不同（一个直接勾、一个要先判断）。 */
  background: var(--primary-soft);
  color: var(--primary-dark);
  font-family: var(--sans);
}

.tag-chip.is-always-on {
  /* 用户钉死的那几条：与「默认生效」区分开，让用户扫一眼就知道
     从哪几条开始改偏好。 */
  background: var(--success-soft);
  color: var(--success);
  font-family: var(--sans);
}

.badge.more,
.badge.suggest {
  background: var(--warn-soft);
  color: var(--warn);
}

.badge.more {
  background: var(--neutral-soft);
  color: var(--muted);
}

.badge.active {
  background: var(--success-soft);
  color: var(--success);
}

.badge.pending {
  background: var(--warn-soft);
  color: var(--warn);
}

.badge.rejected {
  background: var(--danger-soft);
  color: var(--danger);
}

.badge.neutral {
  background: var(--neutral-soft);
  color: var(--text-soft);
}

/* 废弃：条目已退出官方库，但编号与原文仍在，可按编号查回 */
.badge.deprecated {
  background: #efe9ff;
  color: #5334c9;
}

/* ---------------------------- 条目编号 ---------------------------------- */

/*
 * 编号一律等宽显示。
 * 编号是要被人抄写、比对、搜索的（写进 AGENTS.md、工单、对话里），
 * 比例字体下 '0' 与 'O'、'1' 与 'l' 长得几乎一样，等宽 + tabular-nums
 * 才能让肉眼核对成为一个可靠动作。
 */
.item-no {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;
  font-size: 0.85em;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  white-space: nowrap;
}

.badge.deprecated + .item-no,
.item-no .badge {
  color: inherit;
}

.badge.confidence {
  background: var(--primary-soft);
  color: var(--primary-dark);
  font-variant-numeric: tabular-nums;
}

/* 「我的」标记：来自用户私有条目库 */
.badge.mine {
  background: #efe9ff;
  color: #5334c9;
}

/* ---------------------------- 开关 / 标签选择 --------------------------- */

.switch-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-alt);
}

.switch {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 25px;
  flex: none;
  margin-top: 2px;
}

.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

.switch .slider {
  position: absolute;
  inset: 0;
  /* 开关的轨道原来 1.4:1：关掉的那一状态几乎看不出这是个可点的控件 */
  background: #7e8b9e;
  border-radius: 999px;
  transition: background 0.18s;
  cursor: pointer;
}

.switch .slider::before {
  content: "";
  position: absolute;
  width: 19px;
  height: 19px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(16, 24, 40, 0.25);
  transition: transform 0.18s;
}

.switch input:checked + .slider {
  background: var(--primary);
}

.switch input:checked + .slider::before {
  transform: translateX(19px);
}

.switch input:focus + .slider {
  box-shadow: 0 0 0 3px rgba(47, 111, 237, 0.22);
}

.tag-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  max-height: 190px;
  overflow-y: auto;
}

.tag-option {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  font-size: 13px;
  cursor: pointer;
  user-select: none;
  transition: background 0.15s, border-color 0.15s;
}

.tag-option:hover {
  background: var(--neutral-soft);
}

.tag-option input {
  accent-color: var(--primary);
  cursor: pointer;
  margin: 0;
}

.tag-option.is-picked {
  background: var(--primary-soft);
  border-color: #bcd2ff;
  color: var(--primary-dark);
  font-weight: 600;
}

.tag-option .tag-key {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
}

/* ---------------------------- 分析结果清单 ------------------------------ */

.group {
  border-top: 1px solid var(--border);
  padding-top: 16px;
  margin-top: 16px;
}

.group:first-child {
  border-top: none;
  padding-top: 0;
  margin-top: 0;
}

.group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.group-head h3 {
  font-size: 15px;
}

.group-head .count {
  font-size: 12px;
  color: var(--muted);
}

/*
 * 组内的小节标题。
 *
 * 与生成文档里的三级标题一一对应：界面上先分组、再分小节，
 * 用户读清单时的结构与最终拿到的文档一致。
 */
.group-sub {
  font-size: 13px;
  color: var(--muted);
  margin: 14px 0 6px;
  padding-left: 2px;
}

/*
 * 必选项的一行。
 *
 * 控件密度比其他区域低（每行只有一个决定），但它们是必须逐个点过去的东西，
 * 比列表里频繁滚动的条目更需要点得准——触控目标尺寸在下面的
 * any-pointer: coarse 块里统一处理，与全站其他控件保持同一套规则。
 */
.direct-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 8px 12px;
  padding: 10px 0;
  border-top: 1px solid var(--border);
}

.direct-row:first-child {
  border-top: none;
}

.direct-label {
  font-size: 14px;
  line-height: 1.5;
}

.direct-select {
  max-width: 100%;
}

/*
 * 「待选择」标记。
 * 只在未答时出现，且用警示色：一个没答的必选项如果长得跟答过的一样，
 * 用户会以为系统已经替他决定好了。
 */
.direct-pending {
  grid-column: 2;
  font-size: 12px;
  color: var(--warn);
}

.direct-row.is-answered .direct-pending {
  display: none;
}

@media (max-width: 640px) {
  .direct-row {
    grid-template-columns: 1fr;
  }

  .direct-pending {
    grid-column: 1;
  }
}

.check-item {
  display: flex;
  gap: 11px;
  padding: 11px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-alt);
  margin-bottom: 8px;
  transition: border-color 0.15s, background 0.15s;
}

.check-item:hover {
  border-color: var(--border-strong);
}

.check-item.is-checked {
  background: var(--primary-soft);
  border-color: #c9daff;
}

.check-item input[type="checkbox"] {
  width: 17px;
  height: 17px;
  margin: 3px 0 0;
  accent-color: var(--primary);
  flex: none;
  cursor: pointer;
}

.check-item .body {
  flex: 1;
  min-width: 0;
}

.check-item .title-line {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.check-item .title {
  font-weight: 600;
  font-size: 14px;
}

.check-item .desc {
  color: var(--text-soft);
  font-size: 13px;
  margin-top: 3px;
}

.check-item .evidence {
  color: var(--muted);
  font-size: 12.5px;
  margin-top: 5px;
}

.check-item .evidence span + span::before {
  content: " · ";
}

/* ------------------------- 候选方案（同一件事的多种做法） ------------------- */

.scheme-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: #f7f9fd;
}

.scheme-label {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-soft);
  white-space: nowrap;
}

.scheme-select {
  width: auto;
  min-width: 220px;
  max-width: 100%;
  padding: 5px 8px;
  font-size: 13px;
  border-radius: var(--radius-sm);
}

.scheme-reason {
  flex-basis: 100%;
  color: var(--muted);
  font-size: 12.5px;
}

@media (max-width: 720px) {
  .scheme-select {
    min-width: 0;
    width: 100%;
  }
}

details.more {
  margin-top: 4px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  padding: 8px 12px;
  background: var(--surface-alt);
}

details.more > summary {
  cursor: pointer;
  font-size: 13px;
  color: var(--text-soft);
  font-weight: 600;
  list-style: none;
}

details.more > summary::-webkit-details-marker {
  display: none;
}

details.more > summary::before {
  content: "▸ ";
  color: var(--muted);
}

details.more[open] > summary::before {
  content: "▾ ";
}

details.more .check-item {
  margin-top: 8px;
  background: var(--surface);
}

/* ---------------------------- Markdown 预览 ----------------------------- */

.preview {
  margin: 0;
  padding: 16px;
  background: #fbfcfe;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-family: var(--mono);
  font-size: 12.8px;
  line-height: 1.7;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 620px;
  overflow: auto;
  color: #22304a;
}

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

/* 表格自身不横向滚动：宽度由列宽规则决定，窄屏时整张表转成卡片行（见文件末尾）。
   早先的 `min-width: 720px` 会在窄屏上把「状态 / 提交人 / 更新时间」三列
   整个推到可视区之外，看起来就像这三列没有渲染。 */
.table-wrap {
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}

/* 固定列宽布局只给条目表格用：列宽由 data-variant 规则决定，
   内容再长也不会把某一列挤成竖排单字（"领域" 被拆成两行就是这么来的）。
   不声明变体的普通表格仍走 auto 布局——全局固定的话，
   那些没配列宽的表会退化成等宽列，标题列被压得比原来还窄。 */
/* 条目表格的表头：宁可换行，也不截成省略号。
   全局的 thead th 是 nowrap + ellipsis（长表头用省略号收尾），但条目表按固定
   列宽排布，列宽是按文案量定的：列名比可用宽度长时，「Cate…」这种省略号比
   「Category / Submitted by」换到第二行更糟——读者看不出这一列到底是什么，
   而列名是扫读表格时唯一的方向标。 */
.item-table thead th {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

.item-table {
  table-layout: fixed;
}

thead th {
  text-align: left;
  padding: 10px 12px;
  background: var(--surface-alt);
  border-bottom: 1px solid var(--border);
  color: var(--text-soft);
  font-weight: 600;
  font-size: 12.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

tbody td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  /* 单元格内容默认在单词放不下时才断行：长邮箱、长编号、长英文标题都不该把列撑宽，
     也不该把还放得下的词拆开（anywhere 会连 ecommerce 这种刚好放得下的也拆）。
     需要整行不换行的短列（分组、时间）自己再声明 nowrap。 */
  overflow-wrap: break-word;
}

tbody tr:last-child td {
  border-bottom: none;
}

tbody tr:hover td {
  background: var(--surface-alt);
}

/* ----------------------------- 列宽分配 -------------------------------- */

/*
 * 全部用百分比，且每个变体各自加总为 100%。
 *
 * 混用 px 与 % 时，只要「固定列之和 + 百分比之和」超过容器宽度，
 * 浏览器会把整张表连同固定列一起按比例缩小——九个列的表就是这样被压扁的：
 * 编号列塞不下 13 位编号、提交人列把长邮箱折成七八行、状态列只剩一个字的宽度。
 * 纯百分比则永远按比例分配，不会出现「某一列被连累」。
 *
 * 变体由表格的 data-variant 决定：public / review / library / users。
 *
 * 整段包在 min-width 媒体查询里：窄屏下表格转成卡片行，每格都是整行宽度，
 * 这时残留的百分比列宽会让标题列只剩两三个字宽——而它的选择器
 * （.item-table[data-variant] .col-*）比窄屏里的 `table tbody td` 更具体，
 * 光靠后者的 width: auto 盖不住。
 */
@media (min-width: 1181px) {
  /*
   * 每组都按「该变体最宽的一种形态」加总到 100%——这里的「最宽」指
   * **该列在任一语种下要显示的最长文案**，不是中文字数。
   *
   * 列宽是拿真实字宽定的：表头 12.5px/600、单元格 13.5px/600、chip 11.5px 等宽、
   * 按钮 12.5px/600，在最窄的宽屏（1181px）下表格内容宽 992px（.container 1080
   * 减去左右内边距）。由此得到的下限（px）：
   *   分组   82  = Features 58 + 左右内边距 24（表头 Category 57）
   *   标签   92  = 最长单词 75（Trunk-based / Performance / Integration）
   *                   + chip 内边距 14 + 外边距 3；两词的标签（Integration tests）
   *                   在空格处换行，不占额外宽度
   *   操作  108  = Deprecate 64 + 按钮内边距 20 + 格子内边距 24
   *   提交人 106  = Submitted by 82 + 24
   * 按这些下限往上取整到百分比：分组 9%、标签 10%、操作 11%、提交人 11%。
   * 之前这里是「分类 6% / 标签 6% / 操作 10%」——那是按「功能 / 基础项 / 关闭」
   * 这样的两三个字标定的，英文一换（Category 57px、Baseline 56px、Turn off 64px）
   * 就放不下：固定布局下浏览器不会为了内容加宽列，nowrap 的内容直接画到邻列上。
   *
   * 标签列没有按最长的那两三个标签（Integration tests 118px = 16%）去留宽度：
   * 那会把正文列从 54% 压到 40% 以下，而 86 个标签里 90% 都在 20px 以内。
   * 代价是最长的少数几个标签在列里换行（换行不压列，比压列好）。
   *
   * 正文列是这张表里唯一一段长文本，其余各列都是短词或一两个按钮。
   * 所以正文列必须是最宽的一列，且明显宽于标题列：标题撑到三行、
   * 正文被压成一条缝的时候，读者每读一条都要来回找行首。
   */
  /* 公开页：编号不再是独立列（它是标题的副标题），正文列最宽 */
  .item-table[data-variant="public"] .col-title { width: 22%; }
  .item-table[data-variant="public"] .col-content-cell { width: 48%; }
  .item-table[data-variant="public"] .col-group { width: 9%; }
  .item-table[data-variant="public"] .col-tags { width: 10%; }
  .item-table[data-variant="public"] .col-actions { width: 11%; }

  /* 审核页：提交人 + 审核动作，没有状态列也没有时间列 */
  .item-table[data-variant="review"] .col-title { width: 20%; }
  .item-table[data-variant="review"] .col-content-cell { width: 38%; }
  .item-table[data-variant="review"] .col-group { width: 9%; }
  .item-table[data-variant="review"] .col-tags { width: 10%; }
  .item-table[data-variant="review"] .col-email { width: 12%; }
  .item-table[data-variant="review"] .col-actions { width: 11%; }

  /* 后台条目库：七列，正文列仍然最宽 */
  .item-table[data-variant="library"] .col-title { width: 18%; }
  .item-table[data-variant="library"] .col-content-cell { width: 33%; }
  .item-table[data-variant="library"] .col-group { width: 9%; }
  .item-table[data-variant="library"] .col-tags { width: 10%; }
  .item-table[data-variant="library"] .col-email { width: 11%; }
  .item-table[data-variant="library"] .col-time { width: 8%; }
  .item-table[data-variant="library"] .col-actions { width: 11%; }

  .item-table[data-variant="users"] .col-email { width: 60%; }
  .item-table[data-variant="users"] .col-role { width: 16%; }
  .item-table[data-variant="users"] .col-time { width: 24%; }

  /* 我的条目：七列。编号整行不断（13 位编号断在中间会被读成两个编号），
     标题最宽，其余都是短列——之前这张表没挂 data-variant，
     是全站唯一一张没有列宽保证的表，1181–1280px 区间最容易把行操作挤出可视区。 */
  .item-table[data-variant="mine"] .col-no { width: 14%; }
  .item-table[data-variant="mine"] .col-title { width: 30%; }
  .item-table[data-variant="mine"] .col-group { width: 9%; }
  .item-table[data-variant="mine"] .col-tags { width: 14%; }
  .item-table[data-variant="mine"] .col-official { width: 9%; }
  .item-table[data-variant="mine"] .col-time { width: 10%; }
  .item-table[data-variant="mine"] .col-actions { width: 14%; }
}

/* 编号必须整行显示：13 位编号断在中间会让人读成两个编号 */
.item-no {
  white-space: nowrap;
  font-size: 12px;
}

/*
 * 编号作为标题的副标题。
 *
 * 宽屏：单独占标题格的第二行——标题本身占满第一行，编号不与标题抢横向空间。
 * 窄屏（卡片行）：跟在标题右侧同一行，卡片本来就是一格一行，再多占一行纯浪费高度；
 * 放不下时 flex-wrap 自动折到下一行，不会把标题挤变形。
 */
.cell-title-box {
  display: block;
}

.cell-title-box .cell-title-no {
  display: block;
  margin-top: 3px;
  color: var(--muted);
}

/* 短文案列必须整行显示：分组只有两个字，被压成竖排就完全读不出来了 */
.cell-group {
  /* 不整块 nowrap：分组名是「一个词」（功能 / Features / Platform），
     列窄时 nowrap 会让它压到标签列上。「功能」这种两字中文竖排的问题由列宽
     保证——分组列按词典里最长的那个名字标定（见宽屏列宽那一段）。 */
  overflow-wrap: break-word;
  font-weight: 600;
  color: var(--text-soft);
}

.cell-time {
  /* 时间允许在日期与时刻之间的空格处断行：一列放不下整串时就分两行，
     不靠 nowrap 硬撑（那会让最后一列顶出表格边框） */
  color: var(--text-soft);
  font-size: 12.5px;
}

/* 邮箱是整串无空格的字符：不加这条，一个长邮箱就能把后面的列全部挤出可视区 */
.cell-email {
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--text-soft);
  overflow-wrap: anywhere;
  word-break: normal;
}

.cell-title {
  font-weight: 600;
}

.cell-sub {
  color: var(--muted);
  font-size: 12.5px;
}

/*
 * 正文就是生成文档时写进去的那段条文：整段展示，不截断也不做「摘要 + 展开」。
 * 摘要会变成会过时的第二份内容——页面上出现两种说法，读者就得猜哪一份是规范。
 * 页面长度由分页保证（每页 10 条），不由截断保证。
 */
.cell-content {
  color: var(--text-soft);
  white-space: pre-line;
  line-height: 1.75;
}

/* 缺译文的显式标注：斜体加灰，和正常正文一眼能分开 */
.missing {
  color: var(--muted);
  font-style: italic;
  font-weight: 400;
}

.cell-expand {
  margin-top: 6px;
}

.cell-detail {
  margin-top: 8px;
  border-top: 1px dashed var(--border);
  padding-top: 8px;
}

.cell-full {
  margin: 0;
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.75;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--text-soft);
  max-height: 320px;
  overflow: auto;
}

.actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

/* 操作列里的按钮按「一列塞得下两三行」来定尺寸：
   四个动作（编辑 / 通过 / 拒绝 / 删除）竖着排四行会把行高撑到别处读不下去 */
.col-actions .btn {
  padding: 5px 10px;
  font-size: 12.5px;
}

/* 被用户关掉的条目：整行压暗，而不是从表里删掉。
   删掉的话用户就没法在这里找回来，也就永远不知道自己关掉了什么。
   压暗只降到「还能看清正文」的程度——压到看不清就成了另一种丢失。 */
.item-table tbody tr.is-off td {
  opacity: 0.62;
}

/* --------------------------- 筛选区 / 分页条 ---------------------------- */

/* 条目库：宽屏左边栏 + 右边全部条目。
   边栏与表格**各自独立滚动**——筛选条件与筛选结果是同一次决策的两半，
   滚表格时不该把决策的那一半滚走。

   边栏 sticky 而不是 fixed：sticky 保留了在文档流里的位置，
   页脚与页脚的间距照常成立；fixed 会把边栏从流里摘出去，
   后面得手动补一段占位高度，而那段占位高度在边栏收起时要跟着变。 */
.lib-layout {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  align-items: start;
  gap: 20px;
}

.lib-side {
  position: sticky;
  top: calc(var(--nav-h, 0px) + 20px);
  max-height: calc(100dvh - var(--nav-h, 0px) - 40px);
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 16px 46px;
  box-shadow: var(--shadow-sm);
}

.lib-side-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.lib-side-title {
  min-width: 0;
}

.lib-side-title h1 {
  font-size: 17px;
  margin: 0 0 6px;
}

.lib-side-subtitle {
  margin: 10px 0 0;
  line-height: 1.6;
}

/* 三个筛选竖排。竖排而不是并排，是因为边栏只有 260px——
   并排的话每个框只剩 60px，「全部分类」四个字都放不下。 */
.lib-filters {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.lib-filter {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}

.lib-filter > select,
.lib-filter > #level-picker {
  width: 100%;
  min-width: 0;
}

/* 智力等级选择器在边栏里只需要那个 <select>。
   common.js 的 renderLevelSelect 会包一层 .level-picker（竖排 flex + 标签 + 提示），
   留着它，这一格就成了 .lib-filter 的第二个子项而不是那个 select 本身，
   于是下拉框与上面两个错开一行。让它退成透明（display: contents），
   盒子消失，select 直接落进 .lib-filter 的框位。 */
.lib-filter .level-picker {
  display: contents;
}

/* .level-picker.compact 给 .level-select 设了 max-width: 240px，
   那条规则的选择器比下面这条更具体（两个类 + 一个类），
   所以这里必须同样带上 .level-picker 才能覆盖它。 */
.lib-filter .level-picker .level-select {
  max-width: none;
}

.filter-label {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-soft);
  white-space: nowrap;
}

/* 收起按钮：固定在边栏左下角。
   收起的边栏只剩一条竖条，标题与筛选都放不进去，
   而按钮跟着一起藏起来的话，收起之后就再也展不开了。 */
.lib-side-toggle {
  position: absolute;
  bottom: 12px;
  left: 16px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-soft);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  padding: 5px 9px;
  max-width: calc(100% - 32px);
  overflow: hidden;
  white-space: nowrap;
}

.lib-side-toggle:hover {
  background: var(--neutral-soft);
  color: var(--text);
}

.lib-side {
  position: sticky;
}

/* 收起态：边栏收成一条竖条，只留展开按钮。
   44px 是触控目标的最小宽度——这个按钮是这一状态下**唯一**能展开边栏的入口，
   比它更窄的话在触摸设备上就点不中了。 */
.lib-layout.is-collapsed {
  grid-template-columns: 44px minmax(0, 1fr);
}

.lib-layout.is-collapsed .lib-side {
  padding: 10px 0 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.lib-layout.is-collapsed .lib-side > *:not(.lib-side-toggle) {
  display: none;
}

.lib-layout.is-collapsed .lib-side-toggle {
  position: static;
  /* 竖排文字：竖条只有 44px 宽，横排的「收起边栏」四个字放不下。
     writing-mode 让它竖着排，而不是截成「收起…」。
     max-width 必须在这里清掉：上面那条 calc(100% - 32px) 是按 260px 的
     边栏算的余量，落到 44px 的竖条上只剩 12px，按钮被压成一条缝——
     而这是收起之后唯一能展开边栏的入口。 */
  writing-mode: vertical-rl;
  width: auto;
  max-width: none;
  max-height: 140px;
  padding: 8px 5px;
}

.lib-main {
  min-width: 0;
}

/* 窄屏：边栏拆成顶部一条三行筛选，标题退回内容区。
   1000px 这个断点同时是「边栏 260px + 表格至少 700px」的下限——
   表格有编号、正文、分类、标签、操作五列，正文那一列最窄也要 400px 才读得下去。 */
@media (max-width: 1000px) {
  .lib-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
  }
  .lib-side,
  .lib-layout.is-collapsed .lib-side {
    position: sticky;
    top: var(--nav-h, 0px);
    z-index: 15;
    max-height: none;
    overflow: visible;
    padding: 10px 14px;
    /* 窄屏没有「收起」这回事：边栏本来就只剩一条，
       再收一次就只剩一个按钮，而那与直接不显示没有区别。 */
  }
  .lib-layout.is-collapsed {
    grid-template-columns: minmax(0, 1fr);
  }
  .lib-side-toggle,
  .lib-layout.is-collapsed .lib-side-toggle {
    display: none;
  }
  .lib-layout.is-collapsed .lib-side > *:not(.lib-side-toggle) {
    display: revert;
  }
  .lib-side-title h1 {
    font-size: 15px;
    margin: 0;
  }
  .lib-side-subtitle {
    display: none;
  }
  /* 三行，每行「左名右框」，名字列宽固定——三个框因此仍在同一条竖线上。 */
  .lib-filters {
    margin-top: 10px;
    padding-top: 10px;
  }
  .lib-filter {
    display: grid;
    grid-template-columns: 5.5em minmax(0, 1fr);
    align-items: center;
    gap: 8px;
  }
  .filter-label {
    font-size: 13px;
  }
}

.filter-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 14px;
}

.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.pager-summary {
  flex: 1 1 auto;
  min-width: 0;
}

.pager-controls {
  display: flex;
  gap: 8px;
  flex: 0 0 auto;
}

.pager-controls .btn {
  min-height: 40px;
}

.pager-controls .btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* --------------------------- 标签 / 筛选器 ------------------------------ */

.tabs {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.tab {
  padding: 6px 13px;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-soft);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}

.tab:hover {
  background: var(--neutral-soft);
}

.tab.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

.tag-chip {
  display: inline-block;
  padding: 1px 7px;
  /* 5px 的右间距在 chip 列宽下不够：两个会连成「默认生效始终开启」，
     读的人分不清是一个还是两个。5px 加上 chip 自身的内边距，间隙够看清边界。 */
  margin: 1px 5px 1px 0;
  border-radius: 5px;
  background: var(--neutral-soft);
  color: var(--text-soft);
  font-size: 11.5px;
  font-family: var(--mono);
  /* 标签是「一两个词」的分类名：先在词边界换行（Integration / tests 分两行），
     单词自己都放不下时才在词内断。绝不整块 nowrap——列窄时 nowrap 会把标签
     画到邻列上（英文界面压住正文列就是这么来的）。
     「ecommerce 被拆成 ecommerc + e」这类问题由列宽保证：标签列按词典里
     较长的那些标签标定宽度，见宽屏列宽那一段。 */
  white-space: normal;
  overflow-wrap: break-word;
}

/* ------------------------------- 弹窗 ---------------------------------- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(20, 28, 44, 0.42);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 32px 16px;
  overflow-y: auto;
  z-index: 60;
}

.modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  width: 100%;
  max-width: 760px;
  padding: 22px;
}

.modal h3 {
  font-size: 17px;
  margin-bottom: 4px;
}

/* ----------------------------- 状态提示 -------------------------------- */

.status {
  font-size: 13px;
  color: var(--muted);
}

.status.error {
  color: var(--danger);
}

.status.ok {
  color: var(--success);
}

/* 警告：不是失败，但用户必须知道（例：跳过了没有当前语种译文的条目） */
.status.warn {
  color: var(--warn);
  font-weight: 600;
}

.notice {
  padding: 11px 14px;
  border-radius: var(--radius);
  font-size: 13.5px;
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text-soft);
}

/* 导入失败明细这类多行文本需要保留换行 */
.notice.pre {
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 220px;
  overflow-y: auto;
}

.notice.error {
  background: var(--danger-soft);
  border-color: #f2cbc7;
  color: var(--danger);
}

.notice.ok {
  background: var(--success-soft);
  border-color: #c3e6d3;
  color: var(--success);
}

.notice.warn {
  background: var(--warn-soft);
  border-color: #f2ddb8;
  color: var(--warn);
}

.hidden {
  display: none !important;
}

/* ------------------------------- 页脚 ---------------------------------- */

.footer {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 20px 40px;
  color: var(--muted);
  font-size: 12.5px;
}

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

@media (max-width: 720px) {
  body {
    font-size: 14.5px;
  }

  .container {
    padding: 16px 14px 60px;
    gap: 14px;
  }

  .card {
    padding: 16px;
    border-radius: var(--radius);
  }

  .hero h1 {
    font-size: 21px;
  }

  .grid-2 {
    grid-template-columns: 1fr;
  }

  .nav-inner {
    padding: 10px 14px;
    gap: 8px;
  }

  .nav-links {
    width: 100%;
    margin-left: 0;
    gap: 4px;
  }

  .nav-link {
    padding: 6px 10px;
    font-size: 13px;
  }

  .user-select-name {
    max-width: 110px;
  }

  .modal {
    padding: 16px;
  }

  .check-item {
    padding: 10px;
  }
}

/* ------------------------- 窄屏：表格转成卡片行 --------------------------- */

/*
 * 断点定在 1100px：条目库最宽的一张表有九列（含状态、提交人、更新时间、操作），
 * 到这个宽度以下与其让用户横向拖一条看不见的表格，
 * 不如把每一行变成一张卡片——列名从 data-label 取（渲染时写进每个单元格），
 * 列宽规则在这里全部作废。
 */
@media (max-width: 1180px) {
  table,
  table tbody,
  table tr,
  table td {
    display: block;
    width: auto;
  }

  table thead {
    display: none;
  }

  table tbody tr {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    margin-bottom: 10px;
    padding: 6px 12px;
    background: var(--surface);
  }

  table tbody tr:last-child {
    margin-bottom: 0;
  }

  table tbody td {
    display: grid;
    grid-template-columns: 84px minmax(0, 1fr);
    align-items: start;
    gap: 10px;
    padding: 6px 0;
    border-bottom: 1px dashed var(--border);
  }

  table tbody td::before {
    content: attr(data-label);
    color: var(--muted);
    font-size: 12px;
    line-height: 1.7;
    white-space: nowrap;
  }

  table tbody td:last-child {
    border-bottom: none;
  }

  /* 标题与内容自带含义，卡片里再挂一个"标题""内容"标签只是噪音 */
  table tbody td.col-title::before,
  table tbody td.col-content-cell::before {
    display: none;
  }

  table tbody td.col-title,
  table tbody td.col-content-cell {
    grid-template-columns: minmax(0, 1fr);
  }

  /* 窄屏：编号回到标题右侧同一行（宽屏的「第二行」在卡片里只是多占一行高度） */
  table tbody td.col-title .cell-title-box {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px;
  }

  table tbody td.col-title .cell-title-no {
    display: inline-block;
    margin-top: 0;
  }

  table tbody tr:hover td {
    background: transparent;
  }

  .filter-grid {
    grid-template-columns: 1fr;
  }

  .pager {
    flex-direction: column;
    align-items: stretch;
  }

  .pager-controls {
    justify-content: space-between;
  }

  .pager-controls .btn {
    flex: 1 1 0;
    min-height: 44px;
  }

}

/* ---------------------------------------------------------------------------
 * 触控目标不小于 44 × 44 像素
 * ---------------------------------------------------------------------------
 * 判据是「用不用手指」，不是「屏幕窄不窄」。
 *
 * 原来这段规则挂在 @media (max-width: 1180px) 里，于是 iPad 横屏（1181–1366px）、
 * Surface、4K 触屏这些**宽屏触摸设备**上，表格操作列、标签页、导航下拉框
 * 全都退回桌面端的紧凑尺寸（约 31–33px）——按在手指上很难点中。
 * 窄屏只是手指操作的一种，触屏可以是宽的。
 *
 * 规则用 min-height 抬高控件，开关另用伪元素扩（见下）：
 * 开关本体是 44×25 的小控件，min-height 会把它撑成一个圆角方块；
 * 伪元素让命中区域够大，而它自己的样子不变。
 * --------------------------------------------------------------------------- */
@media (any-pointer: coarse) {
  .btn.small,
  .col-actions .btn,
  .tab,
  .lang-tab,
  .lang-select-trigger,
  .user-select-trigger,
  .lang-select-option,
  .user-menu-item,
  .nav-link,
  .brand {
    min-height: 44px;
  }

  /* 开关的命中区用伪元素扩，不用 min-height 撑变形 */
  .switch::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 44px;
    transform: translateY(-50%);
  }

  /* 必选项的控件：与全站其他触控目标同一套尺寸规则 */
  .direct-select {
    min-height: 44px;
  }

  .direct-check {
    width: 44px;
    height: 44px;
  }

  /* 逐条调整页的分栏标签页：与全站其他触控目标同一套尺寸规则 */
  .split-tab {
    min-height: 44px;
  }
}

/* 尊重「减少动效」的系统设置：过渡与位移动画一律去掉。
   动效本身不多，但对动效敏感的人，一次 0.15s 的过渡也足以引起不适。 */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   逐条调整页（/tune）：左右两列对照
   ========================================================================== */

/* 这一页比其它页宽：两列并排时各自要放得下一条完整正文，
   挤在 1080px 里每列只剩 500 出头，长条目就得折成五六行。
   放宽的是这一页，不动 .container —— 其它页的单列宽度是有理由的。 */
.container-wide {
  max-width: 1440px;
}

.split-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.split {
  display: grid;
  /* 3:7 是默认值；--split-left / --split-right 由拖动分隔条改写。
     用 grid-template-columns 而不是 flex-basis：两列各自独立滚动，
     flex 下 flex-basis 会被内容最小宽度顶开，长正文一多就再也拖不动了。 */
  grid-template-columns: var(--split-left, 3fr) 10px var(--split-right, 7fr);
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
  /* 撑满所在卡片的剩余高度，而不是给一个 vh：
     整页固定高度之后，68vh 会让这一块比视口还高，
     于是页面又出现外层滚动条——那正是要消掉的东西。 */
  flex: 1;
  min-height: 0;
}

.split-pane {
  display: flex;
  flex-direction: column;
  min-width: 0; /* grid 子项默认 min-width:auto，长正文会把整列撑破 */
  min-height: 0;
}

.split-pane-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-alt);
}

.split-pane-title {
  font-weight: 600;
  font-size: 13.5px;
}

/* 两列各自滚动。高度定在 .split-pane 上，两边等高，
   「左栏第 N 条」与「右栏第 N 条」才可能在同一屏出现——
   这是左右对应能被看见的前提。 */
.split-scroll {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 10px 12px;
  scroll-behavior: smooth;
}

.split-handle {
  cursor: col-resize;
  background: var(--border);
  position: relative;
  touch-action: none;
}
.split-handle::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 2px;
  height: 34px;
  border-radius: 2px;
  background: var(--border-strong);
}
.split-handle:hover,
.split-handle:focus-visible {
  background: var(--primary-soft);
}
.split-handle:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}
/* 拖动时给整页加这个类：光标与选中行为都换掉，
   否则拖到一半会选中文本，鼠标一松手就选中了一大片正文。 */
body.is-resizing {
  cursor: col-resize;
  user-select: none;
}

/* 左栏一行 = 一条条目 */
.tune-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  margin-bottom: 8px;
}
.tune-row.is-off {
  /* 关掉的条目压暗但不隐藏：它仍然占一行，用户能把它开回来。
     隐藏掉的话「我刚关掉的那条去哪了」要靠记忆才能回答。 */
  opacity: 0.55;
}
.tune-row.is-active {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px var(--primary-soft);
}

.tune-row-title {
  font-size: 13.5px;
  font-weight: 600;
  /* 与 .tag-chip 同一个属性：必要时断词，但不像 anywhere 那样改变最小内容宽度——
     标题很长也不该把分栏那一列的宽度顶开。 */
  overflow-wrap: break-word;
}
.tune-row-no {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--muted);
}
.tune-row-band {
  min-width: 96px;
  max-width: 140px;
}

.tune-group {
  margin: 14px 0 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-soft);
  letter-spacing: 0.02em;
}

/* 右栏一块 = 一条条目在文档里的样子 */
.tune-block {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-alt);
  margin-bottom: 8px;
  scroll-margin-top: 8px;
}
.tune-block.is-active {
  border-color: var(--primary);
  background: var(--primary-soft);
}
.tune-block-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}
.tune-block-title {
  font-size: 12.5px;
  font-weight: 600;
  overflow-wrap: break-word; /* 同 .tune-row-title */
}
.tune-block-band {
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
}
.tune-block-body {
  font-size: 13px;
  line-height: 1.7;
  color: #22304a;
  white-space: pre-wrap;
  word-break: break-word;
}
.tune-block-body:empty::after {
  content: attr(data-empty);
  color: var(--muted);
}

/* hidden 属性靠 UA 样式表的 `[hidden] { display: none }` 生效，
   而下面这条 .split-tabs 的 display 优先级更高——不显式写这一条，
   宽屏下（标签页本该收起）它会照样显示出来。 */
.split-tabs[hidden] {
  display: none;
}

.split-tabs {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.split-tab {
  border: 0;
  background: var(--surface);
  padding: 7px 14px;
  font-size: 13px;
  cursor: pointer;
}
.split-tab.is-active {
  background: var(--primary-soft);
  color: var(--primary-dark);
  font-weight: 600;
}

/* 窄屏：两列改标签页。
   断点 900px 与 .split 的默认并排布局一致：低于它时 grid 那套完全不生效，
   改成 display:block 由标签页决定显示哪一列。
   那个「可拖动的分隔条」在窄屏没有意义（只有一列可见），一起收起来。 */
@media (max-width: 900px) {
  .split {
    display: block;
  }
  .split-handle {
    display: none;
  }
  .split-pane {
    height: auto;
    max-height: none;
  }
  /* 只有选中的那一列占满，选中的 pane 才滚动 */
  .split-pane[hidden] {
    display: none;
  }
  .split-scroll {
    max-height: 62vh;
  }
}

/* ==========================================================================
   主页工作台（body[data-page="home"]）
   ==========================================================================

   这一页的结构与其它页不同：它不是「一篇文章」，而是一块工作台。
   整页不滚动，每一块自己滚。

   为什么不能靠一列卡片往下堆：
   分析结果的长度由需求决定——三条需求出五条清单，一百条需求出七十条。
   页面高度因此随内容变化，同一个操作（「看完清单去点生成」）在不同需求下
   要滚的屏数不同。改成左右两栏各自滚动之后，那一步永远是「看一眼头部」。

   高度用 100dvh 而不是 100vh：移动端浏览器地址栏收放会改变视口高度，
   100vh 会让底栏被地址栏盖住一截，dvh 跟着实际可见区域走。
   min-height 兜底是为了极矮的窗口（横屏手机、外接键盘）——
   那时整页改为可滚动，宁可多滚一点也不能让控件被压到看不见。 */

/* 整页固定高度：body 不滚动，滚动发生在每一栏内部 */
body[data-page="home"] {
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* 导航栏在固定高度布局里不再需要吸顶——它本来就在流的最前面，
   而 body 不滚了，sticky 只会在某些浏览器里留下一条 1px 的缝。 */
body[data-page="home"] .nav {
  position: static;
  flex: none;
}

.home-main {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  max-width: 1600px;
  width: 100%;
  margin: 0 auto;
  padding: 14px 20px 16px;
  gap: 12px;
}

/* 页面身份：一行，不是一张卡片。
   这一页的可视高度是按视口算的（body 固定 100dvh、整页不滚），
   一张带标题与长副标题的卡片会吃掉 100 多像素——
   而那 100 多像素本来是清单的。 */
.home-head {
  flex: none;
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin: 0;
}

.home-head h1 {
  font-size: 17px;
  margin: 0;
  white-space: nowrap;
}

.home-head p {
  margin: 0;
  min-width: 0;
}

/* --------------------------- 第一层：起点标签 --------------------------- */

.top-tabs {
  display: flex;
  gap: 4px;
  flex: none;
  border-bottom: 1px solid var(--border);
}

.top-tab {
  border: 0;
  background: transparent;
  padding: 9px 16px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.top-tab:hover {
  color: var(--text);
}

.top-tab.is-active {
  color: var(--primary-dark);
  border-bottom-color: var(--primary);
}

/* 三态偏好里的「当前选中那一个」。
   三态不是一次开关的两端，四个按钮长得一样的话读者看不出现在处在哪一态——
   而「我以为设了始终开启」与「真的设了」在结果上差着整整一条规范。 */
.btn.is-active {
  background: var(--primary-soft);
  border-color: var(--primary);
  color: var(--primary-dark);
}

/* 未选中的标签不置灰到底（--muted 对正文尺寸只有 4.6:1，
   再压一档就低于 4.5:1），所以保持 --text-soft，只靠下边框区分。 */
.top-panel {
  flex: 1;
  min-height: 0;
  /* 竖排：栏切换条（窄屏才有，但元素一直在）+ 分屏区。
     分屏区要 flex:1 而不是 height:100%——这一格现在有两个子元素，
     height:100% 会让分屏区与切换条加起来超过格子高度，底栏被顶出去。 */
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.top-panel[hidden] {
  display: none;
}

/* ---------------------------- 第二层：左右分屏 --------------------------- */

/* grid 而不是 flex：两栏各自独立滚动，且 grid-template-columns 的
   minmax(0, …) 能压住长条目的最小内容宽度——flex-basis 会被内容顶开，
   一条长正文就能把整栏撑到把另一栏挤没。
   默认 3:7：右栏是清单与结果，它的行数由需求决定，是这一页真正会长的一栏。
   比例写在 --ws-left / --ws-right 上，由 tune.js 那样的一条拖动条改写
   （见 app.js 的 setupSplit）；不给变量值时用这里的 3fr / 7fr 兜底。 */
.workspace {
  display: grid;
  grid-template-columns: var(--ws-left, 3fr) 10px var(--ws-right, 7fr);
  align-items: stretch;
  gap: 0;
  flex: 1;
  min-height: 0;
}

/* 分隔条：可拖动。宽度写在 grid 的第二列（10px）里，
   两边各有 5px 的可拖区域——10px 整条都是热区。 */
.ws-handle {
  cursor: col-resize;
  background: var(--border);
  position: relative;
  touch-action: none;
}
.ws-handle::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 2px;
  height: 34px;
  border-radius: 2px;
  background: var(--border-strong);
}
.ws-handle:hover,
.ws-handle:focus-visible {
  background: var(--primary-soft);
}
.ws-handle:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}
/* 拖动时给整页加这个类：光标与选中行为都换掉，
   否则拖到一半会选中文本，鼠标一松手就选中了一大片正文。 */
body.is-resizing {
  cursor: col-resize;
  user-select: none;
}

.ws-pane {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.ws-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex: none;
  padding: 0 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-alt);
  min-height: 46px;
}

.ws-head-title {
  font-size: 13.5px;
  font-weight: 600;
}

/* 第二层的标签（需求 / 逐项确认、清单 / 生成结果） */
.ws-tabs {
  display: flex;
  gap: 2px;
  flex-wrap: wrap;
}

.ws-tab {
  border: 0;
  background: transparent;
  padding: 12px 12px;
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.ws-tab:hover {
  color: var(--text);
}

.ws-tab.is-active {
  color: var(--primary-dark);
  border-bottom-color: var(--primary);
}

/* 「还没答完」的计数挂在标签上：它是「逐项确认」这一栏唯一需要被提醒的事，
   而这一栏默认是收起的那一栏——折叠起来的东西如果只在展开后才提示，
   用户永远看不到。 */
.ws-tab-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 11.5px;
  font-weight: 700;
}

.ws-tab-badge[hidden] {
  display: none;
}

/* 操作条：贴在清单上方，随清单一起滚走——它是这一屏的「当前动作」，
   滚到第 40 条时它不在视野里是对的（那时候用户在读条目，不在准备生成）。 */
.ws-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  flex: none;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}

.ws-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 14px;
}

.ws-scroll[hidden] {
  display: none;
}

/* 清单里的分组标题吸在滚动区顶部：清单有几十条，滚到第 30 条时
   「这一段属于哪一组」是唯一真正丢了的信息，而它是这一屏唯一
   值得占位置的东西。 */
.ws-scroll [data-ws-panel="list"] .group-head {
  position: sticky;
  top: -14px;
  z-index: 2;
  background: var(--surface);
  padding: 6px 0 4px;
  margin-bottom: 0;
}

/* 空状态文案：分析之前 / 生成之前各有一条。
   以前的做法是「什么都不显示」——空白的右半屏看起来像页面坏了。 */
.empty-hint {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 13px;
}

.empty-hint[hidden] {
  display: none;
}

/* 预览在这一栏里自己滚，所以外层的 max-height 必须去掉：
   620px 的上限加上外层的滚动区会出现两层滚动条，
   而内层那条在不滚动时只是白白吃掉一段高度。 */
.ws-scroll .preview {
  max-height: none;
  overflow: visible;
}

/* 极矮窗口（横屏手机等）：整页改为可滚动。
   宁可多滚一点，也不能让某一栏被压到看不见——
   高度归零的滚动区在触摸设备上会连内容一起吞掉。 */
@media (max-height: 480px) {
  body[data-page="home"] {
    height: auto;
    min-height: 100dvh;
    overflow: visible;
  }
  .home-main {
    min-height: 0;
  }
  .top-panel {
    min-height: 70vh;
  }
  .ws-pane {
    min-height: 320px;
  }
}

/* 窄屏：两栏并排的话每栏只剩一百多像素，一行正文折成三四行，两栏都读不下去。
   所以改成一栏，切换由第三层标签承担（见 .ws-pane-switch）。 */
@media (max-width: 900px) {
  body[data-page="home"] {
    height: auto;
    min-height: 100dvh;
    overflow: visible;
  }
  .home-main {
    padding: 12px 14px 20px;
  }
  .workspace {
    /* 窄屏没有分隔条：一次只看一栏，宽度由标签决定，没有可拖的余地。
       那一档里 .ws-handle 被收起来，grid 退回两列。 */
    grid-template-columns: minmax(0, 1fr);
  }
  .ws-handle {
    display: none;
  }
  .ws-pane {
    /* 固定一段高度而不是让内容撑开：撑开的话这一栏会有几百上千像素高，
       切到另一栏时用户又得滚回顶部。两栏的高度一致，切换才不用重新找位置。 */
    height: 72vh;
    min-height: 380px;
  }
  .ws-scroll {
    /* 移动端地址栏收放会改变 dvh，用它做上限更贴近实际可见区域 */
    max-height: 100%;
  }
  .top-tab {
    padding: 10px 12px;
  }
}

/* 窄屏专用的栏切换：宽屏并排时它没有意义（两栏都看得见），
   收起来而不是 display:none —— 那会让读屏软件与 Tab 键序把它算进去，
   而它在这时是纯装饰。 */
.ws-pane-switch {
  display: none;
  gap: 4px;
  flex: none;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

@media (max-width: 900px) {
  .ws-pane-switch {
    display: flex;
  }
  .ws-pane-switch .top-tab {
    flex: 1;
  }
  /* 一次只看一栏：并排时每栏只剩一百多像素 */
  .workspace[data-ws-mode] .ws-pane[hidden] {
    display: none;
  }
}

/* ==========================================================================
   逐条调整页（/tune）—— 与主页同一套「整页不滚动」结构
   ==========================================================================

   这一页以前是三张卡片竖排（标题 / 档位 / 分屏），页面本身要滚，
   而分屏内部还要再滚一层。嵌套滚动是最难用的那种：鼠标滚轮在两层之间
   归属不明，滚一下不知道动了哪一层，用户于是先花十几秒搞清楚「这里怎么滚」。

   现在：body 固定 100dvh，页面不滚，两栏各自滚。
   容器链上每一级都要 min-height: 0（漏一级，内容就把整页顶出视口）。 */
body[data-page="tune"] {
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

body[data-page="tune"] .nav {
  position: static;
  flex: none;
}

.tune-main {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px 20px 16px;
}

.tune-head {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.tune-head h1 {
  font-size: 17px;
  margin: 0;
}

/* 顶部操作条：这一页唯一的操作区。
   下面两栏都是内容，内容里不放任何按钮——
   滚到哪里都还在这一条上，而「保存 / 复制 / 下载」都不该是某一栏的。 */
.tune-bar {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px 20px;
  flex-wrap: wrap;
  padding: 10px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.tune-bar-band {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  min-width: 0;
}

.tune-bar-band .level-picker {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.tune-bar-band .level-picker-label {
  white-space: nowrap;
}

/* 档位说明占满一整行：它讲的是「这个档位该怎么用」，
   挤在选择器右边会被读成下拉框的一部分。 */
.tune-bar-band #band-note {
  flex: 1 1 100%;
  margin: 0;
  line-height: 1.5;
}

.tune-bar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* 档位卡不再是卡片，提示挂在页面最上面（见 tune.js 的 needAnalyze 分支） */
.split-card {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 12px 14px 14px;
  overflow: hidden;
}

.split-toolbar {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

/* 「同步滚动」开关：它好用，但代价是用户完全失去
   「我在读第几条」的控制——那一列会自己跑。所以默认关。 */
.link-check {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  color: var(--muted);
  cursor: pointer;
  min-height: 24px;
}

.link-check input[type="checkbox"] {
  width: 15px;
  height: 15px;
  margin: 0;
  accent-color: var(--primary);
  cursor: pointer;
}

/* 极矮窗口（横屏手机等）：退回整页可滚动。
   高度归零的滚动区在触摸设备上会连内容一起吞掉。 */
@media (max-height: 480px) {
  body[data-page="tune"] {
    height: auto;
    min-height: 100dvh;
    overflow: visible;
  }
  .split-card {
    min-height: 70vh;
  }
}

/* 窄屏：两列并排的话每列只剩一百多像素，一行正文折成三四行，两列都读不下去。
   所以改成一栏，切换由标签页承担。 */
@media (max-width: 900px) {
  body[data-page="tune"] {
    height: auto;
    min-height: 100dvh;
    overflow: visible;
  }
  .tune-main {
    padding: 12px 14px 20px;
  }
  .split {
    /* 固定一段高度而不是让内容撑开：撑开的话这一栏会有几百上千像素高，
       切到另一栏时用户又得滚回顶部。两栏高度一致，切换才不用重新找位置。 */
    height: 68vh;
    min-height: 380px;
    flex: none;
  }
  .split-scroll {
    max-height: 100%;
  }
}

/* ==========================================================================
   「逐条调整」按钮
   ==========================================================================

   它不是与「生成 AGENTS.md」平级的另一个选项：生成是终点，
   逐条调整是中途换一种做法。做成同款并排按钮时，读的人会以为
   「两个里挑一个」——而实际是「先用这个，不满意再走那一个」。

   所以：次要样式 + 排在生成之后 + 视觉上退到操作条末尾之外，
   前面用一条细竖线与主操作分开。 */
.btn-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 0;
  background: transparent;
  color: var(--primary-dark);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  padding: 4px 2px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}

.btn-link:hover {
  background: var(--primary-soft);
  text-decoration: underline;
}

.btn-link:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.ws-actions-sep {
  width: 1px;
  align-self: stretch;
  min-height: 18px;
  margin: 0 2px;
  background: var(--border);
}
