/* IshiQuant dashboard
 *
 * 设计立意:这块面板的主题不是"交易",是**诚实**。这套系统反复在做的事——标 n、
 * 残差单列、真金不与模拟相加、缺失渲染 — ——才是它区别于任何一块交易面板的地方。
 * 所以「口径注记」是一等公民(.caliber:贴着它所限定的数字、左侧一道细规线),
 * 而不是塞在页脚的免责声明。
 *
 * 视觉语言(2026-08-25 用户拍板改走 FUI,参照 Nicolas Lopardo 的设计语言;
 * 替换 2026-08-23 的 Coinbase 方案):
 *   · **暗色是签名态**:近黑底 + 发丝规线 + 一点冷青强调;亮色不是反色,
 *     是同一套语言的"图纸"变体(纸白 + 灰蓝细线),三态主题架构不动。
 *   · 层级靠**刻度感**:微型标签一律等宽小字加字距(CJK 加字距同样成立),
 *     区块标题带 CSS 计数器编号(01 / 净值)——仪器面板的目录感,纯 CSS 零 JS。
 *   · **直角**:卡片/控件/徽标全部 2px,药丸形废除;卡片四角带 L 形角标
 *     (FUI 的 corner bracket,只做对角两枚,做满四枚会吵)。
 *   · 页面底衬一层极淡点阵网格(卡片自带表面,点阵只在留白处露出)。
 *   · 强调色换成冷青(cyan)——比蓝更"仪器";饱和红绿仍**只**留给带符号的
 *     数字与净值曲线,那是语义不是装饰。
 *   · 线更细:主线 1.6、分量线 1.2 —— FUI 的密度来自细线,不来自粗线堆叠。
 *
 * 字体只能用系统栈(CSP 挡外部字体,零外部资产是当初的设计决定)。
 * 等宽栈就是这套语言的母语;CJK 字形自动回退系统中文字体,无需入栈。
 */

/* ── Design tokens ────────────────────────────────────────────────────────
 * 三态主题:默认跟随系统(prefers-color-scheme),`[data-theme]` 手动覆盖。
 * ⚠ 每个颜色都必须在**裸 :root** 里有定义(浅色为基准),深色只重定义,
 * 不许有哪个颜色只活在某个 media/attr 块里——那会在另一态下变成 unset。
 */
:root {
  /* 表面:纸 → 卡 → 轨(hover / 分段控件底) */
  --s0: #f2f4f6;
  --s1: #fbfcfd;
  --s2: #e9edf0;
  --rule: #d3dae0;
  --rule-soft: #e2e7eb;
  --tick: #a9b4bd;          /* 卡片角标 L 线:比规线深一档才立得住 */
  --grid-dot: rgba(20, 40, 55, .07);   /* 页底点阵 */
  /* 墨:主 → 次 → 弱 */
  --t0: #10161c;
  --t1: #5a6672;
  --t2: #8b95a0;
  /* 语义 */
  --accent: #0072a3;
  --accent-soft: #ddf0f9;
  --pos: #0a8a54;
  --neg: #d21f2f;
  --warn: #b4670e;
  --pos-bg: #e2f3ea;  --pos-line: #aeddc4;
  --neg-bg: #fbe9eb;  --neg-line: #f2b8be;
  --warn-bg: #fdf1e1; --warn-line: #eed4a6;
  --mute-bg: #e9edf0; --mute-line: #d3dae0;
  /* 图表 */
  --c-genesis: #0072a3;
  --c-cpu: #0072a3;
  --c-mem: #0a8a54;
  /* 多序列调色板。**按下标取,不按腿名** —— 代际换腿(gen13 是 BTC/ETH/ADA、
     gen15 是 BTC/SOL/XAU)时零改动即正确。五个够用:三条腿 + 余量。
     选色要求:同一张图上彼此可分,且**不与涨绿跌红撞车** —— 那两个颜色在这套
     面板里已经表示"赚/亏",拿来当序列色会让人以为某条腿在亏钱。 */
  --c-s1: #0072a3;
  --c-s2: #6d28d9;
  --c-s3: #b45309;
  --c-s4: #3b5bdb;
  --c-s5: #be185d;
  --grid: #e2e7eb;
  --shadow: rgba(16, 22, 28, .14);

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
          "Liberation Mono", monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
          "Hiragino Sans GB", "Microsoft YaHei", Roboto, sans-serif;

  /* 排版刻度:四级,不多不少。审计发现原来 242 个文本节点里 194 个同一个字号,
     等于没有层级——眼睛没有落点。
     FUI 的层级公式:标签**等宽 + 字距**、正文安静、数字大而紧 —— 拉开层级的
     是"质感差"(刻度字 vs 正文字),不只是字号差。 */
  --fz-label: 11px;   /* 标签:等宽小字加字距,永远不承载数值 */
  --fz-body: 14px;    /* 正文与表格 */
  --fz-head: 16px;    /* 顶栏品牌字号(区块标题另行定义,见 h2) */
  --fz-kpi: 27px;     /* KPI 数字 */
  --fz-hero: 34px;    /* 分区合计 */
  --ls-label: .1em;   /* 微型标签的字距 —— 刻度感的来源,CJK 同样适用 */

  /* FUI 全直角:卡片/控件/徽标一律 2px,药丸形废除(--r-pill 保留变量名
     以免漏改,但值就是直角 —— 改回大圆角等于换语言,别单点调)。 */
  --r-card: 2px;
  --r-ctl: 2px;
  --r-pill: 2px;

  --pad: 16px;        /* 间距基数 4 的倍数 */
  --tap: 40px;        /* 可点元素最小高度 */
  color-scheme: light;
}

/* 深色态的两处定义必须逐条同步 —— 这里刻意重复而不是 @extend:
   一处漏改就会在某一态下留下上一版的颜色,而那种 bug 只有切主题才看得见。 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --s0: #050708;
    --s1: #0b0e12;
    --s2: #13181d;
    --rule: #222932;
    --rule-soft: #171d23;
    --tick: #3b454f;
    --grid-dot: rgba(160, 190, 210, .05);
    --t0: #e8edf2;
    --t1: #7f8a95;
    --t2: #58626c;
    --accent: #4fc3ff;
    --accent-soft: #0b2434;
    --pos: #05b169;
    --neg: #ff5c5c;
    --warn: #e0a343;
    --pos-bg: #0c2418;  --pos-line: #1a4c33;
    --neg-bg: #2b1416;  --neg-line: #5e262a;
    --warn-bg: #2b2110; --warn-line: #5a4519;
    --mute-bg: #13181d; --mute-line: #222932;
    --c-genesis: #4fc3ff;
    --c-cpu: #4fc3ff;
    --c-mem: #05b169;
    --c-s1: #4fc3ff;
    --c-s2: #b18cff;
    --c-s3: #ffb454;
    --c-s4: #7d8fff;
    --c-s5: #ff7fb2;
    --grid: #14191f;
    --shadow: rgba(0, 0, 0, .6);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --s0: #050708;
  --s1: #0b0e12;
  --s2: #13181d;
  --rule: #222932;
  --rule-soft: #171d23;
  --tick: #3b454f;
  --grid-dot: rgba(160, 190, 210, .05);
  --t0: #e8edf2;
  --t1: #7f8a95;
  --t2: #58626c;
  --accent: #4fc3ff;
  --accent-soft: #0b2434;
  --pos: #05b169;
  --neg: #ff5c5c;
  --warn: #e0a343;
  --pos-bg: #0c2418;  --pos-line: #1a4c33;
  --neg-bg: #2b1416;  --neg-line: #5e262a;
  --warn-bg: #2b2110; --warn-line: #5a4519;
  --mute-bg: #13181d; --mute-line: #222932;
  --c-genesis: #4fc3ff;
  --c-cpu: #4fc3ff;
  --c-mem: #05b169;
  --c-s1: #4fc3ff;
  --c-s2: #b18cff;
  --c-s3: #ffb454;
  --c-s4: #7d8fff;
  --c-s5: #ff7fb2;
  --grid: #14191f;
  --shadow: rgba(0, 0, 0, .6);
}

/* ── Base ─────────────────────────────────────────────────────────────── */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--s0);
  color: var(--t0);
  font: var(--fz-body)/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;     /* 兜底:任何漏网的宽元素不许把整页横着拖走 */
  /* 页底点阵网格 —— FUI 的坐标纸底衬。卡片/顶栏/侧栏都有自己的表面,
     点阵只在页面留白处露出来,不会衬在文字底下。 */
  background-image: radial-gradient(circle, var(--grid-dot) 1px, transparent 1.5px);
  background-size: 26px 26px;
}
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.up { color: var(--pos); }
.down { color: var(--neg); }
.dim { color: var(--t1); }
.miss { color: var(--t2); }
.tl { text-align: left; }

