/* ============ 个人记账 APP · 全局样式 ============ */
/* 色值单一真源：themes.css（皮肤令牌）。此处只保留「结构变量」与过渡期兜底。
   → 新增颜色一律用 themes.css 里的令牌，不要在这里加色值。 */
:root{
  /* 结构尺度（与皮肤无关） */
  --fab-h:58px; --topbar-h:52px;
  /* ★ 白皮书 v2.0 圆角档位：xs2 / sm6(按钮) / md10(卡片) / lg14 / xl20 / full */
  --radius:10px;        /* 卡片 md 10pt（原 14） */
  --radius-sm:6px;      /* 按钮/输入 sm 6pt（原 10） */
  --radius-lg:14px;     /* 大容器 lg 14pt（原 16） */

  /* 间距标尺（4 的倍数） */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px;

  /* 触控基线：WCAG / Material 建议 44px */
  --tap-min:44px;

  /* ★ 第三批：手势点阵**唯一规格**（解锁层与设置页共用；原来两套）*/
  --pd-size:56px; --pd-gap:18px; --pd-dot:15px;
  /* hero 上「达标 / 未达标」数值色（原硬编码在 .rv-hero-sub 里）*/
  --hero-pos:#7be3bc; --hero-neg:#ffb0a6;

  /* 图表语义色（由皮肤派生；无 JS 时用兜底）
     ★ A1 方案二（Fred 2026-10-08 定）：**色值不变、语义重绑** ——
       收入=浅红 / 支出=浅绿 / 结余=浅蓝（A 股口径：涨红跌绿）。
       三个色值仍是原来的 #ee7c74 / #5ec98d / #5eaee8，只是各自换了主人；
       浅色审美（真机 25 轮定稿）完全保留。 */
  --chart-grid:rgba(106,116,136,.16);
  --chart-axis:#6a7488;
  --chart-inc:#ee7c74; --chart-exp:#5ec98d; --chart-bal:#5eaee8;
  --chart-1:#0f62d0; --chart-2:#d97706; --chart-3:#0e9f6e; --chart-4:#6d28d9;
  --chart-5:#c9302c; --chart-6:#0e7490; --chart-7:#be185d;

  /* 兜底：若 themes.css 未加载，页面仍可读（正常情况会被 themes.css 覆盖） */
  /* ★ 第 81 轮：页面底色改白皮书 §1.1 的 --bg-page=#F7F8FA（原 #eaeef5 偏蓝偏深，
     真机反馈「底色是灰的、图标和背景融为一体」的根因之一）。 */
  --bg:#F7F8FA; --card:#ffffff; --card-2:#ffffff; --text:#1b2434; --sub:#6a7488;
  --line:#e3e8f0; --fill:#f1f4f9; --fill-2:#e6ebf3;
  /* ★★ 第 91 轮（Fred「不能与效果图不一致」）：**行分隔线**（比 `--line` 更浅的那一档）。
     它是效果图里的 `--line2`，product 侧**从来没定义过** —— 于是
     `.pf-row` / `.pg-mx tbody td` / `.pg-debt tbody td` / `tr.future` 四处的
     `border-top:1px solid var(--line2)` 全部是**无效声明**（var 无 fallback ⇒ 整条丢弃），
     表格行之间一条线都没有，整页比效果图「平」一大截。这就是真因。
     判据见 `S91-B`（扫 CSS：不许有「用了但没定义」的 var）。 */
  --line2:#F1F4F8;
  /* ★ 第 90 轮（Fred 反馈④「空白输入框的提示文字不要加粗、颜色浅点」）：
     **提示文字色**是独立角色 —— 它不是 `--sub`（次级文字，要用来看清），
     而是「这个框是空的」的信号，必须比 `--sub` 更浅、且**恒不加粗**。
     放中性层：10 套皮肤底色都是浅色，浅灰提示在谁身上都成立 ⇒ 皮肤不派生它。 */
  --ph:#C9CFD8;
  /* ★ 第 82 轮：图标圆牌的 1px 圈线色（方案 B）。写成「主色 24% + 卡片色」的淡蓝，
     随皮肤自动派生（本文件在 themes.css 之前，:root 与 [data-theme=x] 同挂 <html>，
     故 var(--primary)/var(--card) 在 html 上解析时取的已是皮肤值）。 */
  --ic-ring: color-mix(in srgb, var(--primary) 24%, var(--card));
  --primary:#0f62d0; --primary-w:#e4eefb; --primary-d:#0b3a7e; --primary-l:#3d84e2;
  --primary-on:#ffffff; --primary-btn:#0f62d0;
  /* 收入/支出统一指到图表语义色（一处改、全站生效） */
  --income:#ee7c74; --expense:#5ec98d; --transfer:#0f62d0; --adjust:#6d28d9;
  /* 功能色对齐白皮书：成功 #16A34A / 错误 #DC2626 / 警告 #D97706 */
  --danger:#DC2626; --warn:#D97706; --ok:#16A34A;
  --hero-from:#1560c4; --hero-to:#0b3a7e; --hero-sub:#b9d0f5;
  /* hero 卡内收支色随语义互换（收入浅红 / 支出浅绿） */
  --hero-in:#ffd0cb; --hero-out:#7ce0b5;
  /* ★ 第 88 轮 S4：hero 上的「半透明层」三件套。9 套皮肤全是深底白字 ⇒ 默认值是
     「暗底抹一层黑 + 白线 + 白头像底」；**香槟金是亮底深字**，这三样必须整体翻过来
     （白底白线 = 看不见），由 themes.css 的 m01 块覆盖（见 `gen-themes.py` 的 EXTRA）。 */
  --hero-scrim:rgba(0,0,0,.16);          /* 统计条底（.ov-mestat）/ 分类胶囊（.ah-cat） */
  --hero-scrim-strong:rgba(0,0,0,.30);   /* 连续记账徽章底（效果图给的就是 .30，比统计条更强） */
  --hero-line:rgba(255,255,255,.18);     /* 统计条竖向分隔线 */
  --hero-av-bg:rgba(255,255,255,.22);    /* 身份区头像底色 */
  --hero-av-fg:inherit;                  /* 身份区头像字色（默认跟着 hero 文字色） */
  --income-w:#fdecec; --expense-w:#e7f6f1; --danger-w:#fdecec; --warn-w:#fff7e8; --ok-w:#e7f6f1;
  /* 阴影三档（白皮书）：xs 键面 / sm 卡片 / lg 浮层 */
  --shadow-xs:0 1px 2px rgba(16,24,40,.06);
  --shadow:0 1px 3px rgba(16,24,40,.05), 0 3px 12px rgba(16,24,40,.06);
  --shadow-lg:0 6px 28px rgba(16,24,40,.16);
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0}
body{
  font-family:-apple-system,BlinkMacSystemFont,"HarmonyOS Sans SC","PingFang SC","Microsoft YaHei",system-ui,sans-serif;
  background:var(--bg); color:var(--text); font-size:15px; line-height:1.5;
  padding-bottom:calc(var(--fab-h) + env(safe-area-inset-bottom) + 24px);
  min-height:100vh; overflow-x:hidden;
}
button{font-family:inherit;border:none;background:none;cursor:pointer;color:inherit}
input,select,textarea{font-family:inherit;font-size:16px;color:var(--text)}
::-webkit-scrollbar{width:0;height:0}

/* ---------- 底部导航（v3.1 单轴 5 槽：资产/报表/＋/贷款/我的） ---------- */
.bottombar{
  position:fixed;bottom:0;left:0;right:0;height:calc(var(--fab-h) + env(safe-area-inset-bottom));
  z-index:49;display:grid;grid-template-columns:repeat(5,1fr);align-items:stretch;
  background:var(--card);border-top:1px solid var(--line);
  padding:0 4px env(safe-area-inset-bottom);
}
.bnb{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;color:var(--sub);padding:4px 0;min-height:var(--tap-min)}
.bnb .bnb-ic{display:flex;align-items:center;justify-content:center;height:20px;line-height:1}
.bnb .bnb-ic svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.bnb .bnb-lb{font-size:11px;font-weight:500}
.bnb.on{color:var(--primary)}
.bnb.on .bnb-lb{font-weight:700}
.bnb-add{position:relative}
.bnb-add .fab-plus{
  width:46px;height:46px;border-radius:50%;margin-top:-26px;
  background:var(--primary-btn);color:var(--primary-on);
  display:flex;align-items:center;justify-content:center;
  font-size:28px;font-weight:400;line-height:1;
  box-shadow:0 6px 18px color-mix(in srgb, var(--primary) 40%, transparent);transition:transform .15s;
}
.bnb-add:active .fab-plus{transform:scale(.94)}
/* 中央槽「账单」态（非记账页）：去掉悬浮圆底，改为常规槽位样式 */
.bnb-add[data-mode="bill"]{color:var(--sub)}
.bnb-add[data-mode="bill"] .bnb-ic{display:flex;align-items:center;justify-content:center;height:20px;line-height:1}
.bnb-add[data-mode="bill"] .bnb-ic svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.bnb-add[data-mode="bill"] .bnb-lb{font-size:11px;font-weight:500}

/* ---------- 页面与卡片 ---------- */
/* ★ 底部留白必须避开**固定底栏**（.bottombar 高 --fab-h = 58px）。
   原来只留 8px ⇒ 页尾最后一行说明被底栏压住（A3 盘点截图 14-me 可见实证）。
   统一留「底栏高 + 16px 余量」，一改全站生效，不必逐页补 padding。 */
.page{max-width:760px;margin:0 auto;padding:12px 12px calc(var(--fab-h) + 16px);animation:fadeIn .2s}
@keyframes fadeIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
.card{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);margin-bottom:12px;overflow:hidden}
.card-pad{padding:16px}
.sec-title{font-size:15px;font-weight:700;color:var(--text);margin:16px 4px 8px;display:flex;justify-content:space-between;align-items:center}
.sec-title .link{color:var(--primary);font-size:13px;font-weight:500}
.sec-title .sec-r{font-size:11px;color:var(--sub);font-weight:400}

/* 摘要卡 */
.summary{
  background:linear-gradient(135deg,var(--hero-from) 0%,var(--hero-to) 100%);
  /* ★ 第 88 轮 S3：文字色改由 --hero-fg 决定（--primary-on 只是兜底）。
     --primary-on 的语义是「亮档实心块（--primary-btn）上的前景色」；香槟金是**亮底深字**
     hero，两者语义不同 —— 混用会让整张 hero 的字色跟着实心块走。 */
  color:var(--hero-fg,var(--primary-on));
  border-radius:var(--radius-lg);padding:13px 14px 12px;
  position:relative;overflow:hidden;margin-bottom:var(--sp-3);box-shadow:var(--shadow-lg);
}
/* 主位（资产页 .net 净资产 / 记账页 .bal 本月结余 —— 同一视觉组件，H4 约定记账页不用 .net） */
.summary .net,.summary .bal{display:flex;align-items:baseline;gap:7px;min-width:0}
/* 账户详情：hero 左侧放反白圆牌 —— 必须把 baseline 改成 center，否则 40px 圆牌与文字错位 */
.summary .net.has-ic{align-items:center;gap:9px}
.summary .net.has-ic .lbl{font-size:15px;font-weight:600;opacity:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.summary .net.has-ic .num{margin-left:auto}
.summary .net .lbl,.summary .bal .lbl{font-size:12px;opacity:var(--hero-dim,.72);flex:none}
/* 结余主位：独占一行，24px 可撑到千万级不折行（规范 §5.2，禁 overflow-wrap 断金额）
   v3.6（真机第 5 轮反馈③「顶端太臃肿」）：26→24px，摘要卡整体 130→约 104px */
.summary .net .num,.summary .bal .num{font-size:24px;font-weight:700;letter-spacing:.2px;min-width:0;white-space:nowrap;font-variant-numeric:tabular-nums}
/* v9（真机第 13 轮反馈①）：资产/负债页摘要只留主行 —— 主数 = 总资产/总负债（无 ¥），净资产降级为小字。
   .sm 只作用于该页；贷款/资产负债表/账户详情页仍是「主数 + .metric 多列」结构，故不给它们加 .sm
   v15（真机第 23 轮反馈②）：净资产**换行到第二行左缘**。
   根因：.num 是 flex:0 1 auto + min-width:0，nowrap 文本会被压到比自身内容还窄
   （实测 "12,354,678.90" 只分到 158px，而它实际要 171px）→ 溢出的数字直接盖在右侧「净资产」上，
   金额越大叠得越狠。让 .net-sub 独占整行（flex-basis:100%）后两行彻底分开，不再有可叠的余地；
   去掉 margin-left:auto 它就落在第二行**左缘**（Fred 要的「左下角」）。 */
.summary.sm .net{flex-wrap:wrap;row-gap:2px}
.summary.sm .net .net-sub{
  flex:0 1 100%;margin-left:0;min-width:0;white-space:nowrap;
  font-size:12px;opacity:var(--hero-dim,.8);font-variant-numeric:tabular-nums;
}
.summary.sm .net .net-sub b{font-size:13px;font-weight:600;letter-spacing:.2px}
/* v16（真机第 24 轮反馈①）：负债页的同结构占位 —— 保留盒高（等高于资产页）但不可见。
   两态卡片等高，切「资产 ⇄ 负债」时顶端不再跳。 */
.summary.sm .net .net-sub.ph{visibility:hidden}
.summary.sm{padding:11px 14px 10px}
.summary.sm .net .lbl{font-size:13px;opacity:.85}
/* 净资产块移入「资产」页后，摘要卡首个元素即 .metric，故首块不再留顶距 */
.summary .metric{display:flex;margin-top:9px;gap:var(--sp-3)}
.summary .metric:first-child{margin-top:0}
.summary .metric>div{flex:1 1 0;min-width:0}          /* min-width:0 是长数字不撑破容器的关键 */
.summary .metric .m-lbl{font-size:11px;opacity:var(--hero-dim,.7);white-space:nowrap}
/* 收支次级：两列小字，金额用 −/+ 语义，不再与结余抢视觉 */
.summary .metric .m-val{
  font-size:15px;font-weight:600;margin-top:2px;
  font-variant-numeric:tabular-nums;                  /* 数字等宽，避免跳动 */
  min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.35;
}
/* ★ 第 88 轮批 3（Fred 真机反馈①）：收支两列**不再上色**，一律跟 hero 文字色走。
   为什么不写死 `#fff`：**香槟金是亮底深字**（`--hero-fg:#3B2A06`），白字压浅金底＝看不见。
   改白之后收支怎么分：收入带 `+`、支出带 `−`（`money()` 本身就带符号，见 util.js），
   左右位置也不同 —— 信息一点没丢，只是不再用颜色重复表达一次。
   ⚠️ `--hero-in`/`--hero-out` 两个令牌因此在本文件内**不再被引用**（皮肤里仍然生成着，
      效果图 v4 还在用）—— 别急着删令牌，删了得同步 `gen-themes.py`。
   ⚠️ 贷款页（`.summary.loan-sum`，见下面那段）第 26 轮就全白了，这次只是把同一条口径铺开。 */
.summary .metric .m-val.in,
.summary .metric .m-val.out{color:var(--hero-fg,var(--primary-on))}
@media (max-width:380px){
  .summary .metric{flex-wrap:wrap;gap:var(--sp-2) var(--sp-3)}
  .summary .metric>div{flex:1 1 45%}
}
/* 账户详情卡的底栏（真机第 53 轮反馈③）：左边「类型」，右边【调账】按钮。
   原来这里是「当前余额 | 类型」两格 —— 余额与卡片右上角重复，已删掉余额那格。
   按钮在**渐变 hero 卡**上，不能用普通 .btn.ghost（深色描边+深字在彩底上很脏），
   改成半透明白底 + 白色描边 + 白字，跟着卡片文字色走。 */
.summary .metric.card-meta{align-items:center}
.summary .metric.card-meta .adj-btn{
  flex:none;margin-left:auto;min-height:32px;padding:5px 14px;font-size:13px;
  background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.42);
  color:inherit;border-radius:var(--radius-sm);font-weight:600;
}
.summary .metric.card-meta .adj-btn:active{background:rgba(255,255,255,.28)}

/* 真机第 26 轮反馈①：贷款页摘要卡**文字全白**。
   原来是「当年待还本息」浅绿 var(--hero-in)、「下一笔到期」浅粉 var(--hero-out)，
   加上 .lbl/.m-lbl 的 opacity .72/.7 —— Fred 要整卡纯白，故色值与透明度一起归一。
   ① 只用 .loan-sum 变体类，别的模块摘要卡不受影响（.summary 被 6 处共用）；
   ② 必须**排在**上面 .summary .net .lbl / .metric .m-val.in 之后：
      .summary.loan-sum .lbl 与 .summary .net .lbl 特异性同为 (0,3,0)，靠源序决胜；
      .summary.loan-sum .metric .m-val.in 是 (0,5,0)，本来就压得住 (0,4,0) 的旧规则。 */
.summary.loan-sum .lbl,
.summary.loan-sum .num,
.summary.loan-sum .m-lbl,
.summary.loan-sum .metric .m-val,
.summary.loan-sum .metric .m-val.in,
.summary.loan-sum .metric .m-val.out{color:var(--hero-fg,var(--primary-on));opacity:1}

/* 提醒条明细（记账页顶部单行条展开后的列表） */
.remind-item{display:flex;align-items:center;gap:10px;padding:7px 0;width:100%;min-width:0;text-align:left}
.remind-item .txt{flex:1;font-size:15px}
.remind-item .amt{font-weight:600}

/* ==========================================================================
   装饰背景系统（第 88 轮 · 纯 CSS/SVG，零位图）
   --------------------------------------------------------------------------
   Fred 定案：「一套皮肤绑一个默认母题，只做 6 个」（母题 = 渐变卡上的背景花纹）。
   令牌值/形状**逐值搬运**效果图定稿 `ui-lab/skins2.css` §B（v4.2，已验收）。

   ★★ 三层分工（改之前先看这张表，别把职责搅在一起）
     `<html data-deco="dN">`   母题名 —— 由 `js/theme.js` 的 `apply()` 从**当前皮肤派生**
                                （m03→d3 / m04→d8 / m06→d2 / m08→d6 / m07→d1 /
                                  m01→d6 / m05→d3 / m10→d6 / m02→d2 / m09→d4）
     `[data-deco-host]`        hero 上的**静态标记** —— 页面模板只写这个，
                                不写母题名（否则 9 个页面各抄一遍皮肤→母题映射表）
     `[data-deco-host="tr"]`   形态变体：母题收进**右上安全区**（见下）

   ★ 为什么母题挂在 `<html>` 而不是 hero 上：hero 是各页面**动态渲染**的，
     挂 hero 就得在每个页面渲染完后再去补属性（还得处理重渲染）；挂 `<html>` 只需
     切皮肤时改一次，CSS 自己重算 —— 换肤瞬间装饰跟着换，零 JS 参与。

   ★★ `z-index:-1` + `isolation:isolate`（**别照抄效果图的 `> *{z-index:1}`**）
     效果图里给装饰层 `z-index:0` + 给所有子元素 `position:relative;z-index:1` 抬到装饰之上。
     那在 mock 里能用，在产品里是**地雷**：`.summary` 的子元素里有 `position:absolute`
     定位件，被 `> *` 改成 `relative` 会直接错位。
     正解：hero 自己 `isolation:isolate` 建栈上下文 ⇒ 装饰层 `z-index:-1` 落在
     「元素自身背景之上、所有常规流内容之下」，**一个字都不用碰子元素**。
     （`.summary` 原本就有 `position:relative;overflow:hidden`，天然是定位上下文 + 裁剪框。）

   ★ 老 WebView 降级：`mask-image` 不支持时装饰整体不显示（形状靠 mask 成形），
     但**品牌渐变、文字、布局全不受影响** —— 装饰是「有则更好」的层。
   ========================================================================== */
[data-deco-host]{position:relative;isolation:isolate}
[data-deco-host]::before{
  content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-repeat:no-repeat;background-position:center;background-size:cover;
  opacity:var(--deco-o,1);
}

/* ── d1 · 大光斑 ────────────────────────────────────────────────────────────
   右侧一块大面积同族压深色（--deco-2）做主体，其上叠两枚亮色光斑（--deco-1）：
   主斑 r35 落右侧空区中央 (84%,46%)，副斑 r12 在其左上方 (70%,37%)。
   ⚠️ 位置是**实测**出来的：徽章占 y8.6–24.2%、结余主数 y38–60% 且 x<62%、
   支出标签 y65.6%、支出值 y78.6–92% ⇒ 主斑圆心 y 不得低于 47%（羽化尾会蹭「支出」标签）。 */
[data-deco="d1"] [data-deco-host]::before{
  background-image:
    radial-gradient(ellipse 88% 172% at 101% 46%, var(--deco-2) 0%, transparent 63%),
    radial-gradient(circle 35px at 84% 46%, var(--deco-1) 0 58%, transparent 76%),
    radial-gradient(circle 12px at 70% 37%, var(--deco-1) 0 56%, transparent 76%);
}

