/*
 * 测序分析页面专用样式。
 *
 * 站点骨架（.shell/.topbar/.topbar-right/.page-switch/.workspace/
 * .form-section/.field/.primary/.ghost 等）全部来自 styles.css，
 * 因此不改动 styles.css 即可与引物设计页面保持同一套视觉语言。
 * 引物设计页面不会加载本文件。
 */

.seq-workspace .controls {
  /* 测序分析只有两个输入区块，不需要滚动，比引物设计更紧凑 */
  align-self: start;
}

/*
 * 页面用原生 hidden 属性控制显隐，但 .progress / .stat-grid 等元素设了
 * display: flex / grid，其声明的 display 会覆盖 hidden 属性的默认
 * display: none，导致"隐藏"失效。这里显式兜底。
 */
[hidden] {
  display: none !important;
}

.field-hint {
  margin: 0.35rem 0 0;
  font-size: 0.8rem;
  color: var(--muted);
  line-height: 1.5;
}

.field-hint[data-tone="ok"] {
  color: var(--good);
}

.field-hint[data-tone="error"] {
  color: var(--bad);
  font-weight: 600;
}

.field-hint code {
  padding: 0.05rem 0.25rem;
  border-radius: 4px;
  background: var(--accent-soft);
  font-size: 0.95em;
}

.seq-actions {
  display: flex;
  gap: 0.6rem;
  margin-top: 1rem;
}

/* 两个按钮严格等高等宽。
 *
 * styles.css 的 .primary 带 `margin-top: 16px`，那是给"独立成行的主按钮"
 * 用的。在 flex 容器里它会把「开始分析」整体下推，两个按钮因此错位、
 * 看起来大小不同。这里清掉，并把尺寸完全交给 flex 决定。 */
.seq-actions .primary,
.seq-actions .ghost {
  flex: 1;
  width: auto;
  margin-top: 0;
  /* height 用同一值，避免 primary 的 font-weight 760 让行高略高 */
  height: 2.6rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* 状态条：中性信息载体，不是主角。
   成功/警告只用左侧色条 + 文字颜色表示，不整块铺背景色——
   整块绿底会让它比下面的结果表还抢眼，而它只是句提示。

   它与结果标题同处一张 .notes 卡片内，所以不再有外边距和圆角
   （卡片已经提供了），只在下方留一点呼吸空间。 */
.status-bar {
  position: relative;
  margin-top: 12px;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: 8px;
  background: var(--panel-soft);
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--muted);
}

.status-bar[data-tone="ok"] {
  border-left-color: var(--good);
  color: var(--good);
}

.status-bar[data-tone="warn"] {
  border-left-color: var(--warn);
  color: var(--warn);
}

.status-bar[data-tone="error"] {
  border-left-color: var(--bad);
  color: var(--bad);
}

.status-bar[data-tone="error"] {
  border-color: #e6bdb9;
  background: #fbeeed;
  color: var(--bad);
}

.progress {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.8rem;
}

.progress-bar {
  flex: 1;
  height: 6px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--accent);
  transition: width 0.15s ease;
}

.progress-text {
  min-width: 12rem;
  font-size: 0.78rem;
  color: var(--muted);
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(4.5rem, 1fr));
  gap: 0.5rem;
  margin: 0;
}

.stat-grid div {
  padding: 0.55rem 0.4rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-soft);
  text-align: center;
}

.stat-grid dt {
  font-size: 0.7rem;
  color: var(--muted);
}

.stat-grid dd {
  margin: 0.15rem 0 0;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--accent-strong);
  font-variant-numeric: tabular-nums;
}

/* 表格上方的判读范围说明。必须显眼——"哪些位点可信"是判读结果的
   前提条件，藏在脚注里等于没说。 */
/* 说明段落：在 .notes 卡片里，不再自带边框和背景（卡片已经提供了） */
.table-note {
  margin: 0;
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.6;
}

