/* v1.6.7 · 自有 @media 与 Tailwind 断点同一判据:同时看短边。
   手机横屏 844×390 → 移动规则若只按 max-width 判定会全部失效(用户看到的「转手机就变样」)。
   横屏 iframe 也是 844×390,但那是主动要的宽屏视图 → 会真正改变观感的规则用
   html:not(.ls-wide) 排除掉它(纯字号/内距一类无害的不排除,少改一点)。 */
/* ============================================================
   家庭账房 · Private Counting House
   一份起居室里的银行家账册
   ============================================================ */

:root {
  /* — Paper & Ink — */
  --paper:        #F4EFE6;
  --paper-soft:   #EDE6D7;
  --paper-deep:   #E5DCC8;
  --card:         #FFFCF5;
  --card-soft:    #FAF4E6;
  --ink:          #1A1714;   /* on card 17.4:1 */
  --ink-soft:     #5C5147;   /* on card  7.5:1 · AAA */
  /* v1.6 · 对比度修正(visual-spec §1.2 实测):原 #A09486 在 card 上仅 2.90:1 / 在 paper 上 2.59:1,
     连大字号 3:1 都不到,而它承载的恰恰是字号最小的一层(时间/序号/口径/计数/eyebrow)——
     小字 + 低对比 = 双重不可读。改 #706657(card 5.5:1 / paper 4.9:1,双底过 AA)。
     原浅值降级为 --ink-faint,只许画装饰(水印/禁用/占位图形),不许承载信息。 */
  --ink-subtle:   #706657;
  --ink-faint:    #A09486;
  --rule:         #BCAE96;   /* 非文字,but 原 #C9BDA8 仅 1.8:1 偏弱 → 略加深 */
  --rule-soft:    #DBD0BC;

  /* — Accents (used sparingly) — */
  --brass:        #B08642;   /* 仅作底/边/装饰:on card 3.2:1,不可作小字文字 */
  --brass-deep:   #8C6A33;
  /* v1.6 · 铜金作文字专用档(visual-spec §1.3):brass 3.2:1 / brass-deep 在 paper 上 4.34:1 都不过 AA,
     brass-text 5.3:1 / 4.8:1 双底过 AA —— 链接、eyebrow、可点强调文字用它 */
  --brass-text:   #85642F;
  --brass-soft:   #E8D9B6;
  --forest:       #4F6B47;
  --forest-soft:  #C8D5BD;
  --rust:         #9C4A2A;
  --rust-soft:    #E8C8B8;
  --plum:         #5C3A4B;
  --slate:        #3C4A5A;
  --slate-soft:   #C5CDD8;  /* v0.17 · 保险 pill 底色 */
  --fund:         #34587A;  /* v1.30 · 基金账户 / 场外基金 */
  --fund-soft:    #D5DDE6;

  /* — Sizing — */
  --rule-thin:    0.5px;
  --rule-thick:   1px;

  /* — v1.2.2 · 全局字号档位(issue #7)· 一个变量驱动全站缩放;标准=1 时逐像素等价现状 — */
  --fs-scale:     1;

  /* — Effects — */
  --shadow-paper: 0 1px 0 rgba(26, 23, 20, 0.04), 0 8px 24px -12px rgba(26, 23, 20, 0.08);
  --shadow-deep:  0 2px 0 rgba(26, 23, 20, 0.04), 0 24px 60px -32px rgba(26, 23, 20, 0.18);

  /* — v1.35 · 控件 token(按钮 / 标签 / 输入框 / 卡片)· 见 docs/design-system.md §2.1 — */
  --ui-sans:      -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB",
                  "Microsoft YaHei", "Noto Sans SC", "Source Han Sans SC", "WenQuanYi Zen Hei", sans-serif;
  --r-sm:         4px;    /* 标签 */
  --r-md:         6px;    /* 按钮 / 输入框 / 下拉框 */
  --r-lg:         8px;    /* 卡片 */
  --shadow-xs:    0 1px 2px rgba(26, 23, 20, 0.06);
  --ring:         0 0 0 2px var(--card), 0 0 0 4px rgba(176, 134, 66, 0.55);
}

/* v1.2.2 · 字号档位:大 +15% / 特大 +30%(标准不设 = 用 :root 的 1) */
html[data-fs="lg"] { --fs-scale: 1.15; }
html[data-fs="xl"] { --fs-scale: 1.30; }

* { box-sizing: border-box; }

html, body {
  background: var(--paper);
  color: var(--ink);
  font-family: "Source Serif 4", "Noto Serif SC", Georgia, serif;
  font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
  font-size: calc(15px * var(--fs-scale,1));
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ——— 纸张纹理 ——— */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background-image:
    radial-gradient(1px 1px at 10% 20%, rgba(176,134,66,0.05) 50%, transparent 50%),
    radial-gradient(1px 1px at 80% 60%, rgba(26,23,20,0.04) 50%, transparent 50%),
    radial-gradient(1px 1px at 30% 80%, rgba(176,134,66,0.04) 50%, transparent 50%),
    radial-gradient(1px 1px at 70% 30%, rgba(26,23,20,0.03) 50%, transparent 50%);
  background-size: 80px 80px, 120px 120px, 100px 100px, 90px 90px;
  background-position: 0 0, 40px 40px, 20px 60px, 60px 20px;
  opacity: 0.6;
  mix-blend-mode: multiply;
}

/* ——— Typography ——— */

.font-display { font-family: "Fraunces", "Noto Serif SC", Georgia, serif; }
.font-serif   { font-family: "Source Serif 4", "Noto Serif SC", Georgia, serif; }
.font-mono    { font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace; font-feature-settings: "tnum" 1, "calt" 1; }

.tnum         { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }
.swsh         { font-feature-settings: "swsh" 1, "ss01" 1; }   /* Fraunces swash + stylistic */

h1, h2, h3, h4 {
  font-family: "Fraunces", "Noto Serif SC", Georgia, serif;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.eyebrow {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: calc(10.5px * var(--fs-scale,1));
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brass-deep);
}

.eyebrow-ink {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: calc(10.5px * var(--fs-scale,1));
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.dropcap::first-letter {
  font-family: "Fraunces", "Noto Serif SC", Georgia, serif;
  font-weight: 600;
  font-size: 3em;
  line-height: 1;
  float: left;
  padding: 4px 8px 0 0;
  color: var(--brass);
}

/* ——— Components ——— */

.paper-card {
  background: var(--card);
  border: var(--rule-thick) solid var(--rule);
  border-radius: var(--r-lg);   /* v1.35 · 2px → 8px(方向 A:卡片圆角对齐控件) */
  box-shadow: var(--shadow-paper);
  position: relative;
}

.paper-card-soft {
  background: var(--card-soft);
  border: var(--rule-thin) solid var(--rule);
  border-radius: var(--r-md);
}

.envelope {
  background: var(--card);
  border: var(--rule-thick) solid var(--ink);
  border-radius: 0;
  box-shadow:
    4px 4px 0 var(--paper-deep),
    var(--shadow-deep);
}

/* Bracket-cornered cards (账册装饰角) */
.bracket-card {
  position: relative;
  background: var(--card);
  border: 1px solid var(--rule);
  padding: 28px;
}
.bracket-card::before, .bracket-card::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  border: 1.5px solid var(--brass);
}
.bracket-card::before { top: -5px; left: -5px; border-right: none; border-bottom: none; }
.bracket-card::after  { bottom: -5px; right: -5px; border-left: none; border-top: none; }

/* Hairline rules (账册中的细线) */
.rule         { border-color: var(--rule); }
.rule-thick   { border-color: var(--ink); }
.rule-x       { border-top: 1px solid var(--rule); }
.rule-y       { border-left: 1px solid var(--rule); }
.rule-double  { border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); padding: 1px 0; }
.rule-triple-bottom { border-bottom: 3px double var(--rule); padding-bottom: 4px; }

/* Buttons
   v1.35 · 按钮重做(维护者 2026-10-19:「为什么按钮都那么大?还都是个方框」· 方向 A 精修账册)。
   旧版是 12px 等宽 + uppercase + 0.12em 字距 + 12/20 内距 + 直角,一个按钮约 42px,中文被拉成「添 加 持 仓」。
   规格对标 shadcn/ui(nova 那一档的密度)—— 数值与来源见 docs/research/ui-frameworks-2026-10.md:
     · 尺寸档【沿用模板现有写法,不新增修饰类】:按钮带 text-xs / text-[10px] / text-[11px] / text-[12px]
       = 小档 28px(卡片内、行内);其余 = 默认 32px;btn-lg = 40px(登录、引导这类大入口);手机各升一档
     · 无衬线 13px / 500 · 不大写、不加字距 · 圆角 6px · 图标与文字间距 6px
     · 用 min-height 而不是 height:长文字换行时按钮跟着长高,不会把字截掉
   四层:btn-ink 主操作(每区块 1 个)· btn-paper 次操作(白底细边)· btn-ghost 行内轻操作 · btn-danger 删除/归档等不可逆
   btn-brass:新功能 / AI 入口(全站 ≤3 处)。
   护栏 v135-BTN-NO-CAPS / v135-BTN-STATES。 */
.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 32px;
  padding: 5px 12px;
  font-family: var(--ui-sans);
  font-size: calc(13px * var(--fs-scale,1));
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: 0;
  text-transform: none;
  text-decoration: none;
  white-space: nowrap;   /* 中文按钮被挤窄时会一字一行(汇率页「↻ 立 / 即拉 / 取」);宁可旁边的说明文字多折一行 */
  border: 1px solid transparent;
  border-radius: var(--r-md);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 150ms ease, border-color 150ms ease, color 150ms ease, box-shadow 150ms ease, transform 100ms ease;
}
.btn-ink    { background: var(--ink); color: var(--card); border-color: var(--ink); }
.btn-ink:hover    { background: #322C26; border-color: #322C26; color: var(--card); }
.btn-paper  { background: var(--card); color: var(--ink); border-color: var(--rule-soft); box-shadow: var(--shadow-xs); }
.btn-paper:hover  { background: var(--paper-soft); border-color: var(--rule); color: var(--ink); }
/* 旧 btn-brass 是铜底米字(对比度 3.2:1 不够小字);改深铜底,4.9:1 */
.btn-brass  { background: var(--brass-deep); color: var(--card); border-color: var(--brass-deep); }
.btn-brass:hover  { background: #76592A; border-color: #76592A; color: var(--card); }
/* btn-accent:AI 入口 / 新能力的次操作(铜色软底)—— 叠在 btn-paper 上用;实心深铜的 btn-brass 全站 ≤3 处 */
.btn-paper.btn-accent { background: var(--brass-soft); color: var(--brass-text); border-color: transparent; box-shadow: none; }
.btn-paper.btn-accent:hover { background: #E1CE9E; color: var(--brass-deep); border-color: transparent; }
.btn-ghost  { background: transparent; color: var(--ink-soft); }
.btn-ghost:hover  { background: var(--paper-soft); color: var(--ink); }
/* 不可逆操作:描边红字,不用实心红 —— 删除不该是页面上最醒目的东西(实心只给最后一步确认:btn-danger-fill) */
.btn-danger { background: transparent; color: var(--rust); border-color: rgba(156, 74, 42, .38); }
.btn-danger:hover { background: rgba(156, 74, 42, .08); border-color: var(--rust); color: var(--rust); }
.btn-danger.btn-danger-fill { background: var(--rust); color: var(--card); border-color: var(--rust); }
.btn-danger.btn-danger-fill:hover { background: #84391F; border-color: #84391F; color: var(--card); }

/* 小档 28px:模板里给按钮写的字号类就是尺寸档(:is 让优先级 = 0,2,0,压过 Tailwind 同名工具类) */
:is(.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger):is(.text-xs, .text-\[10px\], .text-\[11px\], .text-\[12px\], .btn-sm) {
  min-height: 28px;
  padding: 3px 10px;
  font-size: calc(12px * var(--fs-scale,1));
  line-height: 1.25;
}
/* 模板里写 text-sm / text-base 的按钮回到默认 13px —— 并排按钮字号一致 */
:is(.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger):is(.text-sm, .text-base) {
  font-size: calc(13px * var(--fs-scale,1));
  line-height: 1.25;
}
:is(.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger).btn-lg {
  min-height: 40px;
  padding: 8px 20px;
  font-size: calc(14px * var(--fs-scale,1));
}
/* 模板给按钮加了 block / inline-block 时(Tailwind 后注入、会压掉 inline-flex),换成对应的 flex,文字才竖直居中 */
:is(.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger).block { display: flex; }
:is(.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger).inline-block { display: inline-flex; }
:is(.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger) svg { flex-shrink: 0; }
summary:is(.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger)::-webkit-details-marker { display: none; }

/* 状态四件套 —— 一次覆盖全部按钮类(design-system.md 当年写了「待补」一直没补)
   · 按下:移动端没有 hover,这是唯一的按下反馈
   · focus-visible:Tailwind preflight 去掉了 outline,键盘 Tab 走到哪看不见
   · disabled / 请求中:原来外观不变,会被重复点 */
.btn-ink:active, .btn-paper:active, .btn-brass:active, .btn-ghost:active, .btn-danger:active { transform: translateY(1px); }
.btn-ink:focus-visible, .btn-paper:focus-visible, .btn-brass:focus-visible, .btn-ghost:focus-visible, .btn-danger:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}
.btn-ink[disabled], .btn-paper[disabled], .btn-brass[disabled], .btn-ghost[disabled], .btn-danger[disabled],
.btn-ink[aria-disabled="true"], .btn-paper[aria-disabled="true"], .btn-brass[aria-disabled="true"], .btn-ghost[aria-disabled="true"], .btn-danger[aria-disabled="true"],
.btn-ink.htmx-request, .btn-paper.htmx-request, .btn-brass.htmx-request, .btn-ghost.htmx-request, .btn-danger.htmx-request {
  opacity: .5;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}
/* 手机端没有精确指针,点按区域各升一档:默认 36 / 小档 32 */
@media (max-width: 640px) {
  .btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger { min-height: 36px; padding: 6px 14px; }
  :is(.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger):is(.text-xs, .text-\[10px\], .text-\[11px\], .text-\[12px\], .btn-sm) { min-height: 32px; padding: 4px 11px; }
  :is(.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger).btn-lg { min-height: 44px; }
}

/* Form */
.field-input {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--rule);
  padding: 10px 2px;
  font-family: "Source Serif 4", "Noto Serif SC", serif;
  font-size: calc(16px * var(--fs-scale,1));
  color: var(--ink);
  width: 100%;
  outline: none;
  transition: border-color 180ms ease;
}
.field-input:focus { border-bottom: 2px solid var(--brass); padding-bottom: 9px; }

/* v1.35 · 带框的输入框 / 下拉框 / 文本框与按钮同圆角(6px)。field-input 是账册式下划线,不加圆角。 */
input:is([type=text], [type=number], [type=search], [type=password], [type=email], [type=tel], [type=url],
         [type=date], [type=month], [type=datetime-local], [type=time]):not(.field-input),
select:not(.field-input), textarea:not(.field-input) { border-radius: var(--r-md); }

.field-input-num {
  font-family: "JetBrains Mono", monospace;
  font-variant-numeric: tabular-nums;
  font-size: calc(18px * var(--fs-scale,1));
  text-align: right;
  letter-spacing: 0.02em;
}

.field-label {
  font-family: "JetBrains Mono", monospace;
  font-size: calc(10.5px * var(--fs-scale,1));
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  display: block;
  margin-bottom: 6px;
}

/* Pills / Chips / Tags
   v1.35 · 标签:去掉硬边框、等宽字体、大写和 0.1em 字距 —— 换成软底圆角小标(对标 shadcn Badge / Nuxt Badge)。
   · 字号统一 11px:模板里给 pill 写的 text-[9px] / text-[10px] 一律压到 11px(.pill[class] 优先级 0,2,0),
     9px 的中文在手机上几乎读不出来
   · 边框透明 + !important:很多 pill 用行内 style 写了 border-color 来表达类型,软底 + 字色已经够区分
     (pill-mute 是「描边空心」那一种,单独保留细边)
   · 代码类(股票 / 基金代码)加 font-mono 仍走等宽 */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border: 1px solid transparent !important;
  background: var(--paper-soft);
  font-family: var(--ui-sans);
  font-size: calc(11px * var(--fs-scale,1));
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-soft);
  border-radius: var(--r-sm);
}
.pill[class] { font-size: calc(11px * var(--fs-scale,1)); letter-spacing: 0; }
.pill.font-mono, .pill[data-fund-code-pill] { font-family: "JetBrains Mono", ui-monospace, monospace; }
/* 和大字放在同一行(items-baseline)时按竖直中线对齐 —— 按基线对齐时小标签会比旁边的大字低几像素(v1.35 填报卡) */
.items-baseline > .pill { align-self: center; }
.pill-brass { background: var(--brass-soft); border-color: var(--brass); color: var(--brass-deep); }
.pill-forest { background: var(--forest-soft); border-color: var(--forest); color: var(--forest); }
.pill-rust { background: var(--rust-soft); border-color: var(--rust); color: var(--rust); }
.pill-slate { background: var(--slate-soft); border-color: var(--slate); color: var(--slate); } /* v0.17 保险 */
.pill-fund { background: var(--fund-soft); border-color: var(--fund); color: var(--fund); } /* v1.30 基金账户 */
.text-fund { color: var(--fund); }
.pill-ink { background: var(--ink); border-color: var(--ink); color: var(--paper); }

/* Number coloring */
.num-pos { color: var(--forest); }
.num-neg { color: var(--rust); }

/* KPI 卡片 */
.kpi-card {
  background: var(--card);
  border: 1px solid var(--rule);
  padding: 24px;   /* v1.35 · 不加圆角:KPI 卡是并排拼成一张表格的,各自圆角会在接缝处出豁口 */
  position: relative;
  transition: border-color 180ms ease;
}
.kpi-card:hover { border-color: var(--ink-soft); }
.kpi-eyebrow {
  font-family: "JetBrains Mono", monospace;
  font-size: calc(10px * var(--fs-scale,1));
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  display: block;
  margin-bottom: 14px;
}
.kpi-value {
  font-family: "Fraunces", "Noto Serif SC", serif;
  font-feature-settings: "tnum" 1;
  font-size: calc(30px * var(--fs-scale,1));
  font-weight: 500;
  line-height: 1.1;
  color: var(--ink);
  letter-spacing: -0.015em;
}
.kpi-currency { font-size: 0.55em; vertical-align: 0.65em; color: var(--ink-soft); margin-right: 4px; }
.kpi-delta {
  font-family: "JetBrains Mono", monospace;
  font-feature-settings: "tnum" 1;
  font-size: calc(12px * var(--fs-scale,1));
  margin-top: 10px;
}