/* ── 顶栏 ─────────────────────────────────────────────────────────────── */
.topbar {
  display: flex; align-items: center; gap: 22px;
  padding: 0 var(--pad); min-height: 56px;
  background: var(--s1); border-bottom: 1px solid var(--rule);
  position: sticky; top: 0; z-index: 20;
  flex-wrap: wrap;
}
.brand {
  font-family: var(--mono);
  font-weight: 700; letter-spacing: .08em; font-size: var(--fz-head);
  text-transform: uppercase;
  white-space: nowrap; display: flex; align-items: center; gap: 10px;
}
/* 品牌标。内联 data URI 而不是独立文件:MANIFEST 只按住 html/js/css,
   一张 .png 放进 /var/www 就成了清单外的公网资产;而且静态资产要另装一次到
   /var/www,少一个能忘的步骤。位图取自源 PNG 自己的 alpha 通道(源图本来就是
   透明的),128px 供 26px 显示位用,4.9× 过采样,视网膜屏也够。 */
.mark {
  flex: 0 0 auto; width: 24px; height: 24px;
  background: url(data:image/png;base64,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) center/contain no-repeat;
}
/* 冷青交给标去承担 —— 标已经带蓝青,字里再挑一个词染色就是两处色在打架。 */
.brand em { font-style: normal; color: inherit; }
.spacer { flex: 1 1 auto; }
.tabs { display: flex; gap: 2px; }
.tab {
  background: none; border: 0; color: var(--t1); cursor: pointer;
  font: 500 11.5px/1 var(--mono); letter-spacing: var(--ls-label);
  text-transform: uppercase;
  padding: 0 4px; margin: 0 8px;
  height: var(--tap); border-radius: 0; white-space: nowrap;
  box-shadow: inset 0 -2px 0 transparent;
}
.tab:hover { color: var(--t0); }
/* 活动态只加重字重 + 一道强调色下划线 —— FUI 的导航不填色块 */
.tab.on { color: var(--t0); font-weight: 700; box-shadow: inset 0 -2px 0 var(--accent); }
.tabs.sub {
  padding: 8px var(--pad) 0; border-bottom: 1px solid var(--rule-soft);
  background: var(--s0); overflow-x: auto; scrollbar-width: none;
}
.tabs.sub::-webkit-scrollbar { display: none; }
.meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.stamp {
  font-family: var(--mono); font-size: var(--fz-label); color: var(--t1);
  letter-spacing: .03em; white-space: nowrap;
}
select {
  background: var(--s1); color: var(--t0); border: 1px solid var(--rule);
  border-radius: var(--r-ctl); padding: 0 10px; height: 32px;
  font: 500 11.5px/1 var(--mono); letter-spacing: .04em; cursor: pointer;
}
select:hover { border-color: var(--t2); }

/* ── 布局:内容区 + 右侧导航 ──────────────────────────────────────────
 * 一级(Performance / System)在顶栏 —— 它是"看哪一类东西"的总开关;
 * 二三级(线 × 分页)在右栏 —— 纵向可扩展,加线加页都不会把页顶挤窄。
 * System 只有一页,右栏无内容时整块收起(.no-side),正文铺满。
 */
.shell {
  display: grid; grid-template-columns: 232px minmax(0, 1fr);
  max-width: 1512px; margin: 0 auto; align-items: start;
}
.shell.no-side { grid-template-columns: minmax(0, 1fr); }
.shell.no-side .side { display: none; }
/* 侧栏是一条**轨**,不是一列裸按钮:自己的表面 + 一道分隔规线,
   这样内容区的左边界才立得住。 */
.side {
  position: sticky; top: 56px;            /* 顶栏高度 */
  padding: 24px 12px;
  display: flex; flex-direction: column; gap: 28px;
  max-height: calc(100vh - 56px); overflow-y: auto;
  background: var(--s1); border-right: 1px solid var(--rule-soft);
  min-height: calc(100vh - 56px);
}
.nav-group { display: flex; flex-direction: column; gap: 4px; }
.nav-title {
  font-family: var(--mono); font-size: 10.5px; color: var(--t2); font-weight: 700;
  padding: 0 12px 6px; letter-spacing: var(--ls-label); text-transform: uppercase;
}
.nav-item {
  background: none; border: 0; color: var(--t1); cursor: pointer;
  font: inherit; font-size: 14px; font-weight: 500; text-align: left;
  padding: 0 12px; height: 40px; border-radius: 0;
  white-space: nowrap; display: flex; align-items: center;
  /* 活动态左侧那道竖条用 border 占位,不活动时透明 —— 用 padding 位移
     会让文字在切换时左右跳一下。 */
  border-left: 2px solid transparent;
}
.nav-item:hover { background: var(--s2); color: var(--t0); }
.nav-item.on {
  background: var(--accent-soft); color: var(--accent); font-weight: 700;
  border-left-color: var(--accent);
}
.burger { display: none; }

main { padding: 24px 24px 0; min-width: 0; }
.loading { color: var(--t1); padding: 44px 0; font-family: var(--mono); font-size: 12px; letter-spacing: .06em; }
section { margin-bottom: 34px; }
/* 区块标题:等宽 + 字距 + 计数器编号(01 / 净值)—— 仪器面板的目录感。
   编号按 section 在 main 里的出现顺序自增,纯 CSS,页序变了编号自己跟着变。
   ⚠ 字号故意小于 KPI/正文 —— FUI 的标题是"刻度",不是"标语"。 */
main { counter-reset: sec; }
h2 {
  font-family: var(--mono);
  font-size: 12.5px; letter-spacing: var(--ls-label); text-transform: uppercase;
  color: var(--t0); font-weight: 700;
  margin: 0 0 12px; display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
h2::before {
  counter-increment: sec;
  content: counter(sec, decimal-leading-zero);
  color: var(--accent); font-weight: 700;
  padding-right: 8px; border-right: 1px solid var(--rule);
}
h2 .sub {
  font-family: var(--sans); text-transform: none;
  letter-spacing: 0; font-weight: 400; font-size: 12px; color: var(--t1);
}
/* 卡片:直角 + 对角两枚 L 形角标(corner bracket)。四角做满会吵,
   对角两枚就足以把"面板感"立起来。角标线比规线深一档(--tick)。 */
.card {
  background: var(--s1); border: 1px solid var(--rule-soft);
  border-radius: var(--r-card); padding: 20px;
  position: relative;
}
.card::before, .card::after, .kpis::before, .kpis::after {
  content: ""; position: absolute; width: 8px; height: 8px; pointer-events: none;
}
.card::before, .kpis::before {
  top: -1px; left: -1px;
  border-top: 1px solid var(--tick); border-left: 1px solid var(--tick);
}
.card::after, .kpis::after {
  bottom: -1px; right: -1px;
  border-bottom: 1px solid var(--tick); border-right: 1px solid var(--tick);
}
.grid { display: grid; gap: 14px; }

/* ── 口径注记 —— 本设计的签名元素 ──────────────────────────────────────
 * 左侧一道规线 + 小字,读起来像仪器旁边的铭牌而不是免责声明。
 * 它贴着它所限定的数字,不许再被放逐到页脚。
 */
.caliber {
  margin: 14px 0 0; padding: 6px 0 6px 14px;
  border-left: 2px solid var(--rule);
  font-size: 12.5px; line-height: 1.7; color: var(--t1);
  overflow-wrap: break-word;   /* 长 ASCII 标识符/路径不许把卡片横向撑破 */
}
.caliber b { color: var(--t0); font-weight: 600; }

/* 口径说明的**红牌版**:同一套铭牌形制,但这条不是"顺带一提",而是
   "这个数现在可能是假的,去核对"。用 caliber 的骨架换告警色,保证它长在
   数字旁边而不是被当成页脚免责声明滑过去。 */
.warn {
  margin: 14px 0 0; padding: 10px 12px 10px 14px;
  border-left: 3px solid var(--warn); border-radius: 0;
  background: var(--warn-bg); color: var(--warn);
  font-size: 12.5px; line-height: 1.7;
}
.warn b { color: var(--warn); font-weight: 700; }

/* ── 「口径与算法」折叠区 ─────────────────────────────────────────────
 * 2026-08-24:实测 Genesis 总览 62% 的字是说明文字 —— 那不是仪表盘,是一份
 * 嵌了图表的说明书。而且更糟:一条真警告和一段读过 40 遍的解释长得一模一样,
 * 说明文字成了警告的迷彩。
 *
 * 三层分工:**常驻** = 会改变行动的;**悬停**(title) = 这个数怎么算的;
 * **折叠** = 为什么这么设计、踩过什么坑。后端 `note` 字段本来就全是第三层,
 * 之前被当成第一层渲染了 —— 这不是内容问题,是渲染层级放错了。
 *
 * 用原生 <details>:不需要 JS,也就不会被 CSP 拦。 */
details.cal {
  margin: 12px 0 0; font-size: 12.5px; line-height: 1.7; color: var(--t1);
}
details.cal > summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center;
  gap: 6px; color: var(--t2); font-size: 11px; padding: 2px 0;
  font-family: var(--mono); letter-spacing: .05em;
  user-select: none;
}
details.cal > summary::-webkit-details-marker { display: none; }
details.cal > summary::before {
  content: "›"; display: inline-block; transition: transform .12s ease;
  font-size: 14px; line-height: 1;
}
details.cal[open] > summary::before { transform: rotate(90deg); }
details.cal > summary:hover { color: var(--t0); }
details.cal .body {
  margin-top: 8px; padding: 0 0 2px 14px;
  border-left: 2px solid var(--rule);
  overflow-wrap: break-word;   /* 同 .caliber:折叠展开后一样不许横向溢出 */
}
details.cal .body b { color: var(--t0); font-weight: 600; }
details.cal .body p { margin: 0 0 8px; }
details.cal .body p:last-child { margin-bottom: 0; }
@media (prefers-reduced-motion: reduce) {
  details.cal > summary::before { transition: none; }
}

