/* ============================================================
 * 咖莱翼 · 布局层（Layout & Utilities）
 * ------------------------------------------------------------
 * 【职责】只管"位置与排布"，不管"长什么样"（颜色/边框归组件 CSS）。
 *
 * 【核心设计：列数由变量驱动】
 *   .grid-kpi  → 列数取 --cols-kpi
 *   .grid-cards→ 列数取 --cols-card
 *   .grid-form → 列数取 --cols-form
 *
 *   ⇒ KPI 卡从 4 列改 3 列：tokens.css 里改 `--cols-kpi: 3` 一处，
 *     全站所有 .grid-kpi 同步变化，HTML 与 JS 零改动。
 *   ⇒ 只想改某一处：在该元素上写 style="--cols:3" 或加 .cols-3 类即可。
 *
 * 【常用改动速查】
 *   改全站卡片列数   → tokens.css: --cols-card
 *   改全站间距节奏   → tokens.css: --space-* 系列
 *   某一块单独紧凑   → 元素上加 .gap-2
 *   某一块单独调列数 → 元素上加 .cols-2 / .cols-3 / .cols-4
 *   元素显隐         → .hidden / .d-none
 *
 * ⚠️ 本文件引入顺序在 style.css 之后，但所有规则只作用于"使用了这些
 *    类名的元素"，因此不会改变任何现有元素的视觉。
 * ============================================================ */

/* ============================================================
 * 1. 栅格系统
 * ============================================================ */

/* —— 通用栅格：列数由 --cols 决定，默认 1 —— */
.grid {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: repeat(var(--cols, 1), minmax(0, 1fr));
}

/* —— 语义化栅格：绑定全局列数变量（改布局的推荐入口）—— */
.grid-kpi   { display: grid; gap: var(--grid-gap); grid-template-columns: repeat(var(--cols-kpi),  minmax(0, 1fr)); }
.grid-cards { display: grid; gap: var(--grid-gap-lg); grid-template-columns: repeat(var(--cols-card), minmax(0, 1fr)); }
.grid-form  { display: grid; gap: var(--grid-gap); grid-template-columns: repeat(var(--cols-form), minmax(0, 1fr)); }

/* —— 自适应栅格：不写死列数，按最小列宽自动换行（最省心）—— */
.grid-auto   { display: grid; gap: var(--grid-gap); grid-template-columns: repeat(auto-fill, minmax(var(--col-min), 1fr)); }
.grid-auto-lg{ display: grid; gap: var(--grid-gap); grid-template-columns: repeat(auto-fill, minmax(var(--col-min-lg), 1fr)); }
.grid-auto-sm{ display: grid; gap: var(--grid-gap); grid-template-columns: repeat(auto-fill, minmax(var(--col-min-sm), 1fr)); }

/* —— 显式列数覆盖（局部微调用，优先于语义化变量）—— */
.cols-1 { --cols: 1; --cols-kpi: 1; --cols-card: 1; --cols-form: 1; }
.cols-2 { --cols: 2; --cols-kpi: 2; --cols-card: 2; --cols-form: 2; }
.cols-3 { --cols: 3; --cols-kpi: 3; --cols-card: 3; --cols-form: 3; }
.cols-4 { --cols: 4; --cols-kpi: 4; --cols-card: 4; --cols-form: 4; }
.cols-5 { --cols: 5; --cols-kpi: 5; --cols-card: 5; --cols-form: 5; }
.cols-6 { --cols: 6; --cols-kpi: 6; --cols-card: 6; --cols-form: 6; }

/* —— 跨列 —— */
.col-span-2 { grid-column: span 2; }
.col-span-3 { grid-column: span 3; }
.col-span-full { grid-column: 1 / -1; }

/* —— 栅格间距微调 —— */
.gap-0 { gap: var(--space-0); }
.gap-1 { gap: var(--space-1); }
.gap-2 { gap: var(--space-2); }
.gap-3 { gap: var(--space-3); }
.gap-4 { gap: var(--space-4); }
.gap-5 { gap: var(--space-5); }
.gap-6 { gap: var(--space-6); }
.row-gap-2 { row-gap: var(--space-2); }
.row-gap-4 { row-gap: var(--space-4); }

/* ============================================================
 * 2. 响应式：断点自动降列（改屏幕适配无需改 HTML）
 *    规则：≥1400 满列 → <1200 减一列 → <768 两列 → <576 单列
 * ============================================================ */