/* 成员 avatar 颜色(填报页分组 · 按 ownerColorMap index % 5 分配) */
.avatar-0 { background: #2f5d50 !important; } /* forest 深绿 */
.avatar-1 { background: #6b5b8a !important; } /* 紫灰 */
.avatar-2 { background: #3b6998 !important; } /* 蓝灰 */
.avatar-3 { background: #a77b35 !important; } /* 铜金 */
.avatar-4 { background: #4a5568 !important; } /* slate 灰(fallback / 共同) */

/* KPI 口径说明 tooltip · v0.4.13 */
.kpi-info-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
}
.kpi-info-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px;
  border: none; color: var(--ink-subtle);
  cursor: pointer; margin-left: 3px; vertical-align: middle;
  transition: color .2s;
  flex-shrink: 0; padding: 0; background: none;
}
.kpi-info-btn:hover { color: var(--brass-deep); }
/* 2026-07-19 · 移动可点性:视觉 14px 的小图标,触摸热区扩到 ~38px(::after 不占布局,只吃点击) */
.kpi-info-btn { position: relative; }
.kpi-info-btn::after, .tap::after {
  content: ''; position: absolute; inset: -12px;
}
.tap { position: relative; }
.kpi-info-panel {
  /* absolute 浮层 · 不撑开 parent card 布局 */
  position: absolute;
  top: calc(100% + 4px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 50;
  padding: 8px 10px;
  background: var(--card); border: 1px solid var(--rule-soft);
  border-left: 3px solid var(--brass); border-radius: 4px;
  font-size: calc(11px * var(--fs-scale,1)); line-height: 1.6; color: var(--ink-soft);
  min-width: 220px; max-width: 320px; width: max-content;
  font-family: "Source Serif 4", "Noto Serif SC", serif;
  box-shadow: 0 4px 12px rgba(26,23,20,.12);
  /* 防 panel 把文字从 uppercase 继承过来 */
  text-transform: none; letter-spacing: normal;
}
/* v0.5.3 · 口径(formula)+ 真实计算数值(calc)双层 */
.kpi-info-formula { display: block; }
.kpi-info-calc {
  display: block;
  margin-top: 7px; padding-top: 7px;
  border-top: 1px dashed var(--rule-soft);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: calc(10.5px * var(--fs-scale,1)); line-height: 1.7;
  color: var(--ink);
  /* 多行分项用 \n 软换行 · 不折叠空白 */
  white-space: pre-line;
  text-transform: none; letter-spacing: normal;
}
/* v0.5.5 · 报表「已关账」朱印章(横排小印 · 单行不换行 · 仅快照态显)*/
.report-seal {
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0; white-space: nowrap;
  color: var(--rust);
  border: 2px solid var(--rust);
  border-radius: 5px;
  background: rgba(156, 74, 42, .05);
  box-shadow: inset 0 0 0 2px rgba(156, 74, 42, .14);
  transform: rotate(-4deg);
  padding: 3px 6px 3px 9px;   /* 右侧略收:letter-spacing 末位补偿 */
  font-family: "Noto Serif SC", serif; font-weight: 700;
  font-size: calc(13px * var(--fs-scale,1)); letter-spacing: 3px; line-height: 1;
  opacity: .92;
}
@media (max-width: 640px), (max-height: 479px) {
  .report-seal { font-size: calc(12px * var(--fs-scale,1)); letter-spacing: 2px; padding: 2px 5px 2px 7px; }
}

/* v0.5.6 · 报表长文目录 · PC 右侧常驻树状大纲 + 手机左上唤醒钮 + 底部 sheet */
/* 布局自管(不依赖 Tailwind lg: · 重页 JIT 不稳)· 窄屏单列+FAB · ≥1024px 双列 */
.toc-cols-main { min-width: 0; }
.toc-rail { display: none; }
@media (min-width: 1024px) and (min-height: 480px) {
  .toc-cols { display: flex; gap: 2rem; align-items: flex-start; }
  .toc-cols-main { flex: 1 1 0%; min-width: 0; }
  /* v1.22.4 · DOM 顺序已改成「目录在前」,所以不再需要 order:-1 把它挪过来。
     改 DOM 顺序而不是继续用 order,是因为 HTML 流式到达:
     排在主内容之后的元素要等主内容全部传完才出现(实测晚 0.5~1 秒)。 */
  .toc-rail { display: block; position: sticky; top: 88px; align-self: flex-start; width: 224px; flex-shrink: 0; }
}
.toc-head { font-family:"JetBrains Mono",monospace; font-size: calc(10px * var(--fs-scale,1)); letter-spacing:.18em; text-transform:uppercase; color:var(--ink-subtle); padding:0 0 8px 14px; }
.toc-tree { position: relative; }
.toc-node { display:block; position:relative; text-decoration:none; line-height:1.35;
  font-family:"Source Serif 4","Noto Serif SC",serif; color:var(--ink-soft);
  padding:6px 8px 6px 14px; border-left:2px solid transparent;
  transition:color .15s, border-color .15s, background .15s; }
.toc-node .lbl { font-size: calc(13px * var(--fs-scale,1)); }
.toc-node:hover { color:var(--brass-deep); background:var(--card-soft); }
/* active:aria-current 作样式钩子(a11y)· 朱铜 + 左脊 + 底色 */
.toc-node[aria-current="true"] { color:var(--brass-deep); font-weight:600; border-left-color:var(--brass-deep); background:var(--card-soft); }
.toc-node.ancestor { color:var(--ink); }
/* 子层:缩进 + 竖向引导线 + 横向树枝(支持未来多层嵌套)*/
.toc-children { margin-left:13px; border-left:1.5px solid var(--rule-soft); }
.toc-children > .toc-node { padding-left:16px; }
.toc-children > .toc-node .lbl { font-size: calc(12px * var(--fs-scale,1)); }
.toc-children > .toc-node::before { content:''; position:absolute; left:-1px; top:15px; width:10px; height:1.5px; background:var(--rule-soft); }
.toc-children > .toc-node[aria-current="true"]::before { background:var(--brass-deep); }
/* 手机:左上角唤醒钮(icon-only 小圆钮)+ 底部 sheet · ≥1024px 隐藏(用右栏) */
/* v0.11 · 移动端目录浮钮挪到左下,与隐私浮控(#priv-float, bottom:18px)叠成同一操作区 */
/* v1.6 UED(review A1)· 浮钮从左下改右下 + iOS 安全区:左下是内容起始边,曾压住金额/图例/筛选行 */
.toc-fab { position:fixed; right:14px; bottom:calc(max(18px, env(safe-area-inset-bottom)) + 48px); z-index:9999;
  width:38px; height:38px; border-radius:50%;
  background:var(--ink); color:var(--paper); border:none; box-shadow:0 3px 12px rgba(0,0,0,.22);
  display:inline-flex; align-items:center; justify-content:center; cursor:pointer;
  transition:opacity .25s ease; }
@media (min-width: 1024px) and (min-height: 480px) { .toc-fab { display: none !important; } }
.toc-sheet-mask { position:fixed; inset:0; background:rgba(26,23,20,.4); z-index:70; opacity:0; pointer-events:none; transition:opacity .2s; }
.toc-sheet-mask.open { opacity:1; pointer-events:auto; }
.toc-sheet { position:fixed; left:0; right:0; bottom:0; z-index:80; background:var(--card);
  border-top-left-radius:16px; border-top-right-radius:16px; box-shadow:0 -8px 32px rgba(0,0,0,.22);
  transform:translateY(110%); transition:transform .26s cubic-bezier(.22,1,.36,1);
  padding:8px 6px max(16px, env(safe-area-inset-bottom)); max-height:72vh; overflow:auto; }
.toc-sheet.open { transform:translateY(0); }
.toc-sheet-handle { width:40px; height:4px; border-radius:2px; background:var(--rule); margin:8px auto 4px; }
.toc-sheet-row { display:flex; align-items:center; justify-content:space-between; padding:2px 12px 6px; }
.toc-sheet-row .toc-head { padding:0; }
.toc-sheet-x { width:32px; height:32px; border:none; background:none; color:var(--ink-soft); cursor:pointer; font-size: calc(20px * var(--fs-scale,1)); line-height:1; }
.toc-sheet .toc-node { padding-top:11px; padding-bottom:11px; min-height:44px; box-sizing:border-box; }
.toc-sheet .toc-node .lbl { font-size: calc(15px * var(--fs-scale,1)); }
/* v1.4.x · 目录 sheet 打开时,收起左下角浮钮(隐私眼睛 + 目录浮钮),避免压住 sheet 底部条目 */
body.toc-open #priv-float, body.toc-open .toc-fab { display: none !important; }
/* v1.4.x · 旭日「分析指标 / 看板」横滑行的"还有更多"提示:右缘渐隐 + › 箭头,溢出且未滑到底时出现 */
.lens-hscroll { position: relative; }
.lens-hscroll > .overflow-x-auto { scrollbar-width: none; }
.lens-hscroll > .overflow-x-auto::-webkit-scrollbar { display: none; }
/* v1.6 UED(review A9)· iOS 硬约束:
   ① overscroll-behavior-x:contain —— 横滑到尽头继续拖不再触发 Safari 返回/前进手势(此前会莫名离开页面)
   ② scroll-snap —— 横滑停在完整 pill/卡片边界,不再半个被截断 */
.lens-hscroll > .overflow-x-auto,
.hscroll-x {
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}
.hscroll-x { overflow-x: auto; scrollbar-width: none; }
.hscroll-x::-webkit-scrollbar { display: none; }
.lens-hscroll > .overflow-x-auto > * > *,
.hscroll-x > * { scroll-snap-align: start; }
/* 内部纵向滚动容器不带动整页(iOS momentum 串联) */
.toc-sheet, .scroll-contain { overscroll-behavior: contain; }
/* 图表容器:长按不弹系统「拷贝图片」菜单(review A9 ⑦) */
.chart-card canvas, canvas[id], .echart-box { -webkit-touch-callout: none; }
.lens-hscroll::after {
  content: '\203A'; position: absolute; top: 0; right: 0; bottom: 5px; width: 34px;
  display: flex; align-items: center; justify-content: flex-end; padding-right: 5px;
  color: var(--brass-deep); font-family: 'JetBrains Mono', monospace; font-size: 18px; font-weight: 700;
  background: linear-gradient(to left, var(--card) 38%, transparent);
  pointer-events: none; opacity: 0; transition: opacity .2s; border-radius: 0 8px 8px 0;
}
.lens-hscroll.more::after { opacity: 1; }
@media (max-width: 640px), (max-height: 479px) {
  .kpi-info-panel {
    /* 手机端:固定到屏幕顶部 · 不跟 button 位置 */
    position: fixed;
    left: 1rem; right: 1rem;
    top: 5rem; bottom: auto; /* nav h-16 + sticky top-1 ≈ 68px · 5rem=80px 避开导航 */
    transform: none;
    min-width: unset; max-width: unset; width: auto;
    font-size: calc(12px * var(--fs-scale,1));
    box-shadow: 0 4px 20px rgba(26,23,20,.18);
    animation: kpi-slide-in .3s ease-out;
  }
}
@keyframes kpi-slide-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* 表格 — 账册风 */
.ledger-table {
  width: 100%;
  border-collapse: collapse;
  font-feature-settings: "tnum" 1;
}
.ledger-table thead th {
  font-family: "JetBrains Mono", monospace;
  font-size: calc(10px * var(--fs-scale,1));
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 10px 14px;
  text-align: left;
  border-bottom: 1px solid var(--ink);
}
.ledger-table thead th.num { text-align: right; }
/* v0.8 列表排序:可排序列头 + 三态三角指示(CSS 绘制,不用字形/emoji) */
.ledger-table thead th.sortable-th { cursor: pointer; user-select: none; }
.ledger-table thead th.sortable-th:hover { color: var(--ink); }
.ledger-table thead th.sortable-th::after {
  content: ""; display: inline-block; width: 0; height: 0; margin-left: 5px;
  vertical-align: middle; opacity: .28;
  border-left: 3px solid transparent; border-right: 3px solid transparent;
  border-top: 4px solid currentColor;
}
.ledger-table thead th.sortable-th[aria-sort="ascending"]::after {
  border-top: 0; border-bottom: 4px solid var(--brass-deep); opacity: 1;
}
.ledger-table thead th.sortable-th[aria-sort="descending"]::after {
  border-bottom: 0; border-top: 4px solid var(--brass-deep); opacity: 1;
}
.ledger-table tbody td {
  padding: 14px;
  border-bottom: 1px solid var(--rule-soft);
  vertical-align: middle;
  font-size: calc(14.5px * var(--fs-scale,1));
}
/* v1.9.3 · 账户表的数字格一律不折行。
   这两张表最多 17 列、自然宽远超容器,table-layout:auto 会把**能折行的内容压到 min-content**
   再把宽度让给别的列 —— 于是「930.85%」后面那个「累」上标、「-6.00pp」后面的上标、
   「跑输 -87.10pp」都会掉到第二行,行高从 55px 顶到 67~73px;而窄值行不折,同一列有的一行有的两行。
   逐个格补 whitespace-nowrap 是逐点补:下次加个指标列又会漏。这里按「数字格」这个属性一次网住,
   新增 data-mcol 列自动继承。守护 v193-TABLE-NUM-NOWRAP。 */
#dash-list .ledger-table tbody td.num,
#reports-region .ledger-table tbody td.num { white-space: nowrap; }

.ledger-table tbody td.num {
  font-family: "JetBrains Mono", monospace;
  font-variant-numeric: tabular-nums;
  text-align: right;
  letter-spacing: 0.01em;
}
.ledger-table tbody tr:hover td { background: var(--card-soft); }

/* 边栏 */
.side-rule {
  border-left: 1px solid var(--rule);
  padding-left: 24px;
}

/* 序号水印 */
.folio {
  font-family: "Fraunces", serif;
  font-feature-settings: "ss01" 1, "swsh" 1;
  font-style: italic;
  font-size: calc(76px * var(--fs-scale,1));
  line-height: 1;
  color: var(--paper-deep);
  user-select: none;
}

/* 对勾 / 状态符号 */
.tick-done {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  border: 1.5px solid var(--forest);
  background: var(--forest);
  color: var(--paper);
  font-size: calc(11px * var(--fs-scale,1));
  font-weight: 700;
}
.tick-pending {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  border: 1.5px dashed var(--ink-subtle);
  color: var(--ink-subtle);
}

/* 响应处理 */
@media (max-width: 720px), (max-height: 479px) {
  body { font-size: calc(14.5px * var(--fs-scale,1)); }
  /* v0.14.1 UED · 手机 2 列 KPI 卡:24px padding 偏重、挤内容 → 收紧留白节奏,值略降一档更贴合窄卡 */
  .kpi-card { padding: 16px 15px; }
  .kpi-eyebrow { margin-bottom: 10px; }
  .kpi-value { font-size: calc(24px * var(--fs-scale,1)); }
  .kpi-delta { margin-top: 8px; }
}

/* Print-像-账册的微动效 */
@keyframes fade-up {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.fade-in        { animation: fade-up 600ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.fade-in-delay-1 { animation: fade-up 600ms cubic-bezier(0.2, 0.8, 0.2, 1) both; animation-delay: 100ms; }
.fade-in-delay-2 { animation: fade-up 600ms cubic-bezier(0.2, 0.8, 0.2, 1) both; animation-delay: 200ms; }
.fade-in-delay-3 { animation: fade-up 600ms cubic-bezier(0.2, 0.8, 0.2, 1) both; animation-delay: 300ms; }
.fade-in-delay-4 { animation: fade-up 600ms cubic-bezier(0.2, 0.8, 0.2, 1) both; animation-delay: 400ms; }

/* 账册装饰 — 翻页角 */
.dog-ear {
  position: relative;
}
.dog-ear::after {
  content: "";
  position: absolute;
  top: 0; right: 0;
  width: 24px; height: 24px;
  background: linear-gradient(225deg, var(--paper-deep) 50%, var(--rule-soft) 50%);
  border-left: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}

/* 1px 内边线(账册分栏) */
.col-rule > * + * { border-left: 1px solid var(--rule); padding-left: 24px; }

/* 移动端遮罩(envelope 风格) */
.scrim {
  position: fixed;
  inset: 0;
  background: rgba(26, 23, 20, 0.4);
  backdrop-filter: blur(2px);
  z-index: 50;
}

/* 模态弹层(信函式) */
.envelope-modal {
  background: var(--card);
  border: 1px solid var(--ink);
  box-shadow: 8px 8px 0 var(--paper-deep), var(--shadow-deep);
  position: relative;
}
.envelope-modal::before {
  content: "";
  position: absolute;
  top: -1px; left: 24px; right: 24px;
  height: 4px;
  background: var(--brass);
}

/* 选择 */
::selection {
  background: var(--brass);
  color: var(--paper);
}

/* 链接 */
a {
  color: var(--ink);
  text-decoration-color: var(--rule);
  text-underline-offset: 4px;
  transition: text-decoration-color 200ms ease;
}
a:hover { text-decoration-color: var(--brass); }

a.brass-link {
  color: var(--brass-deep);
  text-decoration-color: var(--brass-soft);
}
a.brass-link:hover { text-decoration-color: var(--brass); }

/* —— Chart palette via CSS vars —— */
.chart-card {
  background: var(--card);
  border: 1px solid var(--rule);
  padding: 24px;
}

/* Sparkline 用 */
.sparkline-pos { color: var(--forest); }
.sparkline-neg { color: var(--rust); }

/* 滚动条 */
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--paper); }
::-webkit-scrollbar-thumb { background: var(--rule); border: 3px solid var(--paper); }
::-webkit-scrollbar-thumb:hover { background: var(--ink-subtle); }

/* — Hamburger summary — 隐藏默认箭头 */
summary { list-style: none; }
summary::-webkit-details-marker { display: none; }
summary::marker { content: ''; }

/* — 填报页 ledger 展开/折叠 文案随状态切换(纯 CSS · 无 JS) — */
details[open]      > summary .lg-when-closed { display: none; }
details:not([open]) > summary .lg-when-open  { display: none; }

/* — v0.7 配置引导 · 折叠式「如何获取」帮助(纯 CSS · 无 JS) — */
.help-fold > summary {
  font-family: "JetBrains Mono", monospace; font-size: calc(11px * var(--fs-scale,1));
  color: var(--brass-deep); cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: 5px; margin-top: 6px;
}
.help-fold > summary::-webkit-details-marker { display: none; }
.help-fold > summary::marker { content: ''; }
.help-fold > summary::before { content: '+'; font-weight: 600; }
.help-fold[open] > summary::before { content: '\2013'; } /* en-dash */
.help-fold .help-body {
  font-size: calc(13px * var(--fs-scale,1)); color: var(--ink-soft); line-height: 1.85;
  margin-top: 8px; padding: 12px 14px;
  background: var(--card-soft); border: 1px solid var(--rule-soft);
}
.help-fold .help-body ol { margin: 0; padding-left: 18px; }
.help-fold .help-body a { color: var(--brass-deep); text-decoration: underline; }

/* ============================================================
   v1.2.2 · 字号档位 · 层2/层5(issue #7)
   层2:6 个写死的 Tailwind arbitrary 字号类(全站 820 处,仅 6 个离散尺寸)
        用 calc×scale 重定义;!important 压 Play CDN 生成的绝对 px
        (仓库既有手法:lens-select .lsel-q 16px !important)。
        标准档 scale=1 → calc(Npx*1)=Npx,与现状逐像素等价。
   ============================================================ */
.text-\[8px\]  { font-size: calc(8px  * var(--fs-scale,1)) !important; }
.text-\[9px\]  { font-size: calc(9px  * var(--fs-scale,1)) !important; }
.text-\[10px\] { font-size: calc(10px * var(--fs-scale,1)) !important; }
.text-\[11px\] { font-size: calc(11px * var(--fs-scale,1)) !important; }
.text-\[12px\] { font-size: calc(12px * var(--fs-scale,1)) !important; }
.text-\[13px\] { font-size: calc(13px * var(--fs-scale,1)) !important; }

/* 层5:移动端输入框 16px 地板(<16px 聚焦触发 iOS 整页放大)。
   只在 大/特大 档生效 → 标准档输入框完全不动,零回归;
   放大档取 max(16px, 14px×scale) 保证既变大又不触发 zoom。 */
@media (max-width: 640px), (max-height: 479px) {
  html[data-fs="lg"] input,  html[data-fs="lg"] select,  html[data-fs="lg"] textarea,
  html[data-fs="xl"] input,  html[data-fs="xl"] select,  html[data-fs="xl"] textarea {
    font-size: max(16px, calc(14px * var(--fs-scale,1))) !important;
  }
}

/* v1.2.2 · 字号控件(nav 下拉 + 移动菜单行)· 高亮 = aria-pressed */
.fs-opt { display:block; width:100%; text-align:left; background:transparent; border:0; cursor:pointer;
  font-family:"JetBrains Mono",monospace; font-size: calc(12px * var(--fs-scale,1)); color:var(--ink-soft);
  padding:7px 14px; white-space:nowrap; letter-spacing:.06em; }
.fs-opt:hover { background:var(--card-soft); color:var(--ink); }
.fs-opt[aria-pressed="true"] { background:var(--ink); color:var(--paper); }
.fs-opt-m { font-family:"JetBrains Mono",monospace; font-size: calc(12px * var(--fs-scale,1)); color:var(--ink-soft);
  border:1px solid var(--rule); background:var(--card); padding:5px 11px; cursor:pointer; letter-spacing:.04em; }
.fs-opt-m[aria-pressed="true"] { background:var(--ink); color:var(--paper); border-color:var(--ink); }
#fs-menu > summary::-webkit-details-marker { display:none; }
#fs-menu > summary::marker { content:''; }

/* v1.3 · 旭日分析指标选择器 */
.sun-m-off { opacity:.42; text-decoration:line-through; cursor:not-allowed; }
#sunMetricPop button { display:block; width:100%; text-align:left; background:none; border:0; cursor:pointer;
  font-family:"JetBrains Mono",monospace; font-size: calc(12px * var(--fs-scale,1)); color:var(--ink-soft);
  padding:6px 14px; white-space:nowrap; }
#sunMetricPop button:hover { background:var(--card-soft); color:var(--ink); }
#sunMetricPop button.on { background:var(--ink); color:var(--paper); }
#sunMetricPop button.off { opacity:.42; text-decoration:line-through; cursor:not-allowed; }

/* ============================================================
   v1.6 · UED review 修复(docs/ued-review-2026-07.md)
   ============================================================ */

/* 补 .pill-mute —— 3 处模板在用(nav 字号钮/隐私钮 · dashboard「本期未填收支」)但此前无定义,
   语义 = 中性/未启用/无数据(spec §6.2 状态标签第 4 档) */
.pill-mute { background: transparent; border-color: var(--rule-soft) !important; color: var(--ink-subtle); }
button.pill-mute:hover, summary.pill-mute:hover { border-color: var(--rule) !important; color: var(--ink-soft); }

/* ---------------------------------------------------------------
   v1.18 · 流水来源微标签(.src-tag)
   为什么不复用 .pill:.pill 是 4px/10px + 10.5px + 大字距 + uppercase,
   给"一个区块一枚"设计的;流水时间线是**每行一枚**,用 .pill 会把行高撑开、
   把本来紧凑的账本读感搞散。另外内容是中文,uppercase 与 0.1em 字距都没意义。
   --------------------------------------------------------------- */
.src-tag {
  display: inline-flex;
  align-items: center;
  padding: 1px 5px;
  border: 1px solid var(--rule-soft);
  background: var(--paper-soft);
  font-family: "JetBrains Mono", monospace;
  font-size: calc(9.5px * var(--fs-scale,1));
  letter-spacing: 0.02em;
  color: var(--ink-subtle);
  border-radius: 1px;
  white-space: nowrap;
  line-height: 1.5;
  /* 定宽:时间线里它是一整列,三种标签(手动填报 50.8 / 来源未记录 60.5 / 自动 · 股价 68.5)
     各按内容宽会让这一列两边都参差。取最宽那个当下限、内容居中,列的左右边缘就都齐了。 */
  min-width: 70px;
  justify-content: center;
}
/* 窄屏放弃定宽 —— 那里本来也排不成列,定宽只会把删除按钮挤到下一行。
   窄屏这一行的参数是在真机上扫出来的(390px · 账户详情 8 月组 78 行):
     类别最小宽 140 + 标签任意宽 → 删除按钮掉行 6 行(这就是我第一版的回归)
     类别最小宽 120 + 标签不定宽 → 掉行 0 · 类别折行 0   ← 采用
     类别最小宽 110 或更小       → 类别被挤上第一行,「估值变动 · 自动(定时)」从中间折断
   所以模板那侧配套写成 min-w-[120px] sm:min-w-[140px]。 */
@media (max-width: 640px) {
  .src-tag { min-width: 0; padding: 1px 4px; }
}
/* 分组配色:自动拉数据=黄铜 · 券商=石板蓝 · 截图导入=森绿 · 手动/系统=中性 */
.src-auto   { background: var(--brass-soft);  border-color: var(--brass);  color: var(--brass-deep); }
.src-broker { background: var(--slate-soft);  border-color: var(--slate);  color: var(--slate); }
.src-import { background: var(--forest-soft); border-color: var(--forest); color: var(--forest); }
.src-manual { background: var(--card-soft);   border-color: var(--rule-soft); color: var(--ink-soft); }
.src-system { background: var(--paper-deep);  border-color: var(--rule);   color: var(--ink-soft); }
/* 历史数据(v1.18 之前)占多数,必须**最不抢视线**:虚线 + 透明底 + 最淡的字 */
.src-unknown { background: transparent; border-style: dashed; border-color: var(--rule-soft); color: var(--ink-faint); }

/* PC 上目录 sheet 与遮罩彻底不参与渲染(此前仅靠 transform 移出视口,仍在合成层里) */
@media (min-width: 1024px) and (min-height: 480px) {
  .toc-sheet, .toc-sheet-mask { display: none !important; }
}

/* review A5 · 1px 发丝网格。
   旧写法 `gap-px bg-rule` 靠容器底色从缝隙透出来画线 —— 格子数不满一行时,空位也透出米灰色,
   形成突兀色块(accounts 9 类型 ÷ 6 列空 3 格 / checkup 5 KPI ÷ 2 列空 1 格)。
   改为:容器白底 + 上左外边线,子项各自画右下线 → 线条一致,空位自然是白底。 */
.grid-hairline { background: var(--card); border-top: 1px solid var(--rule); border-left: 1px solid var(--rule); }
.grid-hairline > * { border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }

/* review B3-4 · 表格窄列里的中文被挤成竖排 → 关键列不换行 */
.ledger-table td.nowrap, .ledger-table th.nowrap { white-space: nowrap; }

/* review B3-3 · 列表行「更多操作」下拉:高频操作留行内,低频收进 ⋯(spec §6.1 行内 ≤3) */
.row-more { position: relative; display: inline-block; vertical-align: middle; }
.row-more > summary {
  list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 30px; color: var(--ink-subtle);
  border: 1px solid transparent; border-radius: var(--r-md); transition: color .15s, border-color .15s, background-color .15s;
}
.row-more > summary::-webkit-details-marker { display: none; }
.row-more > summary::marker { content: ''; }
.row-more > summary:hover { color: var(--ink); background: var(--paper-soft); }
.row-more[open] > summary { color: var(--ink); background: var(--paper-soft); }
/* v1.35 · 菜单浮层:细边 + 柔和投影 + 圆角(原来是墨色粗框 + 4px 实心错位阴影,和新按钮不是一套) */
.row-more-pop {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 45; min-width: 156px;
  background: var(--card); border: 1px solid var(--rule-soft); border-radius: var(--r-lg);
  box-shadow: 0 10px 30px -10px rgba(26, 23, 20, .22), 0 2px 6px rgba(26, 23, 20, .06);
  padding: 4px; text-align: left;
}
.row-more-pop.menu-left { left: 0; right: auto; }
.row-more-pop > a, .row-more-pop button {
  display: block; width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  padding: 7px 10px; border-radius: var(--r-md); font-family: var(--ui-sans);
  font-size: calc(13px * var(--fs-scale,1)); color: var(--ink-soft); white-space: nowrap;
}
.row-more-pop > a:hover, .row-more-pop button:hover { background: var(--paper-soft); color: var(--ink); }
/* 带按钮外观的菜单(持仓页「添加其他 ▾」):summary 用 btn-paper,不吃上面 32×30 的 ⋯ 规格 */
.row-more.menu-btn > summary.btn-paper { width: auto; height: auto; color: var(--ink); border-color: var(--rule-soft); background: var(--card); }
.row-more.menu-btn > summary.btn-paper:hover, .row-more.menu-btn[open] > summary.btn-paper { background: var(--paper-soft); border-color: var(--rule); }
/* 不可逆操作用 rust 描边语义(spec §6.1 danger:有色=要你做决定) */
.row-more-pop .row-more-danger { color: var(--rust); }
.row-more-pop .row-more-danger:hover { background: rgba(156,74,42,.07); color: var(--rust); }

/* review B2-2 · 填报行折叠(移动端 13.9 屏 → 约 3 屏)· summary 满足 40px 触摸高度 */
.entry-fold > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 6px;
  min-height: 40px; margin-top: 6px; padding-top: 8px;
  border-top: 1px solid var(--rule-soft);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: calc(11px * var(--fs-scale,1)); letter-spacing: .08em;
  color: var(--brass-text, #85642F);
}
.entry-fold > summary::-webkit-details-marker { display: none; }
.entry-fold > summary::marker { content: ''; }
.entry-fold > summary:hover { color: var(--ink); }
.entry-fold > summary .fold-chev { transition: transform .18s ease; flex-shrink: 0; }
.entry-fold[open] > summary .fold-chev { transform: rotate(180deg); }
.entry-fold[open] > summary .fold-when-closed { display: none; }
.entry-fold:not([open]) > summary .fold-when-open { display: none; }

/* review A4 · 分析页顶部口径控件折叠条(窄屏收起 / PC 恒展开且不显示 summary → 零回归) */
.filter-fold > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 7px;
  min-height: 44px; padding: 0 14px; margin-bottom: 4px;
  background: var(--card); border: 1px solid var(--rule);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: calc(11px * var(--fs-scale,1)); letter-spacing: .06em; color: var(--ink-soft);
}
.filter-fold > summary::-webkit-details-marker { display: none; }
.filter-fold > summary::marker { content: ''; }
/* v1.6.1 用户反馈②·箭头方向要符合直觉:收起 = ›(向右,「点开」)· 展开 = ⌄(向下)。
   此前是 ⌄ / ⌃,收起态看不出「这里能点开」。 */
.filter-fold > summary .fold-chev { transition: transform .18s ease; flex-shrink: 0; transform: rotate(-90deg); }
.filter-fold[open] > summary .fold-chev { transform: rotate(0deg); }
.filter-fold[open] > summary .fold-when-closed { display: none; }
.filter-fold:not([open]) > summary .fold-when-open { display: none; }
/* 收起态的行动号召:明确写出点开能干什么,而不是一个「改」字 */
.filter-fold > summary .fold-cta { color: var(--brass-text, #85642F); white-space: nowrap; }
.filter-fold:not([open]) > summary { border-color: var(--brass); background: var(--card-soft); }
@media (min-width: 768px) and (min-height: 480px) { .filter-fold > summary { display: none; } }
/* 横屏 iframe 短边只有 390 但确是宽屏视图 → 把手照旧隐藏 */
@media (min-width: 768px) { html.ls-wide .filter-fold > summary { display: none; } }

/* review B1-6 · KPI 带:窄屏「英雄数字 + 横滑 chip」。
   主 KPI(第一个)近满宽 + 字号升档,其余横滑 —— 五个同等大小的数字等于没有重点。 */
/* v1.6.1 用户反馈③ · 横滑方案退回网格。
   核心指标的要求是「一目了然」—— 横滑意味着有指标藏在屏幕外,得划一下才知道,这与目的相悖。
   改法:保留主次(净资产跨两列 + 大字),但把格子做紧凑(padding / eyebrow / value 全部收一档),
   让 5 个指标在一屏内同时可见。
   !important 必要:Tailwind Play CDN 在 style.css 之后注入,其 .grid-cols-2 同为单类选择器。 */
@media (max-width: 767px), (max-height: 479px) {
  html:not(.ls-wide) .kpi-band { display: grid !important; grid-template-columns: 1fr 1fr !important; }
  html:not(.ls-wide) .kpi-band > * { padding: 11px 12px !important; }
  html:not(.ls-wide) .kpi-band > * .kpi-eyebrow { margin-bottom: 5px; font-size: calc(9.5px * var(--fs-scale,1)); letter-spacing: .12em; }
  html:not(.ls-wide) .kpi-band > * .kpi-value { font-size: calc(19px * var(--fs-scale,1)); line-height: 1.15; }
  html:not(.ls-wide) .kpi-band > * .kpi-delta { margin-top: 4px; font-size: calc(10px * var(--fs-scale,1)); }
  /* 主指标:跨两列 + 字号升档,仍是视觉锚点 */
  html:not(.ls-wide) .kpi-band > *:first-child { grid-column: 1 / -1 !important; padding: 13px 14px !important; }
  /* 其余一律单列 —— 模板里第 5 个 KPI 原本带 col-span-2(那是「5 个平铺、最后一个居中」的老布局),
     现在主指标已占满第一行,第 5 个若还跨列就会让第 4 个旁边空一格。 */
  html:not(.ls-wide) .kpi-band > *:not(:first-child) { grid-column: auto !important; }
  html:not(.ls-wide) .kpi-band > *:first-child .kpi-value { font-size: calc(30px * var(--fs-scale,1)); }
  html:not(.ls-wide) .kpi-band > *:first-child .kpi-delta { font-size: calc(11px * var(--fs-scale,1)); }
}

/* review B3-2 · 类型汇总带:窄屏由多行网格改横滑单行(9 个类型曾占满整个首屏 ~950px) */
@media (max-width: 767px), (max-height: 479px) {
  html:not(.ls-wide) .summary-band {
    display: flex !important; overflow-x: auto;
    overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity; scrollbar-width: none;
  }
  html:not(.ls-wide) .summary-band::-webkit-scrollbar { display: none; }
  html:not(.ls-wide) .summary-band > * { flex: 0 0 44% !important; scroll-snap-align: start; }
}

/* spec §5 · 尊重系统「减少动态效果」偏好 —— 前庭障碍用户会因动画产生生理不适。
   功能性 loader(htmx-indicator / animate-spin)保留,装饰性动画一律停。 */
@media (prefers-reduced-motion: reduce) {
  .fade-in, .fade-in-delay-1, .fade-in-delay-2, .fade-in-delay-3, .fade-in-delay-4 {
    animation: none !important; opacity: 1 !important; transform: none !important;
  }
  #page-overlay, #page-overlay * { animation: none !important; }
  #page-progress::before { animation: none !important; }
  .kpi-info-panel { animation: none !important; }
  .toc-sheet { transition-duration: .01ms !important; }
}

/* review B1-7 · 资产透视三个区块(旭日/排行/交叉表)靠 JS 异步填充,填充前是三个大空白框,
   用户不知道是坏了还是在算 → 给统一的计算中占位。JS 渲染时会覆盖。 */
.lens-skeleton {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 120px; height: 100%;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: calc(11px * var(--fs-scale,1)); letter-spacing: .08em; color: var(--ink-subtle);
}

/* review B3-7 · ★ 在 JetBrains Mono 里没有字形,回落后被渲染成点/方块(实测「风险 ······」)。
   星级单独指定有该字形的字体族。 */
.stars {
  font-family: "Noto Serif SC", "Segoe UI Symbol", "Apple Symbols", sans-serif;
  letter-spacing: .04em;
}

/* v1.6.1 的 .rot-* 局部旋转层已删(JS 已无引用)。
   它当年就用对了典范写法 `width:100dvh; height:100vw; transform:translate(100vw,0) rotate(90deg)`,
   只错了一个单位:注释里写「用 dvh 而非 vh,因为 iOS 地址栏收放会改变 vh」—— **正好说反了**。
   vh 是 large viewport(工具栏收起时的高度,恒定),dvh 才是会随工具栏变化的那个。
   用 dvh 当固定尺寸 → 工具栏一收放盒子就变 → 重排。这个误解一路带到 v1.6.6 改成 JS 量 px。 */

/* 触发按钮(仅窄屏出现:桌面本来就宽) */
.landscape-btn { display: none; }
@media (pointer: coarse) { .landscape-btn { display: inline-flex; } }

/* ── v1.6.15 · 整页横屏 · **原地**改断点(不再用 iframe 重载页面)────────────
   历史:v1.6.6–v1.6.14 用同源 iframe 拿"独立 viewport"。有效,但点一下 = 一次完整
   后端渲染 + 12 个脚本重跑(实测 1362ms),而且新文档必然丢滚动位置。
   现在断点由 landscape.js 原地重编译(Play CDN 运行时编译器 · 实测 114ms),
   这里只负责把布局宽度锁成屏幕**长边**,并在设备竖屏时转 90°。

   尺寸用交换后的视口单位(与 v1.6.8 调研的通行写法同一套):
     设备竖屏:width=100vh(长边)· height=100vw(短边)· 转 90°
     设备横屏:width=100vw(长边)· height=100vh(短边)· 不转
   两种情况都是「长边 × 短边」= 同一个物理矩形 → 转手机零重排,且切换由媒体查询完成。
   `max-width: 479px` 是软键盘护栏(竖屏弹键盘会让 orientation 翻成 landscape · SO 8883163)。 */
html.ls-wide { overflow: hidden; }
html.ls-wide > body {
  position: fixed; top: 0; left: 0; margin: 0;
  width: 100vw; height: 100vh;
  /* body 自带 Tailwind `min-h-screen`(min-height:100vh)。不清掉它,height 就被压过去 ——
     实测 body 变成 844×844(应为 844×390),旋转后底部整段跑到屏外,
     连 position:fixed 的退出钮都被算到屏外(rect 3964,730)。 */
  min-height: 0 !important;
  overflow-y: auto; overflow-x: hidden;
  overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  transform-origin: 0 0; transform: none;
}
@media (orientation: portrait) and (max-width: 479px) {
  html.ls-wide > body {
    width: 100vh; height: 100vw;
    transform: translate(100vw, 0) rotate(90deg);
  }
}

/* 退出钮:跟着 body 一起转,位置天然正确。
   内缩量按 iPhone 圆角给足 —— 用户反馈「会被 iPhone 的圆角遮挡导致按不稳」:
   iPhone 的屏幕圆角半径约 44–55pt,贴边 8px 的按钮有一角落在圆角外侧。
   右/上各留 26px,并把 nav 的右侧预留同步加大(见 .nav-inner padding-right)。 */
/* 退出钮由 landscape.js 放进 .nav-actions(随 sticky 导航常驻)。
   不用 position:fixed —— body 被 transform 后 fixed 的包含块变成 body,会跟着内容滚走;
   放进导航行同时解决「被 iPhone 屏幕圆角切到、按不稳」(nav-inner 自带内距)。 */
.ls-exit {
  display: inline-flex; align-items: center; gap: 5px;
  /* v1.6.16 · 用户反馈「经常点击没反应,要点很多次」。
     旧值 min-height:26px —— 旋转后它在屏幕上只有 26px 宽的一条,远低于 iOS HIG 的 44pt
     最小触摸目标,拇指很容易点在边上。加高到 34px,并把整行抬到 44px(见 .nav-inner)。
     touch-action:manipulation 去掉双击缩放的 300ms 等待(等待期内的点击会被吞)。 */
  min-height: 34px; padding: 0 12px; margin-left: 8px; cursor: pointer;
  touch-action: manipulation; -webkit-tap-highlight-color: rgba(26,23,20,.18);
  background: rgba(26,23,20,.88); color: var(--paper); border: none; border-radius: 3px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: calc(11px * var(--fs-scale,1)); letter-spacing: .1em;
  backdrop-filter: blur(4px);
}
.ls-exit:active { transform: translateY(1px); }

/* ── v1.6.9 · 普通模式:手机横屏时把内容钉在设备坐标系(方案 B,用户选定)──────
   效果 = 就像开了系统的「竖屏方向锁定」,只对本 app 生效:
   转手机时页面在屏幕上**一动不动**,要读还得把手机转回来。

   为什么能做到零重排:
     · body 盒子 = 100vh × 100vw = 短边 × 长边 = **竖屏那个形状**(视口单位在横屏下自动交换)
     · 排版宽度仍是短边 → 与竖屏逐像素相同(断点也已在 v1.6.7 改成看短边)
     · 反向旋转把 OS 的旋转抵消掉 → 内容在设备上的位置不变

   旋转符号必须跟着设备转向走(v1.6.8 记录的正是这个风险):
     screen.orientation.angle 的定义 = viewport 相对自然方向**顺时针**转过的角度,
     要抵消就得转 -angle。angle 90(设备逆时针转)→ -90°;angle 270(设备顺时针转)→ +90°。
     angle 由 landscape.js 读出并挂 html.ori-cw(iOS 16.4+ 有 screen.orientation,
     更老的回落 window.orientation)。判错的表现是内容上下颠倒 —— 一个 class 之差。

   旋转量:绕左上角转 -90° 后盒子落到 y 轴负侧 → 下移一个盒子宽度(100vh);
   转 +90° 后落到 x 轴负侧 → 右移一个盒子高度(100vw)。

   护栏:pointer:coarse 挡 PC 矮窗 · min-width:480 挡竖屏软键盘假横屏(SO 8883163 · 112★)
   · :not(.ls-on) 让主动横屏模式不受影响 · :not(.ls-wide) 让 iframe 内不受影响。

   fixed 浮层(浮钮 / toast)会以被 transform 的 body 为包含块 → 自动跟着一起转,
   位置天然正确,不需要单独校正。 */
/* v1.37 · 高度上限 479 → 459(与 landscape.js 的 FREEZE_Q 同值 · 护栏 v137-FREEZE-HEIGHT):
   冻结旋转只留给普通手机横屏(高 ≤ 440);iPhone Duo 外屏横握 / 帐篷(高约 466)是免手持正着看,按横向排 + 侧边操作栏。 */
@media (pointer: coarse) and (orientation: landscape) and (max-height: 459px) and (min-width: 480px) {
  html:not(.ls-wide) { overflow: hidden; }
  html:not(.ls-wide) > body {
    position: fixed; top: 0; left: 0; margin: 0;
    width: 100vh; height: 100vw;
    overflow-y: auto; overflow-x: hidden;
    overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
    transform-origin: 0 0;
    transform: translate(0, 100vh) rotate(-90deg);
  }
  html.ori-cw:not(.ls-wide) > body {
    transform: translate(100vw, 0) rotate(90deg);
  }
  /* 方案 B 固有代价:body 被 transform 之后,它内部所有 position:fixed 浮层的包含块
     从视口变成了 body 盒子。这些浮层的几何(inset-x-0 / bottom:0 / translateY(110%) 收起态)
     都是按「未旋转的视口」写的,放进旋转容器就会错位 —— 实测目录抽屉会漏进屏内、
     顶部进度条会横向溢出 988px。
     冻结态的语义是「用户误转了手机、马上会转回来」的过渡态,不需要这些浮层 →
     几何脆弱的一律藏掉,只留内容本身 + 两个小圆浮钮(它们随 body 一起转,位置自洽,
     而且方向钮必须留着:用户可能就是想横着拿再点开横屏视图)。 */
  html:not(.ls-wide) #toc-sheet,
  html:not(.ls-wide) .toc-sheet,
  html:not(.ls-wide) .toc-sheet-mask,
  html:not(.ls-wide) .toc-fab,
  html:not(.ls-wide) #page-progress,
  html:not(.ls-wide) #toast-stack { display: none !important; }
}

/* 旋转遮帘(普通模式):iOS 自己的旋转动画抹不掉,盖成纯纸面就看不出在转 */
html.ori-turning > body { background: var(--paper); }
html.ori-turning > body > * { opacity: 0 !important; }

/* 嵌套态(iframe 内)· 不再出现横屏入口,避免套娃 */
html.ls-wide #ori-float, html.ls-wide .landscape-btn { display: none !important; }

/* v1.6.10 · 横屏模式的导航条:加回来,但按 844×390 重排 ——————————————
   v1.6.8 我把它整个藏了,理由是「844 宽放不下、390 高太贵」。用户要求加回来 ——
   这是对的:藏掉能力不是解决排版问题的办法。真正要做的是给横屏一套自己的尺度。

   844 宽的账本(实测):退出钮占 ~112px 必须留出 → 可用 ~700px;
   7 个 tab 压到 10px + 13px 间距 ≈ 268px,加印章 20px ≈ 310px —— 宽度其实很宽裕。
   v1.6.8 之所以折行,不是 tab 太多,是 gap-12(48px)+ gap-7(28px)+ 完整品牌文字
   + 版本徽记 + 字号钮 + 隐私钮 + 账期 pill + 用户名 一起挤的结果。

   390 高才是真正稀缺的:导航从 64px 压到 38px,省下的 26px 直接给内容。
   取舍:品牌只留印章(文字/版本在这个高度里是纯消耗)· 右侧那组整组收起
   (隐私有右下浮钮、字号退出再调),换来 7 个 tab 全部一行放下。 */
html.ls-wide > body > header {
  position: sticky; top: 0;
  /* 横屏态去掉毛玻璃:backdrop-filter 在被 transform 的容器里是 iOS 已知的
     命中测试/合成干扰源,而这里它只是装饰(纸面本来就不透明感强)。 */
  backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
  background: var(--paper) !important;
}
html.ls-wide .nav-inner {
  height: 44px !important;   /* 44 = iOS 最小触摸目标;内含 34px 高的钮 */
  padding-left: 12px !important;
  /* 退出钮已放进 .nav-actions 参与 flex 排,不再需要为它预留右侧空白;
     只留一点内缩避开 iPhone 屏幕圆角(圆角半径约 44–55pt,贴边元素会被切)。 */
  padding-right: 26px !important;
}
html.ls-wide .nav-lead { gap: 18px !important; }
html.ls-wide .nav-brandtext { display: none !important; }
html.ls-wide .nav-inner img { width: 21px !important; height: 21px !important; }
html.ls-wide .nav-tabs {
  gap: 13px !important;
  font-size: calc(10px * var(--fs-scale, 1)) !important;
  letter-spacing: .1em !important;
}
/* 选中态下划线原本用 pb-[18px] 撑到 h-16 的底,压扁后必须重算,否则下划线跑到栏外 */
html.ls-wide .nav-tabs > a { white-space: nowrap !important; padding-bottom: 0 !important; }
html.ls-wide .nav-tabs > a[class*="border-b-2"] { padding-bottom: 4px !important; }
/* 右侧那组默认收起,但**保留隐私钮**并放进导航条 —— 原因见下面的浮钮取舍。 */
html.ls-wide .nav-actions { display: flex !important; gap: 0 !important; }
html.ls-wide .nav-actions > * { display: none !important; }
html.ls-wide .nav-actions > .nav-priv { display: inline-flex !important; min-height: 34px; touch-action: manipulation; }
html.ls-wide .nav-actions > .ls-exit { display: inline-flex !important; }

/* 浮钮取舍:隐私浮钮在 390 高的横屏里会压住内容(实测压住交叉表的「AI 解读当前视图」按钮)。
   横屏导航条里 tab 结束在 335px、退出钮从 726px 开始 —— 中间 390px 全是空的,
   把隐私钮放回导航条既不压内容又更好找。目录钮在横屏无意义(整页就一屏多点)一并收起。 */
html.ls-wide #priv-float { display: none !important; }

/* ── v1.6.13 · 横屏模式下的「本页目录」──────────────────────────────
   v1.6.10 我把目录钮一起藏了,理由是「横屏整页就一屏多点,目录无意义」。
   这个判断错了:横屏高度只有 390,一屏能看的内容反而**更少**,跨节跳转比竖屏更需要。
   交互按横屏的空间特性重排:
     · 入口:不用右下浮钮(390 高里浮钮必压内容)→ 放进导航行,与隐私钮同列
     · 面板:不用底部 sheet(竖屏的做法 —— 横屏里它会盖掉大半屏)
              → 改**右侧侧栏**:横屏宽度富余、高度稀缺,侧栏正好反过来用
     · 点条目跳转后 toc.js 原逻辑自动关闭,无需额外处理 */
/* 目录钮参与导航行的 flex 排列(由 landscape.js 搬进 .nav-actions)——
   不用 position:fixed 摆坐标:那样必须和隐私钮的宽度"保持相等",一变就撞。 */
html.ls-wide .nav-actions > .toc-fab {
  display: inline-flex !important;
  position: static !important;
  min-height: 34px; touch-action: manipulation;
  top: auto; right: auto; bottom: auto; left: auto;
  margin-right: 8px;
  /* 与隔壁隐私钮**同款**:.pill + .pill-mute 的描边样式 ——
     并列同级控件必须同尺度同样式(AGENTS.md 护栏 / visual-spec「并列同类元素」)。
     原来它是 38px 深色实心圆(为右下浮钮设计的),搁在描边 pill 旁边像两个系统的东西。 */
  width: auto; height: auto; border-radius: 0;
  padding: 4px 9px;
  background: transparent;
  border: 1px solid var(--rule-soft);
  color: var(--ink-subtle);
  box-shadow: none;
  opacity: 1;
}
html.ls-wide .nav-actions > .toc-fab svg { width: 14px; height: 14px; }
html.ls-wide .nav-actions > .toc-fab:hover,
html.ls-wide .nav-actions > .toc-fab:active { color: var(--ink-soft); border-color: var(--rule); }
/* top 从 38px(横屏导航栏高)起,不是 0 ——————————————————————————
   `<main>` 带 `relative z-10`,它本身就是一个**层叠上下文**;抽屉在 main 里面,
   所以 `.toc-sheet` 的 z-index:80 永远升不到 z-30 的导航之上(实测抽屉的关闭 ×
   被 nav-inner 压住)。同一个原因也让 v1.6.13 的目录浮钮被隐私钮压住。
   与其去拆 main 的层叠上下文(牵连全站),不如让抽屉从导航条下方开始 ——
   顺带导航在抽屉打开时仍可点,体验反而更好。 */
html.ls-wide .toc-sheet {
  left: auto; right: 0; top: 44px; bottom: 0;
  width: min(320px, 42vw); max-height: none;
  border-radius: 14px 0 0 14px;
  box-shadow: -8px 0 32px rgba(0,0,0,.22);
  transform: translateX(110%);
  padding: 10px 8px 12px;
}
html.ls-wide .toc-sheet.open { transform: translateX(0); }
html.ls-wide .toc-sheet-mask { top: 44px; }   /* 遮罩同样不盖导航条 */
html.ls-wide .toc-sheet-handle { display: none; }
html.ls-wide .toc-sheet .toc-node { padding-top: 9px; padding-bottom: 9px; min-height: 38px; }

/* ── 横屏的垂直节奏:390 高是真正稀缺的资源 ────────────────────────
   实测(交叉表页):header 39 + main 上内边距 30 + 标题块 mt-10(37.5)+ 标题 51
   + 说明段 53 → 首张卡片被推到 **221px = 屏高的 57%**。横屏是为了看表格,
   不是为了看留白。压缩的是间距与标题字号,**不删任何内容**。 */
html.ls-wide main { padding-top: 8px !important; padding-bottom: 14px !important; }
html.ls-wide main .mt-8, html.ls-wide main .mt-10, html.ls-wide main .mt-12 { margin-top: 8px !important; }
html.ls-wide main .mb-8, html.ls-wide main .mb-10, html.ls-wide main .mb-12 { margin-bottom: 10px !important; }
/* 页面大标题降一档(text-2xl 不动:那一档大量用在金额上,压了会伤可读性) */
html.ls-wide main .text-4xl { font-size: calc(24px * var(--fs-scale, 1)) !important; line-height: 1.2 !important; }
html.ls-wide main .text-3xl { font-size: calc(22px * var(--fs-scale, 1)) !important; line-height: 1.2 !important; }
/* 首屏印章动画在嵌套态也跳过(landscape.js 已处理),这里兜底避免遮挡 */
html.ls-wide #page-overlay { display: none !important; }

/* 横屏浮钮:与隐私眼 / 目录钮同列。
   可见性只由「触屏」决定 —— **不能带 max-width**:设备横屏时 viewport 变宽会让按钮消失。 */
#ori-float {
  position: fixed; right: 14px;
  bottom: calc(max(18px, env(safe-area-inset-bottom)) + 96px);
  z-index: 56;
  display: none;
  align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--card); color: var(--ink-soft);
  border: 1px solid var(--rule); box-shadow: 0 3px 12px rgba(0,0,0,.16);
  cursor: pointer; opacity: .62;
  transition: opacity .25s ease, border-color .18s ease;
}
@media (pointer: coarse) { #ori-float { display: inline-flex; } }
#ori-float:hover, #ori-float:active, #ori-float:focus-visible { opacity: 1; border-color: var(--ink-soft); }
/* 方向图标双态(Tabler device-mobile / device-mobile-rotated · MIT · 同款描边):
   按钮显示**目标状态** —— 竖屏时显示"横屏手机"(点它去横屏),横屏时显示"竖屏手机"。 */
.ori-ico-port { display: none; }
[aria-pressed="true"] .ori-ico-land { display: none; }
[aria-pressed="true"] .ori-ico-port { display: inline; }
#ori-float[aria-pressed="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); opacity: 1; }
body.is-scrolling #ori-float { opacity: .22; }


/* ── 并列同类图表的公共容器(v1.6.12)────────────────────────────────
   「资产配置」与「按成员分布」是语义同级、并列展示的一对图。它们的容器高度
   原来各写各的 h-[348px]/h-[262px],于是两个环一大一小 —— 用户一眼就看出不对。
   规则(见 docs/visual-spec.md「并列同类图表」):**并列同类图表共用同一个容器 class**,
   任何一侧要改高度都会同时改到另一侧,不可能再单边漂移。 */
.chart-pair-box { height: 336px; }
@media (min-width: 640px) and (min-height: 480px) { .chart-pair-box { height: 380px; } }


/* ── v1.6.16 · 打标页手机端 ─────────────────────────────────────────
   实测 390 宽下:页头两段说明 + 穿透卡 + AI 卡共约 1200px,要滑一整屏才见到第一个
   可操作控件;整页 14054px 高(62 行卡片化),保存钮在最底部。
   做法:说明收成 <details>(PC 全文常显)+ 底部常驻保存条。不删任何信息。 */
.tags-intro > summary { list-style: none; cursor: pointer; }
.tags-intro > summary::-webkit-details-marker { display: none; }
.tags-savebar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 55;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 9px 14px calc(9px + env(safe-area-inset-bottom));
  background: var(--paper); border-top: 1px solid var(--rule);
  box-shadow: 0 -6px 20px rgba(26,23,20,.10);
}
/* 保存条会盖住最后一行 → 给页面补底部留白 */
body:has(.tags-savebar) main { padding-bottom: 76px; }

.tags-todo-toggle {
  display: inline-flex; align-items: center; gap: 7px; margin-bottom: 12px;
  font-size: calc(12px * var(--fs-scale,1)); color: var(--ink-soft); cursor: pointer;
  min-height: 34px; touch-action: manipulation;
}
.tags-todo-toggle input { width: 16px; height: 16px; accent-color: var(--brass-deep); }


/* ── v1.6.17 · 系统浮钮 dock ─────────────────────────────────────────
   三个浮钮(方向 / 本页目录 / 隐藏金额)原来各写死 bottom 偏移,页面缺一个就留空洞
   (打标页没有目录钮 → 中间一个洞,用户反馈④a)。改成 flex 列:有几个排几个。
   z-index 9999 > 首屏遮罩 9998:系统能力不被页面内容的加载进度绑住(反馈①/④b)。 */
/* v1.19.6 · dock 里的「超级 Agent」入口(手机)。
   规格照抄 #ori-float —— 并列同类元素必须同尺寸同样式,不能一个 38 一个 42。
   只在**窄屏**出现:≥768px 上面那个带文字的 .ask-fab 才是主入口,
   两个同时出现就是同一件事给了两个按钮(触屏笔记本会同时命中 coarse 和宽屏)。 */
#ask-float {
  position: fixed; right: 14px;
  bottom: calc(max(18px, env(safe-area-inset-bottom)) + 144px);
  z-index: 56;
  display: none;
  align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--card); color: var(--brass-deep);
  border: 1px solid var(--rule); box-shadow: 0 3px 12px rgba(0,0,0,.16);
  cursor: pointer; opacity: .72;
  transition: opacity .25s ease, border-color .18s ease;
}
@media (pointer: coarse) { #ask-float { display: inline-flex; } }
/* 这两条隐藏规则必须**带上 #float-dock 前缀**:进 dock 之后有一条
   `#float-dock > #ask-float{display:inline-flex!important}`(两个 id),
   只写 `#ask-float` 或 `body.ask-page #ask-float` 的优先级压不过它,规则会静默失效。
   实测踩过:PC 上和 /ask 页面上按钮照样冒出来。 */
@media (min-width: 768px) {
  #ask-float,
  #float-dock > #ask-float { display: none !important; }
}
#ask-float:hover, #ask-float:active, #ask-float:focus-visible { opacity: 1; border-color: var(--brass); }
body.is-scrolling #ask-float { opacity: .28; }
/* 在超级 Agent 页面上不显示 —— 那里点它等于原地打转,而且这一页左右都有要读的内容
   (v1.19 记过:fixed 浮层在这一页放哪儿都挡) */
body.ask-page #ask-float,
body.ask-page #float-dock > #ask-float { display: none !important; }

#float-dock {
  position: fixed; right: 14px;
  bottom: max(18px, env(safe-area-inset-bottom));
  z-index: 9999;
  display: none;
  flex-direction: column; align-items: center; gap: 10px;
}
@media (pointer: coarse) { #float-dock { display: flex; } }
/* dock 里的按钮交给 flex 排,自己不再定位 */
#float-dock > #ori-float,
#float-dock > .toc-fab,
#float-dock > #ask-float,
#float-dock > #priv-float {
  position: static !important; right: auto !important; bottom: auto !important;
  display: inline-flex !important;
}
/* 目录抽屉打开时只藏隐私眼(它会压住抽屉底部条目),目录钮自身留着当关闭入口 */
body.toc-open #float-dock > #priv-float,
body.toc-open #float-dock > #ask-float { display: none !important; }
html.ls-wide #float-dock { display: none !important; }