/* ── KPI 带 —— 规线分隔,不是一排盒子 ──────────────────────────────────── */
.kpis {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(146px, 1fr));
  border: 1px solid var(--rule-soft); border-radius: var(--r-card);
  background: var(--s1);
  position: relative;   /* 角标定位锚(::before/::after 与 .card 共用规则) */
}
.kpi {
  padding: 16px; border-left: 1px solid var(--rule-soft);
  min-width: 0;                 /* 网格项默认 min-width:auto,不给 0 就压不下来 */
}
.kpi:first-child { border-left: 0; }
.kpi .k {
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: var(--ls-label); text-transform: uppercase;
  color: var(--t1); font-weight: 500;
}
/* ⚠ 数字与它的 n 徽标同处一行,而 140px 的格子放不下「−6.33% + n=2.8天」——
   默认的行内流会把徽标**从中间**折断成"n=2.8 / 天"两行,数字的基线跟着塌
   (2026-08-23 实测)。改成 flex + 徽标 nowrap:放得下就并排,放不下整块徽标
   落到下一行左对齐,数字那一行永远完整。 */
.kpi .v {
  font-family: var(--mono); font-size: var(--fz-kpi); font-weight: 500;
  margin-top: 6px; letter-spacing: -.02em; line-height: 1.18;
  display: flex; flex-wrap: wrap; align-items: baseline;
  column-gap: 7px; row-gap: 3px;
  /* ⚠ 数字整体不许断行。默认流会在 `−` 和 `$` 之间断,把负号单独甩到上一行
     (2026-08-24 在 Lumin 上实测,四五位数字全中)。 */
  white-space: nowrap;
}
/* 长数字降字号 —— 由 kpi() 按字符数打的档。$94,959.86 这种十字符在 151px
   的格子里放不下 27px,不缩就会挤进邻格(实测最多 31px)。 */
.kpi .v.len-md { font-size: 21px; }
.kpi .v.len-lg { font-size: 17px; }
.kpi .n { font-size: 11.5px; color: var(--t2); margin-top: 4px; }
/* 样本量内联在数字旁 —— 让人没法只读数字不读它的 n */
.nbadge {
  font-family: var(--mono); font-size: 10px; font-weight: 600; white-space: nowrap;
  letter-spacing: .04em;
  padding: 2px 6px; border-radius: var(--r-pill); align-self: center;
  color: var(--warn); background: var(--warn-bg); border: 1px solid var(--warn-line);
}

/* ── 表 ───────────────────────────────────────────────────────────────── */
table { width: 100%; border-collapse: collapse; font-size: var(--fz-body); }
th, td { padding: 11px 16px; text-align: right; white-space: nowrap; }
th:first-child, td:first-child { text-align: left; }
th {
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: var(--ls-label); text-transform: uppercase;
  color: var(--t1); border-bottom: 1px solid var(--rule);
}
tbody tr { border-bottom: 1px solid var(--rule-soft); }
tbody tr:last-child { border-bottom: 0; }
tbody tr:hover { background: var(--s2); }
td.num, th.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
/* 状态徽标列(System 页心跳/定时器共用,2026-08-26):窄、左对齐、紧贴名称列 ——
   徽标是"判定",该挨着被判定的东西,不该被甩到表格中央。 */
th.st, td.st { text-align: left; width: 1%; white-space: nowrap; padding-right: 28px; }
/* System 页两张表(table.sys)钉死列规,不交给浏览器自动分宽:名称列 30%,
   状态/数字列按内容收紧,末尾的说明/结果列(.tl)吸收余宽 —— 两张表列节奏一致。 */
/* table-layout:fixed + 列宽全部显式给百分比 —— 两张表的列边界才会**逐像素重合**;
   auto 布局下 1% 只是"尽量窄",实际宽度仍随内容漂,上下两表对不齐(2026-08-26)。 */
table.sys { table-layout: fixed; }
table.sys th:first-child { width: 30%; }
table.sys th.st { width: 12%; }
table.sys th.num { width: 15%; }
table.sys th.tl { width: 28%; }
table.sys td.head { overflow: hidden; text-overflow: ellipsis; }
table.sys td.tl { white-space: normal; }
tr.total td { border-top: 1px solid var(--rule); font-weight: 600; }
/* 定时器表的分组分隔行(2026-08-25):同一张表按 Genesis/Lumin/News/Infra 分段。
   悬停不该像数据行那样亮起 —— 它不是一条记录。 */
tr.grp td {
  padding: 14px 16px 5px; text-align: left; white-space: normal;
  font-family: var(--mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--t1);
  border-bottom: 1px solid var(--rule);
}
tbody tr.grp:hover { background: none; }
/* 宽表一律进滚动容器 —— 没有它,窄屏上整页会被横着拖走(2026-08-23 审计实测:
   手机上综合页 scrollWidth 662 / 视口 390) */
.scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tall { max-height: 430px; overflow-y: auto; }
/* 窄屏解除限高(2026-08-25 真机审计):卡片化后每笔 ~170px,430px 只露出
   两张半,第三张被拦腰切断、后面的口径叠在半张卡上,观感像页面坏了。 */
@media (max-width: 620px) { .tall { max-height: none; overflow-y: visible; } }

/* ── 状态徽标 ─────────────────────────────────────────────────────────── */
/* .nbadge 的琥珀色是「样本量警告」的语义,别的数字借用会让警告贬值。
   中性变体给那些只是想紧贴数字的小标(比如超额百分比)。 */
.nbadge.nb-plain {
  color: var(--t1); background: var(--mute-bg); border-color: var(--mute-line);
}

.pill {
  display: inline-block; padding: 2px 8px; border-radius: var(--r-pill);
  font-family: var(--mono); font-size: 10.5px; font-weight: 600;
  letter-spacing: .05em; border: 1px solid; white-space: nowrap;
}
.pill.ok { color: var(--pos); border-color: var(--pos-line); background: var(--pos-bg); }
.pill.warn { color: var(--warn); border-color: var(--warn-line); background: var(--warn-bg); }
.pill.stale, .pill.bad { color: var(--neg); border-color: var(--neg-line); background: var(--neg-bg); }
.pill.mute { color: var(--t1); border-color: var(--mute-line); background: var(--mute-bg); }

/* ── 图 ───────────────────────────────────────────────────────────────── */
figure { margin: 0; }
svg { display: block; width: 100%; height: auto; }
/* 柱状图的透明命中区。0.4 格宽的柱子在日线视图里只有两三像素 ——
   按柱子本身做热区等于"要瞄准才看得见提示"。 */