@media (max-width: 1400px) {
  .grid-kpi   { grid-template-columns: repeat(min(var(--cols-kpi), 4), minmax(0, 1fr)); }
  .grid-cards { grid-template-columns: repeat(min(var(--cols-card), 3), minmax(0, 1fr)); }
}
@media (max-width: 1200px) {
  .grid-kpi   { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-form  { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 768px) {
  .grid-kpi, .grid-cards, .grid-form, .grid-auto-lg {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 576px) {
  .grid-kpi, .grid-cards, .grid-form, .grid-auto, .grid-auto-lg, .grid-auto-sm {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
 * 3. Flex 工具类
 * ============================================================ */
.flex         { display: flex; }
.inline-flex  { display: inline-flex; }
.flex-col     { flex-direction: column; }
.flex-wrap    { flex-wrap: wrap; }
.flex-nowrap  { flex-wrap: nowrap; }
.flex-1       { flex: 1 1 0%; }
.flex-auto    { flex: 1 1 auto; }
.flex-none    { flex: none; }
.flex-grow    { flex-grow: 1; }

.items-start    { align-items: flex-start; }
.items-center   { align-items: center; }
.items-end      { align-items: flex-end; }
.items-baseline { align-items: baseline; }
.items-stretch  { align-items: stretch; }

.justify-start   { justify-content: flex-start; }
.justify-center  { justify-content: center; }
.justify-end     { justify-content: flex-end; }
.justify-between { justify-content: space-between; }
.justify-around  { justify-content: space-around; }
.justify-evenly  { justify-content: space-evenly; }

.self-center { align-self: center; }
.self-end    { align-self: flex-end; }

/* —— 弹性纵向堆叠（表单/列表最常用）—— */
.stack    { display: flex; flex-direction: column; gap: var(--space-3); }
.stack-sm { display: flex; flex-direction: column; gap: var(--space-2); }
.stack-lg { display: flex; flex-direction: column; gap: var(--space-5); }

/* ============================================================
 * 4. 间距工具类（替代内联 style="margin-top:12px"）
 *    命名：{m|p}{t|b|l|r|x|y}-{0..8}
 * ============================================================ */
.m-0 { margin: var(--space-0); } .m-1 { margin: var(--space-1); } .m-2 { margin: var(--space-2); }
.m-3 { margin: var(--space-3); } .m-4 { margin: var(--space-4); } .m-5 { margin: var(--space-5); }
.m-6 { margin: var(--space-6); } .m-7 { margin: var(--space-7); } .m-8 { margin: var(--space-8); }
.mx-auto { margin-left: auto; margin-right: auto; }

.mt-0 { margin-top: var(--space-0); } .mt-1 { margin-top: var(--space-1); }
.mt-2 { margin-top: var(--space-2); } .mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); } .mt-5 { margin-top: var(--space-5); }
.mt-6 { margin-top: var(--space-6); } .mt-7 { margin-top: var(--space-7); }
.mt-8 { margin-top: var(--space-8); } .mt-auto { margin-top: auto; }

.mb-0 { margin-bottom: var(--space-0); } .mb-1 { margin-bottom: var(--space-1); }
.mb-2 { margin-bottom: var(--space-2); } .mb-3 { margin-bottom: var(--space-3); }
.mb-4 { margin-bottom: var(--space-4); } .mb-5 { margin-bottom: var(--space-5); }
.mb-6 { margin-bottom: var(--space-6); } .mb-7 { margin-bottom: var(--space-7); }
.mb-8 { margin-bottom: var(--space-8); }

.ml-1 { margin-left: var(--space-1); } .ml-2 { margin-left: var(--space-2); }
.ml-3 { margin-left: var(--space-3); } .ml-4 { margin-left: var(--space-4); }
.ml-auto { margin-left: auto; }

.mr-1 { margin-right: var(--space-1); } .mr-2 { margin-right: var(--space-2); }
.mr-3 { margin-right: var(--space-3); } .mr-4 { margin-right: var(--space-4); }
.mr-auto { margin-right: auto; }

.p-0 { padding: var(--space-0); } .p-1 { padding: var(--space-1); }
.p-2 { padding: var(--space-2); } .p-3 { padding: var(--space-3); }
.p-4 { padding: var(--space-4); } .p-5 { padding: var(--space-5); }
.p-6 { padding: var(--space-6); } .p-8 { padding: var(--space-8); }

.px-1 { padding-left: var(--space-1); padding-right: var(--space-1); }
.px-2 { padding-left: var(--space-2); padding-right: var(--space-2); }
.px-3 { padding-left: var(--space-3); padding-right: var(--space-3); }
.px-4 { padding-left: var(--space-4); padding-right: var(--space-4); }
.px-5 { padding-left: var(--space-5); padding-right: var(--space-5); }

.py-1 { padding-top: var(--space-1); padding-bottom: var(--space-1); }
.py-2 { padding-top: var(--space-2); padding-bottom: var(--space-2); }
.py-3 { padding-top: var(--space-3); padding-bottom: var(--space-3); }
.py-4 { padding-top: var(--space-4); padding-bottom: var(--space-4); }
.py-5 { padding-top: var(--space-5); padding-bottom: var(--space-5); }

.pt-2 { padding-top: var(--space-2); } .pt-3 { padding-top: var(--space-3); }
.pt-4 { padding-top: var(--space-4); } .pt-5 { padding-top: var(--space-5); }
.pb-2 { padding-bottom: var(--space-2); } .pb-3 { padding-bottom: var(--space-3); }
.pb-4 { padding-bottom: var(--space-4); } .pb-5 { padding-bottom: var(--space-5); }

/* ============================================================
 * 5. 排版工具类
 * ============================================================ */
.text-xs   { font-size: var(--fs-xs); }
.text-sm   { font-size: var(--fs-sm); }
.text-base { font-size: var(--fs-base); }
.text-md   { font-size: var(--fs-md); }
.text-lg   { font-size: var(--fs-lg); }
.text-xl   { font-size: var(--fs-xl); }
.text-2xl  { font-size: var(--fs-2xl); }
.text-3xl  { font-size: var(--fs-3xl); }

.font-normal   { font-weight: var(--fw-normal); }
.font-medium   { font-weight: var(--fw-medium); }
.font-semibold { font-weight: var(--fw-semibold); }
.font-bold     { font-weight: var(--fw-bold); }

.leading-tight  { line-height: var(--lh-tight); }
.leading-normal { line-height: var(--lh-normal); }
.leading-loose  { line-height: var(--lh-loose); }

.text-left   { text-align: left; }
.text-center { text-align: center; }
.text-right  { text-align: right; }

.text-primary   { color: var(--primary); }
.text-secondary { color: var(--text-secondary); }
.text-muted     { color: var(--text-muted); }
.text-success   { color: var(--success); }
.text-warning   { color: var(--warning); }
.text-danger    { color: var(--danger); }

.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.break-all  { word-break: break-all; }
.nowrap     { white-space: nowrap; }

/* ============================================================
 * 6. 尺寸工具类
 * ============================================================ */
.w-full  { width: 100%; }
.w-auto  { width: auto; }
.h-full  { height: 100%; }
.min-w-0 { min-width: 0; }
.max-w-full { max-width: 100%; }

/* 容器：统一最大宽度与内边距（改 --container-max 即全站生效） */
.container-fluid {
  width: 100%;
  max-width: var(--container-max);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--container-pad);
  padding-right: var(--container-pad);
}

/* ============================================================
 * 7. 显隐工具类
 * ============================================================ */
.hidden { display: none !important; }
.d-none { display: none !important; }
.d-block { display: block; }
.d-flex  { display: flex; }
.d-grid  { display: grid; }
.invisible { visibility: hidden; }

/* 响应式显隐 */
@media (max-width: 768px) {
  .hide-mobile { display: none !important; }
}
@media (min-width: 769px) {
  .hide-desktop { display: none !important; }
}

/* ============================================================
 * 8. 区块（Section）容器 —— 页面板块统一外壳
 *    改板块间距：改 --space-* 或在此统一调整
 * ============================================================ */
.l-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.l-section + .l-section {
  margin-top: var(--space-6);
}

/* 板块头部：标题 + 右侧操作区，自动两端对齐 */
.l-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* 工具栏：筛选/搜索/按钮横排，自动换行 */
.l-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* 表格滚动容器：横向滚动 + 最小宽度保护 */
.l-table-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* ============================================================
 * 9. 通用表格外观（配合 js/ui-table.js 使用）
 *    所有取值均来自 Token —— 改表格风格只需改 tokens.css
 * ============================================================ */
.ui-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-base);
  color: var(--text);
}
.ui-table thead th {
  padding: var(--space-2) var(--space-3);
  background: var(--gray-50);
  color: var(--text-secondary);
  font-weight: var(--fw-medium);
  font-size: var(--fs-sm);
  text-align: left;
  white-space: nowrap;
  border-bottom: 1px solid var(--border);
}
.ui-table tbody td {
  padding: var(--space-2) var(--space-3);
  border-top: 1px solid var(--border-light);
  vertical-align: middle;
}
.ui-table tbody tr:hover {
  background: var(--gray-25);
}