/* 表格容器：给滚动留出口，并防止任何内容把布局撑破。
   表格是 auto 布局，列宽按内容算——详情里的图如果超出可用宽度，
   整张表会被推到几千像素宽，排版全乱。 */
.table-wrap {
  width: 100%;
  max-width: 100%;
  overflow-x: auto;
}

.result-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
  /* 列宽固定为内容/表格宽的较小者，超宽内容不再推挤其他列 */
  table-layout: auto;
}

/* 简约风：只留横向细线，不要竖线、不要斑马纹、不要外框。
   行与行之间靠一条 1px 的浅线分隔就够了，多余的框线只会把表格
   切成一格一格，读起来像电子表格而不是结果清单。 */
.result-table th,
.result-table td {
  padding: 0.6rem 0.7rem;
  border-bottom: 1px solid var(--line-soft);
  text-align: left;
  vertical-align: middle;
}

.result-table thead th {
  position: sticky;
  top: 0;
  /* 表头用面板白而非浅灰：浅灰会读成"斑马纹的一行" */
  background: var(--panel);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
  border-bottom: 1px solid var(--line);
}

.result-table td:nth-child(2),
.result-table td:nth-child(3),
.result-table td:nth-child(4) {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* 悬停只做极轻的提示，不铺色块 */
.result-table tbody tr:hover {
  background: var(--panel-soft);
}

/* 需要复核的行：不加任何视觉标记。
 *
 * 原来用左侧一道色条（inset box-shadow）标记"这行需要人工复核"，
 * 但它带来两个问题：
 *   1. 判据太宽（读码框平移 / 结构变异 / 覆盖不满 / 一致性偏低），
 *      结果大多数克隆都被标上，标记等于没有信息量
 *   2. 棕色细条在密集表格里很扎眼，视觉噪声大于提示价值
 *
 * 需要复核的信息改为在突变列的 title 上悬停查看，数值本身保持原样。 */
.result-table .row-warn td {
  background: transparent;
}

.result-table .row-error td {
  color: var(--bad);
}

/* 无信号样本：仪器没测到数据。
 *
 * 与"分析失败"用不同色调—— 分析失败多半是我们这边的问题（参考选错等），
 * 红色警示；无信号是实验/测序本身没测到，灰色更贴合"这里什么也没有"的
 * 事实，也避免整屏红字看着像出了什么大事。 */
.result-table .row-nosignal td {
  color: var(--muted);
}

.result-table .row-nosignal td:first-child {
  box-shadow: inset 2px 0 0 var(--line-strong);
}

/* ---- 可展开行的交互提示 ----
   原来的 "▸" 太小太淡，第一次用的人不知道能点。
   现在：整行可点 + 左侧有实心的展开按钮 + 悬停时按钮变色。 */
.result-toggle {
  cursor: pointer;
  user-select: none;
}

.result-toggle:hover .caret-box {
  background: var(--accent-soft);
  border-color: var(--accent);
}

.result-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.caret-box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15rem;
  height: 1.15rem;
  margin-right: 0.5rem;
  border: 1px solid var(--line-strong);
  border-radius: 5px;
  background: var(--panel);
  color: var(--muted);
  font-size: 0.7rem;
  line-height: 1;
  vertical-align: -2px;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.result-toggle[aria-expanded="true"] .caret-box {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-strong);
}

.result-toggle[aria-expanded="true"] .caret-icon {
  transform: rotate(90deg);
}

.caret-icon {
  display: inline-block;
  transition: transform 0.15s ease;
}

/* 展开后的详情行：整行作为一个浅色块，视觉上从属于上面的摘要行 */
.detail-row > td {
  padding: 0;
  background: var(--panel-soft);
  border-bottom: 1px solid var(--line);
}


/* 失败原因现在放在「突变」列（原备注列已移除），允许换行不撑高整行 */
.result-table .row-error-msg {
  font-size: 0.8rem;
  line-height: 1.5;
  max-width: 34ch;
}