/* ── v1.6.17 · 打标页「持仓方向」横条占比示意 ──────────────────────
   加回最初 UED 稿的横条(用户反馈⑤:原来一堆 pill 会换行,方向多了撑成好几行)。
   横条只表达比例,用同一色系按深浅循环 —— 不冒充"维值配色":
   维值配色由旭日那边 JS 的方案色板决定,服务端渲染取不到,这里自造一套只会与旭日不一致。 */
/* 手机端 .tags-table 会卡片化(td 变块级、宽度由内容决定)→ 横条必须显式吃满宽,
   否则 flex:1 拿不到可分配空间,实测塌成 3px。 */
.alloc-head { display: flex; align-items: center; gap: 8px; width: 100%; }
.alloc-bar {
  display: flex; flex: 1 1 auto; min-width: 60px; width: 100%;
  height: 9px; border-radius: 5px; overflow: hidden;
  background: var(--rule-soft);
}
.alloc-seg { display: block; height: 100%; min-width: 2px; }
.alloc-seg.seg-0 { background: #8a6a3a; }
.alloc-seg.seg-1 { background: #a98a5c; }
.alloc-seg.seg-2 { background: #6f7f6a; }
.alloc-seg.seg-3 { background: #93a08e; }
.alloc-seg.seg-4 { background: #6f7a8c; }
.alloc-seg.seg-5 { background: #9aa3b0; }
/* 标签行:不换行,超出横滑(复用 .hscroll-x 的 iOS 护栏:不触发 Safari 返回手势) */
.alloc-pills { display: flex; align-items: center; padding-bottom: 2px; }


/* v1.6.17 · 三个系统浮钮**基础态**就抬到首屏遮罩(9998)之上。
   #float-dock 是 landscape.js(defer)建的,建之前这三个钮还按各自定位渲染 ——
   实测 dashboard 上要到 3.2s 才可点(等 DOMContentLoaded)。抬 z-index 后首屏即可点。 */
#ori-float { z-index: 9999; }


/* v1.6.18 · 明细抽屉打开时闪一下边框 —— 指标放行时表格很高,
   用户点完需要一个"响应了"的确认(否则以为没下钻)。 */
@keyframes drawer-flash { 0%,100% { box-shadow: 0 0 0 0 rgba(176,141,63,0); } 25% { box-shadow: 0 0 0 3px rgba(176,141,63,.55); } }
.drawer-flash { animation: drawer-flash .9s ease-out 1; }
@media (prefers-reduced-motion: reduce) { .drawer-flash { animation: none; } }

/* v1.6.18 · ⑥ 浮钮 dock 右对齐 ——
   隐私态下 #priv-float 会显出文字标签变宽,而 dock 原来是 align-items:center,
   dock 宽度被最宽的那个撑开 → 另外两个居中钮跟着左移(用户反馈:位置偏移)。
   右对齐后每个钮的右缘固定,谁变宽只往左长,其余不动。 */
#float-dock { align-items: flex-end !important; }


/* v1.6.20 · 打标页横屏态:保存条要留着。
   .tags-savebar 带 md:hidden,而横屏模式把 md: 强制打开 → 它会被藏掉;
   但横屏下 62 行表格仍有两千多像素,保存钮还是不该只在最底部。 */
html.ls-wide .tags-savebar { display: flex !important; }


/* v1.6.20 · 打标页横屏态:说明仍保持折叠。
   横屏把 md: 强制打开 → `hidden md:block` 的全文版会现身、`md:hidden` 的折叠版会消失,
   但**横屏的竖向空间(390)比竖屏(844)更紧**,说明全文正是最该收起来的东西。
   横屏要的是"表格铺开",不是"把说明也铺开"。 */
html.ls-wide .tags-intro,
html.ls-wide .tags-note-fold { display: block !important; }
html.ls-wide .tags-intro-full,
html.ls-wide .tags-note-full { display: none !important; }


/* ── v1.6.20 · 打标页横屏态:页头压到最小,让表格进首屏 ─────────────────
   横屏成了这页的**默认工作模式**,而横屏只有 390 竖向像素。
   实测未压缩前:表头在 418px —— 整个首屏被 eyebrow + 大标题 + 两张说明卡占满,
   一行表格都看不到,等于还是干不了活。
   压的是页头与说明卡(它们已折叠成一行),表格本身一点不动。 */
html.ls-wide .tags-head { margin-bottom: 6px !important; }
html.ls-wide .tags-head .eyebrow { display: none !important; }
html.ls-wide .tags-head h1 { font-size: calc(19px * var(--fs-scale, 1)) !important; line-height: 1.2 !important; }
html.ls-wide .tags-head .tags-intro { margin-top: 2px !important; }
html.ls-wide .tags-head > a { font-size: calc(10px * var(--fs-scale, 1)) !important; }
/* 说明卡:内距压薄 + 标题与「这是什么」同一行 */
html.ls-wide .tags-note { padding: 6px 12px !important; margin-bottom: 6px !important; }
html.ls-wide .tags-note .tags-note-fold { display: inline-block !important; margin-top: 0 !important; margin-left: 8px; }

/* 券商对接状态条(v1.6.24)· 持仓页标题下,一眼看到本账户 ↔ 富途/老虎的 1:1 关联状况。
   用「左侧竖线 + 细框」而不是 paper-card:它是一条**关联信息**,不是一个内容区块;
   竖线用 brass(已关联)/ ink-subtle(未关联)区分,不靠文字才能读出状态。 */
.link-strip {
  border: 1px solid var(--rule); border-left: 3px solid var(--brass-deep);
  background: var(--card); padding: 12px 16px;
  display: flex; flex-wrap: wrap; align-items: center; column-gap: 20px; row-gap: 8px;
}
.link-strip.is-none { border-left-color: var(--ink-subtle); }
.link-strip .ls-kv { font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: calc(11px * var(--fs-scale,1)); color: var(--ink-soft); }
.link-strip .ls-kv b { color: var(--ink); }
.link-strip .ls-acts { margin-left: auto; display: flex; gap: 8px; }
/* 手机:竖排 + 两个按钮各占一半宽(44px 高满足 iOS 触摸目标 · visual-spec §7.6)*/
@media (max-width: 639px) {
  .link-strip { flex-direction: column; align-items: stretch; row-gap: 4px; }
  .link-strip .ls-acts { margin-left: 0; margin-top: 8px; }
  .link-strip .ls-acts > a { flex: 1; justify-content: center; }   /* v1.35 · 高度跟按钮小档走(手机 32px),原 44px 比旁边所有按钮都高一截 */
}

/* v1.9 · 版本徽记的「有新版」圆点 ————————————————————————————
   绝对定位、不进文档流:徽记只有 9px 高、贴在 logo 下面一行,
   任何进流的元素都会把它和 nav 一起撑歪(验收要求两态几何逐项相同)。
   brass 描边不是红色 —— 这是「有个新版本存在」的事实陈述,不是告警。 */
.ver-badge { text-decoration: none; }
.ver-badge:hover { color: var(--brass-text); text-decoration: none; }
/* v1.9.2 · 原 .ver-dot 用 brass-soft 填色,在 paper 背景上只有约 1.2:1 对比度 —— 用户反馈
   「太弱了,和背景色过于相似」,实测确实等于看不见。换成实心文字标签:
   brass-deep 底 + paper 字 ≈ 4.1:1,而且「NEW」是文字、不需要猜含义。
   参考 WordPress 的 #d63638 实心药丸 + 白字(border-radius:9px / font-size:11px / min-width:18px)
   与 sub2api 的「整个徽记变琥珀 chip + 实心点」。
   刻意不用 rust(红):红色在本项目里是告警语义,而「有新版」是事实陈述不是事故。 */
.ver-new {
  display: inline-block; margin-left: 3px;
  background: var(--brass-deep); color: var(--paper);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 7.5px; line-height: 1; letter-spacing: .1em;
  padding: 2.5px 3.5px 2px; border-radius: 2px;
  vertical-align: 1px; font-weight: 600;
  pointer-events: none;
}
/* 有更新时整个徽记也提一档(sub2api 的做法:chip 本身换色,不只挂个角标) */
.ver-badge.has-upd { color: var(--brass-deep); }
.ver-badge.has-upd:hover .ver-new { background: var(--ink); }

/* ── v1.9.2 · 「有新版」弹窗 ───────────────────────────────────────────── */
.upd-mask {
  position: fixed; inset: 0; background: rgba(26,23,20,.42);
  z-index: 10000; opacity: 0; pointer-events: none; transition: opacity .16s ease;
}
.upd-mask.open { opacity: 1; pointer-events: auto; }
.upd-modal {
  position: fixed; z-index: 10001;
  left: 50%; top: 84px; transform: translateX(-50%);
  width: min(440px, calc(100vw - 28px));
  background: var(--card); border: 1px solid var(--ink);
  box-shadow: 0 14px 40px rgba(33,30,23,.24);
}
.upd-modal[hidden] { display: none; }
/* 弹窗挂在 <footer class="... text-center"> 里 —— 不显式左对齐就会继承居中,
   正文和发布日期全跑到中间(移动端尤其明显)。 */
.upd-modal, .upd-modal * { text-align: left; }
/* 弹窗打开时收掉悬浮件:记账/目录/隐私三个 fab 的 z-index 是 9999,
   跟弹窗同级,会直接压在弹窗上面(移动端弹窗贴底,正好撞在按钮区)。 */
body.upd-open #float-dock,
body.upd-open .toc-fab,
body.upd-open #ori-float,
body.upd-open #priv-float { display: none !important; }
.upd-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 11px 14px; border-bottom: 1px solid var(--rule-soft);
}
.upd-x { background: none; border: 0; cursor: pointer; color: var(--ink-subtle); padding: 2px; line-height: 0; }
.upd-x:hover { color: var(--ink); }
.upd-body { padding: 14px; }
.upd-vers { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.upd-cur { font-family: 'JetBrains Mono', monospace; font-size: 0.94rem; color: var(--ink-soft); }
.upd-new {
  font-family: 'JetBrains Mono', monospace; font-size: 1.06rem; font-weight: 600;
  color: var(--paper); background: var(--brass-deep); padding: 1px 7px; border-radius: 2px;
}
.upd-behind {
  font-family: 'JetBrains Mono', monospace; font-size: 0.56rem; letter-spacing: .08em;
  border: 1px solid var(--brass-deep); color: var(--brass-text);
  background: var(--brass-soft); padding: 2px 6px;
}
.upd-meta { font-family: 'JetBrains Mono', monospace; font-size: 0.63rem; color: var(--ink-subtle); margin-top: 5px; }
.upd-sum { font-size: 0.78rem; color: var(--ink); line-height: 1.8; margin-top: 10px; }
.upd-mig {
  font-family: 'JetBrains Mono', monospace; font-size: 0.66rem; line-height: 1.7;
  margin-top: 11px; padding: 7px 9px; border: 1px dashed var(--rule); color: var(--ink-subtle);
}
.upd-mig.risk { border: 1px solid var(--rust); border-style: solid; color: var(--rust); background: rgba(156,74,42,.06); }
.upd-mig.ok   { border-style: solid; border-color: var(--forest); color: var(--forest); background: rgba(79,107,71,.07); }
.upd-foot {
  display: flex; gap: 9px; flex-wrap: wrap;
  padding: 12px 14px; border-top: 1px solid var(--rule-soft); background: var(--card-soft);
}
.upd-btn { font-size: 0.75rem; }
@media (max-width: 640px) {
  .upd-modal { top: auto; bottom: 0; left: 0; right: 0; transform: none; width: auto; border-bottom: 0; }
  /* 贴底抽屉的按钮行要躲开 iPhone 的 home indicator,否则最后一行按钮压在手势条下面 */
  .upd-foot { padding-bottom: max(12px, env(safe-area-inset-bottom)); }
  .upd-foot .upd-btn { flex: 1; text-align: center; }
}


/* ══════════════════════════════════════════════════════════════════════
   v1.10 · 报表页三区(封板快照)
   一区/二区定格于 asof,三区随 range —— 视觉上必须让用户看出这个分界,
   否则「切范围前两区不动」会被当成页面没反应。
   ════════════════════════════════════════════════════════════════════ */
.zone-head { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; flex-wrap: wrap; }
.zone-no {
  font-family: "JetBrains Mono", monospace; font-size: 1.1rem; line-height: 1;
  color: var(--paper); background: var(--brass-deep); padding: 5px 9px; letter-spacing: 0;
}
.zone-t { font-family: "Fraunces", "Noto Serif SC", serif; font-size: 1.25rem; }
.zone-sub { font-size: 0.72rem; color: var(--ink-subtle); line-height: 1.6; }
.zone-line { height: 2px; background: var(--brass-deep); opacity: .35; margin: 10px 0 18px; }

/* 资产 / 负债 对称条 · 左右同一比例尺 */
.sym-bar { display: flex; align-items: stretch; height: 34px; border: 1px solid var(--ink); margin-top: 14px; }
.sym-a { background: var(--brass-soft); display: flex; align-items: center; justify-content: flex-end; padding-right: 8px; overflow: hidden; }
.sym-l { background: rgba(156,74,42,.16); display: flex; align-items: center; padding-left: 8px; border-left: 2px solid var(--ink); overflow: hidden; }
.sym-a span, .sym-l span { white-space: nowrap; }

/* 瀑布 · 截断轴 + 连接线。月度流量与存量差两个数量级,全量轴下中间段看不见 —— 故必须截断轴。 */
.wf-scroll { overflow-x: auto; overflow-y: visible; -webkit-overflow-scrolling: touch; padding-bottom: 1.6rem; }
.wf { display: flex; align-items: flex-end; height: 220px; margin-top: 12px;
      border-bottom: 1px solid var(--rule); min-width: 460px;
      position: relative;              /* 承载截断斜纹带(::after 贴轴线)*/
      padding-top: 1.5rem;             /* v1.11.1 · 给最高柱子的顶部标签留位置 ——
                                          原来标签定位在柱顶 -1.05rem,最高柱贴着容器上边 → 被裁掉一半 */
      box-sizing: content-box; }       /* 柱高是相对 content box 的百分比,padding 不参与 → 比例不变 */
.wf-col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; height: 100%; }
.wf-bar { width: 62%; position: relative; min-height: 2px; }
/* 连接线:本段端点水平延伸到下一段起点 —— 没有它就读成普通柱状图,丢掉「分解」语义 */
.wf-bar::after {
  content: ""; position: absolute; top: 0; right: -61.3%; width: 61.3%; height: 1px;
  background: var(--ink-subtle); opacity: .5;
}
.wf-col:last-child .wf-bar::after { display: none; }
.wf-dl {
  /* v1.11.1 · 标签比柱子宽(¥1,234,567 约 178px vs 柱宽 ~127px),溢出的部分会被 DOM 顺序在后的
     柱子背景盖住 —— .wf-bar 没有 z-index 不构成层叠上下文,所以给标签 z-index 就能浮到所有柱子之上。 */
  position: absolute; left: -22%; right: -22%; top: -1.05rem; text-align: center; z-index: 5;
  font-family: "JetBrains Mono", monospace; font-size: 0.62rem; font-weight: 600; white-space: nowrap;
}
.wf-lab { font-family: "JetBrains Mono", monospace; font-size: 0.56rem; color: var(--ink-subtle);
          margin-top: 6px; text-align: center; line-height: 1.35; }

/* 三列对照表 · 封板要精确值,所以用表不用图 */
.cmp-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.cmp-table { width: 100%; border-collapse: collapse; min-width: 620px; }
.cmp-table th {
  font-family: "JetBrains Mono", monospace; font-size: calc(9.5px * var(--fs-scale,1));
  letter-spacing: .14em; color: var(--ink-soft); text-align: right;
  padding: 8px 10px; border-bottom: 1px solid var(--ink); white-space: nowrap;
}
.cmp-table th:first-child { text-align: left; }
.cmp-table td {
  padding: 9px 10px; border-bottom: 1px solid var(--rule-soft); text-align: right;
  font-family: "JetBrains Mono", monospace; font-size: calc(12px * var(--fs-scale,1)); white-space: nowrap;
}
.cmp-table td:first-child {
  text-align: left; font-family: inherit; font-size: calc(13px * var(--fs-scale,1));
  position: sticky; left: 0; background: var(--card); white-space: nowrap;
}

/* 集中度 · 横条 + 阈值线 + 上期幽灵条(没有上期时不画,而不是画成 0) */
.conc-row { margin-bottom: 12px; }
.conc-cap { display: flex; justify-content: space-between; gap: 10px;
            font-family: "JetBrains Mono", monospace; font-size: calc(10px * var(--fs-scale,1)); margin-bottom: 3px; }
.conc-track { position: relative; height: 16px; background: var(--paper-soft); border: 1px solid var(--rule-soft); }
.conc-ghost { position: absolute; top: 0; bottom: 0; background: rgba(140,106,51,.18); }
.conc-fill { position: absolute; top: 0; bottom: 0; background: var(--brass-deep); opacity: .75; }
.conc-thr { position: absolute; top: -3px; bottom: -3px; width: 1px; background: var(--rust); }

/* 流动性分层 · 单条堆叠 */
.stack { display: flex; height: 42px; border: 1px solid var(--ink); margin-top: 10px; }
.stack > div { display: flex; align-items: center; justify-content: center; overflow: hidden;
               font-family: "JetBrains Mono", monospace; font-size: calc(10px * var(--fs-scale,1)); white-space: nowrap; }
.stack-liquid { background: var(--brass-soft); }
.stack-semi { background: rgba(140,106,51,.30); border-left: 1px solid var(--ink); }
.stack-illiquid { background: rgba(33,30,23,.14); border-left: 1px solid var(--ink); }

/* 归因 · 双向条形(零轴居中,正右负左) */
.biv-row { display: grid; grid-template-columns: 1fr 150px 1fr; align-items: center; gap: 8px; margin-bottom: 7px; }
.biv-name { font-size: calc(12px * var(--fs-scale,1)); text-align: center; }
.biv-left { display: flex; justify-content: flex-end; align-items: center; }
.biv-right { display: flex; align-items: center; }
.biv-bar { height: 15px; min-width: 2px; }
.biv-pos { background: rgba(79,107,71,.55); }
.biv-neg { background: rgba(156,74,42,.5); }
.biv-amt { font-family: "JetBrains Mono", monospace; font-size: calc(10px * var(--fs-scale,1));
           padding: 0 5px; white-space: nowrap; }
@media (max-width: 560px) {
  .biv-row { grid-template-columns: 1fr 96px 1fr; gap: 5px; }
  .biv-name { font-size: calc(11px * var(--fs-scale,1)); }
  .zone-t { font-size: 1.1rem; }
}

/* v1.10 · 截断轴的柱底标记。
   瀑布用截断轴是必须的(月度流量与存量差两个数量级),但代价是存量柱的相对高度失真 ——
   实测 beta:期初柱 11% 高、期末柱 87% 高,而两者金额只差 45%,不加提示会被读成「涨了 8 倍」。
   所以轴被截断时在柱底压一道斜纹带(标准 broken-axis 标记),让人一眼知道柱子不是从 0 起。 */
/* v1.11.1 · 斜纹带必须贴在**轴线**(.wf 的底边)上,不能贴滚动容器的底边 ——
   X 轴标签(.wf-lab)是溢出 .wf 之外、落在容器下方的,贴容器底边会**把标签压掉一半**
   (维护者报「大量数字被遮蔽」)。所以改成 .wf::after,相对轴线定位。 */
/* v1.11.1(二改)· 斜纹带只画在**每根柱子内部的底部**,不横贯整宽。
   横贯版(贴 .wf 底边)会压住 X 轴标签 —— .wf-lab 是溢出 .wf 之外的,那条边正好穿过标签中间
   (维护者报「大量数字被遮蔽」,第一次修只解决了顶部标签被裁,这条才是主因)。
   柱底本来就是轴线,画在柱内语义完全一样,而且一个字都不碰。 */
.wf-truncated .wf-bar::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 5px;
  background: repeating-linear-gradient(115deg, rgba(244,239,230,.92) 0 3px, rgba(33,30,23,.28) 3px 4px);
  pointer-events: none;
}

/* v1.11.1 · 长文目录的二级条目(报表页三区之下的 9 个子节)。
   统一不编号 + 缩进表达层级 —— 给子节编号(四、五…)会让人以为它们和三个区是同级的。 */
.toc-node.toc-sub { padding-left: 1.15rem; }
.toc-node.toc-sub .lbl { font-size: 0.92em; color: var(--ink-subtle); }
.toc-node.toc-sub[aria-current="true"] .lbl { color: var(--ink); }

/* ===========================================================
   终端命令块(v1.17.1)· 需要用户【照着敲】的命令一律用它
   -----------------------------------------------------------
   以前每处各写各的:更新提示是浅色 <pre>、落地页是黑底 .cmd-block、
   向导页又是另一套内联样式 —— 同一件事(这是要你复制去跑的命令)长三个样,
   而且只有落地页那处能一键复制。统一成一个类 + 一个 fragment。
   =========================================================== */
.term-block{ position:relative; background:#1c1a17; border:1px solid #2a2622; border-radius:6px;
             padding:.85rem 1rem; overflow-x:auto; box-shadow:0 6px 18px -12px rgba(0,0,0,.55); }
/* 不用 <pre>:Thymeleaf 在 <pre> 里会把模板自身的缩进一起渲染出来。
   每行做成独立 block + pre-wrap,既没有多余缩进,长命令(digest)也能折行而不是横向滚动。 */
.term-block .t-code{ font-family:'JetBrains Mono',ui-monospace,monospace; font-size:12.5px;
                     line-height:1.85; color:#d8d2c6; display:block; }
.term-block .t-cmt{ color:#7d766a; }                 /* # 注释 */
/* 悬挂缩进:长命令(digest 那种)折行后,续行要缩进,否则看起来像另起一条命令 */
.term-block .t-line{ display:block; white-space:pre-wrap; word-break:break-all;
                     padding-left:1.5em; text-indent:-1.5em; }
/* 复制按钮浮在右上角,只让【第一行】给它让位 —— 整块留白会白白吃掉移动端本就不多的宽度 */
.term-block .t-line:first-child{ padding-right:3.8rem; }
.term-block .t-line::before{ content:'$ '; color:#8fae86; }   /* 提示符:一眼看出这是要敲的命令 */
.term-block .t-line.t-cmt::before{ content:'  '; }             /* 注释行不加 $,否则复制出来会以为要连 $ 一起敲 */
.term-block .t-copy{ position:absolute; top:.5rem; right:.5rem; font-family:'JetBrains Mono',monospace;
                     font-size:11px; color:#d8d2c6; background:#2a2622; border:1px solid #3a352f;
                     border-radius:4px; padding:.22rem .6rem; cursor:pointer; transition:background .15s,color .15s; }
.term-block .t-copy:hover{ background:var(--brass-deep); color:var(--paper); border-color:var(--brass-deep); }
.term-block .t-copy.ok{ background:var(--forest); color:#fff; border-color:var(--forest); }
@media(max-width:640px){ .term-block pre{ font-size:11.5px; } .term-block .t-copy{ font-size:10px; } }

/* ===========================================================
   凭据配置卡 + 状态标签(v1.17.2)
   -----------------------------------------------------------
   三家 AI 平台原来是三列裸 div,只靠间距分隔 —— 用户看不出"这是三个独立的东西";
   而「已配置 / 未配置」是一行灰色小字,混在 label 里,扫一眼根本分不清哪家配好了。
   =========================================================== */
.cred-card{ background:var(--card-soft); border:1px solid var(--rule-soft); border-radius:6px;
            padding:.9rem 1rem; display:flex; flex-direction:column; }
.cred-card.is-on{ border-color:rgba(79,107,71,.42); background:rgba(79,107,71,.045); }
.cred-card .cred-head{ display:flex; align-items:center; gap:.5rem; flex-wrap:wrap; margin-bottom:.55rem; }
.cred-card .cred-name{ font-weight:600; font-size:13.5px; color:var(--ink); }

/* 状态标签:配没配是这一页最该一眼看清的事,所以给底色 */
.state-tag{ display:inline-flex; align-items:center; gap:.28rem; font-family:'JetBrains Mono',monospace;
            font-size:10px; letter-spacing:.06em; padding:.14rem .5rem; border-radius:3px; white-space:nowrap; }
.state-tag.on{  color:#fff; background:var(--forest); }
.state-tag.off{ color:#fff; background:var(--rust); }
.state-tag svg{ width:11px; height:11px; }

/* 已配置时:掩码值(留头尾几位,方便有多把 key 的人确认当前是哪一把) */
.cred-mask{ font-family:'JetBrains Mono',monospace; font-size:11px; color:var(--ink-soft);
            background:var(--paper); border:1px solid var(--rule-soft); border-radius:4px;
            padding:.3rem .5rem; margin-bottom:.4rem; word-break:break-all; }

/* 卡片里的输入框:placeholder 用等宽小字,和上面那行掩码同一视觉层级 ——
   默认 field-input 的 placeholder 是正文 serif 大字号,和掩码并排时抢走全部注意力 */
.cred-card .field-input{ font-family:'JetBrains Mono',monospace; font-size:12px; }
.cred-card .field-input::placeholder{ font-family:'JetBrains Mono',monospace; font-size:11px; opacity:.75; }

/* 下拉里不可选的平台(还没配 key)*/
select option:disabled{ color:var(--ink-subtle); font-style:italic; }

/* ══════════════════════════════════════════════════════════════════════════
   v1.19 · 超级 Agent
   ──────────────────────────────────────────────────────────────────────────
   结构照 Claude / ChatGPT / Manus 已经收敛的那套规范,视觉仍是账房自己的:
   纸色底、铜色强调、eyebrow 字距。照搬中性灰白会让这一页像从别的产品抄来的 ——
   全站另外十几个页面都是这套语言,单独一页跳出来只会显得突兀。
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 列宽 ──
   768px 是 Claude / ChatGPT 收敛出来的值,对应约 65–72 个西文字符。
   中文更宽,15px 下一行约 40 字 —— 长回答读起来不至于串行。
   之前是 860px + 13.5px,一行奔 60 个汉字,那是文档排版不是对话排版。 */
:root{ --ask-col: 768px; }

.ask-main{ flex:1; min-height:0; width:100%; max-width:calc(var(--ask-col) + 5rem);
           margin:0 auto; display:flex; flex-direction:column; position:relative; z-index:10; }
.ask-shell{ flex:1; min-height:0; display:flex; flex-direction:column; overflow:hidden; }
.ask-panel{ flex:1; min-height:0; display:flex; flex-direction:column; }
.ask-col{ width:100%; max-width:var(--ask-col); margin:0 auto; }

@media (min-width:640px){
  .ask-main{ padding:1.5rem 1rem; }
  .ask-shell{ border:1px solid var(--rule); border-radius:12px; background:var(--paper); }
}

/* ── 顶栏 ── */
.ask-head{ display:flex; align-items:center; gap:.6rem; flex:none;
           padding:.7rem 1rem; border-bottom:1px solid var(--rule); }
.ask-head-brand{ flex:none; color:var(--ink); }
.ask-head-ctx{ flex:none; font-family:'JetBrains Mono',monospace; font-size:10.5px;
               color:var(--ink-subtle); border:1px solid var(--rule-soft);
               border-radius:3px; padding:.1rem .4rem; white-space:nowrap; }
.ask-head-title{ font-size:12.5px; color:var(--ink-soft); overflow:hidden;
                 text-overflow:ellipsis; white-space:nowrap; }
.ask-head-gap{ flex:1; }
/* 窄屏顶栏放不下「+ 新对话」四个字符,flex 会把它压成竖排 —— 只留图标 */
@media (max-width:520px){
  .ask-head{ gap:.45rem; padding:.6rem .8rem; }
  .ask-head .ask-mini{ font-size:0; padding:.3rem; }
  .ask-head .ask-mini svg{ width:15px; height:15px; }
  .ask-head-title{ display:none; }
}

/* ── 消息区 ── */
.ask-msgs{ flex:1; min-height:0; overflow-y:auto; padding:1.1rem 1rem .6rem; }
@media (max-width:520px){
  .ask-msgs{ padding:.9rem .85rem 0; }
  .ask-composer-wrap{ padding:.5rem .85rem .4rem; }
}

/* 用户消息:右对齐 + 一条细下划线,**不用气泡**。
   圆角实心气泡传递的是「随便聊聊」,和这一页要给的「可核对的账」相冲;
   而且 AI 那侧是扁平长文,一边气泡一边文档,自己跟自己打架。 */
.ask-me{ display:flex; justify-content:flex-end; margin:1.4rem 0 1.1rem; }
.ask-me > div{ max-width:82%; text-align:right; font-size:14.5px; line-height:1.7;
               color:var(--ink); white-space:pre-wrap;
               padding-bottom:.45rem; border-bottom:1.5px solid var(--brass); }
.ask-me:first-child{ margin-top:.2rem; }

/* 旁白:换账期 / 上游出错 / 已叫停。刻意弱 —— 它不是答案 */
.ask-note{ display:flex; justify-content:center; margin:1rem 0; }
.ask-note span{ font-size:11.5px; color:var(--ink-subtle); background:var(--card-soft);
                border:1px solid var(--rule-soft); border-radius:999px; padding:.2rem .7rem; }

.ask-turn{ margin-bottom:1.8rem; }

/* ── 工具执行:默认折叠 ──
   Manus 那条规矩:对话线程讲结论,自主执行过程另放。常驻平铺会和正文抢注意力,
   而多数时候用户并不关心它查了哪几个维度 —— 只在数字看着不对时才想看。 */
.ask-acts{ margin-bottom:.7rem; }
.ask-acts summary{ display:inline-flex; align-items:center; gap:.35rem; cursor:pointer;
                   list-style:none; font-size:11.5px; color:var(--ink-subtle);
                   padding:.15rem .5rem .15rem .3rem; border-radius:4px; user-select:none; }
.ask-acts summary::-webkit-details-marker{ display:none; }
.ask-acts summary:hover{ color:var(--ink-soft); background:var(--card-soft); }
.ask-caret{ display:inline-block; transition:transform .15s; font-size:9px; }
.ask-acts[open] .ask-caret{ transform:rotate(90deg); }
.ask-acts-body{ margin:.35rem 0 0 .55rem; padding-left:.7rem;
                border-left:1px solid var(--rule-soft); }
.ask-act{ display:flex; align-items:center; gap:.45rem; font-size:11.5px;
          color:var(--ink-subtle); line-height:1.9; }
.ask-act-ms{ font-family:'JetBrains Mono',monospace; font-size:10px; color:var(--ink-faint); }
.ask-dot{ width:5px; height:5px; border-radius:50%; background:var(--brass); flex:none; }
.ask-dot.bad{ background:var(--rust); }
.ask-dot.run{ animation:ask-pulse 1.1s ease-in-out infinite; }
@keyframes ask-pulse{ 0%,100%{opacity:.28} 50%{opacity:1} }

/* 排队中:脉冲点 + 一句话。**不给假进度条** —— 没有进度可报,画一个是骗人 */
.ask-wait{ display:inline-flex; align-items:center; gap:.45rem;
           font-size:12.5px; color:var(--ink-soft); }
.ask-wait::before{ content:''; width:6px; height:6px; border-radius:50%;
                   background:var(--brass); animation:ask-pulse 1.1s ease-in-out infinite; }

/* ── 正文 ── */
.ask-body{ font-size:15px; line-height:1.78; color:var(--ink); }
.ask-body p{ margin:.55rem 0; }
.ask-body p:first-child{ margin-top:0; }
.ask-body strong{ font-weight:600; }
/* 模型很爱用 "- xxx" 列条目。不认它的话每条会变成一个独立段落 ——
   段间距 .55rem 让三条列表撑得像三段话,而且行首那个裸的短横线很难看。 */
.ask-body ul{ margin:.5rem 0; padding-left:1.05rem; list-style:none; }
.ask-body li{ position:relative; margin:.22rem 0; line-height:1.75; }
.ask-body li::before{ content:''; position:absolute; left:-.85rem; top:.72em;
                      width:4px; height:4px; border-radius:50%; background:var(--brass); }

/* 流式光标:没有它,模型思考的停顿会被读成「已经结束了」。
   Claude 用小方块、ChatGPT 用脉冲点 —— 这里取方块,和等宽数字的调性一致。 */
.ask-caret-live{ display:inline-block; width:.5em; height:1.05em; margin-left:1px;
                 background:var(--ink); vertical-align:-.16em;
                 animation:ask-blink 1s step-end infinite; }
@keyframes ask-blink{ 0%,49%{opacity:1} 50%,100%{opacity:0} }

/* ── 引用卡 ──
   这一版最重要的视觉件。四样缺一不可:指标名、数值、账期与关账状态、点回原页。
   缺任何一样,数字就退回成「一个说不清出处的裸数字」—— 而那正是 v1.18 一整个系列在修的病。 */
/* 连排四张时整体重量偏大,所以内距和行距都收过一轮:
   卡片本身要显眼(它是「这个数有出处」的凭证),但四张叠起来不该盖过正文。 */
.ask-cite{ display:block; margin:.5rem 0; padding:.5rem .7rem; text-decoration:none;
           border:1px solid var(--rule); border-left:2px solid var(--brass);
           border-radius:5px; background:var(--card-soft);
           transition:border-color .15s, background .15s; }
.ask-cite:hover{ border-color:var(--brass); background:var(--card); }
.ask-cite-top{ display:flex; align-items:baseline; justify-content:space-between; gap:.75rem; }
.ask-cite-k{ font-size:12px; color:var(--ink-soft); letter-spacing:.02em; }
.ask-cite-v{ font-family:'JetBrains Mono',monospace; font-size:15px; color:var(--ink);
             font-weight:600; white-space:nowrap; }
.ask-cite-meta{ display:flex; align-items:baseline; justify-content:space-between;
                gap:.75rem; margin-top:.2rem; }
/* 同一组里后面几张贴紧一点 —— 它们是一个整体,不是四件独立的事 */
.ask-cite + .ask-cite{ margin-top:.3rem; }
.ask-cite-per{ font-family:'JetBrains Mono',monospace; font-size:9.5px;
               color:var(--ink-faint); white-space:nowrap; }
.ask-cite-go{ font-size:10px; color:var(--ink-faint); text-align:right; }

/* 行内引用:模型没把标记单独成行时的退路,不至于句子中间插一张卡 */
.ask-chip{ display:inline-flex; align-items:baseline; gap:.25rem; padding:.05rem .3rem;
           margin:0 .1rem; border-bottom:1px solid var(--brass); text-decoration:none;
           font-family:'JetBrains Mono',monospace; font-size:13.5px; color:var(--ink); }
.ask-chip i{ font-style:normal; font-size:9.5px; color:var(--ink-subtle); }

/* ── 追问 chip · FR-424b ──
   点一下就等于把那句话问出来。放在操作行**上面**:它是「接下来做什么」,
   比「复制/重来」更该被先看到。 */
.ask-nexts{ display:flex; flex-wrap:wrap; gap:.4rem; margin-top:.9rem; }
.ask-next{ font-size:12.5px; color:var(--ink); background:var(--paper);
           border:1px solid var(--rule); border-radius:999px; padding:.28rem .7rem;
           cursor:pointer; transition:border-color .15s, background .15s; }
.ask-next:hover{ border-color:var(--brass); background:var(--card-soft); }

/* ── 逐条操作 ──
   桌面上 hover 才浮现(不打扰阅读),手机上常驻(没有 hover 这回事)。 */
.ask-tools-row{ display:flex; gap:.15rem; margin-top:.55rem; margin-left:-.3rem;
                opacity:0; transition:opacity .15s; }
.ask-turn:hover .ask-tools-row, .ask-tools-row:focus-within{ opacity:1; }
@media (hover:none){ .ask-tools-row{ opacity:1; } }

.ask-mini{ display:inline-flex; align-items:center; gap:.28rem; font-size:11.5px;
           color:var(--ink-subtle); background:transparent; border:0; cursor:pointer;
           padding:.2rem .45rem; border-radius:4px; transition:color .15s, background .15s; }
.ask-mini:hover{ color:var(--ink); background:var(--card-soft); }
.ask-mini svg{ width:13px; height:13px; fill:none; stroke:currentColor; stroke-width:1.7;
               stroke-linecap:round; stroke-linejoin:round; }
.ask-mini.ok{ color:var(--forest); }

.ask-icon{ width:26px; height:26px; flex:none; display:inline-flex; align-items:center;
           justify-content:center; border:0; background:transparent; cursor:pointer;
           color:var(--ink-subtle); border-radius:5px; }
.ask-icon:hover{ color:var(--ink); background:var(--card-soft); }
.ask-icon svg{ width:15px; height:15px; fill:none; stroke:currentColor; stroke-width:1.7;
               stroke-linecap:round; stroke-linejoin:round; }

/* ── 空态:输入优先 ──
   Notion AI / Linear AI 那套:一句话 + 几条可点的问题,不上来就摊开历史。
   「空聊天窗」对非技术家庭成员是有压力的 —— 他不知道该问什么。 */
.ask-empty{ padding:2.2rem 0 1rem; }
.ask-empty-eyebrow{ color:var(--ink-soft); margin-bottom:.6rem; }
.ask-empty-lead{ font-family:'Noto Serif SC',serif; font-size:22px; color:var(--ink);
                 margin:0 0 .35rem; }
.ask-empty-sub{ font-size:13.5px; color:var(--ink-soft); line-height:1.7;
                margin:0 0 1.3rem; max-width:34em; }   /* 34em ≈ 30 个汉字:42ch 只放得下 21 个,末行会剩「页核对。」四个孤字 */
/* 窄屏不限宽:42ch 在 390px 上会把「页核对。」挤成孤零零的第二行 */
@media (max-width:520px){ .ask-empty-sub{ max-width:none; } }
.ask-presets{ display:flex; flex-direction:column; gap:.5rem; align-items:flex-start; }
.ask-preset{ text-align:left; font-size:13.5px; color:var(--ink); background:var(--paper);
             border:1px solid var(--rule); border-radius:8px; padding:.5rem .8rem;
             cursor:pointer; max-width:100%;
             transition:border-color .15s, background .15s, transform .15s; }
.ask-preset:hover{ border-color:var(--brass); background:var(--card-soft); transform:translateX(2px); }

.ask-recent{ margin-top:2rem; padding-top:1.2rem; border-top:1px solid var(--rule-soft); }
.ask-recent .eyebrow{ color:var(--ink-subtle); margin-bottom:.5rem; }
.ask-recent-list{ display:flex; flex-wrap:wrap; gap:.35rem; }
.ask-recent-list a{ font-size:12px; color:var(--ink-soft); text-decoration:none;
                    border:1px solid var(--rule); border-radius:999px; padding:.2rem .6rem;
                    max-width:15rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ask-recent-list a:hover{ border-color:var(--brass); color:var(--ink); }

/* ── 未启用 ── */
.ask-blocked{ display:flex; align-items:flex-start; gap:.6rem; margin:1rem;
              padding:.9rem 1rem; border:1px solid var(--rule); border-radius:8px;
              background:var(--card-soft); font-size:13px; line-height:1.7;
              color:var(--ink-soft); }
.ask-blocked svg{ flex:none; margin-top:.25rem; }
.ask-blocked a{ display:inline-block; margin-top:.4rem; color:var(--ink); }

/* ── 输入区 ──
   **必须贴底、不能浮动** —— 盖住最后一条消息是这类界面最常见的手机端 bug。 */
.ask-composer-wrap{ flex:none; border-top:1px solid var(--rule); padding:.6rem 1rem .5rem;
                    background:var(--paper); }
.ask-composer-wrap.is-off{ opacity:.5; pointer-events:none; }
.ask-composer{ display:flex; align-items:flex-end; gap:.5rem;
               border:1px solid var(--rule); border-radius:10px;
               padding:.35rem .35rem .35rem .7rem; background:var(--paper);
               transition:border-color .15s; }
.ask-composer:focus-within{ border-color:var(--brass); }
.ask-composer textarea{ flex:1; resize:none; background:transparent; border:0; outline:none;
                        font-size:14.5px; line-height:1.65; color:var(--ink);
                        padding:.4rem 0; max-height:7rem; font-family:inherit; }
.ask-composer textarea::placeholder{ color:var(--ink-subtle); }
.ask-composer button{ flex:none; width:32px; height:32px; border-radius:8px; border:0;
                      display:inline-flex; align-items:center; justify-content:center;
                      background:var(--ink); color:var(--paper); cursor:pointer;
                      transition:opacity .15s; }
.ask-composer button:disabled{ opacity:.35; cursor:default; }
/* 属性选择器必须写在 display 规则之后,否则 [hidden] 的 display:none 被 inline-flex 盖掉 ——
   实测:停止键和发送键并排出现在输入框右边,一黑一红。 */
.ask-composer button[hidden]{ display:none; }
.ask-composer button svg{ width:16px; height:16px; fill:none; stroke:currentColor;
                          stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round; }
/* 停止键用 rust:它是「中断」,不该和「发送」同色让人误点 */
.ask-composer button[data-ask-stop]{ background:var(--rust); }
.ask-composer button[data-ask-stop] svg{ fill:currentColor; stroke:none; }

.ask-foot{ display:flex; flex-wrap:wrap; align-items:center; gap:.3rem;
           font-size:10.5px; color:var(--ink-subtle); padding:.4rem .2rem .1rem; }
.ask-foot-sep{ opacity:.5; }

/* ── PC 抽屉 ──
   不打断当前页:用户正在看仪表盘时问「这个数怎么来的」,底下那页得留在原地。 */
/* text-align:left 是必须的:抽屉挂在 layout::footer 里,而那个 footer 带 text-center,
   不显式覆盖的话空态标题、说明、「最近」全部继承成居中,和左对齐的按钮列拧着。 */
.ask-drawer{ text-align:left;
             position:fixed; top:0; right:0; bottom:0; width:min(460px,94vw); z-index:45;
             background:var(--paper); border-left:1px solid var(--rule);
             box-shadow:-14px 0 40px rgba(26,23,20,.10);
             transform:translateX(100%); transition:transform .22s ease;
             display:flex; flex-direction:column; }
.ask-drawer.open{ transform:translateX(0); }
.ask-drawer > *{ min-height:0; }
/* 抽屉里列宽由容器决定,不再受 768 限制(它本来就只有 460) */
.ask-drawer .ask-col{ max-width:none; }
.ask-drawer .ask-msgs{ padding-left:.9rem; padding-right:.9rem; }
.ask-drawer .ask-body{ font-size:14px; }

/* 悬浮入口:常驻但不打扰 —— 不主动弹、不推送,只是一直在那儿 */
.ask-fab{ position:fixed; right:20px; bottom:22px; z-index:44; display:inline-flex;
          align-items:center; gap:.4rem; padding:.55rem .85rem; border-radius:999px;
          border:1px solid var(--rule); background:var(--paper); color:var(--ink);
          box-shadow:0 3px 14px rgba(26,23,20,.12); font-size:12.5px; letter-spacing:.06em;
          cursor:pointer; transition:border-color .15s, box-shadow .15s; }
.ask-fab:hover{ border-color:var(--brass); box-shadow:0 5px 20px rgba(26,23,20,.16); }
html.ask-open .ask-fab{ opacity:0; pointer-events:none; }
body.ask-page .ask-fab{ display:none; }

/* 全局浮钮 dock(隐私眼 / 横屏 / 目录)在这一页**藏掉**,隐私切换收进顶栏。
   过程值得记,因为「挪个位置」这个直觉是错的 —— 挪到哪儿都挡:
     · 原位右下 → 压住发送键,而输入框是这一页的主操作;
     · 抬高 96px → 压住引用卡右侧的金额(实测挡掉了「¥1,234,568」的后三位);
     · 再挪到左侧 → 压住引用卡左侧的指标名。
   根因是这一页**内容铺满、左右都有要读的东西**(左指标名、右数值),
   而 position:fixed 的浮层不给内容让位。所以不是找位置,是不该用浮层:
   隐私钮进顶栏(那里本来就有空位),目录钮这一页没有,横屏钮让位。 */
body.ask-page #float-dock{ display:none !important; }

/* 顶栏里的隐私切换 —— 只在触摸设备上出现,和被藏掉的 dock 是同一个条件。
   PC 的导航栏本来就有隐私钮,这里再放一个是重复。 */
.ask-priv{ display:none; }
@media (pointer:coarse){ .ask-priv{ display:inline-flex; } }
html.privacy .ask-priv{ color:var(--ink); background:var(--card-soft); }
/* 手机上不要悬浮球:屏幕小,它会压住底部的表格和按钮。移动端走导航里的整页入口 */
@media (max-width:767px){ .ask-fab{ display:none; } }

/* 隐私模式:只糊**金额**,不糊百分比/月数/条数。
   一刀切的后果实测很难看:饼图上的百分比清清楚楚,正文里同一批百分比却是糊的。
   金额型的值在渲染时挂了 data-priv,直接吃全站那条规则(顺带白得「长按临时查看」)。
   图表 canvas 没法局部糊,所以整块判断:datalabels 里有金额的那些图整张糊。 */
html.privacy .ask-chart[data-priv-chart] canvas{ filter:blur(6px); }

/* 减少动效:光标与脉冲都停掉,但**不隐藏光标** —— 它承载「还在生成」这个信息 */
@media (prefers-reduced-motion:reduce){
  .ask-caret-live, .ask-dot.run, .ask-wait::before{ animation:none; }
}

/* ── 思考过程 · 流式进行中 ────────────────────────────────────────────────
   与历史里那份**同一套 DOM**,只是多一个 .live 态。
   进行中默认展开:用户想看的正是「它在查什么」;跑完了再自动收起 ——
   除非他中途做了查看动作(翻页 / 点击 / 选中 / 停在这一栏上),那说明他在读,
   收起就是把他正在看的东西抢走。 */
.ask-acts.live{ border-left:2px solid var(--brass-soft); padding-left:.6rem; margin-left:-.1rem; }
.ask-acts.live > summary{ color:var(--ink-soft); }
.ask-acts.live .ask-acts-body{ border-left:0; padding-left:0; margin-left:0; }
/* 自动收起时闪一下,让用户知道「它收起来了、还能点开」 */
@keyframes ask-fold{ 0%{ background:var(--brass-soft) } 100%{ background:transparent } }
.ask-acts.folded > summary{ animation:ask-fold 1.1s ease-out; border-radius:4px; }

.ask-act{ padding:.18rem 0; }
.ask-act-head{ display:flex; align-items:center; gap:.45rem; font-size:11.5px; color:var(--ink-soft); }
.ask-act-name{ color:var(--ink-soft); }
.ask-act-args{ margin-left:.95rem; font-family:'JetBrains Mono',monospace; font-size:10px;
               color:var(--ink-faint); line-height:1.6; word-break:break-all; }
.ask-act-sum{ margin-left:.95rem; font-size:11px; color:var(--ink-subtle); line-height:1.6; }
/* 思考里的旁白(模型调工具前说的那句)—— 是句子,不是键值,所以不用等宽 */
.ask-act-say{ margin:.25rem 0 .35rem .95rem; font-size:11.5px; color:var(--ink-subtle);
              line-height:1.7; }

/* ── 富展示:图表与自由 HTML ──────────────────────────────────────────────
   模型能自由发挥的是**形式**,不是数据 —— 图上每个点都来自工具返回的引用值。
   所以这两样在版面上比引用卡轻:引用卡是「凭证」,图是「看个形状」。 */
.ask-chart{ margin:.9rem 0; padding:.7rem .8rem .5rem;
            border:1px solid var(--rule); border-radius:6px; background:var(--card-soft); }
.ask-chart-title{ font-size:12px; color:var(--ink-soft); margin-bottom:.5rem; letter-spacing:.02em; }
.ask-chart-canvas{ position:relative; height:210px; }
@media (max-width:520px){ .ask-chart-canvas{ height:190px; } }

.ask-artifact{ margin:.9rem 0; padding:0; border:1px solid var(--rule); border-radius:6px;
               background:var(--card-soft); overflow:hidden; }
.ask-artifact iframe{ display:block; width:100%; height:180px; border:0; background:transparent;
                      transition:height .18s ease; }
.ask-artifact figcaption{ font-size:10.5px; color:var(--ink-subtle);
                          padding:.3rem .7rem .45rem; border-top:1px solid var(--rule-soft); }
/* 隐私模式:自由 HTML 里的数字我们管不着(它在 iframe 里),整块糊掉最保险 */
html.privacy .ask-artifact iframe{ filter:blur(6px); }

/* ── 「AI 接入」· 百炼托管路线的分步向导 ──────────────────────────────────
   这一段以前只有三个空输入框,而其中两项要去阿里云控制台里翻才拿得到 ——
   「业务空间 ID」这种词对着一个空输入框是问不出来的。
   所以做成分步:谁做哪一步一眼看清,人工那几步各配一段可展开的实操说明
   (默认收起 —— 配过一次的人不需要再看第二遍)。 */
.ask-setup{ border-top:1px solid var(--rule); padding-top:.7rem; }
.ask-setup > summary{ cursor:pointer; font-size:12px; color:var(--ink-soft);
                      list-style:none; user-select:none; padding:.2rem 0; }
.ask-setup > summary::-webkit-details-marker{ display:none; }
.ask-setup > summary::before{ content:'▸'; display:inline-block; font-size:9px;
                              margin-right:.35rem; transition:transform .15s; }
.ask-setup[open] > summary::before{ transform:rotate(90deg); }
.ask-setup > summary:hover{ color:var(--ink); }

.ask-steps{ list-style:none; margin:.9rem 0 0; padding:0; counter-reset:askstep; }
.ask-steps > li{ display:flex; gap:.6rem; padding:.55rem 0;
                 border-top:1px solid var(--rule-soft); counter-increment:askstep; }
.ask-steps > li::before{ content:counter(askstep, decimal); flex:none;
                         width:1.35rem; height:1.35rem; line-height:1.3rem; text-align:center;
                         margin-top:.1rem; border:1px solid var(--rule);
                         border-radius:50%; font-family:'JetBrains Mono',monospace;
                         font-size:10px; color:var(--ink-soft); background:var(--paper); }
.ask-steps > li:first-child{ border-top:0; }
.ask-steps > li > div{ flex:1; min-width:0; }
.ask-steps b{ font-size:13px; color:var(--ink); }
.ask-steps p{ font-size:12px; color:var(--ink-soft); line-height:1.75; margin:.25rem 0 0; }
.ask-steps code{ font-family:'JetBrains Mono',monospace; font-size:11px;
                 background:var(--paper-soft); border:1px solid var(--rule-soft);
                 border-radius:3px; padding:0 .25rem; }

/* 「谁做这一步」—— 分步向导里最该一眼看清的一列:
   用户最怕的不是步骤多,是分不清哪几步要他自己动手 */
.ask-step-who{ flex:none; width:2.4rem; text-align:center; height:1.35rem; line-height:1.35rem;
               font-family:'JetBrains Mono',monospace; font-size:9.5px; letter-spacing:.04em;
               border-radius:3px; color:#fff; background:var(--brass-deep); margin-top:.1rem; }
.ask-step-who.ours{ background:var(--ink-subtle); }

/* 实操说明:默认收起 */
.ask-how{ margin-top:.5rem; }
.ask-how > summary{ display:inline-block; cursor:pointer; list-style:none; user-select:none;
                    font-size:11.5px; color:var(--brass-deep);
                    border-bottom:1px dashed var(--brass); padding-bottom:1px; }
.ask-how > summary::-webkit-details-marker{ display:none; }
.ask-how > summary:hover{ color:var(--ink); border-color:var(--ink-soft); }
.ask-how ol{ margin:.5rem 0 0; padding-left:1.15rem; }
.ask-how li{ font-size:12px; color:var(--ink-soft); line-height:1.8; margin:.2rem 0; }
.ask-how pre{ font-family:'JetBrains Mono',monospace; font-size:11px; line-height:1.6;
              background:var(--paper-soft); border:1px solid var(--rule-soft); border-radius:4px;
              padding:.5rem .6rem; margin:.4rem 0; overflow-x:auto; color:var(--ink-soft); }
.ask-how-note{ margin-top:.5rem !important; padding:.5rem .65rem; border-radius:4px;
               background:var(--card-soft); border-left:2px solid var(--brass);
               font-size:11.5px !important; line-height:1.8 !important; }
.ask-how-note a, .ask-steps a{ color:var(--ink); }

/* 诚实交代:这条路线我们没在真实环境验过。放在输入框**上面** ——
   放下面等于让人填完了才知道 */
.ask-caveat{ margin-top:.9rem; padding:.6rem .75rem; border-left:2px solid var(--rust);
             background:var(--rust-soft, rgba(164,85,47,.05));
             font-size:12px; line-height:1.8; color:var(--ink-soft); }
/* 「万一表单长得不一样」那类补充:比正文更弱,别和主步骤抢 */
.ask-how li.ask-how-alt{ color:var(--ink-subtle); font-size:11.5px; }

/* v1.19.7 · 接入方式的岔路口:百炼在这一步给四个选项,选错了后面全对不上
   (用户实测选了「插件」,被要求逐个填工具描述才发现走错了)。
   做成表格是因为**要对比**——只说「选 X」不够,得让人看见另外三个为什么不是。 */
.ask-how-lead{ margin:.1rem 0 .55rem !important; font-size:12px !important;
               line-height:1.8 !important; color:var(--ink-soft); }
.ask-how-tbl{ width:100%; border-collapse:collapse; margin:.1rem 0 .7rem;
              font-size:11.5px; line-height:1.75; }
.ask-how-tbl td{ border-top:1px solid var(--rule-soft); padding:.4rem .5rem .4rem 0;
                 color:var(--ink-subtle); vertical-align:top; }
.ask-how-tbl td:first-child{ width:11.5rem; color:var(--ink-soft); padding-right:.9rem; white-space:nowrap; }
.ask-how-tbl tr:first-child td{ border-top:0; color:var(--ink-soft); }
.ask-how-tbl tr:first-child td:first-child{ color:var(--brass-deep); }
@media (max-width:640px){
  /* 窄屏两列会挤成一条线,改成上下堆叠 */
  .ask-how-tbl td{ display:block; padding:.15rem 0; border-top:0; }
  .ask-how-tbl td:first-child{ width:auto; padding-top:.5rem; border-top:1px solid var(--rule-soft); }
  .ask-how-tbl tr:first-child td:first-child{ border-top:0; }
}
/* 出处行:比 note 再弱一档,它是给想自己核对的人看的 */
.ask-how-src{ border-left-color:var(--rule) !important; color:var(--ink-subtle); }

/* ═══ v1.20 · 账户组:组行与成员行的层级 ═══
   展开之后如果两者长得一样,用户看不出「这 5 行是属于上面那一行的」——
   而这正是分组唯一想表达的关系。所以成员行给一条左引导线 + 略淡的底,
   组行加粗;不是装饰,是把从属关系画出来。 */
tr.acct-member > td:first-child,
details.acct-member { border-left: 2px solid var(--brass-deep); }
tr.acct-member { background: rgba(167, 123, 53, .035); }
tr.acct-member > td { padding-left: .35rem; }
.acct-toggle { font-weight: 500; }

/* 组行:与成员区连成一块,靠上边一条实线把它和上一个无关账户隔开 */
tr:has(> td .acct-toggle) { border-top: 1px solid var(--rule); }
tr:has(> td .acct-toggle) > td { font-weight: 500; }

/* 弹窗要有遮罩 —— 没有遮罩的模态读起来像「卡住的面板」,而不是「需要先处理的东西」 */
dialog::backdrop { background: rgba(26, 23, 20, .38); }

/* ═══ v1.21 · 支出分类宫格 ═══
   为什么用 CSS 类而不是 Tailwind 原子类堆在模板上:这套外观有【三个状态】
   (常态 / hover / 选中),而选中态是 JS 加 .on 切的 —— 写在模板里就得把
   同一组颜色在 JS 里再写一遍,两处必然漂移。

   【所有格子同尺寸】是硬规则(memory feedback_sibling_uniform_selfcheck):
   消费分类与性质项共用 .cat-cell,--nature 只改颜色不改大小。
   第一版性质项用了小一圈的 .cat-chip,两排并列高矮不齐,用户一眼指出来。 */
.cat-row {
  display: grid;
  /* 固定列宽而不是 auto-fit:auto-fit 会让「只有 3 个性质项」那一排的格子
     被拉成大类那排的 3 倍宽 —— 同样是「并列同类元素不同尺寸」。 */
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 7px;
}
@media (max-width: 640px) {
  .cat-row { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); }
}

.cat-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  /* 定高:名字有两字的也有五字的,不定高会让同一排参差不齐 */
  min-height: 68px;
  padding: 10px 6px;
  border: 1px solid var(--rule);
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  text-align: center;
  line-height: 1.15;
  transition: background .12s, border-color .12s, color .12s;
}
.cat-cell:hover { background: var(--card-soft); border-color: var(--brass-deep); }
.cat-cell.on { background: var(--ink); border-color: var(--ink); color: var(--paper); }

/* stroke=currentColor → 选中反色时图标自动跟着变白,不需要第二套样式 */
.cat-cell svg { width: 19px; height: 19px; flex: 0 0 19px; opacity: .78; }
.cat-cell.on svg { opacity: 1; }

.cat-name { font-size: 12px; letter-spacing: .01em; }
.cat-more { color: var(--ink-subtle); font-size: 11px; margin-left: 1px; }
.cat-cell.on .cat-more { color: var(--paper); opacity: .65; }

/* 性质项:同尺寸,靠底色与虚线边区分「这不是消费分类」 */
.cat-cell--nature {
  background: transparent;
  border-style: dashed;
  color: var(--ink-soft);
}
.cat-cell--nature:hover { background: var(--card-soft); }
.cat-cell--nature.on {
  background: var(--rust);
  border-color: var(--rust);
  border-style: solid;
  color: var(--paper);
}

/* 细类 chip —— 它是【二级选择】,和一级格子不是并列关系,小一圈是对的 */
.cat-chip {
  font-size: 11.5px;
  border: 1px solid var(--rule);
  padding: 5px 12px;
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.cat-chip:hover { border-color: var(--brass-deep); }
.cat-chip.on { background: var(--brass-deep); color: var(--paper); border-color: var(--brass-deep); }

/* ═══ v1.21 · [hidden] 必须真的藏住 ═══
   HTML 的 hidden 属性靠 UA 样式表的 `[hidden]{display:none}` 生效,
   而那条规则的优先级比任何 class 都低 —— 元素上只要有 Tailwind 的
   `flex` / `block` / `grid`,hidden 就【完全失效】,元素照常显示。
   实测:分类宫格的细类条 <div hidden class="flex ..."> 在没选中任何大类时也露出来了
   (双端截图抓到)。用 !important 把它焊死,免得每处都要记得改成 style="display:none"。 */
[hidden] { display: none !important; }

/* ═══ v1.21 · 流水列表的搜索 + 分页工具条 ═══
   行数少于阈值时整条不出现(JS 控制 hidden),所以这里不用考虑「空态好不好看」。 */
.flow-bar {
  /* v1.21.2 · 从单行改成两行容器(第 1 行搜索+分页,第 2 行筛选器),
     所以这里是 column;行内的横向排布交给 .flow-bar-line。 */
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  margin-top: 12px;
  padding: 7px 10px;
  border: 1px solid var(--rule);
  background: var(--card-soft);
}
.flow-q {
  flex: 1 1 220px;
  min-width: 180px;
  height: 30px;
  padding: 0 10px;
  border: 1px solid var(--rule);
  background: var(--paper);
  font-size: 12px;
  color: var(--ink);
}
.flow-q::placeholder { color: var(--ink-subtle); font-size: 11px; }
.flow-count { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--ink-soft); white-space: nowrap; }
.flow-pager { display: flex; align-items: center; gap: 6px; }
.flow-pgnum { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--ink-soft); min-width: 4.2em; text-align: center; }
.flow-pg {
  width: 28px; height: 28px;
  border: 1px solid var(--rule);
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  font-size: 12px;
  line-height: 1;
}
.flow-pg:hover:not(:disabled) { border-color: var(--brass-deep); }
.flow-pg:disabled { opacity: .35; cursor: default; }

/* ═══ v1.21 · 导入确认页的分桶页签 ═══
   三个桶尺寸一致(并列同类元素),只用底色和边框区分选中。 */
.bkt {
  /* 固定宽度而不是 min-width:五个桶并排,min-width 会让文案长的那个撑宽一点点
     ——「要导入 125px / 已剔除 118px」,看着就是没对齐。并列同类元素必须同尺寸。 */
  width: 128px;
  padding: 9px 13px;
  border: 1px solid var(--rule);
  background: var(--paper);
  text-align: left;
  cursor: pointer;
  transition: border-color .12s, background .12s;
}
.bkt:hover { border-color: var(--brass-deep); }
.bkt.on { border-color: var(--brass-deep); background: rgba(160,124,58,.08); }
.bkt:not(.on) { opacity: .72; }

/* ═══ v1.21.2 · 流水工具条:两行(搜索/分页 + 筛选器) ═══ */
.flow-bar-line { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; width: 100%; }
.flow-filters { margin-top: 7px; padding-top: 7px; border-top: 1px dashed var(--rule-soft); }
/* 并列的筛选器必须同宽 —— min-width 下「全部类目」会比「全部分类」宽一点点,
   四个摆一排就是参差不齐。每页条数那个窄一些(它不是同一类元素)。 */
.flow-filters .lsel { width: 132px; }
.flow-pager .lsel { width: 94px; }
.flow-f, .flow-size {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  padding: 3px 6px;
  border: 1px solid var(--rule);
  background: var(--paper);
  color: var(--ink-soft);
}
.flow-clear {
  font-family: 'JetBrains Mono', monospace; font-size: 11px;
  padding: 3px 8px; border: 1px solid var(--rule); background: transparent;
  color: var(--ink-subtle); cursor: pointer;
}
.flow-clear:hover { border-color: var(--rust); color: var(--rust); }


/* 窄屏:搜索框独占一行 —— 和「共 N 笔」挤在一行时它只剩 200px 出头,
   放不下「搜商户 / 备注 / 类目 …」那句提示,用户不知道能搜什么。 */
@media (max-width: 640px) {
  .flow-bar-line .flow-q { flex: 1 1 100%; min-width: 0; }
  .flow-filters .lsel, .flow-pager .lsel { width: 46%; }
  .flow-pager { width: 100%; }
}

/* ═══ v1.22 · 导入确认页的逐笔表在窄屏下的行为 ═══
   这张表有 7 列(勾 / 日期 / 商户 / 金额 / 分类 / 账户 / 依据),390px 下按比例压缩的话
   每一列都只剩几十 px —— 商户名会被压成【一个字一行】的竖排,整张表没法读。
   (v1.21 就是这个结构,只是当时拍到的那一屏恰好没有表格内容,没暴露出来。)

   做法是【横向滚动 + 每列保底宽度】而不是重排成卡片:
   这一页的动作是「逐行核对并改分类/账户」,列与列的对齐关系本身就是信息;
   拆成卡片之后「同一列的值上下对比」这件事就没了,而那正是核对时最常做的。 */
.imp-scroll { overflow: auto; }
.imp-scroll > table { min-width: 760px; }

/* 【基础规则必须写在 media query 之前】—— 同特异性下后定义的赢,
   把 display:none 放在后面会把 media query 里的 display:block 盖掉,
   于是提示永远不出现(而 CSS 不会报错,只能靠真机截图发现)。 */
.imp-hint { display: none; font-family: 'JetBrains Mono', monospace; font-size: 10px;
            color: var(--ink-subtle); padding: 5px 10px 0; }

@media (max-width: 640px) {
  /* 提示一下可以横滑 —— 否则用户看到右边被切掉会以为坏了 */
  .imp-scroll { position: relative; -webkit-overflow-scrolling: touch; }
  .imp-hint { display: block; }
}

/* ═══════════════════════════════════════════════════════════════════
   v1.22.1 · 手机端(≤640px)排版收口
   ═══════════════════════════════════════════════════════════════════

   全站的 tag / pill / 按钮尺寸原本只按 PC 调过,搬到 390px 上之后:
   一行塞不下 → 换行 → 核心信息(账户名)被 truncate 掉,而次要的状态标签
   反倒因为带边框而视觉权重最高。这一段只改【尺寸与排布】,不动任何取数与计算。

   三条原则:
   ① 标签类元素大幅缩小 —— 中文 pill 不需要 0.1em 字距和 uppercase
   ② 核心元素(账户名 / 金额)优先占位,永远不阉割
   ③ 复杂行谨慎换行 —— 该换的(次要信息)强制换,不该换的(金额)锁在同一行
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

  /* ── ① 标签类:字距归零 + 收紧 padding ──
     中文本来就有字身间距,再加 0.1em letter-spacing 只是白白变宽。
     uppercase 对中文无效,但会让夹在里面的英文/数字变高。 */
  /* v1.35 · 标签手机端 10px(原 8.5px 太小);字距大写在全局已去掉 */
  .pill, .pill[class] { font-size: calc(10px * var(--fs-scale, 1)); padding: 1px 6px; gap: 3px; }
  .badge { font-size: calc(8.5px * var(--fs-scale, 1)); padding: 1px 5px; letter-spacing: 0.02em; }

  /* ── ② 填报页流水行:手机端走 flex,不走 grid ──
     原来是 grid-cols-[auto_auto_1fr_auto](4 列),而有消费分类时这一行有
     【5 个】元素(头像 / 性质 / 分类 / 账户名 / 金额)—— 第 5 个自动落到下一行,
     于是金额孤零零掉在左下角,和账户名断开。这不是宽度问题,是列数不够。
     改成 flex 之后元素按需排,账户名 flex:1 优先吃掉剩余宽度。 */
  /* 【必须排除 [hidden]】—— 全局有一条 [hidden]{display:none!important},
     而这里也是 !important、又写在文件更后面,同特异性下后者赢:
     不加 :not([hidden]) 的话,前端分页藏起来的那几百行会被这条规则重新放出来,
     列表一下子变成十几屏,而且被隐藏行的布局是塌的(账户名宽度只剩 2px)。 */
  [data-flow-row]:not([hidden]) {
    display: flex !important;
    flex-wrap: wrap;
    align-items: center;
    gap: 5px;
  }
  /* 账户名是这一行的主语,不能被 tag 挤没 */
  [data-flow-row]:not([hidden]) > .flow-acct { flex: 1 1 auto; min-width: 4.5em; font-size: 13px; }
  /* 金额锁在第一行末尾 —— 它和账户名是一对,断开之后这一行就读不成句子了。
     账户名允许被压到 4.5em(配合 truncate)而不是让金额换行:
     一个读得出开头的账户名 + 完整金额,比「完整账户名 + 金额掉到下一行」好读。
     实测 390px 下缩小 tag 之后不会真触发压缩 —— 这只是兜底。 */
  /* 【谁让路】这一行放不下时,该被压缩的是分类不是账户名。
     账户名是这一行的主语 —— 「支付宝-余…」看不出是余额宝还是余额,
     而分类被截成「日用百货 ›…」仍然读得懂。
     真实数据里把这条逼出来的是两种行:千分位长金额(−¥1,500.00)
     和两级分类(日用百货 › 家居家装)。 */
  [data-flow-row]:not([hidden]) > .flow-amt { margin-left: auto; flex: 0 0 auto; font-size: 12.5px; }
  [data-flow-row]:not([hidden]) > .flow-acct { flex: 0 0 auto; }
  /* 消费分类是 Tailwind 的 text-[10px] 硬编码,优先级压过 .pill 那套 ——
     不单独点名的话它在 390px 下仍是 PC 尺寸,一行就差这十几个 px,
     账户名于是被 truncate 掉最后两个字。 */
  [data-flow-row]:not([hidden]) > .flow-cat {
    font-size: 9px !important; letter-spacing: 0;
    flex: 0 1 auto; min-width: 2.2em;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* 备注来自账单原文,能有六七十个字(「闪擎适用苹果11/13/12防窥膜…」)。
     让它占满三行会把整个列表的节奏打散 —— 这正是「复杂列表谨慎换行」说的那种换行。
     截成一行,完整内容进 title(长按/悬停可见)。 */
  [data-flow-row]:not([hidden]) > .flow-meta > .flow-note {
    flex: 1 1 0; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* 状态标签和「删」靠右对齐成一条轴 —— 原来它们跟着备注长度飘,
     十行就有十个不同的 x,眼睛没有着落点 */
  [data-flow-row]:not([hidden]) > .flow-meta > .flow-eff { margin-left: auto; }
  [data-flow-row]:not([hidden]) > .flow-meta > form { margin-left: 8px; }
  /* 次要信息(备注 / 日期 / 状态 / 删)强制独占第二行 —— 这里换行是对的 */
  [data-flow-row]:not([hidden]) > .flow-meta { flex: 0 0 100%; gap: 6px; margin-top: 2px; }
  /* 「已出账 + 流水」是写死的说明文案,每行重复一遍;去掉边框只留色,退到背景里 */
  .flow-eff {
    font-size: calc(8px * var(--fs-scale, 1)) !important;
    padding: 1px 4px;
    border-color: transparent !important;
    letter-spacing: 0;
  }

  /* ── ②b 填报页的账户行:账户名优先占位 ──
     它和流水行是同一个病,但更严重:那边是被 tag 挤窄,这边是被硬编码 max-w 锁死。 */
  /* 校准状态是次要信息,缩小之后大多数情况下还能和账户名同行 */
  /* v1.35 · 改用 .pill 之后跟随标签的手机端 10px,这里只收窄内距 */
  .acct-head > [data-calibrated], .acct-head > [data-not-calibrated] { padding: 1px 5px; }

  /* 账户卡:两栏 → 上下两段。
     头像和勾留在第一段的左侧(它们是行首标识),余额单独一段靠右 ——
     这样左边的「上期末 … · 已填」和入口按钮都有整行宽度可用。 */
  /* 【明确断成两行】,不靠 flex-basis 的像素算术去「刚好放不下」。
     试过 basis:calc(100%-40px) —— 加上容器 8px 的 gap 刚好超 4px,刷新按钮掉到第三行;
     改成 60% —— 又变成整行都塞得下,于是账户名(basis 0、grow 1)只分到【15px】,
     被压成一个省略号。两次都是在跟像素较劲。
     用 flexbox 的标准断行:一个零高、basis 100% 的伪元素 + order 分组。
     第一行 = 头像 / 勾 / 账户名区;第二行 = 余额 / 刷新。 */
  .acct-row { flex-wrap: wrap; row-gap: 6px; }
  .acct-row::before { content: ""; flex: 0 0 100%; height: 0; order: 1; margin: 0; }
  /* 【不是 100%】—— 上一版给它 100% 把头像和那个勾挤成了独占一行,
     账户名跟着掉到第二行。头像 / 勾 / 账户名本来就该是同一行的开头。 */
  .acct-row > .flex-1 { flex: 1 1 0; min-width: 0; order: 0; }
  .acct-row > .acct-refresh { flex: 0 0 auto; align-self: center; order: 3; }
  /* 「上期末 … · 已填」整行收起:上期末右边余额区有一份,已填/待填由那个勾表达 */
  .acct-prev { display: none; }
  /* 账户名那一行【不换行】—— 名字、校准状态、类型、币种是一句话,断开就读不成句 */
  .acct-head { flex-wrap: nowrap; row-gap: 0; overflow: hidden; }
  .acct-head > .acct-name { flex: 0 1 auto; min-width: 0; }
  .acct-head > [data-calibrated], .acct-head > [data-not-calibrated] { flex: 0 0 auto; }
  /* 给刷新按钮留位置,否则它会被挤到下一行最左边 —— 一个孤零零的圆圈,看不出是干嘛的。
     【不要用 calc(100% - 40px)】:.acct-row 自身有 8px 的 gap,
     100%-40px + gap8 + 按钮36 = 100%+4px,刚好超一点点就整个换行,
     而这 4px 在截图上看不出来,只会觉得「怎么又掉下去了」。
     用一个宽松的 basis + grow:1 让它自己撑开,不做像素算术。 */
  .acct-row > .acct-bal {
    flex: 1 1 auto; order: 2;
    display: flex; align-items: baseline; justify-content: flex-end;
    gap: 8px; flex-wrap: wrap;
    padding-top: 4px; border-top: 1px dashed var(--rule-soft);
  }

  /* 账户行的三个入口(持仓变动 / AI 截图导入 / 券商)在 390px 下会一个占一行,
     三行按钮把账户名和余额挤得看不出主次。缩到能一行放下 —— 它们是入口不是主角。 */
  .acct-ops > a {
    font-size: 10px !important;
    padding: 2px 6px !important;
    gap: 3px !important;
  }
  .acct-ops > a > svg { width: 10px; height: 10px; }

  /* ── ③ 宽内容统一横向滚动,而不是被硬切 ──
     KPI 条 / 瀑布图 / 对比表在 390px 下本来就放不下。
     现在是直接溢出被裁掉(文档宽 394 > 390),右边的列用户永远看不到,
     而且没有任何「这里还有内容」的提示。 */
  .m-scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .m-scroll-x::-webkit-scrollbar { height: 3px; }
  .m-scroll-x::-webkit-scrollbar-thumb { background: var(--rule); }

  /* ── ③b 宽图表/宽表:补「可以横滑」的提示 ──
     瀑布图(.wf-scroll)和对比表(.cmp-scroll)本来就能横滑,
     但 390px 下右边被切得干干净净、没有任何视觉线索 ——
     用户看到第 4 根柱子只剩半截,只会以为图坏了,不会想到去滑。
     ::before 贴在容器上沿,不占文档流、不改图表本身的几何。 */
  .wf-scroll, .cmp-scroll, .m-scroll-x, html:not(.ls-wide) .summary-band { position: relative; }
  .wf-scroll::before, .cmp-scroll::before {
    content: "← 可以横滑 →";
    display: block;
    font-family: 'JetBrains Mono', monospace;
    font-size: 9px;
    letter-spacing: .08em;
    color: var(--ink-subtle);
    text-align: right;
    padding-bottom: 2px;
    position: sticky;      /* 跟着横向滚动走,始终贴在可视区右侧 */
    left: 0;
  }

  /* ── ⑤ 大标题与 eyebrow:手机端降一档 ──
     h1 在 PC 上是 text-5xl(48px),窄屏虽然已降到 text-3xl(30px),
     但配上「所 有 设 置 ·」这种手动加空格的排版仍会占满整行还溢出。
     用 clamp 随视口自适应:短标题不受影响,长标题自动缩到放得下。 */
  h1.font-display { font-size: clamp(21px, 6.6vw, 30px) !important; line-height: 1.25; }

  /* eyebrow 的 0.16em 字距是为 PC 的分节横线设计的;390px 下它和后面那句说明
     挤在一行时,两段都读不顺。字距收一半,容器允许换行。 */
  .eyebrow { letter-spacing: 0.08em; }

  /* 资产/负债对称条:标签移到条【外面】。
     负债块的宽度是按比例算的(这家约 14%,390px 下只有 ~55px),
     而「负债 ¥98,765」要 85px —— 塞在色块里必然被切成「…86,700」。
     条本身保持比例(那是它的全部意义),标签挪到下方左右两端。 */
  /* KPI 横条(现金/股票/理财…)本来就能横滑,但右边被切得没有线索。
     它是 flex 容器,::before 会变成一个 flex item —— 所以提示挂在【外层】,
     用兄弟选择器放在条的上方,不参与条内的 flex 排布。 */
  html:not(.ls-wide) .summary-band::after {
    content: "→";
    position: sticky; right: 0; align-self: center;
    flex: 0 0 auto; padding: 0 4px;
    font-family: 'JetBrains Mono', monospace; font-size: 11px;
    color: var(--ink-subtle); background: var(--paper);
  }

  .sym-bar { position: relative; padding-bottom: 15px; overflow: visible; }
  .sym-a > span, .sym-l > span {
    position: absolute; bottom: -1px; white-space: nowrap;
    font-size: 9px !important; color: var(--ink-soft);
  }
  .sym-a > span { left: 0; }
  .sym-l > span { right: 0; }

  /* ── ④ sticky 导航:不透明 + 贴顶 ──
     原来是 top:4px + bg-paper/95 + backdrop-blur —— 那 4px 缝里会漏出下方内容,
     半透明又让滚过去的文字透上来,看着像脏了一层。手机屏幕小,这层噪音很显眼。 */
  header.sticky {
    top: 0 !important;
    background: var(--paper) !important;
    backdrop-filter: none !important;
  }
}

/* v1.22.2 · 列表底部的翻页镜像(只在窄屏由 flow-table.js 插入) */
.flow-pager-bottom {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 9px 0 2px;
}

/* ═══ v1.22.4 · 流水列表的首屏预分页 ═══
   服务端把整月流水全量渲染进 DOM(前端分页的前提),而 flow-table.js 要等
   DOMContentLoaded 才接管 —— 实测 201 行的填报页【裸奔了 2.9 秒】:
   先铺开一条望不到头的长龙,过几秒突然缩成 10 行。

   CSS 在 head 里、阻塞渲染,所以它比任何 JS 都早。这里先按默认每页条数藏掉多余的行,
   JS 接管时把 .flow-prepaged 摘掉,之后一切照旧由 hidden 属性控制,两者不会打架。

   行数少于 MIN_ROWS(12)时模板不加这个 class —— 那种情况本来就不分页。 */
.flow-prepaged > [data-flow-row]:nth-of-type(n+11) { display: none !important; }
@media (max-width: 640px) {
  /* 手机端默认每页 5(见 flow-table.js 的 defaultSize)。
     【必须 !important】—— 手机端另有一条 v1.22.1 加的
     `[data-flow-row]:not([hidden]) { display: flex !important; }`(把流水行改成 flex 排布),
     而 JS 没跑时这些行还没有 hidden 属性,:not([hidden]) 全部命中 →
     那条 !important 会把这里的 display:none 整个盖掉。
     PC 端没有那条规则,所以这个问题【只在手机端出现】——
     前几次测试因为浏览器缓存让 flow-table.js 已经跑过,一直没暴露,
     直到用 javaScriptEnabled:false 的上下文才看见:手机 30 行全可见,PC 正好 10 行。 */
  .flow-prepaged > [data-flow-row]:nth-of-type(n+6) { display: none !important; }
}

/* ═══ v1.27 · 分析范围 / 分析模板 / 分析偏好(issue #23 · preview/v1.27/analysis-scope.html)═══
   范围三个选项必须同尺寸同样式(feedback_sibling_uniform:并列同类元素一大一小是这个项目反复出过的毛病);
   窄屏改成上下排 —— 三个并排每个不到 110px,副文案会折成四五行。 */
.scope-grid { display: grid; grid-template-columns: repeat(var(--scope-cols, 3), minmax(0, 1fr)); gap: 10px; }
/* 上下排时每一行一样高(grid-auto-rows:1fr)—— 一个选项副文案折两行、别的一行,看起来就是一大两小 */
@media (max-width: 767px) { .scope-grid { grid-template-columns: 1fr; grid-auto-rows: 1fr; gap: 8px; } }
.scope-pill { display: flex; flex-direction: column; justify-content: center; min-width: 0; min-height: 64px;
  padding: 10px 13px; border: 2px solid var(--rule); background: var(--paper); text-decoration: none; color: var(--ink);
  transition: border-color .15s, background .15s; }
.scope-pill:hover { border-color: var(--ink-subtle); }
.scope-pill.on { border-color: var(--brass-deep); background: rgba(160,124,58,.07); }
.scope-pill:not(.on) { opacity: .78; }
.scope-pill-t { font-family: "Fraunces", "Noto Serif SC", serif; font-size: 16px; line-height: 1.2; }
.scope-pill-s { font-size: 10.5px; color: var(--ink-subtle); margin-top: 4px; line-height: 1.5; }
@media (max-width: 767px) { .scope-pill { min-height: 54px; padding: 8px 11px; } .scope-pill-t { font-size: 14px; } }
/* 卡片标题旁「不含:自住房 · 车」 */
.scope-note { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 10px; color: var(--brass-deep);
  letter-spacing: .04em; white-space: normal; font-weight: 400; }
/* 模板选择行 */
.tpl-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: stretch; }
.tpl-chip { display: flex; flex-direction: column; justify-content: center; min-height: 44px; padding: 6px 10px;
  border: 2px solid var(--rule); background: var(--paper); font-size: 12.5px; line-height: 1.3; color: var(--ink);
  text-decoration: none; }
.tpl-chip small { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 9px; color: var(--ink-subtle);
  letter-spacing: .06em; margin-top: 2px; }
.tpl-chip:hover { border-color: var(--ink-subtle); }
.tpl-chip.on { border-color: var(--brass-deep); background: rgba(160,124,58,.07); }
.tpl-chip.add { border-style: dashed; color: var(--brass-deep); }
/* v1.27.1 · 定制模板页的「范围」「配置锚」:一张张说明卡(人话 + 正式叫法 + 对你家去掉了谁) */
.opt-list { display: grid; grid-template-columns: 1fr; gap: 8px; }
@media (min-width: 640px) { .opt-list-2 { grid-template-columns: 1fr 1fr; } }
.opt-card { display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px; border: 2px solid var(--rule);
  background: var(--paper); cursor: pointer; transition: border-color .15s, background .15s; }
.opt-card:hover { border-color: var(--ink-subtle); }
.opt-card:has(input:checked) { border-color: var(--brass-deep); background: rgba(160,124,58,.07); }
.opt-card input { margin-top: 4px; flex-shrink: 0; accent-color: var(--brass-deep); }
.opt-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.opt-t { font-family: "Fraunces", "Noto Serif SC", serif; font-size: 15px; line-height: 1.3; color: var(--ink); }
.opt-t small { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 10px; color: var(--ink-subtle);
  letter-spacing: .04em; margin-left: 4px; }
.opt-s { font-size: 12px; line-height: 1.6; color: var(--ink-soft); }
.opt-fact { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 10.5px; line-height: 1.5; color: var(--brass-deep); }
.opt-fact.is-empty { color: var(--ink-subtle); }
/* 首次提示(可关)· AI 页脚 */
.analysis-hint { display: flex; gap: 10px; align-items: center; border: 1px dashed var(--brass-deep);
  background: rgba(160,124,58,.05); padding: 9px 12px; font-size: 12.5px; color: var(--ink-soft); }
.analysis-foot { display: flex; align-items: center; gap: 8px 14px; flex-wrap: wrap; border-top: 1px solid var(--rule-soft);
  margin-top: 12px; padding-top: 9px; font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 10.5px; }
.analysis-foot .af-label { color: var(--brass-deep); }
.analysis-foot a, .analysis-foot summary { color: var(--brass-deep); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.analysis-foot details { position: relative; }
.analysis-foot details > div { position: absolute; z-index: 30; margin-top: 6px; min-width: 220px; background: var(--card);
  border: 1px solid var(--rule); box-shadow: 0 6px 18px rgba(26,23,20,.12); padding: 6px 0; }
.analysis-foot details > div a { display: block; padding: 6px 12px; text-decoration: none; color: var(--ink); font-size: 12px; }
.analysis-foot details > div a:hover { background: var(--card-soft); }
.analysis-foot details > div a.on { color: var(--brass-deep); }
/* 「不参与分析」小徽标 */
.tag-excluded { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 9.5px; padding: 1px 6px; white-space: nowrap;
  border: 1px solid var(--brass-deep); color: var(--brass-deep); background: rgba(160,124,58,.08); letter-spacing: .04em; }
/* 超级 Agent 确认卡 */
.remember-card { border: 2px solid var(--brass-deep); background: rgba(160,124,58,.06); padding: 13px 15px; margin-top: 10px; max-width: 560px; }
.remember-card .rc-t { font-family: "Fraunces", "Noto Serif SC", serif; font-size: 16px; }
.remember-card textarea { width: 100%; margin-top: 8px; border: 0; border-bottom: 1px solid var(--ink); background: transparent;
  font-size: 13px; line-height: 1.6; resize: vertical; padding: 4px 0; }
.remember-card .rc-acts { display: flex; gap: 8px; margin-top: 10px; align-items: center; flex-wrap: wrap; }
.remember-card .rc-more { border-top: 1px solid var(--rule-soft); margin-top: 12px; padding-top: 10px; display: flex; gap: 8px; flex-wrap: wrap; }
@media (max-width: 767px) { .remember-card .rc-more { display: grid; } .remember-card .rc-more > * { text-align: center; } }
/* v1.35 · btn-line 与 btn-paper 小档同规格(原来是 11px 等宽 + 墨色粗框) */
.btn-line { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 28px; padding: 3px 10px;
  font-family: var(--ui-sans); font-size: calc(12px * var(--fs-scale,1)); font-weight: 500; line-height: 1.25;
  border: 1px solid var(--rule-soft); border-radius: var(--r-md); box-shadow: var(--shadow-xs);
  color: var(--ink); background: var(--card); white-space: nowrap; text-decoration: none; cursor: pointer;
  transition: background-color 150ms ease, border-color 150ms ease; }
.btn-line:hover { background: var(--paper-soft); border-color: var(--rule); }
.btn-line:focus-visible { outline: none; box-shadow: var(--ring); }

/* ===========================================================
   v1.28 · 看 AI 收到了什么(PRD §3 · fragments/_prompt-peek.html · js/prompt-peek.js)
   -----------------------------------------------------------
   卡片头一个 >_,点开在卡片里原地展开一个终端 —— 和「复制去服务器上跑」的 .term-block 同一套深色。
   「你的设置带来的」段落用黄铜色左条 + 来源;金额包 data-priv,隐私模式下与页面其他金额一样糊。
   =========================================================== */
/* v1.28.1 · 图标 + 「查看 prompt」;字号 / 内边距 / 描边与卡片头右边的「↻ 刷新 / 重新生成」同一套,
   align-self:stretch 让它在同一行里和邻居一样高(维护者:两个按钮高度要一样) */
.peek-btn{ display:inline-flex; align-items:center; justify-content:center; gap:4px; flex-shrink:0; align-self:stretch;
           font-family:"JetBrains Mono", ui-monospace, monospace; font-size:10px; line-height:inherit; white-space:nowrap;
           padding:2px 8px; border:1px solid var(--rule-soft, var(--rule)); background:transparent; color:var(--ink-subtle);
           cursor:pointer; transition:border-color .15s, background .15s, color .15s; }
.peek-btn:hover{ color:var(--brass-deep); border-color:var(--brass-deep); }
.peek-btn.on{ border-color:#1c1a17; background:#1c1a17; color:#8fae86; }
.peek-btn[hidden]{ display:none; }
.peek{ margin:12px 0 4px; background:#1c1a17; border:1px solid #2a2622; border-radius:6px;
       box-shadow:0 10px 26px -14px rgba(0,0,0,.6); color:#d8d2c6;
       font-family:'JetBrains Mono',ui-monospace,monospace; font-size:12.5px; line-height:1.8; overflow:hidden; text-align:left; }
.peek[hidden]{ display:none; }
.peek .pk-bar{ display:flex; align-items:center; gap:8px; padding:7px 12px; border-bottom:1px solid #2a2622;
               background:#221f1b; font-size:11px; color:#7d766a; }
.peek .pk-dot{ width:9px; height:9px; border-radius:50%; background:#3a352f; display:inline-block; flex-shrink:0; }
.peek .pk-title{ margin-left:6px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.peek .pk-x{ margin-left:auto; cursor:pointer; color:#a39b8c; border:1px solid #3a352f; padding:0 7px; border-radius:3px;
             background:transparent; font:inherit; }
.peek .pk-x:hover{ color:#fff; border-color:var(--brass-deep); }
.peek .pk-body{ padding:12px 14px 6px; max-height:560px; overflow:auto; }
.peek .ln{ display:block; white-space:pre-wrap; word-break:break-word; }
.peek .ln:empty::after{ content:" "; }
.peek .ln.cmd{ color:#e9e3d6; }
.peek .ln.cmd::before{ content:'$ '; color:#8fae86; }
.peek .ln.cmt{ color:#7d766a; }
.peek .ln.ok{ color:#8fae86; }
.peek .ln.warn{ color:#d9a066; }
.peek .ln.kv .k{ color:#a39b8c; display:inline-block; min-width:5em; }
.peek .caret{ display:inline-block; width:.6em; height:1.05em; background:#8fae86; vertical-align:-2px; animation:peekBlink 1.05s steps(1) infinite; }
@keyframes peekBlink{ 50%{ opacity:0; } }
@media (prefers-reduced-motion: reduce){ .peek .caret{ animation:none; } }
.peek .sec{ margin-top:10px; border-top:1px dashed #3a352f; padding-top:8px; }
.peek .sec-h{ display:flex; align-items:baseline; gap:10px; cursor:pointer; color:#e9e3d6; user-select:none; flex-wrap:wrap; }
.peek .sec-h .tri{ color:#8fae86; width:1em; display:inline-block; }
.peek .sec-h .tag{ color:#1c1a17; background:#8fae86; padding:0 5px; font-size:10.5px; }
.peek .sec-h .tag.sys{ background:#7d766a; }
.peek .sec-h .meta{ color:#7d766a; font-size:11px; }
.peek .sec-b{ margin-top:6px; padding-left:1em; color:#cfc8ba; }
.peek .sec:not(.open) .sec-b{ display:none; }
.peek .mine{ display:block; border-left:3px solid #d6b26a; background:rgba(214,178,106,.08); padding:4px 8px;
             margin:6px 0 6px -11px; color:#eadcb8; }
.peek .mine .src{ float:right; color:#d6b26a; font-size:10.5px; margin-left:12px; }
.peek.only-mine .sec-b > .ln, .peek.only-mine .sec.sys{ opacity:.22; }
.peek .pk-log{ margin-top:10px; }
.peek .pk-foot{ border-top:1px solid #2a2622; padding:9px 14px 11px; background:#201d19; }
.peek .chips{ display:flex; gap:6px; flex-wrap:wrap; margin-bottom:8px; }
.peek .chip{ font-family:'JetBrains Mono',monospace; font-size:11px; color:#d8d2c6; background:#2a2622; border:1px solid #3a352f;
             border-radius:3px; padding:2px 9px; cursor:pointer; }
.peek .chip:hover{ background:var(--brass-deep); border-color:var(--brass-deep); color:#fff; }
.peek .chip b{ color:#8fae86; font-weight:400; }
.peek .pk-in{ display:flex; align-items:center; gap:6px; }
.peek .pk-in .p{ color:#8fae86; }
.peek .pk-in input{ flex:1; min-width:0; background:transparent; border:0; outline:0; color:#e9e3d6; font:inherit; caret-color:#8fae86; padding:0; }
.peek .pk-note{ font-size:10.5px; color:#7d766a; margin-top:6px; }
.peek .pk-priv-note{ display:none; }
html.privacy .peek .pk-priv-note{ display:inline; }
html.privacy .peek [data-peek-copy]{ opacity:.4; }
@media (max-width:640px){ .peek{ font-size:11.5px; } .peek .pk-body{ padding:10px 10px 4px; max-height:70vh; } .peek .mine .src{ float:none; display:block; } }

/* v1.28.2 · 产品类目表:从仪表盘「货币基金的风险与参考收益」直达 #cat-MONEY_FUND,高亮那一行 */
/*   类名别用 .cat-row —— 填报页类目宫格已经占了它(display:grid),撞上会把这张表的每一行排成格子 */
.pc-row { scroll-margin-top: 96px; }
.pc-row:target > td { background: var(--brass-soft); }
.pc-row:target > td:first-child { box-shadow: inset 3px 0 0 var(--brass-deep); }

/* ═══ v1.31 · 手机易用性(prd/v1.31.md)═══════════════════════════════════════════
   断点与 tailwind md 同源:<768 = 手机排法。 */

/* —— FR-1030 · 标签永远一行:放不下整个换到下一行,不在标签内部折 —— */
.pill { white-space: nowrap; }

/* —— FR-1010 ~ 1012 · 管理侧栏 —— */
.adm-link { display: flex; align-items: center; gap: 6px; padding: 6px 12px; border-left: 1px solid var(--rule);
  color: var(--ink-soft); text-decoration: none; }
.adm-link:hover { border-left-color: var(--ink); background: var(--card-soft); }
.adm-link.on { border-left: 2px solid var(--brass); background: var(--card-soft); color: var(--ink);
  font-family: "Fraunces", "Noto Serif SC", serif; }
.adm-ro { font-size: calc(10px * var(--fs-scale,1)); color: var(--rust); white-space: nowrap; }
.adm-ro::before { content: '· '; }
.adm-group { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: calc(10px * var(--fs-scale,1));
  letter-spacing: .2em; color: var(--brass-text); padding: 12px 12px 3px; white-space: nowrap; }
/* 分组后侧栏变长:矮屏上 sticky 的侧栏不许比视口高(否则底下几项永远够不着),超出就自己滚 */
.adm-side .sticky { max-height: calc(100vh - 7rem); overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; }
/* PC 侧栏里的本页目录(toc.js 填):挂在当前项下,左边线接着当前项的铜线 */
.adm-toc:empty { display: none; }
.adm-toc { border-left: 2px solid var(--brass); padding: 2px 0 6px; }
.adm-toc a { display: block; padding: 4px 12px 4px 24px; font-size: calc(12px * var(--fs-scale,1)); color: var(--ink-subtle);
  text-decoration: none; line-height: 1.45; }
.adm-toc a.toc-sub { padding-left: 36px; font-size: calc(11.5px * var(--fs-scale,1)); }
.adm-toc a:hover { color: var(--ink); }
.adm-toc a[aria-current="true"] { color: var(--brass-text); font-weight: 600; }
/* 手机切换条 */
.adm-bar { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 44px; padding: 0 12px; border: 1px solid var(--rule); background: var(--card); text-align: left; cursor: pointer; }
.adm-bar-path { font-size: calc(13.5px * var(--fs-scale,1)); color: var(--ink-soft); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.adm-bar-path b { color: var(--ink); font-family: "Fraunces", "Noto Serif SC", serif; font-weight: 500; font-size: calc(15px * var(--fs-scale,1)); }
.adm-bar-sep { color: var(--ink-faint); margin: 0 2px; }
.adm-bar-sw { display: inline-flex; align-items: center; gap: 4px; font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: calc(11px * var(--fs-scale,1)); letter-spacing: .1em; color: var(--brass-text); white-space: nowrap; }
@media (max-width: 767.98px) { .adm-side { margin-bottom: -14px; } }
/* 手机抽屉:沿用 .toc-sheet 的外观与收起动画,只是层级抬到右下浮钮之上(脚本已把它挪到 body 下) */
.adm-mask { z-index: 10000; }
.adm-sheet { z-index: 10001; max-height: 86vh; }
body.adm-open #float-dock { display: none !important; }
.adm-sheet .adm-group { padding: 12px 14px 2px; }
.adm-sheet-grid { display: grid; grid-template-columns: 1fr 1fr; }
.adm-sheet-link { display: flex; align-items: center; justify-content: space-between; gap: 6px; min-height: 40px; padding: 0 14px;
  border-left: 2px solid transparent; font-size: calc(14.5px * var(--fs-scale,1)); color: var(--ink); text-decoration: none; }
.adm-sheet-link.on { border-left-color: var(--brass-deep); background: var(--card-soft); color: var(--brass-text);
  font-family: "Fraunces", "Noto Serif SC", serif; font-weight: 600; }
.adm-sheet-link .adm-ro::before { content: ''; }

/* —— FR-1020 ~ 1022 · 表格在手机上「一行一张小卡」——————————————————————————
   用法:<table class="ledger-table m-cards">,单元格按角色加类:
     m-title  这一行是谁(期号 / 名称)—— 卡片第一行左
     m-badge  状态 / 类型标签 —— 卡片第一行右
     (无类)  普通字段 —— 两列「字段名 值」,字段名取 data-label
     m-full   独占一整行的字段(长说明、详情)
     m-act    操作 —— 卡片最底下占满一行,输入框自动拉满
     m-hide   手机上不显示(只用于 PC 上重复的信息,不许藏操作 —— FR-1022)
   PC(≥768)上这些类全部不生效,表格照旧。 */
@media (max-width: 767.98px) {
  table.m-cards, table.m-cards > tbody { display: block; width: 100%; }
  table.m-cards > thead { display: none; }
  table.m-cards > tbody > tr { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); column-gap: 12px; row-gap: 6px;
    align-items: baseline; padding: 12px 14px; border-bottom: 1px solid var(--rule-soft); }
  table.m-cards > tbody > tr:hover > td { background: none; }
  table.m-cards > tbody > tr > td { display: block; padding: 0; border: 0; min-width: 0; text-align: left; white-space: nowrap;
    font-size: calc(13px * var(--fs-scale,1)); }
  table.m-cards > tbody > tr > td[data-label]::before { content: attr(data-label); margin-right: 6px; font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: calc(10px * var(--fs-scale,1)); letter-spacing: .12em; color: var(--ink-subtle); }
  table.m-cards > tbody > tr > td.m-title { grid-column: 1; font-size: calc(17px * var(--fs-scale,1)); white-space: normal; }
  table.m-cards > tbody > tr > td.m-title { grid-row: 1; }
  table.m-cards > tbody > tr > td.m-badge { grid-row: 1; grid-column: 2; justify-self: end; text-align: right; white-space: normal; }
  table.m-cards > tbody > tr > td.m-full { grid-column: 1 / -1; white-space: normal; word-break: break-word; }
  table.m-cards > tbody > tr > td.m-act { grid-column: 1 / -1; white-space: normal; margin-top: 2px; }
  table.m-cards > tbody > tr > td.m-act form { display: flex; gap: 8px; align-items: stretch; width: 100%; }
  table.m-cards > tbody > tr > td.m-act input[type="text"] { flex: 1 1 auto; min-width: 0; min-height: 36px; font-size: 13px; }
  table.m-cards > tbody > tr > td.m-act button { min-height: 36px; white-space: nowrap; }
  table.m-cards > tbody > tr > td.m-hide { display: none; }
  /* 大字号(右上角 AA 调到「大 / 特大」)下两列放不下一个完整日期时间 → 普通字段改成一行一个 */
  html[data-fs="lg"] table.m-cards > tbody > tr > td:not(.m-title):not(.m-badge),
  html[data-fs="xl"] table.m-cards > tbody > tr > td:not(.m-title):not(.m-badge) { grid-column: 1 / -1; }
  /* 卡片化以后不需要横向滚动;外层若写了 overflow-x-auto,手机上让它别出滚动条 */
  .m-cards-wrap { overflow-x: visible !important; }
}

/* ═══ v1.32 · 固定收支那一行(entry/_fixed-flows.html · prd/v1.32.md FR-1110 ~ 1118)═══════════════
   默认收起只占一行;展开后每笔三行:名称 · 种类 · 金额 / 账户与算式 / 按钮。
   手机上按钮整行、点得中(v1.31 卡片排法);PC 上按钮靠右。 */
.ff { margin: 0 0 4px; }
.ff-box { border: 1px solid var(--rule); border-left: 4px solid var(--brass-deep); background: var(--card); }
.ff-sum { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 10px 16px; cursor: pointer;
  background: rgba(176,134,66,.08); font-size: calc(13.5px * var(--fs-scale,1)); list-style: none; }
.ff-sum::-webkit-details-marker { display: none; }
.ff-sum-ok { background: rgba(79,107,71,.07); }
.ff-sum-empty { cursor: default; border: 1px dashed var(--rule); background: transparent; }
.ff-chev { display: inline-flex; color: var(--brass-deep); transition: transform .15s; }
.ff-box[open] > .ff-sum .ff-chev { transform: rotate(90deg); }
.ff-box[open] > .ff-sum { border-bottom: 1px solid var(--rule-soft); }
.ff-nm { font-family: 'Fraunces','Noto Serif SC',serif; font-size: calc(15px * var(--fs-scale,1)); }
.ff-cnt { color: var(--rust); font-family: 'JetBrains Mono', monospace; font-size: calc(12px * var(--fs-scale,1)); white-space: nowrap; }
.ff-total { font-family: 'JetBrains Mono', monospace; white-space: nowrap; }
.ff-ok { color: var(--forest); }
.ff-sub { color: var(--ink-subtle); font-size: calc(12px * var(--fs-scale,1)); }
.ff-spacer { flex: 1 1 auto; }
.ff-toggle { color: var(--ink-soft); font-size: calc(12px * var(--fs-scale,1)); white-space: nowrap; }
.ff-box:not([open]) .ff-when-open, .ff-box[open] .ff-when-closed { display: none; }
.ff-link, .ff-add { color: var(--brass-deep); font-size: calc(12px * var(--fs-scale,1)); text-decoration: underline; text-underline-offset: 3px; white-space: nowrap; }
.ff-add { text-decoration: none; font-weight: 500; }
.ff-all-btn { white-space: nowrap; }
.ff-flash { padding: 8px 14px; font-size: calc(13px * var(--fs-scale,1)); margin-bottom: 8px; border-left: 2px solid; }
.ff-flash-ok { border-color: var(--forest); background: rgba(79,107,71,.07); }
.ff-flash-err { border-color: var(--rust); background: rgba(159,74,58,.06); }
.ff-row { padding: 10px 16px; border-bottom: 1px solid var(--rule-soft); }
.ff-row-sug { background: rgba(176,134,66,.06); }
.ff-row-later { opacity: .75; }
.ff-row-done { background: rgba(79,107,71,.04); }
.ff-l1 { display: flex; align-items: center; gap: 8px; min-width: 0; }
.ff-l2 { margin-top: 4px; font-size: calc(12px * var(--fs-scale,1)); color: var(--ink-subtle); line-height: 1.6; }
.ff-l3 { display: flex; gap: 8px; align-items: center; justify-content: flex-end; margin-top: 8px; flex-wrap: wrap; }
.ff-l3 form { display: inline; margin: 0; }
.ff-av { display: inline-flex; width: 20px; height: 20px; border-radius: 50%; color: var(--paper); font-size: 11px;
  align-items: center; justify-content: center; flex-shrink: 0; font-family: 'Fraunces','Noto Serif SC',serif; }
.ff-name { font-family: 'Fraunces','Noto Serif SC',serif; font-size: calc(15px * var(--fs-scale,1)); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ff-tag { display: inline-block; white-space: nowrap; font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: .06em;
  padding: 1px 7px; border: 1px solid var(--rule); color: var(--ink-soft); background: var(--paper-soft); flex-shrink: 0; }
.ff-tag-in { background: var(--forest-soft); color: var(--forest); border-color: var(--forest); }
.ff-tag-out { background: var(--rust-soft); color: var(--rust); border-color: var(--rust); }
.ff-tag-loan { background: rgba(60,74,90,.12); color: #3c4a5a; border-color: #3c4a5a; }
.ff-tag-ins { background: var(--brass-soft); color: var(--brass-deep); border-color: var(--brass); }
.ff-tag-sug { background: transparent; color: var(--brass-deep); border-style: dashed; border-color: var(--brass-deep); }
.ff-amt { margin-left: auto; font-family: 'JetBrains Mono', monospace; font-size: calc(14px * var(--fs-scale,1)); white-space: nowrap;
  display: inline-flex; align-items: center; gap: 4px; }
.ff-amt-in { width: 7.5rem; border: 1px solid var(--brass-deep); background: #fffdf7; font-family: 'JetBrains Mono', monospace;
  font-size: calc(14px * var(--fs-scale,1)); padding: 3px 8px; text-align: right; }
.ff-calc { font-family: 'JetBrains Mono', monospace; font-size: 9.5px; color: var(--brass-deep); border: 1px solid var(--brass-deep);
  padding: 0 4px; cursor: help; }
.ff-formula { margin-top: 3px; font-family: 'JetBrains Mono', monospace; font-size: calc(10.5px * var(--fs-scale,1)); color: var(--brass-deep); }
.ff-problem { margin-top: 4px; font-size: calc(12px * var(--fs-scale,1)); color: var(--rust); }
.ff-diff { color: var(--rust); }
.ff-remember { display: inline-flex; gap: 6px; align-items: center; margin-top: 6px; font-size: calc(12px * var(--fs-scale,1)); color: var(--brass-deep); }
.ff-remember[hidden] { display: none; }
.ff-hint { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 8px; padding: 6px 10px;
  font-size: calc(12px * var(--fs-scale,1)); color: var(--brass-deep); background: rgba(176,134,66,.08); }
.ff-fold > summary { padding: 9px 16px; font-size: calc(12.5px * var(--fs-scale,1)); color: var(--ink-soft); cursor: pointer;
  border-bottom: 1px solid var(--rule-soft); }
.ff-fold[open] > summary { color: var(--ink); }
@media (max-width: 767.98px) {
  .ff-sum { padding: 10px 12px; gap: 8px; }
  .ff-all-btn { order: 10; flex: 1 1 100%; min-height: 38px; justify-content: center; }
  .ff-row { padding: 11px 12px; }
  .ff-l3 { justify-content: stretch; }
  .ff-l3 > button, .ff-l3 > form, .ff-l3 > .btn-ink, .ff-l3 > .btn-paper { flex: 1 1 0; }
  .ff-l3 button, .ff-l3 button[class] { width: 100%; min-height: 36px; justify-content: center; }   /* v1.35 · [class] 提权:压过按钮小档在手机上的 32px,这一行要整行好点(FR-1118) */
  .ff-amt-in { width: 6.5rem; }
}
@media (max-width: 767.98px) {
  /* 手机上摘要那一行要放得下「固定收支 · N 笔待确认 · 共 ¥X · 管理」:展开 / 收起两个字让给左边的箭头 */
  .ff-toggle { display: none; }
}
@media (min-width: 768px) {
  /* PC 上按钮挪到第一行右边:一笔两行(名称 · 种类 · 金额 | 按钮 / 账户 · 算式),不是三行 */
  .ff-form, .ff-row-sug, .ff-row-done { display: grid; grid-template-columns: minmax(0,1fr) auto; column-gap: 18px; align-items: center; }
  .ff-form > *, .ff-row-sug > *, .ff-row-done > * { grid-column: 1; }
  .ff-form > .ff-l3, .ff-row-sug > .ff-l3, .ff-row-done > .ff-l3 { grid-column: 2; grid-row: 1; margin-top: 0; }
  .ff-row-done > .ff-l3 { display: flex; }
}
/* 管理页「固定收支」:改 / 停用 两个动作在手机卡片里也排成一行 */
.ff-acts { display: inline-flex; align-items: center; gap: 14px; }
@media (max-width: 767.98px) {
  table.m-cards > tbody > tr > td.m-act .ff-acts form { display: inline; width: auto; }
}

/* ═══ v1.33 · 删除账户的确认面板(accounts/delete.html · 与 .peek 同一套终端配色)═══════════════ */
/* 面板页本身沿用纸色背景(深色只在面板里)—— 整页压暗会让顶栏看不清 */
.adel { background: #1c1a17; border: 1px solid #2a2622; border-radius: 6px; font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: calc(12.5px * var(--fs-scale,1)); color: #cfc8ba; box-shadow: 0 20px 50px -20px rgba(0,0,0,.6); }
.adel-bar { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid #2a2622; color: #a39b8c; font-size: 11.5px; }
.adel-dot { width: 10px; height: 10px; border-radius: 50%; background: #3a352f; display: inline-block; flex-shrink: 0; }
.adel-dot.r { background: #c0563f; }
.adel-title { margin-left: 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.adel-x { margin-left: auto; border: 1px solid #3a352f; padding: 0 7px; border-radius: 3px; color: #a39b8c; text-decoration: none; }
.adel-x:hover { color: #fff; border-color: var(--brass-deep); }
.adel-body { padding: 14px 16px 16px; }
.adel .ln { display: block; white-space: pre-wrap; word-break: break-word; line-height: 1.75; }
.adel .ln.cmd { color: #e9e3d6; }
.adel .ln.cmd::before { content: '$ '; color: #8fae86; }
.adel .cmt { color: #7d766a; }
.adel .warn { color: #d9a066; }
.adel .red { color: #e07a5f; }
.adel .ok { color: #8fae86; }
.adel .hd { color: #e9e3d6; margin-top: 12px; border-top: 1px dashed #3a352f; padding-top: 8px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.adel .hd .tag { color: #1c1a17; background: #d9a066; padding: 0 5px; font-size: 10.5px; }
.adel .hd .tag.red { background: #e07a5f; color: #1c1a17; }
.adel-arch { border: 1px solid #8fae86; color: #8fae86; padding: 1px 9px; margin-left: 10px; font-size: 11.5px; background: transparent; cursor: pointer; font-family: inherit; }
.adel-arch:hover { background: rgba(143,174,134,.12); }
.adel-err { margin: 10px 0 4px; border-left: 3px solid #e07a5f; background: rgba(224,122,95,.10); color: #f0c7b8; padding: 8px 12px; line-height: 1.7; }
.adel-more summary { color: #7d766a; cursor: pointer; padding-left: 4ch; }
.adel .tr { display: grid; grid-template-columns: 70px 110px 200px 1fr; gap: 8px; padding: 3px 0 3px 1em; line-height: 1.6; }
.adel .tr .amt { color: #e9e3d6; }
.adel .confirm { margin-top: 14px; border-top: 1px solid #3a352f; padding-top: 12px; }
.adel .phrase-wrap { position: relative; margin-top: 6px; }
.adel .phrase { background: #26231f; border: 1px dashed #d9a066; padding: 10px 12px; padding-right: 120px; color: #f0e6d2; white-space: pre-wrap;
  word-break: break-word; line-height: 1.8; margin: 0; font-family: inherit; font-size: inherit; }
.adel .copy { position: absolute; right: 8px; top: 8px; background: #d9a066; color: #1c1a17; padding: 4px 10px; font-size: 12px;
  font-family: 'Noto Serif SC', serif; border: none; cursor: pointer; }
.adel .ta { display: block; width: 100%; margin-top: 10px; background: #141210; border: 1px solid #3a352f; min-height: 118px; padding: 10px 12px;
  color: #e9e3d6; line-height: 1.8; font-family: inherit; font-size: inherit; resize: vertical; }
.adel .ta.ok { border-color: #8fae86; }
.adel .acts { display: flex; gap: 10px; align-items: center; margin-top: 12px; flex-wrap: wrap; }
.adel .del { background: #9c4a2a; color: #fff; border: 1px solid #c0563f; padding: 8px 16px; font-family: 'Noto Serif SC', serif; font-size: 13px; cursor: pointer; }
.adel .del:disabled { background: #3a2a24; color: #8a6f62; border-color: #4a3a33; cursor: not-allowed; }
.adel .del-nobk { background: transparent; color: #e08a6d; border: 1px solid #9c4a2a; padding: 8px 14px; font-family: 'Noto Serif SC', serif; font-size: 13px; cursor: pointer; }
.adel .del-nobk:disabled { color: #6f5a50; border-color: #4a3a33; cursor: not-allowed; }
.adel .cancel { color: #a39b8c; border: 1px solid #3a352f; padding: 8px 14px; font-family: 'Noto Serif SC', serif; font-size: 13px; }
.adel .match { font-size: 11.5px; }
@media (max-width: 767.98px) {
  .adel { border-radius: 0; margin: 0 -12px; font-size: calc(11.5px * var(--fs-scale,1)); }
  .adel .tr { grid-template-columns: 62px 1fr; gap: 2px 6px; }
  .adel .tr > span:nth-child(3), .adel .tr > span:nth-child(4) { grid-column: 1 / -1; padding-left: 62px; }
  .adel .phrase { padding-right: 12px; }
  .adel .copy { position: static; display: block; width: 100%; margin-top: 8px; padding: 9px; font-size: 13px; }
  .adel .acts { flex-direction: column; align-items: stretch; }
  .adel .del, .adel .del-nobk, .adel .cancel { text-align: center; min-height: 40px; }
}

/* ── 危险操作区(账户编辑页 · v1.34 重做)──
   每行「名称 + 说明 | 右边按钮」:grid 两列,说明永远从同一列起;按钮同宽同高(并列同类元素同尺寸)。
   手机上按钮整行放在说明下面。 */
.danger-zone { padding: 0; border-color: var(--rust); overflow: hidden; }
.danger-zone-title { font-family: 'Fraunces', 'Noto Serif SC', serif; font-size: 17px; color: var(--rust);
                     padding: 14px 20px; border-bottom: 1px solid rgba(156,74,42,.25); background: rgba(156,74,42,.04); }
.danger-zone-row { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 16px; padding: 14px 20px; }
.danger-zone-row + .danger-zone-row { border-top: 1px solid var(--rule-soft); }
.danger-zone-name { font-size: 14px; font-weight: 600; color: var(--ink); }
.danger-zone-desc { font-size: 12.5px; color: var(--ink-soft); margin-top: 3px; line-height: 1.6; }
.danger-zone-btn { display: inline-flex; align-items: center; justify-content: center; width: 7.5rem; height: 36px;
                   font-size: 13px; letter-spacing: .08em; border: 1px solid var(--rust); color: var(--rust);
                   background: var(--card); cursor: pointer; }
.danger-zone-btn:hover { background: rgba(156,74,42,.06); }
.danger-zone-red { background: var(--rust); color: #fff; }
.danger-zone-red:hover { background: #8a3f22; }
@media (max-width: 767.98px) {
  .danger-zone-row { grid-template-columns: 1fr; gap: 10px; }
  .danger-zone-row form, .danger-zone-btn { width: 100%; }
  .danger-zone-btn { height: 42px; }
}


/* ── 拖拽排序板(v1.34 · 持仓顺序 / 账户顺序 · js/sort-board.js)──
   一张卡一行:左边抓手 + 名字,右边数值;按住拖,卡片浮起跟着走,原位留虚线空位,其它卡片滑开让路。 */
.sort-board { position: relative; }
.sort-list { display: flex; flex-direction: column; gap: 8px; }
.sort-card { display: grid; grid-template-columns: 22px 26px 1fr auto; align-items: center; gap: 10px;
             background: var(--card); border: 1px solid var(--rule); padding: 12px 16px; cursor: grab;
             user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
             transition: box-shadow .15s, border-color .15s; }
.sort-card:hover { border-color: var(--ink-subtle); box-shadow: 0 2px 10px rgba(26,23,20,.06); }
.sort-card:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
.sort-grip { color: var(--ink-subtle); display: inline-flex; }
.sort-card:hover .sort-grip { color: var(--ink); }
.sort-idx { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--ink-subtle); text-align: right; }
.sort-main { display: flex; flex-direction: column; min-width: 0; }
.sort-name { font-family: 'Noto Serif SC', serif; font-size: 15px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sort-sub { font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--ink-subtle); margin-top: 2px; }
.sort-val { font-family: 'JetBrains Mono', monospace; font-size: 13px; color: var(--ink-soft); white-space: nowrap; }
/* 拖动时:原位置 = 虚线空位;跟手的那张 = 浮起 + 阴影。
   跟手的那张**不许有 transform 过渡、也不许自带 transform**:SortableJS 每次移动先读它当前的 transform 矩阵再加上位移,
   有过渡时读到的是动画走到一半的值,差额一路累积 —— 鼠标移 246px 卡只跟 99px(维护者验收:「鼠标移动的像素很少,拖不到别的卡上」)。
   旋转 / 放大同理会被并进矩阵,一并不用,浮起感只靠阴影。e2e flow 51 量「卡片跟手」。 */
.sort-ghost { background: rgba(196,148,62,.06) !important; border: 1px dashed var(--brass) !important; box-shadow: none !important; }
.sort-ghost > * { visibility: hidden; }
.sort-chosen { border-color: var(--brass); }
.sort-drag { cursor: grabbing !important; box-shadow: 0 14px 34px rgba(26,23,20,.22) !important; transition: none !important;
             background: var(--card) !important; opacity: .98 !important; border-color: var(--brass) !important; }
.sort-dropped { animation: sort-pulse .7s ease-out; }
@keyframes sort-pulse { 0% { background: rgba(196,148,62,.22); } 100% { background: var(--card); } }
.sort-board.dragging .sort-card:not(.sort-chosen):hover { box-shadow: none; }
.sort-board.saving { opacity: .92; }
.sort-group + .sort-group { margin-top: 22px; }
.sort-group-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 13px; color: var(--ink-soft); }
.sort-head-sub { font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: .06em; color: var(--ink-subtle); margin-top: 6px;
                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 一键排法:三个按钮同宽同高(并列同类元素同尺寸 · visual-spec「操作行 / 按钮组」)*/
.sort-quick { display: grid; grid-template-columns: auto repeat(3, 9.5rem); gap: 8px; align-items: center; justify-content: start; }
.sort-quick-label { font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: .14em; color: var(--ink-subtle); margin-right: 4px; }
.sort-quick-btn { justify-content: center; height: 32px; padding: 0 8px; white-space: nowrap; }   /* v1.35 · 跟按钮默认档(原 38px + .06em 字距) */
/* 底部提示条:已保存 · 撤销 */
.sort-toast { position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 20px); opacity: 0; pointer-events: none;
              background: var(--ink); color: var(--paper); padding: 10px 14px 10px 16px; display: flex; align-items: center; gap: 14px;
              font-size: 13px; box-shadow: 0 10px 28px rgba(26,23,20,.25); transition: opacity .2s, transform .2s; z-index: 60; }
.sort-toast.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.sort-toast.bad { background: var(--rust); }
.sort-toast button { color: var(--brass); background: none; border: 0; font-size: 13px; cursor: pointer; padding: 2px 4px; text-decoration: underline; }
@media (max-width: 767.98px) {
  .sort-card { grid-template-columns: 18px 1fr auto; padding: 14px 12px; }
  .sort-idx { display: none; }
  .sort-name { font-size: 15px; }
  .sort-val { font-size: 12px; }
  .sort-toast { bottom: 18px; width: calc(100% - 32px); justify-content: space-between; }
  .sort-quick { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
  .sort-quick-label { grid-column: 1 / -1; }
  .sort-quick-btn { height: 36px; padding: 0 4px; }   /* v1.35 · 手机默认档 36(原 42) */
}

/* ── 账户簿页头四个按钮(v1.34)──
   手机上一行四等分、同宽同高(并列同类元素同尺寸);字号收小、字距归零、「(开向导)」不显示。PC 照旧。 */
@media (max-width: 767.98px) {
  .acct-actions[data-acct-actions] { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; width: 100%; }   /* 带属性提高权重:元素上的 Tailwind .flex 是运行时注入、排在 style.css 后面 */
  .acct-actions > a { justify-content: center; height: 38px; padding: 0 2px; font-size: calc(11.5px * var(--fs-scale,1)); letter-spacing: 0; gap: 3px; }
  .acct-actions > a svg { width: 11px; height: 11px; flex: none; }
  .acct-actions-long { display: none; }
}

/* ── 补记到历史期的选择框(v1.34.2 · js/backfill-ask.js)── */
.bf-dialog { border: 1px solid var(--ink); background: var(--card); color: var(--ink); padding: 0; max-width: 520px; width: calc(100% - 32px); }
.bf-dialog::backdrop { background: rgba(26,23,20,.35); }
.bf-dialog form { padding: 20px 22px; display: flex; flex-direction: column; gap: 12px; }
.bf-title { font-family: 'Fraunces', 'Noto Serif SC', serif; font-size: 18px; }
.bf-desc { font-size: 13px; color: var(--ink-soft); line-height: 1.7; }
.bf-opt { display: grid; grid-template-columns: 18px 1fr; gap: 10px; align-items: start; padding: 10px 12px;
          border: 1px solid var(--rule); font-size: 13px; line-height: 1.6; cursor: pointer; }
.bf-opt span { color: var(--ink-soft); }
.bf-opt b { color: var(--ink); font-weight: 600; }
.bf-opt:has(input:checked) { border-color: var(--brass); background: rgba(196,148,62,.06); }
.bf-opt input { margin-top: 4px; }
.bf-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 4px; }
.bf-actions button { justify-content: center; height: 38px; }


/* ═══════════════════════════════════════════════════════════════════
   v1.35 · 控件收口(维护者 2026-10-19「所有页面都要进行调整」)
   ═══════════════════════════════════════════════════════════════════
   btn-* / pill 之外,模板里还有不少手搓的小控件(Tailwind 拼的描边链接、分段切换、小标签)。
   逐个改模板会漏,这里按「形状」统一收口 —— 只动圆角、字距、大小写,不动颜色和尺寸:
   · 顶栏导航:等宽大写 + 0.14em 字距 → 无衬线 13px(中文不再被拉成「仪 表 盘」)
   · 带完整描边的链接 / 按钮 / summary / label → 圆角 6px;带描边的小 span(标签)→ 4px
   · 分段切换(外框 div.flex.border,子项只有 border-l)→ 外框圆角 + 裁切,子项保持连在一起
   · 交互控件上的字距 / 大写去掉(纯标签、表头、eyebrow 不动 —— 那是账册的排印识别) */
.nav-tabs, .nav-drawer { font-family: var(--ui-sans); letter-spacing: 0; text-transform: none; }
.nav-tabs > a { font-weight: 500; }
:is(a, button, summary, label)[class~="border"]:not([class*="rounded"]):not(.pill) { border-radius: var(--r-md); }
span[class~="border"]:not([class*="rounded"]):not(.pill) { border-radius: var(--r-sm); }
div.flex[class~="border"]:has(> :is(a, button, label)[class*="border-l"]) { border-radius: var(--r-md); overflow: hidden; }
:is(button, summary)[class*="tracking-"], :is(a, label)[class~="border"][class*="tracking-"] { letter-spacing: .02em; }
:is(button, summary).uppercase, :is(a, label)[class~="border"].uppercase { text-transform: none; }

/* v1.35 · 持仓卡「改份额」:表单改成浮层,不再撑开同一排的按钮 */
.nav-edit { position: relative; }
.nav-edit > summary::-webkit-details-marker { display: none; }
.nav-edit-pop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  background: var(--card); border: 1px solid var(--rule-soft); border-radius: var(--r-lg);
  box-shadow: 0 10px 30px -10px rgba(26, 23, 20, .22), 0 2px 6px rgba(26, 23, 20, .06);
}
@media (max-width: 1023px) { .nav-edit-pop { left: 0; right: auto; } }
/* 下拉框挂了 .pill(持仓卡「行业?」):标签去掉边框后它就看不出是能点的,补回细边 + 卡片底 */
select.pill { border-color: var(--rule) !important; background-color: var(--card) !important; padding-right: 4px; }
/* 手机菜单里的字号钮 */
.fs-opt-m { font-family: var(--ui-sans); letter-spacing: 0; border-radius: var(--r-md); }
.fs-opt { font-family: var(--ui-sans); letter-spacing: 0; }
/* 当按钮用的 pill(筛选 chip / 建议项 / 分段 tab):给悬停和键盘焦点反馈,看得出能点 */
:is(button, a, summary).pill { cursor: pointer; transition: background-color 150ms ease, color 150ms ease; }
:is(button, a, summary).pill:not([class*="pill-"]):hover { background: var(--paper-deep); color: var(--ink); }
:is(button, a, summary).pill:focus-visible { outline: none; box-shadow: var(--ring); }
/* v1.35 · 组件级的可点控件补圆角(定义散在上面各处,统一在这里收口,不逐个改原定义 —— 原定义里的注释是各自的由来) */
.filter-fold > summary, .cat-cell, .cat-chip, .flow-pg, .bkt, .flow-clear, .adm-bar, .danger-zone-btn,
.bf-opt, .tpl-chip, .scope-pill { border-radius: var(--r-md); }
.filter-fold > summary, .flow-clear, .danger-zone-btn { letter-spacing: .02em; }
.flow-clear { font-family: var(--ui-sans); }
/* 2px 墨色粗框的「当前步骤」区块(填报页第一步等)跟卡片同圆角 */
section[class~="border-2"]:not([class*="rounded"]), div[class~="border-2"][class~="border-ink"]:not([class*="rounded"]) { border-radius: var(--r-lg); }
/* 模板里给按钮叠了 tracking-* / font-mono / uppercase 工具类的(Tailwind 后注入会压过 btn 定义)—— 按钮一律无衬线、不加字距、不大写 */
:is(.btn-ink, .btn-paper, .btn-brass, .btn-ghost, .btn-danger, .btn-line):is([class*="tracking-"], .font-mono, .uppercase) {
  letter-spacing: 0; font-family: var(--ui-sans); text-transform: none;
}
/* 弹框(补记到历史期 / 原生 dialog)跟卡片同圆角 */
.bf-dialog { border-radius: var(--r-lg); }
/* 横屏模式的「退出横屏」浮钮 / 帮助页演示里的按钮:跟按钮规格的字体与圆角 */
.ls-exit { font-family: var(--ui-sans); letter-spacing: 0; border-radius: var(--r-md); }
/* 顶栏品牌名旁的存钱罐(v1.35):图形在 viewBox 里偏下,实测比「账房」字身的墨迹中线低 2px —— 拉齐 */
.nav-coin { transform: translateY(-2px); }
/* v1.35.1 · 管理 → 家庭设置:品牌名旁小图标的选择格(并列同尺寸 36×36 · 选中 = 墨边 + 光圈) */
.bm-group { margin-top: 8px; }
.bm-group-label { font-family: var(--ui-sans); font-size: calc(11px * var(--fs-scale,1)); color: var(--ink-subtle); margin-bottom: 4px; }
.bm-opt { width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--rule-soft); border-radius: var(--r-md); background: var(--card); color: var(--brass-deep);
  cursor: pointer; transition: background-color 150ms ease, border-color 150ms ease, box-shadow 150ms ease; }
.bm-opt:hover { background: var(--paper-soft); border-color: var(--rule); }
.bm-opt[aria-pressed="true"] { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink); background: var(--card); }
.bm-opt:focus-visible { outline: none; box-shadow: var(--ring); }
.bm-opt[disabled] { opacity: .5; cursor: wait; }

/* ══════════════════════════════════════════════════════════════════════════════
   v1.37 · iPhone Duo 侧边操作栏(html.vp-rail)与折痕避让(html.vp-fold)
   判据唯一出处在 layout.html 头部(VP_RAIL_SHAPE_Q / VP_FOLD_Q),这里只认类名 —— 护栏 v137-RAIL-ONE-SOURCE。
   苹果 HIG:外屏和内屏横向时,顶部、底部的操作挪到右侧一列(灵动岛 → 状态栏 → 工具栏 → 标签栏);
   只有内屏竖向保留横向顶栏。半折时按钮、弹层离开中间折痕;网格优先偶数列。
   ══════════════════════════════════════════════════════════════════════════════ */
:root { --rail-w: 52px; --rail-pad: 0px; }
html.vp-rail { --rail-pad: calc(var(--rail-w) + env(safe-area-inset-right)); }
.side-rail { display: none; }
html.vp-rail .side-rail {
  display: flex; flex-direction: column; align-items: center;
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 9990;
  width: var(--rail-pad);
  padding: calc(10px + env(safe-area-inset-top)) env(safe-area-inset-right) calc(10px + env(safe-area-inset-bottom)) 0;
  background: var(--card-soft); border-left: 1px solid var(--rule);
}
/* 内容让出侧边栏;页头不再吸顶(品牌名和版本跟着内容滚走),右侧那组按钮和右下浮钮都进了侧边栏 */
html.vp-rail body { padding-right: var(--rail-pad); }
html.vp-rail header { position: relative !important; top: 0 !important;
  /* 页头的毛玻璃(backdrop-filter)会给里面的 position:fixed 当包含块 —— 侧边栏就被关在页头盒子里了(实测右边缘差一个侧边栏宽)。
     侧边栏模式下页头不吸顶,也就不需要毛玻璃 */
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }
html.vp-rail header .nav-actions,
html.vp-rail #float-dock,
html.vp-rail .ask-fab { display: none !important; }   /* 宽屏那颗「超级 Agent」药丸也收进侧边栏(实测内屏横时压住了「更多」) */
html.vp-rail .toc-sheet { right: var(--rail-pad); }
.side-rail .rail-g { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.side-rail .rail-gap { flex: 1; min-height: 8px; }
.rail-btn {
  width: 40px; height: 40px; border-radius: var(--r-md); border: 0; background: transparent;
  display: flex; align-items: center; justify-content: center; position: relative;
  color: var(--ink-soft); cursor: pointer; list-style: none; -webkit-tap-highlight-color: transparent;
}
.rail-btn svg { width: 19px; height: 19px; }
.rail-btn:active { background: var(--rule-soft); }
.rail-btn.on { background: var(--ink); color: var(--paper); }
.rail-btn:focus-visible { outline: none; box-shadow: var(--ring); }
.rail-badge {
  position: absolute; top: 3px; right: 1px; min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: 8px; background: var(--rust); color: #fff;
  font: 600 9px/15px var(--ui-sans); text-align: center;
}
.rail-more > summary { list-style: none; }
.rail-more > summary::-webkit-details-marker { display: none; }
.rail-more[open] > summary { background: var(--ink); color: var(--paper); }
.rail-more-panel {
  position: fixed; top: 0; bottom: 0; right: var(--rail-pad);
  width: min(300px, calc(100vw - var(--rail-pad) - 24px)); overflow-y: auto;
  padding-top: env(safe-area-inset-top);
  background: var(--card); border-left: 1px solid var(--rule); box-shadow: -10px 0 28px rgba(0,0,0,.14);
}
/* 太矮(外屏横握)放不下 → 账户 / 报表先收进「更多」(苹果:从下往上收;填报和隐私眼最后才收) */
@media (max-height: 439px) {
  html.vp-rail .rail-tabs a[aria-label="账户"],
  html.vp-rail .rail-tabs a[aria-label="报表"] { display: none; }
}

/* 内屏横向:平放和半折网页分不出来,一律按「可能半折」排 —— 弹框、目录抽屉、更新提示开在右半边,
   奇数列网格改偶数列,中线落在列缝(苹果:prefer an even number of columns · 弹层半折时滑到一侧)。 */
html.vp-fold dialog[open] {
  margin: auto calc(var(--rail-pad) + 16px) auto calc(50vw + 20px) !important;
  max-width: calc(50vw - 36px - var(--rail-pad)) !important;
}
html.vp-fold .upd-modal { left: calc(50vw + 20px); right: calc(var(--rail-pad) + 16px); transform: none; width: auto; }
html.vp-fold .toc-sheet { left: calc(50vw + 20px); }
html.vp-fold .md\:grid-cols-3,
html.vp-fold .sm\:grid-cols-3:not([class*="md:grid-cols-"]) { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
html.vp-fold .md\:grid-cols-5 { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; }