/* 紧凑型 */
.ui-table--compact thead th { padding: var(--space-1) var(--space-2); }
.ui-table--compact tbody td { padding: var(--space-1) var(--space-2); }

/* 表头吸顶 */
.ui-table--sticky thead th {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--gray-50);
}

/* 斑马纹 */
.ui-table--striped tbody tr:nth-child(even) { background: var(--gray-25); }

/* 空态（保留旧类名，历史调用方仍可用） */
.ui-table-empty {
  padding: var(--space-5);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--fs-base);
}

/* ============================================================
 * 9.1 表格四态（配合 ui-table.js 的 loading/empty/error/ready）
 *     契约依据：A-契约总册.md §3 每页五态（表格层收敛为四态）
 *     所有取值来自 Token —— 换肤/换密度不需改这里
 * ============================================================ */

/* 状态容器：三态（loading/empty/error）共用一块留白区 */
.ui-table-state {
  width: 100%;
}

/* —— 空态 / 错误态 通用外观 —— */
.ui-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-6) var(--space-5);
  text-align: center;
}
.ui-state-icon {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  margin-bottom: var(--space-1);
  border-radius: var(--radius-lg);
  background: var(--gray-50);
  color: var(--gray-400);
}
.ui-state-title {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  color: var(--text);
}
.ui-state-hint {
  margin: 0;
  max-width: 420px;
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--text-muted);
}
.ui-state-meta {
  margin: var(--space-1) 0 0;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.ui-state-meta code {
  padding: 1px var(--space-1);
  border-radius: var(--radius-sm);
  background: var(--gray-100);
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  color: var(--text-secondary);
}
.ui-state-actions {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.ui-state-btn {
  padding: var(--space-1) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card-bg);
  color: var(--text);
  font-size: var(--fs-base);
  cursor: pointer;
  transition: background .15s, border-color .15s;
}
.ui-state-btn:hover {
  border-color: var(--border-dark);
  background: var(--gray-25);
}
.ui-state-btn--primary {
  border-color: var(--primary);
  background: var(--primary);
  color: var(--text-on-primary);
}
.ui-state-btn--primary:hover {
  background: var(--primary-dark);
  border-color: var(--primary-dark);
}
.ui-state-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* 错误态：⚠️ 用警示橙而非危险红
   理由：数据加载失败多数是「暂时性」，不是「破坏性操作失败」。
   红色应当留给删除/覆盖等不可逆动作，否则红色会失去警示权重。 */
.ui-state--error .ui-state-icon {
  background: var(--warning-light);
  color: var(--warning);
}

/* —— 骨架屏（loading 态）—— */
.ui-table--skeleton tbody td {
  /* 骨架行不需要悬停高亮，避免用户以为可点 */
  pointer-events: none;
}
.ui-table--skeleton tbody tr:hover {
  background: transparent;
}
.kx-skel {
  display: inline-block;
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--gray-100) 25%, var(--gray-50) 37%, var(--gray-100) 63%);
  background-size: 400% 100%;
  animation: kx-skel-shimmer 1.4s ease-in-out infinite;
}
.kx-skel--text {
  height: 11px;
  vertical-align: middle;
}
@keyframes kx-skel-shimmer {
  0%   { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}
/* 尊重用户的减弱动效偏好（前庭障碍用户会因闪烁动效不适） */
@media (prefers-reduced-motion: reduce) {
  .kx-skel {
    animation: none;
    background: var(--gray-100);
  }
}

/* —— 可排序表头 —— */
.ui-table-th-sortable {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.ui-table-th-sortable:hover {
  color: var(--text);
}
.ui-table-th-sortable:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}
/* 排序指示三角：默认淡显，激活时点亮 —— 不占用额外宽度抖动 */
.ui-table-sort-ind {
  display: inline-block;
  width: 0;
  height: 0;
  margin-left: var(--space-1);
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-bottom: 5px solid var(--gray-300);
  vertical-align: middle;
  transition: transform .15s, border-bottom-color .15s;
}
.ui-table-th-sortable.is-asc .ui-table-sort-ind {
  border-bottom-color: var(--primary);
}
.ui-table-th-sortable.is-desc .ui-table-sort-ind {
  transform: rotate(180deg);
  border-bottom-color: var(--primary);
}

/* —— 分页器 —— */
.ui-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-1) var(--space-1);
}
.ui-pager-info {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  /* 数字等宽：翻页时计数不跳字 */
  font-variant-numeric: tabular-nums;
}
.ui-pager-ctrl {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}
.ui-pager-btn {
  min-width: 30px;
  height: 30px;
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card-bg);
  color: var(--text-secondary);
  font-size: var(--fs-base);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: border-color .15s, color .15s, background .15s;
}
.ui-pager-btn:hover:not(:disabled) {
  border-color: var(--primary);
  color: var(--primary);
}
.ui-pager-btn:disabled {
  color: var(--gray-300);
  cursor: not-allowed;
  background: var(--gray-50);
}
.ui-pager-btn.is-active {
  border-color: var(--primary);
  background: var(--primary);
  color: var(--text-on-primary);
  font-weight: var(--fw-medium);
}
.ui-pager-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}
.ui-pager-gap {
  padding: 0 var(--space-1);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

/* 窄屏：分页器改两行堆叠，避免页码被挤断 */
@media (max-width: 560px) {
  .ui-pager {
    justify-content: center;
  }
  .ui-pager-ctrl {
    flex-wrap: wrap;
    justify-content: center;
  }
}

/* —— 表格内可编辑控件（替代写在 <td> 里的内联 style）—— */
.cell-input,
.cell-select {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-sm);
  font-size: var(--fs-base);
  font-family: inherit;
  color: var(--text);
  background: var(--card-bg);
  transition: border-color .15s, box-shadow .15s;
}
.cell-input  { width: 100%; }
.cell-input--num { width: 80px; text-align: right; }
.cell-input:focus,
.cell-select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 2px var(--blue-100);
}
.cell-input:hover,
.cell-select:hover { border-color: var(--border-dark); }