.mut-none {
  color: var(--good);
  font-weight: 600;
}

/* 一致性 < 95%：不显示具体突变，改提示排查方向。
 *
 * 措辞用「请检查序列」而不是「参考可能不匹配」——前者是行动指引，
 * 后者在 95% 这个阈值上多数情况并不成立（微小的 indel 也会拉低一致性），
 * 容易让人以为真出了问题。 */
.mut-lowconf {
  color: var(--ink-2);
  font-style: normal;
}

/* 一致性偏低时给数值加个视觉标记：原本靠备注文字说明，
   备注列移除后颜色是唯一的提示通道。 */
.result-table .ident-low {
  color: var(--warn);
  font-weight: 600;
}

/* 导出按钮组：放在结果区标题行右侧，与「引物结果」的复制按钮同一位置。
   按钮本身是 .ghost，尺寸由 styles.css 的 .ghost 统一，这里只管排列。 */
.export-bar {
  display: flex;
  gap: 0.6rem;
}

@media (max-width: 720px) {
  .topbar {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.8rem;
  }

  .topbar-right {
    justify-content: flex-start;
  }

  .progress-text {
    min-width: 6rem;
  }
}

/* ---------- 详情行：比对折线图 ---------- */

.detail-toggle {
  cursor: pointer;
  user-select: none;
}

.detail-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.col-name {
  white-space: nowrap;
}

.detail-row > td {
  padding: 0;
  border-bottom: 1px solid var(--line);
}

.detail {
  padding: 0.85rem 0.9rem 1rem;
  background: var(--panel-soft);
  font-size: 0.82rem;
}

.detail-empty {
  margin: 0;
  color: var(--muted);
}

.track-box {
  /* 图永远不撑破单元格。SVG 只有 viewBox、没有 width/height，
     实际尺寸由下面两行决定：宽度铺满可用空间，高度写死不随宽度变。 */
  width: 100%;
  max-width: 100%;
  overflow: hidden;
}

.tb {
  display: block;
  width: 100%;
  /* 高度固定：不写 height:auto 是有意的。等比缩放会在窄屏把图
     压到十几像素高，两条线糊在一起；这里配合 preserveAspectRatio="none"
     只压横向、纵向保持原比例高度，代价是窄屏下每个位不足 1px——
     但这张图的目的本来就是看趋势，不是逐位取数。 */
  height: 26px;
  max-width: 100%;
}

/* 横坐标刻度：画在 SVG 之外的 HTML 层。
   SVG 内的 <text> 会随 viewBox 一起被压缩（8px 字实际只剩 1.8px，
   完全看不清），而 HTML 的字号不受影响。 */
.tb-axis {
  position: relative;
  /* 12px 字 + 上边距 2px + 下留白，给足行高避免被裁 */
  height: 1.35rem;
  margin-top: 0.1rem;
  /* 轴线用最淡的灰：它是背景元素，不该和蓝线/绿带这些数据抢视线 */
  border-top: 1px solid var(--line-soft);
}

/* 横坐标刻度。
 *
 * 「重影」的根因是之前的两处设置叠加：
 *   1. 字号 0.66rem ≈ 10.6px  —— 小到这个尺寸，斜向笔画（3、7、2）
 *      已经被栅格化成两三个像素块，缩放时就会裂开
 *   2. opacity: 0.8—— 整个元素半透明，字形边缘与背景做混合，
 *      笔画淡的地方几乎消失、浓的地方还在，看着像描了两遍
 *
 * 字体与表格「检测到的突变」列保持一致：同一套无衬线字体、同样 12px、
 * 同样的正常字重。两处文字是同一份数据的两种呈现，字形不同会让人
 * 以为是两套东西。颜色用纯黑而非淡灰——淡灰在这个尺寸下反而更糊。
 */
