/* ============================================================================
   table.css — 数据表格（B1 /
   ============================================================================
   ⭐ 某项目 最需要的组件：几百行财务数据，没它就没法看。

   三条硬要求（缺一就不算"能上线"）：
     ① **粘性表头**：横向滚动时必须知道"这一列是什么"
     ② **数字列右对齐 + tabular-nums**：不对齐的数字没法竖着比大小
     ③ **空 / 加载 / 出错三态齐全**：只画表格的组件，一半场景没法用

   ⚠️ 不做虚拟滚动（那是独立）——
     本组件的定位是「结构正确 + 状态齐全 + 粘性可用」，
     行数上限交给调用方判断（> 200 行请配合分页或虚拟滚动）。
   ============================================================================ */

.table {
  position: relative;
  overflow: auto;                    /* 横向滚动容器 */
  max-height: var(--table-max-h, 70vh);
  background: var(--surface);
  border: 1px solid var(--border-decor);
  border-radius: var(--r-md);
  /* ⚠️ 圆角 + overflow:auto 会让 sticky 表头的角上露白
     ⇒ 表头自带背景色，不透明，问题自然消失 */
}

.table table {
  width: 100%;
  border-collapse: separate;         /* 🔴 sticky 需要 separate（不是 collapse）*/
  border-spacing: 0;
  font-size: var(--fs-sm);
}

/* ---------- ① 粘性表头 ---------- */
.table thead th {
  /* 🔴 position:sticky 必须配 border-collapse:separate，否则浏览器里不生效 */
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);          /* 走令牌，不写死 */
  background: var(--surface-raised);
  color: var(--text-secondary);
  font-weight: 600;
  text-align: start;
  white-space: nowrap;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border-decor);
}

/* 排序按钮：表头可点排序时用它 */
.table__sort {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-height: 32px;                  /* 表头内可点区（不是 44，见 README 说明）*/
  padding: 0 var(--sp-1);
  margin: 0 calc(-1 * var(--sp-1));
  background: none;
  border: 0;
  border-radius: var(--r-xs, 3px);
  color: inherit;
  font: inherit;
  cursor: pointer;
}

/* 🔴 修正：原来 fallback 写死了 `#1b4d8f`（被 contract-kit 抓到）
   ⇒ 换主题时这个环不会跟着变。
   ⇒ 焦点环令牌定义在 01-tokens/focus-ring.css：
        --focus-ring-width / --focus-ring-offset / --focus-ring-color(=var(--accent))
   ⇒ 直接用令牌，**不给 fallback**（缺令牌时要能立刻发现，而不是悄悄变蓝）。 */
.table__sort:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ⭐ 排序指示符改用 mask 画，不再用文字字形。
   原因：浏览器会把 ::after 的 `content` 文本算进**可访问名**（name-from-contents，
   `<button>` / `<a>` 这类），读屏于是念出「公司 · ↕ · 按钮」—— 这个符号对用户毫无意义，
   而且自动检查抓不到（名字非空即过）。换成图像后字形不进无障碍树。
   ⚠️ 不要改回 `content: "↕"` 的字形写法，那会把符号念出来。
   ⚠️ 也先别改成 `content: "↕" / ""` 的替代文本语法：三引擎实测**都支持**、也都能清掉 ↕，
     但它要 Chromium 108 / Firefox 128 / Safari 17.4 起才认，更老的引擎会丢掉整条声明
     ⇒ 箭头彻底消失（支持矩阵里有 Chromium 97，正好在门槛外）。
     实测矩阵见 docs/A11Y-MANUAL-PROTOCOL.md。 */
.table__sort::after {
  content: "";                       /* 空内容 ⇒ 不进可访问名 */
  inline-size: .85em;
  block-size: .85em;
  flex: none;
  background-color: currentColor;    /* 跟着文字颜色走，暗色自动适配 */
  opacity: .45;
  -webkit-mask: var(--sort-glyph) center / contain no-repeat;
  mask: var(--sort-glyph) center / contain no-repeat;
  --sort-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.4 5.2 4.6h1.7v2.6h2.2V4.6h1.7z'/%3E%3Cpath d='M8 14.6 10.8 11.4h-1.7V8.8H6.9v2.6H5.2z'/%3E%3C/svg%3E");
}