/* ============================================================
 * 10. 定价测算页 · 参数/结果双栏
 *     （原 step3「定价参数」+ step4「定价结果」合并为一屏两栏）
 * ------------------------------------------------------------
 * 【为什么合并】
 *   测算页最高频的动作是「改一档参数 → 看结果变多少」。分两步时这个循环要
 *   来回跳两次（看结果 → 回参数页 → 改 → 再算 → 又看结果）。同屏后改完直接
 *   重算，结果就在右手边。
 *
 * 【为什么是 4/8 而不是 6/6】
 *   左栏只有 3 个滑块 + 一段门店/平台回顾，内容量天生小；
 *   右栏要放 4 张 KPI + 结果表（9~12 列）+ 费用明细三列，是天生的宽内容。
 *   4/8 让结果表尽量少出横向滚动 —— 而横向滚动正是「逐项核对」的敌人。
 * ============================================================ */
.calc-split {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: var(--grid-gap-lg);
  align-items: start;
}

/* 左栏粘性跟随：滚动核对长结果表时，参数面板始终留在视口内 ——
   否则改参数要先滚回顶部，等于把双栏的好处又还回去了。
   top 要让开 sticky 的 .page-head（高度 --header-h）。 */
.calc-params {
  position: sticky;
  top: calc(var(--header-h) + var(--space-4));
}
.calc-params .card { margin-bottom: 0; }