.tb-tick {
  position: absolute;
  top: 2px;
  transform: translateX(-50%);
  color: #111;
  font-family: "Segoe UI", "Microsoft YaHei UI", "Microsoft YaHei",
    -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 12px;
  font-weight: 400;
  /* 不加 opacity：宁可颜色深一点，也不要半透明边缘造成的重影 */
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  white-space: nowrap;
  -webkit-font-smoothing: antialiased;
}

/* 刻度短线：1px 宽、2px 高就够了。原来 3px 高在密集时连成一片，
   反而抢了图本身的视觉重量。 */
.tb-tick::before {
  content: "";
  position: absolute;
  top: -2px;
  left: 50%;
  width: 1px;
  height: 2px;
  background: var(--line);
}

/* ---- 比对图的图形语言 ----
   底部蓝线 = 参考序列
   绿带(50%) = 测序可信区
   灰带(50%) = 测序不可信区
   红竖线= 可信区的突变
   红粗带(50%) = 大范围插入，其下蓝线断开 */

/* 质量带：可信区用绿，不可信区用灰，都是 50% 透明 */
.tb-ok {
  fill: var(--good);
  fill-opacity: 0.5;
}

.tb-untrusted {
  fill: var(--muted);
  fill-opacity: 0.35;
}

/* 大范围插入：红色粗带，50% 透明 */
.tb-ins {
  fill: var(--bad);
  fill-opacity: 0.5;
}

/* 移码区：斜杠纹路。
/*
 * 缺失突变与普通点突变必须一眼分得开——缺一个碱基之后**后面所有密码子
 * 的读法都变了**，这是量级完全不同的问题。实心色块容易和"插入突变"混，
 * 用斜杠纹路则在颜色之外又加了一层纹理编码，色弱用户也能区分。
 *
 * 注意：这里**不写 fill**。斜纹图案的 id 必须逐行唯一（SVG id 是文档
 * 级的，同名 id 只会生效第一个），所以 fill 由 seq_app.js 内联成
 * fill="url(#tb-hatch-xxxx)"，指向该行自己的图案。
 */
.tb-frameshift {
  /* fill 由内联属性提供 */
}

/* 参考序列：底部细实线。大范围插入处断开（那里与参考对不上） */
.tb-ref {
  fill: none;
  stroke: #3f6fbf;
  stroke-width: 2.5;
  stroke-linecap: butt;
  stroke-linejoin: round;
  /* 同红线：图被横向压缩时线宽不该跟着变细 */
  vector-effect: non-scaling-stroke;
}

/* 可信区的突变：红色**粗**竖线，从标记顶端贯穿到参考线。
 *
 * vector-effect="non-scaling-stroke" 是关键：图被横向压到 1/4 时，
 * 普通 stroke-width 会跟着缩到 0.3px，完全看不见。加了它之后
 * 线宽按屏幕像素算，3px 就是 3px。
 *
 * 突变恰恰是用户最需要一眼找到的东西（实测反馈：一定要明显），
 * 所以线宽给到 3。
 */
.tb-tick-mark {
  stroke: var(--bad);
  stroke-width: 3;
  stroke-linecap: butt;
  vector-effect: non-scaling-stroke;
}

/* 透明命中区：只承载悬停提示，不影响视觉 */
.tb-hit {
  fill: transparent;
}

.tb-hit:hover {
  fill: var(--accent-soft);
}

.detail-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.9rem;
  margin-top: 0.6rem;
  color: var(--muted);
  font-size: 0.78rem;
}