/* 🔴 强制色：mask 画的箭头会变成「白底上的白箭头」
   ---------------------------------------------------------------------------
   0.17.0 实拍：列头只剩「公司」两个字，排序箭头一个像素都没有。

   根因不是 mask —— mask **保留**（它不是颜色，强制色不管它）。
   而是 `background-color: currentColor` 被替换成了 Canvas（白）
   ⇒ 白色形状 + 白色底 = 不可见。

   ⇒ 强制色下改用 `CanvasText`（系统前景色）。它是系统色关键字，
     不会被再次强制替换。
   ⚠️ 这是**通用模式**，不是这张表的特例：凡是
        `background-color: currentColor` + `mask` 画图标的地方
      都在强制色下会消失。本库目前只有这里和 `field__error::before` 两处，
      判据 A1（forced-colors-check.js）扫的就是这个模式。
   --------------------------------------------------------------------------- */
@media (forced-colors: active) {
  .table__sort::after {
    background-color: CanvasText;
    opacity: 1;                      /* .45 在黑字上仍可辨，但列头本来就小，别再加一层衰减 */
  }
}

/* 🔴🔴 排序指示符：三态必须**同时**用形状 + 颜色表达（WCAG 1.4.1）
   --------------------------------------------------------------------
   实测到的缺陷：
     demo 把 `aria-sort` 放在**外围 <th>** 上（这是符合 ARIA 规范的写法），
     而这里的旧选择器要求它长在**按钮自己**身上 ⇒ 选择器永远匹配不上
     ⇒ 数据明明排好了，箭头一直是"↕"。
     更糟的是当时的门禁 table-check.js 只检查了"aria-sort 在不在 th 上"，
     ⇒ 结构对了、结果错了，门禁还是绿的。**只看结构不看结果，就是这么翻车的。**

   ⇒ 修法是把选择器改成"从 th 往下找按钮"，而不是把 aria-sort 搬到按钮上
     （那会违反 ARIA：`aria-sort` 属于 columnheader / rowheader 角色）。

   ⚠️ 为什么**两种位置都支持**：本库是给别人抄的，外部集成方完全可能写在
     按钮上（写错一次不值得付出"整列失去排序线索"的代价）。
     ⇒ 两条选择器并存，任何一种写法都能把箭头点亮。 */
.table th[aria-sort="ascending"] .table__sort::after,
.table__sort[aria-sort="ascending"]::after {
  --sort-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.6 4.6 6h2.1v8h2.6V6h2.1z'/%3E%3C/svg%3E");
  opacity: 1;
}

.table th[aria-sort="descending"] .table__sort::after,
.table__sort[aria-sort="descending"]::after {
  --sort-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 14.4 11.4 10h-2.1V2H6.7v8H4.6z'/%3E%3C/svg%3E");
  opacity: 1;
}

/* ---------- 行 ---------- */
.table tbody td,
.table tbody th {
  padding: var(--sp-2) var(--sp-3);
  text-align: start;
  border-bottom: 1px solid var(--border-decor);
  vertical-align: top;
}

.table tbody tr:last-child td { border-bottom: 0; }

/* 行高亮：只对真能悬停的设备（触屏上 hover 会"粘住"）*/
@media (hover: hover) and (pointer: fine) {
  .table tbody tr:hover { background: var(--surface-sunken); }
}

/* ---------- ② 数字列：右对齐 + 等宽数字 ---------- */
.table .num {
  text-align: end;
  /* ⭐ tabular-nums：让每个数字占同样宽 ⇒ 可以竖着比大小
     这是「财务表格」和「装饰表格」的分界线 */
  font-variant-numeric: tabular-nums;
  font-family: var(--mono);
  white-space: nowrap;
}

/* 正负号用颜色 + 符号双线索（不能只靠红绿）*/
.table .num--pos { color: var(--success); }
.table .num--neg { color: var(--danger); }
.table .num--pos::before { content: "+"; }   /* ⭐ 符号是第二线索 */
.table .num--neg::before { content: "−"; }   /* ⭐ 用真正的减号，不是连字符 */

/* ---------- ③ 三态 ---------- */
.table__empty,
.table__error,
.table__loading {
  padding: var(--sp-7) var(--sp-4);
  text-align: center;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
}

.table__empty { background: var(--surface-sunken); }
.table__error  { background: var(--surface-sunken); color: var(--danger); }
.table__loading { color: var(--text-tertiary); }