/* 门店 / 平台回顾：只读展示「这一屏算的是谁」。
   参数面板里最容易出错的是「在错误的门店或平台上调参」，
   把上下文钉在参数正上方，比让用户回上一步确认可靠。 */
.calc-ctx {
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
  background: var(--primary-light);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
}
.calc-ctx__row { display: flex; gap: var(--space-3); }
.calc-ctx__row + .calc-ctx__row { margin-top: var(--space-1); }
.calc-ctx__k { flex: 0 0 34px; color: var(--text-secondary); }
.calc-ctx__v {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--text);
  font-weight: var(--fw-medium);
  /* 门店名可能很长：截断而不是撑破 4 列窄栏 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.calc-result { min-width: 0; }

/* 卡片标题两端对齐（左标题 + 右操作/说明） */
.card-title--flex {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

/* 参数区按钮：4 列窄栏下两个按钮并排会挤到换行，竖排更好按 */
.btn-group--stack { flex-direction: column; margin-bottom: 0; }
.btn-group--stack .btn { width: 100%; }

@media (max-width: 1100px) {
  .calc-split { grid-template-columns: minmax(0, 1fr); }
  /* 单栏后必须解除粘性：否则参数面板会浮在后面的结果之上 */
  .calc-params { position: static; }
  .btn-group--stack { flex-direction: row; }
  .btn-group--stack .btn { width: auto; }
}

/* ------------------------------------------------------------
 * 10.1 金额列三条铁规
 *   ① white-space: nowrap
 *      绝不折行。位数多的金额在窄列里会被折成两行，
 *      「33827 / 8.71」会被读成两个量 —— 这是参考后台真实存在的缺陷。
 *   ② text-align: right
 *      位数不同时，右对齐让小数点落在同一竖线上，可按数量级纵向扫。
 *   ③ font-variant-numeric: tabular-nums
 *      比例字体里 1 比 8 窄，不同行的数字宽度不一，小数点会错位。
 *      等宽数字让整列形成规整的数字栅格。
 * ------------------------------------------------------------ */
.data-table th.amount,
.data-table td.amount {
  white-space: nowrap;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
.data-table td.amount--strong { font-weight: var(--fw-semibold); }

/* ------------------------------------------------------------
 * 10.2 结果汇总行
 *   金额类汇总**必须带口径说明**：不写清算法，对账时无人能复现 ——
 *   而「能不能对上账」正是定价工具的成败点。
 *   口径单独占一行（.result-sum__note），不与数字挤在一起。
 * ------------------------------------------------------------ */
.result-sum {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  margin-top: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--primary-light);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
}
.result-sum__item { color: var(--text); white-space: nowrap; }
.result-sum__item b { font-variant-numeric: tabular-nums; font-weight: var(--fw-semibold); }
.result-sum__k { color: var(--text-secondary); }
.result-sum__note {
  flex: 1 1 100%;
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
}

/* ------------------------------------------------------------
 * 10.3 费用明细逐项拆解
 *   费用项逐条独立列出、不合并成「其他费用」——
 *   对账时任何一项对不上都要能立刻定位到行。
 * ------------------------------------------------------------ */
.fee-subject { margin-left: var(--space-2); color: var(--text-secondary); font-size: var(--fs-sm); font-weight: var(--fw-normal); }
.fee-hint { color: var(--text-secondary); font-size: var(--fs-xs); font-weight: var(--fw-normal); }

.fee-table { width: 100%; border-collapse: collapse; font-size: var(--fs-base); }
.fee-table th {
  padding: var(--space-2) var(--space-3);
  text-align: left;
  white-space: nowrap;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border);
}
.fee-table td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border-light);
  vertical-align: top;
}
.fee-table tbody tr:last-child td { border-bottom: none; }
.fee-table .fee-formula { color: var(--text-secondary); font-size: var(--fs-sm); }
.fee-table .fee-input { color: var(--text-muted); font-size: var(--fs-xs); }
/* 金额列复用同一套铁规，保证与结果表观感一致 */
.fee-table .fee-amount {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
.fee-table tr.fee-row--total { background: var(--primary-light); }
.fee-table tr.fee-row--total td { font-weight: var(--fw-semibold); }
.fee-table tr.fee-row--total .fee-amount { font-weight: var(--fw-semibold); }

.fee-empty {
  padding: var(--space-6) var(--space-4);
  text-align: center;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
}

/* ------------------------------------------------------------
 * 10.4 结果行可点选（联动右下方费用明细）
 *   既有实现是「点单元格弹计算轨迹弹窗」，本批改为
 *   「点行 = 选中并联动明细；点 📊 图标 = 弹完整轨迹」。
 *   ⚠️ 之所以要拆开：两种意图都挂在点击上，不拆就会一次点击弹窗 + 选中同时发生。
 * ------------------------------------------------------------ */
.data-table tbody tr.result-row { cursor: pointer; }
.data-table tbody tr.result-row:hover { background: var(--primary-light); }
.data-table tbody tr.result-row[aria-selected="true"] { background: var(--primary-light); }
.data-table tbody tr.result-row[aria-selected="true"] td:first-child {
  /* 选中态双重编码：底色 + 左竖条（只染底色的话色觉障碍用户看不出来） */
  box-shadow: inset 3px 0 0 var(--primary);
}