.detail-legend > span {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.lg {
  display: inline-block;
  width: 1.1rem;
  height: 0.55rem;
  border-radius: 1px;
  vertical-align: middle;
}

/* 参考序列：细蓝线 */
.lg-ref { height: 2.5px; background: #3f6fbf; }
/* 可信区：绿带 50% */
.lg-ok { background: var(--good); opacity: 0.5; }
/* 不可信区：灰带 */
.lg-untrusted { background: var(--muted); opacity: 0.35; }
/* 可信区突变：红色竖线 */
.lg-mark { width: 3.5px; background: var(--bad); }
/* 大范围插入：红粗带 50% */
.lg-ins { background: var(--bad); opacity: 0.5; }

/* 移码突变：斜杠纹路，与图上的 tb-hatch 图案一致 */
.lg-frameshift {
  background: repeating-linear-gradient(
    45deg,
    var(--bad) 0 2px,
    #fdecea 2px 5px
  );
}

/* ---- 结果标题卡片 ----
   「测序结果」标题 + 状态提示同处一张 .notes 卡片（与引物设计页的
   「引物结果」标题同一视觉层级）。标题行在卡片内不再自带下边距，
   间距交给紧随其后的状态条。 */
.result-head .result-header {
  margin-bottom: 0;
}

/* 「测序结果」标题用纯黑。
 *
 * 原因：.notes 卡片设了 `color: var(--muted)`（#68736d，灰绿），
 * 用来淡化卡片里的说明文字。h2 没显式设色，会继承这个灰绿——
 * 主标题比它下面的说明文字还淡，视觉层级反了。
 *
 * 用 #000 而不是 var(--ink)（#17201b，带一点绿的深色）：
 * 需求要的是纯黑，且主标题与正文说明的明暗差要足够大。
 * .eyebrow（"Results"）保持 var(--accent) 不动，那是刻意的点缀。 */
.result-head h2 {
  color: #000;
}

.result-head .progress {
  margin-top: 12px;
}

/* 无任何输入时也要显示标题卡片，所以它不能依赖 JS 切换 hidden */
.result-head {
  margin-top: 0;
}

/* 判读工作台：结果与证据优先，沿用站点配色。 */
.seq-workspace { grid-template-columns: minmax(280px, 330px) minmax(0, 1fr); }
.input-fields { display: grid; gap: 12px; }
.input-toggle { width: 100%; min-height: 42px; }
.input-fields.is-collapsed { display: none; }
.result-tools { margin-top: 0; }
.stat-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.stat-grid > div, .stat-filter {
  display: flex; flex-direction: column; gap: 5px; align-items: center;
  padding: 9px 4px; border: 1px solid var(--line); border-radius: 6px;
  background: var(--panel-soft); color: var(--ink); text-align: center; min-width: 0;
}
.stat-grid span { font-size: 12px; color: var(--muted); }
.stat-grid strong { font-size: 21px; color: var(--accent-strong); font-variant-numeric: tabular-nums; }
.stat-filter { cursor: pointer; }
.stat-filter:hover, .stat-filter[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); }
.stat-filter[aria-pressed="true"] span { color: var(--accent-strong); font-weight: 650; }
#batchHint { margin-top: 10px; }
.result-filters { display: grid; grid-template-columns: minmax(0, 1.8fr) minmax(0, 1fr) minmax(0, 1fr); gap: 10px; margin-top: 15px; }
.result-filters .field { margin: 0; min-width: 0; }
.field select { width: 100%; min-width: 0; border: 1px solid var(--line); border-radius: 6px; background: var(--panel-soft); color: var(--ink); padding: 10px 8px; font: inherit; }
.filter-count { margin-top: 10px; }
.result-table { table-layout: fixed; min-width: 0; }
.result-table th:nth-child(1) { width: 17%; }
.result-table th:nth-child(2) { width: 35%; }
.result-table th:nth-child(3) { width: 9%; }
.result-table th:nth-child(4) { width: 13%; }
.result-table th:nth-child(5) { width: 26%; }
.result-table .mutation-cell { white-space: normal; }
.cell-note { display: block; margin-top: 4px; font-size: 12px; line-height: 1.5; color: var(--muted); white-space: normal; }
.row-expand { display: grid; grid-template-columns: 24px minmax(0, 1fr); align-items: center; gap: 2px 6px; width: 100%; min-height: 42px; padding: 0; border: 0; background: transparent; color: inherit; text-align: left; cursor: pointer; }
.row-expand .caret-box { grid-row: 1 / 3; margin: 0; width: 23px; height: 23px; }
.row-expand:not(:has(.read-label)) .caret-box { grid-row: 1; }
.sample-id { font-weight: 650; }
.read-label { display: block; font-size: 11px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 3px; }
.row-expand .sample-id, .row-expand .read-label { grid-column: 2; }
.status-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.status-tag { display: inline-block; color: #765010; background: #fbf3e5; border: 1px solid #e9d6b5; border-radius: 4px; padding: 2px 5px; font-size: 11px; line-height: 1.4; white-space: normal; }
.row-error-msg > span { display: block; margin-bottom: 6px; }
.result-table .row-error-msg { white-space: normal; overflow-wrap: anywhere; }
.row-error-msg .status-tag { display: inline-block; }
.mut-scoped { color: var(--muted); }
.error-details { margin-top: 4px; color: var(--muted); font-size: 0.78rem; }
.error-details summary, .interpretation-notes summary { cursor: pointer; }
.error-details summary { padding: 5px 0; }
.error-details p { margin: 6px 0; }
.error-details code { white-space: normal; overflow-wrap: anywhere; }
.interpretation-notes summary { color: var(--ink); font-weight: 600; }
.interpretation-notes[open] summary { margin-bottom: 10px; }
.row-error .read-label { color: var(--muted); }
.track-box { position: relative; cursor: crosshair; overflow: visible; }
.track-selection { position: absolute; top: 0; height: 26px; min-width: 3px; border-left: 2px solid var(--accent-strong); background: var(--accent-soft); opacity: 0.65; pointer-events: none; }
.track-candidate .tb-tick-mark, .track-candidate .tb-insertion-mark { stroke: var(--warn); stroke-dasharray: 3 2; }
.track-candidate .tb-ins, .track-candidate .tb-frameshift { opacity: 0.55; }
.tb-insertion-mark { stroke: var(--bad); stroke-width: 5; vector-effect: non-scaling-stroke; stroke-dasharray: 4 2; }
.tick-start { transform: none; }
.tick-end { transform: translateX(-100%); }
.lg-uncovered { border: 1px solid var(--line-strong); background: transparent; }
.lg-candidate { width: 4px; background: repeating-linear-gradient(to bottom, var(--warn) 0 3px, transparent 3px 5px); }
.variant-list { display: flex; flex-wrap: wrap; gap: 7px; margin: 12px 0; align-items: center; }
.variant-list.compact { margin: 7px 0 0; gap: 5px; }
.variant-chip { font: inherit; font-size: 12px; padding: 6px 9px; min-height: 34px; border: 1px solid var(--line-strong); border-radius: 5px; color: var(--accent-strong); background: var(--panel); cursor: pointer; text-align: left; }
.variant-chip:hover { background: var(--accent-soft); border-color: var(--accent); }
.variant-chip.is-candidate { border-style: dashed; color: #765010; }
.local-controls { display: flex; align-items: center; flex-wrap: wrap; gap: 9px; padding-top: 10px; border-top: 1px solid var(--line); }
.local-controls label { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); }
.codon-input { width: 76px; min-height: 36px; padding: 6px 8px; border: 1px solid var(--line-strong); border-radius: 5px; background: var(--panel); color: var(--ink); }
.local-controls .ghost { min-height: 36px; padding: 7px 10px; font-size: 12px; }
.local-evidence { margin-top: 12px; padding: 13px; background: var(--panel); border: 1px solid var(--line-strong); border-radius: 6px; }
.local-heading { display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.local-heading strong { font-size: 14px; }
.local-heading strong:focus { outline: 2px solid var(--accent); outline-offset: 3px; }
.local-nav { display: flex; gap: 5px; }
.local-nav .ghost { padding: 6px 8px; min-height: 34px; font-size: 12px; }
.local-verdict { margin: 12px 0; font-size: 12px; line-height: 1.5; color: var(--good); }
.local-verdict.needs-review { color: #765010; }
.codon-grid { margin: 13px 0; font-family: Consolas, "Courier New", monospace; }
.codon-row { display: grid; grid-template-columns: 38px repeat(var(--codon-count), minmax(0, 1fr)); }
.codon-label { font-family: "Segoe UI", "Microsoft YaHei", sans-serif; padding: 8px 0; font-size: 12px; color: var(--muted); }
.codon-cell { padding: 7px 2px; text-align: center; border-bottom: 1px solid var(--line-soft); font-size: 13px; }
.codon-cell > span { white-space: nowrap; }
.codon-cell.is-selected { background: var(--accent-soft); }
.base { display: inline-block; width: 1.1em; font-size: 15px; font-weight: 650; }
.base.difference { color: var(--bad); text-decoration: underline; text-underline-offset: 3px; }
.base.untrusted, .base.uncovered { color: var(--muted); font-weight: 400; }
.qv-value { display: inline-block; width: 33.333%; font-size: 10px; }
.qv-row .codon-cell > span { display: block; }
.low-qv { color: #765010; font-weight: 700; }
.seq-workspace button:focus-visible, .seq-workspace input:focus-visible, .seq-workspace select:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

@media (min-width: 1200px) { .stat-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); } }
@media (max-width: 900px) {
  .seq-workspace { grid-template-columns: minmax(0, 1fr); }
  .result-filters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .result-filters .field:first-child { grid-column: 1 / -1; }
}
@media (max-width: 600px) {
  .seq-workspace .result-header { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
  .export-bar { gap: 6px; }
  .export-bar .ghost { font-size: 12px; padding: 7px 9px; min-height: 36px; }
  .result-tools { padding: 12px; }
  .result-tools .table-note { font-size: 12px; }
  .table-wrap { overflow: hidden; }
  .result-table, .result-table tbody { display: block; width: 100%; }
  .result-table thead { display: none; }
  .result-table .result-toggle, .result-table .row-error { display: grid; grid-template-columns: 0.75fr 1fr 1.5fr; padding: 12px; border-bottom: 1px solid var(--line); gap: 8px; }
  .result-table .result-toggle td, .result-table .row-error td { display: block; padding: 0; border: 0; min-width: 0; white-space: normal; }
  .result-toggle td:first-child, .result-toggle td:nth-child(2), .row-error td:first-child, .row-error td:nth-child(2) { grid-column: 1 / -1; }
  .result-toggle td:nth-child(n+3)::before { content: attr(data-label); display: block; margin-bottom: 4px; font-size: 11px; color: var(--muted); }
  .result-toggle td:last-child .cell-note { font-size: 10px; }
  .row-error td:nth-child(n+3) { display: none; }
  .row-expand { grid-template-columns: 26px auto minmax(0, 1fr); }
  .row-expand .caret-box { grid-row: 1; }
  .row-expand .sample-id { grid-column: 2; }
  .row-expand .read-label { grid-column: 3; margin-left: 8px; }
  .detail-row, .detail-row > td { display: block; width: 100%; }
  .detail { padding: 13px 12px; }
  .local-evidence { padding: 10px 7px; }
  .base { font-size: 14px; width: 1em; }
  .codon-label { font-size: 11px; }
  .detail-legend { font-size: 11px; gap: 7px 9px; }
  .variant-chip { min-height: 38px; }
}
@media (prefers-reduced-motion: reduce) {
  .seq-workspace *, .seq-workspace *::before { transition: none !important; scroll-behavior: auto !important; }
}
@media (max-width: 360px) {
  .base { font-size: 13px; }
}