/* 加载态：骨架条（配 aria-busy，容器有语义）*/
.table__bar {
  height: 8px;
  margin: var(--sp-2) auto;
  max-width: 220px;
  background: var(--surface-sunken);
  border-radius: 999px;
  overflow: hidden;
}

@media (prefers-reduced-motion: no-preference) {
  .table__bar::after {
    content: "";
    display: block;
    height: 100%;
    width: 40%;
    background: var(--accent-soft);
    border-radius: 999px;
    animation: table-shimmer 1.2s var(--ease-in-out, ease-in-out) infinite;
  }
  @keyframes table-shimmer {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(250%); }
  }
}

/* 空态里的行动入口 */
.table__empty .btn,
.table__error .btn { margin-top: var(--sp-3); }

/* ---------- 窄屏：表格横向滚动，不挤压列 ---------- */
.table--compact { font-size: var(--fs-xs); }
.table--compact thead th,
.table--compact tbody td { padding: var(--sp-1) var(--sp-2); }

/* ============================================================================
   表题 / 脚注 / 来源
   ============================================================================
   学术与统计表格要求"这张表是什么、数据从哪来"与表本身绑在一起，
   不能只靠正文的一句话。⇒ 用 <caption>（表题）+ 表后脚注两块表达。
   ============================================================================ */
.table__cap {
  caption-side: top;
  text-align: start;
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-xs);
  color: var(--text-tertiary);
}

.table__foot {
  margin: var(--sp-2) 0 0;
  padding: 0 var(--sp-1);
  font-size: var(--fs-xs);
  color: var(--text-tertiary);
  line-height: 1.6;
}
.table__foot ol { margin: 0; padding-inline-start: var(--sp-4); }

/* ============================================================================
   多级表头
   ============================================================================
   🔴 多级表头不是"多画一行 <th>"就完事：
      屏幕阅读器靠 scope / id / headers 把单元格和它真正的表头对上。
      只画两层 <tr> 而不标 scope ⇒ 读屏读到"3.2"时不知道它是哪一列的。
      ⇒ 样式只负责让它看起来是两层，**语义由 HTML 负责**（见 demo.html）。
   ============================================================================ */
.table thead tr + tr th {
  /* 第二层表头：贴近第一层，靠上边框区分而不是加粗字号 */
  top: 2.4em;                        /* 跟着第一层 sticky 一起粘 */
  font-weight: 500;
  font-size: var(--fs-xs);
  color: var(--text-tertiary);
  border-bottom: 1px solid var(--border-decor);
}

/* 分组表头（跨列）居中，让"这两列属于同一组"看得出来 */
.table thead th[colspan] {
  text-align: center;
  border-inline-start: 1px solid var(--border-decor);
}
.table thead th[colspan]:first-child { border-inline-start: 0; }

/* ============================================================================
   预设一：业务 / 财务数据表（默认观感的明确化）
   ============================================================================
   重点：数字比较、金额精度、单位、负数、正负号语义。
   单位写在**列头**而不是每个单元格里 —— 一列重复 20 次"万元"只会增加噪音。
   ============================================================================ */
.table--financial thead th { white-space: nowrap; }
/* 行表头（公司名等）不换行 —— 换来换去会让整张表的行高参差，难竖着读 */
.table--financial tbody th { white-space: nowrap; }

/* 🔴 数值列的**列头必须与数字同侧**（右对齐）：<th> 默认 center，而数字是 end
   ⇒ 列头「2021」居中、下面的「1,095」靠右，两者不在一条竖线上，列数和行长
      越极端错位越明显（五年表实测错开约半个列宽）。会计排版与 Excel「会计格式」
      都是"表头与数据同侧"。⚠️ 只改 financial：三线表的表头居中是学科惯例。 */
.table--financial thead th:not(:first-child) { text-align: end; }