.hit { fill: transparent; }
/* 执行质量条带:一笔一格,挂单/吃单两色 */
.ex-m { fill: var(--t2); }
.ex-t { fill: var(--warn); }
.lg-maker { color: var(--t2); }
.lg-taker { color: var(--warn); }
.hit:hover { fill: var(--t0); fill-opacity: .05; }
.axis text { fill: var(--t2); font-size: 9.5px; font-family: var(--mono); letter-spacing: .03em; }
.grid-line { stroke: var(--grid); }
.mark-line { stroke: var(--accent); stroke-dasharray: 4 3; stroke-width: 1; }
.mark-label { fill: var(--accent); font-size: 9.5px; font-family: var(--mono); }
.limit-line { stroke: var(--warn); stroke-dasharray: 4 3; stroke-width: 1; }
.limit-label { fill: var(--warn); font-size: 9.5px; font-family: var(--mono); }
.cross { stroke: var(--t2); stroke-dasharray: 2 2; }
/* 系列颜色走 class,不走内联 style —— CSP 是 style-src 'self',内联样式会被拦。
   走 CSS 变量还有第二个好处:切主题时图表跟着变,不用重画。
   线宽整体收细一档 —— FUI 的密度来自细线,主线 1.6 已是最粗的普通线。 */
.ln { fill: none; stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round; }
.ln-nav     { stroke: var(--c-genesis); }
/* 净值曲线**按区间涨跌着色**(涨绿跌红)+ 一层渐变填充。它编码的是事实
   (这段区间是赚是亏),不是装饰;判不出方向时才留强调色。
   ⚠ 走 class 不走内联 style:CSP 是 style-src 'self',而且切主题要跟着变。 */
svg.trend-up   .ln-nav { stroke: var(--pos); }
svg.trend-down .ln-nav { stroke: var(--neg); }
.area { stroke: none; }
.ar0 { stop-color: var(--c-genesis); stop-opacity: .16; }
.ar1 { stop-color: var(--c-genesis); stop-opacity: 0; }
/* 水下曲线:整条都是负的,红 */
svg.uw .ln-dd { stroke: var(--neg); }
svg.uw .ar0, svg.uw .ar1 { stop-color: var(--neg); }
svg.trend-up   .ar0, svg.trend-up   .ar1 { stop-color: var(--pos); }
svg.trend-down .ar0, svg.trend-down .ar1 { stop-color: var(--neg); }
/* 逐腿权重图。序列色按下标(ln-s1..s5),理由见 :root 里那段注释 */
/* 总敞口是**总量**不是某条腿,所以不进 s1..s5 那套配色。
   2026-08-24 用户拍板:与净值曲线同款 —— 绿色、实线;三条腿改虚线,一眼分出
   "总量 vs 分量"。2026-08-26 再拍板:线宽同净值(1.6)并带同款渐变阴影。
   ⚠ 绿色在本面板别处表示"赚",这里表示的是**总敞口**不是盈亏 ——
   实线/虚线的对比与图例文字共同承担区分,不要再给别的序列上绿色。 */
.ln-gross { stroke: var(--pos); stroke-width: 1.6; }   /* 2026-08-26:与净值主线同宽 */
/* 持仓图(svg.wt)的渐变阴影挂在总敞口下,同净值曲线的样式,只是色取总敞口的绿 */
svg.wt .ar0, svg.wt .ar1 { stop-color: var(--pos); }
.lg-gross { color: var(--pos); }
.ln-s1 { stroke: var(--c-s1); }
.ln-s2 { stroke: var(--c-s2); }
.ln-s3 { stroke: var(--c-s3); }
.ln-s4 { stroke: var(--c-s4); }
.ln-s5 { stroke: var(--c-s5); }
/* 腿多线密,粗线会糊在一起 —— 只有净值/总敞口那条主线值得加粗。
   虚线:与总敞口那条实线区分"分量 vs 总量"。 */
.ln-s1, .ln-s2, .ln-s3, .ln-s4, .ln-s5 {
  stroke-width: 1.2; stroke-dasharray: 5 3;
}
/* 图例的小横线是 border-top: currentColor,所以给 color 不给 background */
/* 图例可点选:隐藏/显示一条线。<button> 要先卸掉浏览器默认外观,
   否则在图例里会长出一圈灰边和内边距,和旁边的静态图例对不齐。 */
.legend button {
  background: none; border: 0; padding: 0; margin: 0; font: inherit;
  color: inherit; cursor: pointer; display: inline-flex; align-items: center;
}
.legend button:hover { text-decoration: underline; text-underline-offset: 3px; }
.legend button:focus-visible { outline: 2px solid var(--c-genesis); outline-offset: 3px; }
/* 关掉的那条:压淡 + 图例横线改虚线。**只压淡不改线型的话,深色模式下几乎看不出
   区别** —— 关/开必须一眼可辨,否则读者会以为图坏了。 */
.legend button.off { opacity: .45; }
.legend button.off i { border-top-style: dotted; }
.lg-s1 { color: var(--c-s1); }
.lg-s2 { color: var(--c-s2); }
.lg-s3 { color: var(--c-s3); }
.lg-s4 { color: var(--c-s4); }
.lg-s5 { color: var(--c-s5); }
.ln-cpu     { stroke: var(--c-cpu); }
.ln-mem     { stroke: var(--c-mem); }
/* sar 序列点密、锯齿多,粗线会糊成一片色块 —— 细线才读得出形 */
.ln-cpu, .ln-mem { stroke-width: 1.2; }
.bar-pos { fill: var(--pos); }
.bar-neg { fill: var(--neg); }
.bar-residual { fill: var(--t2); opacity: .5; }
.bar-lbl { fill: var(--t0); font-size: 12px; font-family: var(--sans); }
/* .bar-val 已删(2026-08-25):归因柱不再带数值标签,数字归下方表格 */
.hist-bar { fill: var(--accent); opacity: .5; }
.legend {
  display: flex; gap: 15px; flex-wrap: wrap;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .05em;
  color: var(--t1); margin-top: 9px;
}
.legend i { display: inline-block; width: 18px; height: 0; vertical-align: middle;
            margin-right: 6px; border-top: 2px solid currentColor; }
.legend .dash { border-top-style: dashed; }
/* 图表 tooltip 的行:色块 + 名字 + 读数。四条线的读数并排列着,
   没有色块就分不清哪个数是哪条线的 —— 这是它存在的全部理由。
   ⚠ 颜色复用 .lg-<key>(与图上的线同一个 CSS 变量),不另抄一份色值。
   小横线走 border-top: currentColor,与图例那套一致。 */
.tip-t { color: var(--t2); margin-bottom: 4px; }
.tip-row { display: flex; align-items: center; gap: 7px; white-space: nowrap; }
.tip-sw {
  display: inline-block; width: 14px; height: 0; flex: 0 0 auto;
  border-top: 2px solid currentColor;
}
.tip-sw.dashed { border-top-style: dashed; }
/* 名字用序列色,读数用正文色 —— 数字要最容易读,不该被彩色削弱 */
.tip-nm { color: inherit; }
.tip-v { color: var(--t0); margin-left: auto; font-family: var(--mono); }
.range { display: flex; gap: 6px; margin-bottom: 14px; flex-wrap: wrap; }
.range button {
  background: transparent; border: 1px solid transparent; color: var(--t1);
  border-radius: var(--r-pill); padding: 0 12px; height: 30px;
  font: 500 11px/1 var(--mono); letter-spacing: .06em; cursor: pointer;
}
.range button:hover { background: var(--s2); color: var(--t0); }
.range button.on {
  background: var(--accent-soft); color: var(--accent);
  border-color: var(--accent); font-weight: 700;
}

/* ── tooltip ──────────────────────────────────────────────────────────── */
.tip {
  position: fixed; pointer-events: none; z-index: 50;
  background: var(--s1); color: var(--t0);
  border: 1px solid var(--rule); border-radius: var(--r-ctl);
  padding: 7px 10px; font-size: 12px; font-family: var(--mono);
  box-shadow: 0 8px 24px var(--shadow); white-space: pre;
}

/* 富 tooltip:子策略分解卡片。默认那枚 tooltip 是等宽纯文本(小卡),
   这个要宽一些、左对齐、正常字体。 */
.tip.rich {
  font-family: inherit; font-size: 12px; white-space: normal;
  padding: 10px 12px; max-width: 340px;
}
.splitcard[hidden] { display: none; }
.tip .splitcard { display: block; }
/* ⚠ 表格单元格里那份是**模板**,永远不显示 —— 显示的是 bindTips 克隆到
   #tip 里的那一份。放在单元格里只是为了让它走页面正常的渲染路径。 */