/* ── d2 · 斜向光带（多条 118° 宽带 + mask 把左半文字区渐隐）───────────────── */
[data-deco="d2"] [data-deco-host]::before{
  background-image:repeating-linear-gradient(118deg,
    transparent 0 32px,
    var(--deco-2) 32px 86px,
    transparent 86px 146px);
  -webkit-mask-image:linear-gradient(118deg,transparent 0 22%,#000 52%);
          mask-image:linear-gradient(118deg,transparent 0 22%,#000 52%);
}

/* ── d3 · 云纹·雾（内联 SVG 云朵剪影做 mask，竖向渐变填色）────────────────────
   mask 用的 SVG 是 `data:` URI，**单引号包字符串原样落地** ——
   别再手动转义一遍（铁律 `L-esc`：多转义一层 ⇒ 图线全空）。 */
[data-deco="d3"] [data-deco-host]::before{
  background-image:linear-gradient(180deg, var(--deco-1) 0 40%, var(--deco-2) 58% 100%);
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z' fill='%23000'/%3E%3C/svg%3E");
          mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z' fill='%23000'/%3E%3C/svg%3E");
  -webkit-mask-size:auto 52%;
          mask-size:auto 52%;
  -webkit-mask-position:96% 46%;
          mask-position:96% 46%;
  -webkit-mask-repeat:no-repeat;
          mask-repeat:no-repeat;
}

/* ── d4 · 星野（一颗大「星球」+ 三组错位小星点，全部同族压深色）───────────── */
[data-deco="d4"] [data-deco-host]::before{
  background-image:
    radial-gradient(circle 30px at 83% 40%, var(--deco-2) 0 86%, transparent 100%),
    radial-gradient(circle 3px at 50% 50%, var(--deco-2) 0 100%, transparent 100%),
    radial-gradient(circle 2px at 50% 50%, var(--deco-2) 0 100%, transparent 100%),
    radial-gradient(circle 1.4px at 50% 50%, var(--deco-2) 0 100%, transparent 100%);
  background-size:100% 100%, 70px 56px, 104px 88px, 132px 112px;
  background-position:0 0, 0 0, 26px 22px, 50px 11px;
  background-repeat:no-repeat, repeat, repeat, repeat;
  -webkit-mask-image:linear-gradient(90deg,transparent 0 42%,#000 68%);
          mask-image:linear-gradient(90deg,transparent 0 42%,#000 68%);
}

/* ── d6 · 同心波纹（7px 粗弧 / 30px 周期，圆心推到右下角外；右上留一枚柔光）── */
[data-deco="d6"] [data-deco-host]::before{
  background-image:
    repeating-radial-gradient(circle at 108% 118%,
      transparent 0 9px,
      var(--deco-2) 9px 16px,
      transparent 16px 30px),
    radial-gradient(circle 54px at 92% 40%, var(--deco-1) 0%, transparent 72%);
  -webkit-mask-image:linear-gradient(90deg,transparent 0 34%,#000 62%);
          mask-image:linear-gradient(90deg,transparent 0 34%,#000 62%);
}

/* ── d8 · 极光·深空（m04 专属，按 Fred 认可的历史稿「反解」重做）──────────────
   ① 大面积柔辉：中心 (78%,34%)、r44px；② 126° 宽柔斜带；③ 五枚星点（半径 2.6–4.8px）。
   ★★ 位置百分比 + **px 半径**是硬性要求（第 88 轮返工两次的根因）：
     · 用 `ellipse 15% 31%`：椭圆两轴分别按**卡宽/卡高**取百分比 ⇒ 卡一矮（资产页
       `.summary.sm` 只有 82px）圆就被压扁（Fred：「光球变形了」）；
     · 改成 `circle 26%`：**CSS 规范里 `circle` 的半径只接受 `<length>`，不接受百分比**
       ⇒ 整条 `background-image` 被**静默丢弃**，装饰直接没了。
   ⇒ 现在统一 px 半径：82 / 124 / 125px 三种 hero 高度下**都是正圆**。
   ★ 兼容：`--deco-3`/`--deco-4` 只有 m04 定义 ⇒ 其余 9 套自动回落 `--deco-2`，
     仍是「同族压深做形」（`var(--deco-3, var(--deco-2))` 两个参数都要留着）。 */
[data-deco="d8"] [data-deco-host]::before{
  background-image:
    radial-gradient(circle 44px at 78% 34%, var(--deco-3,var(--deco-2)) 0%, transparent 72%),
    linear-gradient(126deg, transparent 26%, var(--deco-3,var(--deco-2)) 44% 54%, transparent 74%),
    radial-gradient(circle 4.8px at 85.0% 49.7%, var(--deco-4,var(--deco-2)) 0 100%, transparent 100%),
    radial-gradient(circle 4.2px at 63.3% 46.0%, var(--deco-4,var(--deco-2)) 0 100%, transparent 100%),
    radial-gradient(circle 3.6px at 72.8% 32.9%, var(--deco-4,var(--deco-2)) 0 100%, transparent 100%),
    radial-gradient(circle 3.0px at 92.1% 34.9%, var(--deco-4,var(--deco-2)) 0 100%, transparent 100%),
    radial-gradient(circle 2.6px at 67.7% 58.7%, var(--deco-4,var(--deco-2)) 0 100%, transparent 100%);
  -webkit-mask-image:linear-gradient(90deg,transparent 0 50%,#000 74%);
          mask-image:linear-gradient(90deg,transparent 0 50%,#000 74%);
}

/* ── 形态变体 `tr`：母题收进右上安全区（右侧 38% × 上 52%）────────────────────
   默认形态假设「hero 文字是左对齐单列」，亮/压深块落**右侧中部空区**。
   两类 hero 破了这个前提：**贷款页**底部是满宽三格（第三格正落在右侧空区）、
   **我的页**底部是满宽三格统计条 ⇒ 母题铺满必压文字（实测白字 CR 15.26 → 3.40）。
   ⇒ 收进右上小盒：那里两页都是空的，母题照样看得见。
   ⚠️ 选择器必须写 `[data-deco] [data-deco-host="tr"]`（含 `[data-deco]`）：
     母题规则是 `[data-deco="dN"] [data-deco-host]`，特异性 (0,2,0)；
     若这里只写 `[data-deco-host="tr"]`（0,1,0）就**压不住母题自带的方向 mask**
     （内联 SVG / 90deg 渐隐会留在小盒里，形被切掉一半）—— 等特异性 + 排最后才赢。
     同时**前缀两个都要写**：d1/d3/d6/d8 用的是 `-webkit-mask-image`。
   ⚠️ 小盒已避开文字 ⇒ 去掉母题自带的方向 mask。
   ★★ 这里用**以右上角为心的径向柔化**（四边都柔），不用「单向下缘渐隐」：
      后者在小盒里会露出一条硬左边 / 硬底边 —— 形状靠 mask 做的母题（d3 云纹 / d6 波纹 /
      d2 斜带）遮罩一被换掉，填色就铺满整个盒子，看着像**贴了一个方块**。
      效果图上也是方块（不是移植错），但那个观感是稿子的疏漏，这里按柔化处理。
      ⇒ **要回效果图那一版**：把下面两条 `mask-image` 换成
         `linear-gradient(0deg,transparent 0 10%,#000 34%)` 即可（一行）。 */
[data-deco] [data-deco-host="tr"]::before{
  inset:0 0 auto auto;width:38%;height:52%;
  -webkit-mask-image:radial-gradient(125% 130% at 100% 0%,#000 0 42%,transparent 80%);
          mask-image:radial-gradient(125% 130% at 100% 0%,#000 0 42%,transparent 80%);
}

/* ==========================================================================
   S4 · 4 处新增 hero 结构（第 88 轮 · 按效果图 v4.2 落地）
   --------------------------------------------------------------------------
   ① 首页概览卡 `.ov-overview > .summary`（新）  ② 报表结论前置卡 `.summary`（新）
   ③ 我的页身份区 `.ov-medata`（新）            ④ 流水详情金额条 `.ov-amt-hero`（新）

   ★★ 两处**必须照抄的数值来源**：效果图定稿时 Fred 提过「首页 / 我的页顶端卡片太高」，
     于是 v4 里把这两个 hero 单独**瘦身**（`.phone[data-theme^="m"]` 那段覆盖）。
     落到产品里就是写死下面这些尺寸 —— **别用 lab.css 的原始大尺寸**，那是瘦身前的。
   ★ 负外边距：`.page` 的内边距是 `12px`，所以「整宽色带」（我的页 / 流水详情）
     用 `margin:-12px -12px 12px` 才能贴到屏幕左右与顶部（效果图就是这么贴边的）。
   ========================================================================== */

/* ── ① 首页概览卡 ─────────────────────────────────────────────────────────── */
.ov-overview{margin:0 0 var(--sp-3)}
.ov-overview .summary{margin-bottom:0;padding:8px 14px}
/* ★ 第 88 轮批 3（Fred 真机反馈②）：原来这里有一行 `.ov-sum-top`（左「2026 年 10 月」+ 右徽章），
   整行已删 —— 卡片矮一整行（约 20px）。徽章改与「本月结余」同行（`margin-left:auto` 顶到右边）。
   `align-items:baseline` 要让位给 `center`：徽章有 padding，baseline 对齐会上下错位。 */
.ov-overview .net{align-items:center;gap:8px}
.ov-overview .net .ov-streak{margin-left:auto}
/* 连续记账徽章：新用户 0 天时**整枚不渲染**（渲染函数负责），别在这里靠 CSS 藏 */
.ov-streak{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:600;
  padding:2px 8px;border-radius:999px;background:var(--hero-scrim-strong);
  color:var(--hero-fg,var(--primary-on));flex:none}
.ov-streak svg{width:10px;height:10px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
/* 概览卡的主数字号与标签：比通用 .summary 更小（瘦身版），故都用 `.ov-overview` 限定 */
.ov-overview .net .lbl{font-size:11px}
.ov-big{font-size:28px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:.2px;
  line-height:1.15;white-space:nowrap}
.ov-big .dec{font-size:18px;font-weight:700}
.ov-overview .ov-big{font-size:25px;line-height:1.05}
.ov-overview .ov-big .dec{font-size:16px}
.ov-overview .metric{margin-top:5px}
.ov-overview .metric .m-lbl{font-size:10.5px}
.ov-overview .metric .m-val{font-size:14px;margin-top:1px;line-height:1.3}

/* ── ③ 我的页身份区（整宽色带，底角圆）────────────────────────────────────── */
.ov-medata{background:linear-gradient(135deg,var(--hero-from) 0%,var(--hero-to) 100%);
  color:var(--hero-fg,var(--primary-on));
  margin:-12px -12px 12px;padding:12px 16px;border-radius:0 0 20px 20px;
  position:relative;overflow:hidden;isolation:isolate}
.ov-meid{display:flex;align-items:center;gap:12px;width:100%;min-width:0;
  background:none;border:0;padding:0;font:inherit;color:inherit;text-align:left;cursor:pointer}
.ov-meid .mi-av{width:44px;height:44px;border-radius:50%;background:var(--hero-av-bg);
  color:var(--hero-av-fg);display:flex;align-items:center;justify-content:center;
  font-size:18px;font-weight:600;flex:none;overflow:hidden}
/* 头像可能是图片（paintAvatar 会往里塞 <img>）：圆内裁切，别撑破圆 */
.ov-meid .mi-av img{width:100%;height:100%;object-fit:cover;display:block}
.ov-meid .mi-bd{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}
.ov-meid .chev{flex:none}
.ov-meid .mi-n{font-size:16px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ov-meid .mi-s{font-size:11px;opacity:var(--hero-dim,.88);margin-top:1px}
.ov-mestat{display:flex;margin-top:9px;background:var(--hero-scrim);border-radius:10px;padding:7px 0}
.ov-mestat .ms-cell{flex:1;text-align:center;min-width:0}
.ov-mestat .ms-cell+.ms-cell{border-left:1px solid var(--hero-line)}
.ov-mestat .ms-v{font-size:14px;font-weight:700;font-variant-numeric:tabular-nums}
.ov-mestat .ms-l{font-size:10px;opacity:var(--hero-dim,.85);margin-top:1px}
/* ★★ 整宽色带的负外边距**必须跟着 `.page` 的内边距走**（第 88 轮审查 M-1）：
   本文件 724 行的桌面断点把 `.page` 改成 `padding:24px 20px 40px`，
   若色带仍用 -12px，宽屏下四周会漏出一圈底色、只剩三边贴边。
   ⇒ 断点变了这里必须跟着变（改 `.page` 内边距时请 grep `ov-medata`）。 */
@media (min-width:960px){
  .ov-medata{margin:-24px -20px 12px}
}

/* ── ④ 流水详情金额条 ───────────────────────────────────────────────────────
   ⚠️ 这里**不是**效果图 lab.css 里的「整宽无圆角版」：产品这一页顶部有 `.phead`
     （返回 + 标题），金额条是标题下面的**一张圆角卡**（效果图 txn.html 末稿用的
     正是 `margin:0 0 12px;border-radius:14px` 那个内联样式版本）。 */
.ov-amt-hero{padding:20px 16px 18px;text-align:center;border-radius:var(--radius);
  background:linear-gradient(135deg,var(--hero-from) 0%,var(--hero-to) 100%);
  color:var(--hero-fg,var(--primary-on));margin:0 0 12px;
  position:relative;overflow:hidden;isolation:isolate}
.ov-amt-hero .ah-cat{display:inline-flex;align-items:center;gap:5px;font-size:12px;opacity:.94;
  background:var(--hero-scrim);padding:3px 11px;border-radius:999px}
.ov-amt-hero .ah-ci{width:13px;height:13px;display:inline-flex;flex:none}
.ov-amt-hero .ah-ci svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.ov-amt-hero .ah-v{font-size:34px;font-weight:700;font-variant-numeric:tabular-nums;
  margin-top:10px;letter-spacing:.3px;line-height:1.1}
.ov-amt-hero .ah-v .dec{font-size:22px}
.ov-amt-hero .ah-t{font-size:12px;opacity:var(--hero-dim,.9);margin-top:6px}

/* 快捷宫格 */
.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:2px;padding:6px 4px}
.grid-item{display:flex;flex-direction:column;align-items:center;gap:5px;padding:10px 4px;font-size:12px;color:var(--sub)}
.grid-item .gi-ic{width:42px;height:42px;border-radius:14px;background:var(--primary-w);display:flex;align-items:center;justify-content:center;font-size:20px}

/* 流水列表 */
.txn-day{display:flex;align-items:center;justify-content:space-between;padding:8px 4px 2px}
.txn-day .d{font-size:13px;font-weight:600}
.txn-day .s{font-size:12px;color:var(--sub)}
/* 列表行：button 作行容器时必须显式 width:100% + min-width:0，
   否则按钮不会收缩到父宽以下（默认 min-width:auto），长金额会把行撑出屏幕。 */
.row{display:flex;align-items:center;gap:12px;padding:11px 14px;border-bottom:1px solid var(--line);text-decoration:none;color:inherit;width:100%;min-width:0;text-align:left}
.row:last-child{border-bottom:none}
.row:active{background:var(--fill)}
/* 退出登录行（第 87 轮：我的 → 点头像后的页面）—— 标题走危险色；
   本机模式没有账号体系 ⇒ 按钮 disabled：标题退回次要色 + 降透明度（点了没反应最伤人） */
.row.danger .t1{color:var(--danger)}
.row:disabled{opacity:.55}
.row.danger:disabled .t1{color:var(--sub)}
/* 全站统一图标：圆形主色浅底（规范 §6，禁彩色装饰底） */
/* 账户卡（资产页 / 每月资产页共用）：**一账户一张独立小卡**（v4.0 按参考图版式）。
   类名沿用 .acc-row（页面与测试都按它选择），但不再与 .row 配用；
   图标走 .acc-ic（见「图标统一画法」）。 */
/* 卡片间距 9→7px（真机第 53 轮反馈⑤，与 .acc-row 降高同一目的）：
   行高 + 间距共同决定「一屏能看几个账户」，间距降 2px × N 行同样省出可见行数。 */
.acc-list{display:flex;flex-direction:column;gap:7px;margin-bottom:12px}
/* ⚠️ user-select / -webkit-touch-callout 是**必须**的（真机第 39 轮反馈②）：
   .cat-lrow 一直有这两条，账户行漏了 → 真机长按 0.5s 起拖之前，浏览器已经先把
   「选中文字」启动了，整块名字/金额被蓝底反白高亮，用户看到的就是「长按只会选中文字」。
   长按起拖的组件**必须**显式关掉选择与系统长按菜单，不能指望它不发生。
   ★ 真机第 41 轮补：**光靠 CSS 不够** —— Android 浏览器「长按起文本选择 + 系统菜单」
   是原生手势，不查 user-select（探针实测桌面 Chrome 长按 3.5s 恒选不中，真机照选）。
   故 CSS 是**第一道闸**，JS 事件层拦截（public/js/ui/noSelect.js）是**第二道闸**，缺一不可。
   -webkit-user-drag:none 顺带掐掉长按被当成拖拽源（会拖出文字/链接的幽灵图）。 */
.acc-row{display:flex;align-items:center;gap:12px;width:100%;min-width:0;text-align:left;
  background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);padding:5px 14px;
  transition:transform .16s ease;
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;-webkit-user-drag:none}
/* 账户行降高（真机第 53 轮反馈⑤：「账户一多就要划来划去」）：
   原来 padding 12px + 图标 40px → 一行约 64px；账户多时一屏只放得下 5~6 个。
   现在 padding 5px + 行内图标 36px → 一行约 54px（−16%），一屏多出约 2 行。
   ⚠️ **不能再低**：拖动柄 .acc-grip 的触控区是 44px（--tap-min 基线，44 是手指下限），
      5 + 44 + 5 = 54px 就是当前版式的物理地板。想更矮只能砍掉拖动柄或改两行式版式，
      那是改交互而不是改高度，得单独定。
   图标只在**账户行内**缩到 36px：.acc-ic 是全局 40px（表单/宫格/详情 hero 都在用），不能动全局。 */
.acc-row .acc-ic{width:36px;height:36px}
.acc-row .acc-ic svg{width:20px;height:20px}
/* 长按锁（真机第 46 轮反馈①，与 public/js/ui/noSelect.js 的第四/五道闸配套）：
   手指按在「长按区」上的这段时间，把全站临时标成不可选 —— 目的是让浏览器在**长按超时之前**
   就把内容判成不可选，从源头不建立选区（选区的原生浮层「复制/分享/全选/搜索/翻译」是浏览器
   自己画的，JS 关不掉它，只能不让它出现）。
   ⚠️ 只在按住期间存在（pointerdown 加、pointerup/cancel 摘）：输入框的长按选词/粘贴是正常操作，
      抬手后立刻恢复正常。类挂在 <html> 上，所以选择器从 html.hold-lock 起写。 */
html.hold-lock,html.hold-lock *{user-select:none !important;-webkit-user-select:none !important;-webkit-touch-callout:none !important}
.acc-row:active{transform:scale(.985)}
.acc-bd{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;line-height:1.32}
.acc-t1{font-size:15px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.acc-t2{font-size:12px;color:var(--sub);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:1px}
.acc-amt{font-size:16px;font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap;flex:none;margin-left:auto;letter-spacing:.2px}
/* 账户行拖动排序（v52 真机第 39 轮反馈③）：手柄照 .cat-lgrip —— 视觉 16px、触控区 44px；
   margin-right:-10px 是**刻意**的（把它顶进卡片原有 14px 右内边距里），
   但不能再往外，否则触控区贴到 Android 手势导航的「边缘返回」带，真机按住会没反应。
   注意 .acc-amt 已有 margin-left:auto，手柄要**跟在其后**才发现得住；故把 amt 的 auto 让给本体。 */
.acc-grip{width:44px;height:44px;flex:none;display:flex;align-items:center;justify-content:center;
  margin-right:-12px;color:var(--sub);touch-action:none;cursor:grab}
.acc-grip svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}
/* 拖动中：被拖行浮起（transition:none —— 换位时 transform 归零，带过渡会「飘」一下不跟手）；
   只解除列表这层裁剪，页面滚动容器不动。
   ⚠️ 底色必须用 --mg 混到不透明：.acc-row 自带 `background:var(--card)`（**是不透明底层**），
   直接写 `background:var(--primary-w)` 盖不住它 —— 浅色皮肤下两者的差只有一点点，
   真机上「拖起来了没」几乎看不出来。用 color-mix 把主色浅底与卡片色混成**不透明**的高亮，才真的浮起来。 */
.acc-row.dragging{background:color-mix(in srgb, var(--primary) 12%, var(--card));position:relative;z-index:3;
  box-shadow:var(--shadow-lg);transition:none;cursor:grabbing}
.acc-row.dragging .acc-grip{cursor:grabbing}
.acc-list.drag-host{overflow:visible}
.row .bd{flex:1 1 auto;min-width:0}
.row .bd .t1{font-size:15px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
.row .bd .t2{font-size:12px;color:var(--sub);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
.row .amt{font-weight:600;font-size:16px;white-space:nowrap;flex:none;font-variant-numeric:tabular-nums;max-width:50%;overflow:hidden;text-overflow:ellipsis}
/* ★ B1（2026-10-08）：**列表金额一律黑** —— 白皮书只允许报表上色。
   收支方向由 +/− 号表达，不用颜色。类名保留（JS 继续用），只把颜色收回 inherit。
   同步改动的还有 `.kv-row .v.in/.out`（弹层 kv 行）。
   ⚠️ 报表类**保留上色**：.pl-cmp/.rv-arows/.tbx/.tf-amt.in 不动。 */
.amt.in,.amt.out,.amt.tf,.amt.adj{color:inherit}
.amount-hero{font-size:32px;font-weight:700;text-align:center;margin:8px 0 4px;font-variant-numeric:tabular-nums}

/* 按钮：统一 44px 触控基线（WCAG / Material 建议） */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:var(--tap-min);padding:10px 18px;border-radius:var(--radius-sm);
  font-size:15px;font-weight:600;transition:.15s;white-space:nowrap;
}
.btn.primary{background:var(--primary-btn);color:var(--primary-on)}
.btn.primary:active{background:var(--primary-d)}
.btn.ghost{background:var(--card);border:1px solid var(--line);color:var(--text)}
.btn.danger{background:var(--danger-w);color:var(--danger);border:1px solid var(--danger-w)}
.btn.block{width:100%}
.btn:disabled{opacity:.45}
/* sm：仍保留 44px 触控高度，只收窄左右内边距与字号，不再降到 28px */
.btn.sm{min-height:var(--tap-min);padding:8px 14px;font-size:13px;border-radius:var(--radius-sm)}

/* chips 快捷分类 */
.chips{display:flex;flex-wrap:wrap;gap:8px}
.chip{padding:6px 13px;background:var(--fill);border-radius:999px;font-size:13px;display:flex;align-items:center;gap:5px;transition:.12s;border:1px solid transparent;white-space:nowrap}
.chip.on{background:var(--primary-btn);border-color:var(--primary-btn);color:var(--primary-on);font-weight:600}
.chip .ci{font-size:16px}

/* 行内按钮组（真机第 26 轮反馈②）：贷款页顶部三个按钮原来走专属的 .qrow/.qbtn
   （42px / 字号 15px / 圆角 12px），与全应用按钮基准不一致。
   现统一改用 .btn 家族（.btn.sm：min-height 44px 触控基线、字号 13px、圆角 --radius-sm），
   本类只负责「等分一行」这个布局职责 —— 不给按钮加任何视觉样式。
   左右内边距收到 8px 是为了让「提前还款策略」6 个字在 360px 屏的三等分格里也放得下
   （6×13px=78 + 16 = 94 ≤ (328−16)/3 = 104），与模块其它按钮的底色/圆角/字重/字号完全一致。 */
.btn-row{display:flex;gap:8px;margin:0 0 14px}
.btn-row>.btn{flex:1;min-width:0;padding-left:8px;padding-right:8px}

/* 表单 */
.field{margin-bottom:12px}
.field label{display:block;font-size:13px;color:var(--sub);margin-bottom:5px}
/* ★★ 第 81 轮（Fred 定案 **D-30**）：**所有输入框统一 44pt / 16sp**。
   改前：`.input` 靠 padding 撑到 43px / 15px；`.input-lg` 是 52px / **20px / 加粗 600 / 居中**。
   同一屏里两种尺寸并存 ⇒ 末级页面里那个大框比上一页正文大一大截，正是 Fred 截图指的那处。
   现在 `.input-lg` 与 `.input` **只差「居中 + 600 字重」**，金额框不再是"大一号"的框。
   ⚠️ 金额框**保留居中** —— 这是**有意偏离**白皮书 §2.2.1 的「52pt / 右对齐 + 等宽」，
       Fred 原话「还款金额还是要居中」，别按白皮书改回去（见 decisions.md D-30）。 */
.input,.select,textarea.input{
  width:100%;height:44px;padding:0 12px;border:1px solid var(--line);border-radius:10px;background:var(--card);outline:none;
  font-size:16px;font-family:inherit;color:var(--text);transition:border .15s;
}
textarea.input{height:auto;padding:10px 12px;line-height:1.5}
/* ★★ 占位符：全站**此前一条规则都没有**（只有下面的 `.nl-input::placeholder`）⇒ 占位提示
   继承了输入框自己的 font-size / font-weight —— 框越大字越粗，看着就是「提示文字又大又黑又粗」。
   这是 Fred 反馈② 的**直接根因**，补一条规则就能修。
   ★ 第 90 轮反馈④：颜色从 `--sub`（次级文字色，偏深）换成 **`--ph`（提示专用浅灰）** ——
   用户看到「空框里的提示跟真值一样黑」的直接原因就是这两个角色被混用。
   ⚠️ `font-weight:400` 必须写死：`::placeholder` **会继承 input 自身的 font-weight**，
   参数行 / 首年格子是 600 ⇒ 只改 color 的话提示照样是粗的（实测踩过）。 */
.input::placeholder,.select::placeholder,textarea.input::placeholder,
.pg-mv::placeholder,.pg-fa-a::placeholder{color:var(--ph);font-weight:400;opacity:1}
.input:focus,.select:focus,textarea.input:focus{border-color:var(--primary)}
/* `.input-lg`：只负责「居中 + 加粗」，尺寸交给上面的 `.input`（两者**恒同时挂在一个元素上**）。
   自带 height/font-size/padding 是为了「万一被单独使用」时也不退回浏览器默认样式。 */
.input-lg{height:44px;font-size:16px;font-weight:600;text-align:center;padding:0 12px}
.seg3{display:flex;background:var(--fill-2);border-radius:10px;padding:3px;gap:2px}
.seg3 button{flex:1;padding:7px;border-radius:6px;font-size:15px;color:var(--sub)}
.seg3 button.on{background:var(--card);font-weight:600;color:var(--text);box-shadow:var(--shadow-xs)}
/* 锁定字段（真机第 31 轮反馈④）：贷款编辑里涉及计算的输入置灰、不接受点按。
   置灰本身就是「这里改不了」最直白的说明 —— 比点了再弹一句 toast 好懂。 */
.input:disabled{opacity:.55;background:var(--fill-2);cursor:not-allowed}
.seg3 button:disabled{opacity:.4;cursor:not-allowed}

/* 贷款新建 / 编辑表单：所有控件统一高度（真机第 35 轮反馈⑦）。
   原来一屏里并存 5 种高度：`.input` 43 / `.input-lg` 52 / `.seg3` 39 / `.tf-mini` 40 / `select` 45，
   高高低低很杂乱（Fred：「有一些格子高度太高了很丑」）。
   统一钉到 44px；金额框保留「字大一点 + 居中」的强调，但不再靠 padding 撑高。
   只在这个表单里生效 —— `.input-lg` 是全局金额输入样式（账户 / 计算器都在用），不能动全局。 */
.lf-form .input,.lf-form select.input,.lf-form .tf-mini,.lf-form .seg3{height:44px}
.lf-form .input{padding:0 12px}
.lf-form .input-lg{font-size:16px;padding:0}
.lf-form .tf-mini{min-height:0;padding:0 10px}
.lf-form .seg3{padding:3px}
.lf-form .seg3 button{height:100%;padding:0;display:flex;align-items:center;justify-content:center;min-width:0}
/* 四选一（还款方式含「等本等息」，真机第 53 轮加、第 55 轮**改回单行**）。
   第 53 轮曾改成 2×2（.seg3.seg-wrap），理由是「四个 4 字标签挤一行字号会掉到 12px 以下」
   —— 第 55 轮实测推翻了这个假设：弹层内宽 724px 时，四个按钮各 175×40、字号仍是 14px，
   点按区远超 44px 高，完全没有挤压。Fred 也说两行「很丑」。
   故 .seg-wrap 一并撤除，还款方式回归单行；`.lf-form .seg3{height:44px}` 的定高压制
   也随之不再需要（那条存在的唯一理由就是防两行被压出重叠，见第 53 轮的踩坑记录）。 */

/* 弹层 */
/* 层叠约定：页面 < .fab(80) < modal-full 全屏表单(110) < overlay 底部弹层(120) < toast(200) < busy(300)。
   弹层必须盖过全屏表单 —— 记一笔内选账户/全部分类打开的 sheetList 也是 overlay。 */
.overlay{position:fixed;inset:0;background:rgba(15,20,30,.45);z-index:120;display:flex;align-items:flex-end;animation:ovIn .18s}
@keyframes ovIn{from{opacity:0}to{opacity:1}}
.sheet{background:var(--card);width:100%;max-width:760px;margin:0 auto;border-radius:20px 20px 0 0;padding:14px 16px calc(18px + env(safe-area-inset-bottom));max-height:92vh;overflow-y:auto;animation:shIn .22s}
@keyframes shIn{from{transform:translateY(40px);opacity:.4}to{transform:none;opacity:1}}
.sheet-title{font-size:16px;font-weight:700;text-align:center;margin:4px 0 12px;position:relative}
.sheet .x{position:absolute;right:0;top:0;font-size:20px;color:var(--sub);width:34px;height:34px}
.modal-full{position:fixed;inset:0;background:var(--bg);z-index:110;display:flex;flex-direction:column;animation:fadeIn .18s}
.modal-full .mf-head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;background:var(--card);border-bottom:1px solid var(--line)}
.mf-head .mf-title{font-size:16px;font-weight:700}
/* 弹层头部的三栏槽（真机第 29 轮反馈⑤）：左返回 / 中标题 / 右「设置」。
   两侧槽**同宽**才能让标题真居中；右侧没内容时也保留占位（.ph-side 空着），
   否则标题会被左侧返回按钮挤偏。 */
.modal-full .mf-head>.ph-side{width:44px;min-width:44px;display:flex;align-items:center;justify-content:flex-end}
.mf-side-btn{font-size:15px;font-weight:600;color:var(--primary);height:40px;padding:0 2px;white-space:nowrap}
/* v3.3：顶部常驻「保存」——备注聚焦时底部键盘区会整体撤掉（#txnForm.no-kp，第 63 轮起是 display:none，
   连占位一起消失），确定键跟着消失，故在头部补一个始终可见的保存入口（真机反馈②） */
.mf-save{font-size:15px;font-weight:600;color:var(--primary);min-width:52px;height:40px;text-align:right;padding:0 2px}
.mf-save:disabled{color:var(--sub)}
.mf-body{flex:1;overflow-y:auto;padding:14px}
.mf-foot{padding:10px 14px calc(12px + env(safe-area-inset-bottom));background:var(--card);border-top:1px solid var(--line)}
.icon-x{font-size:24px;color:var(--sub);width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center}

/* 数字键盘（v3.9 起是 4 列 4 行连算键盘：7 8 9 ⌫ / 4 5 6 ＋ / 1 2 3 － / 空 0 . 确定）
   v3.8 的 5 行版把 ÷ × C ＝ 也铺成键，真机反馈「太高、按不顺手」→ 收敛回 4 行：
   只留 ＋ － 两个运算符，＝ 的结算并入右下角「确定」。数字仍是 3×3 九宫格、位置不变，
   左下角空一格（.kp-key.blank 透明占位），免得 0 被挤到第 1 列。 */
.keypad{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;padding:2px 0}
/* ★ 真机第 62 轮反馈②：分类只能看到 3 行，Fred 要「至少看到 4 行」。
   键盘区是最大的可压缩项（4 行 × 46 + 3 × 6 间距 = 202），压到 40 高可省 24px；
   连同 .mf-foot 的内边距一起收（见下），把省出的高度让给分类网格。
   ★★ 2026-10-08 A2（Fred 定：键盘按白皮书调）：**只动字号/字重/颜色/底色**——
     数字 21sp/500、运算符 17sp 用 #3D4453、确定键 600；键高 38px、gap 6px、
     内边距一律不动（实测这三项一变就会顶掉分类可见行数，见 tools 实测记录）。
     白皮书标称键高 48pt（紧凑 40pt）、间距 7pt —— 与现状的差异保留，属功能取舍。 */
.keypad{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;padding:2px 0;background:var(--fill)}
.kp-key{height:38px;border-radius:9px;background:var(--card);box-shadow:var(--shadow-xs);font-size:21px;font-weight:500;display:flex;align-items:center;justify-content:center}
.kp-key:active{background:var(--fill-2)}
.kp-key.del{font-size:17px;color:#3D4453}
.kp-key.op{font-size:17px;color:#3D4453}
.kp-key.ok{background:var(--primary-btn);color:var(--primary-on);font-size:15px;font-weight:600}
.kp-key.ok:active{background:var(--primary-d)}
.kp-key.blank{background:transparent;box-shadow:none}

/* 服务断开提示条（贴在底部导航上方） */
.offline-bar{
  position:fixed;left:0;right:0;z-index:48;
  bottom:calc(var(--fab-h) + env(safe-area-inset-bottom));
  background:var(--danger-w);color:var(--danger);border-top:1px solid var(--danger-w);
  font-size:13px;padding:8px 14px;text-align:center;line-height:1.4;
}

/* 分组卡 */
.group-h{display:flex;align-items:center;gap:8px;padding:12px 14px 6px;font-size:15px;font-weight:700}
.group-h .g-badge{font-size:12px;color:var(--sub);font-weight:500;margin-left:auto}
/* ★ 可点徽标（第 71 轮反馈②：月度收支「按大类汇总」改成可切换）——
   在 .g-badge 的纯展示样式上加可点性：补内边距撑出 32px 触摸高度、
   给一层浅底 + 描边以示「这是个按钮」、换色为 --primary、按压有反馈。
   ★ 必须显式写 background/border：<button> 有 UA 默认底与边框，不覆盖会顶掉 .g-badge 的裸文样式。
   ★ 第 72 轮（Fred 反馈①）：只用浅底**仍然看不出能点** —— 实测真机就是这个反馈。
     这次一次性补齐四重可点标识：
       ① 换色到 --primary（和旁边灰字标题拉开层级）；
       ② 加 1px 描边（按钮轮廓，不再是「一坨灰底」）；
       ③ 前置一个 ⇄ 换向图标（语义上直接说「可切换」）；
       ④ 后缀一个 › 尖角（朝右小箭头＝可进入/可展开的通用暗示）。
     四者都是**静态**可见的（不依赖 hover），触屏上才有意义。 */
.group-h .g-badge.clickable{display:inline-flex;align-items:center;gap:4px;
  background:color-mix(in srgb,var(--primary) 9%,var(--card));border:1px solid color-mix(in srgb,var(--primary) 26%,var(--card));
  color:var(--primary);font-weight:700;border-radius:10px;
  padding:4px 9px;margin-right:-2px;cursor:pointer;font-family:inherit;
  -webkit-tap-highlight-color:transparent;transition:background .12s}
.group-h .g-badge.clickable:active{background:color-mix(in srgb,var(--primary) 20%,var(--card))}
.group-h .g-badge.clickable .gb-swap{width:12px;height:12px;flex:none;stroke:currentColor;fill:none;
  stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.group-h .g-badge.clickable .gb-cue{font-size:13px;font-weight:700;opacity:.75;line-height:1;margin-top:-1px}

/* 空态 */
/* ── 空状态（A3·2026-10-08：统一为「线性插图 + 主辅文案 + 动作按钮」）──
   插图：64px 浅底圆 + 32px 主色线性图标 —— 与全站图标同一画法，不再用 emoji
   （emoji 是彩色位图，改不了颜色、与线性图标族打架）。
   文案：主文案 16px / 正文色（说清「现在是什么状态」），辅助说明 13px / 次要色（说清「能做什么」）。
   动作：可选一颗主色按钮 .e-act，把用户直接推向下一步，别让空态变成死胡同。
   注：次级分组的「一行字」空态不用本类（见 .sec-empty）。 */
.empty{padding:38px 16px;text-align:center;color:var(--sub)}
.empty .e-ic{width:64px;height:64px;border-radius:50%;background:var(--primary-w);color:var(--primary);border:1px solid var(--ic-ring);
  display:flex;align-items:center;justify-content:center;margin:0 auto 12px}
.empty .e-ic svg{width:32px;height:32px}
.empty .e-t{font-size:16px;color:var(--text);font-weight:500;line-height:1.5}
.empty .e-s{margin-top:8px;font-size:13px;color:var(--sub);padding:0 24px;text-align:center;line-height:1.6}
.empty .e-act{margin-top:16px}

/* toast */
#toastRoot{position:fixed;top:0;left:0;right:0;display:flex;flex-direction:column;align-items:center;z-index:200;pointer-events:none;padding-top:12vh}
.toast{background:rgba(20,26,38,.92);color:var(--on-solid);padding:9px 18px;border-radius:20px;font-size:15px;margin-top:8px;max-width:82vw;animation:fadeIn .2s}

/* 标签/徽标 */
.pill{display:inline-block;padding:1px 8px;border-radius:10px;font-size:12px;background:var(--fill);color:var(--sub)}
.pill.warn{background:var(--warn-w);color:var(--warn)}
.pill.red{background:var(--danger-w);color:var(--danger)}

/* 金额 tabular / 表格 */
table.plain{width:100%;border-collapse:collapse;font-size:13px}
/* ★ 第 88 轮批 4：表头带由中性 `--fill` 改**皮肤派生**（`--tbx-hd-bg/fg`，见本文件 .tbx 段）。
   为什么必须改：年度收支（报表）、还款计划（贷款详情）、试算结果（贷款计算器）三张表都用
   `table.plain`，而 `--fill` 是**全 10 套共用的中性层**（#f1f4f9 偏蓝）⇒ 切皮肤时表头一动不动，
   报表/资产两页因此「完全没有皮肤元素」（Fred 真机反馈③④）。
   文字色一并改 `--tbx-hd-fg`（= 皮肤深档）而不是原来的 `--sub`：`--sub` 压在主色浅底上
   某几套皮肤只有 4.47:1，差一点点破线（实测 m04 的 --primary-w 上）。 */
table.plain th{position:sticky;top:0;background:var(--tbx-hd-bg);font-weight:600;color:var(--tbx-hd-fg);padding:8px 6px;text-align:right;white-space:nowrap;z-index:1}
table.plain th:first-child,table.plain td:first-child{text-align:left}
table.plain td{padding:7px 6px;text-align:right;border-bottom:1px solid var(--line);white-space:nowrap;font-variant-numeric:tabular-nums}
/* 真机第 58 轮反馈②：年度收支表的「月份」列原本吃满 1/4 宽度（表格 width:100% ＋ auto 布局，
   而「9月」只有两个字），右边的金额列反而挤。auto 布局下光给 width 没用 —— 浏览器会把
   富余宽度**按比例分摊**回各列（实测给了 60px 仍渲染成 101.6px）。改为 fixed 布局：
   首列定死 56px（最长内容「12月」≈39px ＋ 左右各 6px padding = 51px，留 5px 余量），
   其余三列平分剩余宽度，比例稳定、不再随文字长短漂移。 */
#yearTbl{table-layout:fixed}
#yearTbl th:first-child,#yearTbl td:first-child{width:56px}
.num{font-variant-numeric:tabular-nums}
.ok{color:var(--ok)} .bad{color:var(--danger)} .warn{color:var(--warn)}

/* 详情页通用 */
.sub-card{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);margin-bottom:12px;padding:14px}
.kv{display:flex;justify-content:space-between;padding:7px 0;font-size:15px;border-bottom:1px dashed var(--line)}
.kv:last-child{border-bottom:none}
.kv .k{color:var(--sub)}
.kv .v{font-weight:500;text-align:right}
.hbar{display:flex;align-items:center;gap:8px;margin-bottom:10px}
.hbar .title{font-size:16px;font-weight:700;flex:1}
.hbar .sub{font-size:12px;color:var(--sub)}

/* 开关 */
.switch{width:44px;height:26px;border-radius:999px;background:var(--line);position:relative;transition:.18s;flex:none}
.switch::after{content:'';position:absolute;width:20px;height:20px;border-radius:50%;background:var(--card);top:3px;left:3px;transition:.18s;box-shadow:0 1px 3px rgba(0,0,0,.2)}
.switch.on{background:var(--primary)}
.switch.on::after{left:21px}
/* 开关行：左侧说明、右侧开关；整行可点（触控 44px） */
.sw-row{display:flex;align-items:center;gap:12px;min-height:44px}
.sw-row .sw-lb{flex:1;min-width:0;font-size:15px;line-height:1.35}
.sw-row .sw-lb small{display:block;font-size:12px;color:var(--sub);margin-top:3px;line-height:1.45}

/* 桌面断点：底部导航居中保留（v3.1 单轴导航，无左侧栏） */
@media (min-width:960px){
  .bottombar{max-width:560px;left:50%;transform:translateX(-50%);border-radius:18px 18px 0 0;box-shadow:0 -4px 20px rgba(23,33,55,.08)}
  .page{max-width:900px;padding:24px 20px 40px}
}

/* ============ M2 账本 UI 增补 ============ */
.no-scroll{overflow:hidden}

/* 二级分段已移除（v1 真机反馈 item 3：页面切换统一到底部导航） */

/* 选项列表（底部选择） */
.opt-list{display:flex;flex-direction:column;gap:2px;margin-top:2px}
/* ★ 第 75 轮：分组小标题（转账的账户选择：资金账户 / 应收待收 / 应付待还）。
   字号小、灰、不占位感 —— 它的作用是「让用户知道下面这排是什么」，不是另一个按钮。 */
.opt-grp{padding:10px 6px 4px;font-size:12px;color:var(--sub);letter-spacing:.04em}
.opt-grp:first-child{padding-top:2px}
.opt-row{display:flex;align-items:center;gap:12px;width:100%;min-width:0;padding:12px 6px;border-radius:10px;text-align:left}
.opt-row:active{background:var(--fill)}
/* ⋯ 菜单图标与 .tl-ic/.ri-ic 同族（规则集中在「图标统一画法」一处），
   子类只给尺寸 —— v4.0 起 sheetList 的 icon 由 catIconSvg() 统一转 SVG */
.opt-row .or-bd{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.35}
.opt-row .or-t1{font-size:15px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.opt-row .or-t2{font-size:12px;color:var(--sub)}
.opt-row .or-ok{color:var(--primary);font-size:16px;font-weight:700;flex:none}
.opt-row.on{background:var(--primary-w)}
.opt-row.on .or-t1{color:var(--primary)}
.opt-row.danger .or-t1{color:var(--danger)}
.opt-row.dis{opacity:.42;pointer-events:none}
.opt-empty{padding:22px;text-align:center;color:var(--sub);font-size:15px}

/* 确认/提示弹层底部按钮 */
.dlg-text{font-size:15px;color:var(--text);padding:2px 4px 4px;line-height:1.6}
.dlg-actions{display:flex;gap:8px;margin-top:16px}
/* ★ 第三批：同一行按钮**等宽平分** —— 此前「取消」按内容自适应、主按钮 flex:1 撑满，
   一行里宽窄悬殊，是 Fred 反馈「按钮别扭」的一处。 */
.dlg-actions>.btn,.dlg-actions>button{flex:1 1 0;min-width:0;box-sizing:border-box}
/* ↑ box-sizing 必须显式写：幽灵/危险按钮带 1px 边框、主按钮没有，内容盒下同组会差 2px */
.btn.danger-solid{background:var(--danger);color:var(--on-solid)}

/* 繁忙遮罩 */
.busy-ov{position:fixed;inset:0;z-index:300;display:flex;align-items:center;justify-content:center;background:rgba(15,20,30,.35)}
.busy-box{background:var(--card);border-radius:14px;padding:20px 26px;display:flex;flex-direction:column;align-items:center;gap:12px;font-size:15px;color:var(--sub);min-width:130px;box-shadow:var(--shadow-lg)}
.spin{width:30px;height:30px;border-radius:50%;border:3px solid var(--line);border-top-color:var(--primary-btn);animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

/* 筛选条 */
.filter-bar{display:flex;align-items:center;gap:8px;padding:0 14px 6px}
.fb{flex:1;min-width:0;background:var(--fill);border:1px dashed var(--line);color:var(--sub);border-radius:14px;padding:6px 12px;font-size:13px;display:flex;align-items:center;gap:4px;text-align:left}
.fb-lbl{color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fb-clear{width:26px;height:26px;border-radius:50%;background:var(--fill-2);color:var(--sub);font-size:13px;flex:none;display:flex;align-items:center;justify-content:center}

/* 加载更多 / 到底 */
.load-more{display:block;width:100%;padding:13px;color:var(--primary);font-size:15px;font-weight:600;text-align:center}
.end-tip{padding:16px;text-align:center;color:var(--sub);font-size:12px}

/* ---------- 记账页：顶部单行提醒条（v3.3，压成一行 44px） ---------- */
/* 真机第 50 轮反馈⑥：左侧加「搜索」，提醒挪到**正中间**。
   用 grid 40px | 1fr | 40px 而不是 flex —— flex 下中间项靠 flex:1 只会「占据剩余空间」，
   两侧宽度一旦不等中间就偏了；grid 的三列才真的把中间钉在正中。 */
.flow-bar{display:grid;grid-template-columns:40px 1fr 40px;align-items:center;gap:8px;padding:0 2px 4px}
/* 真机第 60 轮反馈②：记一笔保存后会自动滚到「那一天」做高亮，顶栏（查找/今日提醒/日历）
   跟着滚出屏幕，看着像被顶掉了。改成 sticky 常驻顶部 —— 时间轴从它下面滚过，顶栏恒在。
   background 必须不透明（页面底色），否则流水会从底栏透上来。
   层叠 20：低于 .offline-bar(48)/.bottombar(49)/.fab(80)/弹层(110+)，只压住页面内容。 */
.ledger-flow #flowRemind{position:sticky;top:0;z-index:20;background:var(--bg)}
.flow-remind{min-width:0;height:44px;display:flex;align-items:center;justify-content:center;gap:8px;padding:0 2px}
.flow-remind .rem-lb{font-size:12px;color:var(--sub);flex:none}
.flow-remind .rem-txt{font-size:15px;color:var(--text);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.flow-remind.none .rem-txt{color:var(--sub)}
.flow-remind .rem-n{font-size:12px;color:var(--sub);flex:none}
.flow-remind .rem-cv{width:14px;height:14px;flex:none;fill:none;stroke:var(--sub);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:transform .18s ease}
.flow-remind.open .rem-cv{transform:rotate(180deg)}
.rem-dot{width:8px;height:8px;border-radius:50%;flex:none}
.rem-dot.red{background:var(--danger)}
.rem-dot.warn{background:var(--warn)}
/* 顶栏左右两个圆形图标钮（搜索 / 日历）—— 同尺寸，中间的提醒才是正的 */
.flow-ic{width:40px;height:40px;border-radius:50%;background:var(--fill-2);color:var(--text);display:flex;align-items:center;justify-content:center;flex:none}
.flow-ic svg{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.rem-list{padding:2px 4px 4px}

/* ---------- 记账页：搜索态（真机第 50 轮反馈⑥） ---------- */
/* 搜索时整条顶栏换成「输入框 + 取消」。不用弹层，是因为键盘弹出后弹层只剩很窄一条可视区。 */
.flow-bar.search{grid-template-columns:1fr auto;gap:8px}
.flow-input{display:flex;align-items:center;gap:6px;height:40px;padding:0 10px;border-radius:20px;background:var(--fill-2);min-width:0}
.flow-input .fi-ic{width:17px;height:17px;flex:none;display:flex;color:var(--sub)}
.flow-input .fi-ic svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}
.flow-input input{flex:1;min-width:0;border:0;background:transparent;font-size:15px;color:var(--text);outline:none;padding:0}
/* 系统自带的那个小叉在 Android 上是深色实心块、跟皮肤打架 → 关掉，用自己画的 */
.flow-input input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
.flow-input .fi-x{width:22px;height:22px;border-radius:50%;background:var(--line);color:var(--sub);font-size:16px;line-height:1;display:flex;align-items:center;justify-content:center;flex:none}
.flow-input .fi-x[hidden]{display:none}
.flow-cancel{height:40px;padding:0 6px;font-size:15px;color:var(--primary);flex:none}
/* 搜索结果的摘要行：把「搜了什么 / 搜的多长时间 / 共几笔」摆明，
   否则用户看到一长串结果无法判断这是全部还是被时间窗截断了 */
.search-sum{padding:2px 4px 6px;font-size:12px;color:var(--sub)}
/* （.empty 系列已上移到 404 行统一维护，此处旧的重复定义已删） */


/* ---------- 流水时间轴（v3.3 记账页，直接铺底无卡片，PRD §3.4）---------- */
/* 结构：1px 轴线 + 图标骑线 + 日期胶囊严格居中；支出在右、收入在左；金额统一正文色 */
.ledger-flow{padding-bottom:26px}
.timeline{position:relative;padding:2px 0}
.timeline::before{content:'';position:absolute;left:50%;top:0;bottom:0;width:1px;margin-left:-.5px;
  background:var(--line);background:color-mix(in srgb, var(--sub) 26%, transparent)}
.tl-day{position:relative}
/* 真机第 30 轮反馈③：记账保存后定位到该日 → 短暂高亮，说明「记到这一天了」。
   用 ::after 铺一层主色淡底，不参与行盒计算、不影响任何既有尺寸。 */
/* ★ 第 88 轮批 3（Fred 真机反馈⑤）：这里原本有一条 `.tl-day.focus-day::after` —— 保存后给
   那一天套一个主色 13% 的圆角块 + 1.8s 淡出（真机第 30 轮反馈③ 加的「高亮」）。现在**删掉**：
   保存后只保留「平滑滚到那一天」，不再套框（Fred 原话：只要跳转到对应日期即可）。
   ⚠️ `.focus-day` 这个**类**必须留着：`focusDate()` 仍然加它，两处断言
      （`ui-components` 的 V30-3 / V60-2）也拿它当「跳到哪一天了」的定位标记 ——
      删类会同时废掉定位判据与守卫。这里只是**不再有视觉效果**。 */
.tl-head{position:relative;height:46px}
.tl-date{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:var(--card);color:var(--sub);
  font-size:11px;font-weight:500;padding:3px 10px;border-radius:10px;z-index:1;white-space:nowrap}
.tl-sum{position:absolute;top:50%;transform:translateY(-50%);font-size:12px;color:var(--sub);font-variant-numeric:tabular-nums;
  white-space:nowrap;max-width:calc(50% - 46px);overflow:hidden;text-overflow:ellipsis;z-index:1}
.tl-sum.in{right:calc(50% + 32px);text-align:right}
.tl-sum.out{left:calc(50% + 32px)}
.tl-body{display:flex;flex-direction:column}
.tl-item{position:relative;display:flex;align-items:center;min-height:54px;padding:5px 0}
/* ── 图标统一画法（第 82 轮改定：**浅蓝圆底 + 主色线性 + 1px 淡蓝圈线** = 方案 B）──
   圆底：var(--primary-w) 浅蓝；图形：var(--primary) 主色**线性描边**（1.7，几何见 ui/catIcon.js + ui/iconLib.js）。
   为什么从第 81 轮的「白底 + 深墨线」改回来：Fred 看第 81 轮效果后判定「太素、跟默认主题蓝不搭」。
   ★ 第 81 轮的两个根因**不能一起回退**，这里只回退「观感」，保留两个真正的修复：
     ① 页面底色 --bg 保持白皮书 §1.1 的 #F7F8FA（不再回到 #eaeef5）——
        旧版「图标和背景融为一体」的真因是**底色偏蓝**，浅蓝圆牌压在同色系底上才糊；现在底色是中性近白，浅蓝圆牌反而正是「主色身份」的体现。
     ② 选择器/账户图标选择器的**选中态描边保持 var(--primary)** ——
        旧值 --primary-d(#0b3a7e) 就是真机反馈的「图标边框是黑色线」。
   ★ 圈线（--ic-ring）是第 82 轮 Fred 选的方案 B：底色 #F7F8FA 与白卡片都很浅，
     纯浅蓝圆牌在弹层/白卡上边界偏软，加 1px 淡蓝圈线把圆牌「托」起来；24% 是实测既不脏也不抢的值。
   深色皮肤下 --primary-w 为深底、--primary 为亮色图形，对比自动成立，无需按皮肤特调。
   v4.0：账户模块（.ri-ic 列表行 / .acc-ic 账户卡 / .or-ic ⋯菜单）并入同一族 ——
   子类**只写宽高**，底色/图形色/圈线一律由下面这条共享规则给，避免「同一页两套图标」。 */
.tl-ic,.cb-ic,.cat-lic,.cm-ic,.cl-ic,.ri-ic,.acc-ic,.or-ic{
  display:flex;align-items:center;justify-content:center;flex:none;
  border-radius:50%;background:var(--primary-w);color:var(--primary);
  border:1px solid var(--ic-ring);
}
.tl-ic svg,.cb-ic svg,.cat-lic svg,.cm-ic svg,.cl-ic svg{
  width:58%;height:58%;max-width:21px;max-height:21px;
}
.ri-ic,.or-ic{width:34px;height:34px}
.ri-ic svg,.or-ic svg{width:19px;height:19px}
.acc-ic{width:40px;height:40px}
.acc-ic svg{width:22px;height:22px}
/* hero 渐变卡上反白（采纳参考图「白圆牌压彩底」）；实测对比度 10.93:1。
   线性方案下这正好就是「白底 + 主色线性」的同一套观感，只是把图形色换成 --primary-d。
   圈线置透明：白圆牌压在深色渐变上本就分得开，再描一圈淡蓝反而像「贴纸」。 */
.acc-ic.on-hero{background:var(--on-solid);color:var(--primary-d);border-color:transparent}
/* v8 账户自定义色：线性方案下底色取「自定义色 14% + 卡片色」的浅底，图形取自定义色本身
   —— 与全站「浅底 + 主色线性」同构，只是把主色换成该账户自己的色；圈线同理换成该自定义色。
   必须排在 .on-hero 之后：两者特异性同为 (0,2,0)，靠源序覆盖 hero 的「白底主色图形」。 */
.acc-ic.has-c{background:color-mix(in srgb, var(--acc-color) 14%, var(--card));color:var(--acc-color);
  border-color:color-mix(in srgb, var(--acc-color) 34%, var(--line))}
/* 时间轴骑线图标：底色必须**不透明**才能盖住 1px 轴线；线性方案下取「主色 12% + 卡片色」浅底。
   为什么是 12%：再深会退回实底圆牌（与线性图形打架），再浅则图形对比度跌破 3:1。
   直径 32px 是 v3.7 真机反馈「缩小 2px 减重」的结论，本次不动。 */
.tl-ic{--ci-bg:color-mix(in srgb, var(--primary) 12%, var(--card));position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:32px;height:32px;z-index:1;
  background:var(--ci-bg)}
.tl-ic svg{width:18px;height:18px}
.tl-bd{display:flex;flex-direction:column;min-width:0;line-height:1.35}
/* 支出靠中线右侧：margin-left 直接推过中线（flex-start 天然生效）
   收入靠中线左侧：**必须 margin-left:auto** 吃掉剩余空间才会靠右，否则 flex-start 下会贴左边缘
   —— 真机反馈②「收入离时间轴太远」即漏了 auto 所致 */
.tl-item.out .tl-bd{margin-left:calc(50% + 26px);margin-right:0;text-align:left}
.tl-item.in .tl-bd{margin-left:auto;margin-right:calc(50% + 26px);text-align:right}
.tl-line{display:flex;align-items:baseline;gap:7px;min-width:0}
.tl-item.in .tl-line{flex-direction:row-reverse}
.tl-name{font-size:15px;font-weight:500;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tl-amt{font-size:15px;font-weight:500;color:var(--text);white-space:nowrap;font-variant-numeric:tabular-nums;flex:none}
.tl-note{font-size:12px;color:var(--sub);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}
/* 展开态：左删除 / 右编辑
   v3.4（真机第 3 轮反馈①「按钮太大」）：视觉收到 30px，触控区仍用 ::after 撑到 44px 基线。
   同时只展开一行，展开时文字区让位。 */
.tl-act{position:absolute;top:50%;transform:translateY(-50%);width:30px;height:30px;border-radius:50%;
  display:none;align-items:center;justify-content:center;z-index:2;box-shadow:0 1px 3px rgba(0,0,0,.16)}
.tl-act::after{content:'';position:absolute;inset:-7px;border-radius:50%}
.tl-act svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.tl-item.on .tl-act{display:flex}
.tl-act.del{left:2px;background:var(--danger);color:var(--card)}
.tl-act.del.lock{background:var(--fill-2);color:var(--sub);box-shadow:none}
.tl-act.edit{right:2px;background:var(--primary-btn);color:var(--primary-on)}
.tl-item.out.on .tl-bd{padding-right:38px}
.tl-item.in.on .tl-bd{padding-left:38px}

/* 独立日历页（页 ⑯） */
.cal-page .cal-month{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
.cal-page .cal-month .m-t{font-size:15px;font-weight:700}
.cal-day-list{margin-top:10px}
.cal-day-list .cd-title{font-size:13px;font-weight:600;margin:8px 4px 6px;color:var(--sub)}

/* ---------- 报表页（v3.1 4 小节）---------- */
.rp-monthbar,.rp-matrix-nav{display:flex;align-items:center;justify-content:center;gap:14px;margin-bottom:8px}
.rp-monthbar .rp-ym,.rp-ym{font-size:15px;font-weight:700;min-width:78px;text-align:center}
/* ★ 第 88 轮批 4：期间切换圆钮由中性灰（--fill-2）改**皮肤主色浅底** ——
   报表页（收支构成 / 收支趋势 / 分类分析）除了表头之外，就靠它来「看得出是哪套皮肤」。
   分类分析页左侧那枚返回圆牌也用同一个类（.rp-nav.cat-back），一起跟着变。 */
.rp-nav{width:30px;height:30px;border-radius:50%;background:var(--primary-w);color:var(--primary);display:flex;align-items:center;justify-content:center;font-size:16px;flex:none}
.g-badge .rp-monthbar,.g-badge .rp-nav{display:none}
.g-badge .rp-ym{font-size:12px;font-weight:600}
/* 月×分类矩阵：首列固定 + 横向滚动 */
.rp-matrix{overflow-x:auto;-webkit-overflow-scrolling:touch}
/* 月度收支矩阵的旧私有样式（.mm-table / .mm-fix / .mm-sep）已于 2026-09-30 随「整表改用统一
   组件 .tbx」一并删除（类名换成 .tbx / .tfz / .tsep），避免留第二套真源。
   .mm-ic 当时就无人引用，随段一起清掉。 */

/* ---------- 资产模块顶层菜单（v3.2：资产/每月资产/规划/盘点共用）---------- */
/* v3.6（真机第 5 轮反馈③）：行高 42→36px，胶囊 32→30px */
.am-tabs{display:flex;gap:6px;overflow-x:auto;-webkit-overflow-scrolling:touch;
  padding:1px 0 6px;margin:0 -2px;scrollbar-width:none}
.am-tabs::-webkit-scrollbar{display:none}
.am-tab{flex:none;display:inline-flex;align-items:center;padding:4px 12px;border-radius:14px;background:var(--fill-2);color:var(--sub);
  font-size:13px;font-weight:500;white-space:nowrap;min-height:30px}
.am-tab.on{background:var(--primary-btn);color:var(--primary-on);font-weight:600}
/* ---------- 每月资产（页 ⑮，v9：表格化 + 双口径盘点）----------
   版式照效果稿第 8 版落地：五列（科目竖排 / 分类 / 记账口径 / 盘点情况 / 备注），
   卡头「快照日靠左 + 月份切换居中 + 万元靠右」，表尾三行（净资产 + 可用资金两行）。 */
.ma-card{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);margin-bottom:12px;overflow:hidden}
.ma-head{display:flex;align-items:center;padding:0 10px;min-height:44px;position:relative}
/* 月份组真居中靠绝对定位：flex 的 justify-content:center 会被两侧文字挤偏（它们有实际宽度）。 */
.ma-mid{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:flex;align-items:center;gap:6px}
/* ★ 第 88 轮批 4：与报表页 `.rp-nav` 同款 —— 期间切换圆钮改**皮肤主色浅底**，
   让资产负债表 / 快照页除了表头带之外再多一处「一眼认出皮肤」的落点。 */
.ma-nav{position:relative;width:26px;height:26px;border-radius:50%;background:var(--primary-w);color:var(--primary);flex:none;
  display:flex;align-items:center;justify-content:center;font-size:15px;line-height:1;transition:background .16s,color .16s}
.ma-nav::after{content:'';position:absolute;inset:-9px -9px}     /* 触控 26 → 44px */
.ma-nav:active{background:var(--fill-2);color:var(--text)}
.ma-nav[disabled]{opacity:.28}
.ma-ym{font-size:15px;font-weight:700;letter-spacing:-.2px;font-variant-numeric:tabular-nums;white-space:nowrap}
/* 真机第 58 轮反馈③：原来「万元 · 快照日」是**一整块**靠右（.ma-meta），而月份组是绝对定位居中的 ——
   标题是区间时（周期 ≠ 自然月，如 09-16 ~ 10-15）会比自然月标题宽不少，于是月份组右端压到那块文字上。
   实测（390px 视口、周期 16）：.ma-mid 110.6→279.4、.ma-meta 266.5→368 ⇒ **重叠 12.9px**，
   看起来就是「月份切换按钮和万元叠在一起」。
   改为拆成两端：快照日靠左、万元靠右，中间的月份组两边都留出空档。 */
.ma-side{font-size:11px;color:var(--sub);white-space:nowrap;font-variant-numeric:tabular-nums;flex:none}
.ma-side.ma-unit{margin-left:auto;font-weight:700}
.ma-tw{overflow-x:auto;-webkit-overflow-scrolling:touch;padding:0 10px 10px}
/* 表格：table-layout:fixed + colgroup 定列宽。
   border-collapse:separate 是「表头 8px / 表尾 9px 圆角」生效的前提。
   框线三档全由 --sub 与 --card 混出 → 6 皮肤自动适配，不新增色值。 */
.ma-tb{width:100%;table-layout:fixed;border-collapse:separate;border-spacing:0;font-size:12px;
  font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased;
  --mg:color-mix(in srgb,var(--sub) 14%,var(--card));          /* 行横线：极弱 */
  --mg-line:color-mix(in srgb,var(--sub) 22%,var(--card));     /* 列竖线：四条同档 */
  --mg-strong:color-mix(in srgb,var(--sub) 32%,var(--card))}   /* 表头带下缘：最强 */
/* 表头带：--fill 底 + 上下圆角。竖线一律画在「所在格的右缘」——
   表头这侧用 inset shadow 而不是 border-right：border 会吃掉 1px 内容宽，
   把「分类」表头推离与分类名的共线；shadow 不占盒模型，对齐 Δ 保持 0。
   ★ 第 88 轮批 4：底色由中性 `--fill` 改**皮肤派生** `--tbx-hd-bg`，字色改 `--tbx-hd-fg`
     （Fred 真机反馈④：资产负债表「完全没有皮肤元素」）。「科目」竖排列同款 —— 它和表头带
     本来就是同一条色带（效果稿如此），跟着一起走才不脱节。 */
.ma-tb th{font-size:11px;font-weight:700;color:var(--tbx-hd-fg);text-align:right;padding:0 8px;height:34px;
  background:var(--tbx-hd-bg);white-space:nowrap;letter-spacing:.4px;vertical-align:middle;
  border-bottom:1px solid var(--mg-strong);box-shadow:inset -1px 0 0 0 var(--mg-line)}
.ma-tb th:first-child{border-radius:8px 0 0 8px}
.ma-tb th:last-child{border-radius:0 8px 8px 0;box-shadow:none}   /* 末格不画 → 那条是表格外缘 */
.ma-tb th.l{text-align:left}
.ma-tb th.cat{padding-left:11px}                                  /* 与 .c-name 左缘共线 */
.ma-tb td{padding:0 8px;height:40px;border-bottom:1px solid var(--mg);text-align:right;
  vertical-align:middle;white-space:nowrap}
/* 科目列：「资产 / 负债」竖排，一格管一组（rowspan）—— 读起来是侧边标签带 */
.ma-tb td.c-sub{width:32px;writing-mode:vertical-rl;letter-spacing:2px;font-size:12px;font-weight:600;
  color:var(--tbx-hd-fg);text-align:center;vertical-align:middle;padding:0;background:var(--tbx-hd-bg);
  border-right:1px solid var(--mg-line)}
.ma-tb td.c-name{text-align:left;font-size:13px;font-weight:500;overflow:hidden;text-overflow:ellipsis;
  color:var(--text);padding-left:11px;border-right:1px solid var(--mg-line)}
.ma-tb td.c-book{color:var(--sub);font-weight:500;border-right:1px solid var(--mg-line)}
/* 放「块级按钮」的格子必须把 line-height 归零：td 是行内格式化上下文，
   块级按钮外面会套一个匿名行盒，行盒 strut 取 td 的 line-height → 34px 的按钮把行抬到 43px。 */
.ma-tb td.c-cnt{line-height:0;padding:0;border-right:1px solid var(--mg-line)}
.ma-tb td.c-note{line-height:0;padding:0 8px;text-align:left;font-size:12px;color:var(--sub);
  white-space:normal;text-overflow:ellipsis;overflow:hidden}
.ma-pk{display:block;width:100%;min-height:36px;padding:0;text-align:right}
/* 盘点情况列与「记账口径」列**完全同款**（同字号同字重同色）—— Fred 真机第 22 轮反馈③：
   数据不该被强调，让用户自己查。可交互的痕迹只留在「点下去弹出下划线输入框」那一刻。
   （此前 13px + --text 比左侧的 12.5px + --sub 又大又黑，看着像在强调。） */
.ma-num{font-size:12px;font-weight:500;color:var(--sub);text-align:right;font-variant-numeric:tabular-nums}
.ma-in{width:100%;text-align:right;border:none;border-bottom:1.5px solid var(--primary);background:transparent;
  color:var(--sub);font-size:12px;font-weight:500;font-variant-numeric:tabular-nums;padding:0 0 1px;outline:none}
/* 备注列默认「看起来是空的」，但仍要能点开（否则想写备注没地方点）。
   **单行省略号**：写长了就在这一行截断，点开弹层看全文 / 改（Fred 2026-09-16 定）。
   max-height 34px + line-height 34px：按钮不超过行高（行高稳在 40）、文字垂直居中。
   ★ button 不继承 td 的 line-height（UA 声明了 normal）→ 必须显式写；
     UA 内边距 1px 6px 也必须归零，否则备注文字比表头右移 6px。 */
.ma-nb{display:block;width:100%;min-height:34px;max-height:34px;padding:0;text-align:left;font-size:12px;
  line-height:34px;color:var(--sub)}
.ma-note{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 表尾：左侧两格**合并成一格**放标签（净资产 / 可用资金），右侧「记账口径 / 盘点情况」两列
   仍与表体逐列同位 —— 三行数字因此与上方数据同像素带。
   线色档位与表体相同（横线 --mg 档 14% / 竖线 --mg-line 档 22%），
   只是底色是 --fill（比 --card 深一档）→ 必须按 --fill 重混，否则同百分比落到这个底就糊了。
   竖线用 border-right 而不是 inset shadow：border 贯通整格高，与横线交叉处不断点。
   注：原先首行那条 6px 透明 border 是空转的（background-clip 默认 border-box，
   底色照样铺满）—— 它只把首行文字压低 3px，已去掉。 */
.ma-tb tfoot{--mgf:color-mix(in srgb,var(--sub) 14%,var(--fill));--mgf-line:color-mix(in srgb,var(--sub) 22%,var(--fill))}
.ma-tb tfoot td{background:var(--fill);height:38px;font-size:13px;font-weight:700;color:var(--text);
  border-bottom:1px solid var(--mgf);border-right:1px solid var(--mgf-line)}
.ma-tb tfoot tr:last-child td{border-bottom:none}
.ma-tb tfoot td:last-child{border-right:none}
.ma-tb tfoot tr:first-child td:first-child{border-radius:9px 0 0 9px}
.ma-tb tfoot tr:first-child td:last-child{border-radius:0 9px 9px 0}
.ma-tb tfoot tr:last-child td:first-child{border-radius:0 0 0 9px}
.ma-tb tfoot tr:last-child td:last-child{border-radius:0 0 9px 9px}
/* 标签格跨「科目 + 分类」两列：43px = 32px 科目列 + 11px 内边距 → 文字仍与上方分类名共线 */
.ma-tb tfoot td.f-lbl{text-align:left;font-size:13px;font-weight:600;color:var(--text);
  padding-left:43px}
.ma-tb tfoot td.f-lbl small{display:block;font-size:11px;font-weight:500;color:var(--sub);line-height:1.3}
/* 盘点情况列的内边距必须归零：表体那一列是 .c-cnt{padding:0} + 满宽按钮，
   表尾若留 8px 内边距，数字右缘会整体左移 8px，与上方盘点数对不齐（Fred 真机第 22 轮反馈③）。 */
.ma-tb tfoot td.f-cnt{padding:0}

/* 皮肤选择网格（我的页） */
.theme-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
.theme-cell{display:flex;align-items:center;gap:10px;padding:12px;border-radius:var(--radius-sm);background:var(--fill);border:2px solid transparent;text-align:left;min-width:0}
.theme-cell.on{border-color:var(--primary);background:var(--primary-w)}
.theme-cell .tc-dot{width:26px;height:26px;border-radius:50%;flex:none;box-shadow:inset 0 0 0 1px rgba(0,0,0,.08)}
.theme-cell .tc-name{font-size:13px;font-weight:500;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* 表单分组（筛选弹层/内联） */
.f-group{margin-bottom:15px}
.fg-label{font-size:13px;color:var(--sub);margin-bottom:8px;font-weight:600}
.f-inline{display:flex;gap:8px;align-items:center}
.f-inline .input{flex:1;min-width:0}
/* ★ 第三批：.f-inline 里的 .field 一律等宽 —— 原用内联 flex:1.2/1 制造不等宽，
   两列宽度不同本身就是「别扭」的来源（Fred 点名的收款弹层即如此）。 */
.f-inline>.field{flex:1 1 0;min-width:0}
/* 自研日期按钮（替代原生 input[type=date]，见 report 区间选择） */
button.rp-date{text-align:left;background:var(--card);cursor:pointer;font-family:inherit;color:var(--text)}
button.rp-date.is-empty{color:var(--sub)}
.hint{font-size:12px;color:var(--sub);margin:4px 0 8px;line-height:1.5}

/* 迷你分段（报表支出/收入切换） */
.seg-mini{display:inline-flex;background:var(--fill-2);border-radius:15px;padding:2px}
.seg-mini b{display:inline-block;padding:4px 13px;border-radius:14px;font-size:12px;font-weight:500;color:var(--sub);text-align:center}
.seg-mini b.on{background:var(--card);color:var(--primary);font-weight:600;box-shadow:var(--shadow-xs)}

/* 图表卡片 */
.chart-card{min-height:248px;position:relative}
.chart-box{height:220px;position:relative}
/* 年度收支图（v3.8 真机反馈⑤）：绘图区 220→110px；卡片最小高度同步收，否则底部空一大片。
   只作用于年度图（规划页仍用 .chart-box 的 220px）。 */
.chart-card.sm{min-height:138px}
.chart-box.sm{height:110px}
.chart-box canvas{display:block;max-width:100%}
.chart-tip{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--sub);font-size:13px;background:color-mix(in srgb, var(--card) 55%, transparent);border-radius:10px;z-index:2;text-align:center;padding:0 16px}

/* ── 支出明细：环形图 + 环心合计 + 下方分类明细（v3.6 真机第 5 轮反馈④）──
   环心三行并**整体居中**（真机第 40 轮反馈①定稿，照 Fred 参考图）：
     类型标签（总支出/总收入）→ 金额 → 左右双向箭头
   ⚠️ 金额**不加粗**（`font-weight:400`）：参考图里金额与标签同为常规字重，
   原来 700 的粗黑数字压在环内显得很重、与 11px 的小标签不成比例 —— Fred 明确要求去粗。
   箭头恢复的原因：环心只剩两行纯文字时，「这里能点」完全看不出来（触屏没有 hover，
   title 等于不存在）。箭头是那枚唯一的可操作暗示，去掉它 = 用户又变成「不知道怎么切」。 */
.cat-donut{position:relative;height:176px;cursor:pointer;-webkit-tap-highlight-color:transparent}
.cat-donut canvas{display:block;max-width:100%}
/* 环心：三行文字在环内正中。pointer-events:auto 是**刻意的** —— 环心中央被 canvas 的
   空心区覆盖，只有让这层可点，用户点文字/箭头才能切换；热区就是这三行本身。
   gap 用 3px：三行挤在 62% 内径里，间隙给大一点就会顶到下环。 */
.dc-mid{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:3px;pointer-events:auto;width:58%;min-width:0;cursor:pointer}
.dc-lb{font-size:11px;color:var(--sub);white-space:nowrap;line-height:1.2}
/* 金额：**常规字重**（第 40 轮按参考图去粗，原为 700）；色用正文色，靠字号（15px）与标签区分层级 */
.dc-amt{font-size:15px;font-weight:400;color:var(--text);font-variant-numeric:tabular-nums;letter-spacing:.2px;
  line-height:1.2;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dc-amt.sm{font-size:13px}
/* 环心切换箭头（真机第 40 轮反馈①恢复；沿用 v3.8 那枚左右双向箭头 —— 「对调」语义与图例一致）。
   尺寸 18px / 描边 1.7：比第 38 轮那枚 24px 圆牌小一号 —— 上一轮被判「太丑」的正是
   「白底圆牌 + 灰色 icon」那种补丁感；这里做**纯线条、无底色**，像一枚居中的指示符而不是按钮。 */
.dc-tg{width:18px;height:18px;flex:none;display:flex;align-items:center;justify-content:center;
  color:var(--primary);margin-top:1px}
.dc-tg svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
/* 长按环心不再弹系统「拷贝/搜索」浮层，也不再选中文字（真机第 38 轮反馈②的「箭头浮在上面」就是这个） */
.cat-donut{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;-webkit-user-drag:none}
/* 空月份（真机第 38 轮反馈③）：整块换成一句话 —— 环、环心数字、切换箭头全部收掉。
   改造前是「环还在 + 环心还写 总支出/0.00 + 盖一层半透明提示」，三层文字叠在一起像打架。 */
.cat-donut.is-empty{cursor:default;display:flex;align-items:center;justify-content:center}
.dc-empty{color:var(--sub);font-size:13px}
.cat-mix{margin-top:4px}
/* 环上「这块是什么」提示卡（第 88 轮批 3）：轻点色块弹出，2.8s 自动收。
   挂在 .cat-donut（position:relative）里 ⇒ 跟着卡片走，不用管滚动/键盘。
   ★ 别和 .chart-tip 混：那个是「图表没画出来」的兜底遮罩，两码事。
   ★ pointer-events:none 是必须的：否则提示卡会挡住下一次点按（点它等于没点）。 */
.donut-tip{position:absolute;z-index:3;pointer-events:none;display:flex;flex-direction:column;
  gap:1px;padding:6px 10px;border-radius:10px;max-width:78%;
  background:rgba(20,26,38,.92);color:#fff;box-shadow:0 4px 14px rgba(15,20,30,.22);
  animation:tipIn .12s ease-out}
.donut-tip .dt-n{font-size:12px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.donut-tip .dt-v{font-size:12px;opacity:.86;white-space:nowrap;font-variant-numeric:tabular-nums}
@keyframes tipIn{from{opacity:0;transform:translateY(3px)}to{opacity:1;transform:none}}
.cl-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line)}
.cl-row:last-child{border-bottom:0}
.cl-ic{width:30px;height:30px}
.cl-ic svg{width:16px;height:16px}
.cl-name{flex:1;min-width:0;font-size:15px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cl-pct{flex:none;width:48px;text-align:right;font-size:12px;color:var(--sub);font-variant-numeric:tabular-nums}
.cl-amt{flex:none;min-width:78px;text-align:right;font-size:15px;font-weight:600;font-variant-numeric:tabular-nums}

/* 真机第 25 轮反馈①：分类行点得进 —— 整行是按钮，行尾 › 沿用「可进下一层」的既有约定（同账户页往来记录行）。
   「其他」是聚合出来的行、没有具体分类 id，箭头留位但隐藏 —— 两种行的金额列才对得齐。 */
.cl-go{width:100%;text-align:left}
.cl-go:active{background:var(--fill)}
.cl-go-i{flex:none;font-size:15px;color:var(--sub);line-height:1;visibility:hidden}
.cl-go .cl-go-i{visibility:visible}

/* 分类流水的返回条（真机第 25 轮反馈①）：整条 .group-h 就是返回键（热区大），
   左侧圆牌直接用月份切换器那枚 .rp-nav，两处导航块长得一样。 */
.cat-bar{width:100%;text-align:left}
.cat-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* 键值行容器（流水详情/调账/报表区间汇总） */
.kv{flex-direction:column;gap:0;border-bottom:none;padding:0}
.kv-row{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:8px 0;border-bottom:1px dashed var(--line);font-size:15px;min-width:0}
.kv-row:last-child{border-bottom:none}
.kv-row .k{color:var(--sub);flex:none;padding-right:12px}
.kv-row .v{font-weight:500;text-align:right;min-width:0;word-break:break-all}
/* ★ B1：弹层 kv 行属「列表」，金额一律黑（同上）。 */
.kv-row .v.in,.kv-row .v.out{color:inherit}

/* 记一笔表单（txnform · v1 真机反馈重构） */
/* 顶部：类型切换 + 金额 */
/* ★ 真机第 61 轮反馈③：下滑分类网格时「类型切换 + 金额」会跟着滚出屏幕 ——
   Fred 原话「顶端的解析和金额行不要因为拖动分类就往上一起拖动了，这样导致用户都看不到自己输入的金额」。
   正解 = 让「解析行 + 类型切换 + 金额」整块 **sticky 钉在滚动区顶部**（与 .tf-fields 钉底同理，一上锚一下锚）。
   ⚠️ 为什么要有 .tf-sticky 这层包裹：sticky **只能在自己的包含块（.mf-body 的内容盒）内移动** ——
     若直接给 .tf-top 加 sticky，而它前面还有解析行，那解析行一滚走、.tf-top 就顶到包含块上边界，
     再往下滚只能跟着走（实测 scrollTop=41 时 top 从 127 掉到 86，等于没生效）。
     包一层后「粘性盒的第一行就在包含块顶边」⇒ 整块可以从头黏到尾。编辑态下解析行不存在，
     粘性盒仍从头开始，行为一致。
   ⚠️ sticky 的尺寸必须**显式写死**，不能让内容决定，否则「算的时候」金额下面会多出一行算式
      （.tf-expr，+21px）⇒ 网格起点在 scrollTop=0 时从 181 跳到 202 —— 那正是「拖动分类版式会变」。
      于是给 .tf-top 定高 42px（= 分类图标高，原自然高度就是 42），算式改成与金额**同排内联**
      （见下方 .tf-amt 那段：定高后副行会被裁掉半截，同行并排才能既完整可见又不改高度），
      margin-bottom 的 10px 挪进 padding-bottom（margin 不能算进 sticky 的占位高度）。
   ⚠️ 背景必须不透明（用页面底色，与 .modal-full 一致），否则分类图标会从它下面透上来。 */
#txnForm .tf-sticky{position:sticky;top:0;z-index:3;background:var(--bg)}
/* ⚠️⚠️ 绝不能改这里的 `justify-content` / 布局对齐方式 —— 踩过：
   为了让算式与金额同行，我一度写成 `justify-content:flex-end`。结果 seg3 靠左、金额靠右、
   **元素中心点正好落在 seg3 的「收入」按钮上** —— 而冒烟测试里用 `page.click('.tf-top')`
   表示「点一下表单区收键盘」，那一下就变成了「切到收入」⇒ 分类被换掉、保存时提示「请选择分类」、表单不关闭。
   （真实用户点顶栏空白处同理，会莫名把类型切走。）保持原样：左对齐，中心点落在空档上，点它不会误触任何按钮。 */
.tf-top{display:flex;align-items:center;gap:10px;margin-bottom:10px}
/* ★ 真机第 62 轮反馈②：顶栏从 42+10 压到 38+6（省 8px），分类网格多露的空间来源之一。
   高度仍**显式写死**（见上面的成因说明），只是把「行高」与「下边距」各收一点。
   ⚠️ 42 → 38 会让金额略靠上，属可接受；**不要**为了好看把 38 改回去 —— 这是给分类腾的地方。 */
#txnForm .tf-top{height:38px;margin-bottom:0;padding-bottom:6px;box-sizing:content-box}
.tf-top .seg3{flex:1;max-width:230px}
/* 金额靠右：用 `margin-left:auto` 让它自己吃掉左侧余量，而不是靠父级 justify-content 重排
   （重排会移动 seg3 的位置、进而改变整行的可点区域划分 —— 见上面的踩坑说明）。 */
.tf-amt{flex:1;margin-left:auto;text-align:right;font-size:24px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:.5px;
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tf-amt.in{color:var(--income)}
.tf-amt.tf{color:var(--transfer)}
/* 连算时的算式（v3.9）：**与金额同一行、排在它左边**（如「5 + 3   8.00」）。
   沿革：v3.9 是「金额主行 + 算式副行」上下堆叠（真机附图同款），
   但真机第 61 轮要求顶栏定高（算式一撑高就会把分类网格顶下去 ⇒「拖动分类版式会变」），
   定高后副行会被裁掉半截（截图实测「5 + 3」只剩上半）—— 那是不可接受的。
   改成同行并排后：既完整可见，又天然不改变顶栏高度，两头的要求同时满足。
   ⚠️ 必须用 `order:-1` 把它排到金额**左边**：DOM 里算式在金额后面（syncAmount 拼的），
     改 DOM 要去动 txnform.js 的 innerHTML 拼装，用 CSS 排序更省、也不会破坏既有断言。 */
.tf-amt .tf-expr{order:-1;font-size:13px;font-weight:600;color:var(--sub);letter-spacing:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.tf-amt:has(.tf-expr){display:flex;align-items:baseline;justify-content:flex-end;gap:8px}/* 分类圆形网格（紧凑，4 列） */
.tf-cat-grid{display:none}
/* ★ 真机第 62 轮反馈②：Fred 要「至少看到 4 行分类图标」。净增可见行数的第 4 个来源就是行高本身：
   球 38→34、gap 5→3、行间距 10→6，每行省 8px；再抬掉网格上下的 2+10 外边距（改 0+4）省 8px。
   合计每行 64px（原 72），4 行 = 256px（原 288）—— 在放不下的窄视口上这是决定性的。
   ⚠️⚠️⚠️ 第 64 轮真机反馈②：「分类第一行图标顶端会被遮挡」——
     根因就是上面那句「抬掉网格上下的 2+10 外边距（改 0+4）」。上边距收成 0 之后，
     首行图标顶边距 `.tf-sticky` 底边**只剩 1px**（实测 412×915 / 393×851 / 360×780 ×
     DPR 1/2.625/2.75/3 × 字体 1/1.15/1.3，共 12 组，**全部是 1px**）。
     桌面浏览器侥幸不重叠，但真机上一丁点度量差异（Android WebView 字体基线、行高取整、
     `.cb-name` 11px 实际行高等）就够压住 1~3px —— 表现为「第一行图标顶端被削掉一条」。
     ⇒ 恢复上边距为 **8px**（实测余量 1px → 9px）。★ 实测确认**不减少可见行数**
       （支出 3 行 / 收入 2 行，mt=0/6/8/10/12 全部相同，且滚动区始终不可滚 ⇒ 有富余）。
     ⚠️ 别再把它收回 0。要腾空间请从 `.tf-top` 的行高、
        或 `.cat-ball .cb-name` 的 `line-height` 上找，**不要动网格与顶栏之间的间距** ——
        那条间距同时承担「防遮挡」职责，它是安全余量，不是浪费。 */
.tf-cat-grid.has{display:grid;grid-template-columns:repeat(5,1fr);gap:6px 4px;margin:8px 0 4px}
.cat-ball{display:flex;flex-direction:column;align-items:center;gap:3px;padding:1px 0}
/* v3.7 真机反馈②：原来整片网格都是满强度主色实底 → 全员同重 = 没有「选中」可言。
   改为「未选中浅底主色图形 / 选中实底卡片色图形」的反转，用浓度差建立主次。
   复用 --primary-w 令牌，十套皮肤自动适配，不需要按皮肤特调。 */
.cat-ball .cb-ic{width:34px;height:34px;transition:.12s;background:var(--primary-w);color:var(--primary)}
.cat-ball .cb-ic svg{width:20px;height:20px}
/* 末尾「编辑」入口：比未选中再弱一档（透明底 + 虚线灰框 + 副色图形） */
.cat-ball .cb-more{background:transparent;border:1.5px dashed var(--line);color:var(--sub)}
.cat-ball .cb-more svg{width:17px;height:17px;stroke-width:2}
.cat-ball .cb-name{font-size:11px;color:var(--sub);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 选中态：主色实底 + 卡片色图形，外圈「卡片色 2px 缝 + 主色环」。
   留缝是必需的：环与球同色相贴会让边界糊成一坨；深色皮肤下自动变成「深蓝缝 + 亮蓝环」。 */
.cat-ball.on .cb-ic{background:var(--primary);color:var(--on-solid);border-color:var(--primary);
  box-shadow:0 0 0 2px var(--card),0 0 0 3.5px var(--primary)}
.cat-ball.on .cb-name{color:var(--primary);font-weight:700}
/* ★★★ 真机第 62 轮反馈①（本条是「三行与数字键盘连在一起」的正解，改前务必读完）：
   Fred 要的结构是：
     滚动区：解析行 + 类型/金额 + 分类网格（**至少看得到 4 行**）
     固定区：账户/日期/备注三行 ← 紧跟 → 数字键盘
   ⇒ 做法：把 `.tf-fields` **从 `.mf-body` 搬进 `.mf-foot`**，让它与 `.keypad` 成为同一 flex 列的兄弟。
   这样三行与键盘之间**只隔一个 gap**，且**永不参与滚动**（Fred 原话「压根不需要往上顶」）。

   ⚠️ 为什么必须搬出滚动区（第 61 轮的旧做法是留在里面靠 sticky + margin-top:auto 钉底）：
     只要字段区还在 `.mf-body` 里，它就**吃掉滚动区的可视高度** —— 分类能滚到哪儿全由它决定。
     实测（视口 700）：滚动区 440，分类 4 行需 278，字段区 91 ⇒ 4 行**本来放得下**，
     但旧结构下字段区压在底部、网格第 4 行的**标题行正好被它盖住**（截图可见「有球没名」）。
     搬出来后滚动区独占 440，第 4 行完整可见 —— 这是根治，不是靠调高度凑出来的。
   ⚠️ 也不再需要 sticky / margin-top:auto 那一套（都是为「留在滚动区里」打的补丁）。
   padding-bottom 收成 0：分类网格是这里的最后一块内容，余下的间距由 `#tf-cats` 自己的
   margin-bottom 提供，避免「网格 → 底部固定区」之间出现双份留白。
   （v62 排查记录：曾怀疑 padding-bottom:0 会把最后一行顶掉，实测**不是** ——
     滚动容器 369px 装 6.8 行，任何滚动位置上下边缘都必然有行是部分可见的，这是滚动本身的
     表现、不是缺陷；实测 8px「刚好对齐」而 12/14/20px 又切回来，纯属凑数，分类数一变即失效，
     所以**绝不能**靠调这个值去修「半行」。判据见 tools/ui-components.test.mjs 的 V62-2。） */
#txnForm .mf-body{padding-bottom:0;display:flex;flex-direction:column}
/* 底部固定区：三行字段 + 数字键盘，纵向排列，**间距压到最小**（反馈①「空隙尽量小」）。
   padding 只在最外圈留一点：上 0（字段区自己带 4px）、左右 14（与内容对齐）、
   下 2px + 安全区（原来 12px，收掉 10px 让分类多露一点，也是反馈②的来源之一）。 */
#txnForm .mf-foot{padding:0 14px calc(2px + env(safe-area-inset-bottom))}
/* 三行字段区：不再是 sticky、不再吃剩余空间，就是底部区里的一个普通块。
   gap 8px 保持（三行同款卡片，间距一致才整齐）；底部 4px 是它与键盘的间隙
   —— 再小会让「备注框」与「数字键」两排白卡片糊在一起，4px 是截图比对后的最小值。
   ⚠️ background 必须是 **var(--card)（与 .mf-foot / .keypad 同色）而不是 var(--bg)**：
     .mf-foot 是白色卡片底，字段区若用页面灰底，会在「分类网格 → 字段区」之间显出一条色块，
     看起来像多出一块灰条（真机截图第一版就是这个毛病）。改成同色后底部区浑然一体。 */
.tf-fields{display:flex;flex-direction:column;gap:8px;background:var(--card);padding:6px 0 4px}
/* ── 转账页：把空出来的纵向空间分给字段卡片（真机第 60 轮反馈④；第 63 轮反馈② 定稿）──
   转账没有分类网格，滚动区会空出一大片，而窄视口下又**刚好没有余量**（字段区 193px 正好占满）
   ⇒ 高度必须**自适应**，不能写死。做法：`.tf-fields` 用 flex:1 吃满剩余空间，四条都加 max-height 上限
   —— 富余多时靠 justify-content 摊到行距上，富余少时自动退回基础高度，**任何视口都不会溢出**
   （溢出会把第一行「转出」顶到可视区外）。
   ⚠️ 必须限定 [data-type="transfer"]：支出/收入页有网格占位，加了会把它们的字段也撑高、与网格抢空间。

   ⚠️⚠️⚠️ 第 63 轮真机反馈②（「转账页面上面不要流出这么多空白，好丑，原本偏上的效果就可以了」）
     把这块的**高度分配彻底重定**了。留档，因为我在这里连续判反两次、并一度改坏了两条老用例：

     · 旧解（第 60b~62 轮）= `flex:0 1 auto` + `min-height:62vh`（见下方「为什么废掉 62vh」）。
       它把富余全挤到**卡片上方**：真机 420×907 实测上方空白 **205px**、390×640 实测 **79px**。
     · 弯路一：只把 `62vh` 换成在 `.mf-foot` 上加 `flex:1`。
       ✗ 更差：`.mf-body` 仍吃 base 的 `flex:1`，两兄弟**平分**富余，上方空白反而涨到 **321px**，
       且矮视口卡片退化到 36px。
     · 弯路二：`flex:1` + 顺手把 `.mf-body` 也改成 `flex:0 0 auto`。
       ✗ **把两条老用例搞红了**（`V45-2` / `V46-1`：点「转出」「账户」弹层再也开不出来）。
       根因见下条铁律 —— **「表格行被压扁」与「点得中」是同一件事**。
     · 正解 = **`min-height:62vh` 整个删掉 + `.mf-body{flex:0 0 auto}`**：
       `.mf-body` 只取内容高度、不再抢富余；`.mf-foot{flex:1}` 独占全部富余并贴住底边；
       富余再被 `space-evenly` 摊进四行之间（正是反馈④要的「均分空档」）。
       ★ 实测（420×907 / 390×640）上方空白 **66px / 12px**（旧解 205 / 79），卡片均 58px、数字键盘贴底。

   ⚠️⚠️ **为什么不能给 `.mf-foot` 加 `min-height:62vh`**（第 60 轮的老解）：它把底部区高度**锁死成 vh 比例**，
     与实际内容无关 ⇒ ① 富余被推到卡片上方（就是 Fred 嫌的那片空白）；② 矮视口下 62vh 反过来把底部区
     顶得过高、数字键盘**脱离视口底边**（实测 420×907 底边 733 ≠ 907）。改用 `flex:1` 让高度由布局决定，
     这两个毛病一起消失。
   ⚠️ **`.mf-body` 必须是 `flex:0 0 auto`**：留着 base 的 `flex:1` 就会与底部区平分富余，
     一半必然显形为滚动区里的空白。**这是本条的关键，漏了它就只剩「平分」那一路。** */
#txnForm[data-type="transfer"] .mf-body{flex:0 0 auto}
#txnForm[data-type="transfer"] .mf-foot{flex:1;display:flex;flex-direction:column}
#txnForm[data-type="transfer"] .tf-fields{flex:1;justify-content:space-evenly}
#txnForm[data-type="transfer"] .tf-fields>.tf-mini,
#txnForm[data-type="transfer"] .tf-fields>.tf-note{flex:1;max-height:58px}
.tf-inline{display:flex;gap:8px;align-items:center}
.tf-mini{
  flex:1;min-width:0;display:flex;align-items:center;gap:6px;min-height:36px;
  background:var(--card);border:1px solid var(--line);border-radius:10px;
  padding:7px 10px;font-size:15px;color:var(--text);text-align:left;
}
/* .tf-v 现在是「图标 SVG + 文字」的容器（真机第 39 轮反馈①：原来把 icon 当文字拼，
   几何 key 会原样显形如「savings 现金」）。省略号必须落在内层文字上，
   外层只负责裁剪与对齐。 */
.tf-mini .tf-v{flex:1;min-width:0;overflow:hidden;display:flex;align-items:center;gap:6px}
.tf-mini .tf-v-t{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tf-mini .tf-v-t2{white-space:normal;overflow:visible;display:flex;flex-direction:column;line-height:1.3}
/* ★ 第 75 轮：转账侧选了往来明细时，字段值下方挂一行小字（动作 + 待收/待还金额）。
   `.tf-v-t` 是 nowrap 单行，这里必须换成列向布局（`.tf-v-t2`）才放得下第二行。 */
.tf-mini .tf-v-sub{font-size:11px;color:var(--sub);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tf-mini .tf-v-ic{flex:none;display:flex;align-items:center}
.tf-mini .tf-v-ic svg{width:17px;height:17px;display:block;color:var(--primary);fill:currentColor}
/* 转账（v3.6 真机反馈②）：转出 / 转入 / 日期 / 备注 各占一行。
   v60 反馈④起**不再套 `.tf-inline.col` 包裹层**（那会让余量只在「三张卡」与「备注」之间二分，
   备注被甩到下面一大截）—— 四行现在是 `.tf-fields`（已是 flex 列）的同级子项，靠它的 gap:8px 分行。 */
.tf-lb{font-size:13px;color:var(--sub);flex:none}
.tf-caret{color:var(--sub);font-size:15px;flex:none}
.tf-mini-input{
  border:1px solid var(--line);border-radius:10px;background:var(--card);
  padding:8px 10px;font-size:15px;outline:none;flex:none;color:var(--text);
}
.tf-mini-input:focus{border-color:var(--primary)}
.tf-note{
  width:100%;border:1px solid var(--line);border-radius:10px;background:var(--card);
  padding:7px 10px;font-size:15px;outline:none;color:var(--text);
}
.tf-note:focus{border-color:var(--primary)}
/* ★★★ 真机第 62 轮反馈①：**整条「把三行卡片抬到键盘上方」的方案已废弃并删除**。
   Fred 的原话把要求说清楚了：
     「账户日期备注和数字键盘连在一起，点击备注的时候，自动出来系统键盘**遮挡住数字键盘**即可
       （也就是账户日期备注和数字键盘页面**压根不需要往上顶**）」
   ⇒ 结构上把三行字段区**从滚动区（.mf-body）搬进底部固定区（.mf-foot）**，
     与数字键盘成为**同一个 flex 列的兄弟** —— 这才是「连在一起」的正解（见 .mf-foot 段）。
     键盘态下整页版式一动不动，系统键盘直接盖在数字键盘那块上。

   ⚠️⚠️ 别再往回加的历史坑（第 61 轮那版被否掉的实现，全部已删）：
     · `--kb-h` 屏蔽区（`.tf-fields::after` 顶出一块与键盘等高的空白，把字段抬到「键盘顶边」）
     · `.kb-held`（键盘态给字段区停用 sticky）
     · `.no-kp .tf-fields{margin-top:auto}`（键盘态换定位方式）
     · txnform.js 的 measureKbH / enterKbHold / scrollFieldsIntoView（「抢先滚一次 + 补滚一次」）
   ⇒ 那一版的思路与 Fred 的真实需求**方向相反**：他要的是「别顶」，旧实现是「尽量顶到位」。
     它同时制造了两个新症状：① 屏蔽区吃掉滚动区高度 ⇒ 分类只剩 3 行可见；
     ② 字段被顶上「键盘顶边」⇒ 用户说的「卡片被顶上去了」其实有一部分就是它造成的。
   ⚠️ 旧实现还把字段区**留在滚动区里**（靠 sticky/auto 外边距钉底）—— 那必然与分类抢纵向空间，
     且滚动区里永远留不出「第 4 行分类」的余地。搬出滚动区才是根治。

   ★ 键盘态只做一件事：把数字键盘**连占位一起撤掉**（`display:none`）。
   ⚠️⚠️ 这里的方向被否过两次，**判据是「字段最终落在哪」，不是「字段动不动」**：
     · 第 60 轮：字段区**还在滚动区（.mf-body）里**，撤占位会让滚动区变高、字段跟着下移 157px
       ⇒ 那一版选了 `visibility:hidden`（隐形但保留占位），字段不动。
     · 第 62 轮起字段区**搬进了底部固定区（.mf-foot）**，方向**正好相反**：
       软键盘弹出 → 视口 907→~490 → `.modal-full{fixed;height:100%}` 跟着变矮 →
       只隐形的话键盘仍占 174px ⇒ `.mf-foot` 被撑到 266px ⇒ **三行字段浮到屏幕中部**
       （实测 `foot.top` 623→223）。这正是 Fred 第 62、63 两轮连报的「点击备注后账户日期备注被顶上去」。
       撤掉占位 ⇒ `.mf-foot` 收缩到 92px、**紧贴新视口底部**（`foot.top` 397），
       系统键盘正好盖在下方那块 ⇒ 三行字段待在原地偏下，**符合 Fred「压根不需要往上顶」**。
   ★ 实测（真机 420×907 + 软键盘 417px，聚焦备注）：
       visibility:hidden：foot.top=223、三行字段 225~314、下方留空 176px  ✗
       display:none     ：foot.top=397、三行字段 398~487、下方留空 0      ✓
   ★ 说明：真机键盘弹起时，**系统键盘会把（已撤掉的）数字键盘那块盖住** —— 这是 Fred 明确要的效果，
     备注输入内容靠系统键盘自带的输入条就能看见，**不需要**我们做任何滚动。
   ★★ 测试侧同步要求（第 63 轮踩过）：涉及软键盘的断言必须**显式把视口压矮**（如 `setViewportSize({height:490})`），
     否则桌面视口不收缩 ⇒ 两种写法量出来一模一样 ⇒ 断言必然假绿（这正是 Fred 连报两轮的间接原因）。 */
/* 备注/日期聚焦时**撤掉**数字键盘（不是隐形）—— 让系统键盘盖在它原来的位置上。
   ⚠️ 必须是 display:none：软键盘弹出会压缩视口，只「隐形」的话键盘仍占 174px，
      会把底部固定区（连同三行字段）整个顶到屏幕中部（第 63 轮真机反馈①，实测 foot.top 623→223）。 */
#txnForm.no-kp .keypad{display:none}

/* 账户/操作按钮行 */
.chip-row{display:flex;flex-wrap:wrap;gap:8px}

/* 页面标题行（账户详情等二级页） */
.phead{display:flex;align-items:center;gap:4px;padding:2px 0 8px}
.phead .pt{flex:1;font-size:16px;font-weight:700;text-align:center}
.phead .ph-side{width:40px}
/* v8 真机反馈：右上角「⋯」太小不显眼 → 换成文字「设置」（左侧 ‹ 仍撑 40px 保持标题居中） */
.phead .ph-txt{min-width:40px;padding:0 2px;font-size:15px;font-weight:600;color:var(--primary);
  text-align:right;white-space:nowrap}
.phead .ph-txt:active{opacity:.6}

/* 持仓行 / 批量净值 */
/* 持仓行整行长按 = 弹操作菜单（account.js 委托 data-hold）→ 同属「长按是业务手势」，
   故同样要两道闸（真机第 41 轮口径，见 .acc-row 上方注释）。 */
.h-row{display:flex;align-items:center;gap:8px;padding:12px 14px;border-bottom:1px solid var(--line);width:100%;min-width:0;
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;-webkit-user-drag:none}
.h-row:last-child{border-bottom:none}
.h-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.h-main .t1{font-size:15px;font-weight:600;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.h-main .t2,.h-main .t3{font-size:12px;color:var(--sub)}
.h-main .t3{font-variant-numeric:tabular-nums}
.h-side{display:flex;gap:6px;flex:none}
.h-row.h-head{background:var(--fill);color:var(--sub);font-size:12px;font-weight:600;padding:8px 14px}
.h-row.h-head .t1{font-weight:600;color:var(--sub);font-size:12px}
.sym{font-size:11px;background:var(--fill);padding:1px 7px;border-radius:6px;color:var(--sub);font-weight:400}
.nav-row .k{color:var(--text);display:flex;flex-direction:column;line-height:1.35}
.nav-row .k .sub{font-size:11px;color:var(--sub);font-weight:400}
.nav-in{width:130px;flex:none;padding:8px 10px;text-align:right}
.nav-list{display:flex;flex-direction:column}

/* 流水详情底部动作 */
.txn-dtl-foot{display:flex;flex-direction:column;margin-top:12px}
.txn-dtl-foot .pill{align-self:center}

/* 账户图标选择器（新建/编辑账户）：与分类管理的 .cm-icpick 同构
   （同列数 6 / 同图标尺寸 20 / 同两态：未选=浅蓝底+主色图形，选中=主色实底+反白图形）
   v8 真机反馈：选择器改成**正圆**（原来是 10px 圆角方块），与全站圆牌图标一致。
   ★ 选中态描边必须是 --primary：旧值 --primary-d(#0b3a7e) 被真机读成「黑色线」。 */
.acc-icons{display:grid;grid-template-columns:repeat(6,1fr);gap:6px}
.acc-ick{aspect-ratio:1;border-radius:50%;border:2px solid var(--ic-ring);background:var(--primary-w);
  color:var(--primary);display:flex;align-items:center;justify-content:center;
  transition:background .16s,color .16s,border-color .16s}
.acc-ick svg{width:20px;height:20px;display:block}
.acc-ick:active{transform:scale(.94)}
.acc-ick.on{background:var(--primary);color:var(--on-solid);border-color:var(--primary)}
/* 表单顶部实时预览：边填边看（与账户卡同一套 .acc-* 结构，故所见即所得） */
.acc-prev{display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:var(--radius);background:var(--fill);margin-bottom:14px}

/* ---------- v8 账户表单新控件（类型宫格 / 点选行 / 48 色板）---------- */
/* 类型宫格：一次点选即同时定下 kind（算法口径）与 subtype（展示细分），
   故不再需要「资产/负债」分段 —— 从哪个 tab 进来就建哪一类（role 由调用方传入）。 */
.acc-types{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.acc-tp{display:flex;flex-direction:column;align-items:center;gap:6px;padding:10px 4px 9px;
  border:1px solid var(--line);border-radius:10px;background:var(--card);color:var(--sub);
  transition:background .16s,border-color .16s,color .16s}
.acc-tp:active{transform:scale(.97)}
.acc-tp .tp-ic{width:32px;height:32px}
.acc-tp .tp-ic svg{width:18px;height:18px}
.acc-tp .tp-t{font-size:12px;font-weight:600;line-height:1.2;white-space:nowrap}
.acc-tp.on{border-color:var(--primary);background:var(--primary-w);color:var(--primary)}
.acc-tp.dis{opacity:.4}
/* 图标 / 颜色「点一行弹一层选」的行控件（两行同构，只是左侧预览件不同） */
.pick-row{display:flex;align-items:center;gap:12px;width:100%;min-height:52px;padding:8px 12px;
  text-align:left;border:1px solid var(--line);border-radius:10px;background:var(--card)}
.pick-row:active{background:var(--fill)}
.pick-row .pk-ic{width:34px;height:34px}
.pick-row .pk-ic svg{width:19px;height:19px}
.pick-row .pk-dot{width:22px;height:22px;border-radius:50%;flex:none;margin:0 6px;border:1px solid var(--line)}
.pick-row .pk-t{flex:1;min-width:0;font-size:15px;font-weight:500;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pick-row .pk-caret{color:var(--sub);font-size:18px;font-weight:600;line-height:1;flex:none}
/* 48 色板（12 色系 × 4 档）：6 列 ⇒ 单色块 ≈44px，够 44px 触控基线；共 8 行可滚动 */
.clr-none{display:flex;align-items:center;gap:12px;width:100%;min-height:52px;padding:8px 12px;text-align:left;
  border:1px solid var(--line);border-radius:10px;background:var(--card);font-size:15px;font-weight:500;color:var(--text)}
.clr-none:active{background:var(--fill)}
.clr-none.on{border-color:var(--primary);background:var(--primary-w);color:var(--primary)}
.clr-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:8px;margin-top:12px}
.clr-dot{aspect-ratio:1;border-radius:50%;border:none;color:#fff;font-size:13px;font-weight:700;
  display:flex;align-items:center;justify-content:center;transition:transform .12s}
.clr-dot:active{transform:scale(.9)}
/* 选中标记：底色全是中深档，白勾一定看得见；加深阴影兜住极浅色 */
.clr-dot.on::after{content:'✓';text-shadow:0 0 3px rgba(0,0,0,.45)}

/* ---------- v8 往来记录（应收款 / 应付款）列表 ---------- */
.rec-list{display:flex;flex-direction:column;gap:9px;margin-bottom:12px}
.rec-row{display:flex;align-items:center;gap:12px;width:100%;min-width:0;text-align:left;
  background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);padding:13px 14px;
  transition:transform .16s ease}
.rec-row:active{transform:scale(.985)}
.rec-ic{width:36px;height:36px;border-radius:50%;background:var(--primary-w);color:var(--primary);border:1px solid var(--ic-ring);
  display:flex;align-items:center;justify-content:center;flex:none}
.rec-ic svg{width:19px;height:19px}
.rec-bd{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:5px}
.rec-t1{display:flex;align-items:center;gap:6px;min-width:0}
.rec-name{font-size:15px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rec-tag{font-size:11px;line-height:1;padding:3px 6px;border-radius:6px;font-weight:600;flex:none}
.rec-tag.done{background:var(--ok-w);color:var(--ok)}
.rec-tag.due{background:var(--warn-w);color:var(--warn)}
.rec-tag.over{background:var(--danger-w);color:var(--danger)}
.rec-t2{font-size:12px;color:var(--sub);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rec-bar{height:5px;border-radius:2px;background:var(--fill-2);overflow:hidden}
.rec-bar i{display:block;height:100%;background:var(--primary);border-radius:2px;transition:width .2s}
.rec-side{display:flex;flex-direction:column;align-items:flex-end;gap:2px;flex:none}
.rec-amt{font-size:16px;font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap}
.rec-sub{font-size:11px;color:var(--sub);font-variant-numeric:tabular-nums;white-space:nowrap}
.rec-go{flex:none;color:var(--sub);font-size:16px;line-height:1;margin-left:-6px}

/* v11：账户页不再铺「往来流水」，流水下沉到记录详情（点开某条记录才显示这笔的流水） */
.rec-tag.live{background:var(--primary-w);color:var(--primary)}
.rec-dtop{display:flex;align-items:center;gap:8px;margin:2px 0 12px}
.rec-dtop .rec-dpct{font-size:12px;color:var(--sub);font-variant-numeric:tabular-nums;flex:none}
.rec-dtop .rec-bar{flex:1 1 auto;min-width:40px}

/* 卡片内紧凑按钮组间距 */
.card-pad .chip-row{margin-bottom:2px}

/* ============ M3 贷款 UI 增补 ============ */
/* 我的贷款卡片
   真机第 27 轮反馈①「每个贷款明细的高度偏高」→ 整体降高：
     padding 14/16 → 11/14，行间距 6/8/6 → 3/5/3，进度条 6 → 5px，
     标题 16 → 15px、剩余本金 18 → 16px，脚注与 meta 同为 11.5px。
   累计降约 20px/卡（实测 128 → 107）。 */
/* v53（真机第 44 轮反馈①）：贷款卡片支持**长按拖动排序**（在还 / 已结清各自段内）。
   两条起拖路径（与账户行一致）：按住卡右上角三条杠手柄 → 立即跟手；卡体按住 500ms → 进入拖动。
   ★ user-select / -webkit-touch-callout / -webkit-user-drag 是**必须**的（第一道闸，见 .acc-row 上方注释）；
     JS 事件层拦截（public/js/ui/noSelect.js 的 HOLD_SELECTORS 里已加 .loan-card）是**第二道闸**。 */
.loan-card{display:block;width:100%;text-align:left;padding:11px 14px;cursor:pointer;
  position:relative;                       /* 拖动柄改成绝对定位的定位祖先（v58 真机第 45 轮反馈②）*/
  transition:transform .16s ease;
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;-webkit-user-drag:none}
.loan-card:active{background:var(--fill)}
.lc-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:3px;padding-right:32px}
/* flex:1 让名称吃满剩余空间（原来是靠 space-between 把名称与金额顶到两端）。
   v58：手柄已改成绝对定位（不再占行内空间），这条仍要留 —— 否则名称过短时金额不会靠右。 */
.lc-name{font-size:15px;font-weight:700;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto}
.loan-list{display:flex;flex-direction:column;gap:9px}
.loan-list.drag-host{overflow:visible}
/* 贷款卡片拖动柄：视觉 16px、触控区 44px（照 .acc-grip / .cat-lgrip）。
   v58（真机第 45 轮反馈②）：从「.lc-top 行内第三件」改成**相对整张卡垂直居中的绝对定位** ——
     原来它跟着第一行的基线走，真机看起来「挂在标题后面、偏上」（Fred：「要显示垂直居中」）。
     right:2px 是照抄上一版的位置（原先靠 margin-right:-12px 顶进 14px 右内边距）：
     不再往里会贴到 Android 手势导航的「边缘返回」带，真机按住没反应；也不再往外，否则会飘出卡片。
   ⚠️ 变成绝对定位后它**不再参与行高**（卡片高度天然不受影响），所以原来那对上下 -12px 的负 margin 一并去掉；
      取而代之的是让所有**整宽元素**右侧留出 32px（= 44px 触控区 - 14px 内边距 + 2px），
      文字/进度条不会钻到手柄下面。 */
.loan-card .lc-grip{position:absolute;right:2px;top:50%;transform:translateY(-50%);
  width:44px;height:44px;display:flex;align-items:center;justify-content:center;
  color:var(--sub);touch-action:none;cursor:grab}
.loan-card .lc-grip svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}
/* 拖动中：被拖卡浮起（transition:none —— 换位时 transform 归零，带过渡会「飘」一下不跟手）。
   底色用 color-mix 混到不透明：.loan-card 走 .card 的不透明底，直接铺 --primary-w 盖不住
   （同 .acc-row.dragging 的注释）。
   ⚠️ 必须排在 `.loan-card:active` **之后**：两者特异性相同（0,2,0），靠顺序取胜。 */
.loan-card.dragging{background:color-mix(in srgb, var(--primary) 12%, var(--card));position:relative;z-index:3;
  box-shadow:var(--shadow-lg);transition:none;cursor:grabbing}
.loan-card.dragging .lc-grip{cursor:grabbing}
.lc-out{font-size:16px;font-weight:700;font-variant-numeric:tabular-nums;flex:none;white-space:nowrap}
.lc-meta{display:flex;flex-wrap:wrap;gap:4px 12px;font-size:12px;color:var(--sub);margin-bottom:5px;padding-right:32px}
/* v58（真机第 45 轮反馈②）：进度条右端内缩 32px —— 手柄垂直居中后正好横在这一行的高度上，
   不让位就会压在进度条上（Fred：「把下面的进度条缩短一点」）。 */
.lc-prog{height:5px;border-radius:2px;background:var(--fill-2);overflow:hidden;margin-bottom:3px;margin-right:32px}
.lc-bar{height:100%;background:linear-gradient(90deg,var(--primary-l),var(--primary));border-radius:2px;transition:width .2s}
.lc-foot{display:flex;justify-content:space-between;font-size:12px;color:var(--sub);padding-right:32px}
/* 已结清卡片（真机第 28 轮反馈①）：
   ① 标题旁的「已结清」原来用全局 .pill（background:var(--fill) + 12px + 1px 8px 内边距），
      深底上的灰药丸 + 额外内边距把卡高顶起来 → 改成纯文字标签（.lc-done），无底色、不加高。
   ② 结清卡本来就没有进度条与脚注，之前却还留着 .lc-meta 的 5px 下边距 → 底部多出一截空白，
      卡比实际内容高。用 :has() 把最后一块的下边距收掉（本机 WebView 是 Chrome 内核，:has() 可用）。
   实测：结清卡多行 79 → 62px，单行 62 → 45px。 */
.loan-card .lc-done{font-size:12px;font-weight:600;color:var(--sub);margin-left:6px;flex:none}
.loan-card:has(.lc-done) .lc-meta{margin-bottom:0}
/* 次级分组的空态（真机第 29 轮反馈①）：已结清分组为空时原来复用 .empty 大空态
   （🏦 图在上、文字在下），被当成「已结清卡片上的房子图标」。次级分组只用一行字。 */
.sec-empty{padding:12px 14px;font-size:12px;color:var(--sub);text-align:center}
/* 计划表已还期灰化 + 整行划掉（真机第 27 轮反馈⑤：已还期「明细整行都划掉」）。
   原先是 opacity .62 的淡色，Fred 要的是删除线；淡色保留作为第二重提示。 */
table.plain tr.paid td{color:var(--sub);opacity:.62;text-decoration:line-through}
/* 还款明细：当前待还期（下一期未还）左侧一条色条，帮眼睛定位「现在还到哪」。
   ⚠️ 必须只画在**第一个格子**上（真机第 35 轮反馈④）：原来写成 `tr.due-next td`，
   6 个 td 各自在左边缘画一条 2px 蓝线 → 表里出现 6 条蓝竖线，用户看着像「蓝色边框」。
   仍用 inset box-shadow 而不是 border-left —— border 会吃 1px 内容宽、让该列数字错位。 */
table.plain tr.due-next td:first-child{box-shadow:inset 2px 0 0 0 var(--primary);font-weight:700;color:var(--text)}

/* ============ 自研日历组件（蓝色主色 / 按年跳转） ============ */
.cal{background:var(--card);border-radius:10px;padding:8px 6px 10px}
.cal-head{display:flex;align-items:center;justify-content:center;gap:2px;margin-bottom:6px}
.cal-nav{width:34px;height:34px;border:none;background:none;font-size:16px;color:var(--sub);border-radius:10px;font-weight:600}
.cal-nav:active{background:var(--primary-w)}
.cal-ym{min-width:120px;height:34px;text-align:center;font-weight:700;font-size:15px;color:var(--text);border:none;background:none;display:inline-flex;align-items:center;justify-content:center;gap:3px}
.cal-caret{font-size:11px;color:var(--sub)}
.cal-wd{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;font-size:11px;color:var(--sub);padding:4px 0;border-bottom:1px solid var(--line)}
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;padding-top:4px}
.cal-cell{position:relative;aspect-ratio:1/1;border:none;background:none;border-radius:10px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;font-size:13px;color:var(--text);cursor:pointer}
.cal-cell.out{color:var(--sub);opacity:.55}
.cal-cell.today .cal-day{color:var(--primary);font-weight:700}
.cal-cell.sel{background:var(--primary-btn);color:var(--primary-on)}
.cal-cell.sel .cal-day{color:var(--primary-on)}
.cal-cell.sel .cal-amt, .cal-cell.sel .cal-inc{color:var(--primary-on)}
/* 日历格里的当日金额（真机第 28 轮答复一·4）：这里原本写 var(--expense)，
   但 --expense 现在统一成了「支出蓝」（跟图表一致）→ 日历上的金额会跟着变蓝，
   而它在日历语境里承担的是「这天有支出，注意一下」的**提示**语义，该保持红。
   改用 --danger（危险/提示红），与 --expense 的「支出」语义正式分家。
   ⚠️ 真机第 42 轮反馈①：格子里现在是**两行** —— 收入 .cal-inc（正数带 +）
   与支出 .cal-amt（负数带 −）。两行都 line-height:1，否则 9px 的字会把格子撑高。
   ★ B1（2026-10-08）：两行的颜色改为跟随 A1 语义 —— 支出=--expense（浅绿）、
     收入=--income（浅红）。原来这里是「支出红 / 收入蓝」的第三套规则，
     与主流水（黑）、账户详情已统一后的语义都不一致，现随 --income/--expense 走。 */
.cal-amt{font-size:11px;color:var(--expense);font-variant-numeric:tabular-nums;transform:scale(.9);line-height:1}
.cal-inc{font-size:11px;color:var(--income);font-variant-numeric:tabular-nums;transform:scale(.9);line-height:1}
.cal-picker{background:var(--fill);border:1px solid var(--line);border-radius:10px;padding:8px 8px;margin:8px}
.dp-ygroup{margin:8px}
.dp-lbl{font-size:11px;color:var(--sub);margin-bottom:4px}
/* 两步下拉第二步的「‹ 重选年份」返回（真机第 43 轮反馈①）：小号文字按钮，跟标签同色系 */
.dp-back{border:none;background:none;padding:0 6px 0 0;color:var(--primary);font-size:11px;font-weight:600}
.dp-chips{display:flex;flex-wrap:wrap;gap:6px}
.dp-chip{min-width:44px;height:30px;padding:0 8px;border:1px solid var(--line);background:var(--card);border-radius:6px;font-size:12px;color:var(--text)}
.dp-chip.on{background:var(--primary-btn);border-color:var(--primary-btn);color:var(--primary-on)}
.dp-root{padding:2px}

/* ============ 还款计划标签（LPR 变动 / 提前还款） ============ */
.sch-tag{display:inline-block;font-size:11px;line-height:1;padding:3px 6px;border-radius:6px;font-weight:600;margin-bottom:3px}
.sch-tag.lpr{background:var(--primary-w);color:var(--primary)}
.sch-tag.prepay{background:var(--ok-w);color:var(--ok)}
.sch-tag.settled{background:var(--warn-w);color:var(--warn)}

/* LPR 变动记录（真机第 26 轮反馈③）：贷款详情页最下面一栏，每档 = 生效日 + LPR + 相对上一档的幅度。
   绿 = 利率下调（少付利息），红 = 上调；持平/初始用副色。
   .k 默认 flex:none，备注写长了会把右侧幅度顶出格子 → 改成可收缩 + 省略号。 */
.lpr-row .k{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lpr-d{font-size:12px;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}
.lpr-d.down{color:var(--ok)}
/* LPR 上调用 --danger 而不是 --expense（真机第 28 轮答复一·4）：
   --expense 已统一为「支出蓝」，而这里表达的是「利率涨了，对你不利」的**警示**语义，
   跟「这笔钱花出去了」不是一回事 → 走危险色，保持红。 */
.lpr-d.up{color:var(--danger)}
.lpr-d.flat{color:var(--sub);font-weight:500}

/* 万元格式化 */
.wan{font-variant-numeric:tabular-nums}

/* ════════════ 贷款详情页（真机第 27 轮反馈②③⑤） ════════════
   ② 顶端卡片：原来用**基类** .summary（不是 .loan-sum），于是
      「当前月供」走 .m-val.in 浅绿、「剩余本金」走 .m-val.out 浅粉 —— 颜色不统一；
      而「年利率」那格塞了「3.85% · LPR 4.2% +60BP」，1/3 列宽（≈104px）装不下被截断；
      最后那句「等额本息 · 2024-01-15 起贷 · 15 日还款 · 已还 3/240 期」用内联样式硬塞，
      长文本在窄屏折成两三行、和上面的 metric 挤在一起（Fred 说的「最三行文字堆一起」）。
   处理：换 .summary.loan-sum（整卡白字，与贷款页顶端同一套口径）+ 三格改成
      「当前月供 / 年利率 / 剩余本金」各自只放一个数；LPR 加点挪到下面独立的 .ld-meta 行，
      与还款方式、起贷日、还款日、进度一起按**行**排（每行一个信息块，不再挤成一行）。 */
.loan-detail .summary .metric .m-val{font-size:15px}
/* 详情页顶端卡片下的信息行：一行一件事，11.5px 副色，行距 1.4 —— 取代原来那句内联右对齐小字 */
.ld-meta{
  margin-top:10px;padding-top:9px;border-top:1px solid rgba(255,255,255,.18);
  display:flex;flex-direction:column;gap:4px;font-size:12px;line-height:1.4;
}
.ld-meta .ld-r{display:flex;justify-content:space-between;gap:10px;min-width:0}
.ld-meta .ld-r .k{opacity:.78;flex:none}
.ld-meta .ld-r .v{font-variant-numeric:tabular-nums;text-align:right;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 全角间隔号在读屏/复制时容易带出杂空格 → 用 0.5em 的独立 span 代替，语义仍是分隔 */
.ld-dot{display:inline-block;width:.5em;text-align:center;opacity:.5}

/* ③ 操作卡（本期还款/提前还款/更新 LPR）：原 card-pad 16px + chip-row 8px gap，
   三个按钮竖排到 390px 下正好两行 → 卡片偏高。改 .act-card 只留 12px 内边距。 */
.act-card{padding:12px}
.act-card .chip-row{gap:8px;margin-bottom:0}
/* 下一期卡片：三行 .kv-row（每行 8px 上下内边距）→ 压到 6px，并把「本金 / 利息」
   那一格的斜杠两侧空开，避免「1,234.56/3,456.78」糊成一团。 */
.next-card{padding:12px}
.next-card .hbar{margin-bottom:6px}
.next-card .kv-row{padding:6px 0}
.next-card .kv-row .v .sep{display:inline-block;width:.7em;text-align:center;color:var(--sub)}

/* ⑤ 还款明细：一张表（已还在上、待还在下，periodNo 连续升序）。
   .link 用按钮语义（原来是 span，点不到热区）。 */
.sch-toggle{color:var(--primary);font-size:13px;font-weight:500;background:none;border:none;padding:2px 0}
/* 行内可点（点开该期的编辑弹层）：整行 40px 高度保证触控热区，靠 .rec-go 约定给尾巴箭头 */
table.plain tr.row-hit{cursor:pointer}
table.plain tr.row-hit:active td{background:var(--fill)}
table.plain td .rec-go{color:var(--sub);font-size:13px;margin-left:2px}

/* ════════════ 提前还款策略（真机第 27 轮反馈⑥⑦ 全新） ════════════ */
/* 明细表输入：每行 = 日期 + 金额（万元） + 删行。用 grid 而不是 table —— 表头要跟输入框共列宽，
   而无边框输入框在 table 里会被 table-layout 算乱。 */
.combo-row{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:center;margin-bottom:8px}
.combo-row .cr-no{font-size:12px;color:var(--sub);font-variant-numeric:tabular-nums;min-width:14px;text-align:right}
.combo-row .cr-fields{display:flex;gap:8px;min-width:0}
.combo-row .cr-fields>*{min-width:0}
.combo-row .cr-date{flex:1.15 1 0}
.combo-row .cr-amt{flex:1 1 0}
.combo-row .cr-del{width:32px;height:32px;border-radius:10px;color:var(--sub);font-size:16px;background:var(--fill);flex:none}
.combo-row .cr-del:active{background:var(--danger-w);color:var(--danger)}
/* 手动微调明细行（真机第 33 轮反馈⑥）：方式 / 日期 / 金额 / 删除 一行四格。
   沿用「新增策略」那套组合行的视觉语言，只多一格「方式」——
   原来方式只能在方案卡上点标签切换，改的时候看不见其它笔。 */
.ep-head,.ep-row{display:grid;grid-template-columns:110px minmax(0,1fr) 68px 28px;gap:6px;align-items:center}
.ep-head{font-size:11px;color:var(--sub);margin:2px 0 6px;padding:0 2px}
.ep-row{margin-bottom:6px}
/* 「方式」= 并排两段选择（真机第 34 轮反馈②）：原来是一个「点一下切换」的小标签，
   手机上 title 提示不显示、没有任何能点的暗示，看着像只读文字 → 用户以为不能改。
   现在两个选项都摆出来，点哪个选哪个，当前项实心高亮。 */
.ep-row .ep-modes{display:flex;height:32px;border-radius:10px;overflow:hidden;background:var(--fill)}
.ep-row .ep-modes .ep-mode{flex:1;min-width:0;height:32px;border:0;border-radius:0;background:transparent;color:var(--sub);font-size:11px;font-weight:600;padding:0 2px;white-space:nowrap}
.ep-row .ep-modes .ep-mode.on{background:var(--primary);color:#fff}
.ep-row .ep-modes .ep-mode.on[data-v="shorten"]{background:var(--ok)}
.ep-row .ep-amt{text-align:right;min-width:0}
.ep-row .ep-del{width:28px;height:32px;border-radius:10px;color:var(--sub);font-size:15px;background:var(--fill)}
.ep-row .ep-del:active{background:var(--danger-w);color:var(--danger)}
.combo-head{display:grid;grid-template-columns:auto 1fr auto;gap:8px;font-size:11px;color:var(--sub);margin-bottom:6px;padding:0 2px}
.combo-head .ch-fields{display:flex;gap:8px}
.combo-head .ch-date{flex:1.15 1 0}
.combo-head .ch-amt{flex:1 1 0}
.combo-head .ch-del{width:32px}
.combo-sum{display:flex;justify-content:space-between;font-size:12px;color:var(--sub);padding:8px 2px 0;border-top:1px dashed var(--line);margin-top:2px}
.combo-sum b{color:var(--text);font-variant-numeric:tabular-nums}

/* 方案结果卡：方案序号圆牌 + 标题 + 该方案的逐笔方式串 */
.plan-card{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);margin-bottom:12px;padding:13px 14px}
.plan-card.picked{outline:2px solid var(--primary);outline-offset:-2px}
.plan-hd{display:flex;align-items:center;gap:8px;margin-bottom:8px}
.plan-key{
  width:26px;height:26px;border-radius:50%;background:var(--primary-btn);color:var(--primary-on);
  display:inline-flex;align-items:center;justify-content:center;font-size:13px;font-weight:700;flex:none;
}
.plan-hd .pt{flex:1;min-width:0;font-size:15px;font-weight:700;line-height:1.3}
.plan-seq{font-size:12px;color:var(--sub);margin-bottom:8px;line-height:1.45}
.plan-desc{font-size:12px;color:var(--sub);line-height:1.5;margin-top:8px;padding-top:8px;border-top:1px dashed var(--line)}
/* 真机第 36 轮反馈①：方案卡顶部的**综合得分**（月供项 70% + 省息项 30%，权重可在「我的 → 高级设置」改） */
.plan-score{display:flex;align-items:baseline;gap:6px;margin:0 0 8px;flex-wrap:wrap}
.plan-score .ps-n{font-size:24px;font-weight:700;line-height:1;color:var(--primary);font-variant-numeric:tabular-nums}
.plan-score .ps-u{font-size:12px;font-weight:600;color:var(--sub)}
.plan-score .ps-bd{font-size:12px;font-weight:600;color:var(--sub);font-variant-numeric:tabular-nums;margin-left:auto}
.plan-items{margin-top:8px;border-top:1px dashed var(--line);padding-top:6px}
.plan-items .pi-row{display:flex;justify-content:space-between;gap:8px;font-size:12px;padding:3px 0;color:var(--sub)}
.plan-items .pi-row .v{font-variant-numeric:tabular-nums;white-space:nowrap}
.plan-items .pi-row .v .tag{
  display:inline-block;font-size:11px;font-weight:600;padding:1px 6px;border-radius:6px;margin-right:6px;
}
.plan-items .pi-row .v .tag.shorten{background:var(--ok-w);color:var(--ok)}
.plan-items .pi-row .v .tag.reduce{background:var(--primary-w);color:var(--primary)}
/* 每一笔之后的实际变化（真机第 32 轮反馈③）：跟着对应那笔另起一行、右对齐。
   原来右侧只有一个「减月供 / 缩期数」标签，用户看不出这一笔到底起了多大作用。 */
.plan-items .pi-eff{
  font-size:12px;color:var(--sub);text-align:right;line-height:1.35;
  font-variant-numeric:tabular-nums;padding:0 0 5px;
}
/* 资金压力三档：ok 绿 / tight 橙 / over 红 */
.press{display:inline-flex;align-items:center;gap:4px;font-size:12px;font-weight:600;padding:1px 7px;border-radius:6px}
.press.ok{background:var(--ok-w);color:var(--ok)}
.press.tight{background:var(--warn-w);color:var(--warn)}
.press.over{background:var(--danger-w);color:var(--danger)}
/* 建议条：给出「建议选方案 X 或 Y」 */
.advice-bar{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:600;margin-bottom:10px}
.advice-bar .keys{display:inline-flex;gap:5px}
.advice-bar .keys b{background:var(--primary-btn);color:var(--primary-on);font-size:12px;padding:1px 8px;border-radius:6px}
/* 用户在结果页改过逐笔方式之后，原来的「综合建议」已对不上新数字 →
   撤掉方案高亮、换成这句提示（不然会出现「建议选方案 C，可 C 卡上的数已经是你改过的」这种自相矛盾）。 */
.advice-bar .adv-note{font-size:12px;font-weight:600;color:var(--sub)}
/* 重算期间：整块降透明度 + 禁点，既防连点堆请求，也告诉用户「确实在算」 */
.planList-busy, .busy-calc{opacity:.5;pointer-events:none;transition:opacity .15s}
/* 已保存策略列表行：名字 + 摘要 + 尾箭头 */
.stg-row{display:flex;align-items:center;gap:10px;width:100%;padding:11px 14px;text-align:left;min-width:0;border-bottom:1px solid var(--line)}
.stg-row:last-child{border-bottom:none}
.stg-row:active{background:var(--fill)}
.stg-row .sr-bd{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
.stg-row .sr-t1{font-size:15px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stg-row .sr-t2{font-size:12px;color:var(--sub);font-variant-numeric:tabular-nums;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stg-row .sr-go{color:var(--sub);font-size:15px;flex:none}

/* 还款计划表：列宽 + 横向滚动，保证剩余本金完整 */
.sch-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table.plain th,.lend-table th{white-space:nowrap}
.sch-wrap table.plain td{white-space:nowrap}

/* 列宽（真机第 33 轮反馈②）：期号列只放 1~3 位数、还款日列固定 10 个字符宽。
   原来没给宽度，table{width:100%} 会把多余空间平摊到每一列 →「期」和「还款日」之间
   被拉出一道很宽的空档（Fred：「期数和还款日之间的间隔太宽了」）。
   把这两列钉窄，多出来的宽度自然归三个金额列（本来就该它们最宽）。 */
.sch-wrap table.plain th:nth-child(1),.sch-wrap table.plain td:nth-child(1){width:40px}
.sch-wrap table.plain th:nth-child(2),.sch-wrap table.plain td:nth-child(2){width:88px}

/* 表头正下方的「合计」行（真机第 33 轮反馈②）：整笔贷款**全部期次**的合计，
   不随「展开全部 / 收起」变化。底色跟着表头走（同一块视觉区），用正文色 + 加粗跟普通表头区分。 */
.sch-wrap table.plain tr.sch-sum td{background:var(--fill);color:var(--text);font-weight:700;border-bottom:1px solid var(--line)}
.sch-wrap table.plain tr.sch-sum .sch-sum-sub{font-weight:600;color:var(--sub);font-size:12px}

/* 期次备注（第 28 轮反馈③ → 第 33 轮反馈② 改版 → 第 35 轮反馈⑤ 补数值）：
   标签放进「期」格里但**绝对定位**：① 脱离文档流 → 再长也不参与列宽计算，只向右延展；
   ② 带标签的行整体下移（下面的 t1/t2/t3 给固定 padding-top），标签浮在那段留白里。
   第 35 轮起标签变长（要带金额和 LPR 幅度），所以改成**每条独占一行**（flex-direction:column），
   行高按条数走 t1/t2/t3 三档 —— 不让长文本把某一行的行高顶起来，表就永远是齐的。
   left 要跟 .plain td 的左内边距对齐（7px 6px），否则标签贴不住左边界。 */
.sch-wrap table.plain td.sch-no{position:relative}
.sch-wrap table.plain td.sch-no .sch-tags{
  position:absolute;left:6px;top:3px;display:flex;flex-direction:column;align-items:flex-start;
  gap:1px;line-height:1.25;pointer-events:none;
  /* ⚠️ 必须显式 width:max-content：绝对定位元素的包含块是 td 的 padding box（只有 40px），
     shrink-to-fit 会把标签挤成几十像素、逐字折行（第 33 轮靠 flex-wrap:nowrap 侥幸躲过，
     第 35 轮改成一列后 nowrap 失效）。max-width 只是兜底，正常文案远短于它。 */
  width:max-content;max-width:calc(100vw - 96px);
}
.sch-wrap table.plain tr.has-tags.t1 td{padding-top:22px}
.sch-wrap table.plain tr.has-tags.t2 td{padding-top:34px}
.sch-wrap table.plain tr.has-tags.t3 td{padding-top:46px}
.sch-wrap table.plain td .sch-date{display:inline-block}
.sch-tags{display:flex;flex-wrap:wrap;gap:0 6px;margin-bottom:1px;line-height:1.25}
.sch-tag{display:inline-block;font-size:11px;line-height:1.25;padding:0;font-weight:600;background:none;border-radius:0;margin-bottom:0;white-space:nowrap}
.sch-tag.lpr{color:var(--primary)}
.sch-tag.prepay{color:var(--ok)}

/* ============ 记账页「本月看板」 ============ */
#flowBoard{margin-bottom:4px}
.flow-tabs{display:flex;gap:8px;margin:10px 0 4px}
.flow-tab{flex:1;height:32px;border-radius:10px;border:1px solid var(--line);background:var(--card);font-size:13px;font-weight:600;color:var(--sub)}
.flow-tab.on{background:var(--primary-btn);border-color:var(--primary-btn);color:var(--primary-on)}
.board-cat{padding:2px 0}
.board-ring{width:150px;height:150px;border-radius:50%;margin:6px auto;position:relative;display:flex;align-items:center;justify-content:center}
.board-ring.empty{background:var(--fill-2)}
.ring-center{width:86px;height:86px;border-radius:50%;background:var(--card);display:flex;flex-direction:column;align-items:center;justify-content:center;box-shadow:0 1px 4px rgba(0,0,0,.06)}
.ring-amt{font-size:15px;font-weight:700;font-variant-numeric:tabular-nums}
.ring-lbl{font-size:11px;color:var(--sub)}
.board-cat-list{display:flex;flex-direction:column;gap:6px;margin-top:8px}
.board-cat-row{display:flex;align-items:center;gap:10px;padding:9px 12px;background:var(--card);border-radius:10px;min-width:0}
.bc-ic{width:30px;height:30px;border-radius:50%;background:var(--primary-w);display:flex;align-items:center;justify-content:center;font-size:15px;flex:none}
.bc-name{flex:1;min-width:0;font-size:15px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bc-pct{width:46px;text-align:right;font-size:12px;color:var(--sub)}
.bc-amt{min-width:78px;text-align:right;font-size:15px;font-weight:600;font-variant-numeric:tabular-nums}
.board-chtgl{margin-top:8px;text-align:center}
.board-sum{display:flex;gap:10px;margin:6px 0}
.bs-card{flex:1;background:var(--card);border-radius:10px;padding:12px;text-align:center}
.bs-lbl{font-size:11px;color:var(--sub);margin-bottom:4px}
.bs-val{font-size:16px;font-weight:700;font-variant-numeric:tabular-nums}
.board-line{width:100%;height:90px;display:block}
.board-legend{display:flex;gap:14px;justify-content:center;font-size:11px;color:var(--sub);margin-top:6px}
.board-legend i{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:4px;vertical-align:-1px}
.board-day{margin-top:8px}
.dd-row{display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--line)}
.dd-row:last-child{border-bottom:none}
.dd-ic{width:30px;height:30px;border-radius:50%;background:var(--primary-w);display:flex;align-items:center;justify-content:center;font-size:15px;flex:none}
.dd-main{flex:1;min-width:0;font-size:15px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dd-amt{font-size:15px;font-weight:600;font-variant-numeric:tabular-nums}



/* ── 分类清单（记一笔 → 末尾「编辑」入口；v3.4 对齐真机参考图：图标球 + 名称 + 右箭头）── */
.cat-list{overflow:hidden;margin-bottom:10px}
.cat-lrow{display:flex;align-items:center;gap:12px;width:100%;min-width:0;padding:9px 14px;
  border-bottom:1px solid var(--line);text-align:left;
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;-webkit-user-drag:none}
.cat-lrow:last-child{border-bottom:0}
.cat-lic{width:36px;height:36px}
.cat-lname{flex:1;min-width:0;font-size:15px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 行尾拖动手柄（v3.8）：视觉 16px、触控区 44px；只在这块区域接收拖动。
   v3.9：去掉原来的 margin-right:-10px —— 手柄触控区原来贴到离屏幕右边只剩 18px，
   Android 手势导航的「边缘返回」就在这一带，真机按住容易没反应；退回行内边距（28px）更稳。 */
.cat-lgrip{width:44px;height:44px;flex:none;display:flex;align-items:center;justify-content:center;
  color:var(--sub);touch-action:none;cursor:grab}
.cat-lgrip svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}
/* 拖动中：被拖行浮起；只解除**卡片**这一层裁剪（.cat-list 是 overflow:hidden，不解除会被切掉）。
   绝不能动 .mf-body 的 overflow —— 它是滚动容器，清单一长就有 scrollTop>0，
   改成 visible 会把 scrollTop 钳回 0 ⇒ 整列表跳位、被拖行跑到屏幕外
   （真机复验第 9 轮补充：只有「要滚动才看得见的最后几行」会踩到，观感就是「拖不动」）。 */
.cat-lrow.dragging{background:var(--primary-w);position:relative;z-index:2;box-shadow:0 2px 10px rgba(0,0,0,.14)}
.cat-list.drag-host{overflow:visible}

/* ── 分类管理（记一笔「＋编辑」入口）── */
.cm-row{display:flex;align-items:center;gap:8px;padding:10px 14px;border-bottom:1px solid var(--line)}
.cm-row:last-child{border-bottom:0}
.cm-ic{width:28px;height:28px}
.cm-name{flex:1;min-width:0;font-size:15px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cm-act{border:1px solid var(--line);background:var(--card);color:var(--sub);border-radius:6px;padding:4px 10px;font-size:12px;cursor:pointer}
.cm-act.danger{color:var(--danger);border-color:color-mix(in srgb, var(--danger) 32%, transparent)}
/* A4：图标池从 18 枚扩到 51 枚（白皮书图标库 支出 40 + 收入 11）——
   限高自滚，避免弹层被撑到 92vh 把「名称 / 归属大类」挤出视野。 */
.cm-icons{display:grid;grid-template-columns:repeat(6,1fr);gap:8px;max-height:42vh;overflow-y:auto;padding:4px}
/* 图标选择器：未选中 = 浅蓝底 + 主色图形；选中 = 主色实底 + 反白图形（反转，对比最强）。
   ⚠️ 选中态的边必须用 --primary：旧值 --primary-d(#0b3a7e 近黑深蓝) 被真机读成「图标边框是黑色线」。 */
/* v8 真机反馈：图标选择器一律正圆（原为 10px 圆角方块），与账户表单 .acc-ick 同构 */
.cm-icpick{aspect-ratio:1;border-radius:50%;border:2px solid var(--ic-ring);background:var(--primary-w);color:var(--primary);cursor:pointer;display:flex;align-items:center;justify-content:center}
.cm-icpick svg{width:20px;height:20px}
.cm-icpick.on{border-color:var(--primary);background:var(--primary);color:var(--on-solid)}

/* ── 分类管理：两级化（大类分组，PRD §5.2.6）── */
.cm-group{margin-bottom:10px;overflow:hidden}
.cm-ghead{display:flex;align-items:center;gap:8px;padding:9px 14px;background:var(--fill);border-bottom:1px solid var(--line)}
.cm-gname{font-size:13px;font-weight:700;color:var(--text);flex:none;max-width:46%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cm-gcount{flex:1;min-width:0;font-size:11px;color:var(--sub)}
.cm-addin{display:block;width:100%;text-align:left;padding:9px 14px;font-size:12px;color:var(--primary);background:transparent;border:0;border-top:1px solid var(--line);cursor:pointer;font-family:inherit}
/* 归属大类选择 chips（小类新增/编辑弹层内） */
.cm-groups{display:flex;flex-wrap:wrap;gap:6px}
.cm-gpick{padding:6px 12px;border-radius:14px;background:var(--fill-2);color:var(--sub);font-size:12px;border:2px solid transparent;cursor:pointer;font-family:inherit;min-height:32px}
.cm-gpick.on{background:var(--primary-w);color:var(--primary);border-color:var(--primary);font-weight:600}

/* ============ 财务规划模块（M4 · 页 ⑦⑧⑨） ============ */
.plan-page{padding-bottom:8px}

/* 页头：左标题 + 右上角动作按钮（页面规范 §2.2 · T6）
   ★ 应用外壳只有底部导航、没有顶栏，所以这里是**页面内**的页头，位置等价于效果图里的「右上角」。
   ★ 底色/字色走 --primary 派生（不写死 #E6EEF9 / #014DB2），六套皮肤自动适配。 */
.pg-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:2px 2px 10px}
.pg-head-t{font-size:16px;font-weight:700;color:var(--text)}
.nav-act{position:relative;display:inline-flex;align-items:center;gap:5px;height:32px;padding:0 12px;border-radius:14px;
  /* ★ 第三批：底色 10%→6% —— 10% 时 amber 皮肤上文字对比度只有 4.38（<AA 4.5），
     调浅底色是最小改动（换文字色会砸掉深色皮肤：那里 --primary-d 是深蓝）。 */
  border:0;background:color-mix(in srgb,var(--primary) 6%,var(--card));color:var(--primary);
  font-size:12px;font-weight:700;flex:none;max-width:40vw;white-space:nowrap}
.nav-act:active{background:color-mix(in srgb,var(--primary) 14%,var(--card))}
.nav-act svg{width:13px;height:13px;flex:none;stroke:currentColor;fill:none;
  stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
/* ★ 必须显式写：上面的 display:inline-flex 会盖掉 UA 的 [hidden]{display:none}（类选择器优先级更高） */
.nav-act[hidden]{display:none}

/* ── 财务规划空态（第 70 轮 Fred 测试反馈①，效果图 1:1）────────────────
   图标块 + 标题 + 两行说明 + 三张特性卡 + 主按钮 + 底部小字。
   底色/字色一律走 --primary 派生，不写死色值，六套皮肤自动适配（同 .pg-head 的约定）。 */
.pl-empty{display:flex;flex-direction:column;align-items:center;padding:22px 4px 12px;text-align:center}
.pl-empty-ic{width:88px;height:88px;border-radius:24px;display:flex;align-items:center;justify-content:center;
  font-size:36px;line-height:1;background:color-mix(in srgb,var(--primary) 10%,var(--card));margin-bottom:16px}
.pl-empty-t{font-size:18px;font-weight:700;color:var(--text);margin-bottom:9px}
.pl-empty-d{font-size:12px;line-height:1.75;color:var(--sub);margin-bottom:20px}
.pl-feats{width:100%;box-sizing:border-box;background:var(--card);border-radius:14px;padding:2px 14px;
  border:1px solid color-mix(in srgb,var(--sub) 14%,var(--card));text-align:left}
.pl-feat{display:flex;gap:11px;padding:13px 0}
.pl-feat + .pl-feat{border-top:1px solid color-mix(in srgb,var(--sub) 12%,var(--card))}
.pl-feat-ic{width:30px;height:30px;flex:none;border-radius:10px;display:flex;align-items:center;justify-content:center;
  font-size:16px;line-height:1;background:color-mix(in srgb,var(--primary) 9%,var(--card))}
.pl-feat-tx b{display:block;font-size:15px;font-weight:700;color:var(--text);margin-bottom:3px}
.pl-feat-tx p{margin:0;font-size:12px;line-height:1.65;color:var(--sub)}
.pl-empty-btn{width:100%;margin-top:18px}
.pl-empty-note{margin-top:11px;font-size:12px;color:var(--sub)}

/* ── 内容区标题行 + 年度盘点入口（第 70 轮：页签取消后改从财务规划页进入）──
   规格见 `docs/页面规范-财务规划入口与年度盘点.md` §2.2/§3：入口在**内容区标题行右侧**。
   ★ 盘点页本身零改动，这里只是一个「进得去」的入口。 */
.pl-titlerow{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 2px 10px}
.pl-titlerow-y{font-size:18px;font-weight:700;color:var(--text);flex:none}
/* ★ 第 73 轮：标题行右侧动作区（表格切换 / ⋯ 方案操作）。
   原先这 3 个按钮在 `.pg-head` 里横排，顶到屏幕右缘（Fred 反馈①④「超过了标签页」），
   现在并入标题行右侧，随标题行 flex 排布。
   ★ 第 74 轮：只剩 2 个（视图切换 + ⋯），「年度盘点」下沉进年份卡（见 `.rv-row` / `.yrow-rv`）。 */
.pl-titlerow-acts{display:inline-flex;align-items:center;gap:6px;flex:none;min-width:0}
/* ⋯ 按钮：字符略大一点、左右各留够padding，才不会看着像"点不动的点" */
.pl-titlerow-acts .nav-act{max-width:none;padding:0 10px;font-size:12px;flex:none;overflow:visible}
.pl-titlerow-acts .nav-act[hidden]{display:none}
.pl-titlerow-acts #pl-set{font-size:15px;line-height:1;padding:0 12px;letter-spacing:1px}
.rv-link{display:inline-flex;align-items:center;height:28px;padding:0 10px;border-radius:14px;border:0;
  background:transparent;color:var(--primary);font-size:12px;font-weight:700;
  font-family:inherit;cursor:pointer;flex:none;white-space:nowrap}
.rv-link:active{background:color-mix(in srgb,var(--primary) 10%,var(--card))}

/* ★ 第 74 轮（Fred 反馈①）：年度盘点入口下沉到年份卡内 ——
   展开态：对照卡底部一整行 `.rv-row`（贴住卡片下缘，视觉上"属于这张卡"）。
   ★ 第 75 轮（Fred 反馈④）：收起态那颗小「盘点 ›」已删（`.yrow-rv` 规则随之删除）——
   年度盘点是低频动作，且语义绑在那张年的对照卡上，收起时就先看不见。 */
.rv-row{display:flex;align-items:center;justify-content:center;gap:8px;
  padding:8px 14px 10px;border-top:1px solid var(--line)}
.pl-cmp .rv-row .rv-link{height:26px;font-size:12px}

/* ── 当年「规划 / 实际」双栏对照卡 + 往年摘要（第 71 轮，照效果图 ①）────────────
   卡片式明细，**不是表格** —— 只统一边框 / 分隔线 / 分组底色（同 box-sizing 与 .tcard）。
   左右两栏各自浅底：左「规划」暖白、右「实际」浅青，中间 1px 竖线；当年结余行加粗强调。
   ★ 第 72 轮（Fred 反馈②）：`.card-hd` / `.yrow` 都变成**可点折展**的入口 ——
     两者都带 `role=button + tabindex=0`，光标与按压反馈按按钮给。 */
.pl-cmp{margin-bottom:12px}
.pl-cmp .card-hd{display:flex;align-items:center;justify-content:space-between;
  padding:0 13px;height:38px;background:var(--primary-w);color:var(--primary);
  border-bottom:1px solid var(--line);cursor:pointer;-webkit-tap-highlight-color:transparent;
  user-select:none}
.pl-cmp .card-hd:active{background:color-mix(in srgb,var(--primary) 16%,var(--card))}
.pl-cmp .card-hd-t{font-size:12px;font-weight:700;letter-spacing:.2px}
.pl-cmp .card-hd-v{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;color:var(--primary)}
/* 折展指示三角：展开时朝下 ⌄，收起时朝右 ›（旋转 90°） */
.pl-cmp .card-hd-v .hd-cv{display:inline-block;font-size:12px;line-height:1;opacity:.8;
  transition:transform .18s}
/* ★ 第 73 轮：`.pl-cmp.is-closed` 三条规则**整体删除**。
   当年收起后不再退化成「蓝底卡头」，而是与往年一样渲染成 `.yrow` 摘要行
   （Fred 反馈③：「应该每个年度保持一样的样式」）⇒ 收起态已无 `.pl-cmp`，
   保留这些规则就是没人会命中它们。收起时 `.yrow .hd-cv` 用 `›` 表达，不再需要旋转。 */
/* 往年展开出来的对照卡：与当年卡同款，只是去掉外描边强调 */
.pl-cmp-past{margin:10px 0}
.pl-cmp .cmp{display:flex;border-top:1px solid var(--line)}
.pl-cmp .cmp .c{flex:1 1 0;min-width:0;padding:10px 10px 12px}
.pl-cmp .cmp .c+.c{border-left:1px solid var(--line)}
.pl-cmp .cmp .c.e{background:var(--expense-w)}
.pl-cmp .cmp .c.i{background:var(--income-w)}
.pl-cmp .cmp .c .hd{text-align:center;font-size:11px;font-weight:700;letter-spacing:.4px;
  padding:5px 0 7px;margin:-10px -10px 8px;border-bottom:1px solid var(--line)}
.pl-cmp .cmp .c.e .hd{color:var(--expense);background:var(--expense-w)}
.pl-cmp .cmp .c.i .hd{color:var(--income);background:var(--income-w)}
.pl-cmp .cmp .c .r{display:flex;justify-content:space-between;align-items:baseline;gap:6px;
  font-size:12px;line-height:1.35;padding:5px 0;border-bottom:1px solid var(--line)}
.pl-cmp .cmp .c .r:last-child{border-bottom:none}
.pl-cmp .cmp .c .r .k{color:var(--sub);flex:none}
.pl-cmp .cmp .c .r .v{font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}
.pl-cmp .cmp .c .r .v.out{color:var(--expense)}
.pl-cmp .cmp .c .r .v.in{color:var(--income)}
.pl-cmp .cmp .c .r.sum{border-top:2px solid var(--line);border-bottom:none;margin-top:6px;padding-top:7px}
.pl-cmp .cmp .c.e .r.sum{background:var(--expense-w);margin-left:-10px;margin-right:-10px;padding-left:10px;padding-right:10px}
.pl-cmp .cmp .c.i .r.sum{background:var(--income-w);margin-left:-10px;margin-right:-10px;padding-left:10px;padding-right:10px}
.pl-cmp .cmp .c .r.sum .k{font-weight:700;color:var(--text)}
.pl-cmp .cmp .c .r.sum .v{font-weight:700;font-size:13px}
/* 实际列的「—」占位（第 71 轮）：细分类行在实际列没有对应口径 → 显式留白，不造数 */
.pl-cmp .cmp .c .r .dash{color:var(--sub);opacity:.55;font-weight:500}

/* 往年一行摘要：年份 + 「净资产 X 万 / 结余 ±Y 万」右对齐两行
   ★ 第 72 轮：整行可点（展开成同款对照卡），故补 cursor / 按压底 / 右侧 › 指示 */
.pl-past{padding:2px 14px}
.pl-past .yrow{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:11px 0;border-bottom:1px solid var(--line);cursor:pointer;
  -webkit-tap-highlight-color:transparent;user-select:none}
.pl-past .yrow:last-child{border-bottom:0}
.pl-past .yrow:active{background:var(--fill-2);margin:0 -14px;padding-left:14px;padding-right:14px}
.pl-past .yrow .y{display:inline-flex;align-items:center;gap:5px;font-size:15px;font-weight:700;color:var(--text)}
.pl-past .yrow .y .hd-cv{font-size:13px;font-weight:700;color:var(--sub);opacity:.8;line-height:1}
.pl-past .yrow .s{text-align:right;font-size:12px;color:var(--sub);line-height:1.65}
.pl-past .yrow .s b{font-size:15px;font-weight:700;color:var(--text);font-variant-numeric:tabular-nums}

/* ★ 第 74 轮：`.pg-head-acts` / `.nav-act-danger` 两条规则**整体删除** ——
   它们服务于第 72 轮的 `.pg-head`（页头右侧动作组），而第 73 轮已把整块 `.pg-head`
   从 DOM 里删掉（Fred 反馈①④）。`grep pg-head-acts|nav-act-danger public/**/*.js` 无命中
   ⇒ 留着就是没人会命中它的死代码。 */
.nav-act-danger:active{background:color-mix(in srgb,var(--expense) 20%,var(--card))}

/* ── 表格视图（效果图 ② 的 14 列宽表，第 72 轮）────────────────────────
   每年两行（`.lv-p` 规划 / `.lv-a` 实际）；年份与版本两列冻结（`.frz`），
   最右「年底净资产」钉住（`.pin.pin2`）作关键指标。
   ★ 配色按效果图顶部图例（天青蓝）：表头 #E8F0FA/#1B4E8C · 分组带 #DCE8F8
     · 冻结列 #E7EAFF · 钉住列 #EFF6FF · 组缝 #D5E2F2 —— 全部走 `--tbx-*` 令牌。 */
.pv-note{padding:2px 2px 8px;font-size:12px;color:var(--sub);line-height:1.7}
.pv-note b{color:var(--tbx-hd-fg)}
.tbx-pv{overflow-x:auto;-webkit-overflow-scrolling:touch;border-radius:10px}
/* ★ 固定布局：列宽严格照 `colgroup` 走（auto 布局会把 52/44 挤成 42/38）。
   冻结列宽度必须与 `--pv-fz-1/--pv-fz-2` 完全一致，否则横滚时两列之间会漏出内容。
   ⚠️ 第二个坑（实测踩到）：`table-layout:fixed` + `width:auto` 时，若**显式宽度和**
   小于浏览器算出的表宽，Chrome 会把各列**按最小内容宽**重排（实测 58px 的列被渲染成
   38/45/47 三种值），此时任何「列宽 = 常量」的假设都失效。
   ⇒ 正解：表宽**显式等于列宽和**（`--pv-w-sum`，在下面用 calc 展开），永不进入收缩分支。 */
.pv-table{table-layout:fixed;border-collapse:separate;border-spacing:0;
  width:calc(var(--pv-fz-1) + var(--pv-fz-2) + var(--pv-w-rest));min-width:100%;
  font-size:12px;--pv-fz-1:52px;--pv-fz-2:52px;
  --pv-w-rest:58px*6 + 58px + 58px + 60px + 58px*3 + 66px}
.pv-table th,.pv-table td{white-space:nowrap;padding:7px 6px;text-align:right;
  border-bottom:1px solid var(--tbx-hd-line);font-variant-numeric:tabular-nums}
.pv-table thead th{background:var(--tbx-hd-bg);color:var(--tbx-hd-fg);font-weight:700;
  font-size:11px;line-height:1.25;text-align:right;vertical-align:middle}
.pv-table thead tr:first-child th{height:30px}
.pv-table thead th.pv-gp{text-align:center;background:var(--tbx-gp-bg);color:var(--tbx-hd-fg);font-size:11px}
.pv-table thead th.frz,.pv-table thead th.v{text-align:center}
/* 冻结列：年份（左起第 1 列）+ 版本（第 2 列）
   ★ 第 72 轮教训 + 第 75 轮修正：曾为「冻结带逐行连续」把 tbody 的「年份」去掉 rowspan，
     改成规划/实际两行各出一格（`.lv-a` 那格留空去内沿线）⇒ 视觉上像合并、实际是两个洞。
     Fred 第 75 轮要求真合并（`rowspan=2`），故恢复rowspan，并把护栏换成
     「横滚后用 `elementsFromPoint`验左带最上层是冻结格」（见 `tools/ui-smoke.mjs`）。
   ⇒ 合并格必须**自己盖住两行**：td 默认撑满 rowspan 区间 + 冻结格底色不透明（下方 `td.frz` 规则），
     且 `z-index` 要压过同行的普通格 —— `.frz` 的 `z-index:2` 已满足。 */
.pv-table th.frz,.pv-table td.frz{position:sticky;background:var(--tbx-fz-bg);z-index:2;text-align:center}
.pv-table th.frz{background:var(--tbx-hd-bg);z-index:3}
.pv-table th.frz:nth-child(1),.pv-table td.frz:nth-child(1){left:0}
/* ★ 第二列的 `left` 偏移必须 = 第一列**实际渲染宽**，而不是 colgroup 里的声明值。
   三个坑叠在一起（第 72 轮实测）：
     ① `table-layout:auto` 会把 52/44 挤成 42/38 ⇒ 偏移比真实边界大 10px ⇒ **漏缝**；
     ② 改 `table-layout:fixed` 后若表宽 ≠ 列宽和，Chrome 仍按**最小内容宽**重排列 ⇒ 继续漏；
     ③ 表宽修好后，`.tbx` 给每格的 `border-right:1px` + `padding:0 7px` 会让
        「声明 52px」的列**实测 56px**（`border-collapse:separate` 下边框算进列宽）
        ⇒ 若偏移仍用 52px，两列之间会**重叠** 4px（重叠是安全的，漏缝才是问题）。
   ⇒ 所以偏移 = `--pv-fz-1` + `--pv-fz-pad`（每格横向边框+间距的补偿量，默认 4px）。
     改列宽只动 `--pv-fz-1/--pv-fz-2`，两处自动一致。 */
.pv-table th.frz.v,.pv-table td.frz.v{left:calc(var(--pv-fz-1) + var(--pv-fz-pad,4px))}
.pv-table thead th.frz.v{z-index:4}
/* ★ 第 75 轮：年份格 `rowspan=2` 真合并 ⇒ 内容在两行中间垂直居中（原先是两个 td，
   「年份」永远显示在上格）。同时给 `.carry`「沿用」角标留出点空间。 */
.pv-table tbody td.fz-year{vertical-align:middle;line-height:1.25}
/* 钉住最右一列「年底净资产」（`.pin.pin2`）；「当年结余」只加底纹强调、不钉
   （它在第 10 列、与右边缘隔 3 列，贴右会盖住中间三列 —— 实测如此）。 */
.pv-table th.pin,.pv-table td.pin{position:sticky;right:0;background:var(--tbx-pin-bg);z-index:2;
  font-weight:700}
.pv-table th.pin{background:var(--tbx-pin-hd-bg);color:var(--tbx-pin-hd-fg);z-index:3}
.pv-table th.pin.pin2,.pv-table td.pin.pin2{
  box-shadow:-6px 0 8px -6px color-mix(in srgb,var(--tbx-hd-fg) 30%,transparent)}
/* 当年结余：关键指标但不钉，用底纹让它一眼可见 */
.pv-table thead th.pin-hl{background:var(--tbx-gp-bg);color:var(--tbx-hd-fg)}
/* 行底纹：规划行用极浅的蓝底、实际行用卡片底 —— 两行一眼分得开 */
.pv-table tbody tr.lv-p td{background:color-mix(in srgb,var(--tbx-hd-bg) 62%,var(--card))}
.pv-table tbody tr.lv-a td{background:var(--card)}
.pv-table tbody tr.lv-a td.frz.v{color:var(--sub);font-weight:600}
/* ★ 冻结格 / 钉住格必须显式盖回**不透明**底色：行底纹上面已给它们上了淡蓝，
   但 sticky 格子在滚动时不能透出后面的内容。 */
.pv-table tbody tr.lv-p td.frz{background:var(--tbx-fz-bg)}
.pv-table tbody tr.lv-a td.frz{background:var(--tbx-fz-bg)}
.pv-table tbody tr.lv-p td.pin{background:var(--tbx-pin-bg)}
.pv-table tbody tr.lv-a td.pin{background:var(--tbx-pin-bg)}
.pv-table tbody tr.grp-start td{border-top:1.5px solid var(--tbx-hd-line)}
.pv-table tbody tr.lv-p td.pin2{background:var(--tbx-pin-bg-a)}
.pv-table td .dash{color:var(--sub);opacity:.55}
.pv-table td .carry{display:inline-block;margin-left:3px;font-size:11px;color:var(--sub)}


/* 方案卡片 */
.plan-card{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);
  padding:12px 12px;margin:8px;border:1.5px solid transparent}
.plan-card.is-target{border-color:var(--primary-l);background:var(--primary-w)}
.pc-head{display:flex;align-items:center;gap:8px;margin-bottom:9px}
.pc-name{font-size:16px;font-weight:700;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pill-target{background:var(--primary-btn);color:var(--primary-on)}
.pill-loan{background:var(--warn-w);color:var(--warn)}
.pc-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:9px}
.pc-grid>div{display:flex;flex-direction:column;gap:2px;min-width:0}
.pc-grid i{font-size:11px;color:var(--sub);font-style:normal}
.pc-grid b{font-size:15px;font-weight:600;font-variant-numeric:tabular-nums;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.c-in{color:var(--income)}
.c-out{color:var(--text)}
.pc-meta{display:flex;flex-wrap:wrap;gap:6px 12px;font-size:12px;color:var(--sub);margin-bottom:10px}
.pc-acts{display:flex;gap:6px;flex-wrap:wrap}
.mini{position:relative;flex:none;min-height:33px;padding:0 13px;border-radius:14px;border:1px solid var(--line);
  background:var(--card);color:var(--sub);font-size:13px;font-weight:500;
  display:inline-flex;align-items:center;justify-content:center;white-space:nowrap}
.mini:active{background:var(--fill-2)}
.mini.soft{background:var(--primary-w);border-color:transparent;color:var(--primary)}
.mini.danger{color:var(--danger);background:var(--danger-w);border-color:transparent}
.mini.primary{background:var(--primary-btn);border-color:transparent;color:var(--primary-on);font-weight:600}
.mini.primary:active{background:var(--primary-d)}

/* 预测表 / 通用表格 */
.sec-r{display:flex;gap:5px}
.span-btn{padding:3px 10px;border-radius:10px;background:var(--fill-2);color:var(--sub);font-size:12px}
.span-btn.on{background:var(--primary-btn);color:var(--primary-on);font-weight:600}
.tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;border-radius:10px;background:var(--card);
  box-shadow:var(--shadow)}
.fc-tbl{width:100%;border-collapse:collapse;font-size:12px;white-space:nowrap}
.fc-tbl th{font-weight:600;color:var(--sub);font-size:11px;text-align:right;padding:6px 8px;
  background:var(--fill);position:sticky;top:0}
.fc-tbl th:first-child,.fc-tbl td:first-child{text-align:left}
.fc-tbl td{padding:6px 8px;text-align:right;border-top:1px solid var(--line);
  font-variant-numeric:tabular-nums}
.fc-y{font-weight:600;color:var(--text)}
.fc-net{font-weight:700;color:var(--primary)}
.fc-empty{color:var(--sub);text-align:center !important}
.carry{display:inline-block;margin-left:4px;padding:0 5px;border-radius:6px;background:var(--fill);
  color:var(--sub);font-size:11px;font-weight:500}
.fc-note{font-size:12px;color:var(--sub);margin:8px 2px 6px}
.neg{color:var(--danger)}
.plan-tip{background:var(--card);border-radius:10px;box-shadow:var(--shadow);padding:18px;
  text-align:center;color:var(--sub);font-size:13px}
.pf-sec{font-size:12px;color:var(--sub);font-weight:600;margin:14px 0 7px;
  padding-left:8px;border-left:3px solid var(--primary)}
.pf-sec .mini{font-weight:500}

/* ══ 财务规划表单：**分区卡片**（第 91 轮，Fred 反馈①④：必须与效果图一致）══
   每区一张白卡，卡头 = 序号徽标 + 标题 + ⓘ；说明文字全部收进 `.pf-tip`，
   默认隐藏、点 ⓘ 才展开（原来是一堆常显的灰色小字，页面又长又花、还跟效果图不一样）。 */
.pf-card{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);
  margin:0 0 10px;overflow:hidden}
.pf-hd{display:flex;align-items:center;gap:8px;padding:13px 14px 10px}
.pf-hd .pf-n{flex:none;width:18px;height:18px;border-radius:6px;background:var(--primary-w);
  color:var(--primary);font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center}
.pf-hd .pf-t{flex:1;min-width:0;font-size:14px;font-weight:600;color:var(--text);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pf-hd .pill{flex:none}
.pf-i{flex:none;width:18px;height:18px;border-radius:50%;border:1px solid var(--line);
  color:var(--sub);font-size:11px;font-style:italic;line-height:1;display:flex;
  align-items:center;justify-content:center;cursor:pointer;user-select:none}
.pf-tip{display:none;margin:0 14px 10px;padding:8px 10px;background:var(--fill);
  border-radius:9px;font-size:12px;line-height:1.6;color:var(--sub)}
.pf-tip.on{display:block}
/* 行式字段：左标签 / 右数值 / 定宽单位 / ⓘ（对齐效果图第 2 张卡 —— 四个框在同一张卡里，
   不再拆成「一整行一个框 + 并排两个框」那种拼盘） */
.pf-row{display:flex;align-items:center;min-height:48px;padding:0 14px;border-top:1px solid var(--line2)}
.pf-row .lb{flex:0 0 auto;color:var(--text);font-size:13.5px}
.pf-row .lb .req{color:var(--danger);font-style:normal;margin-left:2px}
.pf-row .sp{flex:1}
.pf-row .unit{flex:0 0 auto;min-width:30px;margin-left:4px;color:var(--sub);font-size:12.5px}
.pf-row .pf-inp{flex:none;width:104px;height:34px;border:0;background:transparent;outline:none;
  text-align:right;font-size:16px;font-weight:600;font-family:inherit;color:var(--text);
  font-variant-numeric:tabular-nums;border-radius:8px;padding:0 6px}
.pf-row .pf-inp:focus{background:var(--primary-w);box-shadow:inset 0 0 0 1px var(--primary-l)}
/* ★ 提示文字必须**显式压回 400**：`::placeholder` 会继承 input 自身的 font-weight，
   而 `.pf-inp` 是 600 ⇒ 光改颜色的话空框里的提示照样又黑又粗，看着像已经填过了（§W-ph）。 */
.pf-row .pf-inp::placeholder{color:var(--ph);font-weight:400;opacity:1}
/* 规划区间：两块浅底格子（小字标签在上、年份大字在下 + ▾），与效果图同款 */
.pg-grid2{display:flex;gap:10px;padding:0 14px 12px}
.pg-cell{flex:1 1 0;min-width:0;background:var(--fill);border-radius:11px;padding:8px 11px}
.pg-cell label{display:block;font-size:11.5px;color:var(--sub);margin-bottom:2px}
.pg-cell .pg-ysel{width:100%;border:0;background:transparent;outline:none;font-family:inherit;
  font-size:16px;font-weight:600;color:var(--text);font-variant-numeric:tabular-nums;
  padding:0 18px 0 0;appearance:none;-webkit-appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='11' viewBox='0 0 10 10'%3E%3Cpath d='M2 3.6l3 3 3-3' fill='none' stroke='%239aa3b2' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 2px center}
.pf-span{display:flex;align-items:center;gap:6px;padding:0 14px 12px;font-size:12px;color:var(--sub)}
.pf-span b{color:var(--primary);font-weight:600}

/* 多年规划方案区（M4.5 · PRD §5.3.0） */
/* 方案 chips 行：方案多时横向滑动（效果稿 v2.0） */
.pg-chips{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;padding:2px;margin:0 0 12px;scrollbar-width:none}
.pg-chips::-webkit-scrollbar{display:none}
/* 方案卡 kv 信息行（效果稿：标签左 / 数值中 / 注释右）
   注意：全局已有旧 .kv（流水详情用，纵向排列）——必须用 .pg-card 前缀提升优先级 */
.pg-card .kv{display:flex;flex-direction:row;align-items:baseline;gap:8px;padding:4px 0;min-width:0;border-bottom:none}
.pg-card .kv .k{color:var(--sub);font-size:12px;flex:none}
.pg-card .kv .v{font-weight:700;font-size:15px;font-variant-numeric:tabular-nums;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;word-break:normal}
.pg-card .kv .tgt{margin-left:auto;color:var(--sub);font-size:12px;flex:none;text-align:right;font-weight:400}
/* .pg-empty（旧空态那条灰字提示）已随第 70 轮空态改造删除，改由 .pl-empty 承接（见上方财务规划空态段） */
.pg-card{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);
  padding:12px 12px;margin:8px;border:1.5px solid transparent}
.pg-card.is-active{border-color:var(--primary-l);background:var(--primary-w)}
.pg-span{font-size:12px;color:var(--sub);flex:none}

/* 多年规划年度明细表（首年 → 终止年） */
.span-tbl{font-size:12px}
/* 两级表头：th 不做 sticky —— 两行都钉在 top:0 会互相覆盖 */
.span-tbl thead th{position:static}
.span-tbl thead tr:first-child th{text-align:center}
.span-tbl thead tr:first-child th:first-child{text-align:left}
.span-tbl td.sp-y{font-weight:600;color:var(--text);text-align:left}
.span-tbl td.sp-y .pill{margin-left:5px}
.span-tbl td.sp-act{text-align:right;padding-right:4px}
.span-tbl td.sp-net{font-weight:600;color:var(--primary)}
.span-tbl tr.is-target{background:var(--primary-w)}
.span-tbl tr.is-target td.sp-y{color:var(--primary)}
/* .pill-src（「多年规划」来源标签）已随第 70 轮——取消「多年/单年」区分——一并删除：
   该标签在所有卡片上恒为真，没有信息量。 */
.pill-manual{background:var(--warn-w);color:var(--warn)}

/* ── 多年规划表单：明细表（第 89 轮建 / 第 90 轮按 Fred 效果图重做 / 第 91 轮补输入框外观）──
   四张表（收入 / 支出 / 固定资产 / 债务）共用**同一套骨架**：
     · 表头是**纯文字列名**，重命名 / 删除收进一枚极淡的「⋯」—— 平时看不到输入框和 ✕；
     · 格子**有浅底 + 细边**、右对齐、等宽数字，聚焦才浮出主色底（跟全站输入框同一套语义）——
       第 91 轮补的：原来无边框，与右侧只读的「合计」列长得一样，用户分不清哪格能填；
     · 末列固定是「合计 / 累计」；
     · ⚠️ 必须 `table-layout:fixed` + 每列显式宽度 —— `auto` 布局下 `<input>` 的
       **固有宽度**会把列撑到 400px+、右对齐的数字被顶出可视区（实测踩过，§W-table）。 */
.pg-del{flex:none;width:30px;height:30px;border-radius:6px;background:var(--danger-w);color:var(--danger);
  font-size:13px;display:flex;align-items:center;justify-content:center}
.pg-del:active{background:var(--danger-w)}

.pg-mx-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:2px}
/* ⚠️ 表宽由 JS 按「列宽之和」显式写（见 matrixHtml），这里再加 `min-width:100%`：
   列少时撑满容器（不然右边留一大块空白），列多时由外层 .pg-mx-wrap 横向滚动。 */
.pg-mx{border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:13px;min-width:100%}
.pg-mx th,.pg-mx td{padding:0;height:44px;white-space:nowrap;font-weight:400;vertical-align:middle}
/* 表头：纯文字列名（右对齐跟数字列对齐；年份列左贴） */
.pg-mx thead th{height:32px;font-size:11.5px;color:var(--sub);text-align:right;
  padding:0 10px 0 4px;border-bottom:1px solid var(--line);width:104px}
.pg-mx thead th.pgm-y{text-align:left;padding-left:14px;width:56px}
.pg-mx thead th.pgm-sum{color:var(--text);font-weight:600;width:84px;padding-right:14px}
.pg-mx thead th.pgm-n .pgm-hd{display:inline-block;max-width:70px;overflow:hidden;
  text-overflow:ellipsis;vertical-align:middle}
.pg-mx thead th.pgm-n .pgm-more{border:0;background:transparent;color:#C3CAD6;font-size:14px;
  line-height:1;padding:6px 5px;cursor:pointer;vertical-align:middle;font-family:inherit}
/* 数字输入框去掉原生上下箭头（移动端也不显示，但桌面 / WebView 会冒出来，跟效果图不一致） */
.pg-mx input[type=number]::-webkit-outer-spin-button,
.pg-mx input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.pg-mx input[type=number]{-moz-appearance:textfield}
.pg-mx thead th.pgm-n .pgm-nm{width:calc(100% - 18px);height:30px;border:1px solid var(--primary-l);
  border-radius:8px;background:var(--card);color:var(--text);font-size:12.5px;font-family:inherit;
  padding:0 6px;text-align:right;outline:none}
/* 行头（年份）：左贴 + 横向滚动时钉住（列多必用） */
.pg-mx tbody th.pgm-y{color:var(--sub);font-size:12.5px;text-align:left;padding-left:14px;
  font-variant-numeric:tabular-nums;position:sticky;left:0;background:var(--card);z-index:2}
.pg-mx tbody td{border-top:1px solid var(--line2);text-align:right;padding:0 10px 0 4px}
.pg-mx tbody td.pgm-sum{font-weight:600;font-variant-numeric:tabular-nums;padding-right:14px}
/* 基础行不可删：那一格留空（保持四列对齐），不给用户一个点了没用的 ✕ */
.pg-mx tbody td.pgm-x{width:28px;text-align:center;padding:0}

.pg-mx tbody td.pgm-x .pg-del{width:24px;height:24px;font-size:11px;border-radius:6px}
/* 「20NN+ 按增长率推算」：把「可填 / 自动」的边界画在表里，而不是藏在提示文字里 */
.pg-mx tbody tr.future th,.pg-mx tbody tr.future td{border-top:1px solid var(--line2);
  color:var(--ph);font-size:12.5px}
/* ★★ 格子里的输入框（第 91 轮 Fred 反馈②：「可以填写的地方没有输入框，看起来很别扭」）——
   补上**看得见的输入框**：细边 + 圆角 + 白底，聚焦时主色描边。
   为什么必须改：原来是无边框透明格子，跟右侧**只读**的「合计」列长得一模一样 ⇒
   用户分不清哪格能点、哪格是结果。现在「能填 = 有框」，「只读 = 纯文字」。
   ★★ 第 92 轮（Fred：「输入框都是灰色底色，容易让用户以为是不能编辑的」）：
   **底色 `--fill`（浅灰蓝 #F1F4F9）→ `--card`（白）**。灰底是**禁用态**的通用语言 ——
   全站的 `.input:disabled`（`opacity:.55;background:var(--fill-2)`）就是灰底，
   拿它当可编辑框的底色，等于把「能填」亲手画成了「不能填」（第 91 轮刚补上框又踩了这个坑）。
   改后与全站 `.input` 完全一致：`background:var(--card)` + `1px solid var(--line)`。
   顺带消掉一处抖动：`:focus` 本来就是白底（见下条），灰底常态 ⇒ 聚焦时底色会跳一下。
   ⚠️ 别退回「无边框」——那是第 91 轮刚修掉的形态，会重新跟只读的「合计」列混在一起。 */
.pg-mx .pg-mv,
.pg-mx .pg-fa-a{width:100%;height:34px;border:1px solid var(--line);background:var(--card);
  outline:none;text-align:right;font-size:14.5px;font-family:inherit;color:var(--text);
  font-variant-numeric:tabular-nums;border-radius:8px;padding:0 8px}
.pg-mx .pg-mv:focus,
.pg-mx .pg-fa-a:focus{border-color:var(--primary);
  box-shadow:0 0 0 2px var(--primary-w)}
/* 空格子里的提示（`0.00`）：浅灰细体 —— 字重必须显式压回 400（`::placeholder` 会继承 input） */
.pg-mx .pg-mv::placeholder,
.pg-mx .pg-fa-a::placeholder{color:var(--ph);font-weight:400;opacity:1}
/* 固定资产表的「年份」列：基础行（首年 → 本年）是**纯文字**，追加行是可选年份的下拉。
   下拉外观与「规划区间」那两块格子同一套（去边框 + 自绘 ▾）。 */
.pg-mx .pg-fa-y{width:100%;height:34px;border:0;background:transparent;outline:none;
  font-family:inherit;font-size:12.5px;color:var(--sub);font-variant-numeric:tabular-nums;
  padding:0 14px 0 0;appearance:none;-webkit-appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'%3E%3Cpath d='M2 3.6l3 3 3-3' fill='none' stroke='%23B9C1CC' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 0 center}

/* 表脚（单位 + 「＋ 新增」）：与效果图一致 —— 上面一条分隔线、左单位、右侧**金色文字按钮**。
   ⚠️ 这里**不用 `.mini primary`（实心药丸）**：效果图里它就是一枚金色文字。
      但触控目标仍按 44pt 撑开（`min-height`），不因为「是文字」就把可点区域缩小。 */
.pgm-addrow{display:flex;align-items:center;gap:8px;padding:4px 14px 6px;
  border-top:1px solid var(--line2)}
.pgm-addrow .pgm-unit{flex:1;font-size:12px;color:var(--sub)}
.pgm-addrow .pgm-note{font-size:12px;color:var(--ph)}
.pgm-add{display:flex;align-items:center;gap:3px;margin-left:auto;min-height:44px;padding:0 2px;
  border:0;background:transparent;color:var(--primary);font-size:12.5px;font-weight:600;
  font-family:inherit;cursor:pointer}
.pgm-add:active{opacity:.55}
/* 固定资产表列少（4 列）⇒ 直接撑满；收入/支出表列数可变，宽度在 JS 里按列数写死。
   ⚠️ 年份列里可能是**原生 select**（追加行）也可能是纯文字（基础行）
      ⇒ 84px 是「2024 年」+ 自绘 ▽ 都放得下的宽度（66px 会把「年」和箭头挤在一起，实测踩过）。 */
.pg-mx.pg-fa{width:100%}
.pg-mx.pg-fa thead th.pgm-y{width:84px}
.pg-mx.pg-fa thead th.pgm-n{width:130px}
.pg-mx.pg-fa thead th.pgm-sum{width:110px}
.pg-mx.pg-fa thead th.pgm-x{width:28px}
/* 行尾的删除键：**低调但要认得出**（原来常驻淡红底 + 红 ✕，在表格里太抢眼） */
.pg-mx tbody td.pgm-x .pg-del{width:26px;height:26px;font-size:12px;border-radius:7px;
  background:transparent;color:color-mix(in srgb, var(--danger) 46%, var(--card))}
.pg-mx tbody td.pgm-x .pg-del:active{background:var(--danger-w);color:var(--danger)}

/* 「只读 · 自动取数」药丸（债务偿还卡头） */
.pill-ro{background:#DFF3E9;color:#0b7f59;font-weight:600}

/* 「⋯」列名菜单（重命名 / 删除）—— 固定定位，JS 算坐标 */
.pgm-pop{position:fixed;z-index:80;background:var(--card);border-radius:10px;
  box-shadow:0 8px 24px rgba(16,24,40,.18);padding:4px;min-width:116px}
.pgm-pop button{display:block;width:100%;text-align:left;border:0;background:transparent;
  padding:10px 12px;font-size:14px;color:var(--text);border-radius:8px;font-family:inherit;cursor:pointer}
.pgm-pop button:active{background:var(--fill)}
.pgm-pop button.danger{color:var(--danger)}

/* ── 债务偿还：只读表「年份 × 当年应还 + 展开看拆分」（第 90 轮 Fred 定案③）──
   ★ 与上面几张表的区别只有一条：**格子不是输入框**（没有边框 / 聚焦底色 / 点不动）；
     药丸标「自动取数 · 只读」。
   ⚠️ 展开子行跨了「当年应还 + 箭头」两列 ⇒ 右侧 padding 必须是
      **箭头列宽(34) + 主行 padding(10)**，否则展开里的金额与主行金额右边缘对不齐。 */
.pg-debt{border-collapse:separate;border-spacing:0;table-layout:fixed;width:100%;font-size:13px}
.pg-debt th,.pg-debt td{padding:0;height:44px;white-space:nowrap;font-weight:400;vertical-align:middle}
.pg-debt thead th{height:32px;font-size:11.5px;color:var(--sub);text-align:right;
  padding:0 10px 0 4px;border-bottom:1px solid var(--line)}
.pg-debt thead th.pgm-y{text-align:left;padding-left:14px;width:56px}
.pg-debt thead th.pgt-tg{width:34px;padding:0}
.pg-debt tbody th.pgm-y{color:var(--sub);font-size:12.5px;text-align:left;padding-left:14px;
  font-variant-numeric:tabular-nums}
.pg-debt tbody td{border-top:1px solid var(--line2);text-align:right;padding:0 10px 0 4px}
.pg-debt tbody td.pgm-sum{font-weight:600;font-variant-numeric:tabular-nums;padding-right:14px}
.pg-debt tbody td.pgt-tg{text-align:center;padding:0;color:#B9C1CC}
.pg-debt tbody tr.drow{cursor:pointer}
.pg-debt tr.drow .caret{display:inline-flex;transition:transform .16s}
.pg-debt tr.drow.on .caret{transform:rotate(180deg)}
.pg-debt tbody tr.dsub td{border-top:0;background:var(--fill);height:32px;font-size:12.5px;
  color:var(--sub);padding:0 48px 0 4px}
.pg-debt tbody tr.dsub.hide{display:none}
.pg-debt tbody tr.dsub b{color:var(--text);font-weight:600;margin-left:8px;
  font-variant-numeric:tabular-nums}
.pg-debt-empty{padding:10px 12px;font-size:12.5px;color:var(--sub);line-height:1.6}
.chk-line{display:flex;align-items:center;gap:7px;font-size:13px;color:var(--text);cursor:pointer}
.chk-line input{width:16px;height:16px;accent-color:var(--primary)}

/* 年度盘点 */
.rv-intro{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);
  padding:14px 15px;margin-bottom:14px}
.rv-intro-t{font-size:15px;font-weight:600;margin-bottom:4px}
.rv-intro-d{font-size:12px;color:var(--sub);line-height:1.55}
.rv-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}
.rv-time{font-size:11px;color:var(--sub)}
/* 年度实际数据块（第 71 轮）：理财收益手填 + 手动锁定 */
.rv-actual{margin-bottom:12px}
.rv-actual .card-hd{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;
  border-bottom:1px solid var(--line)}
.rv-actual .card-hd-t{font-size:12px;font-weight:700;letter-spacing:.2px}
.rv-actual .card-hd-v{font-size:11px;font-weight:700;color:var(--primary)}
.rv-actual .card-hd-v.locked{color:var(--sub)}
.rv-actual-body{padding:8px 14px 10px}
.rv-arow{display:flex;align-items:baseline;justify-content:space-between;gap:8px;
  padding:6px 0;border-bottom:1px dashed var(--line);font-size:13px}
.rv-arow:last-of-type{border-bottom:none}
.rv-arow .k{color:var(--sub)}
.rv-arow .v{font-variant-numeric:tabular-nums;font-weight:600}
/* ★ 第 74 轮（Fred 反馈②）：「锁定年度实际数据」与「生成年度报告」并成一行两个按钮。
   .rv-acts 本身只有 gap，子按钮各自 flex:1 会平分；这里额外把「生成」那颗做成主角
   （primary 权重更高），锁定是次要动作（ghost）。等宽平分，任一文案变长都不跳版。 */
.rv-acts-pair .btn{flex:1 1 0;min-width:0;white-space:normal;line-height:1.25;text-align:center}
/* 已锁定时「解锁」降级成实际数据卡里的一枚小字链接 —— 它是撤销类动作，
   不该和「生成」抢一行的注意力。 */
.rv-unlock{margin-left:6px;padding:0;border:none;background:none;font-family:inherit;
  font-size:12px;color:var(--primary);text-decoration:underline;cursor:pointer}
.rv-unlock:active{opacity:.6}
.rv-cards{display:grid;grid-template-columns:repeat(2,1fr);gap:9px;margin-bottom:4px}
.rv-card{background:var(--card);border-radius:10px;box-shadow:var(--shadow);padding:11px 12px}
.rv-lb{font-size:12px;color:var(--sub);margin-bottom:5px}
.rv-vals{display:flex;align-items:baseline;gap:5px;flex-wrap:wrap}
.rv-actual{font-size:16px;font-weight:700;font-variant-numeric:tabular-nums}
.rv-vs{font-size:11px;color:var(--sub)}
.rv-gap{font-size:12px;font-weight:600;margin-top:4px}
.rv-gap.ok{color:var(--ok)}
.rv-gap.bad{color:var(--danger)}
.rv-rate{font-size:11px;color:var(--sub);margin-top:2px}
.rv-acts{display:flex;gap:8px;margin-top:16px}
.fc-tbl td.ok{color:var(--ok);font-weight:600}
.fc-tbl td.bad{color:var(--danger);font-weight:600}

/* ── 年度盘点 · hero / 预警条 / 分项达成（第 72 轮，照效果图 ③）──────────────
   三块自上而下：达成率大卡 → 预警条 → 分项列表（名称 + 实际值 + 徽标 + 目标/偏差 + 进度条）。
   颜色一律走 --primary / --expense / --income 派生，六套皮肤自动适配。 */
.rv-hero{background:linear-gradient(135deg,
    color-mix(in srgb,var(--primary) 92%,#000) 0%,
    color-mix(in srgb,var(--primary) 72%,#000) 100%);
  border-radius:var(--radius);padding:18px 16px 16px;color:#fff;margin-bottom:12px}
.rv-hero-k{font-size:12px;opacity:.86;margin-bottom:6px}
.rv-hero-v{font-size:36px;font-weight:700;line-height:1;font-variant-numeric:tabular-nums;letter-spacing:-.5px}
.rv-hero-v small{font-size:15px;font-weight:600;opacity:.88;margin-left:6px;letter-spacing:0}
.rv-hero-sub{display:flex;gap:10px;margin-top:16px}
.rv-hero-sub>div{flex:1 1 0;min-width:0}
.rv-hero-sub .k2{font-size:11px;opacity:.82;margin-bottom:3px}
.rv-hero-sub .v2{font-size:15px;font-weight:700;font-variant-numeric:tabular-nums}
/* hero 里的 ok/bad 要压在深底上，不能用页面的深绿深红（对比度不足）→ 提亮一档 */
.rv-hero-sub .v2.ok{color:var(--hero-pos)}
.rv-hero-sub .v2.bad{color:var(--hero-neg)}

/* 预警条：⚠️ + 文案 + 「看明细 ›」 */
.rv-todo{display:flex;align-items:center;gap:8px;padding:10px 12px;margin-bottom:12px;
  border-radius:10px;font-size:12px;line-height:1.5;
  background:color-mix(in srgb,var(--warn,#D97706) 12%,var(--card));
  color:color-mix(in srgb,var(--warn,#D97706) 78%,var(--text))}
.rv-todo .ic{flex:none;font-size:15px}
.rv-todo .tx{flex:1 1 auto;min-width:0}
.rv-todo .go{flex:none;font-weight:700;opacity:.9}

/* 分项达成列表 */
.rv-arows{padding:2px 14px}
.rv-arows .arow{padding:12px 0;border-bottom:1px solid var(--line)}
.rv-arows .arow:last-child{border-bottom:0}
.rv-arows .arow .t{display:flex;align-items:baseline;justify-content:space-between;gap:8px}
.rv-arows .arow .n{font-size:13px;font-weight:600;color:var(--text)}
.rv-arows .arow .r{font-size:13px;font-weight:700;font-variant-numeric:tabular-nums;
  display:inline-flex;align-items:baseline;gap:6px}
.rv-arows .arow .r.c-in{color:var(--income)}
.rv-arows .arow .d{display:flex;justify-content:space-between;gap:8px;
  font-size:12px;color:var(--sub);margin-top:4px}
.rv-arows .arow .d b{font-weight:700}
.rv-arows .arow .d b.c-in{color:var(--income)}
.rv-arows .arow .d b.c-out{color:var(--expense)}
/* 徽标：达成（绿）/ 轻微超支（橙）/ 大幅超支（红） */
.rv-arows .pct{font-size:11px;font-weight:700;padding:2px 7px;border-radius:10px;line-height:1.5;
  white-space:nowrap;font-variant-numeric:tabular-nums}
.rv-arows .pct.ok{color:var(--income);background:var(--income-w)}
.rv-arows .pct.mid{color:var(--warn,#D97706);background:color-mix(in srgb,var(--warn,#D97706) 14%,var(--card))}
.rv-arows .pct.bad{color:var(--expense);background:var(--expense-w)}
/* 进度条：宽度由内联 style 给，颜色按偏差语义给 */
.rv-arows .pb{height:6px;border-radius:2px;overflow:hidden;margin-top:8px;
  background:color-mix(in srgb,var(--sub) 16%,var(--card))}
.rv-arows .pb i{display:block;height:100%;border-radius:2px;transition:width .3s}
.rv-arows .pb.g i{background:var(--income)}
.rv-arows .pb.w i{background:var(--warn,#D97706)}
.rv-arows .pb.r i{background:var(--expense)}

/* ── 一句话记账（M5「打字版」，真机第 47 轮）──────────────────────────────
   入口在「记一笔」表单顶部：一段话 → 预览卡里逐条核对 → 全部入账。
   预览卡复用 .sheet 外壳，只补「一条一笔」的行样式；改为在卡内直接可点即改，
   所以每个字段都是按钮/输入框，缺口用 .miss 标黄（认不出就让用户选，不替他猜）。 */
.nl-row{display:flex;gap:8px;align-items:center;margin-bottom:10px}
.nl-input{flex:1 1 auto;min-width:0;height:38px;padding:0 12px;border-radius:var(--radius-sm);
  border:1px solid var(--line);background:var(--fill);color:var(--text);font-size:13px}
.nl-input::placeholder{color:var(--sub)}
.nl-go{flex:none;height:38px;padding:0 14px;border-radius:var(--radius-sm);border:0;
  background:var(--primary-btn);color:var(--primary-on);font-size:13px;font-weight:600}
.nl-go[disabled]{opacity:.55}
.nl-sheet{max-height:80vh;display:flex;flex-direction:column}
.nl-sheet .sheet-body{overflow-y:auto}
.nl-list{display:flex;flex-direction:column;gap:8px}
.nl-item{background:var(--card-2);border:1px solid var(--line);border-radius:var(--radius);padding:10px 12px}
.nl-item.bad{border-color:var(--danger)}
.nl-i-top{display:flex;align-items:center;gap:8px}
.nl-tag{flex:none;font-size:11px;font-weight:600;padding:2px 8px;border-radius:6px;background:var(--fill-2);color:var(--sub)}
.nl-tag.expense{background:var(--expense-w);color:var(--expense)}
.nl-tag.income{background:var(--income-w);color:var(--income)}
.nl-tag.transfer{background:var(--primary-w);color:var(--transfer)}
.nl-amt{flex:1 1 auto;display:flex;align-items:baseline;gap:2px;min-width:0}
/* 金额只显示裸数字，不带货币符号 —— 与「记一笔」的 .tf-amt 同口径（全站符号只由 money(…,{sym}) 产出） */
.nl-amt-in{flex:1 1 auto;min-width:0;border:0;background:transparent;color:var(--text);
  font-size:20px;font-weight:700;font-variant-numeric:tabular-nums;padding:0}
.nl-del{flex:none;width:30px;height:30px;border:0;background:transparent;color:var(--sub);font-size:15px}
.nl-i-mid{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.nl-pick{height:28px;padding:0 10px;border-radius:6px;border:1px solid var(--line);
  background:var(--card);color:var(--text);font-size:12px}
.nl-pick.miss{border-color:var(--warn);background:var(--warn-w);color:var(--warn)}
.nl-note{margin-top:8px;width:100%;height:30px;padding:0 10px;border-radius:6px;
  border:1px solid var(--line);background:var(--card);color:var(--text);font-size:12px}
.nl-err{margin-top:6px;font-size:12px;color:var(--danger)}
.nl-tip{margin:10px 2px 0;font-size:12px;color:var(--sub)}

/* ════════════════════════════════════════════════════════════
   【我的设置】模块（开发计划 3.49）—— 依据 docs/效果图归档/20260920-设置模块-mockup效果稿
   · 主页 + 六个二级页；金色是 VIP 唯一强调色，跨皮肤保持一致（会员身份不该随皮肤变）
   · 二级页返回条沿用 .group-h 的排版节奏，整条可点（触屏友好）
   ════════════════════════════════════════════════════════════ */
:root{
  --vip:#7a5000; --vip-w:#f7ead1; --vip-line:#e3c584;
}

/* VIP 金色按钮：与 .btn 同尺寸，只是换配色（不新造一套按钮体系） */
.btn.gold{background:linear-gradient(135deg,#c8901f,#a9761a);color:#fff;font-weight:600}
.btn.gold:active{background:linear-gradient(135deg,#a9761a,#8a5f13)}
.me-vip-btn{width:100%;margin:0 0 8px}

/* 次级角标（「待接云端」这类）—— 灰底，不抢主色 */
.rt-badge{flex:none;font-size:11px;padding:2px 8px;border-radius:6px;
  background:var(--fill-2);color:var(--sub);white-space:nowrap}

/* 二级页返回条：整条都是热区 */
.me-back{width:100%;text-align:left;background:none;border:0;font:inherit;color:var(--text);
  cursor:pointer;align-items:center}
.me-back-i{flex:none;width:22px;height:22px;line-height:20px;text-align:center;
  border-radius:50%;background:var(--fill-2);color:var(--sub);font-size:15px}
.me-back-t{flex:1;min-width:0;font-size:15px;font-weight:700;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* 头像：无自定义图时显示昵称首字（字形头像） */
.avatar{flex:none;width:42px;height:42px;border-radius:50%;background:var(--primary-w);
  color:var(--primary);font-size:16px;font-weight:700;line-height:42px;text-align:center;overflow:hidden}
.avatar.has-img{background:var(--fill-2);line-height:0}
.avatar img{width:100%;height:100%;object-fit:cover;display:block}
.avatar-lg{width:76px;height:76px;font-size:28px;line-height:76px}

/* 个人资料页：头像区居中，整块可点 */
.me-avatar-card{padding:18px 14px;display:flex;justify-content:center}
.me-avatar-pick{display:flex;flex-direction:column;align-items:center;gap:8px;
  background:none;border:0;font:inherit;color:inherit;cursor:pointer;padding:0}
.me-avatar-tip{font-size:12px;color:var(--sub)}

/* 皮肤设置：默认两列网格，`.one` = 一栏到底（第 88 轮起 10 套皮肤用） */
.me-skin-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px}
.me-skin-grid.one{grid-template-columns:1fr}
.me-skin-cell{display:flex;align-items:center;gap:10px;padding:12px;border-radius:var(--radius-sm);
  background:var(--card);border:1px solid var(--line);font:inherit;color:inherit;
  cursor:pointer;text-align:left;min-width:0;position:relative}
.me-skin-cell.on{border-color:var(--primary);background:var(--primary-w)}
.me-skin-cell.locked{opacity:.62}
.me-skin-cell .tc-dot{flex:none;width:26px;height:26px;border-radius:50%;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.08)}
.me-skin-cur{flex:none;margin-left:auto;font-size:11px;font-weight:500;color:var(--primary);
  background:var(--card);border:1px solid var(--primary);border-radius:999px;padding:2px 8px;
  white-space:nowrap}
.me-skin-bd{display:flex;flex-direction:column;min-width:0;gap:1px}
.me-skin-bd .sn{font-size:13px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.me-skin-bd .sd{font-size:11px;color:var(--sub);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.me-skin-lock{position:absolute;right:8px;top:8px;color:var(--vip)}
.me-skin-lock svg{width:13px;height:13px}

/* 意见反馈：历史列表 */
.fb-item{padding:11px 14px;border-bottom:1px solid var(--line)}
.fb-item:last-child{border-bottom:none}
.fb-time{font-size:11px;color:var(--sub);margin-bottom:4px;
  font-variant-numeric:tabular-nums}
.fb-body{font-size:15px;line-height:1.55;white-space:pre-wrap;word-break:break-word}
.em-area{width:100%;padding:10px 12px;border-radius:var(--radius-sm);border:1px solid var(--line);
  background:var(--fill);color:var(--text);font:inherit;font-size:15px;line-height:1.55;
  resize:vertical;box-sizing:border-box}

/* 关于页 */
.about-hero{padding:22px 14px;display:flex;flex-direction:column;align-items:center;gap:6px}
.about-logo{width:56px;height:56px;border-radius:14px;background:var(--primary);
  color:var(--on-solid);font-size:24px;font-weight:700;line-height:56px;text-align:center}
.about-name{font-size:16px;font-weight:700}
.about-ver{font-size:12px;color:var(--sub)}

/* 对话框正文要保留换行（导入恢复的确认文案是多段的，挤成一行会读不懂） */
.dlg-text{white-space:pre-line}

/* ── 应用密码锁（3.49 T3）──
   覆盖全屏、拦在内容之上；不通过就不显示任何内容。 */
.lock-layer{position:fixed;inset:0;z-index:9999;background:var(--bg);
  display:flex;align-items:center;justify-content:center;padding:24px;
  animation:fadeIn .18s}
.lock-card{display:flex;flex-direction:column;align-items:center;gap:12px;width:100%;max-width:360px}
.lock-logo{width:52px;height:52px;border-radius:50%;background:var(--primary-w);
  color:var(--primary);display:flex;align-items:center;justify-content:center}
.lock-logo svg{width:26px;height:26px}
.lock-title{font-size:16px;font-weight:700}
.lock-tip{font-size:12px;color:var(--sub);min-height:18px}
.lock-tip.err{color:var(--danger)}
/* 自绘键盘装在这里（原先的 .lock-pad/.lock-key/.lock-dots 数字键盘已随反馈①下线） */
.lock-body{width:100%;display:flex;flex-direction:column;align-items:center;gap:12px}
.lock-go{width:100%;max-width:290px}
.lock-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--pd-gap);margin:6px 0 2px}
.lock-pd{width:var(--pd-size);height:var(--pd-size);border-radius:50%;border:0;background:transparent;
  padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center}
.lock-pd i{display:block;width:var(--pd-dot);height:var(--pd-dot);border-radius:50%;background:var(--fill-2);
  box-shadow:inset 0 0 0 1px var(--line);transition:background .12s,transform .12s}
.lock-pd.on i{background:var(--primary);transform:scale(1.18);box-shadow:none}
.pl-wrap{display:flex;flex-direction:column;align-items:center;gap:2px}
/* ★ 第三批：.pl-grid 原来自带一套尺寸（46px/13px）⇒ 同一个 3×3 手势控件两套规格。
   现统一走 --pd-* 令牌（与解锁层同规格），本类只保留容器语义。 */
.pl-grid{}
.pl-step{font-size:12px;color:var(--sub);margin-top:4px}
.pin-step{display:flex;align-items:baseline;gap:8px;padding:2px 0 9px;font-size:13px;color:var(--sub)}
.pin-step .ps-n b{color:var(--primary);font-size:15px}
.pin-step .ps-t{color:var(--text);font-weight:600}
.lock-reset{margin-top:6px}
@keyframes lockShake{0%,100%{transform:translateX(0)}20%{transform:translateX(-8px)}
  40%{transform:translateX(8px)}60%{transform:translateX(-5px)}80%{transform:translateX(5px)}}
.lock-layer.shake .lock-card{animation:lockShake .42s}
@media (prefers-reduced-motion:reduce){
  .lock-layer,.lock-layer.shake .lock-card{animation:none}
}

/* ---------- 应用内安全键盘（真机第 50 轮反馈①） ---------- */
/* 自绘键盘：密码不进系统输入法，切换 数字 / 英文 / 符号 三种布局。 */
.si{width:100%}
.si-box{display:flex;align-items:center;gap:10px;min-height:52px;padding:0 12px;border-radius:10px;background:var(--fill);border:1px solid var(--line)}
.si-dots{flex:1;min-width:0;display:flex;align-items:center;font-size:18px;letter-spacing:3px;color:var(--text);overflow:hidden;white-space:nowrap}
.si-dots .si-ph{font-size:15px;letter-spacing:0;color:var(--sub)}
/* 刚按下的那一位短暂显明文：字距归零、加个底色，一眼能认出是「刚输入的」 */
.si-dots .si-last{letter-spacing:0;margin-left:3px;padding:1px 5px;border-radius:6px;background:var(--primary-w);color:var(--primary-d);font-weight:700}
.si-dots .si-n{margin-left:auto;font-size:12px;letter-spacing:0;color:var(--sub);flex:none}
.si-clr{font-size:13px;color:var(--primary);flex:none;padding:4px 2px}
.si-hint{font-size:12px;color:var(--sub);padding:7px 2px 0;line-height:1.65}
.si-kb{margin-top:10px;display:flex;flex-direction:column;gap:6px}
.kb-row{display:flex;gap:5px}
.kb-key{flex:1;min-width:0;height:46px;border-radius:9px;background:var(--card);border:1px solid var(--line);color:var(--text);font-size:18px;display:flex;align-items:center;justify-content:center;user-select:none;-webkit-user-select:none}
.kb-key:active{background:var(--fill-2)}
.kb-key.fn{background:var(--fill-2);font-size:13px;color:var(--sub)}
.kb-key.fn.on{background:var(--primary);border-color:var(--primary);color:var(--on-solid)}
.kb-key svg{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
/* 数字布局只有 3 列：限宽居中，别让按键被拉成一整条 */
.si-kb.ly-digit{max-width:290px;margin-left:auto;margin-right:auto}
.si-kb.ly-digit .kb-key{height:52px;font-size:20px}
/* 弹层里的键盘：底部安全区留白，别被手势条压住 */
.sheet .si-kb{padding-bottom:2px}

/* ---------- 账号：登录 / 注册页（内测云端版 v65） ---------- */
.auth-wrap{min-height:100vh;display:flex;flex-direction:column;padding:44px 20px 28px;max-width:520px;margin:0 auto}
.auth-brand{text-align:center;margin-bottom:26px}
.auth-logo{width:64px;height:64px;border-radius:20px;margin:0 auto 12px;display:flex;
  align-items:center;justify-content:center;font-size:32px;font-weight:700;color:#fff;
  background:linear-gradient(160deg,#2b7ce0,#0f56b4)}
.auth-logo svg{width:34px;height:34px;fill:none;stroke:#fff;stroke-width:2.4;
  stroke-linecap:round;stroke-linejoin:round}
.auth-name{font-size:21px;font-weight:700;letter-spacing:.4px}
.auth-slogan{font-size:12px;color:var(--sub);margin-top:5px}
.auth-tabs{display:flex;gap:6px;background:var(--fill-2);border-radius:10px;padding:4px;margin-bottom:14px}
.auth-tab{flex:1;height:38px;border:0;background:transparent;border-radius:10px;font-size:15px;
  color:var(--sub);cursor:pointer;font-family:inherit}
.auth-tab.on{background:var(--card);color:var(--text);font-weight:600;box-shadow:var(--shadow)}
.auth-card{padding:16px}
.auth-submit{width:100%;margin-top:14px;height:46px}
.auth-foot{margin-top:auto;padding-top:22px;text-align:center;font-size:12px;color:var(--sub);line-height:1.7}
.pw-rules{display:flex;flex-wrap:wrap;gap:8px 12px;margin:0 0 12px;font-size:12px;color:var(--sub)}
.pw-r.ok{color:var(--ok)}

/* ==========================================================================
   统一表格组件 .tbx（2026-09-30「天青蓝」定稿 · Fred 在 10 版选型中选定第 4 款）
   真源：docs/表格样式规范-v1.0.md §一 ｜ 效果基准：docs/效果图归档/20260930-效果稿v4-财务规划与收支明细/效果图v4-天青蓝.png
   用在六处：① 规划卡片内表 ② 规划·表格视图 ③ 资产负债表 ④ 年度收支
             ⑤ 月度收支明细 ⑥ 盘点分项
   ★ 表头是「一整套」：底 + 字 + 36px 高 + 右竖线。只把底色从灰改浅蓝、字号高度不动，
     一眼仍看出不是同一套（第 5 轮 Fred 反馈「⑦⑧ 没调过来」就是这么漏的）。
   ★ 行/列线与语义色一律 color-mix / var() 派生 → 十套皮肤自动适配，不写死。
   ★★ 第 88 轮批 4（2026-10-14 · Fred 真机反馈③④）：**表头一整套改由皮肤主色派生**。
     起因：原来这 9 个令牌写死「天青蓝」色值（`#e8f0fa` 等），于是**切皮肤时表头一动不动** ——
     报表·收支趋势 与 资产·资产负债表 这两页因此「完全没有皮肤元素」（Fred 原话）。
     定案：全部改成 `var(--primary-w)` / `var(--primary-d)` / `color-mix(主色…)`。
     ⚠️ 对 m03 晴空蓝**几乎看不出差别**（primary-w `#E1EFFB` ≈ 原 `#e8f0fa`、
        primary-d `#0A4B85` ≈ 原 `#1b4e8c`）—— 当年那版「天青蓝」本来就是这个肤色，
        所以这不是推翻 2026-09-30 的选型，而是把同一个选型**推广到十套皮肤**。
     ⚠️ 这里的 color-mix 只服务 CSS（JS 不读这 9 个令牌）。**凡是 JS 要读的令牌都不许写 color-mix**
        —— `getComputedStyle()` 对自定义属性返回的是**字面量**，`color-mix(...)` 原样传给
        Chart.js 会解析失败（见 --chart-grid 保持纯色值的原因）。
   ★ 表头色走令牌。第 88 轮删掉 dark（墨夜黑）皮肤后，原来给深色底准备的
     `[data-theme="dark"]` 覆盖块一并移除 —— 10 套皮肤**全是浅色底**，一套令牌够用。
   ========================================================================== */
:root{
  --tbx-hd-bg:var(--primary-w);                                          /* 表头底 */
  --tbx-hd-fg:var(--primary-d);                                          /* 表头字 */
  --tbx-hd-line:color-mix(in srgb,var(--primary) 18%,var(--card));       /* 表头右竖线 / 下缘 */
  --tbx-gp-bg:color-mix(in srgb,var(--primary-w) 95%,var(--primary));    /* 分组带 */
  --tbx-fz-bg:color-mix(in srgb,var(--primary-w) 30%,var(--card));       /* 左侧冻结列 */
  --tbx-pin-bg:color-mix(in srgb,var(--primary-w) 45%,var(--card));      /* 钉住列格 */
  --tbx-pin-bg-a:color-mix(in srgb,var(--primary-w) 68%,var(--card));    /* 钉住列格（实际行） */
  --tbx-pin-hd-bg:color-mix(in srgb,var(--primary-w) 88%,var(--primary));/* 钉住列表头底 */
  --tbx-pin-hd-fg:var(--primary-d);                                      /* 钉住列表头字 */
}

.tbx{border-collapse:separate;border-spacing:0;table-layout:fixed;width:100%;
  font-variant-numeric:tabular-nums;font-size:12px}
/* ★ table-layout:fixed + width:100% 必须配 min-width（写在 table 的 style 上），
   否则列被压扁成表头粘连、数字重叠。 */
.tbx th,.tbx td{height:34px;padding:0 7px;text-align:right;white-space:nowrap;
  border-bottom:1px solid color-mix(in srgb,var(--sub) 16%,var(--card));
  border-right:1px solid color-mix(in srgb,var(--sub) 16%,var(--card));
  vertical-align:middle;overflow:hidden;text-overflow:ellipsis}
.tbx th:last-child,.tbx td:last-child{border-right:0}
.tbx thead th{height:36px;background:var(--tbx-hd-bg);color:var(--tbx-hd-fg);
  font-size:11px;font-weight:700;line-height:1.15;text-align:center;white-space:normal;
  letter-spacing:.2px;border-right:1px solid var(--tbx-hd-line);border-bottom:0}
/* 分组带：跨列标题，**左对齐** —— 居中会让右端滑出 390px 视口被裁 */
.tbx .tgp{background:var(--tbx-gp-bg)!important;color:var(--tbx-hd-fg)!important;
  text-align:left;padding-left:10px!important;font-size:11px;font-weight:700;letter-spacing:.4px}
/* 冻结列：左侧常驻。★ 必须显式 width，靠内容撑会裁字（「2026」显示成「202」）。
   双冻结列时第二列的 z-index 必须高于第一列。 */
.tbx .tfz{position:sticky;left:0;z-index:4;text-align:left;padding-left:11px;font-weight:600;
  background:var(--tbx-fz-bg);color:var(--text);box-shadow:2px 0 4px -2px rgba(10,22,40,.18)}
.tbx thead th.tfz{background:var(--tbx-gp-bg);color:var(--tbx-hd-fg);text-align:left;padding-left:11px}
/* 钉住列（横滑时常显的关键列）。★ 表头两个属性都必须 !important ——
   否则被上面 .tbx thead th 的底/字压掉（第 1 轮实测：白字落到浅底上几乎不可见）。 */
.tbx td.pin{background:var(--tbx-pin-bg);font-weight:700}
.tbx thead th.pin{background:var(--tbx-pin-hd-bg)!important;color:var(--tbx-pin-hd-fg)!important}
.tbx .tfz2{position:sticky;right:0;z-index:4;box-shadow:-2px 0 4px -2px rgba(10,22,40,.18)}
/* 月度收支的右侧「合计」列（第 70 轮 Fred 测试反馈③）：
   原来是「合计 / 结余」两列同时钉住（sticky），现 **两处改动** ——
     · 「结余」列整列删除（数据行恒为「—」，只有表尾那一行有值，占一列没意义）；
     · 「合计」列取消钉住，不再 sticky，跟随正常横滑即可。
   ⇒ `.mm-sum` / `.mm-bal` 两条规则一并删除（列宽 58 的 right 偏移也随之失去意义）。
   ★ 保留 `.pin` 的强调底/粗体：列的**语义**没变（这是合计），只是不再常显。 */
/* 分节行（支出 / 收入 / 资产 / 负债）：整行 colspan */
.tbx .tsep th{background:color-mix(in srgb,var(--sub) 8%,var(--card));color:var(--sub);
  text-align:left;padding-left:11px;font-size:11px;font-weight:700;letter-spacing:.5px;
  height:26px;border-bottom:1px solid color-mix(in srgb,var(--sub) 16%,var(--card))}
.tbx .tsep.e th{background:color-mix(in srgb,var(--expense) 12%,var(--card));color:var(--expense)}
.tbx .tsep.i th{background:color-mix(in srgb,var(--income) 12%,var(--card));color:var(--income)}
.tbx .tsep.a th{background:var(--tbx-fz-bg);color:var(--tbx-hd-fg)}
.tbx .tsep.l th{background:color-mix(in srgb,var(--expense) 8%,var(--card));color:var(--expense)}
/* 合计行（支出 / 收入 / 结余） */
.tbx tr.tsum td{background:color-mix(in srgb,var(--sub) 8%,var(--card));font-weight:700;height:36px}
.tbx tr.tsum td.tfz{background:color-mix(in srgb,var(--sub) 14%,var(--card))}
.tbx tr.tsum.e td{background:color-mix(in srgb,var(--expense) 8%,var(--card))}
.tbx tr.tsum.e td.tfz{background:color-mix(in srgb,var(--expense) 14%,var(--card));color:var(--expense)}
.tbx tr.tsum.i td{background:color-mix(in srgb,var(--income) 8%,var(--card))}
.tbx tr.tsum.i td.tfz{background:color-mix(in srgb,var(--income) 14%,var(--card));color:var(--income)}
.tbx tr.tsum.b td{background:color-mix(in srgb,var(--primary) 9%,var(--card))}
.tbx tr.tsum.b td.tfz{background:color-mix(in srgb,var(--primary) 15%,var(--card));color:var(--primary)}
/* 语义色（取主题变量，随皮肤走；空值 = 半透明灰） */
.tbx .in{color:var(--income)} .tbx .out{color:var(--expense)}
.tbx .mute{color:color-mix(in srgb,var(--sub) 45%,var(--card))}
/* 实际行（斑马纹）与年份分组缝 */
.tbx tbody tr.lva td{background:color-mix(in srgb,var(--primary) 5%,var(--card))}
.tbx tbody tr.lva td.pin{background:var(--tbx-pin-bg-a)}
.tbx tbody tr.gstart td{border-top:2px solid var(--tbx-hd-line)}
/* 卡片外壳 + 横滑容器（隐藏滚动条） */
.tcard{background:var(--card);border-radius:10px;overflow:hidden;box-shadow:var(--shadow)}
.tcard .tw{overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.tcard .tw::-webkit-scrollbar{display:none}
/* 页面专属：⑦ 资产负债表（竖排资产/负债标 · 分类列 · 表尾标签格） */
.tbx td.vsub{writing-mode:vertical-rl;letter-spacing:2px;font-size:12px;font-weight:600;
  color:var(--sub);text-align:center;padding:0;background:var(--tbx-fz-bg)}
.tbx td.cname{text-align:left;font-size:12px;font-weight:600;padding-left:11px}
.tbx thead th.cname{text-align:left;padding-left:11px}
/* ★ 表尾只在**整个表尾上方**压一条 2px 组分线，行间用普通细线 ——
   否则每行一条粗线，看着像三张表叠一起。 */
.tbx tfoot td{background:var(--tbx-fz-bg);height:38px;font-weight:700;border-top:none}
.tbx tfoot tr:first-child td{border-top:2px solid var(--tbx-hd-line)}
.tbx tfoot td.flbl{text-align:left;padding-left:43px}
.tbx tfoot td.flbl small{display:block;font-size:11px;font-weight:500;color:var(--sub);line-height:1.3}
/* 页面专属：⑧ 年度收支（月份列左对齐；本表无横向滚动 ⇒ 不做冻结列） */
.tbx td.mon{text-align:left;font-weight:600}
.tbx thead th.mon{text-align:left}

/* ==========================================================================
   报表两张表：表头换成统一表头（2026-09-30 · 开发任务 T3 / T4）
   ★ 按规范「结构一行不动，只换表头」。**不用 .tbx 整表**，因为：
     · ③ 资产负债表有可点改的盘点格（.ma-pk 高 36px）与备注格（.ma-nb 高 34px）
       ⇒ 行高必须留在 40px，压到 .tbx 的 34px 会把按钮撑出格子、破坏触控区。
     · 两表的对齐、列宽、行高、字号一律照代码（Fred 第 4 轮明确：居中那些也要保持代码一致）。
   ★ 表头对齐**照代码**（分类左 / 其余右），不跟效果图的居中 —— 与上一版同口径。
   ========================================================================== */
.ma-tb th{height:36px;background:var(--tbx-hd-bg,#e8f0fa);color:var(--tbx-hd-fg,#1b4e8c);
  border-bottom:1px solid var(--tbx-hd-line,#d5e2f2);
  border-right:1px solid var(--tbx-hd-line,#d5e2f2);box-shadow:none}
.ma-tb th:last-child{border-right:0}
#yearTbl th{height:36px;background:var(--tbx-hd-bg,#e8f0fa);color:var(--tbx-hd-fg,#1b4e8c);
  border-bottom:0;border-right:1px solid var(--tbx-hd-line,#d5e2f2)}
#yearTbl th:last-child{border-right:0}

/* ============ B5 · 触控热区补齐 44pt（白皮书可达性基线） ============
   原则：**视觉尺寸一律不变**，只用 ::after 把命中区扩到 44×44。
   只对「邻居非交互元素」的独立图标按钮这么做（返回 / 关闭 / 翻月 / 侧栏 / 页头动作）；
   两类**不扩**（扩了会盖住邻元素反而误触）：
     · 行内密集按钮 .cm-act（一行三个）→ 抬高 min-height 折中；
     · 紧邻金额输入框的 .cr-del / .ep-del → 只把实际尺寸抬到 36×36（不铺 ::after）。 */
.icon-x,.sheet .x,.mf-side-btn,.cal-nav,.pg-del{position:relative}
.icon-x::after,.sheet .x::after,.mf-side-btn::after,.cal-nav::after,.pg-del::after{
  content:'';position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:44px;height:44px;min-width:100%;min-height:100%;
}
.cm-act{min-height:32px;padding:8px 8px}          /* 行内三连按钮：抬高到 32，不扩热区 */
.cr-del{width:36px;height:36px}                     /* 紧邻输入框：只用实际尺寸换触控 */
.ep-del{width:36px;height:36px}
.seg3 button{padding:12px 7px}                      /* 还款方式四选一：≈44 高 */
.me-back{min-height:44px}                           /* 二级页返回条：整条即热区 */

/* ============ B10 · .icon-btn 补定义 ============
   此前 loanDetail.js 用了 .icon-btn 但样式表没有该类，按钮落回 UA 默认样式。 */
.icon-btn{display:inline-flex;align-items:center;justify-content:center;gap:4px;
  min-height:44px;min-width:44px;padding:0 8px;border-radius:var(--radius-sm);
  color:var(--sub);background:none;font-size:15px}

/* ============ B9 · kv 行金额补等宽数字 ============
   贷款/往来弹层的 kv 行右侧全是金额，缺 tabular-nums 时数字会左右跳动。 */
.kv-row .v{font-variant-numeric:tabular-nums}

/* ============ 第三批（一致性收口）新增类 ============ */
/* ── 列表行箭头 .chev ──
   此前「我的」模块 31 处把箭头写成 class="amt"（金额类：600/16px/tabular-nums/max-width:50%），
   箭头被加粗放大、语义也错位，还额外挂了 25 处内联 color。统一收进本类。 */
.chev{flex:none;display:inline-flex;align-items:center;justify-content:center;
  min-width:16px;color:var(--sub);font-size:15px;font-weight:400;line-height:1}

/* ── 数据驱动的颜色改走 CSS 变量 ──
   原先直接把十六进制写进 style（主题色数据 / 账户色板常量），
   颜色仍由数据驱动，但 HTML 里不再出现色值。 */
.tc-dot{background:var(--tc,var(--primary))}
.clr-dot{background:var(--sw,var(--fill-2))}

/* ── 列表行右侧「文本值」槽（未填写 / 未设置之类）──
   此前借用金额类 .amt（600 / tabular-nums / max-width:50%），语义错位。 */
.row-v{flex:none;margin-left:auto;max-width:50%;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;color:var(--sub);font-size:15px}

/* ── 迷你按钮补足 44pt 命中区（视觉尺寸不变，做法同 B5）── */
.mini::after,.nav-act::after{
  content:'';position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);height:44px;
}

/* ── 表格内空态行 / 账户备注行 / 表单占位格 / 持仓表操作列 ── */
.td-empty{text-align:center;color:var(--sub)}
.acc-note{margin-top:4px;font-size:12px;color:var(--sub)}
.f-ph{flex:0 0 0;pointer-events:none}
.h-op{width:110px;flex:none}

/* ── 第三批 · 尾批补漏 ── */
/* .tf-mini 是「整行字段按钮」，宽度天然 100%（原先每处内联 width:100%，共 10 处）*/
.tf-mini{width:100%}
/* 贷款详情「删除」：幽灵按钮外观 + 危险色（原先用内联 color 覆盖 .btn.ghost）*/
.btn.danger-ghost{background:var(--card);border:1px solid var(--line);color:var(--danger)}
/* 非交互的列表行（关于页调试信息）：不给按压反馈 */
.row-static{cursor:default}
.row-static:active{background:transparent}
/* 策略页「返回列表」：文案式按钮，补足 44pt 命中区（视觉不变）*/
.sch-toggle{position:relative}
.sch-toggle::after{content:'';position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);height:44px}