/* ============================================================================
   🔴 单位在列头的写法 —— 跟着学科规范走，不是随手设计（0.8.5）
   ============================================================================
   依据（五处权威口径一致，不是"我觉得"）：
     · GB/T 7713.2-2022《学术论文编写规则》5.5.4
         「表头栏目的标注应正确、齐全」；同时用量与单位表示时采用
         「**量的符号或名称/单位符号**」的标准化形式
     · CY/T 170—2019《学术出版规范 表格》
         表头标注形式为「量的名称或符号/单位符号」；
         且「表身中单元格内的数值**不宜带单位**」
     · Science（Author Guidelines）
         "Every vertical column should have a heading, **followed by a unit of
         measure (if any) in parentheses**"
     · IEEE Standards Style Manual 14.3.1
         "Units of measure shall always be provided ... **in parentheses**, or
         preceded by a solidus in the column headings [E (V) or E/V]"
     · 三线表通行做法：项目栏 =「量的名称 +（单位）」，同栏单位不得变化

   🔴 为什么原来不对（用户指出的问题）：
     原来 `.table__unit` 是「小一号 + 更浅的灰」，**贴在列名后面**。
     两点都不合规范：
       ① **字号更小** ⇒ 视觉上像"这是两样东西"，而不是"这是列名的单位"
       ② **没有括号** ⇒ 国标/IEEE/Science 三方都要求 `列名 (单位)` 或 `列名/单位`，
          裸写 `抗拉强度 MPa` 不符合「量的名称/单位符号」的标准化形式
     规范做法：`抗拉强度 (MPa)` —— 单位带括号、同字号、
     与列名成组从同一条线起排 ⇒ 竖着读数列时视线只走一条直线。
   ============================================================================ */
.table__unit {
  font-weight: 400;
  /* 🔴 不再缩小：字号差会造成"这是两样东西"的错觉。
     规范里单位与列名同字号（可选斜体区分）。 */
  font-size: inherit;
  color: var(--text-secondary);
  /* ① 单位与列名之间留一个空格，避免「抗拉强度MPa」读起来粘连 */
  margin-inline-start: 0.35em;
  /* ② 🔴 关键：整组不拆行 —— 规范要求单位紧跟列名，
     折行会让"这一列叫什么"变难读 */
  white-space: nowrap;
}

/* 🔴 缺失值：既不是 0，也不是空字符串 —— 必须看得出"这里没数据" */
.table .num--na,
.table .cell--na {
  color: var(--text-tertiary);
  text-align: center;
}

/* ============================================================================
   预设二：学术出版表格（三线表）
   ============================================================================
   为什么不是"把财务表改成灰的"：
   论文表格的读者要**逐格比对数值**，竖线和斑马纹会干扰视线；
   三线表只留顶线、表头下线、底线三条，把注意力留给数字本身。
   ============================================================================ */
.table--academic {
  border: 0;
  border-radius: 0;
  background: transparent;
  max-height: none;                  /* 三线表不滚动：它应当完整呈现 */
}
.table--academic table { background: transparent; }

.table--academic thead th {
  background: transparent;
  color: var(--text-primary);
  font-weight: 600;
  border-top: 2px solid var(--border-decor-str);
  border-bottom: 1px solid var(--border-decor);
  position: static;                  /* 不滚动 ⇒ 不需要 sticky */
}
.table--academic thead tr + tr th {
  font-weight: 400;
  border-top: 0;
  border-bottom: 1px solid var(--border-decor);
}
.table--academic tbody td,
.table--academic tbody th {
  border-bottom: 0;                  /* 行间不画线 */
}
.table--academic tbody tr:last-child td,
.table--academic tbody tr:last-child th {
  border-bottom: 1px solid var(--border-decor);   /* 底线 */
}
@media (hover: hover) and (pointer: fine) {
  .table--academic tbody tr:hover { background: transparent; }
}

/* ============================================================================
   预设三：统计 / 实验结果表
   ============================================================================
   🔴 这些列的格式**不能**交给通用数字格式化：
      · 估计值与其标准误是**两个数**，不是"一个带括号的字符串"
      · 置信区间是**区间**，不是两个独立数字
      · p 值有自己的书写惯例（< .001 不写 0.000）
   组件只负责把它们放在各自的语义位置，**不替调用方计算显著性**。
   ============================================================================ */
.table--stats .stat__se {            /* 标准误：次级信息，弱化 */
  color: var(--text-tertiary);
  font-size: var(--fs-xs);
}
.table--stats .stat__p {             /* p 值：等宽且右对齐 */
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
.table--stats .stat__p--sig {        /* 达到显著性水平：加粗（不只靠颜色） */
  font-weight: 700;
  color: var(--text-primary);
}
.table--stats .stat__ci {            /* 置信区间：方括号是它的语义符号 */
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---------- 窄屏：表格横向滚动，不挤压列 ---------- */
/* ---------- 打印：去掉粘性（打印时不需要）---------- */
@media print {
  .table { max-height: none; overflow: visible; }
  .table thead th { position: static; }
  .table--academic thead th { border-top: 2px solid var(--text-primary); }
}