td .splitcard { display: none; }

/* 有分解可看的腿名:虚线下划线 + help 光标。原先在腿名后面挂一句
   「子策略分解 ▾」,和「BTC 多」挤成了「BTC 多子策略分解」(2026-08-24 实测)。
   虚线下划线是"这里还有东西"的标准提示,不占一行也不会挤。 */
td.head .cue {
  border-bottom: 1px dashed var(--t2); cursor: help;
}
td.head.has-card { cursor: help; }

.sc-head {
  font-size: 13px; font-weight: 700; color: var(--t0);
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding-bottom: 6px; border-bottom: 1px solid var(--rule); margin-bottom: 6px;
}
.sc-tgt { font-family: var(--mono); font-weight: 600; color: var(--accent); }
.sc-now { font-size: 11px; font-weight: 400; color: var(--t2); }

/* 轨道要能看出量程 —— 不画轨道时一根短柱是"占一点点"还是"整条就这么长",
   读者分不出来。 */
.sc-track { fill: var(--s2); }
.sc-pos { fill: var(--pos); }
.sc-neg { fill: var(--neg); }
.sc-zero { stroke: var(--t2); stroke-width: 1; opacity: .85; }
.sc-lbl { fill: var(--t1); font-size: 11px; }
.sc-val { font-family: var(--mono); font-size: 10.5px; }
.sc-val.pos { fill: var(--pos); }
.sc-val.neg { fill: var(--neg); }
.sc-val.mute { fill: var(--t2); }

.sc-foot {
  display: flex; flex-direction: column; gap: 3px;
  margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--rule);
  font-size: 11px; line-height: 1.55; color: var(--t1);
}
.sc-foot b { color: var(--t0); font-weight: 600; }
.sc-foot i { color: var(--t2); font-style: normal; }

/* ── 算法说明页 ───────────────────────────────────────────────────────
 * 这一页本身就是说明书,所以文字密度高是对的 —— 但仍要可扫读:
 * 段落有呼吸、公式块单列、参数值加粗且可悬停查键名。 */
.algo-p { margin: 0 0 10px; font-size: 13.5px; line-height: 1.85; color: var(--t1); }
.algo-p:last-child { margin-bottom: 0; }
.algo-p b { color: var(--t0); font-weight: 600; }
.algo-l { margin: 0 0 10px; padding-left: 20px; }
.algo-l li { font-size: 13.5px; line-height: 1.85; color: var(--t1); margin-bottom: 6px; }
.algo-l li b { color: var(--t0); font-weight: 600; }
.algo-f {
  font-family: var(--mono); font-size: 12px; line-height: 1.75;
  background: var(--s0); border: 1px solid var(--rule-soft);
  border-radius: var(--r-ctl); padding: 12px 14px; margin: 0 0 12px;
  overflow-x: auto; color: var(--t0);
}
/* 参数值:加粗 + 虚线下划线,悬停给出它在 strategy.toml 里的键名 ——
   想核对的人不必去翻源码。 */
.pv {
  color: var(--accent); font-weight: 600; font-family: var(--mono);
  border-bottom: 1px dotted var(--accent); cursor: help;
}
section[data-sec="algo"] h3 {
  font-size: 14px; font-weight: 700; color: var(--t0); margin: 0 0 8px;
}
section[data-sec="algo"] h3.mt16 { margin-top: 20px; }
/* ⚠ 表头也要跟着左对齐 —— 全局 th/td 默认 text-align:right(为了数字列),
   只改 td 会让表头和内容各靠一边。 */
.algo-t th, .algo-t td { text-align: left; vertical-align: top; white-space: normal; }
.algo-t td:first-child, .algo-t th:first-child { white-space: nowrap; width: 64px; }
.algo-t td:first-child { font-weight: 600; color: var(--t0); }
.algo-t td:nth-child(2) { width: 42%; }
.algo-t td, .algo-t th { padding: 10px 14px 10px 0; }

/* ── 出错 / 缺失 ──────────────────────────────────────────────────────── */
.err {
  border: 1px solid var(--neg-line); background: var(--neg-bg); color: var(--neg);
  border-left-width: 3px;
  border-radius: var(--r-ctl); padding: 12px 14px; font-size: var(--fz-body);
}
.err code { font-family: var(--mono); opacity: .85; }
/* ⚠ 错误文案里常常带长路径/长 URL,这类串没有断行点,会把整页顶出视口
   (2026-08-24 实测:一条含 Windows 路径的 sar 报错在 390px 上溢出 140px)。
   报错本来就是意外情形,它更不该顺手再破坏一次版式。 */
.err, .err code { overflow-wrap: anywhere; word-break: break-word; }
.mt12 { margin-top: 12px; }
.mt16 { margin-top: 16px; }
.mt20 { margin-top: 20px; }
.mb12 { margin-bottom: 12px; }

.foot {
  /* 2026-08-26:页脚只剩一句,居中(原来两句左右分列,max-width 1280 与正文 1512
     的边不齐,单句靠左会像没对齐)。 */
  max-width: 1512px; margin: 0 auto; padding: 4px var(--pad) 32px;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .04em;
  color: var(--t2); text-align: center;
  display: flex; gap: 14px; flex-wrap: wrap; justify-content: center;
}

/* ── 窄屏:表 → 定义行 ─────────────────────────────────────────────────
 * 390px 上一张 9 列的成交表无论怎么滚都读不了。改成每笔一块:
 * 首行是"品种 · 方向 · 时间",其下是 label/value 对。
 * data-l 由 JS 写在每个 td 上,CSS 用 ::before 取出来当行内标签。
 */
/* ≤900px:侧栏收成抽屉。横向铺开的话 7 个按钮加 3 个组标题会挤成两行,
   而且每次点都要先横向滚 —— 抽屉在小屏上反而更快。 */
@media (max-width: 900px) {
  .shell { grid-template-columns: minmax(0, 1fr); }
  .burger {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; border: 1px solid var(--rule);
    border-radius: var(--r-ctl); background: var(--s1); color: var(--t0);
    font-size: 16px; cursor: pointer;
  }
  /* 窄屏:侧栏收成抽屉。它在 DOM 里已经排在正文前面,展开就在顶部。 */
  .side {
    display: none; position: static; max-height: none; min-height: 0;
    padding: 12px var(--pad); border-right: 0;
    border-bottom: 1px solid var(--rule-soft);
    background: var(--s1);
  }
  /* ⚠ 这里**不能**用 flex-direction:column。列向 flex 的交叉轴是水平方向,
     而 align-items:stretch 只会把子项**撑大**、不会压小 —— 子项内容的
     min-content 一宽(System 页那张定时器表 ~500px),main 就跟着变成 590px
     顶出视口,`min-width:0` 也救不了(那个属性管的是主轴)。
     侧栏现在在 DOM 里已经排在正文前面,不再需要 order,所以退回普通块布局。 */
  .shell { display: block; }
  body.side-open .side { display: flex; }
}

@media (max-width: 620px) {
  :root { --pad: 12px; --fz-hero: 27px; --fz-kpi: 21px; }
  main { padding-top: 14px; }
  .topbar { gap: 10px; padding: 8px var(--pad); }
  .meta { width: 100%; order: 3; justify-content: space-between; }
  .kpis { grid-template-columns: repeat(2, 1fr); }
  .kpi { border-left: 1px solid var(--rule-soft); border-top: 1px solid var(--rule-soft); }
  .kpi:nth-child(-n+2) { border-top: 0; }
  .kpi:nth-child(odd) { border-left: 0; }

  table.rows thead { display: none; }
  table.rows, table.rows tbody { display: block; width: 100%; }
  /* 每笔一块卡片,卡内**两列**:一笔成交 7 行拉到 5372px 的页面高度是不能接受的
     (2026-08-23 实测),两列排完高度减半,而且一个字段都没藏。 */
  table.rows tr {
    display: grid; grid-template-columns: 1fr 1fr; gap: 1px 14px;
    border: 1px solid var(--rule-soft); border-radius: var(--r-card);
    padding: 9px 11px; margin-bottom: 8px; background: var(--s1);
  }
  table.rows tr:hover { background: var(--s1); }
  table.rows td {
    text-align: right; padding: 2px 0; white-space: normal; min-width: 0;
    display: flex; justify-content: space-between; gap: 10px;
  }
  /* 空单元格(比如单策略页没有"线"这一列)不许占一行空位 */
  table.rows td:empty { display: none; }
  table.rows td.tl { grid-column: 1 / -1; }
  table.rows td::before {
    content: attr(data-l); text-align: left; color: var(--t1);
    font-size: 10px; letter-spacing: .06em;
    font-family: var(--mono); flex: 0 0 auto; align-self: center;
  }
  /* 策略说明页的「腿 → 它在赌什么 → 信号家族」表:单元格装的是**整句话**,
     不是数字。塞进 1fr 1fr 的两列里每格只有 ~170px,中文会折成一行一个字
     (2026-08-24 实测)。这张表在窄屏上一格占一整行,标签另起一行放在上面。
     ⚠ 选择器必须写成 `table.rows.algo-t` —— 上面那条是 `table.rows tr`
     (0,1,2),`.algo-t tr` 只有 (0,1,1) 会被它压过去,改了等于没改
     (2026-08-24 就是这么先写错一版的:测出来单元格仍是 55px)。 */
  table.rows.algo-t tr { grid-template-columns: 1fr; }
  table.rows.algo-t td { display: block; text-align: left; padding: 3px 0;
    /* 宽屏那两条列宽(第一列 64px、第二列 42%)在卡片模式里必须清掉 ——
       每格独占一行时它们只会把格子压窄,是这次 116px 的直接原因 */
    width: auto; }
  table.rows.algo-t td::before { display: block; margin-bottom: 1px; }
  table.rows.algo-t td:first-child { margin-top: 4px; }
  table.rows.algo-t td:first-child::before { content: none; }

  /* 分组分隔行在卡片化布局里降级为一条窄标签,不摆成卡片 */
  table.rows tr.grp {
    display: block; border: 0; background: none; border-radius: 0;
    padding: 8px 2px 0; margin-bottom: 4px;
  }
  table.rows tr.grp td { display: block; text-align: left; }
  table.rows tr.grp td::before { content: none; }

  table.rows td.head {
    grid-column: 1 / -1;
    display: flex; justify-content: flex-start; gap: 9px; align-items: baseline;
    flex-wrap: wrap;
    border-bottom: 1px solid var(--rule-soft); padding-bottom: 6px; margin-bottom: 5px;
    font-weight: 600;
  }
  table.rows td.head::before { content: none; }
  /* System 表的桌面列宽(30% / 1% / 左内边距)在卡片化布局里必须清掉 ——
     否则名称被压成两行、徽标格被拉成竖条(2026-08-26 真机审计)。 */
  table.sys { table-layout: auto; }
  table.sys td, table.sys th, table.sys td.head, table.sys td.st, table.sys td.num, table.sys td.tl {
    width: auto; padding-left: 0; padding-right: 0; white-space: normal; overflow: visible;
  }
}

/* ── 收益日历 ──────────────────────────────────────────────────────────
 * 左侧日历格 + 右侧当期盈亏柱。格子里三行:日期 / 盈亏 / 收益率。
 * 没有数据的格子**留白**,不写 0 —— "那天没数据"与"那天不赚不亏"是两回事。
 */
.cal-head {
  display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap;
  padding: 4px 0 12px; border-bottom: 1px solid var(--rule-soft); margin-bottom: 12px;
}
.cal-title {
  font-family: var(--mono); font-size: 15px; font-weight: 700;
  letter-spacing: .08em;
}
.cal-sum { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.cal-sum .num { font-size: 17px; margin-right: 6px; }

.cal-wrap { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 18px; }
.cal-left, .cal-right { min-width: 0; }

.cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 1px;
            background: var(--rule-soft); border: 1px solid var(--rule-soft);
            border-radius: var(--r-card); overflow: hidden; }
/* 年视图:横向排列(2026-08-25 用户拍板)——月份从左到右一行一行读,行优先填充,
   每行恰好一个季度,季度标签(.cal-q)在行首。外层仍是单列容器,矩阵自己开网格。 */
.cal-grid.y { grid-template-columns: 1fr; }
.cal-ybody {
  display: grid; grid-template-columns: auto repeat(3, minmax(0, 1fr)); gap: 1px;
  background: var(--rule-soft);
}
.cal-q { display: flex; align-items: center; justify-content: center; padding: 0 10px;
         font-family: var(--mono); font-size: 11px; letter-spacing: .06em; }
.cal-wd {
  background: var(--s2); text-align: center; padding: 7px 0;
  font-family: var(--mono); font-size: 10px; letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--t1); font-weight: 500;
}
.cal-cell {
  background: var(--s1); min-height: 62px; padding: 5px 6px;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  gap: 1px; text-align: center;
}
.cal-grid.y .cal-cell { min-height: 74px; justify-content: center; gap: 3px; }
.cal-cell.blank { background: var(--s0); }
.cal-cell.nodata .cal-d { color: var(--t2); font-weight: 400; }
.cal-cell .cal-d { font-family: var(--mono); font-size: 11px; font-weight: 600; color: var(--t0); }
.cal-cell .num { font-size: 11.5px; line-height: 1.35; }
.cal-cell .num.sm { font-size: 10.5px; opacity: .85; }

@media (max-width: 900px) {
  .cal-wrap { grid-template-columns: 1fr; }
}
@media (max-width: 620px) {
  .cal-cell { min-height: 54px; padding: 4px 2px; }
  .cal-cell .num { font-size: 10px; }
  .cal-cell .num.sm { font-size: 9.5px; }
  /* ⚠ 窄屏动的是**内层**矩阵,别碰 .cal-grid.y(外层是单列容器,改它会把
     矩阵挤成并排格子,2026-08-23 实测塌到 27px 列宽)。横向排列后每行 =
     季度标签 + 3 个月,窄屏放得下,只把标签的内边距收一收。 */
  .cal-q { padding: 0 5px; font-size: 10px; }
  .cal-sum .num { font-size: 15px; }
}

/* 基准线:与净值同图,虚线弱化——它是参照不是主角 */
.ln-bench { stroke: var(--t2); stroke-dasharray: 5 4; }
.lg-nav { color: var(--c-genesis); }
/* 图例色必须跟着曲线的涨跌色走。⚠ .lg-nav 与 .up 同为单类选择器,而 .lg-nav
   写在文件更靠后 —— 不显式写这两条,图例会一直是蓝的而线是绿/红的。 */
.lg-nav.up { color: var(--pos); }
.lg-nav.down { color: var(--neg); }
.lg-bench { color: var(--t2); }

/* ── 登录门 ───────────────────────────────────────────────────────────────
 * 2026-08-26 用户拍板:首页即登录页。同一套 FUI 语言,只是把"仪器"感放大:
 *   · 全屏近黑底 + 点阵网格;中央三圈刻度环慢速反向旋转(conic/dashed),
 *     一条扫描线自上而下扫过;四角 HUD 微标签(等宽 + 字距)。
 *   · 卡片仍是直角 + 对角 L 角标;标(logo)带一圈冷青光晕呼吸。
 *   · 输入框只有底线,聚焦时底线变冷青 —— 表单不该比面板更"网页"。
 *   · 动效全部走 CSS keyframes;prefers-reduced-motion 下由顶部的全局规则关掉。
 * 颜色一律走 token,亮色态自动变成"图纸"版(纸白 + 灰蓝线)。
 * ⚠ 不许有 inline style(CSP 与 test_web 都盯着);状态全靠 class:
 *   body.gated(壳页隐藏)/ .gate.pass(通过揭幕)/ .gate.shake(口令错)/ .gate-btn.busy
 */
body.gated .topbar, body.gated .shell, body.gated .foot { display: none; }
.gate {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: center; justify-content: center;
  background: var(--s0);
  background-image: radial-gradient(circle, var(--grid-dot) 1px, transparent 1.5px);
  background-size: 26px 26px;
  overflow: hidden;
  font-family: var(--mono);
}
.gate[hidden] { display: none; }

/* 背景层:三圈刻度环 + 扫描线 + 两道发丝十字线 */
.gate-bg { position: absolute; inset: 0; pointer-events: none; }
.gate-ring {
  position: absolute; left: 50%; top: 50%;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  opacity: .55;
}
.gate-ring.r1 {
  width: 520px; height: 520px;
  border: 1px dashed var(--tick);
  animation: gate-spin 90s linear infinite;
}
.gate-ring.r2 {
  width: 680px; height: 680px;
  /* 刻度环:conic 渐变做 60 格断续刻度,mask 只留一圈细边 */
  background: repeating-conic-gradient(var(--tick) 0 .6deg, transparent .6deg 6deg);
  -webkit-mask: radial-gradient(circle, transparent 0 calc(50% - 10px), #000 calc(50% - 9px) 50%, transparent 50%);
          mask: radial-gradient(circle, transparent 0 calc(50% - 10px), #000 calc(50% - 9px) 50%, transparent 50%);
  animation: gate-spin 140s linear infinite reverse;
  opacity: .8;
}
.gate-ring.r3 {
  width: 900px; height: 900px;
  border: 1px solid var(--rule);
  /* 一段冷青弧在最外圈慢慢绕 */
  background: conic-gradient(from 0deg, var(--accent) 0 28deg, transparent 28deg 360deg);
  -webkit-mask: radial-gradient(circle, transparent 0 calc(50% - 3px), #000 calc(50% - 2px) 50%, transparent 50%);
          mask: radial-gradient(circle, transparent 0 calc(50% - 3px), #000 calc(50% - 2px) 50%, transparent 50%);
  animation: gate-spin 24s linear infinite;
  opacity: .7;
}
@keyframes gate-spin { to { transform: translate(-50%, -50%) rotate(360deg); } }
.gate-scan {
  position: absolute; left: 0; right: 0; height: 120px; top: -120px;
  background: linear-gradient(to bottom, transparent, var(--accent-soft) 70%, var(--accent));
  opacity: .28;
  animation: gate-scan 7s cubic-bezier(.4, 0, .6, 1) infinite;
}
@keyframes gate-scan { 0% { top: -120px; } 100% { top: 100%; } }
.gate-hair { position: absolute; background: var(--rule-soft); }
.gate-hair.h1 { left: 0; right: 0; top: 50%; height: 1px; }
.gate-hair.h2 { top: 0; bottom: 0; left: 50%; width: 1px; }

/* 四角 HUD 微标签 */
.gate-hud {
  position: absolute; padding: 18px 20px;
  font-size: var(--fz-label); letter-spacing: var(--ls-label); color: var(--t2);
  text-transform: uppercase; white-space: nowrap; pointer-events: none;
}
.gate-hud.tl { left: 0; top: 0; }
.gate-hud.tr { right: 0; top: 0; }
.gate-hud.bl { left: 0; bottom: 0; font-variant-numeric: tabular-nums; }
.gate-hud.br { right: 0; bottom: 0; }
/* 登录屏语言切换:右上 HUD 标签正下方,同一套微型标签语言,显示"另一种语言" */
.gate-lang {
  position: absolute; right: 20px; top: 44px; z-index: 2;
  background: transparent; color: var(--accent); border: 1px solid var(--accent);
  border-radius: var(--r-ctl); padding: 0 10px; height: 26px;
  font: 700 10.5px/1 var(--mono); letter-spacing: var(--ls-label); cursor: pointer;
}
.gate-lang:hover { background: var(--accent-soft); }
@media (max-width: 620px) { .gate-lang { right: 12px; top: 36px; } }
.gate-hud::before {
  content: ''; display: inline-block; width: 6px; height: 6px; margin-right: 8px;
  background: var(--accent); vertical-align: 1px;
}

/* 卡片 */
.gate-card {
  position: relative; z-index: 1;
  width: min(380px, calc(100vw - 32px));
  padding: 34px 32px 26px;
  background: var(--s1); border: 1px solid var(--rule);
  border-radius: var(--r-card);
  box-shadow: 0 30px 80px var(--shadow), 0 0 0 1px var(--s0);
  display: flex; flex-direction: column; align-items: center;
  animation: gate-in .7s cubic-bezier(.2, .8, .2, 1) both;
}
@keyframes gate-in { from { opacity: 0; transform: translateY(14px) scale(.985); } }
/* 对角 L 角标(与 .card 同一套语法,尺寸放大一档) */
.gate-card::before, .gate-card::after {
  content: ''; position: absolute; width: 14px; height: 14px;
  border: 0 solid var(--accent); pointer-events: none;
}
.gate-card::before { left: -1px; top: -1px; border-left-width: 2px; border-top-width: 2px; }
.gate-card::after { right: -1px; bottom: -1px; border-right-width: 2px; border-bottom-width: 2px; }

.gate-mark {
  position: relative; width: 84px; height: 84px; margin-bottom: 16px;
  display: grid; place-items: center;
}
.gate-mark .mark { width: 64px; height: 64px; position: relative; z-index: 1; }
/* 标后面一圈冷青呼吸光晕 + 一圈细环 */
.gate-mark::before {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle, var(--accent) 0%, transparent 65%);
  opacity: .28; filter: blur(6px);
  animation: gate-breathe 3.2s ease-in-out infinite;
}
.gate-mark::after {
  content: ''; position: absolute; inset: -6px; border-radius: 50%;
  border: 1px dashed var(--accent); opacity: .5;
  animation: gate-spin-flat 30s linear infinite;
}
@keyframes gate-breathe { 50% { opacity: .55; transform: scale(1.12); } }
@keyframes gate-spin-flat { to { transform: rotate(360deg); } }

.gate-brand {
  font-weight: 700; font-size: 22px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--t0);
}
.gate-brand em { font-style: normal; color: var(--accent); }
.gate-sub {
  margin: 6px 0 26px;
  font-size: var(--fz-label); letter-spacing: var(--ls-label); color: var(--t1);
  display: flex; align-items: center; gap: 8px;
}
.gate-dot {
  width: 6px; height: 6px; background: var(--warn);
  animation: gate-blink 1.4s steps(2, start) infinite;
}
@keyframes gate-blink { to { opacity: 0; } }
.gate.pass .gate-dot { background: var(--pos); animation: none; }

.gate-field { display: block; width: 100%; margin-bottom: 18px; }
.gate-label {
  display: block; font-size: var(--fz-label); letter-spacing: var(--ls-label);
  color: var(--t1); text-transform: uppercase; margin-bottom: 4px;
}
.gate-field input {
  width: 100%; height: 38px; padding: 0 2px;
  background: transparent; border: 0; border-bottom: 1px solid var(--rule);
  border-radius: 0; color: var(--t0);
  font: 500 15px/1 var(--mono); letter-spacing: .04em;
  transition: border-color .2s, box-shadow .2s;
}
.gate-field input:focus {
  outline: none; border-bottom-color: var(--accent);
  box-shadow: 0 1px 0 var(--accent);
}
.gate-field input:-webkit-autofill {
  -webkit-text-fill-color: var(--t0);
  -webkit-box-shadow: 0 0 0 1000px var(--s1) inset;
  transition: background-color 9999s;
}
.gate-keep {
  align-self: flex-start; display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--t1); cursor: pointer; user-select: none;
  font-family: var(--sans);
}
.gate-keep input { accent-color: var(--accent); width: 14px; height: 14px; margin: 0; }

.gate-err {
  width: 100%; margin-top: 14px; padding: 8px 10px;
  border: 1px solid var(--neg-line); border-left: 3px solid var(--neg);
  background: var(--neg-bg); color: var(--neg);
  font-size: 12px; letter-spacing: .03em;
}
.gate-err[hidden] { display: none; }

.gate-btn {
  width: 100%; height: 44px; margin-top: 20px;
  position: relative; overflow: hidden;
  /* 字色取表面色而不是写死深色:亮色态的强调蓝偏深,深字压不住 */
  background: var(--accent); color: var(--s1); border: 0; border-radius: var(--r-ctl);
  font: 700 12.5px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase;
  cursor: pointer;
  transition: filter .15s, transform .1s;
}
.gate-btn:hover { filter: brightness(1.08); }
.gate-btn:active { transform: translateY(1px); }
.gate-btn:disabled { cursor: progress; filter: saturate(.6); }
/* 高光扫过一次的斜条 */
.gate-btn::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 40%; left: -60%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .45), transparent);
  animation: gate-sheen 3.6s ease-in-out infinite;
}
@keyframes gate-sheen { 0%, 60% { left: -60%; } 100% { left: 130%; } }
.gate-btn.busy::after { animation: gate-sheen .9s linear infinite; }
.gate-btn span { position: relative; z-index: 1; }

.gate-foot {
  margin-top: 22px; font-size: 10.5px; letter-spacing: .06em; color: var(--t2);
  font-family: var(--sans); text-align: center;
}

/* 口令错:卡片横向抖一下 */
.gate.shake .gate-card { animation: gate-shake .4s cubic-bezier(.36, .07, .19, .97); }
@keyframes gate-shake {
  10%, 90% { transform: translateX(-1px); } 20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-4px); } 40%, 60% { transform: translateX(4px); }
}
/* 通过:卡片淡出上浮,外圈弧变绿加速 */
.gate.pass .gate-card { animation: gate-out .5s cubic-bezier(.4, 0, 1, 1) forwards; }
@keyframes gate-out { to { opacity: 0; transform: translateY(-18px) scale(1.02); } }
.gate.pass .gate-ring.r3 {
  background: conic-gradient(from 0deg, var(--pos) 0 120deg, transparent 120deg 360deg);
  animation-duration: 1.2s;
}

/* 顶栏「退出」:与 select 同一套控件语言 */
.logout {
  background: var(--s1); color: var(--t1); border: 1px solid var(--rule);
  border-radius: var(--r-ctl); padding: 0 10px; height: 32px;
  font: 500 11.5px/1 var(--mono); letter-spacing: .04em; cursor: pointer;
}
.logout:hover { color: var(--neg); border-color: var(--neg-line); }
.logout[hidden] { display: none; }

@media (max-width: 620px) {
  .gate-hud { padding: 12px 12px; font-size: 10px; }
  .gate-hud.tr, .gate-hud.br { display: none; }   /* 窄屏留左侧两枚就够 */
  .gate-card { padding: 28px 22px 20px; }
  .gate-ring.r1 { width: 360px; height: 360px; }
  .gate-ring.r2 { width: 480px; height: 480px; }
  .gate-ring.r3 { width: 640px; height: 640px; }
}

/* ── 页内动效 ─────────────────────────────────────────────────────────────
 * 2026-08-26 用户拍板:登录页之后,面板内部也要动效 ——"不过分夸张,但要够酷"。
 * 家法:
 *   · **只在进场时动一次**(#view.anim 由 render() 在换页/首载时打上;区间钮、
 *     图例、日历这类局部重绘不重放,5 分钟静默刷新也不重放)。
 *   · 动的是"仪器上电"那一类语义:区块依次上浮、曲线从左描到右、柱子从零轴长出、
 *     KPI 数字逐格亮起。不做弹跳、不做旋转、不做颜色闪烁。
 *   · 常驻动效只有两处:陈旧徽标呼吸(那是警示,该被看见)、数据刷新时间戳轻闪。
 *   · 悬停:卡片角标伸长变冷青、边线提亮 —— "指到哪块,哪块上电"。
 *   · 全部 CSS keyframes;prefers-reduced-motion 由顶部全局规则关掉。
 */
@keyframes iq-rise { from { opacity: 0; transform: translateY(8px); } }
@keyframes iq-fade { from { opacity: 0; } }
@keyframes iq-grow { from { transform: scaleY(0); } }
@keyframes iq-grow-x { from { transform: scaleX(0); } }

/* 区块依次上浮(计数器编号的顺序就是进场顺序) */
#view.anim section, #view.anim > .kpis {
  animation: iq-rise .5s cubic-bezier(.2, .7, .2, 1) both;
}
#view.anim section:nth-of-type(2) { animation-delay: .06s; }
#view.anim section:nth-of-type(3) { animation-delay: .12s; }
#view.anim section:nth-of-type(4) { animation-delay: .18s; }
#view.anim section:nth-of-type(5) { animation-delay: .24s; }
#view.anim section:nth-of-type(6) { animation-delay: .30s; }
#view.anim section:nth-of-type(n+7) { animation-delay: .36s; }

/* KPI 数字逐格亮起 */
#view.anim .kpi .v { animation: iq-rise .55s cubic-bezier(.2, .7, .2, 1) both; }
#view.anim .kpi:nth-child(2) .v { animation-delay: .07s; }
#view.anim .kpi:nth-child(3) .v { animation-delay: .14s; }
#view.anim .kpi:nth-child(4) .v { animation-delay: .21s; }
#view.anim .kpi:nth-child(5) .v { animation-delay: .28s; }
#view.anim .kpi:nth-child(n+6) .v { animation-delay: .35s; }

/* 曲线连同阴影从左向右扫入(整组 <g class="lines"> 做 clip-path)。
   ⚠ 不用 pathLength + dasharray 描线:那会吃掉虚线的线型(见 app.js svgLine 注释)。 */
@keyframes iq-sweep { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
#view.anim .lines { animation: iq-sweep 1.3s cubic-bezier(.4, 0, .2, 1) .2s both; }
#view.anim .mark-line, #view.anim .mark-label,
#view.anim .limit-line, #view.anim .limit-label { animation: iq-fade .6s ease-out 1s both; }

/* 柱子从零轴长出:正柱底部为原点、负柱顶部为原点;横向条从左长出 */
#view.anim .bar-pos, #view.anim .hist-bar, #view.anim .bar-neg {
  transform-box: fill-box; animation: iq-grow .7s cubic-bezier(.2, .7, .2, 1) .15s both;
}
#view.anim .bar-pos, #view.anim .hist-bar { transform-origin: bottom; }
#view.anim .bar-neg { transform-origin: top; }
#view.anim .ex-m, #view.anim .ex-t {
  transform-box: fill-box; transform-origin: left;
  animation: iq-grow-x .6s cubic-bezier(.2, .7, .2, 1) .15s both;
}

/* 悬停:角标伸长并转冷青,边线提亮 */
.card, .kpis { transition: border-color .2s ease; }
.card:hover, .kpis:hover { border-color: var(--rule); }
.card::before, .card::after, .kpis::before, .kpis::after {
  transition: width .22s cubic-bezier(.2, .7, .2, 1), height .22s cubic-bezier(.2, .7, .2, 1),
              border-color .22s ease;
}
.card:hover::before, .card:hover::after, .kpis:hover::before, .kpis:hover::after {
  width: 16px; height: 16px; border-color: var(--accent);
}
.tab { transition: color .15s ease, box-shadow .15s ease; }
.nav-item { transition: background-color .15s ease, color .15s ease, border-color .15s ease; }

/* 常驻:陈旧徽标呼吸;刷新时间戳收到新数据时闪一下冷青 */
@keyframes iq-breathe { 50% { opacity: .55; } }
.pill.stale { animation: iq-breathe 2.4s ease-in-out infinite; }
@keyframes iq-tick { 0% { color: var(--accent); } 100% { color: var(--t1); } }
.stamp.tick { animation: iq-tick 1.4s ease-out; }

/* ── 强平距离刻度带 / 杠杆基准线 / 阶段徽标(2026-08-26)──────────────────── */
.ln-benchlev { stroke: var(--c-s3); stroke-dasharray: 2 3; stroke-width: 1.2; }
.lg-benchlev { color: var(--c-s3); }
.pill.stage { margin-left: 6px; vertical-align: 2px; font-weight: 500; }
/* 头部八格固定两行四列(2026-08-26 用户拍板);窄屏仍走 620px 断点的两列 */
.kpis.kpis-2row { grid-template-columns: repeat(4, 1fr); }
.kpis.kpis-2row .kpi:nth-child(n+5) { border-top: 1px solid var(--rule-soft); }
.kpis.kpis-2row .kpi:nth-child(5) { border-left: 0; }
.mg-gauge { margin: 4px 0 10px; }
.mg-gauge svg { overflow: visible; }
.mg-liq { fill: var(--neg); opacity: .9; }
.mg-halt { fill: var(--neg); opacity: .45; }
.mg-derisk { fill: var(--warn); opacity: .55; }
.mg-ok { fill: var(--pos); opacity: .35; }
.mg-tick { stroke: var(--t2); stroke-width: 1; }
.mg-lbl { fill: var(--t2); font-size: 9.5px; font-family: var(--mono); letter-spacing: .03em; }
.mg-ptr { fill: var(--t0); }
.mg-ptr.warn { fill: var(--warn); }
.mg-ptr.down { fill: var(--neg); }
.mg-now { fill: var(--t0); font-size: 11px; font-weight: 700; font-family: var(--mono); }
.mg-now.warn { fill: var(--warn); }
.mg-now.down { fill: var(--neg); }
/* 希腊字母不随 uppercase 变形(β→Β 看着像 B) */
.gk { text-transform: none; }
/* 净值图 tooltip 的收益%(相对当前区间起点) */
.tip-ret { font-size: 10.5px; margin-left: 4px; }
.tip-ret.up { color: var(--pos); } .tip-ret.down { color: var(--neg); }
